| name | browser-engine |
| description | Build browser games that are actually PLAYABLE — 2D or 3D — not tech demos. Use for ANY request to build, prototype, or fix a game that runs in a web browser (canvas/WebGL/WebGPU) — top-down, platformer, shooter, puzzle, 3D. Kills the |
Browser Engine — playable games, not tech demos
Most AI-built browser games look like a game and play like a screensaver. A rock is drawn but you walk through it. The "physics" is x += speed with an if that half-works. It runs at 60fps until three enemies spawn, then it's a slideshow. That is the failure this skill exists to prevent.
A game is not done when it renders. It's done when it's playable: solid things are solid, movement feels good, and it holds 60fps under load. Rendering is the easy 20%.
BANNED (the default AI-game look — never ship any of these)
- Decorative "solid" objects — a sprite/mesh drawn on screen with no collision body. If you asked for a rock and got a picture of a rock, that's the bug. See game-collision.
- Whole-sprite hitboxes in top-down — making the entire tree image solid so there's an invisible wall around the leaves. Collision is the footprint, not the picture.
- Homemade
if (ax < bx + bw && ...) as the entire physics system for anything non-trivial. Fine for one AABB check; a trap as a game's collision foundation.
- Framerate-dependent movement —
x += 5 every frame. Runs double-speed at 120Hz, half-speed under load. Movement must be * dt or on a fixed timestep.
- Allocating in the game loop —
new Bullet() / [].filter() every frame → GC stutter. Pool it. See game-optimization.
- No debug view — shipping collision you've never seen. Draw every hitbox before you trust one. The debug overlay is non-negotiable.
- Reinventing an engine — hand-rolling a renderer + physics + input + audio when Phaser/Babylon exists. Reinvent only what you deliberately choose to.
- "It works on my machine" at 165Hz — never tested at 60Hz, on mobile, or with the tab throttled.
Process (in order — do NOT start coding at step 4)
- Name the genre and its collision model. Top-down, platformer, physics-sandbox, and 3D each have a different correct collision approach. Pick it now — it dictates everything. See references/stack-selection.md.
- Pick the stack deliberately (2D vs 3D, engine, physics library) from references/stack-selection.md. Default 2D → Phaser 4. Default 3D → Three.js/Babylon + Rapier. Don't hand-roll unless you can justify it.
- Know the constraints you're building against — references/browser-constraints.md. Tab throttling,
requestAnimationFrame timing, single main thread, asset loading, input latency, mobile. These shape the architecture.
- Build collision FIRST, before art. Grey boxes that collide correctly beat beautiful sprites that don't. Load game-collision and make solids solid — verified with the debug overlay — before adding a single decorative pixel.
- Build the game loop right — fixed timestep for simulation, delta-time for rendering. game-optimization/references/game-loop.md. Get this wrong and every physics bug becomes non-reproducible.
- Make it feel good — references/playability.md. Input buffering, coyote time, acceleration curves, camera. A technically-correct game that feels dead is still a failure.
- Optimize under real load — game-optimization. Pool, batch, spatial-partition. Test with 200 entities, at 60Hz, on a throttled tab.
- Verify like a player: play it. Walk into every wall. Sprint at thin walls (tunneling). Spawn 200 enemies. Resize. Tab away and back. Any walk-through, any stutter, any speed change = not done.
The three laws (memorize)
- If it looks solid, it IS solid — or it doesn't exist. No object blocks movement unless it owns a collision body registered with the physics/collision system, and you've seen that body in the debug overlay.
- Simulate on a clock, not on a frame. Movement and physics advance by time (
dt or fixed steps), never "per frame drawn." The renderer's speed must never change the game's speed.
- Never allocate in the loop. Everything that spawns during play — bullets, particles, enemies, damage numbers — comes from a pool. The steady-state game loop makes zero garbage.
Companion skills
- brainstorm-game-design — design the game's concept (pillars, core loop, hook, scope) before any code, and write it to
game-design/GDD.md in the project so no agent loses the thread.
- brainstorm-level-design — design levels/encounters from the game's own pillars, persisted to
game-design/levels/.
- game-collision — the heart. Solid bodies, footprint hitboxes, tilemap collision layers, y-sort depth (walk behind the tree), anti-tunneling, axis-separated resolution. Load it for anything that moves and must not overlap.
- game-optimization — the fixed-timestep loop, object pooling, sprite batching / texture atlases, spatial partitioning, and profiling. Load it before claiming 60fps.
Design memory — don't get lost between sessions
Before building, design should be written into the game project, not left in chat. The brainstorm modes persist decisions to game-design/ and wire AGENTS.md so every agent (Claude Code, Cursor, Antigravity, …) reloads them next session. When the user says "continue" or "add a level," read game-design/GDD.md first — it's the source of truth. See references/design-memory.md.
The playable checklist (before claiming done)