The problem
A portfolio should be readable in thirty seconds, but a list of links says nothing about how someone builds things. Hotfix is a small maze game inside a 3D cabinet: clear the bits, fix the bugs, and finish a run in a minute. It never blocks the page around it.
How to play
Steer a disc through three mazes. Eat every bit. A patch lets you fix bugs for points; otherwise they cost a life. Arrow keys, WASD, a swipe, or the mouse.
The name, mazes, and sprites are original. The genre is a maze chase, not a copy of any one machine.
Architecture
GameHost (fixed 120 Hz step)
├─ Game pure TypeScript: modes, maze, bugs, score
├─ renderGame draws a 320×240 Canvas 2D frame
└─ view
├─ ThreeView canvas → CanvasTexture → CRT ShaderMaterial on a curved mesh
└─ FlatView the same canvas inside a CSS cabinet (Lite mode)
The game knows nothing about how it is shown. Each animation frame, the active view asks the host to step the simulation and redraw the 320×240 canvas, then displays it.
Three decisions
A fixed timestep, separate from rendering. The game advances in steps of 1/120 s however fast the screen refreshes, so movement stays the same at 60 Hz and 144 Hz, and the engine can be unit tested without a browser. The cost is an accumulator loop and a cap on catch-up steps after a stall.
The CRT is a shader, not a post-process. The screen is its own mesh with a gentle bulge. Its material
does the barrel distortion, scanlines, aperture grille, and power-on sweep. Scanlines fade out with
fwidth once they are too fine to resolve.
Everything is procedural. The cabinet is built in code from a measured side profile. There are no model files to download, at the cost of the extra detail a hand-modelled cabinet would have.
Coins
The cabinet takes coins. Every visit comes with one, and three more are hidden around the site. Finding all of them turns on free play.
Respecting the page
- The page is readable before any 3D code loads.
- Without WebGL 2, with Save-Data on, or on low-memory devices, the site uses Lite mode instead.
- With reduced motion, the camera cuts instead of moving, and the screen does not flicker.
- Sound is off until it is turned on.
- The animation loop stops when the cabinet is scrolled out of view or the tab is hidden.
What’s unfinished
- The cabinet is modelled in code. A hand-built model would add the small irregularities that make real objects look real.
- There is no bloom pass. Glow comes from halation in the CRT shader and from emissive materials.