SKILL.md
High-End Browser Western
Build the most polished small browser world, not the largest one. Every browser 3D reference that succeeds wins because scope, control, camera, art direction, loading, and sound reinforce one experience. None win by adding polygons.
This skill is the research-to-production workflow. Engine mechanics (fixed-step loop, system/view separation, cloud persistence, AI state machines) belong to build-3d-game and are not repeated here.
Non-negotiables
Ranked by how often violating them breaks builds.
- No gameplay value in React state. Headless simulation in plain JS/TS, a zustand store mirrored at ~8 Hz, React renders the HUD only.
- Full-screen game route disables SSR. Embedded 3D uses a hydration-gated wrapper. The wrong choice is the top white-screen cause.
- Fixed-timestep simulation, interpolated render. Clamp raw delta (
Math.min(raw, 0.05)), accumulate, step at fixed dt. Damping isv *= Math.exp(-k * dt), neverv *= 0.9. - WebGL2 ships; WebGPU is an opt-in preset. A failed adapter request on older mobile Safari is a black canvas, not a slow scene.
- Instance every repeated prop. One
InstancedMeshper species per LOD band. N meshes of the same thing is rejected regardless of N. - Never fetch an environment map or HDRI from a CDN at runtime. A failed fetch behind Suspense is a permanently blank scene. Bundle a small local one.
- Nothing allocates per frame. A
new Vector3()inside a frame function is a bug. Pool or hoist. - No asset ships without a license sidecar. Unclear license means rejected, not "probably fine".
- Persist through a debounced server function. Never write from the frame loop. Persist the seed plus deltas, never raw transforms or FSM states.
- Screenshot before claiming anything works. A compiling black screen is a failed build. Sandbox screenshots prove correctness only, never performance.
Memoization gate
useMemo / useCallback / memo are disallowed in game code by default. Before proposing one, state precisely: which state changes, which computation or object identity that invalidates, and which invariant makes the invalidation structurally required. Vague answers mean the defect is state-graph partitioning, not caching. In a correctly built game the frame loop reads state imperatively, React does not re-render on gameplay ticks, and there is nothing to memoize.
Workflow
- Research before selecting systems. Benchmark successful browser worlds, then design. Never adopt a library because a demo looked good.
- Write a measurable quality target before designing the map: payload, time to first interaction, frame rate, draw calls, triangles, texture memory, density, accessibility. Numbers, not adjectives.
- Design the map around gameplay loops, then shrink it until it can be polished deeply. One map, about five districts, roughly 2 km, no loading screens.
- World before player, player before mechanics, mechanics before narrative, narrative before persistence. Each stage ends with a screenshot.
- One mechanic at a time, shipped whole: systems, view, HUD, persisted record. Half-built mechanics compound.
- Optimize last, measure always. Report the 1% low, never the average.
Original-IP rule
Take inspiration from the feel, pacing, camera work, and environmental storytelling of major westerns. Copying characters, maps, missions, dialogue, branding, music, UI, or assets is out, and so is a name that reads as a variant of a protected title. Every proper noun is authored here.
Honesty rule
Mark third-party teardowns [SECONDARY] and behavioral readings [INFERENCE]. Never claim a project uses a library without the author's statement or its source. Never report a command as run unless it ran. Never report a performance number without the device and date it was measured on.
Good vs bad
Bad: "Frame rate is smooth, around 60fps" from a sandbox screenshot session, and "this reference uses Rapier" inferred from how collisions look.
Good: "58fps 1% low, 71fps median, mid-tier Android, measured <DATE>" and "[INFERENCE] collision behavior suggests a physics engine; author has not confirmed which."
Verification
Load the game and capture a screenshot of the lit, playable scene. Expect world, player, and HUD visible with a clean console. If black or dirty, the build failed regardless of compilation.
Then audit the asset manifest. Run a check that every shipped asset path has a matching license sidecar entry. Expect zero assets without one. If any lack it, pull the asset from the build until the license is verified.
Completion checklist
- [ ] Benchmarks analyzed in depth, inference and secondary sources marked
- [ ] Measurable quality target exists and is met, or has a dated gap list
- [ ] One map fully designed; first play session documented beat by beat
- [ ] Cast has full sheets; cutscenes have shot-level direction
- [ ] Every adopted asset has a verified license and a sidecar
- [ ] Renderer, terrain, and cinematic architectures each have a written decision
- [ ] Structured data validated by a runtime schema at import
- [ ] No gameplay value in React state; no per-frame allocation; repeated props instanced
- [ ] Screenshot shows the lit, playable scene; console and runtime clean
- [ ] Every route has its own head metadata, no placeholder titles
Any box unchecked: not done. Fix or say so.
Footguns
- Runtime HDRI fetch fails silently behind Suspense. Scene stays blank forever with no error surfaced. Fix: bundle a small local environment map.
- WebGPU as the default path. Older mobile Safari returns no adapter and users get a black canvas. Fix: WebGL2 default, WebGPU behind an opt-in preset.
- Per-frame allocation. GC pauses read as stutter and get misdiagnosed as scene cost. Fix: hoist scratch vectors, pool objects.
- Scaling the map before polishing it. A big rough world is worse than a small finished one. Fix: cut area until the quality target is met everywhere.
Red flags
Stop if you catch yourself saying:
- "It's probably around 60fps"
- "This project almost certainly uses <library>"
- "The license is probably fine, it was on a free-assets site"
- "We can grow the map now and polish later"
- "The screenshot can wait until the end"
Each is a violation of the honesty rule or the polish-over-size principle wearing a reasonable tone. Measure it, source it, or mark it inference.