Jelly Jumper (Excalibur)
A 2D platformer built with Excalibur.js 0.32 and Tiled tilemaps. The engine comes straight from npm with no fork and no patch.
A game engine written for the browser, reaching for WebGL2, <canvas>, XMLHttpRequest, DOMParser, ResizeObserver, requestAnimationFrame and WebAudio, runs inside a native Adwaita window. If gjsify can carry Excalibur, it can carry the npm library you had in mind.
Based on sample-jelly-jumper by the Excalibur team.
Live demo
Section titled “Live demo”Run it
Section titled “Run it”It declares all four runtimes, so pick the one you have:
gjsify showcase excalibur-jelly-jumper --runtime gjsgjsify showcase excalibur-jelly-jumper --runtime nodegjsify showcase excalibur-jelly-jumper --runtime bungjsify showcase excalibur-jelly-jumper --runtime denoA GTK 4 window opens with the game filling it and pause and mute buttons in the header bar. Same window and same game on all four.
| Action | Keyboard | Gamepad |
|---|---|---|
| Move | Arrow keys | D-pad |
| Jump | A | Face button 1 (A on an Xbox pad) |
| Run | S | Face button 3 (X on an Xbox pad) |
| Performance overlay | F1 |
The engine renders through WebGL2 on Gtk.GLArea. If no GL2 context is available it falls back to Canvas 2D over Cairo, the same fallback the browser build takes.
--runtime gjs runs the --app gjs bundle against GJS’s native gi://. The other three share one --app node bundle, where gi:// goes through the node-gi bridge. Leave the flag off and Choose the runtime says what the CLI picks.
Run it in the browser
Section titled “Run it in the browser”import { mount } from '@gjsify/example-dom-excalibur-jelly-jumper/browser';
const handle = mount(document.getElementById('app')!, { assetBase: '/demos/jelly-jumper/', // where the tilemaps and spritesheets live startMuted: true,});
handle.unmute();handle.pause();assetBase is what makes one resource table serve both targets. The game’s /res/... paths are rewritten against it at load time. The handle also exposes resume(), mute(), isPaused and isMuted.
Tilemaps and spritesheets ship with the package under @gjsify/example-dom-excalibur-jelly-jumper/assets/*.
What it uses
Section titled “What it uses”| Package | What Excalibur needs it for |
|---|---|
@gjsify/webgl | WebGLBridge on Gtk.GLArea, Excalibur’s WebGL2 renderer |
@gjsify/canvas2d | The Cairo fallback renderer when GL2 is unavailable |
@gjsify/dom-elements | HTMLCanvasElement and the ResizeObserver that DisplayMode.FitContainerAndFill watches |
@gjsify/xmlhttprequest and @gjsify/fetch | The asset loader, including arraybuffer and blob responses |
@gjsify/domparser | @excaliburjs/plugin-tiled parsing .tmx map files |
@gjsify/event-bridge | Keyboard and gamepad input |
@gjsify/webaudio | Sound effects, played through GStreamer in the GTK build |
Copy the structure
Section titled “Copy the structure”showcases/dom/excalibur-jelly-jumper/
Every target enters the same startGame(canvas, options) in src/game.ts. The scenes, actors, physics, components, state and UI all sit at the top level of src/ and never mention a platform. Only the shell differs. src/gjs/gjs.ts builds the Adw.Application and its window, src/browser/browser.ts exports mount(), and src/browser/browser-main.ts runs it full-page.
Per-target tuning goes through options on that one function (pixelRatio, fixedUpdateFps, enablePerf) rather than through forked code.
Related
Section titled “Related”- Bridge widgets covers the
WebGLBridgelifecycle this game sits on, including how resizes reach aResizeObserver. canvas2d-fireworksis the smaller demo on the same bridges.pixel-rpg/map-editoris a downstream project built on the same Excalibur and Tiled stack.