Document the pass, and correct the notes it made stale
The README is this project's design document, so the reasoning behind each change belongs in it rather than only in commit messages. Adds sections on what a crash costs and why the coefficients are anchored to a measured figure, killed in action, giving up a job, districts and landmarks, militia, and how a hunter drives. Also removes three notes that had gone stale - persistence not existing, wear rates awaiting tuning, and the heat lines wanting to come out of the HUD - and replaces the "take the debug lines out first" instruction under Next with three Phase 9 gates, since all of those are now done. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
parent
6c7e67cf79
commit
1a7a4776c1
178
README.md
178
README.md
@ -11,6 +11,8 @@ Endless driving survival game.
|
|||||||
- **Phase 6** — an inhabited world: traffic, people, patrols, and a live war.
|
- **Phase 6** — an inhabited world: traffic, people, patrols, and a live war.
|
||||||
- **Phase 7** — sound, synthesised from the simulation.
|
- **Phase 7** — sound, synthesised from the simulation.
|
||||||
- **Phase 8** — recognition: being noticed, being hunted, and getting away.
|
- **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
|
## Running
|
||||||
|
|
||||||
@ -28,9 +30,16 @@ seeds may be numbers or words.
|
|||||||
| `Space` | handbrake (rear wheels only) |
|
| `Space` | handbrake (rear wheels only) |
|
||||||
| `R` | respawn the car — **does not** repair it |
|
| `R` | respawn the car — **does not** repair it |
|
||||||
| `1`–`3` | accept a mission, when parked at a base |
|
| `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 |
|
| `M` | sound on/off |
|
||||||
| hold `R` | wipe the campaign and start over (5 seconds) |
|
| 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
|
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.
|
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
|
can still get around one; it means threading a maze at walking pace instead of a
|
||||||
free detour at speed.
|
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
|
### Other deliberate choices
|
||||||
|
|
||||||
- **Concrete never closes around the car standing in the gap.** A block spawning
|
- **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
|
works at *any* base, not the issuing one, because the brief is explicit that a
|
||||||
blocked road home must never strand the player.
|
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
|
### Work you find rather than work you are given
|
||||||
|
|
||||||
Past the line, and only when you have nothing in hand, someone occasionally
|
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
|
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.
|
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
|
## A world with people in it
|
||||||
|
|
||||||
Up to Phase 5 the world was scenery. Heat poured concrete on a road and that was
|
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
|
**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.
|
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
|
### The war you are driving through
|
||||||
|
|
||||||
Skirmishes break out between the two armies on contested and occupied ground,
|
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
|
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.
|
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:
|
**Getting away** takes one of two things:
|
||||||
|
|
||||||
- **Break line of sight for fourteen seconds.** They drive to where they last
|
- **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.
|
the move. Any glimpse resets the clock.
|
||||||
- **Let your own side occupy them.** Hunters are patrols, not fanatics: an
|
- **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
|
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
|
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
|
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
|
**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
|
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
|
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
|
frontier is cold and short-sighted. On top of the light, the population: home
|
||||||
line is debug scaffolding for the same reason the heat numbers are — Phase 3's
|
ground is thick with your own people and thins to nobody past the line. The HUD
|
||||||
gate is telling them apart *without* being told.
|
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
|
## 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
|
- **The road network's shape is always visible**, as faint dashed lines. You are
|
||||||
an operative with a map, not an amnesiac.
|
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
|
- **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.
|
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
|
- **Ground you have driven through** is filled in, tinted by who held it *when
|
||||||
@ -445,13 +576,14 @@ ever opening a browser.
|
|||||||
```
|
```
|
||||||
src/
|
src/
|
||||||
sim/ pure model, no engine imports:
|
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
|
radio, opportunities — texture: chatter and field work
|
||||||
units, combat — traffic, patrols, soldiers, rounds
|
units, combat — traffic, patrols, soldiers, rounds
|
||||||
save — the campaign as JSON
|
save — the campaign as JSON
|
||||||
regions — the front line and who holds what
|
regions — the front line and who holds what
|
||||||
intel, routing, quests — what the player knows and is asked to do
|
intel, routing, quests — what the player knows and is asked to do
|
||||||
bases, car — where missions come from, and decline
|
bases, car — where missions come from, and decline
|
||||||
|
kia — what happens when the decline runs out
|
||||||
physics/ Rapier world, raycast vehicle, input → wheel forces
|
physics/ Rapier world, raycast vehicle, input → wheel forces
|
||||||
render/ three.js scene, roads, markers, chase camera
|
render/ three.js scene, roads, markers, chase camera
|
||||||
core/ fixed-timestep loop, seeded RNG, keyboard
|
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
|
- **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,
|
`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.
|
not something tuned by feel. That tuning *is* Phase 0's verification gate.
|
||||||
- **Wear rates are deliberately aggressive** so decline is visible in minutes
|
- **Wear rates are tuned against the parts economy** rather than by feel: a
|
||||||
rather than hours. Turn them down in `applyWear` once the curve reads right.
|
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
|
- **No interpolation** between physics steps. Fine at 60 Hz; revisit if the step
|
||||||
rate changes.
|
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
|
- **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
|
back. The brief wants repair to be a physical, on-foot act with scavenged
|
||||||
parts; that is Phase 6.
|
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
|
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
|
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.
|
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
|
- **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
|
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.
|
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
|
- **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`
|
`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
|
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
|
about you. If firefights read as encounters staged for the player, the spacing
|
||||||
and spawn rules in `sim/units.ts` are the dial.
|
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
|
Still deferred: a deeper repair economy
|
||||||
with scavenged parts and on-foot work, car identity and disguise feeding into
|
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.
|
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
|
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
|
job is *nearest* and ignoring the intel line entirely, the board is decorative
|
||||||
and the phase has not landed, whatever the reward numbers say.
|
and the phase has not landed, whatever the reward numbers say.
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user