Jelly Jumper (Excalibur)
A small 2D platformer built with the unmodified Excalibur.js game engine and Tiled tilemaps. The same npm package runs in the browser and on GJS — Excalibur reaches for <canvas>, WebGL, XMLHttpRequest, DOMParser, ResizeObserver, and requestAnimationFrame, and every one of those calls is served by the corresponding @gjsify/* package on GJS.
Live demo
Section titled “Live demo”What it exercises
Section titled “What it exercises”| Pillar | What Excalibur needs |
|---|---|
@gjsify/webgl | WebGLBridge → Gtk.GLArea (Excalibur’s WebGL renderer) |
@gjsify/dom-elements | HTMLCanvasElement, ResizeObserver (the ancestor-walking one — see Bridges) |
@gjsify/xmlhttprequest | Excalibur’s asset loader (responseType: 'arraybuffer' + 'blob') |
@gjsify/domparser | excalibur-tiled parses the .tmx XML map files |
@gjsify/event-bridge | Keyboard input (jump / move / restart) |
@gjsify/webaudio | Sound effects via Excalibur’s WebAudio backend (GStreamer pipeline on GJS) |
This is the showcase that surfaced the ResizeObserver-on-bridge bug in v0.4.20 — DisplayMode.FillContainer mode observes canvas.parentElement, which only fires when the bridge’s GTK resize signal walks the polyfill DOM tree’s ancestors. The fix lives in @gjsify/dom-elements’s notify-resize and is what makes this showcase reflow correctly on window resize.
Run it on GJS
Section titled “Run it on GJS”gjsify showcase excalibur-jelly-jumperOpens a GTK4 window with the GLArea-backed canvas filling it. Arrow keys move, space jumps, R restarts. The Excalibur engine ticks at the GTK frame clock’s vsync.
Run it in the browser
Section titled “Run it in the browser”import { mount } from '@gjsify/example-dom-excalibur-jelly-jumper/browser';mount(document.getElementById('app')!);The asset loader fetches tilemaps + spritesheets from @gjsify/example-dom-excalibur-jelly-jumper/assets/* (resolved via require.resolve in both targets — the browser bundles them via the website’s Vite config).
Source
Section titled “Source”showcases/dom/excalibur-jelly-jumper/ — entry points: src/gjs/gjs.ts (Adw.Application + JellyJumperWindow), src/browser/browser.ts (mount module — Adwaita-styled shell + startGame(canvas)), src/browser/browser-main.ts (standalone fullscreen browser entry). Shared scene/actor code lives at the top level — src/game.ts, src/resources.ts, src/scenes/, src/actors/, src/components/, src/physics/, src/state/, src/ui/ — and runs unchanged in both targets.
Why this showcase is load-bearing
Section titled “Why this showcase is load-bearing”Excalibur is the canonical real-world consumer of the full WebGL + Canvas + WebAudio + XHR + DOMParser stack. Every time we promote a @gjsify/* package from Partial → Full, this showcase is one of the first regression checks — if Excalibur’s “FillContainer” mode reflows correctly, if its asset loader resolves binary blobs without truncation, if its WebAudio mixer plays a multi-channel sound effect without artifacts, then the gjsify port of the underlying API is genuinely production-grade.
Related
Section titled “Related”refs/excalibur/— Excalibur source, used for gap analysis against the bundled showcase.- Bridge widgets pattern — covers the WebGLBridge lifecycle that this showcase uses.
pixel-rpg/map-editor— companion downstream project that built atop the same Excalibur + Tiled stack.