Demos

Experiments, products, and the ideas that escaped the notebook.

Everything below runs in the browser, is deployed alongside this site, and is built on the same handful of shared packages. The XR ones want a headset, and each has a button for trying it without one. Open a demo and poke at it — that is what it is there for.

WebXR game2026

Castle XR

Build a castle out of bricks on your table, then take a slingshot to it.

A board hangs below eye level in passthrough AR with a tray of bricks beside it. Build what you like, then press Ready: the bricks gain weight, a slingshot appears, and the game becomes how long your castle stays standing.

  • Bricks snap by their low corner onto a half-cell grid, so faces line up rather than centres — and the preview turns red wherever two would overlap, because a castle that explodes before the first shot is nobody's idea of a castle.
  • The slingshot has a real one's ergonomics: one hand carries the fork, the other reaches for the pouch, and the draw is the shot. At a desk, gaze aim and a held space bar feed the same arithmetic.
  • Victory waits for the rubble to settle — four still readings in a row, turning counted as well as travelling — because a rolling brick looks finished a moment before it leans on another one.
  • TypeScript
  • WebXR
  • three.js
  • Rapier physics
  • RxJS
  • Custom signal library
  • Custom reactive renderer

Language & interactive editor2015 / 2026

Euclid

A language for compass-and-straightedge constructions, with an editor that draws both ways.

A small language for the constructions in geometry handbooks — points, lines, circles and their intersections. Type a statement and the figure appears; construct by hand and the statements write themselves. The language is from a 2015 Meteor project, the editor around it a 2026 rebuild on the signal library.

  • The code is the single source of truth. Tools append statements instead of touching a scene graph, and a click on a crossing writes an expression like (c1.c2)[0] rather than baked-in coordinates, so the construction stays a construction.
  • Geometry lives on the complex projective plane, so every operation is total: circles that miss still meet in complex points, parallels meet at infinity, and rendering simply filters for what is real.
  • Selection runs both ways — click a circle in the drawing and its statement lights up in the editor; put the caret on a statement and the object it defines turns blue.
  • TypeScript
  • SVG
  • RxJS
  • Custom signal library
  • Custom reactive renderer

Strategy game2016 · rebuilt 2026

Knights

A turn based hex battle out of Heroes of Might and Magic III, by way of a 2016 meetup demo.

Two armies on a hex field, one stack at a time. The active stack stands on the red field with its reach shaded around it: click to send it somewhere, or point at an enemy to walk up and swing — the defender swings back with whatever it has left. The opponent is the computer, or a friend at the same keyboard.

  • The original is KnightsJS, written in 2016 in Meteor, React and redux for a JavaScript meetup talk in Kraków. This is that game on a signal-based core: state in plain classes, everything derived from it a memoized getter, and only the bindings whose values moved re-run.
  • Moves play out as a script — walk, land, swing, take the hit, swing back — and can be cut short mid-animation without derailing the rest of the sequence.
  • The opponent looks one turn ahead: it scores every trade it could make, damage dealt against damage taken, and walks toward the nearest enemy when none is worth taking.
  • TypeScript
  • SVG
  • RxJS
  • Custom signal library
  • Sprite animation

Rendering experiment2026

Todo App

Everyone's first app, written against the signal core and rendered twice: onto a page, and into a headset.

The classic first app, taken as a rendering exercise. On the page it is plain DOM wired to signals — components are functions, updates land as attribute and text writes, and there is no framework underneath. In the headset the same list is a floating panel: every widget still ordinary HTML and CSS, projected into the scene, down to a virtual keyboard that swings out under the input like a phone on a stand.

  • The page version holds its content back for a second on purpose, to show suspense working without a framework: a progress bar is given the same duration, so it fills up just as the todos arrive.
  • In the headset the list sits behind a scrolling window, and the portal clips whatever is below the fold — not drawn, and not a ray target either, so a Delete button scrolled out of sight cannot be pressed by accident.
  • Tapping the input summons the keyboard on a portal of its own, reclined toward the hands. At ten columns to the row each key comes out about four centimetres across — bigger than a real key, which a target at the end of a ray wants to be — and the board and the panel share nothing but the state object between them.
  • TypeScript
  • WebXR
  • three.js
  • RxJS
  • Custom signal library
  • Custom reactive renderer
  • PWA

WebXR testbed2026

Showcase XR

Four panels of ordinary HTML hanging in a scene — the test bench for the renderer behind the other demos.

The proving ground for the DOM-to-scene renderer the other headset demos are built on. Four panels hang in a shallow cockpit — interactions, images, self-running motion and the box model — each one ordinary HTML and CSS projected through a portal of its own. Point a ray at a button and it restyles through the same CSS transitions a mouse hover would play, frame by frame, in the scene.

  • Buttons answer a controller ray the way they answer a mouse: hover and press restyle through data attributes, and every change of transform or colour animates — CSS transitions, playing out inside a three.js scene.
  • The motion panel keeps one specimen per animation mechanism: CSS keyframes, the Web Animations API, and a frame loop writing inline styles. The last one takes its frames from the XR session rather than the page, because once a headset has the display the page stops rendering — and a requestAnimationFrame bar would simply stand still.
  • Both rendering bugs this renderer actually shipped passed every unit test and were caught by a person looking at the scene. The visual suite is that person, automated: an emulated headset that answers like a Quest 3, every clock frozen mid-swing, and the photographs held against pixel baselines.
  • TypeScript
  • WebXR
  • three.js
  • RxJS
  • Custom signal library
  • Custom reactive renderer

WebXR experiment2025

Polytope XR

A spherical polytope, cut into pieces, reassembled in augmented reality.

A geodesic sphere sliced into interlocking pieces that float in front of you in AR. Grab them with a controller or your bare hands and drag until neighbours snap together; the solved shape settles into a slow spin, then splits one piece further. The puzzle escalates for as long as you keep going.

  • The scene graph is driven by a reactive core rather than a frame loop — meshes, materials and geometries are declared as signals and disposed automatically when they fall out of the graph.
  • The status panel is ordinary DOM, authored as HTML and CSS and projected into the scene, so a controller ray landing on a button arrives at the markup as a click: written once, and working with a ray, a hand or a mouse.
  • Subdivision and the merge test are pure geometry, kept apart from the scene and property-tested with fast-check.
  • TypeScript
  • WebXR
  • three.js
  • RxJS
  • Custom signal library
  • Custom reactive renderer
  • PWA

Rendering experiment2025

Hex Minesweeper

Minesweeper on a hexagonal grid, built without a UI framework.

Minesweeper, except the board is hexagonal and there is no framework underneath it. The whole interface is a single SVG element wired up by a small signal library: pick a size, click to uncover a cell, right-click or long-press to plant a flag.

  • No virtual DOM. A reactive primitive updates attributes and text nodes in place, and the components are plain functions returning observables.
  • The covered area is not a pile of hexagons — its outline is traced into one SVG path, holes and all, so the board reads as a single surface.
  • Hex-to-pixel mapping, border tracing and hit testing live in a standalone geometry package, shared with the other apps built on grids.
  • TypeScript
  • SVG
  • RxJS
  • Custom signal library
  • PWA

More on the way

A few more games and XR experiments are queued up behind the ones above. They will show up here once they have had their final round of polish.