Showcases
Showcases are finished, runnable apps. One command starts one and a real GTK 4 window opens. Behind that window is ordinary web code: <canvas>, WebGL, fetch, XMLHttpRequest, RTCPeerConnection, Express. Run a few to find out whether gjsify can carry the app you have in mind. Each one is also a working template you can copy from.
Run one
Section titled “Run one”You need the gjsify CLI and at least one of gjs, node, bun and deno. Two of the ten below declare gjs only, and the table says which. Nothing to clone:
gjsify showcase # list every showcasegjsify showcase canvas2d-fireworks # run one, opens a GTK 4 windowThe CLI fetches the showcase’s npm package on demand, sets up the native typelibs it needs, and launches it. If a system library is missing, gjsify system-check names it. Add --runtime to say which of the four runs it, or leave it off and let the CLI resolve one. Choose the runtime below covers both.
On Linux the GTK 4 stack comes from your distribution on every runtime. On macOS and Windows the node, bun and deno route pulls a prebuilt GTK 4 and Adwaita closure (@gjsify/gtk-runtime-<os>-<arch>) into the same cache, so there is no system GTK to install either.
Pick a showcase
Section titled “Pick a showcase”| Showcase | What it shows | Runs on |
|---|---|---|
adwaita-storybook | Every Libadwaita widget, live, with a two-way controls panel | GJS, Node, Bun, Deno, browser |
canvas2d-fireworks | Particle fireworks on a 2D <canvas> with Adwaita controls | GJS, Node, Bun, Deno, browser |
excalibur-jelly-jumper | A 2D platformer on the unmodified Excalibur.js engine | GJS, Node, Bun, Deno, browser |
three-geometry-teapot | A Three.js scene driven by native Adwaita rows | GJS, Node, Bun, Deno, browser |
three-loader-ldraw | Three.js models streamed from disk over fetch | GJS, Node, Bun, Deno, browser |
three-postprocessing-pixel | A Three.js EffectComposer post-processing chain | GJS, Node, Bun, Deno, browser |
express-webserver | An unmodified Express 5 app serving HTTP and JSON | GJS, Node, Bun, Deno |
minimalist-browser | A browser shell: URL bar plus an <iframe> backed by WebKit | GJS, browser |
webrtc-loopback | Two peers in one process talking over an RTCDataChannel | GJS, browser |
webrtc-video | A webcam preview through getUserMedia | GJS, browser (from a checkout) |
Nine of these ship in the CLI catalog. webrtc-video needs a camera and extra GStreamer plugins, so it runs from a checkout instead.
Choose the runtime
Section titled “Choose the runtime”Seven of the ten run on all four runtimes, and --runtime says which one:
gjsify showcase canvas2d-fireworks --runtime gjsgjsify showcase canvas2d-fireworks --runtime nodegjsify showcase canvas2d-fireworks --runtime bungjsify showcase canvas2d-fireworks --runtime denoSame window, same code. What differs is underneath:
--runtime gjsruns the showcase’s--app gjsbundle. GJS is GNOME’s own JavaScript runtime, sogi://Gtkis native and nothing bridges into GTK.--runtime node,bunanddenorun its--app nodebundle, wheregi://goes through the node-gi bridge. One bundle serves all three, because Node-API is their shared native ABI.- GJS is packaged for Linux and, partially, macOS; there is no GJS host on Windows. Node, Bun and Deno reach all three operating systems. Platform Support has the per-OS state.
With no --runtime flag, the CLI runs the --app gjs bundle when gjs is on PATH, and otherwise the --app node bundle on whichever runtime the CLI itself is running on. That default is packaging, not preference. A showcase’s canonical build is its --app gjs bundle, declared as gjsify.main. Every showcase ships one, and not every showcase ships an --app node bundle.
Each showcase declares the runtimes it supports in package.json under gjsify.example.runtimes. Ask for one it does not declare and you get a clear error rather than a crash deep in the bundle. minimalist-browser and webrtc-loopback declare ["gjs"], because their native side is a WebKit view and a GStreamer pipeline reached through a typelib, so neither ships an --app node bundle. Their browser builds are unaffected: those run on the browser’s own WebKit and WebRTC.
More detail: Runtimes and the CLI reference.
Put one in a web page
Section titled “Put one in a web page”Every showcase in the catalog except express-webserver also ships a ./browser entry that mounts into any DOM container:
import { mount } from '@gjsify/example-dom-canvas2d-fireworks/browser';
const handle = mount(document.getElementById('app')!);handle.pause(); // stop the render loophandle.resume();The package name follows the pattern @gjsify/example-<category>-<name>, so adwaita-storybook is @gjsify/example-gtk-adwaita-storybook. The live demos on the showcase pages below are these same modules, mounted by the site.
Read the source
Section titled “Read the source”Every showcase lives under showcases/ in the gjsify repo. They share one layout. A platform-agnostic module holds the app itself, and a thin shell per target wraps it. src/gjs/ is the GTK shell, src/browser/ is the DOM shell, and the file in between imports nothing platform-specific.
That split is what you want to copy. Keep your app logic free of @gjsify/* imports, write against the standard APIs, and the same file runs on GTK and in a browser.
Related
Section titled “Related”- Bridge widgets explains how a
<canvas>or an<iframe>becomes a GTK widget - Adwaita widgets covers the native UI the showcases wrap around their canvases
- Getting started scaffolds your own app from the same pieces