GJSify
Native Linux apps,
in TypeScript
One framework for GNOME, Node.js and the Web: build GTK 4 / Adwaita apps, games and CLIs in TypeScript and run them on GJS, Node.js, Deno or Bun. The same GObject-Introspection code runs on Node, Bun and Deno across Linux, macOS and Windows through the node-gi bridge. No embedded browser.
$ gjs -m express-webserver.js
Express.js blog running on GJS
➜ Local: http://localhost:3000/ ➜ API: http://localhost:3000/api/posts
Press Ctrl+C to stop
[12:34:56] GET /[12:34:56] GET /style.css[12:34:56] GET /app.js[12:34:56] GET /api/runtime[12:34:56] GET /api/posts A real Express.js
blog, running on GJS
import '@gjsify/node-globals';import express from 'express';import { posts } from './data/posts.js';
const app = express();app.use(express.json());
app.get('/api/posts', (_req, res) => { res.json({ count: posts.length, posts });});
app.get('/api/posts/:slug', (req, res) => { const post = posts.find((p) => p.slug === req.params.slug); if (!post) return res.status(404).json({ error: 'Not found' }); res.json(post);});
app.use(express.static('public'));
app.listen(3000, () => { console.log('Express server running at http://localhost:3000');}); See for yourself —
on any runtime!
on any runtime!
Terminal
gjsify showcase express-webservernpx @gjsify/cli@latest showcase express-webserver --runtime nodebunx @gjsify/cli@latest showcase express-webserver --runtime bundeno run -A npm:@gjsify/cli@latest showcase express-webserver --runtime deno Create stories for your GTK widgets
just as you would in web development
import { ControlType, type StoryMeta } from '@gjsify/stories';
// Author a widget's story once — renderer-free metadata + controls.// The native GTK storybook (gjsify storybook) and the browser one// both render it from this same source, so the two stay in lockstep.export const switchRowMeta: StoryMeta = { title: 'Boxed Lists/Switch Row', description: 'Adw.SwitchRow — a row with a trailing switch.', controls: [ { name: 'title', label: 'Title', type: ControlType.TEXT, defaultValue: 'Automatic updates' }, { name: 'active', label: 'Active', type: ControlType.BOOLEAN, defaultValue: true }, ],}; See for yourself —
on any runtime!
on any runtime!
Terminal
gjsify showcase adwaita-storybooknpx @gjsify/cli@latest showcase adwaita-storybook --runtime nodebunx @gjsify/cli@latest showcase adwaita-storybook --runtime bundeno run -A npm:@gjsify/cli@latest showcase adwaita-storybook --runtime deno This WebGL demo runs
natively on Linux!
import Adw from 'gi://Adw?version=1';import { WebGLBridge } from '@gjsify/webgl';import * as THREE from 'three';import { RenderPixelatedPass } from 'three/addons/postprocessing/RenderPixelatedPass.js';import { EffectComposer } from 'three/addons/postprocessing/EffectComposer.js';
const app = new Adw.Application({ application_id: 'gjsify.examples.pixel' });app.connect('activate', () => { const glArea = new WebGLBridge(); glArea.onReady((canvas) => { const renderer = new THREE.WebGLRenderer({ canvas }); const scene = new THREE.Scene(); const camera = new THREE.OrthographicCamera(); const composer = new EffectComposer(renderer); composer.addPass(new RenderPixelatedPass(6, scene, camera)); });}); See for yourself —
on any runtime!
on any runtime!
Terminal
gjsify showcase three-postprocessing-pixelnpx @gjsify/cli@latest showcase three-postprocessing-pixel --runtime nodebunx @gjsify/cli@latest showcase three-postprocessing-pixel --runtime bundeno run -A npm:@gjsify/cli@latest showcase three-postprocessing-pixel --runtime deno Real Three.js,
powered by GJS
import Adw from 'gi://Adw?version=1';import { WebGLBridge } from '@gjsify/webgl';import * as THREE from 'three';import { TeapotGeometry } from 'three/addons/geometries/TeapotGeometry.js';
const app = new Adw.Application({ application_id: 'gjsify.examples.teapot' });app.connect('activate', () => { const glArea = new WebGLBridge(); glArea.onReady((canvas) => { const renderer = new THREE.WebGLRenderer({ canvas }); const scene = new THREE.Scene(); const camera = new THREE.PerspectiveCamera(45); scene.add(new THREE.Mesh( new TeapotGeometry(50, 20), new THREE.MeshPhongMaterial({ color: 0xc0c0c0 }) )); });}); See for yourself —
on any runtime!
on any runtime!
Terminal
gjsify showcase three-geometry-teapotnpx @gjsify/cli@latest showcase three-geometry-teapot --runtime nodebunx @gjsify/cli@latest showcase three-geometry-teapot --runtime bundeno run -A npm:@gjsify/cli@latest showcase three-geometry-teapot --runtime deno The web game engine
Excalibur.js, natively
in GJS — no WebView
import Adw from 'gi://Adw?version=1';import { WebGLBridge } from '@gjsify/webgl';import * as ex from 'excalibur';import { startGame } from './game.js';
const app = new Adw.Application({ application_id: 'gjsify.examples.jelly-jumper',});app.connect('activate', () => { const glArea = new WebGLBridge(); glArea.onReady(async (canvas) => { const game = await startGame(canvas); // game.mute(); // toggle audio // game.pause(); // toggle pause });}); See for yourself —
on any runtime!
on any runtime!
Terminal
gjsify showcase excalibur-jelly-jumpernpx @gjsify/cli@latest showcase excalibur-jelly-jumper --runtime nodebunx @gjsify/cli@latest showcase excalibur-jelly-jumper --runtime bundeno run -A npm:@gjsify/cli@latest showcase excalibur-jelly-jumper --runtime deno Canvas 2D, drawn
with Cairo
import Adw from 'gi://Adw?version=1';import { Canvas2DBridge } from '@gjsify/canvas2d';import { start } from './fireworks.js';
const app = new Adw.Application({ application_id: 'gjsify.examples.fireworks' });app.connect('activate', () => { const canvasWidget = new Canvas2DBridge(); canvasWidget.installGlobals(); canvasWidget.onReady((canvas) => { const demo = start(canvas); // demo.effectController.particleCount = 60; // demo.effectController.autoInterval = 150; });}); See for yourself —
on any runtime!
on any runtime!
Terminal
gjsify showcase canvas2d-fireworksnpx @gjsify/cli@latest showcase canvas2d-fireworks --runtime nodebunx @gjsify/cli@latest showcase canvas2d-fireworks --runtime bundeno run -A npm:@gjsify/cli@latest showcase canvas2d-fireworks --runtime denoGet started in seconds
Terminal
gjsify create my-appnpx @gjsify/cli@latest create my-appbunx @gjsify/cli@latest create my-appdeno run -A npm:@gjsify/cli@latest create my-app
or run npx @gjsify/cli@latest --help to explore all commands