Phase 1: road network and heat

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>
This commit is contained in:
dejvino
2026-08-07 07:47:19 +02:00
co-authored by Claude Opus 5
parent a66032674d
commit 506d07be5d
14 changed files with 830 additions and 49 deletions
+15 -1
View File
@@ -1,4 +1,5 @@
import type { CarCondition } from '../sim/car';
import type { HeatLevel } from '../sim/heat';
const BAR_WIDTH = 12;
@@ -7,12 +8,19 @@ function bar(value: number): string {
return '█'.repeat(filled) + '·'.repeat(BAR_WIDTH - filled);
}
export interface HeatReadout {
segmentId: number | null;
value: number;
level: HeatLevel | null;
hottest: number;
}
export function createHud(seed: number) {
const el = document.getElementById('hud')!;
let last = 0;
return {
update(speedMs: number, condition: CarCondition, now: number) {
update(speedMs: number, condition: CarCondition, now: number, heat: HeatReadout) {
// The HUD is debug scaffolding, not the real interface — 10 Hz is plenty.
if (now - last < 0.1) return;
last = now;
@@ -23,6 +31,12 @@ export function createHud(seed: number) {
`tires ${bar(condition.tires)} ${(condition.tires * 100).toFixed(0)}%`,
`chassis ${bar(condition.chassis)} ${(condition.chassis * 100).toFixed(0)}%`,
'',
// Debug only. The real game signals heat through the road itself —
// see the design brief: no numeric meter ships.
`[debug] road ${heat.segmentId === null ? 'off-road' : `#${heat.segmentId}`}`,
`[debug] heat ${bar(heat.value)} ${heat.level ?? '—'}`,
`[debug] hottest ${bar(heat.hottest)}`,
'',
`seed ${seed}`,
'WASD drive · space handbrake · R respawn',
].join('\n');