diff --git a/README.md b/README.md index da7ca03..34fd57b 100644 --- a/README.md +++ b/README.md @@ -11,6 +11,8 @@ Endless driving survival game. - **Phase 6** — an inhabited world: traffic, people, patrols, and a live war. - **Phase 7** — sound, synthesised from the simulation. - **Phase 8** — recognition: being noticed, being hunted, and getting away. +- **Phase 9** — stakes: a crash that costs something, a death that costs + something, a chase you can lose, and a town you can navigate. ## Running @@ -28,9 +30,16 @@ seeds may be numbers or words. | `Space` | handbrake (rear wheels only) | | `R` | respawn the car — **does not** repair it | | `1`–`3` | accept a mission, when parked at a base | +| `X` | give up the mission in hand, when parked at a base | | `M` | sound on/off | | hold `R` | wipe the campaign and start over (5 seconds) | +Add `?debug=1` for the tuning readouts — heat, district standing, which band +you are in — and the debug panel. Without it the HUD tells you the car, the job +and your cover, and nothing else: several of the design gates below are about +reading the world rather than a number, and they cannot be judged with the +number on screen. + Progress saves itself every 20 seconds, and immediately whenever you take or finish a job. Saves are per seed; `?seed=x` is a separate campaign. @@ -150,6 +159,30 @@ bypass lanes around a checkpoint from none obstructed to about two thirds. You can still get around one; it means threading a maze at walking pace instead of a free detour at speed. +### Districts, and the buildings that ignore them + +Every building used to be the same grey box between four and twelve metres tall. +From the air the 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 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 twice over — it makes crossing +into the next district a visible event, and it is the only reason the exceptions +read at all. + +Because about one plot in fifty ignores its district completely: much taller, +lighter, a different shape. Those are the things you actually navigate by, and +they are floored at a height that clears 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. + ### Other deliberate choices - **Concrete never closes around the car standing in the gap.** A block spawning @@ -196,6 +229,15 @@ the most, but it pays for what *arrives*, not what you set off with. Hand-in works at *any* base, not the issuing one, because the brief is explicit that a blocked road home must never strand the player. +### Giving one up + +Park at any base with a job you have not started bringing home and `X` takes it +off you, for 12 m of front line. A target can end up behind concrete there is no +way round, and the only exit used to be holding `R` — which does not drop the +job, it destroys the campaign. It cannot be free either, or the board is a +reroll button: park, dislike the route, drop it, take another. Dropped jobs are +counted apart from finished ones. They are not runs. + ### Work you find rather than work you are given Past the line, and only when you have nothing in hand, someone occasionally @@ -229,6 +271,53 @@ This is what gives the board's reward a reason to matter. Without an economy the choice between a safe route and a risky one has no stakes; with one, the risky job is what keeps the car alive a while longer. +### What a crash actually costs + +The impact coefficients were originally written against an imagined scale. +Measured on the running game, a head-on into a building at 85 km/h comes back +from Rapier as a single contact event of about **2.5e6 N** — twenty-five units +of "impact" against the old 1e5 reference. Through the old coefficients that was +123% of the chassis and 37% of its ceiling, gone, in one step, in a game whose +missions pay about 0.3 parts. One crash ended the campaign, and the campaign had +no way to end. + +Everything is now anchored to that measured figure, and damage is capped per +step — a crash is a pile of contacts across several steps plus whatever the car +scrapes on the way to a standstill, and that sum has no natural bound. A hard +crash costs about 15% of the chassis and 5% of its ceiling. + +Baseline wear came down with it. Tyres shed 8e-5 per metre, so twelve clean +kilometres took them from new to ruined while a two-kilometre round trip paid +0.3 parts against 0.24 of condition spent. Driving perfectly barely broke even. +At a quarter of that, a typical mission spends about 0.06, so roughly two clean +runs pay for one bad crash — enough slack to gamble with, not enough to ignore. + +## Killed in action + +A car could be driven to zero in every subsystem and would keep going forever at +a wheezing thirty kilometres an hour. Nothing was at stake, so nothing was worth +protecting, so there was never a reason to take the quiet road. "Decline, not +reset" only reads as a stake if the decline can run out. + +When the **chassis** is gone, so are you. Somebody pulls you out; you come round +at the nearest base; the job in hand is written off with the car; and 25 m of +front line goes back to the enemy, through the same path a finished mission uses +so the war moves for one reason only. + +The replacement is a real car — patched to its ceilings, because one that still +needed the parts you do not have would just kill you again on the way out of the +yard — and every ceiling is 8% down on the one you wrote off. That is the +ratchet applied at the one moment repairs cannot reach. + +It stops at a floor, and that is worth being honest about: strictly it breaks +"the ceiling only ever falls". Without one, enough deaths issue a car that is +written off the instant you are handed it, and the only way out of the campaign +is wiping it. A genuinely miserable car you can still drive is the interesting +version of that ending rather than the broken one. + +Nothing about any of it is announced. The front moving against you is something +you find out by driving back out there. + ## A world with people in it Up to Phase 5 the world was scenery. Heat poured concrete on a road and that was @@ -256,6 +345,20 @@ Let the road cool and the whole thing is abandoned. **Traffic and people.** Civilian cars route across the network with somewhere to be; people wander on foot near the buildings. Both scatter when shooting starts. +**Your own side is standing in your own streets.** Liberated territory read as +empty — no patrols by design, and nobody else either — so the safest part of the +map was also the deadest, and coming home felt like arriving nowhere rather than +arriving somewhere held. Militia mirror the ambient patrols the other way up: +fourteen at home, five in contested ground, none past that, because a friendly +face on the frontier would be a safety net the setting is not supposed to have. +Crossing the map reads 14, 14, 11, 5, 0 against enemies 0, 0, 3, 4, 4 — who is +standing in the street is a more legible signal of whose ground you are on than +the palette is. + +They are placed by checking who holds the ground they would *stand* on rather +than the band the player is in, since near a border those are different answers, +and they leave when the line moves over them. + ### The war you are driving through Skirmishes break out between the two armies on contested and occupied ground, @@ -294,6 +397,20 @@ patrols — a chase you could outrun by passing more of them would be no chase. This is also the *only* thing that makes the enemy shoot at you: being a target is a state, not a property of the road you are on. +**They drive differently when they are chasing.** A patrol on its rounds does +14 m/s and a healthy car does 29, so being hunted used to mean holding `W` until +the 95 m sight radius did the rest. Chasing cars wind up to 21 m/s, which sits +deliberately between the two: faster than anyone averages through a grid of +junctions and buildings, slower than the car's top end on a clear run. So a long +trunk straight is an escape and the lanes are not — which puts the road +hierarchy under real pressure for the first time. The fast conspicuous road is +the one you want when they are behind you, and it is the one they will be +looking on next time. + +They also go **round** buildings rather than through them. Line of sight was +already blocked by them and movement was not, which made "break line of sight +and change direction" advice the world did not honour. + **Getting away** takes one of two things: - **Break line of sight for fourteen seconds.** They drive to where they last @@ -301,7 +418,10 @@ is a state, not a property of the road you are on. the move. Any glimpse resets the clock. - **Let your own side occupy them.** Hunters are patrols, not fanatics: an insurgent squad on their doorstep is a better use of their time. Enough of - them peeling off ends the chase outright. + them peeling off ends the chase outright. This is why the militia matter + mechanically as well as atmospherically — running for your own lines works + because the closer you get to home the more likely they peel off. The rule + always existed; there was simply nobody around to trigger it. Escaping does not hand your cover straight back. Suspicion drops to 0.6 and decays slowly from there — they know there is a car worth looking for, and you @@ -407,9 +527,11 @@ running diagonally, so area is nowhere near linear in depth. **You are never told which band you are in by the world itself.** Crossing a border eases the fog, the light and the palette: your own ground is open and green, contested goes flat and hazy, occupied turns dusty and closes in, the -frontier is cold and short-sighted. The HUD names the band for now, but that -line is debug scaffolding for the same reason the heat numbers are — Phase 3's -gate is telling them apart *without* being told. +frontier is cold and short-sighted. On top of the light, the population: home +ground is thick with your own people and thins to nobody past the line. The HUD +names the band only under `?debug`, for the same reason the heat numbers are +behind it — Phase 3's gate is telling them apart *without* being told, and you +cannot judge that with the answer on screen. ## The map @@ -417,6 +539,15 @@ A sketch map, top right, drawn from `Intel` rather than from the world: - **The road network's shape is always visible**, as faint dashed lines. You are an operative with a map, not an amnesiac. +- **Your own ground starts filled in.** A fresh campaign knows the pocket its + side holds — the cells, the roads through them, and the junctions as places + you have been. You are a local with a car; the war is the part you would not + know. It also fixes the board, which splits its offers into targets you have + visited and targets you have not: with nothing visited every offer came up + "new", so the known-against-new comparison the mission design turns on was not + on screen until you had wandered around for a while. None of it survives the + line moving — the map still only remembers who held a place when you last + stood in it. - **Roads you have actually seen** are drawn solid and coloured by the heat you remember on them — which is what you last saw, not what is there now. - **Ground you have driven through** is filled in, tinted by who held it *when @@ -445,13 +576,14 @@ ever opening a browser. ``` src/ sim/ pure model, no engine imports: - world, roads, heat — the map and its memory + world, roads, heat — the map, its districts and its memory radio, opportunities — texture: chatter and field work units, combat — traffic, patrols, soldiers, rounds save — the campaign as JSON regions — the front line and who holds what intel, routing, quests — what the player knows and is asked to do bases, car — where missions come from, and decline + kia — what happens when the decline runs out physics/ Rapier world, raycast vehicle, input → wheel forces render/ three.js scene, roads, markers, chase camera core/ fixed-timestep loop, seeded RNG, keyboard @@ -477,13 +609,11 @@ one place where "how broken the car is" turns into "how it drives". - **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. +- **Wear rates are tuned against the parts economy** rather than by feel: a + clean mission spends about a fifth of what it pays, and a hard crash costs + roughly two clean missions. Those ratios are the dial, not the raw numbers. - **No interpolation** between physics steps. Fine at 60 Hz; revisit if the step rate changes. -- **Nothing is persisted** across reloads — condition, heat, intel and completed - runs all reset. IndexedDB comes with the campaign layer, and `sim/intel.ts` - plus `sim/heat.ts` are the two things that most need it. - **Repairs are automatic on hand-in.** Parts get spent the moment you report back. The brief wants repair to be a physical, on-foot act with scavenged parts; that is Phase 6. @@ -499,11 +629,12 @@ one place where "how broken the car is" turns into "how it drives". gameplay shape is right; the presentation wants berms, wire, or wreckage on the outer sections. They can also clip scenery placed on the verge — both are static bodies, so physics is unaffected, but it looks wrong up close. +- **Hunters steer round buildings by trial rather than by pathfinding.** They + try seven headings, widening either side of straight-on, and take the first + that is clear. Good enough that corners work; it will not solve a cul-de-sac. - **Heat has no diegetic signal at a distance.** You learn a road is hot by arriving at the checkpoint. The brief wants it readable from patrol density and wreckage before you commit — that needs the enemy presence Phase 5 brings. -- **The heat HUD lines are debug scaffolding.** The brief is explicit that no - numeric heat meter ships; they exist to tune the curve and should come out. - **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 @@ -547,15 +678,28 @@ and people you have no reason to interact with, and a war that is obviously not about you. If firefights read as encounters staged for the player, the spacing and spawn rules in `sim/units.ts` are the dial. +**Phase 9:** three gates, and all of them are about whether anything is at +stake. + +- You slow down for a corner you would previously have taken flat, because the + car is worth protecting. If you still drive like it is a rental, `IMPACT_REFERENCE` + is too forgiving; if a single mistake ends the run, it is too harsh. +- Being hunted makes you think about *where* rather than only about the + throttle. If you still escape by holding `W` on any road at all, raise + `HUNT_SPEED`; if the chase is unloseable, the answer is more militia near home + rather than slower hunters, since being saved by your own side is the more + interesting exit. +- You can say where you are without the HUD, from the roofline and from who is + standing in the street. Districts and militia are both aimed squarely at this; + if it still takes reading a line of text, push `PALETTES` apart before + touching anything else. + Still deferred: a deeper repair economy with scavenged parts and on-foot work, car identity and disguise feeding into -heat, and expanded combat. Nothing there should be pulled forward until the loop +heat, expanded combat, and something happening when the front line reaches a +landmark — missions move it and nothing ever acknowledges that it moved. Nothing there should be pulled forward until the loop below it is proven. -The most useful thing before any of that is taking the debug lines out of the -HUD. Several gates now depend on reading the world rather than a readout, and -the scaffolding actively works against you when you sit down to judge them. - Watch for one failure mode in particular: if you find yourself taking whichever job is *nearest* and ignoring the intel line entirely, the board is decorative and the phase has not landed, whatever the reward numbers say.