Skip to content

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.

Terminal
$ 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
express-webserver.ts
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');
});
Full example →
Terminal
Terminal
gjsify showcase express-webserver
Terminal
npx @gjsify/cli@latest showcase express-webserver --runtime node
Terminal
bunx @gjsify/cli@latest showcase express-webserver --runtime bun
Terminal
deno run -A npm:@gjsify/cli@latest showcase express-webserver --runtime deno
switch-row.meta.ts
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 },
],
};
Full example →
Terminal
Terminal
gjsify showcase adwaita-storybook
Terminal
npx @gjsify/cli@latest showcase adwaita-storybook --runtime node
Terminal
bunx @gjsify/cli@latest showcase adwaita-storybook --runtime bun
Terminal
deno run -A npm:@gjsify/cli@latest showcase adwaita-storybook --runtime deno
pixel-demo.ts
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));
});
});
Full example →
Terminal
Terminal
gjsify showcase three-postprocessing-pixel
Terminal
npx @gjsify/cli@latest showcase three-postprocessing-pixel --runtime node
Terminal
bunx @gjsify/cli@latest showcase three-postprocessing-pixel --runtime bun
Terminal
deno run -A npm:@gjsify/cli@latest showcase three-postprocessing-pixel --runtime deno
teapot-demo.ts
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 })
));
});
});
Full example →
Terminal
Terminal
gjsify showcase three-geometry-teapot
Terminal
npx @gjsify/cli@latest showcase three-geometry-teapot --runtime node
Terminal
bunx @gjsify/cli@latest showcase three-geometry-teapot --runtime bun
Terminal
deno run -A npm:@gjsify/cli@latest showcase three-geometry-teapot --runtime deno
jelly-jumper.ts
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
});
});
Full example →
Terminal
Terminal
gjsify showcase excalibur-jelly-jumper
Terminal
npx @gjsify/cli@latest showcase excalibur-jelly-jumper --runtime node
Terminal
bunx @gjsify/cli@latest showcase excalibur-jelly-jumper --runtime bun
Terminal
deno run -A npm:@gjsify/cli@latest showcase excalibur-jelly-jumper --runtime deno
fireworks.ts
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;
});
});
Full example →
Terminal
Terminal
gjsify showcase canvas2d-fireworks
Terminal
npx @gjsify/cli@latest showcase canvas2d-fireworks --runtime node
Terminal
bunx @gjsify/cli@latest showcase canvas2d-fireworks --runtime bun
Terminal
deno run -A npm:@gjsify/cli@latest showcase canvas2d-fireworks --runtime deno

Get started in seconds

Terminal
Terminal
gjsify create my-app
Terminal
npx @gjsify/cli@latest create my-app
Terminal
bunx @gjsify/cli@latest create my-app
Terminal
deno run -A npm:@gjsify/cli@latest create my-app

or run npx @gjsify/cli@latest --help to explore all commands