Steering. The falloff with speed was linear, so the car had already lost a third
of its lock by 20km/h — exactly the speed you take a right-angle junction at, on
a map made of right-angle junctions. It is quadratic now, which leaves low
speeds nearly untouched and still calms things down at pace, plus a faster rack
and a little more lock. Pinned with a test that drives an actual quarter turn and
measures its radius. A first attempt asserted that fast corners take longer,
which is simply false: a fast car swings through ninety degrees quicker, just
across far more tarmac. Radius is what a corner costs you.
Contact. Units were points that ignored everything, so there was nothing to hit.
Vehicles now carry kinematic bodies and ramming one is a real collision that
damages them and shoves you. People get no collider on purpose — a capsule means
snagging on pedestrians or launching them — so you drive through them and they go
down, and running over a civilian is counted for later.
Territory. Liberated ground covered more than half the map because the player
started in the middle of it, so most of the world was safe by geometry. The
starting base is now at the friendly edge and the bands are anchored to give
roughly 15/25/27/33 across liberated, contested, occupied and frontier. Measured
in the running game rather than guessed, since the axis runs diagonally across a
square and area is not linear in depth.
Also fixes a fragile test that compared reward rates across whichever targets a
board happened to offer, and so mostly measured route length rather than the
novelty premium it claimed to check.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
No audio files. The build stays self-contained, so the engine is detuned
oscillators, tyres and gunfire are shaped noise, ambience is a filtered drone.
The constraint pays: sound generated from the sim can carry the sim's state
instead of decorating it.
The engine has gears, so the note climbs and drops rather than tracking the
speedometer forever. A worn engine sounds wrong rather than merely slow —
roughness rises and the top of the rev range falls away as condition drops, so
decline is audible as well as felt. Bald tyres squeal sooner than good ones, off
the lateral slip the physics actually reports. Gunfire falls off with the square
of distance and pans as the car turns, so a firefight is a direction. Territory
has a tone: the drone drops and thickens past the line, matching the palette.
Split so it can be tested: audio/mix.ts holds every decision as plain numbers and
is covered; audio/audio.ts is only wiring, which cannot run outside a browser.
A test caught panning being mirrored — +X is the car's left in this world, so the
sine needed negating.
Also adds hold-R-for-five-seconds to wipe the campaign, with a filling meter so
it cannot happen by accident, and M to mute. Tapping R still just respawns.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Braking. Rapier brake impulses were far too small next to a 1100kg chassis, so
the car would not come to a standstill. Raised, plus a coast brake so lifting
off actually slows you and a hold below walking pace so "stop the car" for a
mission is not a fight. First attempt overshot to 1.9g, which reads as hitting a
wall; tuned to about 0.8g, ~25m from 70km/h, and pinned with tests that assert
both an upper and a lower bound on stopping distance.
Stutter. The render drew the raw latest physics transform, so frames that
consumed two steps or none landed as visible jitter at speed. Now interpolated
between the last two steps by the leftover accumulator. Buildings moved into one
instanced draw call and the minimap dropped to 10Hz, both of which were wasted
work in a frame budget that also has to fit a shadow pass.
Roads. Three classes: single-track lanes, two-lane roads, four-lane trunks that
cross the whole map and are never thinned away. Class drives width, the route
corridor, barricade span, map line weight, surface colour, and two things that
matter more: routing is now by travel time so journeys prefer trunks, and
attention scales with class, so a farm track is slow and unwatched while a trunk
is fast and the first place anyone looks.
Towns. Buildings were small and sparse enough to drive around freely. They are
now laid out on a jittered lattice — rejection sampling cannot pack boxes and
saturated at a third of the target — which takes bypass lanes around a barricade
from 0% obstructed to about two thirds. World scaled to 400m half-extent, 81
junctions, 107 roads.
Autosave. Every 20 seconds, plus an immediate checkpoint on taking and
completing a job. Saves carry the subsystem ceilings, what the player knew
including the parts that are now wrong, and where the war had got to. A save is
validated against seed, format version and array lengths before anything is
applied: half-restoring a campaign is worse than starting a fresh one.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Four allied bases, placed by greedy farthest-point so no choke point can strand
the player, with the first at the spawn junction so the loop is available at
once. Missions hand in at any base, not the issuing one.
The board offers known and new targets side by side and describes each route in
words. Crucially it never reads heat directly — it reads sim/intel.ts, a record
of what the player has actually observed and when. Notes age while roads keep
escalating unwatched, so a known route is knowable, stale, and never a promise.
Recon missions survey everything within 130m, which is how a new target becomes
a known one without driving every road there.
New targets pay 1.8x. That multiplier is the phase's tuning dial: too low and
nobody takes the unknown, too high and nobody takes the known.
Payment is parts, which repair the car. To keep "decline, not reset" intact,
each subsystem gains a ceiling that falls permanently with damage — repairs
restore up to what the car is still capable of, never to what it was. Without an
economy the board's rewards had no stakes; with one, the risky job is what keeps
the car running a while longer.
Adds Dijkstra over the road graph, taking a cost function so a "safest route"
preview is a small change later.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Roads are a jittered 7x7 grid with ~a quarter of the edges thinned out, kept
connected. The loops are the point: "take a different road" is not a decision
without alternative routes.
Every metre driven adds heat to that segment; all roads shed it slowly. Crossing
a threshold escalates Clear -> Patrol -> Barricade -> Turret, each of which puts
real obstructions on the tarmac. Hysteresis stops a road on a boundary from
rebuilding its barricade every few seconds.
Level changes are deferred while the car is on the segment. Building a barricade
around the player would spawn a static collider inside the chassis, and the
player is meant to discover escalation by returning to a road, not by watching
it assemble behind them.
Checkpoint positions are seeded from the segment id, so a stretch of road always
fortifies in the same place — recognising it is part of learning the map.
Scenery now avoids the tarmac and the car spawns at a junction.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Vite + TypeScript + three.js + Rapier raycast vehicle, fixed 60 Hz step.
Flat plate, seeded obstacle scatter, chase camera, debug HUD. Car condition
(engine/tires/chassis) degrades permanently and is derived into handling
numbers, so decline is felt through the wheel rather than read off a meter.
src/sim/ is kept free of three.js and Rapier imports — the later heat, region
and front-line systems all live there, and staying engine-free is what makes
them unit-testable without a browser.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>