Cutting straight from the crash to a base three hundred metres away
read as a bug rather than as a death, and the one moment in a campaign
worth actually looking at was the one moment the player was not allowed
to see it.
The run now ends five seconds after the car does. Control goes; the
camera leaves the bumper and climbs away to sixty metres, turning
slowly, until the street, whatever was hit and whoever is standing
around watching are all in frame. The point of the shot is not the car
- by then the car is a fact - it is *where* this happened, which is the
thing you have to drive back out to.
The world keeps running underneath it. A death cam over a frozen world
is a screenshot, not a moment. What stops is the driver: no throttle,
no board, no overhaul, and no quietly finishing the job by virtue of
having stopped moving on top of the target.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Every building was the same grey box between four and twelve metres
tall. From the air the whole world was one texture; from the driver's
seat every junction looked like the junction before it, and "learn the
map" was not something the map supported.
The world is now cut into districts, and a district agrees with itself:
its buildings share a palette, a rough height and a silhouette and vary
only slightly around them. That agreement is the point - it is what
makes crossing into the next one a visible event, and it is the only
reason the exceptions read at all.
Because the occasional building ignores its district completely: much
taller, lighter, a different shape. Those are the things you actually
navigate by. They clear every ordinary roofline on the map, since a
landmark you cannot see from outside its own district is no use in the
only place you need it.
Colour rides on the instance rather than the material, so a district
costs no extra draw calls. Colliders stay boxes whatever the silhouette
says - both the physics and the line-of-sight grid already assume a
building is solid to its own footprint.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Three fixes, all from watching it run.
Cars stuck against buildings. routeTo dropped the node a route starts from,
which is fine for a unit standing on it and wrong for anything re-routing from
mid-segment: its first leg became a straight line to a node two hops away,
across buildings and open country. Routes now include their start node so a unit
rejoins the road before setting off.
No patrols anywhere. They only existed as a reaction to the player's own tracks,
so hostile territory was empty until you had personally made a road notorious.
Enemy ground now carries standing patrols by how dangerous it is — none behind
your lines, five on the frontier — spawned onto their roads so the territory has
them the moment you arrive.
This surfaced a second bug: dispatched units were culled at 546m from the player
while dispatch origins reached 600m, so a patrol or engineer could be deleted on
its first step and simply never turn up. Anything with an assignment is now kept
regardless of range; its expiry still bounds it.
Barricades appearing instantly. Crossing a heat threshold placed concrete on the
road with nobody involved. Construction is now staged: an engineer is dispatched
for the barricade, another for the tower, and heatProps is driven by finished
builds rather than by heat levels. It still refuses to close a slab around a car
parked in the gap.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Nothing on a road simply appears any more. A road that turns notorious gets a
patrol dispatched to it: it starts at a junction a few hundred metres away,
drives there, sweeps the road for about a minute, and while it works the road it
brings the heat down — then leaves. Checkpoints are built rather than placed. At
turret level an engineer is sent, the tower rises over forty seconds of someone
standing on site, and a gunner mans it once it stands, up on top so he clears his
own barricade. Let the road cool and the whole thing is abandoned. heat.ts now
only pours concrete; everything living has to arrive.
Civilian traffic routes across the network with somewhere to be, people wander on
foot, and both scatter when shooting starts.
Skirmishes break out between the two armies on contested and occupied ground
regardless of where the player is. Rounds are real objects in flight rather than
instant hits between combatants — that is the point of the feature. If shots
resolved instantly, driving through a battle would cost nothing and "the only
road to the target runs through a firefight" would not be a decision. Strays hit
bystanders, civilians and the player alike; buildings stop them, so cover means
something; hits go through the same wear model as a crash, so being shot costs
ceiling too.
The enemy does not shoot at an undercover driver by default. They open up only
past the line and only on a road they have already checkpointed.
Reload was being counted in stepUnits while firing lived in stepCombat, so combat
stepped on its own never reloaded. A test caught it; ownership now sits with the
module that fires.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
The pane this build runs in does not composite, so requestAnimationFrame never
fires, the loop stalls, and nothing can be screenshotted from outside. Adds a
`?debug=1` handle that steps the simulation by hand and renders on demand, plus
a dev-only endpoint that takes a POSTed frame and writes it to shots/. Moving
the image as bytes rather than a pasted data URL matters: a truncated base64
string decodes to nothing.
Looking at the result immediately found a real problem. Base beacons were wide
translucent cylinders — legible from a distance, a solid green wall from inside,
and the car parks in the middle of one. Now a slim pillar plus a ring on the
ground that marks where to stop. Also raised the sky and fog brightness, which
was dark enough to read as night.
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>
Three things, all tangled together enough to land at once.
Regions. A single directional front cuts the map into liberated, contested,
occupied and frontier. Heat accrual behind your own lines is exactly zero, not
merely small — a trickle would eventually fortify your own back garden, and
would mean the safe area quietly punished you for using it. Decay is judged by
whoever holds the road, not whoever holds the ground the car is standing on.
Modelled as one front rather than blobs of territory because the brief wants the
line to move in both directions, and Phase 4 can then just slide the offsets.
Territory is signalled by tone, never by the world announcing itself: crossing a
border eases the fog, light and palette between four looks. Phase 3's gate is
telling occupied from liberated without being told, so the HUD line naming the
band is debug scaffolding like the heat numbers.
Minimap. There was no way to tell where a target was. The map is drawn from
Intel, not from the world: the road network's shape is always faintly visible,
but only roads actually seen carry remembered heat, only ground actually driven
through is filled in, and the front line is dashed in only where both sides of
it have been explored. Adds a coarse fog-of-war grid to Intel, plus an
eight-point compass arrow in the HUD.
Base huts. The building was centred on the junction, so the starting hut sat
directly over the car and hid it. Huts now stand off the junction, in whichever
direction is furthest from tarmac, and are solid.
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>