Flappy
One button, an endless procession of pipes, and no second chances — the same
apps/flappy that builds a native binary, running here.
controls
One key or one tap, plus the three the loop keeps.
- Flap Space, ↑ or tap
- Start a run, or begin again after one ends Space or the button on screen
- Restart at any time R
- Pause — and from it, fullscreen and the debug panel the PAUSE button, top right
- Pause and resume Esc
- Fullscreen F11
- Debug overlay F3
- Debug console `
- Pause, fullscreen and the debug overlay keys — unless a control for them is listed above
- Debug console, and its on-screen keyboard the CONSOLE button, once you have touched the canvas
why a second game
To find out what the first one's shape left behind.
Breakout proved the engine can host a game. A single consumer cannot tell a design from an accident, though — every convenience that happens to suit a paddle and a brick grid reads as good design until something else needs the same seam. So this one is deliberately different: continuous forward motion instead of a fixed field, pipes created ahead and destroyed behind instead of a static grid, one button instead of two axes, and no lives at all.
Every place the engine resisted that is written down rather than worked around quietly — the findings are in the roadmap, next to the phase that owes the fix.
what is actually running
The native sample, with four differences the browser forces.
Start-up is polled across several frames, because
requestDevice is a promise and the main thread cannot block on
it. The frame loop is driven by requestAnimationFrame out here
rather than by a loop inside the engine. The clock is the
browser's, because wasm32-unknown-unknown has no
Instant. And the best score lives in the Origin Private File
System instead of ~/.config.
Everything else — the ECS, the fixed-tick server, the physics, the render graph, the spatial audio — is the same code the native build runs. The course itself is not sent anywhere: gap positions are a pure function of a seed and the pipe's index, so the client and the server agree about a thousand pipes without a byte crossing between them.
console.log, so log lines are queued
inside wasm and drained by the page each frame. crcbl.audio(),
crcbl.saves() and crcbl.logLevel(4) are there too.