SupplyTruck
The weapons truck: drive into the back, pick a refit, roll back out.
What it does
supplyTruck.dispatch brings a tractor and its trailer onto the slow lane, arriveAhead metres in front of the player. The tractor is an ordinary car with an AutoRunnerDriver in the truck role. The trailer is dragged behind it.
Drive into the back of the trailer, roughly lined up. Full throttle is fine; coming in sideways is a crash. The car turns ghost, rolls to the middle of the trailer over loadSeconds and goes out of sight. While it rides inside, the HUD offers up to three refits:
- missiles: +3
- oil slicks: +5
- smoke screens: +5
- guns: one level up
- armour: a full repair
A weapon you are full of is never offered. Armour only shows up below 95% health, unless there is nothing else to offer. Pick one with the chooseKeys, or the first offer is fitted after menuSeconds. Then the car rolls out of the tail a little slower than the truck, and the truck speeds off and goes back to its pools.
If the player never docks, the truck waits patience seconds, or gives up at once if the player drives 70 m past it or drops 160 m behind.
supplyTruck.deliver uses the same truck for a new life: the new car rides inside for deliverSeconds and is let out behind it.
Use it in a scene
A scene is just data — a list of entities, each with its components. At startup the SceneLoader turns this JSON into a live world; edit the file and reload to rebuild it.
Build it from scratch with the bjs CLI:
- 1Scaffold a project
World, renderer, and dev server — ready to run.
- 2Install dependencies
- 3Add SupplyTruck
Copies its source into src/ so the scene resolves.
First time? Run bjs login once.
- 4Paste the scene into src/scenes/arcade-room.ts and run
SceneLoader builds the world from the JSON; reload to rebuild.
Give the trailer "kinematic": true on CarCollision, so a crash pushes other cars off it without fighting the hitch.
The trailer swings wide
The trailer is never driven. Each frame its nose sits on the tractor's hitch and its heading eases toward the tractor's:
d is the angle between tractor and trailer. Speed times dt is the distance the truck moved, so the trailer turns by distance, not by time. For each trailer length of road, the angle shrinks by about two thirds, at any speed. A 6.4 m trailer at 30 m/s covers its own length in about 0.2 seconds. Through a bend the trailer lags the tractor and cuts inside its line, which is why a real semi swings wide.
The dock gate
Docking is a box behind the trailer's doors. The player's nose has to be in it, lined up, and closing:
maxAngle is about 31 degrees. A player who aims at the back of the truck gets in. One who comes in at 45 degrees rams the trailer instead.
Settings
| Field | Default | What it does |
|---|---|---|
player | "Player" | The car it serves |
cabPool | "truckCab" | Pool the tractor comes from |
trailerPool | "truckTrailer" | Pool the trailer comes from |
cruiseSpeed | 30 | The truck's pace on the road, m/s |
arriveAhead | 75 | How far ahead of the player it turns up, metres |
hitchBack | 0.4 | Hitch distance, metres. The hitch sits half the tractor's length + hitchBack − 0.6 m behind its centre. |
loadSeconds | 0.6 | Seconds the car takes to roll from the doors to the middle of the trailer |
menuSeconds | 6 | Seconds to pick a refit before the first one is fitted |
deliverSeconds | 1.4 | Seconds a new car rides inside before it rolls out |
patience | 30 | Seconds the truck waits on the road before it leaves |
chooseKeys | [["Digit1", "Numpad1"], ["Digit2", "Numpad2"], ["Digit3", "Numpad3"]] | Keys for refits 1, 2 and 3 |
Events
| Event | Payload | Direction |
|---|---|---|
supplyTruck.arrived | { truckId } | emits |
supplyTruck.loading | { entityId, truckId } | emits |
supplyTruck.docked | { entityId, truckId, offers, seconds } | emits: the HUD shows offers |
supplyTruck.upgraded | { entityId, offer } | emits |
supplyTruck.released | { entityId, truckId } | emits |
supplyTruck.delivered | { entityId, truckId } | emits: the director hands the car back |
supplyTruck.left | { truckId } | emits |
autoRunnerWeapons.grant | { entityId, weapon, amount } | emits |
autoRunnerWeapons.enabled.set | { entityId, enabled } | emits: holds fire while aboard |
health.heal | { entityId, amount } | emits |
mesh.visible.set | { entityId, visible } | emits |
carDrive.nudge | { entityId, dx, dz, dvx, dvz, dheading } | emits: steers the trailer and the car inside |
supplyTruck.dispatch | {} | listens |
supplyTruck.deliver | { entityId } | listens |
supplyTruck.choose | { index } | listens |
keyboard.keydown | { code } | listens |
Needs
- CarDrive moves the tractor, the trailer and the car inside.
- CarCollision gives the sizes, and its ghost tag lets the car pass through the doors.
- MeshPrimitive gives positions.
- HighwayRoad puts the truck in the slow lane and off any bridge.
- AutoRunnerDriver drives the tractor.
- AutoRunnerWeapons is read to pick offers, and takes the refit.
- Health is read for the armour offer, and takes the repair.
- KeyboardInput turns DOM key presses into
keyboard.keydownon the bus, which is how the refit keys arrive.



































