End-to-end test plan
The source of truth for feature coverage: one row per meaningful user-facing behavior, linked to the Playwright test that proves it by its @E2E-nn tag. npm run e2e-plan (part of validate) fails when this table and the specs under tests/e2e/specs drift apart. How to keep it current is in AGENTS.md ("End-to-end test plan"); how the suite is organized is in tests/README.md.
Tiers
| Tier | Tag | Needs | Budget | Runs |
|---|---|---|---|---|
| smoke | @smoke | A built client (npm run build -w apps/client) | < 3 min | npm run test:e2e:smoke; CI job on every push and PR |
| core | @core | Nothing (headless Chromium + one game server per level folder) | 20 s a test on the self-hosted runner; the tier 12 min in its five lanes alone | npm run test:e2e; every pull request and push to develop, beside the smoke tier: the gate |
| long | @long | The same | none | npm run test:e2e -- --project=long; every night on develop and before a release is published |
Every test carries exactly one tier tag, at least one area tag (@app, @drive, @net, @ai, @platform) and its plan id. A test slower than the gate's 20 seconds is made faster or goes to long; every test-* level keeps a core test (its only one may take longer). npm run e2e-plan checks the budgets against the recorded seconds (tests/e2e/timings.json).
Coverage
Status: implemented (a tagged test exists), planned (write it next), blocked (needs a product or tooling change first; say which).
| Id | Feature | Area | Tier | Spec | Status |
|---|---|---|---|---|---|
| E2E-01 | The Electron app boots from the built bundle, connects to the given server and shows the HUD | app | smoke | smoke/electron.spec.ts | implemented |
| E2E-16 | With no server given, the Electron app opens on the main menu, set in Changa from the bundle over file://, with no game server of its own: nothing listens on its port until Play local → Host starts the bundled server on the city picked (FOI_PORT, 7777 by default) and plays it; the pause menu says where friends on the network join (the machine's addresses and the port); Play local stays offline with Steam handing out a ticket and a platform named that does not answer: nothing is signed in | app | smoke | smoke/electron.spec.ts | implemented |
| E2E-17 | The field on the Server tab of the legend card reconnects the page to the given server (host:port or a full URL) | app | core | levels/test-core-gameplay/app/overlay.spec.ts | implemented |
| E2E-02 | Throttle accelerates the car along its heading, steering turns it, the handbrake slows it | drive | core | levels/test-core-gameplay/drive/drive.spec.ts | implemented |
| E2E-03 | Prediction keeps corrections under 0.5 m at a simulated 150 ms RTT, boosting included, and can be toggled off with P | net | core | levels/test-core-gameplay/net/prediction.spec.ts | implemented |
| E2E-04 | A second player is shown as a remote car on both screens and disappears when they leave | net | core | levels/test-core-gameplay/net/prediction.spec.ts | implemented |
| E2E-05 | Off the jump ramp the car flies and comes down on its four wheels; R puts a car back at a spawn, at rest on its wheels | drive | core | levels/test-core-gameplay/drive/ramps.spec.ts | implemented |
| E2E-06 | Visual regression: a still frame of the core level and the player's car (noon, the clock stopped, no pedestrians) matches the baseline kept for its platform and renderer (GPU or software); where none exists yet it skips (npm run test:e2e:snapshots or the e2e-snapshots workflow writes them) | app | core | levels/test-core-gameplay/app/visual.spec.ts | implemented |
| E2E-07 | V switches the car to the next of twenty-three vehicle classes (six cars, three trucks, three two-wheelers, the police car, the city's taxi, bus, ambulance, fire truck and garbage truck, then the pickup, the limo, the delivery scooter, the ice-cream van and the tractor) on one press, in place (the change is the server's: the car shows exactly one new class, never flipping back or a class too far, and does not move; a press during the half-second cooldown is kept for when it ends); the HUD names the class, its engine placement and drivetrain | drive | core | levels/test-core-gameplay/drive/vehicle-class.spec.ts | implemented |
| E2E-08 | A powerful rear-wheel drive (the muscle car) spins its rear tyres under full throttle: the HUD flags SPIN and rear grip drops | drive | core | levels/test-core-gameplay/drive/vehicle-class.spec.ts | implemented |
| E2E-18 | Double-tapping and holding W boosts (extra engine, enough to power-drift) while the meter lasts; the meter refills while driving on and a new double tap boosts again; the HUD shows the meter and BOOST | drive | core | levels/test-core-gameplay/drive/boost.spec.ts | implemented |
| E2E-19 | S against the direction of travel brakes hard (80 km/h to a stop in a few metres), then reverses at up to 108 km/h, straight from a standstill too; the HUD marks reverse with R | drive | core | levels/test-core-gameplay/drive/reverse.spec.ts | implemented |
| E2E-20 | The car is drawn interpolated between ticks: at speed no frame moves it zero or two ticks' worth (no periodic hitch) | drive | core | levels/test-core-gameplay/drive/smooth.spec.ts | implemented |
| E2E-21 | Driving over a nail strip pops the tyres that cross it; the HUD shows each flat as ✕ and FLAT; flats drag and cost top speed; R puts new tyres on | drive | core | levels/test-core-gameplay/drive/tyres.spec.ts | implemented |
| E2E-22 | The number keys select the inventory's slots and what the player holds is the selected slot's weapon: in free roam's arsenal 1 is the fists' empty slot, 2–6 the pistol, shotgun, rifle, rocket launcher and grenades (the HUD names the weapon with its ammunition); seated, only the pistol selected, the HUD saying why another does not fire from a car; a click fires; hitscan shots show as tracers on every player's screen | net | core | levels/test-core-gameplay/drive/weapons.spec.ts | implemented |
| E2E-23 | On foot, the rocket launcher and the grenade put a projectile in the world that flies or bounces, then blows up (a flash that shoves cars and people; no damage yet) | drive | core | levels/test-core-gameplay/drive/weapons.spec.ts | implemented |
| E2E-24 | On foot the character faces the mouse cursor (Hotline Miami style: the body moves along the keys, the facing follows the mouse, the view leans toward it) | drive | core | levels/test-core-gameplay/drive/weapons.spec.ts | implemented |
| E2E-25 | The van, the box truck and the semi are classes; the semi tows a trailer that follows the cab on a ball joint (eighteen tyres in all; the HUD shows the cab's six wheels) | drive | core | levels/test-core-gameplay/drive/trucks.spec.ts | implemented |
| E2E-26 | The scooter, the bicycle and the motorbike ride on two wheels held upright by the simulation, lean into turns on screen and keep going through a turn | drive | core | levels/test-core-gameplay/drive/trucks.spec.ts | implemented |
| E2E-27 | Pedestrians walk the avenues around the plaza as remote characters nobody owns; they are not counted as other players | net | core | levels/test-core-gameplay/drive/trucks.spec.ts | implemented |
| E2E-28 | A minimap in the bottom-right corner shows the whole city north-up with the player's marker where the car is, other players and the nail strips | app | core | levels/test-core-gameplay/drive/trucks.spec.ts | implemented |
| E2E-29 | Fists: on foot a click throws a punch that shoves whoever stands within reach in the front half-circle; pedestrians go down | drive | core | levels/test-core-gameplay/drive/weapons.spec.ts | implemented |
| E2E-30 | From inside a car only the pistol selected fires, and only into the front half-circle of the car: the fists or the rifle selected, nothing fires and the HUD says to select the pistol (2) | drive | core | levels/test-core-gameplay/drive/weapons.spec.ts | implemented |
| E2E-31 | A pedestrian a car hits above 20 km/h tumbles, hurt by the car's speed (the log: so much left), and gets up a few seconds later; above 35 km/h it dies and comes back at its post (the legend's Player page stands one 25 m ahead) | drive | long | levels/test-core-gameplay/drive/hits.spec.ts | implemented |
| E2E-09 | E gets the player out of the car; on foot WASD walks, Shift runs, Space jumps and the character faces the mouse; E next to a car gets back in | drive | core | levels/test-core-gameplay/drive/character.spec.ts | implemented |
| E2E-11 | A hard landing dulls the controls for a moment and the HUD shows LANDING, then not | drive | core | levels/test-core-gameplay/drive/ramps.spec.ts | implemented |
| E2E-12 | The bridge is driven over, the tunnel through under its fading roof, the garage up to its first floor; a jump ramp met from behind is a wall | drive | long | levels/test-core-gameplay/drive/structures.spec.ts | implemented |
| E2E-15 | On foot, the character walks up and down the terrace's and the garage's stairs | drive | core | levels/test-core-gameplay/drive/stairs.spec.ts | implemented |
| E2E-13 | The overlay (React) shows the key legend on the Keys tab of the legend card and switches language with the card's button (i18next) | app | core | levels/test-core-gameplay/app/overlay.spec.ts | implemented |
| E2E-14 | The music toggles with the overlay button and M (quiet while the radio plays); the engine follows the car and the tyres scrub only while drifting (audible only, not asserted) | app | core | levels/test-core-gameplay/app/overlay.spec.ts | implemented |
| E2E-10 | A second player walks to the first player's car, gets in as a passenger and rides along when it drives | net | long | levels/test-core-gameplay/drive/character.spec.ts | implemented |
| E2E-32 | The game opened without ?server= (?play), from the page the Vite dev server serves, joins the game over WebSocket on its own origin (/game, proxied to the game server): one port to forward in Codespaces | net | core | levels/test-core-gameplay/net/prediction.spec.ts | implemented |
| E2E-33 | Shots pitch up and down to the target on the line of fire (a dummy on the ground, on a pedestal, on a tower); the mouse wheel picks which of several at different heights; the HUD names the target and its height | drive | long | levels/test-core-gameplay/drive/combat.spec.ts | implemented |
| E2E-34 | Pedestrians take damage: a shot knocks one down (it topples over, never stands dead like a pin; the HUD logs the hit) and ten seconds later it stands at its post again with full health | drive | long | levels/test-core-gameplay/drive/combat.spec.ts | implemented |
| E2E-35 | Cars take damage (the HUD shows the health of the car and logs every hit); a wrecked car answers nobody, keeps its own paint as it was until it blows up (its shell charred then, never red) and cannot be entered | drive | core | levels/test-core-gameplay/drive/combat.spec.ts | implemented |
| E2E-36 | Q at a wall or a car, whichever way the character faces, takes cover: hidden, the character cannot shoot or be shot (crouching behind low cover), walks along the cover but not away from it; the right mouse button pops up and hides again; Q leaves | drive | core | levels/test-core-gameplay/drive/combat.spec.ts | implemented |
| E2E-37 | Health: the HUD shows the player's hit points and logs the hits taken; at zero the player goes down and respawns at the nearest spawn point with full health | drive | long | levels/test-core-gameplay/drive/combat.spec.ts | implemented |
| E2E-38 | The HUD hides and shows with the legend panel's HUD button and with H; the legend and the minimap stay | app | core | levels/test-core-gameplay/app/overlay.spec.ts | implemented |
| E2E-39 | Pressed against a high wall, the character walks to its end and stops there; the right button leans it out past the edge (PEEKING: a line of fire at the targets the wall hid, a shot hits) and back behind it | drive | core | levels/test-core-gameplay/drive/combat.spec.ts | implemented |
| E2E-40 | The HUD's character line shows the stance on foot (standing, walking, running, in the air, crouching, pressed against the wall, peeking), where it faces and where it stands; the character is drawn flattened against tall cover | drive | core | levels/test-core-gameplay/drive/character.spec.ts | implemented |
| E2E-41 | Backspace, or the legend's button, resets the whole level: every player back in a fresh compact at their spawn, new pedestrians, no projectiles | net | core | levels/test-core-gameplay/app/level.spec.ts | implemented |
| E2E-42 | The grenade is cooked while the click is held (the HUD shows the seconds left), thrown toward the cursor on release (up to 50 m) with the rest of the fuse, and goes off in the hand after 3 s | drive | core | levels/test-core-gameplay/drive/weapons.spec.ts | implemented |
| E2E-43 | The legend card folds away with its Hide button and comes back with the Legend button left in its place | app | core | levels/test-core-gameplay/app/level.spec.ts | implemented |
| E2E-44 | The NPCs' view cones (90°, 12 m, red when they see the player) toggle in the game and on the minimap, separately, from the legend's View tab | app | core | levels/test-core-gameplay/app/level.spec.ts | implemented |
| E2E-45 | The bicycle makes no sound; every other class has an engine to hear | app | core | levels/test-core-gameplay/drive/trucks.spec.ts | implemented |
| E2E-47 | The server runs the level FOI_LEVEL names (a bundled test-* or main-* level, main-riverbend by default (E2E-249), or the path of a .json level file) and announces it in the welcome: the client builds its world from it and the HUD names it; a level given as a .json file boots the same | app | core | levels/test-core-gameplay/app/level.spec.ts | implemented |
| E2E-48 | Every exported level boots: its server starts, the client joins, the HUD names it, and the View tab's Colliders box (or ?colliders=1) draws the collision meshes as a wireframe over the level and hides them again | app | long | levels.spec.ts | implemented |
| E2E-49 | A nail strip pops the tyres of a car that crosses it at any speed: each wheel's path since the last tick is swept against the strip, so a sports car at top speed (nearly a metre per tick, twice the strip's width) loses all four tyres on the strip at the north end of the avenue | drive | core | levels/test-core-gameplay/drive/tyres.spec.ts | implemented |
| E2E-56 | The level's roads (polylines with lanes and a speed) arrive in the welcome and are drawn as ribbons on the level and as strips on the minimap | app | core | levels/test-ai-pathfinding/app/level.spec.ts | implemented |
| E2E-50 | The legend's Chasers panel spawns an NPC on foot with the chosen style behind the player (unarmed when its box is unticked); it closes in and holds the style's approach distance (the readout and the HUD line say chase and the distance); Clear removes it | ai | core | levels/test-ai-pathfinding/ai/chase.spec.ts | implemented |
| E2E-51 | A guard spots the player in its view cone and chases; out of its sight for longer than the profile's lose-sight time it searches where it last saw them, then returns home (readout modes alert, chase, search, return, idle) | ai | long | levels/test-ai-pathfinding/ai/chase.spec.ts | implemented |
| E2E-52 | The legend's Spawn in a car drops a chaser at the wheel on the road behind the player (30 m back, in the lane toward them); it follows the road graph and closes on the player's car driving along it (the readout shows it seated, the distance shrinking, the HUD line says car) | ai | core | levels/test-ai-pathfinding/ai/car-chase.spec.ts | implemented |
| E2E-53 | A chaser in a car dropped behind a player who has walked where cars cannot follow (into the zigzag enclosure through its 4 m gap) drives up to where the car's grid ends, gets out there and reaches the player on foot through the gap | ai | long | levels/test-ai-pathfinding/ai/loop.spec.ts | implemented |
| E2E-54 | On foot through the obstacle course a pursuit chaser reaches the player beyond the zigzag walls through their gaps, never standing still for more than three seconds on the way | ai | long | levels/test-ai-pathfinding/ai/course.spec.ts | implemented |
| E2E-55 | FOI_CHASERS_FOOT / FOI_CHASERS_CAR / FOI_CHASER_PROFILE pre-spawn chasers at boot (a server a spec starts for itself), the readout and the HUD list them, and /health reports the AI counts and step time | ai | core | levels/test-ai-pathfinding/ai/options.spec.ts | implemented |
| E2E-46 | Crashes cost a car hit points by the speed lost in the impact (the log says a crash did it); a car nearly wrecked (the legend's car health) is wrecked by the same hit | drive | core | levels/test-core-gameplay/drive/hits.spec.ts | implemented |
| E2E-57 | The Chasers panel's Style page picks the chasing style with a mouse click on its chip (the chosen one highlighted) and explains in a few lines how that style chases and reacts; the pages turn with the arrows | ai | core | levels/test-ai-pathfinding/ai/panel.spec.ts | implemented |
| E2E-58 | The Car tactics page sets what a chaser spawned in a car does (shoot from the car, ram, get out and fight), its crew and its car's class: a crew of three in a sedan arrives as three seated chasers, every one an enemy drawn in orange | ai | core | levels/test-ai-pathfinding/ai/panel.spec.ts | implemented |
| E2E-59 | The Player page's infinite health makes the player immortal: the HUD reads ∞, an armed chaser's shots land for no damage, and the switch comes off again | ai | core | levels/test-ai-pathfinding/ai/panel.spec.ts | implemented |
| E2E-60 | A chaser the player's car knocks down (reversing into it above 20 km/h) tumbles, hurt, and is back on its feet chasing within a few seconds; one that is killed lies in its own colours | ai | core | levels/test-ai-pathfinding/ai/knockdown.spec.ts | implemented |
| E2E-62 | A click on the legend (a button, a chip, its own text) or on the minimap is never a shot and leaves the trigger up; the right button over the legend does not pop the player up; the wheel over it leaves the target pick alone (over the game it steps); the keys drive the game right after the click, with no click on the canvas | app | core | levels/test-core-gameplay/app/input.spec.ts | implemented |
| E2E-63 | Typing in the legend's server field drives nothing: W, Space, E, R, V, a digit and Backspace go into the field (the car stands still and keeps its class, the level is not reset) and Enter connects; back on the game the keys work | app | core | levels/test-core-gameplay/app/input.spec.ts | implemented |
| E2E-64 | The overlay fits the window: at 800×500 the legend card spans its column under the HUD, scrolls inside itself and overlaps neither the HUD nor the minimap, which shrinks; at 1920×1080 it is a card in the corner and the minimap is full size; the tabs (Keys, View, Chasers, Server) switch the sections and keep the others mounted | app | core | levels/test-core-gameplay/app/responsive.spec.ts | implemented |
| E2E-65 | The player's car and everyone else on screen are the low-poly models of their class, loaded from models/vehicles.glb and models/character.glb (wheels where the simulation's are; the body tinted per player, orange for an enemy; a wreck in its own paint, charred once it has blown up, the dead in their own colours; wireframe boxes until the files arrive), swapped when the class changes and drawn centred on the car in every class; on foot the player is the character model; a car's collider is the convex hull of its body and of its wheels above the body's floor | app | core | levels/test-core-gameplay/app/models.spec.ts | implemented |
| E2E-67 | Driving under a structure held over the ground fades it: in test-curves' tunnel under the central hill the roof (the hillside over the cutting) is drawn see-through while the car is inside, and solid again once it is out | drive | core | levels/test-curves/app/tunnel.spec.ts | implemented |
| E2E-68 | Without a GPU (a software rasterizer such as SwiftShader, as on a CI runner) the game draws cheaper: no antialiasing and two thirds of the resolution along each axis, and the HUD says so on its connection line | app | core | levels/test-core-gameplay/app/render.spec.ts | implemented |
| E2E-69 | Light pieces of a level (hydrants, street lamps, traffic lights, benches, bins: placements with a breakable mass) stop a sedan slower than 60 km/h and stand; a sedan at 60 km/h or more (the kinetic energy that fells one) knocks one loose (it flies off as a body of its mass, every client sees it) and drives on, leaving the batch it was baked into (its triangles there folded away, its own instance drawing it where it lies); a level reset plants them again, back in their batches | drive | core | levels/test-breakables/drive/breakables.spec.ts | implemented |
| E2E-70 | A game's first mission starts when the player joins: the mission panel shows its title, its first objective with its step (1/3) and the start notice; its target is drawn in the world (a ring and a beacon) and as a ring on the minimap | app | core | levels/test-mission-basics/app/mission-tracker.spec.ts | implemented |
| E2E-71 | A mission plays through: driving into the checkpoint moves the tracker on to stealing the parked rental (Dispatch's phone message arrives), taking its wheel to delivering it against the clock (a rule's line shows), driving into the drop-off completes it and pays $400 and 20 Rep into the wallet | drive | long | levels/test-mission-basics/drive/mission-run.spec.ts | implemented |
| E2E-72 | A level reset starts the player's mission over from its first objective, the player back at their spawn | app | core | levels/test-mission-basics/app/mission-tracker.spec.ts | implemented |
| E2E-74 | The Games tab signs the player in with an email and a password instead of the device's guest (the account named, kept across page loads) and signs them out again, back to the guest | platform | core | platform/rooms.spec.ts | implemented |
| E2E-80 | A level generated from a level spec boots: test-generated-town, built by the grid-town template of the Blender generator (assets/blender/levels/generate.py), arrives in the welcome with its one terrain mesh, its seven streets drawn as ribbons and on the minimap and its buildings, and the player starts in a lane of a street | app | core | levels/test-generated-town/app/level.spec.ts | implemented |
| E2E-81 | Driving a generated town: the car spawned in a lane of a street of test-generated-town, facing along it, drives straight on for a few seconds and stays on the street, near its centre line, on every frame drawn | drive | core | levels/test-generated-town/app/drive.spec.ts | implemented |
| E2E-549 | A road's lines give way to the level's own paint (@foi/world's roadPaint): on test-generated-town some steps of its edge and lane lines stop at its zebra crossings and stop lines, and no step drawn lies over that paint (read back off the meshes drawn) | app | core | levels/test-generated-town/app/road-paint.spec.ts | implemented |
| E2E-85 | A published game is found on the legend's Games tab (the page signs in as a guest), played in a room of its own on a game server the platform API opens it on (the room runs the game's missions), and a second player joins that room from the tab: both play in the same room | platform | core | platform/rooms.spec.ts | implemented |
| E2E-86 | The Games tab says when the platform cannot be reached | platform | core | platform/rooms.spec.ts | implemented |
| E2E-87 | A game on a level generated from a level spec: a creator's draft on a spec (that of test-generated-town) is built by the Blender generator in the API's process, its game (take a compact at a generated junction, deliver it to another) published; the room opened from the Games tab plays on the generated town (named after the draft, its seven streets drawn) with the mission's car at the generated place. Skips itself where Blender is not installed (CI); the API side is covered without Blender by apps/api's tests | platform | core | platform/generated.spec.ts | implemented |
| E2E-550 | A level generated from a spec is audited before anybody plays it (@foi/world's auditLevel and its repair, in the worker or the API's process): a region's draft built through the platform reports what the audit left out (here nothing) and the faults left (none), and passes; a build that left pieces out says how many and why in a warning, never an error (apps/api's tests word it) | platform | core | platform/generated.spec.ts | implemented |
| E2E-551 | A city from a spec (test-city, the city template: solved by @foi/catalogue's city solver, built by city.py): the car drives north up its street over the river on its bridge at the town's height, its wheels down, never down to the water a level below, and stays on the street | drive | core | levels/test-city/drive/city.spec.ts | implemented |
| E2E-552 | The city's roundabout is one way in three arcs: the car follows them round, the whole way round, on the carriageway | drive | long | levels/test-city/drive/city.spec.ts | implemented |
| E2E-553 | A game on a city generated from its spec through the platform: a draft on test-city's spec is solved in the API and built by Blender in its process, its game (take a compact waiting at the spec's place by the bridge, bring it to the roundabout's place) published; the room plays on the generated city with the mission's car at that place. Skips itself where Blender is not installed (CI) | platform | long | platform/generated.spec.ts | implemented |
| E2E-90 | Carjacking: at the driver's door of another player's stopped car (free roam lets players hurt each other) E pulls the driver out, knocked down on foot at the driver's door just outside the car, and after a beat gets in at that door and drives off; both HUD logs say so (you carjacked the compact, player N carjacked your car) | drive | long | levels/test-core-gameplay/drive/carjack.spec.ts | implemented |
| E2E-91 | A chaser crew parked in its car (a guard crew of three, FOI_CHASERS_CAR), come up to from the side unseen, is carjacked: the driver is thrown out, the crew gets out, all of them flee (the readout says flee), and the player drives off in their car | drive | core | levels/test-ai-pathfinding/drive/carjack.spec.ts | implemented |
| E2E-92 | The interaction prompt above the character on foot (the in-game UI's, drawn in the scene) says what E would do: Get in beside an empty car, Get in as passenger behind an occupied one, Carjack at its driver's door; nothing while seated | drive | long | levels/test-core-gameplay/drive/carjack.spec.ts | implemented |
| E2E-95 | Mission logic: on test-mission-logic, "Hold the Lot" starts as the player enters the lot and runs a defend objective with its hold clock on the tracker; a while rule (the player within the lot) spawns a wave of mission enemies every eight seconds, capped at two by a counter the objective's text shows (0/2, 1/2, 2/2) with the HOA's message per wave; the enemies are drawn as enemies; the clock completes the mission, pays $300 and 15 Rep and despawns the group | app | core | levels/test-mission-logic/app/hold-the-lot.spec.ts | implemented |
| E2E-96 | Mission branches: on test-mission-logic, "Pivot Season"'s first objective runs out of time and its next.failed leads to a different second objective instead of failing the mission (its fail line shown): survive the two investors it spawns for 20 s on the hold clock, which completes the mission with the branch's reward ($100, 5 Rep) | app | long | levels/test-mission-logic/app/branch.spec.ts | implemented |
| E2E-100 | Tyre effects on test-drift-pad: rolling straight leaves nothing; a handbrake drift on the asphalt pad lays black tyre marks along the sliding wheels' paths (lifted over the road and its paint) and puffs light grey tyre smoke, no dust | drive | core | levels/test-drift-pad/drive/effects.spec.ts | implemented |
| E2E-101 | Tyre marks fade: once the car stops sliding, the newest mark grows fainter and every mark is gone about twenty seconds after it was laid | drive | long | levels/test-drift-pad/drive/effects.spec.ts | implemented |
| E2E-102 | Off-road, the same slide puffs dust instead of smoke (the ground under the wheel read from the level: the dirt patch and its dirt track) and lays brown ruts | drive | core | levels/test-drift-pad/drive/effects.spec.ts | implemented |
| E2E-103 | Seats: a character in a seat is drawn there, at the vehicle model's seat anchor in the seat's pose (a rider astride, a pillion, the buggy's driver and passenger, a car's people behind its glass); the player's own rider shows on the scooter and the bicycle and at the wheel of a closed car, and leaves and comes back with E | app | long | levels/test-drift-pad/app/riders.spec.ts | implemented |
| E2E-104 | A car that flies off the ramp (boosted up the run, test-drift-pad) throws up a ring of dust where it lands | drive | core | levels/test-drift-pad/drive/effects.spec.ts | implemented |
| E2E-105 | Hit sparks: a pistol shot that stops on a wall (the shipping container south of the pad) throws a burst of sparks there, and so does a shot that hits a car | drive | core | levels/test-drift-pad/drive/sparks.spec.ts | implemented |
| E2E-110 | Ambient traffic on test-traffic-junction (sixteen cars, FOI_TRAFFIC): the cars drive the lanes, and one coming up to the cross while its approach's light is red stops at the line (the readout's red), the lamps over its approach drawn red by the client from the junction's plan and the tick; when they turn green it drives on | ai | long | levels/test-traffic-junction/ai/lights.spec.ts | implemented |
| E2E-111 | Ambient cars queue behind each other at the red light: the next car in the lane stops behind the one at the line (the readout's queue), a gap between their bumpers | ai | long | levels/test-traffic-junction/ai/queue.spec.ts | implemented |
| E2E-112 | Ambient cars give way at a T junction without a light: a car that came up after another, across whose way it goes, waits at its line (the readout's giveway), then goes on | ai | core | levels/test-traffic-junction/ai/give-way.spec.ts | implemented |
| E2E-113 | Carjacking an ambient car: parked across its lane, the player holds a car up, walks to its driver's door and presses E; the driver is thrown out and flees on foot (the readout's walkers say flee), the car leaves the traffic and the player drives it; the HUD logs the carjack | ai | long | levels/test-traffic-junction/ai/carjack.spec.ts | implemented |
| E2E-114 | Gunfire scares the ambient traffic: pistol shots near cars on the street make their drivers speed away (the readout's panic) or bail out and run (flee) | ai | core | levels/test-traffic-junction/ai/panic.spec.ts | implemented |
| E2E-120 | Police: on test-police (the one level server with police), gunfire near the range dummies raises the Heat into a star (the Wanted stars top centre, wanted ★ on the HUD); a police car comes from out of sight and its officer spots the player (the stars flash); the police cars carry their light bars | ai | core | levels/test-police/ai/crimes.spec.ts | implemented |
| E2E-121 | Police: carjacking another player’s car on test-police raises the carjacker’s Heat (a star), never the victim’s | ai | core | levels/test-police/ai/crimes.spec.ts | implemented |
| E2E-122 | Losing the police: hidden in cover at a wall on test-police, wanted at two stars (the legend’s Player page), the player is never seen; the stars come down one at a time (15 s unseen at two, 10 s at one) and the police cars give up and go | ai | long | levels/test-police/ai/lose.spec.ts | implemented |
| E2E-123 | An arrest: on foot and standing still at one star on test-police, the officer of the police car that comes walks up and arrests the player: back at a spawn point, the stars cleared, the fine shown under the stars and in the hits log | ai | core | levels/test-police/ai/arrest.spec.ts | implemented |
| E2E-130 | Items on the ground on test-inventory: out of the car, the prompt names the first-aid kit lying nearby (E Pick up First-aid kit), E picks it up and the inventory strip shows it; G drops the selected slot's items a step ahead, on the ground again | drive | core | levels/test-inventory/drive/items.spec.ts | implemented |
| E2E-131 | Using an item: F at full health leaves the first-aid kit be; hurt by a grenade held past its fuse, F heals 50 and the kit is used up | drive | core | levels/test-inventory/drive/items.spec.ts | implemented |
| E2E-132 | A crate's panel on test-inventory: E opens it (E Open) into a panel of what it holds and what the player holds; a click on its cash takes it into the player's Cash (the wallet), on its keycard into the strip, a click on the player's puts it back; the game's keys still work while it is open (X selects the next slot); E closes it | app | core | levels/test-inventory/app/crate.spec.ts | implemented |
| E2E-133 | A car's trunk: behind the player's car standing still with nobody at its wheel, E Open trunk opens its panel; the first-aid kit put in stays there when the trunk is closed and opened again | drive | core | levels/test-inventory/drive/items.spec.ts | implemented |
| E2E-134 | A mission of items (Parcel Run, test-inventory's game): collect three parcels lying east of the spawn (each counted on screen), deliver them in the depot's zone (handed over, gone from the inventory), the mission completes and pays | app | core | levels/test-inventory/app/mission.spec.ts | implemented |
| E2E-135 | A locked door on test-interaction: without its key the prompt says E Locked and E leaves it shut; with the office key lying nearby picked up, E Open door swings it open, unlocked for good, the player walks in and Office Hours (use the front door) completes | drive | core | levels/test-interaction/drive/doors.spec.ts | implemented |
| E2E-136 | An unlocked door: shut, it stops the player; E swings it open with its collider and the player walks through; E Close door shuts it | drive | core | levels/test-interaction/drive/doors.spec.ts | implemented |
| E2E-137 | A locker opens from its front only: beside it the key offers nothing, in front of it E opens its panel (Locker: cash and a keycard) and a click takes the keycard | app | core | levels/test-interaction/app/locker.spec.ts | implemented |
| E2E-140 | The phone on test-phone: T takes it out over the game (its panel drawn in the scene), which goes on (W still drives the car under it and S brakes it); its home lists Messages, Contacts, Calls, Map and the installed RentaCar; while it is out the number keys press its numbered buttons instead of selecting a slot (the weapon held stays) and Esc goes back a page; put away with T, the number keys select the slots again | app | core | levels/test-phone/app/phone.spec.ts | implemented |
| E2E-141 | A message from a contact at the mission's start (message): a notice, the unread count on the phone's Messages tile, read once the Messages page shows; a reply button sends the reply once (shown as "You: …", the buttons gone) and runs its actions (Mo's answer on screen) | app | core | levels/test-phone/app/calls.spec.ts | implemented |
| E2E-142 | A call (call): the phone rings over its page; answered, the dialogue's lines and choices; a choice sets a flag and the call's end (dialogue:<id>.ended) brings the message that flag allows; the call log keeps it (answered) | app | core | levels/test-phone/app/calls.spec.ts | implemented |
| E2E-143 | Calling from Contacts, listed newest first (Gary's, added three seconds in, goes on top and the contact under the pointer stays where it was): a contact with a dialogue (addContact's) answers with it, one without does not answer; a ringing call declined is logged and heard about (dialogue:<id>.declined) | app | core | levels/test-phone/app/calls.spec.ts | implemented |
| E2E-144 | Talking face to face: E Talk at a contact a mission put in the world opens their dialogue in the phone's panel; a choice whose condition fails answers and stays; the conversation's end puts the phone away and does the talk objective | app | core | levels/test-phone/app/world.spec.ts | implemented |
| E2E-145 | An app as data: the RentaCar app's Unlock says so beyond 10 m of the rental car and, within 10 m (near), hands over the car's key (key:vehicle:rental_car, in the inventory strip) and goes to its next screen | app | core | levels/test-phone/app/world.spec.ts | implemented |
| E2E-146 | A keypad door: E Enter code opens a keypad in the phone's panel; a wrong code says so and the door stays locked; the code from a contact's message opens it (unlocked, swung open) and does the unlock objective | app | core | levels/test-phone/app/world.spec.ts | implemented |
| E2E-147 | A terminal: E Hack at the Smart Kiosk opens its app's screen in the phone's panel from the world; a button whose condition fails says so, another sets the waypoint (a mission action) and goes on; walking away closes it and puts the phone away | app | core | levels/test-phone/app/world.spec.ts | implemented |
| E2E-148 | The map app: a click on its map drops a waypoint there (on the minimap too, with an arrow at its edge); Clear removes it | app | core | levels/test-phone/app/phone.spec.ts | implemented |
| E2E-149 | Each player's phone is their own: one player's reply and the call it brings reach neither the other player's phone nor their message's replies | app | core | levels/test-phone/app/calls.spec.ts | implemented |
| E2E-150 | The city's vehicle classes: on test-new-vehicles, V reaches the taxi, the bus, the ambulance, the fire truck and the garbage truck in turn after the police car (and goes on to the pickup); the HUD names each with its layout and fittings (taxi · front engine · rear-wheel drive · roof sign, fire truck · … · light bar, siren, ladder), the car is drawn as its own model in its livery | drive | long | levels/test-new-vehicles/drive/classes.spec.ts | implemented |
| E2E-151 | Light bars flash: at the wheel of the police car, the ambulance and the fire truck each lamp of the light bar lights in turn in the livery's pattern (both lamps on their own at some point); the taxi has a lit roof sign and no light bar | drive | long | levels/test-new-vehicles/drive/emergency.spec.ts | implemented |
| E2E-152 | Sirens: G at the wheel of the ambulance switches its siren on (the HUD says SIREN, it is heard) and off again; a change of class switches it off; in a taxi G only honks | drive | long | levels/test-new-vehicles/drive/emergency.spec.ts | implemented |
| E2E-153 | A bus seats several players: one drives it, another walks up to its side (the prompt offers a ride), gets in as a passenger with E (passenger in a bus, seat …) and rides along when it moves off | drive | long | levels/test-new-vehicles/drive/bus.spec.ts | implemented |
| E2E-160 | Locked cars on test-locks-garages: at a parked car of a vehicle spawner, locked and nobody’s, the prompt says E Locked · hold to pick and a press leaves it shut; with its key (an item tagged key:vehicle:bay-1) picked up on the street by it, E Unlock unlocks it and gets in: the car is the player’s | drive | core | levels/test-locks-garages/drive/locks.spec.ts | implemented |
| E2E-161 | Picking a lock: E held at a locked car without its key shows E Picking… and how far (the server’s word); after three seconds the car is unlocked and the player’s. Unseen it raises no Heat; by the range dummy watching bay-3 it raises the Heat (a crime, under a star) | drive | long | levels/test-locks-garages/drive/locks.spec.ts | implemented |
| E2E-162 | A car’s key kept in a crate: taken out of the crate’s panel, it unlocks the car parked in front of it (E Unlock) | drive | long | levels/test-locks-garages/drive/locks.spec.ts | implemented |
| E2E-163 | A vehicle spawner: once its car is driven away (the legend’s Go to), another locked car, nobody’s, stands in its bay ten seconds later | drive | long | levels/test-locks-garages/drive/locks.spec.ts | implemented |
| E2E-164 | A respray: at the wheel of a car standing still in the garage’s bay (Go to, the driveway), its panel offers 1 Respray $50 and 2 Store free; 1 (or a click) repaints the car, takes the cash and clears the Wanted level the police did not see | drive | core | levels/test-locks-garages/drive/garage.spec.ts | implemented |
| E2E-165 | A respray under the police’s eyes (the level’s server runs with police): once an officer sees the player in the bay, 1 repaints the car but the stars stay | drive | core | levels/test-locks-garages/drive/garage.spec.ts | implemented |
| E2E-166 | Storing a car: 2 in the garage puts the player out where it stood and keeps it (the stored cars); on foot in the empty bay E Take out compact brings it back, the player at its wheel | drive | core | levels/test-locks-garages/drive/garage.spec.ts | implemented |
| E2E-167 | A mission of locks (Repo Season, test-locks-garages’s game): the yard starts it and giveKey hands over the van’s key; E Unlock at the locked van does the unlock objective; the van in the garage’s bay does the deliver to a garage (garage:<id>.entered heard), and the mission completes | app | core | levels/test-locks-garages/app/mission.spec.ts | implemented |
| E2E-168 | The tag over the car the player looks at on foot: Yours by their own car, Locked at a locked one, Locked · your key once they carry its key | app | core | levels/test-locks-garages/drive/locks.spec.ts | implemented |
| E2E-169 | The RentaCar on test-phone stands locked (E Locked · hold to pick at its door); the key its app hands over unlocks it: E Unlock and the player is at its wheel | app | core | levels/test-phone/app/world.spec.ts | implemented |
| E2E-170 | The page of games (?browse) lists a published game as a card: its preview (the level seen from above, the picture its build stored, 384 px across), its title, its creator, its rating ("Not rated yet") and its blurb, the card linking to the game's page | platform | core | platform/pages.spec.ts | implemented |
| E2E-171 | The legend's Games tab links to the page of games, which lists the published games | platform | core | platform/pages.spec.ts | implemented |
| E2E-172 | A game's page (?game=<id>) shows the game, its preview and its missions; Play opens a room of it that runs its missions, and a second player joins that room with the page's Join: both play in the same room | platform | core | platform/pages.spec.ts | implemented |
| E2E-173 | Rating a game on its page: a guest's stars change its average, another player's rating counts too, the page keeps the guest's own stars when loaded again, and rating again replaces them | platform | core | platform/pages.spec.ts | implemented |
| E2E-174 | A report sent from a game's page (a reason and a few words) reaches the moderators' list through the API; their takedown takes the game off the page of games, and its page says it was taken down | platform | core | platform/pages.spec.ts | implemented |
| E2E-175 | Remixing a game from its page: a guest cannot (the button waits for a creator's account), a player signed in with an email can; the remix is a draft of theirs, credited to the game, and the page shows the Claude Code command that continues it (draft_get of the new draft) | platform | core | platform/pages.spec.ts | implemented |
| E2E-176 | The page of games finds games by the words of its search box (kept in the address) and sorts them: newest first, top rated (the best average first) and featured (the moderators' pick first, marked) | platform | core | platform/pages.spec.ts | implemented |
| E2E-180 | Hearing on test-stealth: the gatekeeper (at its post, facing west) hears a pistol shot it cannot see, 25 m off: suspicious, a "?" over its head, and it turns to the shot | ai | core | levels/test-stealth/ai/hearing.spec.ts | implemented |
| E2E-181 | The alert cycle: walking into a guard's view cone makes it suspicious, then alert ("!"), and it shoots; hidden against the shed's wall, the player is out of its sight: it leaves its post for where it saw them last, searches, goes on caution and walks back to its post | ai | long | levels/test-stealth/ai/alert.spec.ts | implemented |
| E2E-182 | The camera over the gate sweeps its cone over the approach: it spots the player in it after a moment, the player is SEEN and the gatekeeper, 30 m off within the camera's call, comes alert; the compound's alert is ALERT | ai | core | levels/test-stealth/ai/camera.spec.ts | implemented |
| E2E-183 | The tranquilizer: the darts lying beside the car picked up, 7 selects its slot (the HUD counts the darts); a dart into a guard 24 m off hurts nothing and puts it to sleep a few seconds later (not on the spot), a "z" over it | drive | core | levels/test-stealth/drive/tranquilizer.spec.ts | implemented |
| E2E-184 | A body found: in the east yard two guards face each other; the one put to sleep by a dart from out of both cones is seen by the other, which raises the alarm (alert, the player still hidden), walks to it, shakes it awake and searches | ai | core | levels/test-stealth/ai/body.spec.ts | implemented |
| E2E-185 | The knockout: round to the gatekeeper's back unseen, fists (1) and a punch knock it out without a scratch (the log says no damage), a ✱ over it lying down, its alert never raised | drive | core | levels/test-stealth/drive/knockout.spec.ts | implemented |
| E2E-186 | Searching a body: beside the knocked-out gatekeeper the prompt says E Search; E opens its pockets in the container panel (Pockets) and a click takes its keycard | app | core | levels/test-stealth/app/search.spec.ts | implemented |
| E2E-187 | The keycard gate: along the compound's wall (out of the camera's cone) the gate says E Locked and stays shut; with the gatekeeper's keycard (knocked out, searched) E Open door opens it, unlocked for good, and the player walks in | drive | long | levels/test-stealth/drive/gate.spec.ts | implemented |
| E2E-188 | Clean Exit (test-stealth's mission) completed unseen: the gatekeeper knocked out and searched, the gate opened with its keycard, the night clerk (the mission's NPC) knocked out from behind, the Q3 synergy report taken, back out the gate: complete | app | long | levels/test-stealth/app/mission.spec.ts | implemented |
| E2E-189 | Clean Exit fails as soon as the player is seen (walking into the camera's cone over the gate): "You were seen." | app | core | levels/test-stealth/app/mission.spec.ts | implemented |
| E2E-190 | Stealth on screen: the badge under the Wanted level says HIDDEN, then SEEN (and the HUD's line) once the camera sees the player, and the alert; the minimap always draws every guard's view cone and the camera's, the legend's cone toggle draws them in the world (the camera's on the ground before the gate) | app | core | levels/test-stealth/app/hud.spec.ts | implemented |
| E2E-210 | Two players become friends on the legend's Social tab (one asks by name, the other accepts); the friend shows online and playing the other's game, and joins that room from the friend's row | platform | core | platform/social.spec.ts | implemented |
| E2E-211 | A party of two (started on the Social tab, a friend invited and joining) lands in the room its leader opens: the member's page follows into the same room, both in one party | platform | core | platform/social.spec.ts | implemented |
| E2E-212 | A party in a room shares its mission: both trackers on the same objective, and the leader reaching its zone moves the member's tracker on too | platform | core | platform/social.spec.ts | implemented |
| E2E-213 | The party's channel and a direct message (from a friend's row) reach the other player in the chat, marked by their channel | platform | core | platform/social.spec.ts | implemented |
| E2E-214 | The room's chat: a line, a quick-chat phrase and an emote reach the other player of the room, each worded in their language | platform | core | platform/social.spec.ts | implemented |
| E2E-215 | In a public room, a line with a word the moderation refuses reaches nobody but its sender, who sees it marked hidden | platform | core | platform/social.spec.ts | implemented |
| E2E-216 | In a private room (a game shared by link) the same line is not moderated: the other player reads it | platform | core | platform/social.spec.ts | implemented |
| E2E-217 | A player muted from the room's players on the Social tab: their lines leave the chat of whoever muted them (their own chat still shows them) | platform | core | platform/social.spec.ts | implemented |
| E2E-218 | A third player voted out by the other two (a vote started on the Social tab, a Yes in the chat's vote): disconnected, off the room's roster, the room says so | platform | long | platform/social.spec.ts | implemented |
| E2E-219 | A report of a player from the room's players reaches the moderators' queue with the player's name | platform | long | platform/social.spec.ts | implemented |
| E2E-220 | Enter opens the chat (closed, it takes no key from the game): the keys typed there never drive, Enter sends the line to the room's other player, Esc hands the keys back | net | core | levels/test-safe-zones/net/chat.spec.ts | implemented |
| E2E-221 | In a game's safe zone a player at the wheel is never carjacked: at the driver's door the prompt offers a ride; out of the zone it offers the carjack | net | long | levels/test-safe-zones/net/griefing.spec.ts | implemented |
| E2E-222 | Shots between players in a safe zone deal no damage (the hit log says so); out of it they hurt | net | core | levels/test-safe-zones/net/griefing.spec.ts | implemented |
| E2E-223 | A player shot down comes back as a ghost for the game's few seconds (see-through, to themselves and to the others), then solid again | net | core | levels/test-safe-zones/net/griefing.spec.ts | implemented |
| E2E-249 | A server started without FOI_LEVEL runs main-riverbend, the city that ships | app | core | levels/main-riverbend/app/default.spec.ts | implemented |
| E2E-250 | test-compound, the walled compounds' level, boots: a 3 × 2 town round Zenful Campus (its title on the minimap), its game's loadout in the strip (the tranquilizer on 2 with twelve darts, the pistol on 3 with six rounds), the night's clock at half pace, the compound's guards and its four cameras watching, the player hidden | app | core | levels/test-compound/app/compound.spec.ts | implemented |
| E2E-251 | A guard's break by the room clock: at twenty-five to the hour the lab's guard leaves its post for the staff's picnic table, off guard (its phone out, the minimap drawing its cone short), and at ten to it comes back to its post, on guard | ai | long | levels/test-compound/ai/schedules.spec.ts | implemented |
| E2E-252 | A shift change by the room clock: at six the day gatekeeper walks into the guardhouse and vanishes indoors as the night gatekeeper comes out of it and takes the post | ai | long | levels/test-compound/ai/schedules.spec.ts | implemented |
| E2E-253 | The gap: from the street beyond the compound's west wall, through the stretch that fell in, into the zen garden behind it, unseen | drive | long | levels/test-compound/drive/ways-in.spec.ts | implemented |
| E2E-254 | The roof: up the fire stairs outside the annex built across the north wall to its landing six metres up, across the annex's roof, down the stairs inside, onto the ground within the walls, unseen | drive | long | levels/test-compound/drive/ways-in.spec.ts | implemented |
| E2E-255 | The lab's guard, off guard on its break at the picnic table, its back to the player: knocked out from behind, its pockets searched (E Search) give a keycard | drive | long | levels/test-compound/drive/lab.spec.ts | implemented |
| E2E-256 | The lab is a building one walks into: its sliding door, locked by a keycard, opens with E to the keycard out of the lab's guard's pockets and stays unlocked, its roof fades over the player inside, where the Calm Pod stands, and comes back outside | drive | long | levels/test-compound/drive/lab.spec.ts | implemented |
| E2E-257 | The camera on its mast inside the main gate, shot from the avenue's pavement out of its cone with the game's pistol, over the wall: destroyed, it stops watching; the other three still watch | drive | core | levels/test-compound/drive/camera.spec.ts | implemented |
| E2E-259 | The main gate keeps out a person without a keycard: before its door the prompt says Locked and E leaves it shut, the barrier across the drive down and locked | app | long | levels/test-compound/app/compound.spec.ts | implemented |
| E2E-260 | The animation gallery (/?anim-gallery, no server) shows every clip of the library on a labelled mannequin, the states' order first, each playing, a clip that holds or fires a weapon with that weapon's model in its hands (the pistol, the rifle, the shotgun, the launcher, a grenade); R knocks its row of ragdolls down, flung, and they get up again | app | core | levels/test-on-foot/app/gallery.spec.ts | implemented |
| E2E-261 | On foot the player's figure sways idle standing, shows the walk walking and the run running (Shift), its stride played by the distance covered | drive | core | levels/test-on-foot/drive/moves.spec.ts | implemented |
| E2E-262 | A jump rises and lands; walked off the 5 m ledge the player falls (arms flailing), then lands hard or rolls on | drive | core | levels/test-on-foot/drive/moves.spec.ts | implemented |
| E2E-263 | Behind low cover the player crouches, crouch-walks along it and pops up to aim; flat against tall cover, its back to the wall, it side-steps along it and peeks out past its end | drive | core | levels/test-on-foot/drive/cover.spec.ts | implemented |
| E2E-264 | A pistol is held out in one hand and kicks when fired; a rifle is held in both hands and kicks too | drive | core | levels/test-on-foot/drive/weapons.spec.ts | implemented |
| E2E-265 | The fists punch (and stay up a moment after); a grenade is wound up while held, then thrown | drive | core | levels/test-on-foot/drive/weapons.spec.ts | implemented |
| E2E-266 | Getting out of a car the player steps out of it; getting back in it steps in | drive | core | levels/test-on-foot/drive/rides.spec.ts | implemented |
| E2E-267 | Astride the bicycle the player pedals; astride the motorbike it rides leaning to the bars | drive | long | levels/test-on-foot/drive/rides.spec.ts | implemented |
| E2E-268 | The player bends down to pick an item up, opens the crate and rummages in it while it is open, pushes a door open | app | core | levels/test-on-foot/app/hands.spec.ts | implemented |
| E2E-269 | The phone out (T) is held in the hand and looked at, over whatever the legs do; put away, the hand is free | app | core | levels/test-on-foot/app/hands.spec.ts | implemented |
| E2E-270 | At a terminal the player types; face to face with a contact it gestures as it talks | app | core | levels/test-on-foot/app/hands.spec.ts | implemented |
| E2E-271 | A guard at its post stands looking around; a guard on its patrol walks with its pistol held low | ai | core | levels/test-on-foot/ai/guards.spec.ts | implemented |
| E2E-272 | A guard hearing a shot it cannot see turns suspicious toward it | ai | core | levels/test-on-foot/ai/guards.spec.ts | implemented |
| E2E-273 | A guard put to sleep by a dart goes limp to the ground (a ragdoll that comes to rest) and lies asleep | ai | core | levels/test-on-foot/ai/guards.spec.ts | implemented |
| E2E-274 | A person run over goes limp, flung along the car's way (the cosmetic ragdoll), and comes to rest | drive | core | levels/test-on-foot/drive/falls.spec.ts | implemented |
| E2E-275 | A knockdown topples along the hit: a punched person falls the way the punch went | drive | core | levels/test-on-foot/drive/falls.spec.ts | implemented |
| E2E-276 | A survivor lies limp while stunned, its body near the server's capsule, then gets up where the server stands it, without a jump | drive | core | levels/test-on-foot/drive/falls.spec.ts | implemented |
| E2E-277 | A person shot dead leaves a body that comes to rest and lies still | drive | core | levels/test-on-foot/drive/falls.spec.ts | implemented |
| E2E-278 | An emote picked in the chat plays over the player's character (and shows in the chat), then hands back | app | core | levels/test-on-foot/app/emote.spec.ts | implemented |
| E2E-279 | Another player sees the player's phone out in its hand and the recoil of its pistol (the act byte of the snapshots, the phone of the input) | net | core | levels/test-on-foot/net/remote.spec.ts | implemented |
| E2E-280 | test-buildings, generated from a level spec with six districts of six satire themes, arrives with its districts tinted and titled on the minimap (their names, titles and themes) and every building of the downtown and civic kits standing in it | app | core | levels/test-buildings/app/districts.spec.ts | implemented |
| E2E-281 | Driving down the main street of test-buildings (east from its middle, then west in reverse) draws a building of every family (civic, commercial, residential, industrial, transport) and every building fronting the street | app | long | levels/test-buildings/app/main-street.spec.ts | implemented |
| E2E-282 | A body shop's open bay is a garage where its anchor stands (the generator put it there): the legend's Go to puts the car in it nose in, its panel offers a respray for $150 and storage for free, and 2 stores the car | app | core | levels/test-buildings/app/anchors.spec.ts | implemented |
| E2E-283 | A car rental's bays hold its locked cars where its anchors stand (vehicle spawners the generator put there): at a driver's door E Locked · hold to pick, and holding E picks the lock and the car can be driven | app | long | levels/test-buildings/app/anchors.spec.ts | implemented |
| E2E-290 | A race won on test-race: after the countdown the player passes the four race gates in order (the legend's Go to puts the car in each) before the rival drivers finish; the mission completes and pays | drive | core | levels/test-race/drive/race.spec.ts | implemented |
| E2E-291 | A race lost on test-race: the two rival drivers (the game's driver actors) drive the circuit at full speed through its gates in order; one finishes first and the mission fails with the race's words | ai | long | levels/test-race/ai/rivals.spec.ts | implemented |
| E2E-292 | A race on the HUD: the countdown, then the lap, the next gate of how many and the player's position among the racers; the tracker's target is the next gate and the minimap's arrow at its edge points to it | app | core | levels/test-race/app/race-hud.spec.ts | implemented |
| E2E-293 | A restricted zone that raises the alert (test-city-life's compound yard, reaching over the gate's drive): the guards turn suspicious at once, the mission hears of the trespass, the alarm a few seconds on | ai | core | levels/test-city-life/ai/zones.spec.ts | implemented |
| E2E-294 | A restricted zone that raises the Heat (test-city-life's lawn by the range dummy): driving onto it in sight of somebody is a crime, the mission hears of the trespass | ai | core | levels/test-city-life/ai/zones.spec.ts | implemented |
| E2E-295 | The police come out of the level's spawn point of the police role (test-city-life's station on the ring) | ai | core | levels/test-city-life/ai/spawns.spec.ts | implemented |
| E2E-296 | The ambient traffic comes out of the level's spawn points of the traffic role (test-city-life, eight cars), never anywhere else | ai | core | levels/test-city-life/ai/spawns.spec.ts | implemented |
| E2E-297 | A driver (a level NPC of the driver role, a taxi) drives its route of points over the roads, point after point | ai | long | levels/test-city-life/ai/roles.spec.ts | implemented |
| E2E-298 | A target (a level NPC of the target role) goes about its rounds until a gun is aimed at it, then runs to its refuge by the apartments' door and cowers there in plain sight (never gone indoors) | ai | long | levels/test-city-life/ai/roles.spec.ts | implemented |
| E2E-299 | A VIP (the concierge mission's client) follows the player who comes up to it and gets into their car with them; the mission's rules hear it join and board | ai | core | levels/test-city-life/ai/roles.spec.ts | implemented |
| E2E-300 | The VIP's death fails the mission (its npc:<id>.killed rule) | ai | core | levels/test-city-life/ai/roles.spec.ts | implemented |
| E2E-301 | The room clock on the HUD (#clock, from the game's start hour, a game minute a second) runs; the legend's View tab sets its hour and pace; the shop's clerk keeps its schedule: home at 18:00 (it walks to its door and goes in), out again at 06:00 | app | long | levels/test-city-life/app/clock.spec.ts | implemented |
| E2E-302 | The crowd by the hour: the morning's commuters walk to work, at 02:00 most people go home and the shopkeepers are in, at 18:00 the streets fill again with commuters headed home | ai | core | levels/test-city-life/ai/crowd.spec.ts | implemented |
| E2E-303 | A gate (a kind of the door block, locked by a keycard): shut for a car without the keycard, open for its driver with it, shut again once the car is through | drive | long | levels/test-city-life/drive/gates.spec.ts | implemented |
| E2E-304 | A barrier (a kind of the door block, locked by a parking ticket): a ticket bought at the shop lifts it for its driver, and it drops behind the car | drive | long | levels/test-city-life/drive/gates.spec.ts | implemented |
| E2E-305 | Traffic lights an app switches: CityOS (installed by the concierge mission) sets Main Cross all red, every lamp over it turns red, the ambient cars stop at its lines, the mission hears of it; back to normal, the plan again | app | core | levels/test-city-life/app/signals.spec.ts | implemented |
| E2E-306 | A shop and the one Cash: cash picked up goes into the player's Cash (the wallet); the shop's counter opens (E Shop) into its stock at the game's prices and the Cash, a click buys one; the garage's respray is paid out of the same Cash | app | core | levels/test-city-life/app/shop.spec.ts | implemented |
| E2E-307 | A supermarket's counter on test-buildings is a shop where its anchor stands (the generator put it there): the legend's Go to puts the player beside it, its groceries sell at the game's prices for the Cash its errand started with | app | core | levels/test-buildings/app/city.spec.ts | implemented |
| E2E-308 | A player who goes down on test-buildings comes back at the hospital (its respawn anchor, a spawn point of the role hospital, under the game's rules.respawn: hospital) | app | long | levels/test-buildings/app/city.spec.ts | implemented |
| E2E-310 | A car that may touch the player's (a chaser ramming it) is drawn at the local time, where the prediction meets it, not interpolated in the past: a ramming car is never drawn inside the player's car (__poc().contact.deepest) | net | core | levels/test-collisions/net/contact.spec.ts | implemented |
| E2E-311 | A chaser's push comes only on contact: at every touch the prediction feels against the player's car, the two cars are drawn touching, never across a visible gap (__poc().contact.touches) | net | core | levels/test-collisions/net/contact.spec.ts | implemented |
| E2E-312 | On foot, a jump keeps the speed and the way it had when the feet left the ground: the movement keys neither steer nor speed it up in the air, and steer again once the feet are down | drive | core | levels/test-collisions/drive/foot.spec.ts | implemented |
| E2E-313 | The sprint (Shift) tops out at 35 km/h | drive | core | levels/test-collisions/drive/foot.spec.ts | implemented |
| E2E-314 | A light piece falls to a vehicle's kinetic energy, not its speed: a box truck at about 40 km/h knocks a hydrant loose that a sedan needs 60 km/h for | drive | long | levels/test-breakables/drive/breakables.spec.ts | implemented |
| E2E-315 | Getting out of a car never sets the player inside a wall or beyond it: along a wall too close to the driver's door, out of the other side's; between two walls, out ahead of the car | drive | core | levels/test-collisions/drive/exit.spec.ts | implemented |
| E2E-320 | The interaction prompt is drawn in the scene (Babylon's GUI, not the page) and follows the character at the frame rate: while the camera moves, its point is projected on every frame drawn, exactly where the character is drawn, the prompt's box centred just above the character's feet | app | core | levels/test-core-gameplay/app/game-ui.spec.ts | implemented |
| E2E-321 | A click on a panel of the in-game UI (the phone's) presses the button under it and is never a shot: the trigger stays released and the pointer over the panel does not aim (the aim holds where it was); the same click away from the panels throws a punch | app | core | levels/test-inventory/app/game-ui.spec.ts | implemented |
| E2E-322 | The in-game UI reads in the language the toolbar picks: the prompt, the inventory strip and the phone switch to Italian and back | app | core | levels/test-inventory/app/game-ui.spec.ts | implemented |
| E2E-323 | On a small window (800×500, the legend folded away) the in-game UI stays inside it: the inventory strip and the phone in the window, the phone above the minimap; a page taller than the room left (the map) scrolls inside the phone with the wheel, and its buttons below the fold then take a click | app | core | levels/test-inventory/app/game-ui.spec.ts | implemented |
| E2E-324 | A click on a slot of the inventory strip selects it: the use and drop keys act on it, the strip marks it | app | core | levels/test-inventory/app/game-ui.spec.ts | implemented |
| E2E-340 | A dead pedestrian lies where its ragdoll left it, drawn in its own colours (its shirt as it was alive), never as the red wireframe outline the dead were once drawn in | drive | core | levels/test-core-gameplay/drive/combat.spec.ts | implemented |
| E2E-341 | A wrecked car smokes for as long as it is there: a dark plume, thick at first and settling, rising out of its engine bay and drifting off on the wind (unlike the tyres' light grey smoke, low and gone in a second and a half) | drive | core | levels/test-core-gameplay/drive/combat.spec.ts | implemented |
| E2E-342 | A shot's tracer, a short bright streak flying to where the shot stopped, leaves the muzzle of the gun in the shooter's hand (the pistol held out in the right hand: ahead of the character, on its right, at the shoulders), with a muzzle flash there; not from the character's middle | drive | core | levels/test-core-gameplay/drive/weapons.spec.ts | implemented |
| E2E-343 | Each gun has its tracer: the rifle's longer, wider and whiter than the pistol's yellow streak; the shotgun's a short thin streak per pellet (eight) | drive | core | levels/test-core-gameplay/drive/weapons.spec.ts | implemented |
| E2E-344 | Another player's shot from their car leaves by the car's window (out by the windscreen ahead of the driver for a shot forward), not from the middle of the car | net | core | levels/test-core-gameplay/drive/weapons.spec.ts | implemented |
| E2E-345 | Blood stays on the person it came from: a chaser shot as it runs up keeps the burst of blood on it as it runs on (it follows the body instead of hanging where the round struck), and the drops it threw stain the ground | drive | core | levels/test-ai-pathfinding/drive/blood.spec.ts | implemented |
| E2E-346 | The player shot by an armed chaser while fleeing keeps the burst of blood on them as they run on | drive | core | levels/test-ai-pathfinding/drive/blood.spec.ts | implemented |
| E2E-350 | A closed car's people show through its glass: the glass is drawn see-through (the windscreen lighter than the other windows) over a grey interior, the player at the wheel is drawn in the driver's seat (the head under the windscreen), and a second player who gets in beside is drawn in a passenger's seat, on both players' screens | app | core | levels/test-new-vehicles/app/glass.spec.ts | implemented |
| E2E-351 | A car's door swings open (about 65°, in a fifth of a second) when someone gets in or out of its seat and shuts again a moment later: the driver's door of the player's car as the player gets out, and again as the player gets back in; every class with doors swings them (a bus's doorways and an ambulance's back doors as two leaves), players' and NPCs' alike | app | core | levels/test-new-vehicles/app/doors.spec.ts | implemented |
| E2E-352 | A window a shot goes through cracks where it did (a crack of white lines on that pane, for as long as the car lasts): the pistol fired from the wheel cracks the windscreen, the other player's screen shows it cracked too, and R puts the car back at its spawn with clean glass (so does a repair, a respawn or another class) | app | core | levels/test-new-vehicles/app/glass.spec.ts | implemented |
| E2E-353 | The vehicle gallery (/?vehicle-gallery, no server) shows every class, by name in the classes' order, with a person in every seat (behind a closed one's glass), its doors swinging open and shut, its steering wheel and front wheels turning from lock to lock (none on a two-wheeler) and its windscreen cracked by a shot from the driver's seat; the open ones (the buggy, the two-wheelers) have neither doors nor glass to crack; the semi is drawn with its trailer behind it; D pans the camera | app | core | levels/test-new-vehicles/app/gallery.spec.ts | implemented |
| E2E-354 | An NPC's doors swing as a player's do: at three stars the police crews get out of their cars to fight on foot, and a police car's doors swing open as its crew gets out and shut behind them | ai | core | levels/test-police/ai/doors.spec.ts | implemented |
| E2E-360 | E behind a car (out of its trunk's reach) runs the player round to the driver's door and gets them in there, facing the door, just outside the car (__poc().boarding.ins); the wheel is theirs | drive | core | levels/test-collisions/drive/doors.spec.ts | implemented |
| E2E-361 | Getting out at a crawl (8 km/h or less) the player stands at the driver's door, on the car's left level with the driver's seat, 20 cm clear of the body, facing straight out of it (__poc().boarding.outs) | drive | core | levels/test-collisions/drive/doors.spec.ts | implemented |
| E2E-362 | E at speed: above 35 km/h the player stays at the wheel; braked under 30 km/h, E bails them out at the driver's door with the car's speed, knocked down and tumbling, and they get up again | drive | core | levels/test-collisions/drive/doors.spec.ts | implemented |
| E2E-363 | The crew of a chaser's car shot to a wreck with the pistol as it drives up at the player never leaves it faster than 35 km/h: they leave it at their doors, beside the car (never ahead of it), tumbling when it still moves faster than a crawl | ai | core | levels/test-collisions/drive/doors.spec.ts | implemented |
| E2E-364 | A chaser crew that pulls up to fight (Car tactics: get out and fight) steps out at a crawl right at its doors, on its feet, just outside the car, facing out; the driver by the driver's door | ai | core | levels/test-collisions/drive/doors.spec.ts | implemented |
| E2E-365 | A bus passenger gets in and out by the bus's doors on the kerb side (its right): from its left the passenger goes round the bus to a door there; out again, just outside the bus by a door, facing out, never on the driver's side, the doorway its seat is reached by (the middle one) swinging open as it gets out | drive | long | levels/test-new-vehicles/drive/bus.spec.ts | implemented |
| E2E-370 | give: on test-mission-verbs, "Hand-Off" hands the player a USB stick; at Mo, the person the give is under way to, the interaction prompt says Give USB stick instead of Talk and E hands it over into his pockets; the objective is done once it changed hands, the mission complete and paid | app | core | levels/test-mission-verbs/app/give.spec.ts | implemented |
| E2E-371 | A mission’s message read: "Hand-Off"’s message from Mo (one with an id) read on the phone’s messages page is heard by the mission’s rules (message:brief.read), which say so | app | core | levels/test-mission-verbs/app/give.spec.ts | implemented |
| E2E-372 | Objectives in parallel: "Errands" is a group of three objectives under way at once (drop a parcel in a crate, photograph a mural, wait on a bench); the tracker lists them with their states and the group’s count, the world and the minimap draw each one’s target; each ends on its own, its target gone, and the group completes the mission once all three are done | app | core | levels/test-mission-verbs/app/errands.spec.ts | implemented |
| E2E-373 | give into a container: "Errands"’ parcel put into the crate through its panel ends that member, the group going on (1/3 done) | app | core | levels/test-mission-verbs/app/errands.spec.ts | implemented |
| E2E-374 | photograph: the phone’s Camera (a tile of its home, its shutter on 1, its frame on the minimap) takes a photo along the aim; from outside the zone it says not from here, aimed away from the subject it says it missed, from the mural’s spot and aimed at it the photograph is done | app | core | levels/test-mission-verbs/app/errands.spec.ts | implemented |
| E2E-375 | wait: "Errands"’ bench clock (4 s, on the member’s line) runs while the player stands in its zone, the wait done when it runs out | app | core | levels/test-mission-verbs/app/errands.spec.ts | implemented |
| E2E-376 | escort: on "Ride Along" the VIP waiting on the kerb joins the player’s car, gets in at the passenger’s door, and the tracker turns from the VIP to the hotel and shows its health; driven into the hotel’s zone with it aboard, the escort is done | drive | core | levels/test-mission-verbs/drive/escort.spec.ts | implemented |
| E2E-377 | chase on foot: on "Pickpocket" the target bolts for his refuge as the chase starts (the tracker rings him at the catch radius and says how far he is); run down by the car and stopped with the player near, he is caught | drive | core | levels/test-mission-verbs/drive/chase.spec.ts | implemented |
| E2E-378 | escape from the police: "Heat Check" sets a star as it starts; once the stars are back to zero the escape is done and the mission paid | app | core | levels/test-mission-verbs/app/escape.spec.ts | implemented |
| E2E-379 | The Wanted level heard by a mission’s rules: "Heat Check"’s rules hear it go up (wanted:up) and come back to zero (wanted:0) | app | core | levels/test-mission-verbs/app/escape.spec.ts | implemented |
| E2E-380 | escape from actors: on "Shake Them" two tails on foot come after the player; the escape’s clock stands full while they see the player and, driven out of their sight, runs out four seconds later | drive | core | levels/test-mission-verbs/app/escape.spec.ts | implemented |
| E2E-381 | destroy: "Bad Review"’s target is the level’s hydrant at the end of the diner’s road (a prop actor); knocked loose by a box truck, it is destroyed (prop:<id>.destroyed heard) and the mission done | drive | core | levels/test-mission-verbs/drive/destroy.spec.ts | implemented |
| E2E-382 | The minimap’s route line: from the player over the roads (along the station’s street, down the avenue, along the cafe’s street) to the mission’s target, every turn on a road, worked out again as the player moves | app | core | levels/test-mission-verbs/app/route.spec.ts | implemented |
| E2E-383 | A party sees each other: two players joined in one party play "Hand-Off" together; each has the other on the tracker (a green ring on the minimap) wherever they are, the same target marked, and their own route line to it | net | core | levels/test-mission-verbs/net/party.spec.ts | implemented |
| E2E-384 | chase by car: on "Missed Delivery" the courier parked ahead drives off flat out to his getaway as the chase starts; getting there, he has got away and the chase fails with its line | drive | core | levels/test-mission-verbs/drive/chase.spec.ts | implemented |
| E2E-390 | Weapons as items on test-inventory: the number keys select the inventory's slots and what the player holds is the selected slot's weapon (1, an empty slot, the fists; 2 the pistol, the HUD naming its rounds; 3, empty here, the fists; 6 the grenades; 9, empty, the fists), the strip marking the slot selected; seated, only the pistol selected, the HUD naming its key (fists · 2: pistol to fire) | drive | core | levels/test-inventory/drive/weapons.spec.ts | implemented |
| E2E-391 | Ammunition: every shot spends a round out of the inventory (the pistol's tile and the HUD's count go down); with the rounds put in the car's trunk (from the pouch, among the player's own in its panel) the pistol does not fire and the HUD says OUT OF AMMO; taken back, it fires | drive | core | levels/test-inventory/drive/weapons.spec.ts | implemented |
| E2E-392 | A weapon is an item: G drops the pistol a step ahead (the fists in hand), E picks it up into the first free slot (its key now 1), and it goes into the car's trunk like any item | drive | core | levels/test-inventory/drive/weapons.spec.ts | implemented |
| E2E-393 | A player who dies drops the items a mission defined where they fell (Parcel Run's waybill, killed by two grenades held past their fuse), keeping the common ones (the pistol and its rounds); back at a spawn without it, the waybill still lying there | drive | long | levels/test-inventory/drive/weapons.spec.ts | implemented |
| E2E-394 | A game's loadout replaces free roam's arsenal: test-inventory's game starts the player with a pistol on the strip's slot 2 (its tile reading its 24 rounds, kept in the pouch, never a tile of their own), three grenades on 6 and the phone on 16, and none of the arsenal's other guns | app | core | levels/test-inventory/drive/weapons.spec.ts | implemented |
| E2E-395 | Three stars on test-police: the police cars after the player have the pursuit tune (an interceptor's engine: __poc().police.pursuit), the ones out fitted at once and every one sent after; at two stars they have not | ai | core | levels/test-police/ai/three-stars.spec.ts | implemented |
| E2E-396 | Nail strips at three stars: driving west along the south road, an officer on the kerb throws a strip across the road five metres short of the corner ahead, a police car parked behind it; the strip unrolls from the kerb, the whole road wide a second later (drawn as a chain of scissor links with spikes); driven over, it pops the car's tyres (FLAT on the HUD) and the officer reels it in once the car has passed it | ai | core | levels/test-police/ai/three-stars.spec.ts | implemented |
| E2E-397 | The Heat of breaking property: test-police's parked car (nobody's) shot to a wreck with the pistol, in the range dummies' sight but out of reach of gunfire near them, costs the player 2 Heat, no star and no police | ai | core | levels/test-police/ai/heat.spec.ts | implemented |
| E2E-398 | The Heat of speeding past the police: at one star, the police car's officer having seen the player, the sports car floored well over the south road's limit in its sight costs 3 Heat (the stars stay at one) | ai | core | levels/test-police/ai/heat.spec.ts | implemented |
| E2E-399 | The inventory strip on test-inventory lays its sixteen slots in two rows of eight (a tile's count under its name, a weapon's rounds under the pistol's), no taller than the strip of eight slots and clear of the legend, so the aim still follows the mouse 160 px south of the character | app | core | levels/test-inventory/app/game-ui.spec.ts | implemented |
| E2E-400 | A player who dies sees YOU DIED mid-screen (#banner) until back on their feet (killed by two grenades held past their fuse on test-inventory) | app | long | levels/test-inventory/app/banner.spec.ts | implemented |
| E2E-401 | A level reset (Backspace) says LEVEL RESET mid-screen for a few seconds | app | core | levels/test-inventory/app/banner.spec.ts | implemented |
| E2E-406 | A page that loses its server says DISCONNECTED mid-screen, offers no prompt and holds everyone still (nobody walking on the spot); once the server is back it joins again by itself | net | core | levels/test-core-gameplay/net/reconnect.spec.ts | implemented |
| E2E-407 | Checkpoints: every objective that gets done saves one (the tracker says Checkpoint.); dying fails the mission (YOU DIED, back to the last checkpoint) and a few seconds on the player is where the checkpoint left them, on test-mission-basics at the stolen rental's wheel where it was taken, on full health, the delivery's clock full again | drive | long | levels/test-mission-basics/drive/checkpoint.spec.ts | implemented |
| E2E-408 | A passenger's camera follows the car it rides in as the car is drawn, smoothly frame by frame (no stall and leap at each snapshot), while the driver drives off on test-core-gameplay | net | long | levels/test-core-gameplay/net/passenger.spec.ts | implemented |
| E2E-409 | The legend's Player page has a max health slider (25 to 250) next to infinite health: set, the player is healed to it at once and the HUD's bar reads out of it (200, then 50, then a player's 100) | ai | core | levels/test-ai-pathfinding/ai/panel.spec.ts | implemented |
| E2E-670 | The legend works with the real mouse, each control clicked where it is drawn (nothing over it): the Chasers tab, a style chip, Spawn on foot and Clear, the Car tactics page's ram box and Spawn in a car, the page arrows, infinite health on and off (the HUD reads ∞), and the View tab's Go to (a road picked, Go clicked, the car there); on a server that takes debug commands nothing says they are off | app | core | levels/test-ai-pathfinding/app/legend-input.spec.ts | implemented |
| E2E-671 | The legend works with the keyboard alone: from the page, Tab reaches its tab list and the arrow keys pick Chasers; Tab then Space picks a style chip, Enter spawns a chaser and Space clears it, Enter on the arrow turns the pages (the focus kept) and Space switches infinite health on and off | app | core | levels/test-ai-pathfinding/app/legend-input.spec.ts | implemented |
| E2E-672 | On a server whose debug commands are off (FOI_DEBUG=0, as a platform's rooms and the live platform are; the welcome says debug: false), the legend says so above the Chasers panel and Go to, the clock and the weather, greyed out (disabled and described by that line, not silently doing nothing); the chasers' pages still turn and the view cones still switch | app | core | levels/test-ai-pathfinding/app/legend-input.spec.ts | implemented |
| E2E-673 | In a run's room, whose level nobody resets, the legend's Reset level is greyed out but stays in the keyboard's reach, described by the reason beside it; Backspace, or the button pressed anyway, puts the same reason in the HUD's log and resets nothing | app | core | levels/test-versus/app/reset.spec.ts | implemented |
| E2E-674 | The platform's FOI_DEBUG_ACCOUNTS: in a room the platform hands out (a published game's, whose own debug commands are off), the account it names uses the legend's debug options (a chaser spawned and read out to them, infinite health); another account in the same room sees them greyed out under the line that says why and is sent no readout | platform | core | platform/debug-accounts.spec.ts | implemented |
| E2E-410 | Sitting still at the wheel at three stars (infinite health), the police pull up rather than ram, and once the car has stood still three seconds an officer walks to the driver's door, pulls the player out and arrests them: on foot, the stars cleared, BUSTED | ai | core | levels/test-police/ai/pullout.spec.ts | implemented |
| E2E-411 | Kerbs are steps: walking up the generated town's 15 cm kerb onto the pavement, running back across the street (down one, up the other) and walking down again, the player's figure never jumps or falls | drive | core | levels/test-generated-town/drive/kerbs.spec.ts | implemented |
| E2E-413 | The layered navigation on test-storeys: the player climbs the office's stairs onto its upper floor (its ground floor sealed), a pursuit dropped behind them follows them up the stairs onto the floor, not under it | ai | core | levels/test-storeys/ai/upstairs.spec.ts | implemented |
| E2E-414 | A ladder on test-vertical: at its foot the prompt says Climb, E takes it, the forward key climbs it (faster with Shift), and at the top the player steps off onto the roof it leans on | drive | core | levels/test-vertical/drive/vertical.spec.ts | implemented |
| E2E-415 | Falls hurt: off the shed's roof (5 m) the player loses some health; off the tower (14 m, climbed by its ladder) they die (YOU DIED) | drive | long | levels/test-vertical/drive/vertical.spec.ts | implemented |
| E2E-416 | A lift: the player steps onto its platform while it stands at the bottom, rides it up to its stop 6 m up and walks off onto the deck | drive | long | levels/test-vertical/drive/vertical.spec.ts | implemented |
| E2E-417 | An escalator: the player standing still on its steps is carried up its length onto its landing | drive | long | levels/test-vertical/drive/vertical.spec.ts | implemented |
| E2E-418 | The mall on test-landmarks: Go to its up escalator's foot (Go to lists the game's places), the three storeys over the player fade; a step onto it and the steps carry the player to the first floor, where only the two storeys over them fade | drive | core | levels/test-landmarks/drive/landmarks.spec.ts | implemented |
| E2E-419 | The hospital: the player steps onto its lift's platform just come down to the ground floor, rides it to the roof, walks off it to the helipad's ladder and climbs onto the helipad | drive | long | levels/test-landmarks/drive/landmarks.spec.ts | implemented |
| E2E-420 | The castle: from the courtyard up the flight to the east wall walk, along it to the bridge and across into the keep's upper hall, 9 m up | drive | core | levels/test-landmarks/drive/landmarks.spec.ts | implemented |
| E2E-421 | The mall's top floor: up the flight from the first floor to the top one (a flight standing on a floor), along it to the food court, where the bundled game's mission ends | drive | core | levels/test-landmarks/drive/landmarks.spec.ts | implemented |
| E2E-422 | Terrain tiles on test-tiles-terrain (a region built from its spec): a car driven north from the spawn apron climbs the hill across five tiles' seams to its peak, its four wheels on the ground all the way | drive | core | levels/test-tiles-terrain/drive/terrain.spec.ts | implemented |
| E2E-423 | On foot over the steep little mountain's flank (two levels a tile) to its peak and back down, unhurt | drive | long | levels/test-tiles-terrain/drive/terrain.spec.ts | implemented |
| E2E-424 | Road tiles on test-tiles-roads (roads laid over a region from its spec): Go to the highway, drive west along it: the car crosses the gorge on its bridge, well over the ground, its wheels on the deck | drive | core | levels/test-tiles-roads/drive/roads.spec.ts | implemented |
| E2E-425 | The country road north from the spawns crosses the highway at a flat junction, level with it, the car's wheels on the road all the way | drive | core | levels/test-tiles-roads/drive/roads.spec.ts | implemented |
| E2E-426 | Water on test-water: a car driven north off the yard into the pond's deep end floods, wrecked and sunk, the player put out of it swimming, afloat with the head out, the HUD saying swimming | drive | core | levels/test-water/drive/water.spec.ts | implemented |
| E2E-427 | On foot down the pond's steps: wading over the shelf (the water over the knees), swimming beyond it, back onto the shelf and up the steps onto the yard, unhurt | drive | long | levels/test-water/drive/water.spec.ts | implemented |
| E2E-428 | Walking into the lava pit kills: YOU DIED, the hit log naming lava | drive | core | levels/test-water/drive/water.spec.ts | implemented |
| E2E-429 | A town inside a region (test-tiles-town): the car drives in from the spawns on the country road at a town's pace (54 km/h) and on up a street over the town's hill, its wheels down | drive | long | levels/test-tiles-town/drive/town.spec.ts | implemented |
| E2E-430 | On foot down and back up the town's steep street, unhurt, then to a townhouse's door on it: the player's feet at the building's base, level with the pavement there | drive | long | levels/test-tiles-town/drive/town.spec.ts | implemented |
| E2E-431 | The terraced district's street is level from one junction to the next, at its terrace's height | drive | long | levels/test-tiles-town/drive/town.spec.ts | implemented |
| E2E-432 | The kit gallery (/?kit-gallery, no server) shows everything a game made through the MCP server can be built of: every building (each archetype a district's mix names) and prop of the downtown, civic, landmarks, city, compound, street, urban and nature kits and the six osm-* kits the generator makes from OpenStreetMap’s tags (125 buildings and 19 facilities), the seven terrain shapes, the seven features, the eight biomes in their rich tones, the twelve landuse kinds’ grounds and the five road classes, each drawn and none on another | app | long | levels/test-buildings/app/kit-gallery.spec.ts | implemented |
| E2E-433 | The kit gallery looks at what its address names (=volcano, =highway, =bld-bank-a, a kit: =civic), the thing on screen, and 3 lifts the camera to 420 m | app | core | levels/test-buildings/app/kit-gallery.spec.ts | implemented |
| E2E-434 | The parking brake: a car driven down test-tiles-town's steep street, braked to a crawl and left there stays where it was left (it rolls without the brake) | drive | core | levels/test-tiles-town/drive/town.spec.ts | implemented |
| E2E-435 | The kit gallery's camera goes anywhere: D pans it east, W north, the wheel zooms it out, F goes back to the focus | app | core | levels/test-buildings/app/kit-gallery.spec.ts | implemented |
| E2E-437 | A bare address opens the main menu: its title screen (press any key) over a rented sedan burning (flames and smoke drawn), every text in Changa; any key brings its list, with the start cue, Play online chosen, and no Play local in a browser (a page runs no server) | app | core | levels/test-core-gameplay/app/menu.spec.ts | implemented |
| E2E-438 | The menu's keys move through its list with a quiet cue each; Play online lists the levels that ship (one city: Smart City Pilot, main-riverbend) with its picture and blurb, on the page's game server; chosen (?level=), it opens its room on the game server and plays it; a test level asked for is refused, the page saying the server has no such room (a full room says it is full) | app | core | levels/test-core-gameplay/app/menu.spec.ts | implemented |
| E2E-439 | The menu leads to the four galleries (the kit gallery opens) and to the community's games (?browse); Esc goes back to its list, on the item it came from, with the back cue | app | core | levels/test-core-gameplay/app/menu.spec.ts | implemented |
| E2E-440 | Alone in the room, Esc (or the toolbar's Pause) opens the pause menu and the room waits: the server's tick holds until the player resumes, and nothing jumps when it goes on | app | core | levels/test-core-gameplay/app/pause.spec.ts | implemented |
| E2E-441 | With another player in the room, the pause menu says the city doesn't wait and the room ticks on; once the other leaves, it waits for the one who paused | app | core | levels/test-core-gameplay/app/pause.spec.ts | implemented |
| E2E-442 | The pause menu's Quit goes back to the main menu, the server kept | app | core | levels/test-core-gameplay/app/pause.spec.ts | implemented |
| E2E-443 | Settings changed on the menu's Settings screen with the keys (the volume, the radio's volume and earbuds, the HUD, the camera's height) are kept over a reload and applied in the game: the HUD hidden, every text in Changa | app | core | levels/test-core-gameplay/app/settings.spec.ts | implemented |
| E2E-560 | In a car the camera zooms out at speed (Settings → Display → Zoom out at speed, on by default): from its standstill height (30 m) it rises as the car speeds up, the drawn area (the view rectangle the culling uses) widening with it, and comes back down to 30 m a few seconds after the car stops, never jumping | drive | core | levels/test-core-gameplay/drive/camera-zoom.spec.ts | implemented |
| E2E-561 | With Zoom out at speed turned off (as the Settings screen keeps it in the browser), the camera stays at its standstill height whatever the car's speed | drive | core | levels/test-core-gameplay/drive/camera-zoom.spec.ts | implemented |
| E2E-562 | The Settings screen's Display section has Zoom out at speed after the camera's height: a switch (on) and two sliders, its strength (how much farther out at full speed: +75 % by default, none to twice the height) and its response (×1, half to twice as quick), dimmed while the switch is off; set with the mouse and the keys, they are kept over a reload and read by the game | app | core | levels/test-core-gameplay/app/settings.spec.ts | implemented |
| E2E-563 | Getting out of a car while the camera is zoomed out at speed, the view eases back in to the standstill height on foot without a jump | drive | core | levels/test-core-gameplay/drive/camera-zoom.spec.ts | implemented |
| E2E-444 | test-curves, the curves' level, arrives with one terrain mesh, a one-way roundabout of four arcs, a crescent, a park drive, a tunnel under a roof that fades, a dirt rally track, two bridges and buildings along the streets; the player starts on the main avenue south of the roundabout | app | core | levels/test-curves/app/level.spec.ts | implemented |
| E2E-447 | A person hit at speed comes off the car, never carried on its bumper: thrown up and ahead, it lies in the road and the car driven on passes over it, leaving it behind | drive | core | levels/test-on-foot/drive/falls.spec.ts | implemented |
| E2E-448 | A hitch of the page at speed (its main thread stuck 100 ms, three times, at a simulated 150 ms round trip) needs no correction over 5 cm: the server runs the ticks it waited for on the throttle held and takes the late inputs as too late, never driving the car on twice, and the page runs the ticks it drops beyond its backlog on the server's guess, as the server ran them (Predictor.guess), the crowd out or not | net | core | levels/test-core-gameplay/net/prediction.spec.ts | implemented |
| E2E-520 | On a server that offers a WebRTC data channel (FOI_RTC=1), the page offers one once welcomed and moves its inputs and snapshots onto it: __poc().net.transport is udp, the HUD says "connected via udp", the snapshots are the acked ones, the car drives and no snapshot ever needs a resync, at the move or after | net | core | levels/test-core-gameplay/net/rtc.spec.ts | implemented |
| E2E-521 | The Server tab's "Drop the data channel" (the debug command rtcDrop: the server drops its side without a word) makes the page fall back to its WebSocket within 2 s, on the silence of the channel: transport ws, the HUD saying so, the same player still connected and the snapshots still coming; a channel that had opened is offered again a few seconds later and the page moves back onto it | net | core | levels/test-core-gameplay/net/rtc.spec.ts | implemented |
| E2E-522 | ?rtc=0 keeps the page on the WebSocket on a server that offers the channel, and a server without FOI_RTC offers none: transport ws, the channel off | net | core | levels/test-core-gameplay/net/rtc.spec.ts | implemented |
| E2E-523 | Getting in takes the whole of its half second at the door: with the throttle held from before E, the car does not move until the player is in its seat (the car's place watched every frame), and the driver is drawn in the seat from then on, nobody left at the door | drive | core | levels/test-collisions/drive/doors.spec.ts | implemented |
| E2E-524 | Killed in a crash (a quarter of the health, a car nearly wrecked, flat out into a wall), the player stays in the car, slumped in the seat (seat-dead), never laid out at the door; the wreck is drawn in its paint as it was until it blows up, charred then; ten seconds on the player is back on foot at a spawn | drive | core | levels/test-core-gameplay/drive/hits.spec.ts | implemented |
| E2E-525 | After a level reset, which hands every entity's id out again (on test-fire a car's id comes back as the player's character), the player's own twins are what they are: the weapon held shows its rounds (not OUT OF AMMO), and the car is driven where the server has it with the mouse off to its side, never a capsule that walks and turns to the pointer | net | core | levels/test-fire/net/twins.spec.ts | implemented |
| E2E-546 | On main-riverbend, the city drawn freely round a river, "Smart City Pilot" starts on joining: Onboarding Flow, the app's welcome message, the rental parked at the car rental in The Docks; taken there and brought to the Market Gate, the mission pays and the next one (Ring Road Rumble) starts | app | long | levels/main-riverbend/app/city.spec.ts | implemented |
| E2E-547 | Riverbend's river is water: the streets stand over it, and a car driven off the Old Town's quay floods (wrecked, the player put out, swimming with the head out of the water) | drive | core | levels/main-riverbend/app/city.spec.ts | implemented |
| E2E-548 | Riverbend's roofs carry what roofs carry (air conditioners, vents, dishes, solar panels: the urban kit's pieces on the free spots of the buildings' flat roofs), Exchange Square has its statue, its carousel and a hot-dog cart, and The Docks a crane on the quay, its boom over the dock road a car drives on under, and fishing boats on the river | app | core | levels/main-riverbend/app/city.spec.ts | implemented |
| E2E-115 | Riverbend has its traffic: its game asks for 40 ambient cars (rules.traffic), they drive its streets, and its traffic lights' lamps are lit, red for some approaches and green for others | ai | long | levels/main-riverbend/ai/traffic.spec.ts | implemented |
| E2E-154 | Taxis and buses drive among Riverbend's ambient cars (its game's 40, on a server of the spec's own), drawn as what they are; most of the traffic is still cars | ai | long | levels/main-riverbend/ai/traffic.spec.ts | implemented |
| E2E-155 | An ambient bus on Riverbend pulls in to the kerb now and then (the readout's stop), stands there a few seconds and goes on | ai | long | levels/main-riverbend/ai/traffic.spec.ts | implemented |
| E2E-156 | Pedestrians walk Riverbend's pavements: the crowd kept around the player (40 on a main-* level), every everyday role out in the Old Town at eight in the morning (civilian, commuter, jogger, shopkeeper; the city's routines beside them), each walking one a few metres beside a street, nobody down its middle (a crossing quickly over); each drawn in its role's shirt | ai | long | levels/main-riverbend/ai/crowd.spec.ts | implemented |
| E2E-157 | A shopkeeper in Riverbend's Old Town steps out from its door along the pavement now and then and goes back to it, standing there again | ai | long | levels/main-riverbend/ai/crowd.spec.ts | implemented |
| E2E-230 | What is drawn is what the camera sees: on Riverbend, among the crowd kept around the player, every person within the camera's ground view is drawn (by the models' batches), those beyond it are placed but not drawn, the minimap still shows them, and someone walking into view is drawn while still beyond the edge of the screen | app | long | levels/main-riverbend/ai/crowd.spec.ts | implemented |
| E2E-570 | Riverbend is drawn in batches (level-batches.ts: its standing pieces baked at load by 64 m cell and surface): from the highest camera (1.5) on the Old Town's ring the frame is under 250 draw calls (300 for the level alone before), and the Old Town's buildings are among the pieces drawn | app | core | levels/main-riverbend/app/batches.spec.ts | implemented |
| E2E-572 | Far traffic is drawn at an even pace: on a Riverbend server with its game's 40 cars, the cars 85 to 245 m from the player (sent every second or fourth snapshot) change their step from one frame to the next by more than 6 cm in under 1 % of their frames (a snapshot that left a car out no longer freezes it, then sends it on at twice its speed); measured on the ticks the frames drew them at, the frames of a stall of the server left out, so a busy machine is no jolt | net | long | levels/main-riverbend/net/far-traffic.spec.ts | implemented |
| E2E-573 | The sound board (?sound-board, from the menu's galleries) lists every sound of the bank (apps/client/audio/sounds.json) with its bus, what it plays (its placeholder, or its file) and where a file goes to replace it (apps/client/audio/sfx/<id as folders>.ogg), and the five sample radio stations of five items each, nothing wrong with either; its button plays a sound | app | core | levels/test-core-gameplay/app/sound-board.spec.ts | implemented |
| E2E-574 | The game plays the sound bank's events: G sounds the horn (vehicle.horn), a pistol shot its own (weapon.pistol.shot); others' shots, hits and carjacks are heard where they happen (audible only) | app | core | levels/test-core-gameplay/app/sounds.spec.ts | implemented |
| E2E-575 | Getting into a car turns its radio on (the settings' Radio on when getting in a car): one of the five sample stations plays, from the station's live moment | app | core | levels/test-core-gameplay/app/radio.spec.ts | implemented |
| E2E-576 | . and , step through the radio's stations, Off between the last and the first, each tuning shown on the now-playing banner (the station, what it plays; "Radio off") | app | core | levels/test-core-gameplay/app/radio.spec.ts | implemented |
| E2E-577 | Holding B opens the radio wheel (the stations round a circle, Off last); the station the mouse points at is tuned on letting go, with the tuning's crackle | app | core | levels/test-core-gameplay/app/radio.spec.ts | implemented |
| E2E-578 | Getting out of the car silences the radio (its keys tune nothing on foot); back in, the car still plays its station | app | core | levels/test-core-gameplay/app/radio.spec.ts | implemented |
| E2E-579 | With the settings' Keep listening on foot (earbuds), the radio plays on after getting out and its keys tune it on foot; the car got into then plays the station picked | app | core | levels/test-core-gameplay/app/radio.spec.ts | implemented |
| E2E-580 | On foot in free roam (no phone of one's own), T takes out a phone with only the Radio app, whose numbered buttons tune a station (through earbuds) or turn it off | app | core | levels/test-core-gameplay/app/radio.spec.ts | implemented |
| E2E-581 | A station of addresses (Riverbend Podcasts' urls) plays them, skipping an address that will not load; when none will, "No signal" | app | long | levels/test-core-gameplay/app/radio-live.spec.ts | implemented |
| E2E-582 | A station plays on while nobody listens: tuned away from and back to, it is as far on as the time away (or on a later item) | app | long | levels/test-core-gameplay/app/radio-live.spec.ts | implemented |
| E2E-446 | On foot along a jetty of Riverbend's Docks: dry on its deck over the river, from near the shore to its end; a few steps off its end, in the water | drive | long | levels/main-riverbend/drive/jetty.spec.ts | implemented |
| E2E-507 | A big level (Riverbend's, 7.7 MB) is named by its hash in a welcome under 50 kB; the page downloads it from the game server the first time (levelSource network) and loads it from the browser's store after a reload (cache), the same level | net | long | levels/main-riverbend/net/level-cache.spec.ts | implemented |
| E2E-449 | On the main menu's Play online, a platform's address typed (the site's, its /api tried first) is asked what it is across origins (the API's CORS), kept over reloads, and plays the city on the game server it names; the community's page lists that platform's games | platform | core | platform/online.spec.ts | implemented |
| E2E-450 | A platform of another protocol greys Play online's city out, saying its release and this game's; a game server of another protocol says both releases in place of the game, which never starts | platform | core | platform/online.spec.ts | implemented |
| E2E-451 | The Electron app's Play local → Join plays on a friend's game server at the address they read out (192.168.1.23:7777), the app's own server never started | app | smoke | smoke/electron.spec.ts | implemented |
| E2E-452 | The Electron app given a platform (FOI_PLATFORM_URL; the build carries one from the release's variable) plays the city online on its game server, asked from file:// across origins, the app's own server never started | app | smoke | smoke/electron.spec.ts | implemented |
| E2E-453 | A game made in Claude Code over the MCP server on HTTP (a creator's session as the bearer) is built, its playtest link plays it in the browser on the platform's game server, and once published the community's page lists it | platform | core | platform/mcp.spec.ts | implemented |
| E2E-454 | Opening a car's trunk turns the player to face it, whatever the aim, as long as its panel is open; closed, the facing follows the aim again | drive | core | levels/test-inventory/drive/items.spec.ts | implemented |
| E2E-455 | Steering a car turns its front wheels about their hubs and its steering wheel about its column: A to the left, D to the right, both straight again once the key is let go; a two-wheeler has neither | drive | core | levels/test-new-vehicles/drive/steering.spec.ts | implemented |
| E2E-456 | People seated inside a car's body (the compact, the saloons, the sports and muscle cars, the police car, the taxi) are drawn without their legs, so none pokes out under it; those on a bus, in a truck's cab, in the buggy or on a two-wheeler keep theirs | app | core | levels/test-new-vehicles/app/gallery.spec.ts | implemented |
| E2E-457 | The galleries' panel has a speed slider (a quarter to eight times; + doubles it, - halves it): at 4× D pans more than twice as far; each gallery keeps its own speed across a reload | app | core | levels/test-buildings/app/kit-gallery.spec.ts | implemented |
| E2E-458 | The kit gallery's panel finds a thing by the words typed (/ puts the cursor there, Enter looks at the first match), goes to a section or a kit, and maps the whole gallery (a click looks there); keys typed in the field never move the camera | app | core | levels/test-buildings/app/kit-gallery.spec.ts | implemented |
| E2E-459 | The kit gallery labels only the nearest things big enough on the screen to read, 150 at most: close over the street props some are labelled, from high up the small things lose theirs | app | core | levels/test-buildings/app/kit-gallery.spec.ts | implemented |
| E2E-460 | The kit gallery shows inside a walk-in building (the mega-mall): its stairs and escalators, lift and shaft, shops and named places drawn where their anchors stand; [ takes its storeys off down to the ground floor, with what stands on them, and ] puts them back | app | core | levels/test-buildings/app/kit-gallery.spec.ts | implemented |
| E2E-461 | A parked car shot low smokes (30 hit points left, not yet on fire), one more shot sets it on fire (flames drawn, the car in its paint as it was), and a few seconds later it blows up: an explosion a car's size (7 m), the wreck at 0 and burning on, its shell charred | drive | long | levels/test-fire/drive/fire.spec.ts | implemented |
| E2E-462 | A car blowing up lights the one parked beside it, 3 m away: the row of four sedans goes up one after the other, in order | drive | long | levels/test-fire/drive/fire.spec.ts | implemented |
| E2E-463 | A box truck's blast reaches further than a car's (over 9 m), a bus's further still | drive | long | levels/test-fire/drive/fire.spec.ts | implemented |
| E2E-464 | The crew of a car on fire gets out of it: a chaser that tails the player in a car, its car shot down to a quarter of its hit points | ai | core | levels/test-fire/drive/fire.spec.ts | implemented |
| E2E-565 | Whoever is aboard a vehicle when it blows up dies, two-wheelers too: the player on a scooter set to five hit points catches fire, rides on and blows up: YOU DIED, thrown off it at once (on foot, not carried on by the wreck), the hit log naming the explosion | drive | core | levels/test-fire/drive/blast.spec.ts | implemented |
| E2E-566 | No smoke in water (test-water): a car smoking at 25 hit points driven off the yard onto the pond's shelf, its body in the water, stops smoking within moments (the HUD no longer says SMOKING) and puffs none while it stands there, not flooded | drive | core | levels/test-water/drive/doused.spec.ts | implemented |
| E2E-567 | No fire in water: a car set alight on the yard (five hit points) and driven onto the pond's shelf is put out by the server, and neither flames nor smoke are drawn while it stands in the water | drive | core | levels/test-water/drive/doused.spec.ts | implemented |
| E2E-465 | The weapon the player holds is drawn in its hands as its model (empty-handed with the fists, the pistol with 2, the rifle with 4), and a shot leaves by the gun's muzzle: a rifle's well ahead of the shooter | drive | core | levels/test-core-gameplay/drive/held-weapons.spec.ts | implemented |
| E2E-466 | A rocket flies as the rocket's model, nose first along its flight, trailing smoke, and blows up in the new explosion (a fireball, a flash, a shockwave, a smoke column and a scorch) as big as its blast | drive | core | levels/test-core-gameplay/drive/held-weapons.spec.ts | implemented |
| E2E-467 | A shot from a car holds the pistol out of the seat (its model in the hand) for a moment, then the hands go back to the wheel | drive | core | levels/test-core-gameplay/drive/held-weapons.spec.ts | implemented |
| E2E-468 | A tyre gone flat pops in a puff of rubber smoke and sparks, the wheel drawn squashed onto its rim, and the rim throws sparks as the car rolls on | drive | core | levels/test-police/ai/three-stars.spec.ts | implemented |
| E2E-469 | A rich region’s ground is drawn in its biome’s tones and its landuse areas’ colours (15 or more on test-plots), with ground cover near the player: tufts of grass and flowers read off the ground’s colours | app | core | levels/test-plots/app/ground.spec.ts | implemented |
| E2E-470 | Each landuse area of a region is dressed with its own pieces, drawn where Go to puts the car: the farm’s windpump and bales, the vineyard’s rows of vines, the cemetery’s wall and graves, the campsite’s tents round its fire, the orchard’s fruit trees | drive | core | levels/test-plots/drive/plots.spec.ts | implemented |
| E2E-471 | A rich region’s points of interest are there to find at their places: a ruin, a camp round its fire, a viewpoint with its binoculars, an abandoned car; and a pond dug into the land, its water waded into from its shore | drive | long | levels/test-plots/drive/plots.spec.ts | implemented |
| E2E-473 | A town of six districts built of the buildings the generator makes from OpenStreetMap’s tags (test-osm-buildings: a high street, a farm village, works, homes, a street of shops, a leisure quarter) is drawn as the osm-* kits’ pieces: the works’ silo, tank and sheds by the spawn, other districts’ buildings along the avenue | app | core | levels/test-osm-buildings/app/osm.spec.ts | implemented |
| E2E-474 | The kit gallery looks at a building by the OpenStreetMap tag it is made from (/?kit-gallery=shop=bakery: the bakery of the osm-commercial kit, its loaf on the roof) | app | core | levels/test-buildings/app/kit-gallery.spec.ts | implemented |
| E2E-475 | On test-city-actions, on foot beside a bench the prompt offers Sit; E sits the player on its nearer free seat, drawn seated (sit-bench) facing the bench's way; a movement key gets them up in front of it | app | core | levels/test-city-actions/app/bench.spec.ts | implemented |
| E2E-476 | A cash machine (test-city-actions) pays the Cash carried into the bank but its $2 fee (Pay in $148), the wallet showing the balance ($0 · $148 in the bank); with no Cash to speak of it takes $100 out (and the fee) | app | core | levels/test-city-actions/app/money.spec.ts | implemented |
| E2E-477 | A kiosk's counter sells hot dogs, sodas and coffee, a market stall's snacks, sodas and ice cream, at their prices, for Cash (test-city-actions) | app | long | levels/test-city-actions/app/money.spec.ts | implemented |
| E2E-478 | At the wheel of a car standing still by a petrol station's pump, the panel offers Fill up $10; 1 fills up: the boost full at once and recharging twice as fast for a while, paid in Cash (test-city-actions) | drive | core | levels/test-city-actions/drive/fill-up.spec.ts | implemented |
| E2E-479 | The crowd keeps the city's routines at eight in the morning (test-city-actions, a crowd of forty): dog walkers, a street sweeper, an officer on its beat, the vendors beside the kiosk's and the stall's counters, a queue at the bus stop, a sitter making for the bench; drawn in their routines (a vendor leaning on its counter, a walker with its dog's lead held out, a sweeper's broom and cart, a sitter on the bench); every dog walker has its dog, an entity of its own and no person of the crowd | ai | core | levels/test-city-actions/ai/routines.spec.ts | implemented |
| E2E-480 | A bus the player stops at a bus stop takes its queue on board: the queuers walk to its door and are gone (test-city-actions) | ai | long | levels/test-city-actions/ai/routines.spec.ts | implemented |
| E2E-536 | A dog walker's dog is an NPC of its own (test-city-actions, a crowd of forty at eight in the morning): on its lead it ranges round its walker, its place relative to the walker changing by more than a metre while it keeps within the lead's 2.2 m, and the dogs on their leads stop to sniff; the crowd's readout lists the walker and no dog | ai | long | levels/test-city-actions/ai/dogs.spec.ts | implemented |
| E2E-537 | Beside the player a dog is drawn as the dog model in a pose of its own (standing, trotting, sniffing, sitting), no figure among the page's people and no pedestrian of its counts, its lead drawn from its walker's hand to its collar; its walker walks with the lead held out (walk-dog) while the dog is on it | ai | core | levels/test-city-actions/ai/dogs.spec.ts | implemented |
| E2E-538 | A pistol shot beside a dog on its lead sets it bolting: it pulls free with a yelp (a bark) and runs off; once it has calmed down it is back on its lead beside its walker, or stays a stray | ai | long | levels/test-city-actions/ai/dogs.spec.ts | implemented |
| E2E-539 | A stray dog wanders the pavements on its own: no walker and no lead, a good way along its pavement within a minute, never on the carriageway, stopping to stand, sit and sniff on its way | ai | long | levels/test-city-actions/ai/dogs.spec.ts | implemented |
| E2E-481 | V reaches the pickup, the limo, the delivery scooter, the ice-cream van and the tractor after the garbage truck, each named on the HUD and drawn as its own model, then wraps round to the compact; the tractor tops out near 40 km/h (test-new-vehicles) | drive | long | levels/test-new-vehicles/drive/classes.spec.ts | implemented |
| E2E-482 | An ice-cream van standing still a couple of seconds opens its hatch on its kerb side: a counter there sells ice cream and soda; driven off, it shuts (test-new-vehicles) | app | long | levels/test-new-vehicles/app/ice-cream.spec.ts | implemented |
| E2E-483 | A game’s NPC on a schedule sits on the free seat nearest its place at its sit hour, still while the hour lasts, and gets up at the next (on a server of the spec's own: the city actions' game with a civilian who lunches on the bench) | ai | core | levels/test-city-actions/ai/lunch.spec.ts | implemented |
| E2E-484 | The page plays on delta snapshots (__poc().net: one keyframe, never a lost thread, a fraction of whole snapshots’ bytes on test-traffic-junction’s sixteen cars), and a car out in the far tiers, its pose sent every second or fourth snapshot, is drawn gliding between its updates, never standing still nor jumping | net | core | levels/test-traffic-junction/net/deltas.spec.ts | implemented |
| E2E-485 | A city whose game server takes no new room (past its players: FOI_CAPACITY) turns the page away as full: it says the room or its server is full and it tries again in 30 seconds, and it does | net | long | levels/test-core-gameplay/net/fleet.spec.ts | implemented |
| E2E-486 | A game server drained for maintenance (POST /drain with the room secret; 401 without): its players read in the room's chat that it restarts in so many seconds, at the deadline their game ends as restarting and the page says so, and once a server is back on its port the page plays again | net | long | levels/test-core-gameplay/net/fleet.spec.ts | implemented |
| E2E-487 | The keys are remappable on the Controls screen (the main menu's and the pause menu's): a key pressed after its action's button becomes that action's, swapping with the action that had it (the screen says so); the fixed keys (Esc, Enter, the number keys) cannot be taken; the car drives on the new key and not the old one, every text names the new keys (the HUD's, the prompt's), they are kept across a reload, and Reset puts every key back | app | core | levels/test-core-gameplay/app/controls.spec.ts | implemented |
| E2E-488 | The main menu asks once, at the first start, whether to send crash reports and anonymous statistics (both unticked; yes to both, no thanks, or the choice ticked); the answer is kept, never asked again, and changed in Settings → Privacy, where a new anonymous id can be made | app | core | levels/test-core-gameplay/app/privacy.spec.ts | implemented |
| E2E-489 | A crash (an uncaught error on the page) is reported to the platform's /telemetry/crash only when the player agreed, once, scrubbed of home folders and query strings, with where in the game it happened; a page its server turns away (no such room) is no crash | app | core | levels/test-core-gameplay/app/privacy.spec.ts | implemented |
| E2E-490 | The privacy policy and the terms are pages of their own (?privacy, ?terms), in both languages, the operator in neutral words where the platform names none, linked from the main menu's footer (and the pause menu's, the game pages') and from the sign-in form, which says that signing in accepts the terms | app | core | levels/test-core-gameplay/app/privacy.spec.ts | implemented |
| E2E-491 | The weather's rain (the View tab's picker, on a server whose debug commands are on) falls in streaks round the player, the roads wet and shining, the icon by the clock saying so; a storm's lightning flashes; clear weather stops it and dries the roads | app | core | levels/test-weather/app/weather.spec.ts | implemented |
| E2E-492 | A car braking hard on a wet road stops with less bite than on a dry one (four fifths of it: gently), its deceleration worked out from where it was and how fast it went during the stop | drive | core | levels/test-weather/drive/braking.spec.ts | implemented |
| E2E-493 | At night every street lamp pools its light on the ground under a halo at its head, a share of the windows is lit with their light on the pavement, and the player's car's headlights come on, its beams on the road; the Settings' brightness at night lifts the dark (kept in the browser) | app | core | levels/test-weather/app/weather.spec.ts | implemented |
| E2E-494 | At two in the morning, where the night shortens sight, a guard misses a player 12 m off in the dark but sees one 12 m off under a street lamp; by day the same 12 m in the dark street are seen | ai | core | levels/test-weather/ai/night.spec.ts | implemented |
| E2E-526 | A street lamp knocked down by a truck goes out: its pool of light and the halo at its head are gone (five lit, then four, one out) while the others stay lit, for as long as it lies there; a level reset plants it and lights it again | app | long | levels/test-weather/app/lamps.spec.ts | implemented |
| E2E-527 | A lamp knocked down is out for the guards too: 12 m in front of the lit street's guard under its first lamp a player is seen (the page reads the lamp's share of sight there); the lamp knocked down, the guard comes to look at the noise and goes back to its post, and the same spot is dark (the night's share of sight) and the player goes unseen; under the next lamp the street is lit as before | ai | long | levels/test-weather/ai/night.spec.ts | implemented |
| E2E-528 | The windows are lit by the hour, the same ones for as long as the hour stands: most at nine in the evening, with the ground floors' light on the pavement, fewer than half of them at three in the morning, none at noon (nor any pool, patch or beam) | app | core | levels/test-weather/app/weather.spec.ts | implemented |
| E2E-529 | At night every car that somebody drives throws its headlights on the road (__poc().night.beamCars): the player's own at the wheel and each ambient car under way on screen; the car the player leaves stands parked with its lights off while the traffic drives on with its own; by day no car has them on | app | core | levels/test-traffic-junction/app/night.spec.ts | implemented |
| E2E-530 | With a GPU the three lit lamps nearest to where the camera looks light the cars and the people under them (__poc().night.actorLamps), none by day; the software renderer makes no such light and draws the pools on the ground all the same | app | core | levels/test-weather/app/lamps.spec.ts | implemented |
| E2E-495 | A mission's skipTime skips the room clock three hours on, the screen fading with "3 hours later", and its setWeather brings the rain in; the View tab's skip does the same | app | core | levels/test-weather/app/mission.spec.ts | implemented |
| E2E-496 | Fog thickens the haze over the scene while the minimap stays as clear as it was | app | core | levels/test-weather/app/weather.spec.ts | implemented |
| E2E-497 | Snow falls round the player and whitens the ground, the icon by the clock saying snow | app | core | levels/test-weather/app/weather.spec.ts | implemented |
| E2E-498 | A region's highway with tunnels: "auto" holds its grade under a mountain in a long tunnel: driven through on the road's bed, its roof faded over the car while it is under it, nothing faded once out | drive | core | levels/test-tiles-tunnel/drive/tunnels.spec.ts | implemented |
| E2E-499 | A country road with tunnels: "auto" goes through two hills in two short tunnels, one after the other, each roof fading in turn | drive | long | levels/test-tiles-tunnel/drive/tunnels.spec.ts | implemented |
| E2E-500 | On foot over the mountain's flank, a tunnel's roof carries the player across the road far under it and stays drawn | drive | long | levels/test-tiles-tunnel/drive/tunnels.spec.ts | implemented |
| E2E-508 | Your games (?browse&list=mine) asks a guest to sign in, then lists the creator's draft with its last build and a link to look round its level, and the game they shared by link; Friends' lists a friend's link-shared game, which the public list does not | platform | core | platform/yours.spec.ts | implemented |
| E2E-509 | A build's preview (?preview=<artifact>) draws its level under the galleries' free camera, lists its places and spawns to find by name (a place found flies the camera there), and loads it from the browser's store the next time | platform | core | platform/yours.spec.ts | implemented |
| E2E-516 | Claude Code signed in with OAuth: a client registered with the API opens its sign-in page, the creator signs in with an e-mail and a password and allows it on the consent (their name and the client's callback shown); the browser goes back to the client's loopback callback with a code and the state, the code and its PKCE verifier give an hour's access token, and the MCP server's creating tools take it (a draft made as the creator) | platform | core | platform/oauth.spec.ts | implemented |
| E2E-517 | The OAuth sign-in page: Deny sends the browser back to the client with access_denied and the state, no code; a link naming a redirect URI the client never registered stops on the page with why, sending nobody there | platform | core | platform/oauth.spec.ts | implemented |
| E2E-518 | At a simulated 10 % loss (K cycles 0, 2, 5, 10, 20 %; the HUD's latency line shows it) of the snapshots and the input frames, with jitter, over the page's WebSocket, the server switches the page to the acked snapshots and the car drives on with corrections under 0.5 m, never a keyframe asked for; one press of E gets the player out and one more back in, each landing once | net | core | levels/test-core-gameplay/net/loss.spec.ts | implemented |
| E2E-583 | Your games (?browse&list=mine) says each waiting build's place in the platform's build queue (data-position, "number 1", "number 2" for the creator's two builds an API holding every build took), asking again while builds wait, and shows both built once an API that builds comes back on the same store | platform | core | platform/queue.spec.ts | implemented |
| E2E-584 | A build queued when the API is killed is built after an API comes back on the same file store, of the game as it was queued (the draft edited meanwhile), its place in the queue said while it waited; the day's build quota spent before the restart still counts | platform | core | platform/queue.spec.ts | implemented |
| E2E-585 | An admin (FOI_ADMINS) reaches the admin page (?admin) from the game pages' account bar and the main menu's Admin, finds an account by name, sees its builds a day and today's use, raises its builds to 3 with a note: its next build past the default (1) is accepted; the override is listed and the change ("Builds default → 3", the note, the admin) is in the audit trail; Reset puts the default back and the next build is refused | platform | core | platform/admin.spec.ts | implemented |
| E2E-586 | A signed-in player who is no admin sees no admin entry on the account bar or the main menu; ?admin says the page is for the platform's admins; the admins' routes answer 403 to a creator and a guest, 401 to nobody signed in | platform | core | platform/admin.spec.ts | implemented |
| E2E-587 | On a platform for the game's owners (FOI_ENTITLEMENT=steam, the fake Steam) the game pages offer only "Sign in through Steam" (no e-mail form); an owner signs in through Steam's OpenID (the fake's page) and plays a city online on a game server that asks every player for a join token (FOI_JOIN=token): /play signs one for the level's room | platform | core | platform/steam.spec.ts | implemented |
| E2E-588 | Back from Steam's OpenID the page is signed in (its session kept) and the sign-in's one-time code is gone from the address (history.replaceState), the page's own query (?browse&sort=top) as it was | platform | core | platform/steam.spec.ts | implemented |
| E2E-589 | A Steam account without the game is told so (#browse-steam-refused, not-owned) with "Get it on Steam" (the store's page, FOI_STEAM_STORE_URL), and nobody is signed in: no session, no guest; playing a city online then shows why, "Sign in through Steam" and "Get it on Steam" (#play-refused) instead of the game | platform | core | platform/steam.spec.ts | implemented |
| E2E-590 | A game server with FOI_JOIN=token refuses a bare /game, a ?level= and a forged token with 4401 before any room opens (no Riverbend room after a ?level=main-riverbend); /play's address for an owner joins; a page on the bare server is told its invitation ran out | platform | core | platform/steam.spec.ts | implemented |
| E2E-591 | Claude Code's OAuth sign-in page on a platform for the game's owners has no e-mail form: "Sign in through Steam" (the fake's OpenID) comes back to the consent, Allow sends the code to the client's callback, and its access token is the Steam account's, which makes a draft | platform | core | platform/steam.spec.ts | implemented |
| E2E-592 | A lent copy (family sharing, shared on the fake) signs in and plays a city online, but makes no games: Your games says, in the refusal's own words, that making games needs a copy of one's own and POST /drafts answers 403 shared | platform | core | platform/steam.spec.ts | implemented |
| E2E-593 | An e-mail account from before the platform was for owners links its Steam account ("Have an e-mail account? Link it to Steam": Steam's OpenID, then its e-mail and password) and keeps its drafts (Your games lists them, "Linked to Steam"); signed out, signing in through Steam lands in the same account | platform | core | platform/steam.spec.ts | implemented |
| E2E-594 | The desktop app on a platform for the game's owners (the fake Steam, FOI_STEAM=fake): Play online's "Sign in through Steam" signs in with the app's Steam ticket (window.foi.steam.ticket, the main process's fake one, FOI_STEAM_FAKE_TICKET), never by itself the first time and without a window; the session is the Steam account's, and a city plays on the game server that asks every player for a join token | app | smoke | smoke/steam.spec.ts | implemented |
| E2E-595 | A Steam ticket for an account without the game is refused on the desktop app's Play online: #menu-steam says why (not-owned) with "Get it on Steam" (the store's page), and nothing is kept: no session, no sign-in for the next time | app | smoke | smoke/steam.spec.ts | implemented |
| E2E-596 | With Steam not running (no ticket), the desktop app's Play online "Sign in through Steam" opens Steam's page (the fake's) in a window of the app's own; signing in there closes it on its way back (the redirect to the platform caught by the main process) and the page exchanges the one-time code for the Steam account's session | app | smoke | smoke/steam.spec.ts | implemented |
| E2E-597 | Once the desktop app signed in through Steam on this device, it signs in again by itself with its ticket where its session is gone: on Play online (no click) and on the game pages' account bar; signed out there it no longer does, and the account bar's "Sign in through Steam" signs in with the ticket | app | smoke | smoke/steam.spec.ts | implemented |
| E2E-600 | Creating in the game (?create, FOI_CREATOR=fake, a creator runner with the scripted model): a brief of 2 missions goes from queued to running with its step ("Running: writing the missions"…) to done, spending one of the day’s five creations; its result shows its title, its missions, its preview and Look round, and Playtest plays it in a room | platform | core | platform/create.spec.ts | implemented |
| E2E-601 | A creation cancelled while it waits in the queue (its place in line said) is over at once and its creation is given back (5 left again) | platform | core | platform/create.spec.ts | implemented |
| E2E-602 | A creation cancelled while it runs stops within seconds: the page says cancelled, its draft so far stays (shown once its texts were checked: while the model writes it, with moderation on, nobody but the creation sees it) and moves on no more, and its creation stays spent | platform | core | platform/create.spec.ts | implemented |
| E2E-603 | An account’s sixth creation of the day is refused: the page says none are left and that they start again in so many hours (midnight UTC), and the API’s reason | platform | core | platform/create.spec.ts | implemented |
| E2E-604 | After an admin raises an account’s creations a day to 10 on the admin page (5 used of 5), its sixth creation is accepted | platform | core | platform/create.spec.ts | implemented |
| E2E-605 | While a running creation holds the day’s budget, an account an admin made budget-exempt sees creation open and its brief is queued, while ordinary accounts are refused | platform | core | platform/create-budget.spec.ts | implemented |
| E2E-606 | The admin page lists the platform’s creations (another owner’s, running, with its brief) and the model’s budget (today’s to spend, the month of $25), and an admin’s Cancel stops it: cancelled "by admin", its creation not given back | platform | core | platform/create.spec.ts | implemented |
| E2E-607 | A second creation of an owner waits while the first runs, the page saying why and its place ("Waiting for your other creation to finish · number 1 in line"), and runs once the first is done | platform | core | platform/create.spec.ts | implemented |
| E2E-608 | In a game the platform opened, the owner signed in, the toast of a creation that ended ("“…” is ready: open it") opens the creation page on its result, done and playable | platform | core | platform/create.spec.ts | implemented |
| E2E-609 | Revise on a creation’s result queues a new creation on the same draft (the form says which, without the level’s choices): done, the draft at a later revision with its new title and missions, a creation spent for each | platform | core | platform/create.spec.ts | implemented |
| E2E-610 | With the day’s budget held by a running creation (the month’s cap set to ten cents a day), the creation page says creation resumes in so many hours and takes no brief, the API refuses one without spending a creation, and a creation queued behind says it waits for budget | platform | core | platform/create-budget.spec.ts | implemented |
| E2E-611 | With creation off (FOI_CREATOR=off), the main menu’s Create opens the creation page, which asks a guest to sign in and tells an account creation is not available on this platform; the API answers 503 | platform | core | platform/create-budget.spec.ts | implemented |
| E2E-612 | On a platform for the game’s owners (FOI_ENTITLEMENT=steam, the fake Steam) with creation on, a lent copy (family sharing) signed in through Steam is told on ?create that creating needs a copy of its own and can send no brief, and POST /jobs refuses it (403, shared); an owner of a copy of their own signed in through Steam has a brief queued | platform | core | platform/create-steam.spec.ts | implemented |
| E2E-620 | A brief the moderation refuses (the platform's word list) is turned away on ?create before any model runs: the page says moderation refused the brief, the allowance stays 5 left, nothing is queued for a runner, and POST /jobs answers 422 moderation | platform | core | platform/create.spec.ts | implemented |
| E2E-621 | When the scripted model writes a blocked word into its game (FOI_CREATOR_FAKE_BLURB), the creation fails with "moderation refused what the model wrote" and shows nothing of it: no result, nothing in Your games, the word nowhere in what the API answers; its creation stays spent | platform | core | platform/create.spec.ts | implemented |
| E2E-622 | On a platform for the game's owners, ?create offers a visitor nobody signed in to "Sign in through Steam" (never "Loading…"), and the fake Steam's OpenID comes back to the creation form signed in, 5 creations left | platform | core | platform/create-steam.spec.ts | implemented |
| E2E-623 | On a platform for the game's owners, Your games asks a visitor nobody signed in to sign in through Steam, and tells a lent copy in the refusal's own words that making games needs a copy of its own, never that the platform is not answering | platform | core | platform/create-steam.spec.ts | implemented |
| E2E-624 | The privacy policy names Anthropic (Claude, straight), OpenRouter, the model providers (Google, OpenAI, DeepSeek, Alibaba) and Valve, and keeps the creations' conversations 30 days, in both languages; it says what is kept of Respect and conduct, that conduct is worked out only from what the game server measures in a run and from reports a moderator upholds, and how to download it (Your standing, the conduct score and the skill rating included) and have it deleted ("Respect and conduct", "Rispetto e condotta"); the terms say how creating with the platform's model is moderated and that Steam's Subscriber Agreement applies | app | core | levels/test-core-gameplay/app/privacy.spec.ts | implemented |
| E2E-625 | The admins' page shows the Steam account an account signs in with (an admin signed in through Steam, FOI_ADMINS): in the search's results and on the account | platform | core | platform/create-steam.spec.ts | implemented |
| E2E-626 | Other cars are drawn from the server's measurements alone (RemoteIntake, @foi/net-client: a sample pushed only where a frame measured a pose, at the tick measured; a stop and a start sent at once, whatever the car's turn; a far car drawn behind the render tick by its tier's delay, between two of its measurements): on test-traffic-junction from the level's corner, a far car (85 to 245 m) setting off from its light after standing is never drawn faster than 1.3 times the speed the server had it over the last half second, and its wheels turn at the speed its body moves; measured per drawn tick, so a software renderer's frame rate is no jolt | net | core | levels/test-traffic-junction/net/measured.spec.ts | implemented |
| E2E-627 | No figure walks on the spot after stopping, and none is posed standing while its body moves: on test-core-gameplay among its crowd, over ten seconds of frames, every person in view whose body stands over two drawn frames plays a standing clip with its feet still, and every one whose body moves over two frames plays a moving clip (a stop is a measurement the server sends at once; the speed a figure animates at is the speed its body is drawn moving at); measured per drawn tick | net | core | levels/test-core-gameplay/net/figures.spec.ts | implemented |
| E2E-628 | An entity the server removes leaves the screen with the next snapshot, never held where it was: on test-traffic-junction a reset of the level (Backspace) takes the sixteen cars away, none of them is drawn a quarter of a second later, and the traffic made anew comes back under the same ids as new remotes (each id's life, RemoteReading.life, counted up: the simulation turns an id's generation over on every removal and the snapshots carry it, so an id back is a new entity on the wire) | net | core | levels/test-traffic-junction/net/measured.spec.ts | implemented |
| E2E-640 | A stall of the snapshots (window.__stall(300): the frames received held 300 ms and handed over together) is absorbed without a leap: the other player's car keeps its pace through it, the drawn tick never standing nor leaping (every frame's advance within 2 % of its own length, never backward) and the car never moved farther in a frame than its pace's share of it plus what its buffer may have held past its extrapolation limit | net | core | levels/test-core-gameplay/net/stall.spec.ts | implemented |
| E2E-641 | A car coming within touching range of the player's goes onto the predicted timeline without a dash (PredictedRemotes: the blend from its interpolated pose to its predicted one bounded to a third again its pace, entered from as far as that blend needs, Mirror.predicts): on test-collisions, a chaser dropped on the road behind and ramming the player's car is seen blending and then drawn at the twin, and per drawn tick no frame moves it faster than a third again its pace (its speed over the last half second and the acceleration over the timelines' gap) plus what a decaying snapshot correction of its twin may add; the contact depth stays at zero (__poc().contact.deepest under the hulls' reach past the boxes) | net | core | levels/test-collisions/net/contact.spec.ts | implemented |
| E2E-645 | The ambient cars accelerate and brake like drivers (traffic-drive.ts: an acceleration commanded, 2.5 m/s² pulling away, 4 braking, 8 in an emergency, the foot moving at 8 m/s³, realised through the class's engine and brakes; the amber decided once): on test-traffic-junction over a minute of the lights, the server's own measurements of the sixteen cars (__remotes(), a new one when the recorded tick moves on) change a car's speed by more than 5 m/s² between two measurements in under half a per cent of the intervals, by more than 12 (a collision) twice at most, and never flip from over 3 m/s² one way to over 3 the other within consecutive measurements more than once | ai | long | levels/test-traffic-junction/ai/smooth.spec.ts | implemented |
| E2E-642 | A crash of the player's car into a wall at 80 km/h on test-collisions is immediate: the prediction stops it in one tick and the drawn car stops within two frames, never drawn on past it; the crash is heard and shown in the hit log on the frame the prediction feels it, a round trip before the server's hit, which sounds nothing again; the server agrees with the prediction through the crash, nothing corrected at the impact (under 5 cm: a confirmed prediction is never run again, Predictor); the camera stops with the car within four frames, comes back onto it at under 10 m/s (LookAhead.impact) and shakes | net | core | levels/test-collisions/net/impact.spec.ts | implemented |
| E2E-643 | At a simulated 150 ms of round trip (L, ten inputs or more in flight) the crash into the wall is as immediate as E2E-642, the server's word on it coming over 150 ms after the crash was heard, and nothing corrected over the crash when that word comes | net | core | levels/test-collisions/net/impact.spec.ts | implemented |
| E2E-644 | Rear-ending another player's car at rest at 80 km/h is felt, heard and shown in the hit log on the frame the prediction meets it (slowed by over 5 m/s), never sounded again by the server's word on either car, and the correction when that word comes is under 10 cm (the twin is simulated where the server has it) | net | core | levels/test-collisions/net/impact.spec.ts | implemented |
| E2E-647 | A hydrant knocked loose at 80 km/h on test-breakables is heard on the frame the prediction knocks it (vehicle.knock, the local world's own break) and drawn flying within two frames where the local world has it (PredictedPieces: a light piece near the player drawn at the local time from the tick it comes loose, not from the snapshots a lead and the interpolation delay behind), the car never drawn on through where it stood | net | core | levels/test-breakables/net/knock.spec.ts | implemented |
| E2E-646 | A stall of the page (200 ms) just after a crash into the wall on test-collisions costs no correction: the ticks the frame loop drops are run in the prediction on the server's guess, the last input held without its presses (Predictor.guess, guessedInput), and a snapshot acknowledging ticks the page had not reached has them run on it first (Predictor.catchUp), so every snapshot after the stall stands on the prediction | net | core | levels/test-collisions/net/impact.spec.ts | implemented |
| E2E-648 | A co-op mission never starts in a level's room (the hub): on a server of test-mission-basics whose game lists its co-op mission ("Carpool Pilot") first, the player who joins is given the first solo mission ("Same-Hour Rental") and the tracker counts the hub's two solo missions; no run frame reaches the page | app | core | levels/test-mission-basics/app/run-hub.spec.ts | implemented |
| E2E-649 | A party of two opens a published game's co-op mission from its game page (the mission listed as Co-op, 2–4 players, with a Play of its own that opens a lobby of the party: the member's page asks, "leader joined a lobby", and Join takes them into it) and, both ready, both land in one new room-… of its own: one run, a seat each; the countdown holds the cars (a second of full throttle moves nothing), then both trackers show the run's one objective ("Meet at the checkpoint", 1 mission) | platform | long | platform/runs.spec.ts | implemented |
| E2E-650 | Reaching the checkpoint finishes the co-op run for both: the results ("Run complete", each seat's part) on both screens, the run's room closed a few seconds later on the game server, and GET /runs/:id answering complete with both accounts, a seat credited | platform | long | platform/runs.spec.ts | implemented |
| E2E-651 | A run's player who reloads within the minute takes their seat back (the same seat, both seats present again on the other player's page); a stranger with a join token of the run's room (signed with the room secret) not on its roster is refused by its server with 4403, and the platform gives them neither a join URL of the room (POST /rooms/:id/join: 403) nor a seat (POST /runs/:id/rejoin: 404) | platform | long | platform/runs.spec.ts | implemented |
| E2E-652 | A run whose tries are used up ends failed: a creator's playtest of a short co-op mission (its minimum relaxed, out of time in 5 s, one retry) goes back to its start once, then shows "Run failed", and GET /runs/:id answers failed, marked a playtest (lives used up are the runtime's and the run room's integration tests) | platform | long | platform/runs.spec.ts | implemented |
| E2E-653 | The teams of a versus run on test-versus (a debug run of robbers and chasers, two robbers and a chaser, /?run=getaway&team=…): each team starts at its spawn (the robbers south of the bank, the chaser north of it), every page knows its own team and the roster colours each player by theirs (two teams' colours); on foot on the avenue a robber's rifle hits the other robber for no damage (the hit log says so, their health stays full) and hurts the chaser | net | core | levels/test-versus/net/teams.spec.ts | implemented |
| E2E-654 | A robber whose car is held stopped beside a chaser's for three seconds is caught (getaway_spectate: a caught robber watches): out of the run, their body out of the world, their camera on the other robber (#run-watching with its seat, Space keeping to the one teammate there is), the run live for the other robber, every roster marking the caught one out (a caught robber sent back to the team's spawn is the run room's integration test) | net | core | levels/test-versus/net/catch.spec.ts | implemented |
| E2E-655 | The loot delivered: the robber picks it up on foot by the bank (E) and stands in the hideout with it, and both screens show "Robbers win" (#run-results won by robbers); the level server's result of the run (GET /runs/<id>, what it reports to the platform) says won, winner: robbers, with both seats on their teams | app | core | levels/test-versus/app/getaway.spec.ts | implemented |
| E2E-656 | Time running out on robbers and chasers (getaway_short, its eight-second clock, nobody delivering): the chasers win, "Chasers win" on both screens | app | core | levels/test-versus/app/getaway.spec.ts | implemented |
| E2E-657 | A race between two players (sprint, every player on their own: seats p1 and p2): the second player goes through the loop's four gates in order (the tracker pointing at the next after each) and wins the run on both screens; the results place both seats, the winner first, the other second (__poc().run.places, each row's data-place); the gates were reached with Go to, a debug command, so the results say the run pays nothing and why (#run-debug) | app | core | levels/test-versus/app/race.spec.ts | implemented |
| E2E-658 | A lobby made from a game page (a published game's short co-op mission: its Play opens a lobby, the player its host, the rules in words on its card): a second player opens its link and joins, both on the crew, the lobby in its ready check; both ready, the countdown on both pages, then both land in one run of the mission (one run-…, seats 0 and 1, each page's address remembering the lobby) | platform | long | platform/lobbies.spec.ts | implemented |
| E2E-659 | The host's Start is disabled under the mission's minimum (a co-op lobby of one) and enabled once a second player joins by the link (nobody but the host has it); a member the host kicks sees their page say so (#lobby-gone, kicked) with the way back and none of the lobby's buttons; when the host leaves, their page goes to Play together and the lead passes to the other member, alone again, Start disabled again | platform | long | platform/lobbies.spec.ts | implemented |
| E2E-660 | Quick play's Races puts two players who are not friends in one public lobby (test-versus's sprint, curated with FOI_DEBUG=1 on the API): the first opens it, the second is placed in it, both ready, so it counts down at once at its minimum, and both race in one run, seats p1 and p2 | platform | long | platform/lobbies.spec.ts | implemented |
| E2E-661 | After a run, both pages come back to the lobby with its results ("Run failed", each seat's row); the vote offers a mission on another level that takes the group (test-versus's robbers and chasers), both vote for it, the lobby moves there with its teams made again (one robber, one chaser), both ready, and both land in its run on test-versus, on their teams | platform | long | platform/lobbies.spec.ts | implemented |
| E2E-662 | Replay: the run over and both pages back in the lobby with its results (the run's id, two seats), both vote Replay and land at once in a new run of the same mission (another run-…, the same mission) | platform | long | platform/lobbies.spec.ts | implemented |
| E2E-663 | After a clean co-op run of a curated mission (Carpool Pilot from test-mission-basics' page, two players who are not a party, the checkpoint reached), the lobby's results show what it paid ("+N Respect", #run-standing, its base among the steps) with the player's tier and total now; each lobby member shows their tier (Unverified); the account bar shows the tier and the total (#browse-standing), and the standing's page (?profile) the same, the next tier (Local) and the conduct band (good) | platform | long | platform/respect.spec.ts | implemented |
| E2E-664 | A player who shoots a teammate on foot in a mission of friendly fire (the lobby's rules say "Friendly fire on") until they are under half their health, then leaves for good, gets nothing (GET /runs/:id/standing: 0, not there at the end) once the run runs out of time; on the admins' page (?admin, the account found by its id) their conduct is under 7,500 and the run's line says why (leaving a run, and hurting or killing a teammate) | platform | long | platform/respect.spec.ts | implemented |
| E2E-665 | A mission that asks for Respect tier 2 (a creator's, held there until it qualifies) says so on its lobby's card ("Respect tier 2 (Local) or higher"), its host showing Local; a player of tier 1 who asks to join is refused, the lobby saying which tier it needs and what they have, and stays out of it | platform | long | platform/respect.spec.ts | implemented |
| E2E-666 | A teammate outside one's party is endorsed from the lobby's results (Endorse beside their name); the endorser's results say so and the endorsed's show "Endorsed by name: +5" as it comes | platform | long | platform/respect.spec.ts | implemented |
| E2E-667 | The same mission played again that day (Replay) pays less: the results show fewer Respect than the first time, with the step "Run 2 of this mission today: ×0.5" | platform | long | platform/respect.spec.ts | implemented |
| E2E-668 | The leaderboard (?leaderboard) lists the season's players by the Respect they earned in it, the most first, the reader's own line marked; its all-time tab lists them too | platform | long | platform/respect.spec.ts | implemented |
| E2E-669 | A versus lobby's teams are balanced by the players' hidden skill (four players of 2,200, 2,100, 900 and 800 joining in turn come out robbers 2,200 and 800 against chasers 2,100 and 900, where their numbers alone would have made 3,100 against 2,900) | platform | long | platform/respect.spec.ts | implemented |
| E2E-680 | Under always (test-versus's "Open Plan": robbers 1–2, one chaser, 2–3 players), a seat dropped past its minute (four seconds on the spec's server, FOI_RUN_GRACE_S) is filled by a Quick play player: the run's room advertises the robbers' seat (RoomStatus.open), Quick play for Versus seats the player straight in the run under way on that team (seat 3), at the robbers' spawn, the tracker on the robbers' objective under way; the others see the seat filled and nothing more open | platform | long | platform/continuous.spec.ts | implemented |
| E2E-681 | Under untilCheckpoint (test-mission-basics' "Carpool Relay"), once the run's first checkpoint is saved no seat is filled: a player who leaves for good after it is gone past their minute and the room advertises no open seat, and Quick play for Co-op puts another player in a lobby of their own, never in the run, which plays on | platform | long | platform/continuous.spec.ts | implemented |
| E2E-682 | The phone's Jobs app in the city (a room of a game on test-mission-basics, never a run's): its tile on home, its page listing a stranger's public lobby on test-versus and the missions of other levels; picking the lobby opens its page (?lobby=), where the player joins it and invites a friend, whose Jobs page (open meanwhile) gets the invitation on top | platform | long | platform/continuous.spec.ts | implemented |
| E2E-683 | A lobby opened from a playlist on the Play together screen (Co-op's missions across levels, Carpool Pilot's "Open a lobby") remembers it (#lobby-playlist); after its run the vote offers the playlist's next mission on another level (Riverbend), and when nobody votes the lobby moves on there once the vote's time is out, never playing the same mission again | platform | long | platform/continuous.spec.ts | implemented |
| E2E-684 | A seat filled under way is paid its Respect pro rata: a player Quick play seats in a co-op run whose seat was given up (straight into it, seat 2, the tracker on the objective under way) and who plays it out gets "+N Respect" in the lobby's results with the step "Your part of the run: N % of it"; the player there from start to end has no such step | platform | long | platform/continuous.spec.ts | implemented |
Not covered on purpose
- Creations by a real model on OpenRouter or on Anthropic's API (
FOI_CREATOR=openrouter,claude): no key exists in the tests and none may be used. The end-to-end tests run the scripted model (FOI_CREATOR=fake); OpenRouter's and Claude's clients, their prices and the per-call bound are unit-tested on recorded answers' shapes through an injectedfetch(apps/creator/src/openrouter.test.ts,claude.test.ts,runner.integration.test.ts); the real models are measured by hand withnpm run creator:evalon a key of its own (apps/creator), and the live platform's first week is watched against OpenRouter's activity (Operations). - Driving feel (drift balance, camera smoothness) is judged by hand in
npm run dev; the vitest envelope tests inpackages/simpin the numbers. - A new life under a reused entity id arriving at a client as a removal and a new entity, and a pose measured in a lost frame recorded at the tick it was true: in-process (
packages/protocol/src/snapshot-v2.test.ts,snapshot-acked.test.ts,snapshot-acked.property.test.tsover two hundred lossy worlds,apps/server/src/snapshots.test.tswith the crowd's despawn and spawn in one step,packages/sim/src/lifetimes.test.ts); the netcode probe's invariants on the drawn picture against the server's word (tests/netcode/harness.test.ts,stale-samples.integration.test.ts: no car over 1.3 times its authoritative speed in any tier, no stale fill, no slide, no figure walking on the spot, no teleport within 80 m, no freeze at a reappearance), which a browser's frame rate without a GPU would blur. - Real packet loss and reordering: the WebSocket transport cannot produce them. The page's simulated loss (
K, E2E-518) drops and jitters frames over it; the acked snapshots are held to the ordered ones through loss, duplicates and reordering in-process (packages/protocol/src/snapshot-acked.property.test.ts,apps/server/src/lossy.integration.test.ts). - A player joining a Riverbend server does not stall the others' snapshots: the measure is the server's loop (a join is handled between two steps; on Riverbend it held the loop 60 to 150 ms, a gap in every player's snapshots at every join), in milliseconds a shared runner drawing at 14 to 45 fps cannot judge from a page, and the page's intake is the client's own. The invariant is held in-process on a real Riverbend server with its game, the join's own time and the twelve steps after it each under 25 ms and the newcomer's first snapshot within two snapshot intervals of its welcome, by
apps/server/src/join.integration.test.ts, for the first player into the room as it opened as for the others (the room's world warmed as it opened,GameServer.warmUp: a browser sees only a page connecting a second longer), and measured on the real stack with the netcode probe (tests/netcode: a recorder's snapshot gaps while other bots join, the loop's late steps from/metrics).