# Drive Between the Lines — Phase 0 prototype Endless driving survival game. This is the **Phase 0** skeleton from the roadmap: a drivable car on a flat plate with scattered obstacles, plus the persistent wear system that makes condition felt through the wheel. ## Running ```bash npm run dev ``` Then open http://localhost:5173. Append `?seed=anything` to regenerate the world — seeds may be numbers or words. | | | |---|---| | `W` / `S` | throttle / brake-reverse | | `A` / `D` | steer | | `Space` | handbrake (rear wheels only) | | `R` | respawn the car — **does not** repair it | ```bash npm test # sim + headless physics npm run build # typecheck + production bundle ``` ## Layout The one rule worth keeping: **`src/sim/` imports neither three.js nor Rapier.** Phases 1–4 (heat, regions, front lines, quests) are all simulation, and keeping them engine-free is what makes them unit-testable and fast-forwardable — you can run a hundred simulated days in milliseconds to tune an escalation curve without ever opening a browser. ``` src/ sim/ pure model — world generation, car condition → handling physics/ Rapier world, raycast vehicle, input → wheel forces render/ three.js scene, chase camera core/ fixed-timestep loop, seeded RNG, keyboard ui/ debug HUD carSpec.ts shared car dimensions, so body and mesh cannot drift apart ``` Data flows one way: `sim` → `physics` → `render`. Condition reaches the physics layer already digested into a `Handling` by `deriveHandling`, so there is exactly one place where "how broken the car is" turns into "how it drives". ## Notes on the state of it - **The car handles like a placeholder.** Suspension, grip, and engine numbers in `physics/physics.ts` and `sim/car.ts` are first guesses that pass a smoke test, not something tuned by feel. That tuning *is* Phase 0's verification gate. - **Wear rates are deliberately aggressive** so decline is visible in minutes rather than hours. Turn them down in `applyWear` once the curve reads right. - **No interpolation** between physics steps. Fine at 60 Hz; revisit if the step rate changes. - **Condition is not yet persisted** across reloads. IndexedDB comes with the campaign layer. - **Bundle:** ~2.7 MB raw / ~945 KB gzipped, dominated by Rapier's WASM, which `rapier3d-compat` inlines as base64. Switching to the non-compat `@dimforge/rapier3d` package serves the WASM as a separate file (~570 KB gzipped, compiled in parallel with the JS) at the cost of extra Vite plugin config. Worth doing before anyone but you plays it; not worth doing now. ## Next Phase 0's gate: drive for 15–20 minutes, feel the condition changing how the car handles, and want to keep driving anyway. Everything else waits on that.