# Forge Asset Library in this game

The models in `public/library/` were picked from Forge's asset library for this game. Each one has a card in
`public/library/manifest.json`: its name, true size in metres, footprint, collision boxes and sockets.
`public/library/assets.lock.json` pins the exact versions (release hashes): do not edit either file.

## Rules
- L1. Every object in the manifest is placed with `lib.place(id, { x, z, yaw, scene })` (or `lib.load(id)`). Never
  draw a crate, barrel, lighthouse, wall, bench... from boxes and cylinders when the manifest has one.
- L2. Models are true metres, origin on the ground, front +Z. Never scale, stretch or squash them. Lay out the scene
  from `asset.size` and `asset.footprint` (a 3 m wall module is 3 m: place modules every 3 m).
- L3. Collision: use `place(...).colliders` (world boxes from the card). Do not invent collision sizes.
- L4. Create it with your renderer, `createLibrary(THREE, { renderer })` (some models use GPU-compressed KTX2 textures), and
  `await lib.preload()` before the game starts; show the game's own loading state meanwhile.
- L5. Reuse: place the same id many times (each `load` is a cheap copy). Mix variants (`-b`, `-c`) for variety.
- L6. Import the kit only from client code that builds the three.js scene. Do not edit `src/lib/library` or `public/library`.
- L7. Anything the manifest does not hold (a tank, a castle, a dragon) is yours to make as before.
- L8. Tall models (`size.h` above 8 m: lighthouses, towers, cranes) stand where they never come between the camera and
  the player (behind the play area, at its edges), or fade while they do. In a top-down or chase view a true-size
  22 m lighthouse beside the path hides the player (Storm Harbour Delivery, 7 Oct 2026).
- L9. Vehicles from the library (cars, race cars, motorbikes, scooters, bicycles, buses) are both street life AND the cars
  people drive. DRIVEN cars (the player's car, rivals, AI racers, chase cars, any car your physics moves) are
  `const rig = lib.vehicle(id, { paint })` after `await lib.preload()`: the same rig as the Garage's `createVehicle`
  (`scene.add(rig.group)`, move and turn `rig.group`, `rig.setSteer(angle)`, `rig.spin(metres travelled)`, `rig.dims` for
  collision boxes, `rig.exhausts` for boost flames, `rig.player = true` on the player's car, `rig.setPaint({ body: '#hex' })`),
  so the Garage ground look (`look.track(rig)`) and your camera take it as is. They are true metres (a race car is 4.6 to
  5.6 m long): never rescale one; tune speeds, camera distance and track width to `rig.dims`. Give every car its own
  paint (an index into the card's six, or a palette colour). PARKED cars and traffic are `place(id, { ..., paint:
  'random' })`; roll their wheels from `lib.parts(object)` when they move. The Garage keeps karts and the vehicle types
  this game's manifest does not hold (taxi, police car, ambulance, fire truck, tractor...).
- L10. Military vehicles (jeeps, Humvees, troop trucks, tanks, helicopters, jets, bombers) carry no national markings:
  give each side its own paint (`paint`) and, if you want, your own flag or number. Animate them ONLY through
  `const p = lib.parts(object)`: `p.drive(metres)` every frame rolls the wheels and moves the tank tracks (their links
  travel round the loop), `p.steerTo(angle)` turns front wheels, `p.turn(rotor, time * 14)` spins rotors (never leave a
  flying helicopter's rotor still; a tail rotor spins about its own shaft), `p.turn(p.turret, yaw)` traverses,
  `p.aim(gun, yaw, pitch)` aims (pitch positive = up; a helicopter chin gun aims down and sideways, the card limits
  clamp it), `p.turn(surface, angle)` moves flaps and rudders on their hinge. Never set `rotation.x/y/z` of these
  parts yourself: their axes differ per model. Hide `p.gear` once an aircraft is airborne. Aircraft are true size (a
  bomber spans 50 m): park them on an airfield edge or fly them above the play area, never between houses.
- L11. Tanks whose card has `damage` are DESTRUCTIBLE: `const d = await lib.damage(tank.object)` once per placed tank, then
  show what happens to it, never a generic flash only: `d.hit(side)` on every hit ('front', 'left', 'right', 'rear',
  'turret', or `{ point }` = where the shell struck; it shows hit marks, dents panels, then knocks them off: throw the
  returned `lost` panel as debris if you like), `d.track('left' | 'right')` when a track is hit (the tank stops until
  repaired), `d.gun()` when the gun is knocked out (it cannot fire), `d.wreck({ turretOff: true })` when it is destroyed
  (burnt wreck, the turret blown off beside it; add fire and smoke), `d.repair()` when it respawns. Keep the turret and gun
  animation through `lib.parts(object)` (L10): the damage pieces follow the turret by themselves.
- L12. Spacecraft (`vehicle.space.*`: fighters, bombers, shuttles, freighters, gunships, escape pods, cruisers, battleships,
  motherships, alien vessels; `vehicle.space.speeder` = hover bikes and hover cars) are true metres like everything else:
  a fighter is 11 to 24 m, a cruiser 180 to 450 m, a battleship about 1 km, a mothership up to 2 km. Never rescale one
  against another: put capital ships far away as backdrops, bosses or carriers, and tune camera distance and speeds.
  Their origin is the centre of the craft (not the ground): `lib.place(id, { x, y, z, yaw, scene })` with the altitude in
  `y`; speeders hover by themselves (origin on the ground). Nose = +Z. Give each faction its own paint (`paint`); there are
  no markings. Animate them ONLY through `const s = lib.parts(object)`: flames, glow or trails go on the EMPTY nodes
  `s.thrusters` (exhaust toward the craft's -Z; scale the flame with the craft) and `s.lifts` (speeders); shots start at
  `s.muzzles`, missiles at `s.hardpoints`, small craft launch from `s.hangars`; `s.turn(turret, yaw)` traverses each of
  `s.turrets`, `s.turn(gun, pitch)` elevates each of `s.guns` (positive = up, card-clamped), `s.turn(ring, time * 0.3)`
  spins `s.rings` and `s.fans`, `s.turn(door, angle)` opens `s.doors` (canopies, ramps, bay doors, hatches, radiators).
  Never set `rotation` of these parts yourself and never draw a spaceship from boxes when the manifest has one.
