{"version":3,"sources":["../src/props.ts","../src/props/tree.ts","../src/core/random.ts","../src/core/palette.ts","../src/props/impostor.ts","../src/props/rock.ts","../src/materials/surface.ts","../src/props/crate.ts","../src/props/carryables.ts","../src/props/workstations.ts","../src/core/types.ts","../src/props/fence.ts","../src/props/lamp.ts","../src/props/grass.ts","../src/props/building.ts","../src/props/stall.ts","../src/materials/shared.ts","../src/props/banner.ts","../src/materials/clothWave.ts","../src/props/fire.ts","../src/props/furniture.ts","../src/props/gatherings.ts","../src/props/bunting.ts","../src/props/fountain.ts","../src/environment/water.ts","../src/materials/waterFlow.ts","../src/props/waterworks.ts","../src/props/statue.ts","../src/props/cart.ts","../src/props/sign.ts","../src/text/textGeometry.ts","../src/text/font.ts","../src/props/aircraft.ts","../src/materials/glass.ts","../src/props/luminous.ts","../src/props/airfield.ts","../src/props/pickups.ts","../src/props/markers.ts","../src/props/hazards.ts","../src/props/destructibles.ts","../src/props/workshop.ts","../src/props/stations.ts","../src/props/vehicles.ts","../src/props/watercraft.ts","../src/props/modern.ts","../src/props/mechanisms.ts","../src/props/climbing.ts","../src/props/electronics.ts","../src/materials/screen.ts","../src/props/terminals.ts","../src/props/fixtures.ts","../src/props/wallArt.ts","../src/materials/picture.ts","../src/props/bathing.ts","../src/props/soft.ts","../src/props/washing.ts","../src/props/vessels.ts","../src/props/pool.ts","../src/props/heat.ts","../src/props/cookware.ts","../src/props/prep.ts","../src/props/sail.ts","../src/props/mooring.ts","../src/props/oars.ts","../src/props/steamPlant.ts","../src/props/smoke.ts","../src/props/gauge.ts","../src/props/hold.ts","../src/props/stabiliser.ts","../src/props/plumbing.ts","../src/props/sound.ts","../src/props/woofer.ts","../src/props/shala.ts","../src/props/bowl.ts","../src/props/beach.ts","../src/props/cricket.ts","../src/props/tropics.ts","../src/props/lagoon.ts","../src/props/beachkit.ts","../src/props/seamark.ts","../src/props/smallCraft.ts","../src/props/gear.ts","../src/props/deckedShip.ts","../src/props/ingredient.ts","../src/props/dresser.ts","../src/props/sink.ts","../src/props/cold.ts","../src/props/plants.ts","../src/props/paper.ts","../src/props/clutter.ts","../src/props/rollingstock.ts","../src/props/platform.ts","../src/props/ammunition.ts","../src/props/boards.ts","../src/props/armour.ts"],"sourcesContent":["// SCENA — props: the prop library\n//\n// A sub-path entry point. `import from 'scena3d'` still gives you everything;\n// this exists so a bundler can see module boundaries, and so an import says\n// what part of the library it depends on.\n//\n// GENERATED from src/index.ts by scripts/entries.mjs — every statement below\n// is the root barrel's own, partitioned by source directory. `npm run\n// entries:check` fails if this file and the barrel disagree.\n\nexport {\n  createTree,\n  treeBiome,\n  TREE_SPECIES,\n  TREE_BIOMES,\n  type TreeOptions,\n  type TreeSpecies,\n  type TreeSeason,\n  type TreeBiome,\n  type TreeBiomeOptions,\n} from './props/tree';\nexport {\n  createImpostor,\n  treeLOD,\n  type ImpostorOptions,\n  type ImpostorProfile,\n  type TreeLODOptions,\n} from './props/impostor';\nexport { createRock, type RockOptions } from './props/rock';\nexport { createCrate, type CrateOptions } from './props/crate';\nexport {\n  createBarrel,\n  createBasket,\n  createSack,\n  createLantern,\n  type CarryableOptions,\n  type LanternOptions,\n} from './props/carryables';\nexport {\n  createChoppingBlock,\n  createOreVein,\n  createCookpot,\n  createSawhorse,\n  type WorkStation,\n  type WorkStationOptions,\n} from './props/workstations';\nexport { createFence, type FenceOptions } from './props/fence';\nexport { createLamp, type LampOptions } from './props/lamp';\nexport { createGrassTuft, createBush, type GrassOptions, type BushOptions } from './props/grass';\nexport {\n  createHouse,\n  createTower,\n  createWell,\n  createRuin,\n  type HouseOptions,\n  type TowerOptions,\n  type WellOptions,\n  type RuinOptions,\n  type WallStyle,\n  type RoofStyle,\n} from './props/building';\nexport { createStall, type StallOptions, type StallGoods } from './props/stall';\nexport {\n  createBanner,\n  type BannerOptions,\n  type BannerStyle,\n  type BannerPattern,\n} from './props/banner';\nexport { createBrazier, createCampfire, type FireOptions } from './props/fire';\nexport {\n  createTable,\n  createSeat,\n  createBed,\n  createShelf,\n  createChest,\n  createCandle,\n  createRug,\n  type TableOptions,\n  type TableStyle,\n  type SeatOptions,\n  type SeatStyle,\n  type BedOptions,\n  type BedSize,\n  type ShelfOptions,\n  type ShelfStock,\n  type ChestOptions,\n  type CandleOptions,\n  type CandleStyle,\n  type RugOptions,\n  type RugShape,\n} from './props/furniture';\nexport {\n  createDiningTable,\n  createPicnicTable,\n  createLongBench,\n  createGameTable,\n  createCampCircle,\n  type GatheringOptions,\n  type DiningTableOptions,\n  type PicnicTableOptions,\n  type LongBenchOptions,\n  type GameTableOptions,\n  type CampCircleOptions,\n  type BoardGame,\n} from './props/gatherings';\nexport { createBunting, type BuntingOptions } from './props/bunting';\nexport { createFountain, type FountainOptions } from './props/fountain';\nexport {\n  createCart,\n  type CartOptions,\n  type CartStyle,\n  type CartCargo,\n} from './props/cart';\nexport {\n  createStatue,\n  type StatueOptions,\n  type StatueFigure,\n  type StatueMaterial,\n} from './props/statue';\nexport {\n  createSign,\n  type SignOptions,\n  type SignKind,\n  type Direction,\n} from './props/sign';\nexport {\n  createPlane,\n  createHelicopter,\n  createFighterJet,\n  type AircraftProp,\n  type AircraftInput,\n  type PlaneOptions,\n  type HelicopterProp,\n  type HelicopterInput,\n  type HelicopterOptions,\n  type FighterProp,\n  type FighterInput,\n  type FighterOptions,\n} from './props/aircraft';\nexport {\n  createRunway,\n  createWindsock,\n  createHangar,\n  createHelipad,\n  type Runway,\n  type RunwayOptions,\n  type Windsock,\n  type WindsockOptions,\n  type HangarOptions,\n  type HelipadOptions,\n} from './props/airfield';\nexport {\n  createStreetLight,\n  createLanternLight,\n  createNeonSign,\n  createStringLights,\n  createRevolvingBeacon,\n  createPhotocell,\n  type Luminous,\n  type LuminousClaim,\n  type StreetLightOptions,\n  type LanternLightOptions,\n  type NeonSign,\n  type NeonSignOptions,\n  type StringLightsOptions,\n  type RevolvingBeaconOptions,\n  type Photocell,\n  type PhotocellOptions,\n} from './props/luminous';\nexport {\n  createPickup,\n  createPickupField,\n  type Pickup,\n  type PickupKind,\n  type PickupState,\n  type PickupOptions,\n  type PickupField,\n  type PickupFieldOptions,\n  type FieldTrigger,\n} from './props/pickups';\nexport {\n  createCheckpoint,\n  createZone,\n  createBeacon,\n  createFinishGate,\n  type Checkpoint,\n  type CheckpointState,\n  type CheckpointOptions,\n  type Zone,\n  type ZoneOptions,\n  type Beacon,\n  type BeaconOptions,\n  type FinishGate,\n  type FinishGateOptions,\n} from './props/markers';\nexport {\n  createPlatform,\n  createCrumblingPlatform,\n  createBouncePad,\n  createPendulum,\n  createSpikeTrap,\n  createConveyor,\n  createPressurePlate,\n  type MovingPlatform,\n  type PlatformOptions,\n  type PlatformMotion,\n  type CrumblingPlatform,\n  type CrumbleOptions,\n  type CrumbleState,\n  type BouncePad,\n  type BouncePadOptions,\n  type Pendulum,\n  type PendulumOptions,\n  type SpikeTrap,\n  type SpikeTrapOptions,\n  type Conveyor,\n  type ConveyorOptions,\n  type PressurePlate,\n  type PressurePlateOptions,\n} from './props/hazards';\nexport {\n  createBreakable,\n  createTargetDummy,\n  createScoreboard,\n  createStumps,\n  type Breakable,\n  type BreakableKind,\n  type BreakableState,\n  type BreakableOptions,\n  type TargetDummy,\n  type TargetDummyOptions,\n  type Scoreboard,\n  type ScoreboardOptions,\n  type Stumps,\n  type StumpsOptions,\n} from './props/destructibles';\nexport {\n  createForge,\n  createOven,\n  createLoom,\n  createCounter,\n  type WorkshopOptions,\n} from './props/workshop';\nexport {\n  createTreadmill,\n  createGuitar,\n  createToilet,\n  createSink,\n  createBathtub,\n  type TreadmillOptions,\n  type TreadmillProp,\n  type GuitarOptions,\n  type BathroomOptions,\n} from './props/stations';\nexport {\n  createCar,\n  createBike,\n  createTractor,\n  createTruck,\n  type VehicleOptions,\n  type VehicleInput,\n  type VehicleProp,\n} from './props/vehicles';\nexport {\n  createBoat,\n  createShip,\n  type CraftOptions,\n  type CraftInput,\n  type CraftProp,\n} from './props/watercraft';\nexport {\n  createRailing,\n  createModernWindow,\n  createGate,\n  createCladding,\n  createPergola,\n  createPlanter,\n  type RailingOptions,\n  type RailingStyle,\n  type ModernWindowOptions,\n  type ModernWindowStyle,\n  type ModernWindowProp,\n  type GateOptions,\n  type GateStyle,\n  type GateProp,\n  type CladdingOptions,\n  type CladdingStyle,\n  type PergolaOptions,\n  type PlanterOptions,\n} from './props/modern';\nexport {\n  createDoor,\n  createDrawer,\n  createLever,\n  createValve,\n  createHatch,\n  createPortcullis,\n  type Manipulable,\n  type MechanismOptions,\n  type DoorOptions,\n  type DrawerOptions,\n  type LeverOptions,\n  type ValveOptions,\n  type HatchOptions,\n  type PortcullisOptions,\n} from './props/mechanisms';\nexport {\n  createLadder,\n  createSaddle,\n  createBridle,\n  type Ladder,\n  type LadderOptions,\n  type LadderStyle,\n  type TackOptions,\n  type TackStyle,\n} from './props/climbing';\nexport {\n  createMonitor,\n  createTelevision,\n  createLaptop,\n  createSmartDisplay,\n  createTablet,\n  createPhone,\n  createSmartwatch,\n  createScreenLight,\n  type ScreenProp,\n  type ScreenPropOptions,\n  type ScreenCarryable,\n  type TelevisionOptions,\n  type LaptopOptions,\n  type ScreenLight,\n  type ScreenLightOptions,\n} from './props/electronics';\nexport {\n  createTerminal,\n  type Terminal,\n  type TerminalOptions,\n  type TerminalStyle,\n} from './props/terminals';\nexport {\n  createFixture,\n  createDeskSet,\n  type Fixture,\n  type FixtureOptions,\n  type FixtureStyle,\n  type DeskSet,\n} from './props/fixtures';\nexport {\n  createPainting,\n  createFramedPhoto,\n  createMirror,\n  createWallClock,\n  createTapestry,\n  type WallArt,\n  type FrameStyle,\n  type PaintingOptions,\n  type FramedPhotoOptions,\n  type MirrorOptions,\n  type WallClock,\n  type WallClockOptions,\n  type TapestryOptions,\n} from './props/wallArt';\nexport {\n  createShower,\n  createTub,\n  createJacuzzi,\n  type Shower,\n  type ShowerOptions,\n  type ShowerStyle,\n  type ShowerState,\n  type Tub,\n  type TubOptions,\n  type TubStyle,\n  type Jacuzzi,\n  type JacuzziOptions,\n} from './props/bathing';\nexport {\n  createPool,\n  type Pool,\n  type PoolOptions,\n  type PoolStyle,\n  type PoolLadder,\n} from './props/pool';\nexport {\n  createHeatSource,\n  createHearth,\n  createRange,\n  createHob,\n  type HeatSource,\n  type HeatOptions,\n  type HeatEra,\n  type HeatState,\n  type HeatZone,\n  type HeatControl,\n  type HeatField,\n} from './props/heat';\nexport {\n  createCookware,\n  COOKWARE_KINDS,\n  type Cookware,\n  type CookwareOptions,\n  type CookwareKind,\n  type CookState,\n} from './props/cookware';\nexport {\n  createPrepStation,\n  PREP_KINDS,\n  type PrepStation,\n  type PrepOptions,\n  type PrepKind,\n} from './props/prep';\nexport {\n  createSailRig,\n  RIG_KINDS,\n  noGoDegrees,\n  type SailRig,\n  type SailOptions,\n  type RigKind,\n  type WindSource,\n} from './props/sail';\nexport {\n  createBerth,\n  moor,\n  createGangway,\n  BERTH_ERAS,\n  type Berth,\n  type BerthEra,\n  type BerthOptions,\n  type Bollard,\n  type Mooring,\n  type MooringLine,\n  type MooringOptions,\n  type Moorable,\n  type Gangway,\n  type GangwayOptions,\n  type Carrier,\n} from './props/mooring';\nexport {\n  createOarBank,\n  oarGripAt,\n  OAR_KINDS,\n  OAR_GRIP,\n  type OarBank,\n  type OarBankOptions,\n  type OarKind,\n  type Oar,\n} from './props/oars';\nexport {\n  createSteamPlant,\n  pressureFor,\n  tempFor,\n  expansionRatio,\n  steamPerWork,\n  firesVisibleFrom,\n  STEAM_KINDS,\n  type SteamPlant,\n  type SteamPlantOptions,\n  type SteamKind,\n  type SteamState,\n  type SteamControl,\n} from './props/steamPlant';\nexport {\n  createHold,\n  freeSurfaceCost,\n  holdPoint,\n  HOLD_KINDS,\n  type Hold,\n  type HoldOptions,\n  type HoldKind,\n  type Compartment,\n  type Loading,\n  type TrimState,\n} from './props/hold';\nexport {\n  createStabilisers,\n  dampingAt,\n  STABILISER_KINDS,\n  type Stabilisers,\n  type StabiliserOptions,\n  type StabiliserKind,\n} from './props/stabiliser';\nexport {\n  createPlumbing,\n  headPressure,\n  orificeFlow,\n  mixedAt,\n  mixFor,\n  SUPPLY_KINDS,\n  SCALD,\n  type Plumbing,\n  type PlumbingOptions,\n  type SupplyKind,\n  type SupplyState,\n  type OutletKind,\n  type OutletOptions,\n  type Draw,\n} from './props/plumbing';\nexport {\n  createPA,\n  spreadingLoss,\n  barrierLoss,\n  exposureLimit,\n  earshot,\n  loudnessState,\n  sumDecibels,\n  AIR_ABSORPTION,\n  A_WEIGHTING,\n  BAND_HZ,\n  BARRIER_CAP,\n  SPEED_OF_SOUND,\n  QUIET,\n  SHOUTING,\n  HARMFUL,\n  SHOUT_AT_1M,\n  type PublicAddress,\n  type PAOptions,\n  type PAEra,\n  type Band,\n  type BandLevels,\n  type LoudnessState,\n  type EchoState,\n  type EchoReading,\n  type SoundField,\n  type SoundArrival,\n  type SourceSpec,\n  type BarrierSpec,\n} from './props/sound';\nexport {\n  createWoofer,\n  createDanceTiles,\n  bedPulse,\n  RADIO_STATIONS,\n  type Woofer,\n  type WooferOptions,\n  type WooferState,\n  type RadioStation,\n  type RadioMedia,\n  type AudioPulse,\n  type DanceTiles,\n  type DanceTilesOptions,\n} from './props/woofer';\nexport {\n  createShala,\n  SHALA_ERAS,\n  type Shala,\n  type ShalaEra,\n  type ShalaOptions,\n  type MatSpot,\n} from './props/shala';\nexport {\n  createSingingBowl,\n  type SingingBowl,\n  type SingingBowlOptions,\n  type BreathPulse,\n} from './props/bowl';\nexport { createBeach, type Beach, type BeachOptions } from './props/beach';\nexport {\n  createCricketGround,\n  createBat,\n  createCricketBall,\n  PITCH_LENGTH,\n  PITCH_WIDTH,\n  STUMP_HEIGHT,\n  STUMP_SPREAD,\n  CREASE_FRONT,\n  type CricketGround,\n  type CricketGroundOptions,\n  type CricketBallProp,\n  type BatOptions,\n} from './props/cricket';\nexport {\n  createPalm,\n  createBananaTree,\n  type TropicalTree,\n  type PalmOptions,\n  type BananaOptions,\n} from './props/tropics';\nexport { createLagoon, type Lagoon, type LagoonOptions } from './props/lagoon';\nexport {\n  createLifeguardTower,\n  createBeachUmbrella,\n  createLounger,\n  MIAMI_COLORS,\n  type BeachProp,\n  type LifeguardTowerOptions,\n  type BeachUmbrellaOptions,\n  type LoungerOptions,\n  type LoungerRecline,\n} from './props/beachkit';\nexport {\n  createSeamark,\n  geographicRange,\n  luminousRange,\n  MARK_KINDS,\n  SECTOR_TRANSMISSION,\n  NM,\n  type Seamark,\n  type SeamarkOptions,\n  type MarkKind,\n  type SightState,\n  type Sighting,\n  type Sector,\n} from './props/seamark';\nexport {\n  createSmallCraft,\n  livesIn,\n  isBreaking,\n  CRAFT_FITS,\n  type SmallCraft,\n  type SmallCraftOptions,\n  type CraftFit,\n  type CraftState,\n  type Hand,\n} from './props/smallCraft';\nexport {\n  createGear,\n  listFor,\n  GEAR_KINDS,\n  type Gear,\n  type GearOptions,\n  type GearKind,\n  type GearState,\n} from './props/gear';\nexport {\n  createPressureGauge,\n  type PressureGauge,\n  type PressureGaugeOptions,\n} from './props/gauge';\nexport {\n  createDeckedShip,\n  SHIP_ERAS,\n  type DeckedShip,\n  type DeckedShipOptions,\n  type ShipEra,\n  type ShipInput,\n  type DeckField,\n  type DeckLevel,\n  type Companionway,\n} from './props/deckedShip';\nexport {\n  createSmoke,\n  createExtractor,\n  createSmokeLayer,\n  SMOKE_STYLES,\n  EXTRACTOR_ERAS,\n  type SmokeSource,\n  type SmokeOptions,\n  type SmokeStyle,\n  type SmokeField,\n  type Extractor,\n  type ExtractorOptions,\n  type ExtractorEra,\n  type ExtractorFan,\n  type SmokeLayer,\n  type SmokeLayerOptions,\n} from './props/smoke';\nexport {\n  createIngredient,\n  keepsFor,\n  INGREDIENT_KINDS,\n  type Ingredient,\n  type IngredientOptions,\n  type IngredientKind,\n  type IngredientForm,\n  type IngredientState,\n} from './props/ingredient';\nexport {\n  createDresser,\n  stock,\n  createUtensil,\n  createCrockery,\n  createKitchenware,\n  DRESSER_KINDS,\n  UTENSIL_STYLES,\n  type Storage,\n  type StorageSpace,\n  type SpaceKind,\n  /** The prop a dresser returns. Named `Storage` because that is what it is. */\n  type DresserKind,\n  type DresserOptions,\n  type DresserDoor,\n  type StockOptions,\n  type UtensilStyle,\n  type UtensilOptions,\n  type CrockeryOptions,\n  type KitchenwareOptions,\n} from './props/dresser';\nexport {\n  createWashUp,\n  createTrough,\n  createKitchenSink,\n  createDishwasher,\n  SINK_ERAS,\n  type WashUp,\n  type SinkOptions,\n  type SinkEra,\n  type SinkDoor,\n  type WashQueue,\n} from './props/sink';\nexport {\n  createColdStore,\n  createLarder,\n  createIcebox,\n  createFridge,\n  spoilRate,\n  COLD_ERAS,\n  type ColdStore,\n  type ColdOptions,\n  type ColdEra,\n  type ColdState,\n  type ColdDoor,\n  type ChillField,\n} from './props/cold';\nexport {\n  createBasin,\n  createTap,\n  createEwer,\n  BASIN_ERAS,\n  type Basin,\n  type BasinOptions,\n  type BasinEra,\n  type Tap,\n  type TapOptions,\n  type TapStyle,\n  type EwerOptions,\n} from './props/washing';\nexport {\n  createStream,\n  createSpray,\n  createFill,\n  createSteam,\n  type Stream,\n  type StreamOptions,\n  type Spray,\n  type SprayOptions,\n  type Fill,\n  type FillOptions,\n  type Steam,\n  type SteamOptions,\n} from './props/waterworks';\nexport {\n  createPlant,\n  createHangingPlant,\n  createWindowBox,\n  PLANT_SPECIES,\n  type Plant,\n  type PlantOptions,\n  type PlantSpecies,\n  type HangingPlantOptions,\n  type WindowBoxOptions,\n} from './props/plants';\nexport {\n  createCurtains,\n  createCushion,\n  createThrow,\n  type Curtains,\n  type CurtainsOptions,\n  type CurtainStyle,\n  type CushionOptions,\n  type ThrowOptions,\n} from './props/soft';\nexport {\n  createPoster,\n  createPinboard,\n  createWhiteboard,\n  createStickyNotes,\n  type PosterOptions,\n  type PinboardOptions,\n  type WhiteboardOptions,\n  type StickyNotesOptions,\n} from './props/paper';\nexport {\n  createVessel,\n  VESSEL_STYLES,\n  type Vessel,\n  type VesselOptions,\n  type VesselStyle,\n} from './props/vessels';\nexport {\n  createBooks,\n  createPapers,\n  createFolded,\n  createTrinket,\n  createFruitBowl,\n  createClutter,\n  CLUTTER_THEMES,\n  type BooksOptions,\n  type BookStyle,\n  type PapersOptions,\n  type FoldedOptions,\n  type TrinketOptions,\n  type FruitBowlOptions,\n  type ClutterOptions,\n  type ClutterKitOptions,\n  type ClutterTheme,\n} from './props/clutter';\nexport {\n  createLocomotive,\n  createCarriage,\n  createWagon,\n  createConsist,\n  type RollingStock,\n  type RollingStockOptions,\n  type WagonOptions,\n  type Consist,\n  type ConsistOptions,\n} from './props/rollingstock';\nexport {\n  createStationPlatform,\n  type StationPlatform,\n  type StationPlatformOptions,\n} from './props/platform';\nexport {\n  AMMO,\n  AMMO_KINDS,\n  ballisticsOf,\n  chargeVelocity,\n  createAmmoDump,\n  createBandolier,\n  createCharge,\n  createLoader,\n  createPowderKeg,\n  type AmmoDump,\n  type BandolierOptions,\n  type ChargeOptions,\n  type DumpOptions,\n  type KegOptions,\n  type LoaderOptions,\n  type LoaderStyle,\n  createAmmoBox,\n  createBelt,\n  createCasing,\n  createMagazine,\n  createQuiver,\n  createRack,\n  createReady,\n  createRound,\n  describeAmmo,\n  roundTriangles,\n  type AmmoBoxOptions,\n  type AmmoKind,\n  type AmmoSpec,\n  type Ballistics,\n  type BeltOptions,\n  type CaseKind,\n  type CasingOptions,\n  type ContainerOptions,\n  type Countable,\n  type HeadKind,\n  type RackOptions,\n  type Round,\n  type RoundOptions,\n} from './props/ammunition';\nexport {\n  createBoard,\n  boardStrength,\n  stackStrength,\n  TIMBERS,\n  TIMBER_NAMES,\n  type BoardOptions,\n  type BoardShape,\n  type BoardStack,\n  type BoardState,\n  type BoardStrength,\n  type Timber,\n  type TimberSpec,\n} from './props/boards';\nexport {\n  ALLOYS,\n  ALLOY_NAMES,\n  TABOR,\n  createArmour,\n  mailStrength,\n  plateStrength,\n  type Alloy,\n  type AlloySpec,\n  type ArmourOptions,\n  type ArmourProp,\n  type MailShape,\n  type MailStrength,\n  type PlateShape,\n  type PlateStrength,\n} from './props/armour';\n","import {\n  BoxGeometry,\n  Color,\n  ConeGeometry,\n  CylinderGeometry,\n  Group,\n  IcosahedronGeometry,\n  Mesh,\n  MeshStandardMaterial,\n} from 'three';\nimport { Rng } from '../core/random';\nimport { DEFAULT_PALETTE, type Palette } from '../core/palette';\nimport type { WindField } from '../environment/wind';\nimport type { Prop } from '../core/types';\n\nexport type TreeSpecies =\n  | 'pine'\n  | 'oak'\n  | 'cypress'\n  | 'birch'\n  | 'cedar'\n  | 'maple'\n  | 'sakura'\n  | 'palm'\n  | 'willow'\n  | 'sequoia'\n  | 'banyan'\n  | 'baobab'\n  | 'acacia';\n\n/** The season a tree wears. Currently shapes `sakura` (bloom / green / warm / bare). */\nexport type TreeSeason = 'spring' | 'summer' | 'autumn' | 'winter';\n\n/** Every species `createTree` can build. */\nexport const TREE_SPECIES: readonly TreeSpecies[] = [\n  'pine',\n  'oak',\n  'cypress',\n  'birch',\n  'cedar',\n  'maple',\n  'sakura',\n  'palm',\n  'willow',\n  'sequoia',\n  'banyan',\n  'baobab',\n  'acacia',\n];\n\nexport interface TreeOptions {\n  seed?: number;\n  /** Overall height in world units. Default is species-specific. */\n  height?: number;\n  /** Which species. Default: a seeded pick of pine or oak (new species are opt-in). */\n  species?: TreeSpecies;\n  /** @deprecated Use `species`. Kept as an alias so old calls keep working. */\n  style?: TreeSpecies;\n  /** Season — currently drives `sakura` (blossom in spring, green in summer, warm in autumn, bare in winter). */\n  season?: TreeSeason;\n  /** A WindField to sway the canopy in (the trunk stays planted). */\n  wind?: WindField;\n  palette?: Palette;\n}\n\n// --- shared helpers -----------------------------------------------------\n\nfunction mat(color: number): MeshStandardMaterial {\n  return new MeshStandardMaterial({ color, flatShading: true });\n}\n\n/** Blend a base colour toward another — species tints that still theme with the palette. */\nfunction tint(base: number, toward: number, t: number): number {\n  return new Color(base).lerp(new Color(toward), t).getHex();\n}\n\n// --- silhouette builders (shared by the recipes) ------------------------\n\n/** A gently curving trunk from stacked segments — the lean of a palm. Returns the crown position. */\nfunction curvedTrunk(\n  group: Group,\n  material: MeshStandardMaterial,\n  height: number,\n  baseR: number,\n  topR: number,\n  curve: number\n): { x: number; y: number } {\n  const segs = 7;\n  const segH = height / segs;\n  let cx = 0;\n  for (let i = 0; i < segs; i++) {\n    const f = i / segs;\n    const r0 = baseR + (topR - baseR) * f;\n    const r1 = baseR + (topR - baseR) * ((i + 1) / segs);\n    cx = curve * f * f; // accelerating lean\n    const seg = new Mesh(new CylinderGeometry(r1, r0, segH * 1.04, 6), material);\n    seg.position.set(cx, segH * (i + 0.5), 0);\n    seg.rotation.z = -curve * 0.12;\n    group.add(seg);\n  }\n  return { x: curve, y: height };\n}\n\n/** A crown of long, drooping, radial fronds — a palm top. */\nfunction frondCrown(\n  group: Group,\n  material: MeshStandardMaterial,\n  rng: Rng,\n  cx: number,\n  cy: number,\n  count: number,\n  length: number,\n  droopDeg: number\n): void {\n  const droop = (droopDeg * Math.PI) / 180;\n  for (let i = 0; i < count; i++) {\n    const a = (i / count) * Math.PI * 2 + rng.range(-0.12, 0.12);\n    const frond = new Group();\n    const w = length * 0.13;\n    const blade = new Mesh(new ConeGeometry(w, length, 4), material); // tapered blade\n    blade.rotation.z = -Math.PI / 2; // point along +x\n    blade.position.x = length * 0.5;\n    blade.scale.z = 0.28; // flatten into a frond\n    frond.add(blade);\n    frond.position.set(cx, cy, 0);\n    frond.rotation.y = a;\n    frond.rotation.z = -(droop + rng.range(-0.14, 0.14)); // droop down\n    group.add(frond);\n  }\n}\n\n/** Long strands hanging and swaying from the canopy hem — a willow's veil. */\nfunction droopStrands(\n  group: Group,\n  material: MeshStandardMaterial,\n  rng: Rng,\n  cy: number,\n  radius: number,\n  count: number,\n  minLen: number,\n  maxLen: number\n): void {\n  for (let i = 0; i < count; i++) {\n    const a = (i / count) * Math.PI * 2 + rng.range(-0.12, 0.12);\n    const rr = radius * rng.range(0.78, 1.02); // hang from the outer hem\n    const len = Math.min(rng.range(minLen, maxLen), cy - 0.4); // never punch through the ground\n    if (len <= 0.3) continue;\n    // A leafy strip, wide enough to read as a veil from any angle.\n    const strand = new Mesh(new BoxGeometry(0.12, len, 0.12), material);\n    strand.position.set(Math.cos(a) * rr, cy - len / 2, Math.sin(a) * rr);\n    strand.rotation.y = -a;\n    strand.rotation.z = rng.range(-0.08, 0.08);\n    group.add(strand);\n  }\n}\n\n/** A few splayed structural branches — visible on a bare sakura. */\nfunction branches(group: Group, material: MeshStandardMaterial, rng: Rng, trunkTop: number, count: number, len: number): void {\n  for (let i = 0; i < count; i++) {\n    const a = (i / count) * Math.PI * 2 + rng.range(-0.25, 0.25);\n    const br = new Mesh(new CylinderGeometry(0.025, 0.055, len, 5), material);\n    br.position.set(Math.cos(a) * len * 0.28, trunkTop + len * 0.34, Math.sin(a) * len * 0.28);\n    br.rotation.set(-Math.sin(a) * 0.7, 0, Math.cos(a) * 0.7);\n    group.add(br);\n  }\n}\n\n/** A massive trunk that flares into buttress roots at the base — a sequoia. */\nfunction buttressTrunk(group: Group, material: MeshStandardMaterial, rng: Rng, height: number, baseR: number, topR: number): void {\n  const trunk = new Mesh(new CylinderGeometry(topR, baseR, height, 9), material);\n  trunk.position.y = height / 2;\n  group.add(trunk);\n  const flares = 6;\n  for (let i = 0; i < flares; i++) {\n    const a = (i / flares) * Math.PI * 2;\n    const wedge = new Mesh(new ConeGeometry(baseR * 0.5, height * 0.16, 4), material);\n    wedge.position.set(Math.cos(a) * baseR * 0.65, height * 0.05, Math.sin(a) * baseR * 0.65);\n    wedge.rotation.set(-Math.sin(a) * 0.35, 0, Math.cos(a) * 0.35);\n    wedge.scale.z = 0.5;\n    group.add(wedge);\n  }\n}\n\n/** A fat, bulging bottle trunk tapering to a narrow top — a baobab. Returns the crown height. */\nfunction bottleTrunk(group: Group, material: MeshStandardMaterial, rng: Rng, height: number, baseR: number): number {\n  const trunkH = height * 0.68;\n  // Two stacked cylinders: a fat barrel, then a quick taper — the bottle bulge.\n  const belly = new Mesh(new CylinderGeometry(baseR * 0.62, baseR, trunkH * 0.66, 8), material);\n  belly.position.y = trunkH * 0.33;\n  group.add(belly);\n  const neck = new Mesh(new CylinderGeometry(baseR * 0.28, baseR * 0.62, trunkH * 0.34, 8), material);\n  neck.position.y = trunkH * 0.66 + trunkH * 0.17;\n  group.add(neck);\n  // A few stubby top branches.\n  const arms = rng.int(3, 5);\n  for (let i = 0; i < arms; i++) {\n    const a = (i / arms) * Math.PI * 2 + rng.range(-0.2, 0.2);\n    const arm = new Mesh(new CylinderGeometry(0.05, 0.11, height * 0.22, 5), material);\n    arm.position.set(Math.cos(a) * baseR * 0.3, trunkH + height * 0.06, Math.sin(a) * baseR * 0.3);\n    arm.rotation.set(-Math.sin(a) * 0.9, 0, Math.cos(a) * 0.9);\n    group.add(arm);\n  }\n  return trunkH + height * 0.12;\n}\n\n/** Aerial prop-roots dropping from the crown to the ground — a banyan. */\nfunction aerialRoots(group: Group, material: MeshStandardMaterial, rng: Rng, cy: number, radius: number, count: number): void {\n  for (let i = 0; i < count; i++) {\n    const a = (i / count) * Math.PI * 2 + rng.range(-0.2, 0.2);\n    const rr = radius * rng.range(0.45, 1.0);\n    const h = cy - 0.02;\n    const root = new Mesh(new CylinderGeometry(rng.range(0.04, 0.08), rng.range(0.07, 0.13), h, 5), material);\n    root.position.set(Math.cos(a) * rr, h / 2, Math.sin(a) * rr);\n    root.rotation.z = rng.range(-0.06, 0.06);\n    root.rotation.x = rng.range(-0.06, 0.06);\n    group.add(root);\n  }\n}\n\n/**\n * A species recipe: the height band, its wind response (how stiffly it sways),\n * its steering footprint, and how to build it. `build` returns the single\n * foliage material — the one the wind binds, leaving the trunk planted.\n */\ninterface Recipe {\n  heightRange: [number, number];\n  /** Wind stiffness exponent (higher = stiffer base). */\n  stiffness: number;\n  /** Fraction of height below which nothing sways (keeps the trunk still). */\n  anchorFrac: number;\n  /** Steering footprint radius (the GAMA handshake) — a number, or scaled from height for giants. */\n  obstacleRadius: number | ((height: number) => number);\n  build(group: Group, rng: Rng, palette: Palette, height: number, season?: TreeSeason): MeshStandardMaterial;\n}\n\n// --- species recipes ----------------------------------------------------\n\nconst SPECIES: Record<TreeSpecies, Recipe> = {\n  // Stacked cones — the classic conifer. (Verbatim from the original, so every\n  // seeded forest built before the species system renders identically.)\n  pine: {\n    heightRange: [3.2, 5.2],\n    stiffness: 2.4,\n    anchorFrac: 0.22,\n    obstacleRadius: 0.5,\n    build(group, rng, palette, height) {\n      const trunkMaterial = mat(palette.trunk);\n      const foliageMaterial = mat(rng.pick(palette.foliage));\n      const trunkHeight = height * 0.25;\n      const trunk = new Mesh(new CylinderGeometry(0.09, 0.14, trunkHeight, 6), trunkMaterial);\n      trunk.position.y = trunkHeight / 2;\n      group.add(trunk);\n\n      const tiers = rng.int(3, 4);\n      let y = trunkHeight;\n      let radius = height * rng.range(0.24, 0.3);\n      const tierHeight = (height - trunkHeight) / tiers + 0.15;\n      for (let i = 0; i < tiers; i++) {\n        const cone = new Mesh(new ConeGeometry(radius, tierHeight * 1.35, 7), foliageMaterial);\n        cone.position.y = y + tierHeight * 0.55;\n        cone.rotation.y = rng.range(0, Math.PI);\n        group.add(cone);\n        y += tierHeight * 0.8;\n        radius *= 0.72;\n      }\n      return foliageMaterial;\n    },\n  },\n\n  // Foliage blobs on a forked trunk. (Verbatim from the original.)\n  oak: {\n    heightRange: [3.2, 5.2],\n    stiffness: 2.4,\n    anchorFrac: 0.22,\n    obstacleRadius: 0.6,\n    build(group, rng, palette, height) {\n      const trunkMaterial = mat(palette.trunk);\n      const foliageMaterial = mat(rng.pick(palette.foliage));\n      const trunkHeight = height * 0.45;\n      const trunk = new Mesh(new CylinderGeometry(0.12, 0.2, trunkHeight, 6), trunkMaterial);\n      trunk.position.y = trunkHeight / 2;\n      trunk.rotation.z = rng.range(-0.08, 0.08);\n      group.add(trunk);\n\n      const blobs = rng.int(2, 4);\n      for (let i = 0; i < blobs; i++) {\n        const radius = height * rng.range(0.18, 0.28);\n        const blob = new Mesh(new IcosahedronGeometry(radius, 0), foliageMaterial);\n        blob.position.set(\n          rng.jitter(0, height * 0.16),\n          trunkHeight + radius * rng.range(0.5, 0.9) + i * radius * 0.35,\n          rng.jitter(0, height * 0.16)\n        );\n        blob.rotation.set(rng.range(0, Math.PI), rng.range(0, Math.PI), 0);\n        group.add(blob);\n      }\n      return foliageMaterial;\n    },\n  },\n\n  // Tall, narrow flame — a lumpy column of deep-green foliage tapering to a\n  // point. Barely moves in the wind; perfect for avenues and cemeteries.\n  cypress: {\n    heightRange: [6, 10],\n    stiffness: 3.4,\n    anchorFrac: 0.32,\n    obstacleRadius: 0.35,\n    build(group, rng, palette, height) {\n      const trunkMaterial = mat(palette.trunk);\n      const foliageMaterial = mat(tint(rng.pick(palette.foliage), 0x123a24, 0.5)); // deep green\n      const trunkH = height * 0.14;\n      const trunk = new Mesh(new CylinderGeometry(0.07, 0.11, trunkH, 6), trunkMaterial);\n      trunk.position.y = trunkH / 2;\n      group.add(trunk);\n\n      const maxR = height * 0.075; // narrow flame\n      const crownBase = trunkH * 0.6;\n      const crownH = height - crownBase;\n      const tiers = Math.max(7, Math.round(crownH / (maxR * 1.4)));\n      const step = crownH / tiers;\n      for (let i = 0; i < tiers; i++) {\n        const f = i / (tiers - 1);\n        // Rounded low, tapering steadily to a slim top.\n        const r = Math.max(0.05, maxR * (0.55 + 0.7 * Math.pow(1 - f, 0.8)) * (0.6 + 0.4 * Math.sin(f * Math.PI)));\n        const blob = new Mesh(new IcosahedronGeometry(r, 0), foliageMaterial);\n        blob.position.set(rng.jitter(0, maxR * 0.12), crownBase + i * step + step * 0.5, rng.jitter(0, maxR * 0.12));\n        blob.scale.y = 1.5; // stretch into a smooth column\n        blob.rotation.set(rng.range(0, Math.PI), rng.range(0, Math.PI), rng.range(0, Math.PI));\n        group.add(blob);\n      }\n      // A pointed cap to finish the flame.\n      const cap = new Mesh(new ConeGeometry(maxR * 0.7, crownH * 0.22, 6), foliageMaterial);\n      cap.position.y = crownBase + crownH + crownH * 0.02;\n      group.add(cap);\n      return foliageMaterial;\n    },\n  },\n\n  // Slender, high-canopied, pale cream bark with dark bands and a loose, light\n  // yellow-green crown.\n  birch: {\n    heightRange: [4, 7],\n    stiffness: 1.5,\n    anchorFrac: 0.45,\n    obstacleRadius: 0.32,\n    build(group, rng, palette, height) {\n      const barkMaterial = mat(0xe6e2d6); // birch cream\n      const bandMaterial = mat(0x4a453e);\n      const foliageMaterial = mat(tint(rng.pick(palette.foliage), 0xd2e69a, 0.4)); // light yellow-green\n      const trunkH = height * 0.72;\n      const trunk = new Mesh(new CylinderGeometry(0.05, 0.08, trunkH, 6), barkMaterial);\n      trunk.position.y = trunkH / 2;\n      trunk.rotation.z = rng.range(-0.04, 0.04);\n      group.add(trunk);\n\n      // Characteristic dark bark bands on the lower trunk.\n      const bands = rng.int(2, 4);\n      for (let i = 0; i < bands; i++) {\n        const band = new Mesh(new CylinderGeometry(0.076, 0.076, 0.05, 6), bandMaterial);\n        band.position.y = rng.range(trunkH * 0.15, trunkH * 0.8);\n        group.add(band);\n      }\n\n      // Sparse, loose crown up high.\n      const crownBase = trunkH * 0.85;\n      const blobs = rng.int(3, 5);\n      for (let i = 0; i < blobs; i++) {\n        const r = height * rng.range(0.12, 0.19);\n        const blob = new Mesh(new IcosahedronGeometry(r, 0), foliageMaterial);\n        blob.position.set(\n          rng.jitter(0, height * 0.14),\n          crownBase + rng.range(0, height * 0.22),\n          rng.jitter(0, height * 0.14)\n        );\n        blob.rotation.set(rng.range(0, Math.PI), rng.range(0, Math.PI), 0);\n        group.add(blob);\n      }\n      return foliageMaterial;\n    },\n  },\n\n  // Broad, flat horizontal tiers on a stout trunk — a spreading cedar.\n  cedar: {\n    heightRange: [4, 6],\n    stiffness: 2.8,\n    anchorFrac: 0.3,\n    obstacleRadius: 0.75,\n    build(group, rng, palette, height) {\n      const trunkMaterial = mat(palette.trunk);\n      const foliageMaterial = mat(tint(rng.pick(palette.foliage), 0x3a6b58, 0.45)); // blue-green\n      const trunkH = height * 0.32;\n      const trunk = new Mesh(new CylinderGeometry(0.13, 0.22, trunkH, 6), trunkMaterial);\n      trunk.position.y = trunkH / 2;\n      group.add(trunk);\n\n      const tiers = rng.int(3, 4);\n      const crownBase = trunkH * 0.8;\n      const crownH = height - crownBase;\n      const maxR = height * rng.range(0.4, 0.5); // broad\n      for (let i = 0; i < tiers; i++) {\n        const f = tiers > 1 ? i / (tiers - 1) : 0;\n        const r = maxR * (1 - f * 0.45);\n        const plate = new Mesh(new IcosahedronGeometry(r, 0), foliageMaterial);\n        plate.position.set(rng.jitter(0, maxR * 0.1), crownBase + f * crownH * 0.9, rng.jitter(0, maxR * 0.1));\n        plate.scale.y = 0.3; // flatten into a horizontal plate\n        plate.rotation.y = rng.range(0, Math.PI);\n        group.add(plate);\n      }\n      return foliageMaterial;\n    },\n  },\n\n  // A full, rounded dome on a straight trunk. Reads green in a meadow palette\n  // and blazes orange under the `autumn` palette.\n  maple: {\n    heightRange: [3.5, 5.5],\n    stiffness: 2.2,\n    anchorFrac: 0.24,\n    obstacleRadius: 0.65,\n    build(group, rng, palette, height) {\n      const trunkMaterial = mat(palette.trunk);\n      const foliageMaterial = mat(tint(rng.pick(palette.foliage), 0x86a83a, 0.2));\n      const trunkH = height * 0.4;\n      const trunk = new Mesh(new CylinderGeometry(0.12, 0.19, trunkH, 6), trunkMaterial);\n      trunk.position.y = trunkH / 2;\n      trunk.rotation.z = rng.range(-0.05, 0.05);\n      group.add(trunk);\n\n      const crownBase = trunkH + height * 0.12;\n      const R = height * rng.range(0.28, 0.34);\n      const center = new Mesh(new IcosahedronGeometry(R, 1), foliageMaterial); // detail 1 = rounder dome\n      center.position.y = crownBase;\n      center.rotation.set(rng.range(0, Math.PI), rng.range(0, Math.PI), 0);\n      group.add(center);\n\n      const ring = rng.int(4, 6);\n      for (let i = 0; i < ring; i++) {\n        const a = (i / ring) * Math.PI * 2 + rng.range(-0.2, 0.2);\n        const r = R * rng.range(0.55, 0.75);\n        const blob = new Mesh(new IcosahedronGeometry(r, 0), foliageMaterial);\n        blob.position.set(Math.cos(a) * R * 0.75, crownBase - R * 0.15 + rng.range(-0.1, 0.2), Math.sin(a) * R * 0.75);\n        blob.rotation.set(rng.range(0, Math.PI), rng.range(0, Math.PI), 0);\n        group.add(blob);\n      }\n      return foliageMaterial;\n    },\n  },\n\n  // A wide, low umbrella of blossom on a short dark trunk. `season` decides its\n  // dress: pink in spring, green in summer, warm in autumn, bare in winter.\n  sakura: {\n    heightRange: [3, 4.6],\n    stiffness: 2,\n    anchorFrac: 0.3,\n    obstacleRadius: 0.7,\n    build(group, rng, palette, height, season) {\n      const s = season ?? 'spring';\n      const barkMaterial = mat(tint(palette.trunk, 0x2e2320, 0.4)); // dark cherry bark\n      const trunkH = height * 0.4;\n      const trunk = new Mesh(new CylinderGeometry(0.1, 0.16, trunkH, 6), barkMaterial);\n      trunk.position.y = trunkH / 2;\n      trunk.rotation.z = rng.range(-0.06, 0.06);\n      group.add(trunk);\n      branches(group, barkMaterial, rng, trunkH, rng.int(4, 6), height * 0.5);\n\n      // Canopy colour by season (blossom pink is blossom pink, palette aside).\n      const canopyColor =\n        s === 'summer'\n          ? tint(rng.pick(palette.foliage), 0x7fb04a, 0.2)\n          : s === 'autumn'\n            ? tint(rng.pick(palette.foliage), 0xe08a3a, 0.7)\n            : tint(0xf3c1d6, 0xfdeaf1, rng.range(0, 0.4)); // spring blossom\n      const canopyMaterial = mat(canopyColor);\n\n      if (s !== 'winter') {\n        const crownBase = trunkH + height * 0.16;\n        const R = height * rng.range(0.34, 0.4);\n        const center = new Mesh(new IcosahedronGeometry(R, 1), canopyMaterial);\n        center.position.y = crownBase;\n        center.scale.y = 0.55; // flatten into an umbrella\n        group.add(center);\n        const ring = rng.int(5, 7);\n        for (let i = 0; i < ring; i++) {\n          const a = (i / ring) * Math.PI * 2 + rng.range(-0.2, 0.2);\n          const r = R * rng.range(0.5, 0.72);\n          const blob = new Mesh(new IcosahedronGeometry(r, 0), canopyMaterial);\n          blob.position.set(Math.cos(a) * R * 0.8, crownBase - R * 0.1 + rng.range(-0.05, 0.1), Math.sin(a) * R * 0.8);\n          blob.scale.y = 0.6;\n          group.add(blob);\n        }\n      }\n      return canopyMaterial;\n    },\n  },\n\n  // A curved bare stem crowned with long drooping fronds — a palm.\n  palm: {\n    heightRange: [5, 8],\n    stiffness: 1.2,\n    anchorFrac: 0.7,\n    obstacleRadius: 0.4,\n    build(group, rng, palette, height) {\n      const trunkMaterial = mat(tint(0x9c7b4e, palette.trunk, 0.3)); // tan stem\n      const crown = curvedTrunk(group, trunkMaterial, height * 0.86, 0.16, 0.1, height * 0.12);\n      const frondMaterial = mat(tint(rng.pick(palette.foliage), 0x4e8f3a, 0.3));\n      frondCrown(group, frondMaterial, rng, crown.x, crown.y, rng.int(9, 13), height * 0.42, 24);\n      // A cluster of coconuts under the crown.\n      const nutMaterial = mat(0x6b4a2f);\n      const nuts = rng.int(2, 4);\n      for (let i = 0; i < nuts; i++) {\n        const a = (i / nuts) * Math.PI * 2;\n        const nut = new Mesh(new IcosahedronGeometry(height * 0.045, 0), nutMaterial);\n        nut.position.set(crown.x + Math.cos(a) * 0.12, crown.y - 0.12, Math.sin(a) * 0.12);\n        group.add(nut);\n      }\n      return frondMaterial;\n    },\n  },\n\n  // A rounded crown trailing a veil of long swaying strands — a weeping willow.\n  willow: {\n    heightRange: [4, 6],\n    stiffness: 1.5,\n    anchorFrac: 0.05,\n    obstacleRadius: 0.7,\n    build(group, rng, palette, height) {\n      const trunkMaterial = mat(palette.trunk);\n      const trunkH = height * 0.42;\n      const trunk = new Mesh(new CylinderGeometry(0.12, 0.2, trunkH, 6), trunkMaterial);\n      trunk.position.y = trunkH / 2;\n      trunk.rotation.z = rng.range(-0.05, 0.05);\n      group.add(trunk);\n\n      const foliageMaterial = mat(tint(rng.pick(palette.foliage), 0xb6cf6e, 0.4)); // willow yellow-green\n      const crownBase = trunkH + height * 0.22;\n      const R = height * rng.range(0.32, 0.4);\n      const dome = new Mesh(new IcosahedronGeometry(R, 1), foliageMaterial);\n      dome.position.y = crownBase;\n      dome.scale.y = 0.7;\n      group.add(dome);\n\n      // The signature: a veil of strands hanging from the canopy hem.\n      droopStrands(group, foliageMaterial, rng, crownBase - R * 0.35, R * 0.95, rng.int(30, 38), height * 0.42, height * 0.72);\n      return foliageMaterial;\n    },\n  },\n\n  // A colossus — a thick buttressed redwood trunk carrying a high conical crown.\n  // Towers over an ordinary wood; place it sparingly.\n  sequoia: {\n    heightRange: [22, 32],\n    stiffness: 4,\n    anchorFrac: 0.5,\n    obstacleRadius: (h) => h * 0.06,\n    build(group, rng, palette, height) {\n      const barkMaterial = mat(0x8a4b32); // redwood bark\n      const foliageMaterial = mat(tint(rng.pick(palette.foliage), 0x1f4a34, 0.5)); // deep green\n      const baseR = height * 0.075;\n      buttressTrunk(group, barkMaterial, rng, height * 0.55, baseR, baseR * 0.4);\n\n      // A tall conical crown of stacked cones over the upper trunk.\n      const tiers = rng.int(5, 7);\n      let y = height * 0.42;\n      let radius = height * rng.range(0.16, 0.2);\n      const tierH = (height - y) / tiers + 0.4;\n      for (let i = 0; i < tiers; i++) {\n        const cone = new Mesh(new ConeGeometry(radius, tierH * 1.4, 8), foliageMaterial);\n        cone.position.y = y + tierH * 0.55;\n        cone.rotation.y = rng.range(0, Math.PI);\n        group.add(cone);\n        y += tierH * 0.82;\n        radius *= 0.74;\n      }\n      return foliageMaterial;\n    },\n  },\n\n  // A vast crown resting on a stout trunk and a curtain of aerial prop-roots —\n  // a whole grove from one tree.\n  banyan: {\n    heightRange: [5, 8],\n    stiffness: 3,\n    anchorFrac: 0.3,\n    obstacleRadius: (h) => h * 0.3,\n    build(group, rng, palette, height) {\n      const barkMaterial = mat(tint(palette.trunk, 0x4a3320, 0.3));\n      const foliageMaterial = mat(tint(rng.pick(palette.foliage), 0x1d5a3a, 0.35));\n      const trunkH = height * 0.4;\n      const trunk = new Mesh(new CylinderGeometry(height * 0.09, height * 0.15, trunkH, 8), barkMaterial);\n      trunk.position.y = trunkH / 2;\n      group.add(trunk);\n\n      const crownBase = trunkH + height * 0.2;\n      const R = height * rng.range(0.5, 0.62); // very wide\n      const center = new Mesh(new IcosahedronGeometry(R, 1), foliageMaterial);\n      center.position.y = crownBase;\n      center.scale.y = 0.62;\n      group.add(center);\n      const ring = rng.int(6, 9);\n      for (let i = 0; i < ring; i++) {\n        const a = (i / ring) * Math.PI * 2 + rng.range(-0.15, 0.15);\n        const r = R * rng.range(0.45, 0.65);\n        const blob = new Mesh(new IcosahedronGeometry(r, 0), foliageMaterial);\n        blob.position.set(Math.cos(a) * R * 0.85, crownBase - R * 0.12 + rng.range(-0.1, 0.15), Math.sin(a) * R * 0.85);\n        blob.scale.y = 0.7;\n        group.add(blob);\n      }\n      // Aerial roots drop from the crown to the ground.\n      aerialRoots(group, barkMaterial, rng, crownBase - R * 0.3, R * 0.7, rng.int(7, 11));\n      return foliageMaterial;\n    },\n  },\n\n  // A fat bottle trunk under a sparse, high crown — the upside-down savanna tree.\n  baobab: {\n    heightRange: [5, 8],\n    stiffness: 3.5,\n    anchorFrac: 0.55,\n    obstacleRadius: (h) => h * 0.16,\n    build(group, rng, palette, height) {\n      const barkMaterial = mat(tint(palette.trunk, 0x8f8272, 0.5)); // pale grey-brown bark\n      const foliageMaterial = mat(tint(rng.pick(palette.foliage), 0x6f8a3a, 0.3));\n      const crownY = bottleTrunk(group, barkMaterial, rng, height, height * 0.19);\n\n      // Sparse tufts of foliage at the branch tips.\n      const tufts = rng.int(4, 6);\n      for (let i = 0; i < tufts; i++) {\n        const a = (i / tufts) * Math.PI * 2 + rng.range(-0.3, 0.3);\n        const r = height * rng.range(0.12, 0.18);\n        const tuft = new Mesh(new IcosahedronGeometry(r, 0), foliageMaterial);\n        tuft.position.set(Math.cos(a) * height * 0.22, crownY + rng.range(0, height * 0.1), Math.sin(a) * height * 0.22);\n        tuft.scale.y = 0.7;\n        group.add(tuft);\n      }\n      return foliageMaterial;\n    },\n  },\n\n  // A thin trunk under a broad, flat-topped umbrella — the acacia of the savanna.\n  acacia: {\n    heightRange: [4, 6],\n    stiffness: 2.5,\n    anchorFrac: 0.4,\n    obstacleRadius: 0.5,\n    build(group, rng, palette, height) {\n      const barkMaterial = mat(tint(palette.trunk, 0x6a5030, 0.3));\n      const foliageMaterial = mat(tint(rng.pick(palette.foliage), 0x8fa04a, 0.35)); // dusty savanna green\n      const trunkH = height * 0.62;\n      const trunk = new Mesh(new CylinderGeometry(0.06, 0.13, trunkH, 6), barkMaterial);\n      trunk.position.y = trunkH / 2;\n      trunk.rotation.z = rng.range(-0.05, 0.05);\n      group.add(trunk);\n\n      // The umbrella: a wide, very flat canopy of overlapping plates.\n      const crownBase = trunkH + height * 0.08;\n      const R = height * rng.range(0.5, 0.6);\n      const plates = rng.int(3, 4);\n      for (let i = 0; i < plates; i++) {\n        const r = R * (1 - i * 0.16);\n        const plate = new Mesh(new IcosahedronGeometry(r, 0), foliageMaterial);\n        plate.position.set(rng.jitter(0, R * 0.12), crownBase + i * height * 0.05, rng.jitter(0, R * 0.12));\n        plate.scale.y = 0.22; // very flat umbrella\n        plate.rotation.y = rng.range(0, Math.PI);\n        group.add(plate);\n      }\n      return foliageMaterial;\n    },\n  },\n};\n\n/**\n * A seeded low-poly tree. Nine species — `pine` and `oak` (the originals), plus\n * `cypress` (a tall narrow flame), `birch` (slender, pale, banded), `cedar`\n * (broad flat tiers), `maple` (a full rounded dome), `sakura` (a blossom\n * umbrella), `palm` (a curved stem with drooping fronds) and `willow` (a veil of\n * swaying strands) — each with its own silhouette, colour, wind response and\n * steering footprint. Same seed → identical tree, forever.\n *\n * New species are opt-in via `species`; with none given, a forest stays the\n * familiar pine/oak mix, so existing scenes are untouched. `season` dresses a\n * `sakura` — pink in spring, green in summer, warm in autumn, bare in winter.\n *\n * ```ts\n * const cypress = createTree({ species: 'cypress', seed: 7 });\n * const bloom = createTree({ species: 'sakura', season: 'spring' });\n * const palm = createTree({ species: 'palm', seed: 3 });\n * ```\n */\nexport function createTree(options: TreeOptions = {}): Prop {\n  const rng = new Rng(options.seed ?? 1);\n  const palette = options.palette ?? DEFAULT_PALETTE;\n  // Default stays pine/oak (one rng draw), so seeded forests never change.\n  const species = options.species ?? options.style ?? (rng.next() < 0.6 ? 'pine' : 'oak');\n  const recipe = SPECIES[species];\n  const height = options.height ?? rng.range(recipe.heightRange[0], recipe.heightRange[1]);\n\n  const group = new Group();\n  group.name = `tree-${species}`;\n  const foliageMaterial = recipe.build(group, rng, palette, height, options.season);\n  // Tag the canopy material so a Seasons controller can find and re-grade it\n  // (spring→autumn→winter) while leaving the trunk planted and unchanged.\n  (foliageMaterial.userData ??= {}).scenaFoliage = true;\n\n  // Only the canopy sways — the trunk material is left unbound, so it stays\n  // planted. (For a scattered forest, prefer applyWind(forest.group), which\n  // drives the shared clock from the rendered InstancedMesh.)\n  if (options.wind) {\n    options.wind.bind(foliageMaterial, {\n      height,\n      stiffness: recipe.stiffness,\n      anchor: height * recipe.anchorFrac,\n    });\n    options.wind.attach(group);\n  }\n\n  const obstacleRadius =\n    typeof recipe.obstacleRadius === 'function' ? recipe.obstacleRadius(height) : recipe.obstacleRadius;\n  return { object: group, obstacleRadius };\n}\n\n// --- biomes: a weighted species mix for scattering a wood in one call --------\n\nexport type TreeBiome =\n  | 'temperate'\n  | 'boreal'\n  | 'mediterranean'\n  | 'tropical'\n  | 'savanna'\n  | 'redwood'\n  | 'grove'\n  | 'wetland';\n\n/** The species mix (and relative frequency) each biome scatters. */\nexport const TREE_BIOMES: Record<TreeBiome, ReadonlyArray<{ species: TreeSpecies; weight: number }>> = {\n  temperate: [{ species: 'oak', weight: 4 }, { species: 'pine', weight: 3 }, { species: 'birch', weight: 2 }, { species: 'maple', weight: 2 }],\n  boreal: [{ species: 'pine', weight: 5 }, { species: 'cedar', weight: 2 }, { species: 'birch', weight: 2 }],\n  mediterranean: [{ species: 'cypress', weight: 3 }, { species: 'oak', weight: 3 }, { species: 'pine', weight: 2 }],\n  tropical: [{ species: 'palm', weight: 5 }, { species: 'banyan', weight: 1 }],\n  savanna: [{ species: 'acacia', weight: 4 }, { species: 'baobab', weight: 1 }],\n  redwood: [{ species: 'sequoia', weight: 1 }, { species: 'pine', weight: 4 }, { species: 'cedar', weight: 2 }],\n  grove: [{ species: 'sakura', weight: 1 }],\n  wetland: [{ species: 'willow', weight: 3 }, { species: 'birch', weight: 2 }],\n};\n\nexport interface TreeBiomeOptions {\n  palette?: Palette;\n  season?: TreeSeason;\n  /** Visual variants generated per species. Default 4. */\n  variants?: number;\n}\n\n/**\n * The species mix for a biome, ready to drop into `scatter({ items })` — so a\n * whole wood takes on a character in one word. A `redwood` stand towers with\n * sequoias over pines; a `tropical` shore is palms and the odd banyan; a\n * `savanna` is acacias and a baobab. Each species keeps its own silhouette,\n * wind response and (height-scaled) steering footprint.\n *\n * ```ts\n * scatter({ items: treeBiome('tropical', { palette }), area, density: 0.02 });\n * ```\n */\nexport function treeBiome(biome: TreeBiome, options: TreeBiomeOptions = {}): Array<{\n  create: (rng: Rng) => Prop;\n  weight: number;\n  variants: number;\n}> {\n  return TREE_BIOMES[biome].map(({ species, weight }) => ({\n    create: (rng: Rng) =>\n      createTree({ species, seed: rng.int(1, 1e9), palette: options.palette, season: options.season }),\n    weight,\n    variants: options.variants ?? 4,\n  }));\n}\n","/**\n * Deterministic seeded randomness — the backbone of SCENA. Same seed,\n * same tree; forests are reproducible, diffable and network-syncable.\n */\nexport class Rng {\n  private state: number;\n\n  constructor(seed = 1) {\n    this.state = seed >>> 0 || 1;\n  }\n\n  /** Next float in [0, 1) (mulberry32). */\n  next(): number {\n    this.state = (this.state + 0x6d2b79f5) >>> 0;\n    let t = this.state;\n    t = Math.imul(t ^ (t >>> 15), t | 1);\n    t ^= t + Math.imul(t ^ (t >>> 7), t | 61);\n    return ((t ^ (t >>> 14)) >>> 0) / 4294967296;\n  }\n\n  /** Float in [min, max). */\n  range(min: number, max: number): number {\n    return min + this.next() * (max - min);\n  }\n\n  /** Integer in [min, max] inclusive. */\n  int(min: number, max: number): number {\n    return min + Math.floor(this.next() * (max - min + 1));\n  }\n\n  /** Random element of a non-empty array. */\n  pick<T>(items: readonly T[]): T {\n    return items[Math.floor(this.next() * items.length)];\n  }\n\n  /** value ± spread (uniform). */\n  jitter(value: number, spread: number): number {\n    return value + (this.next() * 2 - 1) * spread;\n  }\n\n  /** A new independent Rng derived from this one. */\n  fork(): Rng {\n    return new Rng(Math.floor(this.next() * 0xffffffff) || 1);\n  }\n}\n\n/** Integer-lattice hash to [0, 1) — the base of the value noise. */\nexport function hash2(ix: number, iz: number, seed: number): number {\n  let h = (ix * 374761393 + iz * 668265263 + seed * 2246822519) >>> 0;\n  h = Math.imul(h ^ (h >>> 13), 1274126177) >>> 0;\n  return ((h ^ (h >>> 16)) >>> 0) / 4294967296;\n}\n\nconst smooth = (t: number): number => t * t * (3 - 2 * t);\n\n/** 2D value noise in [0, 1). Continuous; used by terrain and scatter density. */\nexport function valueNoise2(x: number, z: number, seed: number): number {\n  const ix = Math.floor(x);\n  const iz = Math.floor(z);\n  const fx = smooth(x - ix);\n  const fz = smooth(z - iz);\n  const a = hash2(ix, iz, seed);\n  const b = hash2(ix + 1, iz, seed);\n  const c = hash2(ix, iz + 1, seed);\n  const d = hash2(ix + 1, iz + 1, seed);\n  return a + (b - a) * fx + (c - a) * fz + (a - b - c + d) * fx * fz;\n}\n\n/** Fractal (octaved) value noise in [0, 1). */\nexport function fractalNoise2(\n  x: number,\n  z: number,\n  seed: number,\n  octaves = 4,\n  lacunarity = 2,\n  gain = 0.5\n): number {\n  let amplitude = 1;\n  let frequency = 1;\n  let sum = 0;\n  let total = 0;\n  for (let i = 0; i < octaves; i++) {\n    sum += valueNoise2(x * frequency, z * frequency, seed + i * 101) * amplitude;\n    total += amplitude;\n    amplitude *= gain;\n    frequency *= lacunarity;\n  }\n  return sum / total;\n}\n","/**\n * Theme palettes: one coherent set of colors shared by every generator,\n * so procedural props look like a matched set rather than a junk drawer.\n * Pass `palette` to any generator to restyle it; whole scenes retheme by\n * building with a different palette.\n */\nexport interface Palette {\n  foliage: number[];\n  trunk: number;\n  rock: number[];\n  wood: number;\n  woodDark: number;\n  metal: number;\n  lampGlow: number;\n  grassLow: number;\n  grassHigh: number;\n  cliff: number;\n  peak: number;\n  skyTop: number;\n  skyBottom: number;\n  fog: number;\n  water: number;\n  sand: number;\n  path: number;\n  /** Building plaster/wall color. */\n  wall: number;\n  /** Building roof color. */\n  roof: number;\n}\n\nexport const PALETTES: Record<'meadow' | 'autumn' | 'dusk' | 'winter' | 'urban', Palette> = {\n  meadow: {\n    foliage: [0x2f9e57, 0x37b26a, 0x2a8f4f, 0x45b878],\n    trunk: 0x6b4a33,\n    rock: [0x8a8f98, 0x767c86, 0x9aa0a8],\n    wood: 0x8a6642,\n    woodDark: 0x6b4a33,\n    metal: 0x3d4451,\n    lampGlow: 0xffd889,\n    grassLow: 0x3f9d5a,\n    grassHigh: 0x6fae66,\n    cliff: 0x7d7a72,\n    peak: 0xe8ecef,\n    skyTop: 0x3d70b8,\n    skyBottom: 0xbfd9e8,\n    fog: 0xb8cfdd,\n    water: 0x3f7fae,\n    sand: 0xc9b98a,\n    path: 0x9a815f,\n    wall: 0xd9ccb0,\n    roof: 0xa8563e,\n  },\n  autumn: {\n    foliage: [0xc9752f, 0xd98e3a, 0xb35c2a, 0xe0a545],\n    trunk: 0x5d4030,\n    rock: [0x8d8578, 0x776f63, 0x9c948a],\n    wood: 0x7d5a3a,\n    woodDark: 0x5d4030,\n    metal: 0x463f3a,\n    lampGlow: 0xffc571,\n    grassLow: 0x9d8a3f,\n    grassHigh: 0xb59b4a,\n    cliff: 0x82746a,\n    peak: 0xe3ded4,\n    skyTop: 0x8e6ca8,\n    skyBottom: 0xe8c9a8,\n    fog: 0xd9c1a8,\n    water: 0x4a7a92,\n    sand: 0xcbb083,\n    path: 0x8d7454,\n    wall: 0xccb894,\n    roof: 0x8a4a30,\n  },\n  dusk: {\n    foliage: [0x1f5e46, 0x24684f, 0x1a5240, 0x2d7458],\n    trunk: 0x413147,\n    rock: [0x565672, 0x484861, 0x646484],\n    wood: 0x5d4a63,\n    woodDark: 0x413147,\n    metal: 0x2b2b3d,\n    lampGlow: 0xffb35c,\n    grassLow: 0x2d6b52,\n    grassHigh: 0x3d7a5e,\n    cliff: 0x52516b,\n    peak: 0xb8b8d9,\n    skyTop: 0x1d2145,\n    skyBottom: 0xc96a4a,\n    fog: 0x6a5a7a,\n    water: 0x2d4a68,\n    sand: 0x8a7a6a,\n    path: 0x6a5a52,\n    wall: 0x8d8299,\n    roof: 0x453558,\n  },\n  winter: {\n    foliage: [0x2e5c48, 0x38695a, 0x527a68, 0x87a596],\n    trunk: 0x4a3a33,\n    rock: [0x9aa4ad, 0x848e98, 0xb0b8c0],\n    wood: 0x776049,\n    woodDark: 0x54453a,\n    metal: 0x39404d,\n    lampGlow: 0xffd889,\n    grassLow: 0xcfd9de,\n    grassHigh: 0xe4ebee,\n    cliff: 0x76797d,\n    peak: 0xf4f7fa,\n    skyTop: 0x5a7ba6,\n    skyBottom: 0xd8e4ec,\n    fog: 0xccd8e0,\n    water: 0x4a7086,\n    sand: 0xb8c2c6,\n    path: 0x8b8378,\n    wall: 0xd2c9bb,\n    roof: 0x6b4638,\n  },\n  // Modern district: warm-white render, charcoal trim, teak accents, clipped\n  // green — for bungalows, towers and the Tier-4 surfaces.\n  urban: {\n    foliage: [0x4a8f56, 0x5aa065, 0x3f7f4b, 0x6aae74],\n    trunk: 0x5d4a38,\n    rock: [0x9a9a96, 0x85857f, 0xaaaaa4],\n    wood: 0x8a5c36, // teak\n    woodDark: 0x54402c,\n    metal: 0x2f353c, // charcoal powder-coat\n    lampGlow: 0xffe0a8,\n    grassLow: 0x5a9a5e,\n    grassHigh: 0x7aae6e,\n    cliff: 0x8a8a84,\n    peak: 0xe8ecef,\n    skyTop: 0x4a7ec2,\n    skyBottom: 0xcfe0ec,\n    fog: 0xc8d4dd,\n    water: 0x3f7fae,\n    sand: 0xc9bfa8,\n    path: 0xb0aca2, // pale concrete\n    wall: 0xe8e2d6, // warm-white render\n    roof: 0x3a3d42, // charcoal fascia\n  },\n};\n\nexport const DEFAULT_PALETTE: Palette = PALETTES.meadow;\n","import { Color, Group, Mesh, MeshBasicMaterial, PlaneGeometry } from 'three';\nimport { Rng } from '../core/random';\nimport { DEFAULT_PALETTE, type Palette } from '../core/palette';\nimport type { Prop } from '../core/types';\nimport type { ScatterItem } from '../scatter/scatter';\nimport { createTree, type TreeSpecies, type TreeOptions } from './tree';\n\n/** The slice of the shader object `onBeforeCompile` receives. */\ninterface PatchableShader {\n  uniforms: Record<string, { value: unknown }>;\n  vertexShader: string;\n  fragmentShader: string;\n}\n\n/**\n * A silhouette family. The billboard carves this shape per-fragment from its\n * UVs — so an impostor is one camera-facing quad, not a texture.\n * - `conifer`  — a tall triangle over a trunk (pine, **sequoia**).\n * - `round`    — a broad dome (oak, maple, **banyan**).\n * - `column`   — a slender flame (cypress).\n * - `umbrella` — a wide flat crown high on a thin trunk (**acacia**).\n * - `bottle`   — a sparse crown on a fat tapering trunk (**baobab**).\n */\nexport type ImpostorProfile = 'conifer' | 'round' | 'column' | 'umbrella' | 'bottle';\n\ninterface ProfileParams {\n  profile: ImpostorProfile;\n  /** Normalised height where the canopy begins (below is trunk). */\n  canopyBase: number;\n  /** Where in the canopy the silhouette is widest (0 base … 1 top). */\n  belly: number;\n  /** How sharply the width falls off away from the belly. */\n  taper: number;\n  /** Trunk half-width, in UV (fraction of the quad's half-width). */\n  trunkHalf: number;\n  /** Trunk taper: how much the trunk narrows going up (0 = parallel, 1 = to a point). */\n  trunkTaper: number;\n  /** Crown diameter as a fraction of height (sets the billboard's world width). */\n  widthRatio: number;\n}\n\n// One row per silhouette; giants first, then the garden species for reuse.\nconst SPECIES_PROFILE: Partial<Record<TreeSpecies, ProfileParams>> = {\n  sequoia: { profile: 'conifer', canopyBase: 0.4, belly: 0.0, taper: 1.25, trunkHalf: 0.09, trunkTaper: 0.35, widthRatio: 0.34 },\n  banyan: { profile: 'round', canopyBase: 0.26, belly: 0.55, taper: 1.6, trunkHalf: 0.12, trunkTaper: 0.1, widthRatio: 1.1 },\n  baobab: { profile: 'bottle', canopyBase: 0.72, belly: 0.5, taper: 1.4, trunkHalf: 0.22, trunkTaper: 0.55, widthRatio: 0.62 },\n  acacia: { profile: 'umbrella', canopyBase: 0.58, belly: 0.9, taper: 2.2, trunkHalf: 0.05, trunkTaper: 0.25, widthRatio: 1.0 },\n  pine: { profile: 'conifer', canopyBase: 0.22, belly: 0.0, taper: 1.4, trunkHalf: 0.06, trunkTaper: 0.3, widthRatio: 0.5 },\n  oak: { profile: 'round', canopyBase: 0.42, belly: 0.5, taper: 1.5, trunkHalf: 0.08, trunkTaper: 0.15, widthRatio: 0.62 },\n  cypress: { profile: 'column', canopyBase: 0.12, belly: 0.35, taper: 1.1, trunkHalf: 0.05, trunkTaper: 0.2, widthRatio: 0.22 },\n  maple: { profile: 'round', canopyBase: 0.4, belly: 0.5, taper: 1.5, trunkHalf: 0.08, trunkTaper: 0.15, widthRatio: 0.68 },\n};\n\nconst DEFAULT_PARAMS: ProfileParams = SPECIES_PROFILE.oak!;\n\n/** Mid-height (world units) a species stands, used to size an impostor from a name. */\nconst SPECIES_HEIGHT: Partial<Record<TreeSpecies, number>> = {\n  sequoia: 27, banyan: 6.5, baobab: 6.5, acacia: 5, pine: 4.2, oak: 4.2, cypress: 8, maple: 4.5,\n};\n\n/** Characteristic foliage tint per species (matches the full tree's recipe). */\nfunction foliageFor(species: TreeSpecies | undefined, palette: Palette, rng: Rng): number {\n  const base = new Color(rng.pick(palette.foliage));\n  const toward: Partial<Record<TreeSpecies, number>> = {\n    sequoia: 0x1f4a34, banyan: 0x1d5a3a, baobab: 0x6f8a3a, acacia: 0x8fa04a,\n    cypress: 0x123a24, maple: 0x86a83a, pine: 0x2f5d2a, oak: 0x3f7d2f,\n  };\n  const t = species && toward[species] !== undefined ? new Color(toward[species]) : null;\n  return t ? base.lerp(t, 0.4).getHex() : base.getHex();\n}\n\nexport interface ImpostorOptions {\n  /** Species to imitate (picks the silhouette, size and colours). */\n  species?: TreeSpecies;\n  /** Silhouette family, if not deriving it from `species`. */\n  profile?: ImpostorProfile;\n  /** Height in world units. Default: the species' typical height. */\n  height?: number;\n  /** Crown diameter in world units. Default: derived from height. */\n  width?: number;\n  /** Foliage colour (hex). Default: derived from the palette + species. */\n  foliage?: number;\n  /** Trunk colour (hex). Default: the palette trunk. */\n  trunk?: number;\n  seed?: number;\n  palette?: Palette;\n}\n\nconst IMP_UNIFORMS = /* glsl */ `\nuniform float uImpWidth;\nuniform float uImpHeight;\nuniform vec3  uImpFoliage;\nuniform vec3  uImpTrunk;\nuniform float uImpCanopyBase;\nuniform float uImpBelly;\nuniform float uImpTaper;\nuniform float uImpTrunkHalf;\nuniform float uImpTrunkTaper;\nuniform float uImpSeed;\nvarying vec2  vImpUv;\n`;\n\n// Cylindrical billboard: expand the quad around the instance's world origin\n// using the camera's world right axis and world up — so it always faces the\n// camera but stays upright. Per-instance scale is read from the instance matrix.\nconst IMP_PROJECT = /* glsl */ `\nvec4 mvPosition = vec4( transformed, 1.0 );\n{\n  mat4 scenaInst = mat4(1.0);\n  #ifdef USE_INSTANCING\n    scenaInst = instanceMatrix;\n  #endif\n  mat4 scenaWM = modelMatrix * scenaInst;\n  vec3 scenaAnchor = scenaWM[3].xyz;\n  float scenaScl = length(scenaWM[0].xyz);\n  vec3 scenaRight = normalize(vec3(viewMatrix[0][0], viewMatrix[1][0], viewMatrix[2][0]));\n  vec3 scenaUp = vec3(0.0, 1.0, 0.0);\n  vec3 scenaWorld = scenaAnchor\n    + scenaRight * (position.x * uImpWidth * scenaScl)\n    + scenaUp    * (position.y * uImpHeight * scenaScl);\n  mvPosition = viewMatrix * vec4(scenaWorld, 1.0);\n}\ngl_Position = projectionMatrix * mvPosition;\n`;\n\n// Carve the species silhouette from the UVs, tint canopy vs. trunk, bake a\n// vertical + lateral shading gradient for volume, and discard the empty corners.\nconst IMP_FRAG = /* glsl */ `\n{\n  float ix = vImpUv.x - 0.5;      // -0.5 … 0.5 across\n  float iy = vImpUv.y;            // 0 base … 1 top\n  float inside = 0.0;\n  vec3  impCol = uImpTrunk;\n\n  // Canopy: width peaks at the belly and tapers away, with a little edge wobble.\n  if (iy >= uImpCanopyBase) {\n    float t = (iy - uImpCanopyBase) / max(1.0 - uImpCanopyBase, 1e-3);\n    float above = t - uImpBelly;\n    float span = above > 0.0 ? (1.0 - uImpBelly) : uImpBelly;\n    float k = clamp(1.0 - abs(above) / max(span, 1e-3), 0.0, 1.0);\n    float w = 0.5 * pow(k, uImpTaper);\n    w += 0.03 * sin(iy * 34.0 + uImpSeed) * step(0.02, w); // ragged edge\n    if (abs(ix) < w) {\n      inside = 1.0;\n      float shade = 1.0 - 0.4 * (abs(ix) / max(w, 1e-3)); // rounder toward the edge\n      impCol = uImpFoliage * (0.82 + 0.32 * iy) * shade;\n    }\n  }\n  // Trunk: a tapering bar up to (and a little into) the canopy.\n  float trunkTop = uImpCanopyBase + 0.08;\n  if (iy < trunkTop) {\n    float th = uImpTrunkHalf * (1.0 - uImpTrunkTaper * iy);\n    if (abs(ix) < th) {\n      inside = 1.0;\n      impCol = uImpTrunk * (0.7 + 0.4 * iy);\n    }\n  }\n  if (inside < 0.5) discard;\n  diffuseColor.rgb = impCol;\n}\n`;\n\n/**\n * A billboard **impostor** — a single camera-facing quad that stands in for a\n * full tree at distance. The species silhouette is carved procedurally from the\n * quad's UVs (no texture), lit by a baked gradient and three's fog, and the\n * billboard is expanded in the vertex shader so one shared quad faces the camera\n * for every instance. Built for {@link scatter}'s far-LOD slot, so a *dense\n * giant forest* — thousands of sequoias — can cull to a handful of draw calls\n * of billboards beyond the swap distance while the near tiles keep full geometry.\n *\n * ```ts\n * const far = createImpostor({ species: 'sequoia', palette });\n * // usually via treeLOD(), which pairs the full tree with this automatically:\n * scatter({ items: [treeLOD('sequoia', { palette })], lod: { distance: 90 } });\n * ```\n */\nexport function createImpostor(options: ImpostorOptions = {}): Prop {\n  const rng = new Rng(options.seed ?? 1);\n  const palette = options.palette ?? DEFAULT_PALETTE;\n  const params = (options.species && SPECIES_PROFILE[options.species]) || DEFAULT_PARAMS;\n  const height = options.height ?? (options.species ? SPECIES_HEIGHT[options.species] ?? 5 : 5);\n  const width = options.width ?? height * params.widthRatio;\n  const foliage = new Color(options.foliage ?? foliageFor(options.species, palette, rng));\n  const trunk = new Color(options.trunk ?? palette.trunk);\n\n  const uniforms = {\n    uImpWidth: { value: width },\n    uImpHeight: { value: height },\n    uImpFoliage: { value: foliage },\n    uImpTrunk: { value: trunk },\n    uImpCanopyBase: { value: params.canopyBase },\n    uImpBelly: { value: params.belly },\n    uImpTaper: { value: params.taper },\n    uImpTrunkHalf: { value: params.trunkHalf },\n    uImpTrunkTaper: { value: params.trunkTaper },\n    uImpSeed: { value: rng.range(0, 100) },\n  };\n\n  // A unit quad, base at y=0, so position.y is the 0…1 height and position.x\n  // the -0.5…0.5 span — read directly as UVs in the shader (no uv attribute).\n  const geometry = new PlaneGeometry(1, 1).translate(0, 0.5, 0);\n  const material = new MeshBasicMaterial({ fog: true });\n  material.onBeforeCompile = (shader: PatchableShader) => {\n    Object.assign(shader.uniforms, uniforms);\n    shader.vertexShader = shader.vertexShader\n      .replace('#include <common>', '#include <common>\\n' + IMP_UNIFORMS)\n      .replace('#include <begin_vertex>', '#include <begin_vertex>\\n  vImpUv = vec2(position.x + 0.5, position.y);')\n      .replace('#include <project_vertex>', IMP_PROJECT);\n    shader.fragmentShader = shader.fragmentShader\n      .replace('#include <common>', '#include <common>\\n' + IMP_UNIFORMS)\n      .replace('#include <color_fragment>', '#include <color_fragment>\\n' + IMP_FRAG);\n  };\n  material.customProgramCacheKey = () => 'scena-impostor-v1';\n\n  const mesh = new Mesh(geometry, material);\n  mesh.frustumCulled = false; // the billboard reaches beyond its origin\n  const group = new Group();\n  group.name = `impostor-${options.species ?? params.profile}`;\n  group.add(mesh);\n\n  // Match the full tree's steering footprint so a mixed near/far wood is honest.\n  const obstacleRadius = options.species\n    ? (options.species === 'sequoia' ? height * 0.06\n      : options.species === 'banyan' ? height * 0.3\n      : options.species === 'baobab' ? height * 0.16\n      : width * 0.35)\n    : width * 0.35;\n  return { object: group, obstacleRadius };\n}\n\nexport interface TreeLODOptions extends TreeOptions {\n  /** Relative frequency among scatter items. Default 1. */\n  weight?: number;\n  /** Full-detail visual variants. Default 4. */\n  variants?: number;\n  /** Per-instance uniform scale range. Default [0.85, 1.2]. */\n  scale?: [number, number];\n}\n\n/**\n * A {@link ScatterItem} that pairs a full {@link createTree} with its billboard\n * {@link createImpostor} — the near/far LOD couple. Drop it straight into\n * `scatter({ items, lod })` and tiles past the swap distance trade full trees\n * for camera-facing impostors, so a forest of giants stays a few draw calls at\n * range while the trees you can walk up to keep every branch.\n *\n * ```ts\n * const forest = scatter({\n *   area, surface: terrain.heightAt, density: 0.01, minSpacing: 7,\n *   items: [treeLOD('sequoia', { palette }), treeLOD('pine', { palette, weight: 3 })],\n *   lod: { distance: 90, tileSize: 24 },\n * });\n * scene.add(forest.group);\n * // each frame: forest.update(camera)\n * ```\n */\nexport function treeLOD(species: TreeSpecies, options: TreeLODOptions = {}): ScatterItem {\n  const { weight, variants, scale, ...treeOptions } = options;\n  return {\n    create: (rng: Rng) => createTree({ ...treeOptions, species, seed: rng.int(1, 1e9) }),\n    createFar: (rng: Rng) =>\n      createImpostor({ species, palette: treeOptions.palette, seed: rng.int(1, 1e9) }),\n    weight: weight ?? 1,\n    variants: variants ?? 4,\n    scale: scale ?? [0.85, 1.2],\n  };\n}\n","import { BufferAttribute, Group, IcosahedronGeometry, Mesh } from 'three';\nimport { Rng } from '../core/random';\nimport { DEFAULT_PALETTE, type Palette } from '../core/palette';\nimport { createSurface } from '../materials/surface';\nimport type { Prop } from '../core/types';\n\nexport interface RockOptions {\n  seed?: number;\n  /** Approximate radius. Default ~0.4–1.1 by seed. */\n  size?: number;\n  palette?: Palette;\n}\n\n/**\n * A seeded low-poly boulder: an icosahedron with jittered vertices and a\n * flattened underside so it sits on the ground.\n */\nexport function createRock(options: RockOptions = {}): Prop {\n  const rng = new Rng(options.seed ?? 1);\n  const palette = options.palette ?? DEFAULT_PALETTE;\n  const size = options.size ?? rng.range(0.4, 1.1);\n\n  const geometry = new IcosahedronGeometry(size, 0);\n  const positions = geometry.getAttribute('position') as BufferAttribute;\n  // Jitter welded-by-value: identical vertex values get identical offsets,\n  // so faces stay connected.\n  const seen = new Map<string, [number, number, number]>();\n  for (let i = 0; i < positions.count; i++) {\n    const key = `${positions.getX(i).toFixed(4)},${positions.getY(i).toFixed(4)},${positions.getZ(i).toFixed(4)}`;\n    let offset = seen.get(key);\n    if (!offset) {\n      offset = [rng.jitter(0, size * 0.22), rng.jitter(0, size * 0.16), rng.jitter(0, size * 0.22)];\n      seen.set(key, offset);\n    }\n    positions.setXYZ(\n      i,\n      positions.getX(i) + offset[0],\n      Math.max(positions.getY(i) + offset[1], -size * 0.15), // flatten the bottom\n      positions.getZ(i) + offset[2]\n    );\n  }\n  geometry.computeVertexNormals();\n\n  const rock = new Mesh(\n    geometry,\n    createSurface('stone', { color: rng.pick(palette.rock), seed: options.seed ?? 1 })\n  );\n  rock.position.y = size * 0.15;\n  rock.scale.y = rng.range(0.6, 0.9);\n\n  const group = new Group();\n  group.name = 'rock';\n  group.add(rock);\n  return { object: group, obstacleRadius: size * 1.05 };\n}\n","import { Color, MeshPhysicalMaterial, MeshStandardMaterial, Vector2, Vector3 } from 'three';\n\n/**\n * Procedural surface materials — the reason low-poly SCENA props can look\n * richer than a downloaded GLTF at a fraction of the bytes.\n *\n * A downloaded model ships baked albedo/normal/roughness textures (often\n * megabytes). Here the same detail — weathered stone, wood grain, mottled\n * plaster, thatch, tile — is generated in the shader from triplanar value\n * noise, so nothing is fetched and every prop is unique. The result is a\n * plain `MeshStandardMaterial` with an `onBeforeCompile` patch, so it keeps\n * three's full PBR lighting, shadows, fog, tone-mapping, and SCENA's\n * day/night emissive dimming — none of which a raw `ShaderMaterial` would.\n *\n * ```ts\n * const mat = createSurface('stone', { color: 0x8a8f98 });\n * mesh.material = mat;                       // that's it\n * ```\n *\n * Triplanar means no UVs are needed (a `BoxGeometry` has none worth using),\n * and because the noise is sampled in world space a wall built from several\n * abutting boxes reads as one continuous stone face with no visible seams.\n */\nexport type SurfaceKind =\n  | 'plaster'\n  | 'stone'\n  | 'wood'\n  | 'plank'\n  | 'thatch'\n  | 'tile'\n  | 'metal'\n  | 'dirt'\n  // Tier 1 — ground & terrain\n  | 'sand'\n  | 'gravel'\n  | 'mud'\n  | 'grass'\n  // Tier 1 — stone & masonry\n  | 'sandstone'\n  | 'granite'\n  | 'slate'\n  // Tier 1 — organic\n  | 'bark'\n  | 'leather'\n  | 'canvas'\n  | 'parchment'\n  | 'terracotta'\n  | 'bone'\n  // Tier 1 — metals\n  | 'rust'\n  | 'bronze'\n  | 'brass'\n  // Tier 2 — masonry tiling\n  | 'brick'\n  | 'cobblestone'\n  | 'ashlar'\n  | 'floortile'\n  | 'shingle'\n  // Tier 3 — cap & glow\n  | 'snow'\n  | 'moss'\n  | 'lava'\n  | 'crystal'\n  // Tier 4 — modern & machined\n  | 'concrete'\n  | 'paint'\n  | 'marble'\n  | 'terrazzo'\n  | 'steel'\n  | 'chrome'\n  | 'paintedMetal'\n  | 'corten'\n  | 'teak'\n  | 'porcelain'\n  | 'glaze'\n  | 'mosaic'\n  | 'parquet'\n  | 'patternedTile'\n  // Tier 5 — industrial\n  | 'corrugatedIron'\n  | 'asphalt'\n  | 'diamondPlate'\n  | 'galvanised'\n  | 'copperPatina'\n  | 'basalt'\n  // Tier 6 — physical (MeshPhysicalMaterial; see `physical`)\n  | 'velvet'\n  | 'silk'\n  | 'brushedMetal'\n  | 'nacre'\n  | 'ice'\n  | 'gemstone';\n\nexport interface SurfaceParams {\n  /**\n   * Natural base colour for this kind (hex int). Used when the caller passes\n   * no `color`, so `createSurface('sand')` looks like sand out of the box.\n   * A caller's `color` always wins.\n   */\n  baseColor?: number;\n  /** PBR base roughness. */\n  roughness: number;\n  /** PBR metalness. */\n  metalness: number;\n  /** Noise frequency in world units (higher = finer grain). */\n  scale: number;\n  /** How strongly the fine noise lightens/darkens the albedo (0–1). */\n  albedoVar: number;\n  /** Secondary colour blended into cavities, as a hex int. */\n  tint: number;\n  /** How much of `tint` shows in cavities (0–1). */\n  tintAmount: number;\n  /** Low-frequency cavity darkening — the baked-AO look (0–1). */\n  ao: number;\n  /** Surface relief strength (normal perturbation from the noise). */\n  bump: number;\n  /** Roughness variation added from the noise (0–1). */\n  roughVar: number;\n  /** Anisotropic grain strength for wood-like surfaces (0 = none). */\n  grain: number;\n  /** Grain ring frequency. */\n  grainScale: number;\n  /** World axis the grain runs along. */\n  grainAxis: Vector3;\n  /** flatShading default for this kind. */\n  flat: boolean;\n\n  // --- masonry tiling (all optional; `tile: 0` — the default — disables it) ---\n  /** Tiling strength (0 off, 1 full). Turns on the brick/tile grid. */\n  tile?: number;\n  /** Cell width in world metres (the length of a brick/tile). */\n  tileW?: number;\n  /** Cell height in world metres (the course height). */\n  tileH?: number;\n  /** Mortar-joint width in world metres. */\n  mortar?: number;\n  /** Row offset: 0 = aligned grid, 1 = half-cell running bond. */\n  bond?: number;\n  /** Cell profile: 0 = flat tiles, 1 = domed cobbles. */\n  round?: number;\n  /** Per-cell brightness/roughness jitter (0–1), so no two read alike. */\n  tileJitter?: number;\n  /** Mortar-joint colour, as a hex int. */\n  mortarColor?: number;\n  /** Groove relief strength for the joints (normal perturbation). */\n  tileRelief?: number;\n  /** Fraction of cells painted solid `tint` (mosaic accent chips, 0–1). */\n  tileTint?: number;\n  /** 1 = shear alternate column bands ±45° — chevron/herringbone parquet. */\n  chevron?: number;\n  /** Per-cell ring + dot motif painted in `tint` (patterned cement tiles). */\n  motif?: number;\n\n  // --- snow / moss cap (settles on up-facing faces; `cap: 0` disables it) ---\n  /** Cap strength (0 off, 1 full) — snow, moss, dust on the tops. */\n  cap?: number;\n  /** Cap colour, as a hex int (white snow, green moss…). */\n  capColor?: number;\n  /** How up-facing a face must be before the cap takes (0 everywhere … 1 only dead-level tops). */\n  capUp?: number;\n  /** Softness of the cap edge (bigger = more gradual). */\n  capSharp?: number;\n  /** Roughness inside the capped area (fresh snow reads matte/bright). */\n  capRough?: number;\n\n  // --- physical: light responses MeshStandardMaterial cannot produce -----\n  /**\n   * Build a `MeshPhysicalMaterial` instead of a `MeshStandardMaterial`.\n   *\n   * Some surfaces are defined by a light response the standard model has no\n   * term for at all — the retroreflective rim of velvet, the stretched\n   * highlight on silk, the thin-film hue shift on a shell, light going\n   * THROUGH ice. None of those can be faked with albedo and roughness.\n   *\n   * It costs: a physical material is a bigger shader, and `transmission` in\n   * particular makes three render the scene a second time into a buffer. Use\n   * it on OBJECTS, not on facades — which is exactly why `createGlass` fakes\n   * its glass rather than transmitting it.\n   */\n  physical?: boolean;\n  /** Sheen strength — velvet, felt, wool. The rim IS the material. */\n  sheen?: number;\n  /** Sheen colour, as a hex int. */\n  sheenColor?: number;\n  /** Sheen roughness. */\n  sheenRough?: number;\n  /**\n   * Anisotropy strength: a stretched highlight instead of a round one.\n   * Silk, brushed metal, carbon fibre. NOTE it follows the geometry's UVs,\n   * so a mesh with no UV attribute will not show it.\n   */\n  anisotropy?: number;\n  /** Which way the grain runs, in radians. */\n  anisotropyRotation?: number;\n  /** Thin-film iridescence — nacre, beetle shell, oil on water. */\n  iridescence?: number;\n  /** Iridescent film IOR. */\n  iridescenceIOR?: number;\n  /** Film thickness range in nanometres, [min, max]. */\n  iridescenceThickness?: [number, number];\n  /** Transmission: light passing THROUGH. Expensive — see `physical`. */\n  transmission?: number;\n  /** How thick the volume is, for transmission. */\n  thickness?: number;\n  /** Index of refraction (water 1.33, ice 1.31, glass 1.5, diamond 2.42). */\n  ior?: number;\n  /**\n   * Chromatic dispersion: how far apart the red and blue refractions fall.\n   *\n   * A real transparent solid has a DIFFERENT index of refraction for every\n   * wavelength, which is why a cut stone throws colour and a window does not.\n   * three refracts red, green and blue separately over\n   * `ior ± (ior - 1) * 0.025 * dispersion`, so the spread grows with the IOR\n   * as well — 0 is a plain glass, 10 on a diamond-grade IOR is a gemstone.\n   *\n   * Needs `transmission` and a non-zero `thickness`: with nothing passing\n   * through the volume there is nothing to split. Costs a third transmission\n   * sample per pixel.\n   */\n  dispersion?: number;\n  /** Colour light picks up on its way through, as a hex int. */\n  attenuationColor?: number;\n  /** How far light travels before it is fully attenuated, in metres. */\n  attenuationDistance?: number;\n\n  // --- ribs: parallel ridges (opt-in; `ribs: 0` — the default — is flat) ---\n  /** Ridge relief strength (0 off). Corrugated sheet, fluting, tread plate. */\n  ribs?: number;\n  /** Ridges per world metre. */\n  ribScale?: number;\n  /**\n   * 1 = turn the ridges through 90° on the face. Ribs are laid out in the\n   * FACE's own plane, not along a world axis: two world axes that differ in\n   * space collapse onto the same direction once projected onto a wall, which\n   * turned a crossed tread plate back into plain stripes.\n   */\n  ribTurn?: number;\n  /** 1 = a second set crossed over the first: the diamond studs of tread plate. */\n  ribCross?: number;\n\n  // --- aggregate: hard-edged chips (opt-in; `speck: 0` — the default — off) ---\n  /**\n   * Chip contrast. The rest of the shader runs on smooth fbm, which reads as\n   * mottling; asphalt is STONES IN TAR, and stones have edges.\n   */\n  speck?: number;\n  /** Chips per world metre. */\n  speckScale?: number;\n\n  // --- cells: warped Voronoi (opt-in; `cells: 0` — the default — off) ---\n  /**\n   * Cell strength. Irregular polygons: the columnar jointing of basalt and\n   * the zinc spangle on galvanised steel are the same function at two very\n   * different scales.\n   */\n  cells?: number;\n  /** Cells per world metre. */\n  cellScale?: number;\n  /** How dark and deep the seams between cells run (0–1). */\n  cellEdge?: number;\n  /** Per-cell brightness jitter (0–1). */\n  cellJitter?: number;\n  /**\n   * 1 = lay the cells out in PLAN and extrude them vertically, whatever the\n   * face is pointing at. That is what columnar jointing is — a crazy paving\n   * seen from above, pulled up into columns — and projecting it per-face\n   * instead gives blotches on a wall rather than columns in a cliff.\n   */\n  cellPlan?: number;\n\n  // --- crust: a mineral layer (opt-in; `crust: 0` — the default — off) ---\n  /**\n   * How much crust has grown: verdigris on copper, a rust bloom, lichen.\n   * It takes in the cavities and on the up-facing side, and it is a CRUST,\n   * not a tint — wherever it takes hold the metalness goes with it, because\n   * a mineral scab does not reflect like the metal underneath.\n   */\n  crust?: number;\n  /** Crust colour, as a hex int (verdigris green, rust orange…). */\n  crustColor?: number;\n  /** Roughness inside the crust. */\n  crustRough?: number;\n\n  // --- wear: water (opt-in; `wet: 0` — the default — is bone dry) ---\n  /**\n   * How wet the surface is: 0 dry, 1 running with water.\n   *\n   * This is a STATE, not a kind. Every one of the presets above can be\n   * rained on, and water behaves the same way on all of them — it darkens\n   * the albedo, collapses the roughness to a film, and, most of all, it\n   * POOLS: at a light wetting only the hollows and the mortar joints are\n   * dark and glossy, and the face only sheets over when it is properly\n   * raining.\n   */\n  wet?: number;\n  /**\n   * How well water clings to vertical faces: 0 = only the tops ever get\n   * wet, 1 = a wall wets as fast as a floor. Default 0.55 — rain falls\n   * down, so a sill soaks while the wall under it is merely damp. Sealed,\n   * shedding surfaces (glass, glaze, chrome) want less; things that wick\n   * (plaster, concrete, canvas) want more.\n   */\n  wetCling?: number;\n\n  // --- emissive glow (opt-in; `glow: 0` — the default — keeps it dark) ---\n  /** Glow strength added straight to emissive radiance (lava, crystal, runes). */\n  glow?: number;\n  /** Glow colour, as a hex int. */\n  glowColor?: number;\n  /** How much of the surface glows: low = only the deep cracks, high = most of it. */\n  glowThreshold?: number;\n}\n\nconst V = (x: number, y: number, z: number): Vector3 => new Vector3(x, y, z);\n\nexport const SURFACE_PRESETS: Record<SurfaceKind, SurfaceParams> = {\n  // Lime-washed cottage walls: soft warm mottle, gentle relief.\n  plaster: {\n    baseColor: 0xd9ccb0,\n    roughness: 0.92, metalness: 0, scale: 3.4, albedoVar: 0.14, tint: 0x9c8f74,\n    tintAmount: 0.12, ao: 0.18, bump: 0.15, roughVar: 0.1, grain: 0,\n    grainScale: 1, grainAxis: V(0, 1, 0), flat: true,\n  },\n  // Rough weathered stone: strong cavity AO + mossy tint, pitted relief.\n  stone: {\n    baseColor: 0x8a8f98,\n    roughness: 0.96, metalness: 0, scale: 2.6, albedoVar: 0.26, tint: 0x5c6b44,\n    tintAmount: 0.16, ao: 0.34, bump: 0.42, roughVar: 0.14, grain: 0,\n    grainScale: 1, grainAxis: V(0, 1, 0), flat: true,\n  },\n  // Structural timber: pronounced grain rings darkening the albedo.\n  wood: {\n    baseColor: 0x8a6642,\n    roughness: 0.82, metalness: 0, scale: 5.5, albedoVar: 0.12, tint: 0x3a2a1c,\n    tintAmount: 0.14, ao: 0.16, bump: 0.12, roughVar: 0.12, grain: 0.55,\n    grainScale: 3.2, grainAxis: V(0, 1, 0), flat: true,\n  },\n  // Sawn planks: finer, straighter grain, a touch smoother.\n  plank: {\n    baseColor: 0x9a7a52,\n    roughness: 0.78, metalness: 0, scale: 6.5, albedoVar: 0.1, tint: 0x40301f,\n    tintAmount: 0.1, ao: 0.12, bump: 0.1, roughVar: 0.1, grain: 0.4,\n    grainScale: 5.0, grainAxis: V(1, 0, 0), flat: true,\n  },\n  // Straw thatch: busy fibrous streaking, high roughness, deep shadowing.\n  thatch: {\n    baseColor: 0xb39a5c,\n    roughness: 0.98, metalness: 0, scale: 9.0, albedoVar: 0.3, tint: 0x6a5324,\n    tintAmount: 0.2, ao: 0.28, bump: 0.3, roughVar: 0.08, grain: 0.35,\n    grainScale: 8.0, grainAxis: V(0, 0, 1), flat: true,\n  },\n  // Clay roof tiles: regular ridged rows, warm cavity tint.\n  tile: {\n    baseColor: 0xa8563e,\n    roughness: 0.7, metalness: 0, scale: 4.0, albedoVar: 0.14, tint: 0x6e2f22,\n    tintAmount: 0.16, ao: 0.24, bump: 0.34, roughVar: 0.1, grain: 0.6,\n    grainScale: 6.0, grainAxis: V(1, 0, 0), flat: true,\n  },\n  // Aged iron/bronze: mild mottle, low roughness variance, metallic.\n  metal: {\n    baseColor: 0x3d4451,\n    roughness: 0.52, metalness: 0.85, scale: 4.5, albedoVar: 0.16, tint: 0x2a2118,\n    tintAmount: 0.18, ao: 0.22, bump: 0.16, roughVar: 0.2, grain: 0,\n    grainScale: 1, grainAxis: V(0, 1, 0), flat: true,\n  },\n  // Turf. There is a `createGrass` prop for blades you can see individually;\n  // this is the ground they stand in, and the ground on its own from any\n  // distance. `moss` is NOT this — it is a grey-green cap that grows ON stone,\n  // and reaching for it as a lawn gives a field the colour of a damp wall.\n  // (Written after doing exactly that.)\n  grass: {\n    baseColor: 0x5c7a3c,\n    roughness: 0.97, metalness: 0, scale: 5.5, albedoVar: 0.26, tint: 0x33471f,\n    tintAmount: 0.24, ao: 0.24, bump: 0.22, roughVar: 0.08, grain: 0.22,\n    grainScale: 11.0, grainAxis: V(0, 0, 1), flat: true,\n  },\n  // Packed earth: broad soft variation, strong low-frequency patches.\n  dirt: {\n    baseColor: 0x8a7a58,\n    roughness: 1.0, metalness: 0, scale: 2.0, albedoVar: 0.22, tint: 0x4a3524,\n    tintAmount: 0.2, ao: 0.3, bump: 0.1, roughVar: 0.05, grain: 0,\n    grainScale: 1, grainAxis: V(0, 1, 0), flat: false,\n  },\n\n  // --- Tier 1: ground & terrain -----------------------------------------\n  // Fine granular sand with soft wind ripples; smooth-shaded dunes.\n  sand: {\n    baseColor: 0xcbb98a,\n    roughness: 1.0, metalness: 0, scale: 7.0, albedoVar: 0.16, tint: 0x9c8048,\n    tintAmount: 0.14, ao: 0.14, bump: 0.14, roughVar: 0.06, grain: 0.18,\n    grainScale: 3.0, grainAxis: V(1, 0, 0), flat: false,\n  },\n  // Loose gravel / riverbed: chunky faceted stones, strong relief.\n  gravel: {\n    baseColor: 0x9a948a,\n    roughness: 0.95, metalness: 0, scale: 5.5, albedoVar: 0.3, tint: 0x605a4f,\n    tintAmount: 0.18, ao: 0.32, bump: 0.5, roughVar: 0.16, grain: 0,\n    grainScale: 1, grainAxis: V(0, 1, 0), flat: true,\n  },\n  // Wet churned mud: darkened patches with a damp sheen (lower roughness).\n  mud: {\n    baseColor: 0x4a3826,\n    roughness: 0.6, metalness: 0, scale: 2.4, albedoVar: 0.2, tint: 0x241708,\n    tintAmount: 0.3, ao: 0.34, bump: 0.16, roughVar: 0.24, grain: 0,\n    grainScale: 1, grainAxis: V(0, 1, 0), flat: false,\n  },\n\n  // --- Tier 1: stone & masonry ------------------------------------------\n  // Warm sandstone: soft, faintly streaked, gentle relief — temples, cliffs.\n  sandstone: {\n    baseColor: 0xc9a06a,\n    roughness: 0.9, metalness: 0, scale: 3.4, albedoVar: 0.18, tint: 0x8a6a3c,\n    tintAmount: 0.16, ao: 0.22, bump: 0.24, roughVar: 0.1, grain: 0.22,\n    grainScale: 2.4, grainAxis: V(0, 1, 0), flat: true,\n  },\n  // Speckled granite: fine mineral fleck, low relief, a hint of polish.\n  granite: {\n    baseColor: 0x8e8a94,\n    roughness: 0.58, metalness: 0, scale: 9.0, albedoVar: 0.34, tint: 0x45414d,\n    tintAmount: 0.14, ao: 0.14, bump: 0.12, roughVar: 0.2, grain: 0,\n    grainScale: 1, grainAxis: V(0, 1, 0), flat: true,\n  },\n  // Dark slate: blue-grey cleavage plates, low roughness, subtle streaks.\n  slate: {\n    baseColor: 0x50565e,\n    roughness: 0.55, metalness: 0, scale: 3.0, albedoVar: 0.14, tint: 0x2c3540,\n    tintAmount: 0.2, ao: 0.2, bump: 0.18, roughVar: 0.12, grain: 0.2,\n    grainScale: 3.0, grainAxis: V(1, 0, 0), flat: true,\n  },\n\n  // --- Tier 1: organic --------------------------------------------------\n  // Tree bark: deep vertical ridges (grain rings around the trunk axis).\n  bark: {\n    baseColor: 0x5a4535,\n    roughness: 0.92, metalness: 0, scale: 6.0, albedoVar: 0.2, tint: 0x2a1c10,\n    tintAmount: 0.2, ao: 0.26, bump: 0.45, roughVar: 0.12, grain: 0.7,\n    grainScale: 5.5, grainAxis: V(0, 1, 0), flat: true,\n  },\n  // Leather / hide: soft mottled grain with a gentle sheen — straps, armour.\n  leather: {\n    baseColor: 0x6a4630,\n    roughness: 0.62, metalness: 0, scale: 5.0, albedoVar: 0.16, tint: 0x2e1a0f,\n    tintAmount: 0.22, ao: 0.2, bump: 0.18, roughVar: 0.12, grain: 0,\n    grainScale: 1, grainAxis: V(0, 1, 0), flat: false,\n  },\n  // Woven canvas: fine directional weave, matte — tents, sails, sacks.\n  canvas: {\n    baseColor: 0xcabd9c,\n    roughness: 0.95, metalness: 0, scale: 11.0, albedoVar: 0.14, tint: 0x8a7a5c,\n    tintAmount: 0.12, ao: 0.14, bump: 0.12, roughVar: 0.06, grain: 0.3,\n    grainScale: 12.0, grainAxis: V(1, 0, 0), flat: false,\n  },\n  // Aged parchment: near-white with soft foxing stains — signs, scrolls.\n  parchment: {\n    baseColor: 0xe0d4b0,\n    roughness: 0.9, metalness: 0, scale: 3.0, albedoVar: 0.12, tint: 0x9a8558,\n    tintAmount: 0.18, ao: 0.16, bump: 0.08, roughVar: 0.06, grain: 0,\n    grainScale: 1, grainAxis: V(0, 1, 0), flat: false,\n  },\n  // Unglazed terracotta: warm clay, smooth, low relief — pots, urns.\n  terracotta: {\n    baseColor: 0xb5623a,\n    roughness: 0.72, metalness: 0, scale: 4.0, albedoVar: 0.12, tint: 0x7a3a20,\n    tintAmount: 0.16, ao: 0.16, bump: 0.14, roughVar: 0.08, grain: 0,\n    grainScale: 1, grainAxis: V(0, 1, 0), flat: false,\n  },\n  // Weathered bone / ivory: off-white with cavity staining — ossuaries, décor.\n  bone: {\n    baseColor: 0xdcd2ba,\n    roughness: 0.55, metalness: 0, scale: 6.0, albedoVar: 0.14, tint: 0x8a7f66,\n    tintAmount: 0.2, ao: 0.22, bump: 0.12, roughVar: 0.1, grain: 0,\n    grainScale: 1, grainAxis: V(0, 1, 0), flat: true,\n  },\n\n  // --- Tier 1: metals ---------------------------------------------------\n  // Rusted iron: patchy orange corrosion, part-metallic, high roughness spread.\n  rust: {\n    baseColor: 0x8a4a2c,\n    roughness: 0.85, metalness: 0.25, scale: 4.0, albedoVar: 0.28, tint: 0x5a2a12,\n    tintAmount: 0.3, ao: 0.26, bump: 0.28, roughVar: 0.3, grain: 0,\n    grainScale: 1, grainAxis: V(0, 1, 0), flat: true,\n  },\n  // Bronze: warm dark metal with patina in the cavities — bells, statues.\n  bronze: {\n    baseColor: 0x9a6a3a,\n    roughness: 0.44, metalness: 0.9, scale: 4.5, albedoVar: 0.16, tint: 0x3a2410,\n    tintAmount: 0.24, ao: 0.22, bump: 0.16, roughVar: 0.18, grain: 0,\n    grainScale: 1, grainAxis: V(0, 1, 0), flat: true,\n  },\n  // Brass: brighter warm metal, smoother and shinier — fittings, instruments.\n  brass: {\n    baseColor: 0xc9a24a,\n    roughness: 0.34, metalness: 0.95, scale: 5.0, albedoVar: 0.12, tint: 0x6a4a12,\n    tintAmount: 0.16, ao: 0.16, bump: 0.1, roughVar: 0.14, grain: 0,\n    grainScale: 1, grainAxis: V(0, 1, 0), flat: true,\n  },\n\n  // --- Tier 2: masonry tiling -------------------------------------------\n  // Fired brick in running bond: long thin courses, pale mortar, bricks that\n  // each weather a little differently.\n  brick: {\n    baseColor: 0x9e4a34,\n    roughness: 0.86, metalness: 0, scale: 6.0, albedoVar: 0.14, tint: 0x5a2418,\n    tintAmount: 0.16, ao: 0.2, bump: 0.1, roughVar: 0.12, grain: 0,\n    grainScale: 1, grainAxis: V(0, 1, 0), flat: true,\n    tile: 1, tileW: 0.25, tileH: 0.085, mortar: 0.014, bond: 1, round: 0,\n    tileJitter: 0.18, mortarColor: 0xb3a892, tileRelief: 0.06,\n  },\n  // Rounded cobblestones: small domed setts, wide earthy joints, heavy\n  // per-stone variation — streets and courtyards.\n  cobblestone: {\n    baseColor: 0x8a8f98,\n    roughness: 0.9, metalness: 0, scale: 5.0, albedoVar: 0.2, tint: 0x4a4436,\n    tintAmount: 0.18, ao: 0.28, bump: 0.2, roughVar: 0.14, grain: 0,\n    grainScale: 1, grainAxis: V(0, 1, 0), flat: true,\n    tile: 1, tileW: 0.17, tileH: 0.15, mortar: 0.03, bond: 1, round: 1,\n    tileJitter: 0.24, mortarColor: 0x35322b, tileRelief: 0.13,\n  },\n  // Ashlar: large squared blocks, tight fine joints — castle and keep walls.\n  ashlar: {\n    baseColor: 0xb9b2a4,\n    roughness: 0.9, metalness: 0, scale: 3.0, albedoVar: 0.16, tint: 0x7a725f,\n    tintAmount: 0.16, ao: 0.2, bump: 0.12, roughVar: 0.1, grain: 0,\n    grainScale: 1, grainAxis: V(0, 1, 0), flat: true,\n    tile: 1, tileW: 0.55, tileH: 0.32, mortar: 0.02, bond: 0.5, round: 0,\n    tileJitter: 0.1, mortarColor: 0x857e6f, tileRelief: 0.05,\n  },\n  // Floor tiles: an aligned grid of square flags, dark grout, low relief —\n  // halls and plazas.\n  floortile: {\n    baseColor: 0x6a6e72,\n    roughness: 0.5, metalness: 0, scale: 4.0, albedoVar: 0.12, tint: 0x33363a,\n    tintAmount: 0.16, ao: 0.16, bump: 0.08, roughVar: 0.1, grain: 0,\n    grainScale: 1, grainAxis: V(0, 1, 0), flat: true,\n    tile: 1, tileW: 0.4, tileH: 0.4, mortar: 0.014, bond: 0, round: 0,\n    tileJitter: 0.12, mortarColor: 0x2a2a2c, tileRelief: 0.045,\n  },\n  // Wooden shingles: overlapping courses with grain, deep shadow lines —\n  // roofs and spires.\n  shingle: {\n    baseColor: 0x6b4a33,\n    roughness: 0.85, metalness: 0, scale: 6.0, albedoVar: 0.16, tint: 0x2e2012,\n    tintAmount: 0.18, ao: 0.24, bump: 0.12, roughVar: 0.12, grain: 0.32,\n    grainScale: 6.0, grainAxis: V(0, 1, 0), flat: true,\n    tile: 1, tileW: 0.2, tileH: 0.13, mortar: 0.012, bond: 1, round: 0,\n    tileJitter: 0.2, mortarColor: 0x241811, tileRelief: 0.09,\n  },\n\n  // --- Tier 3: cap & glow -----------------------------------------------\n  // Snow settled on cold rock: white on every up-facing face, grey stone on\n  // the sides, its edge broken by the noise. Cap works on any surface.\n  snow: {\n    baseColor: 0x9aa0a8,\n    roughness: 0.9, metalness: 0, scale: 4.0, albedoVar: 0.14, tint: 0x6a7280,\n    tintAmount: 0.14, ao: 0.2, bump: 0.24, roughVar: 0.1, grain: 0,\n    grainScale: 1, grainAxis: V(0, 1, 0), flat: true,\n    cap: 0.95, capColor: 0xf4f8fc, capUp: 0.12, capSharp: 0.32, capRough: 0.9,\n  },\n  // Moss creeping over a boulder: grey stone with green growth on the tops\n  // and shoulders, thicker (lower capUp) than snow.\n  moss: {\n    baseColor: 0x8a8f88,\n    roughness: 0.94, metalness: 0, scale: 3.5, albedoVar: 0.2, tint: 0x4a5240,\n    tintAmount: 0.16, ao: 0.28, bump: 0.34, roughVar: 0.12, grain: 0,\n    grainScale: 1, grainAxis: V(0, 1, 0), flat: true,\n    cap: 0.74, capColor: 0x40592a, capUp: 0.34, capSharp: 0.3, capRough: 0.96,\n  },\n  // Cooling lava: dark basalt crust with molten orange glowing up through the\n  // cracks. The glow burns constant, day or night.\n  lava: {\n    baseColor: 0x2a1712,\n    roughness: 0.88, metalness: 0, scale: 3.2, albedoVar: 0.18, tint: 0x120806,\n    tintAmount: 0.26, ao: 0.34, bump: 0.5, roughVar: 0.14, grain: 0,\n    grainScale: 1, grainAxis: V(0, 1, 0), flat: true,\n    glow: 2.6, glowColor: 0xff5a1e, glowThreshold: 0.3,\n  },\n  // Glowing crystal: faceted blue mineral lit from within — most of the face\n  // emits, the deepest cavities darkest.\n  crystal: {\n    baseColor: 0x3a5c8a,\n    roughness: 0.22, metalness: 0, scale: 5.0, albedoVar: 0.14, tint: 0x1a2f52,\n    tintAmount: 0.2, ao: 0.16, bump: 0.3, roughVar: 0.1, grain: 0,\n    grainScale: 1, grainAxis: V(0, 1, 0), flat: true,\n    glow: 1.5, glowColor: 0x6fd6ff, glowThreshold: 0.72,\n  },\n\n  // --- Tier 4: modern & machined ----------------------------------------\n  // Fair-faced concrete: near-even grey with fine mottle and shutter-panel\n  // joint lines (the tiling grid, dialed way down) — the modern wall.\n  concrete: {\n    baseColor: 0xb5b3ac,\n    roughness: 0.88, metalness: 0, scale: 3.0, albedoVar: 0.08, tint: 0x8a887f,\n    tintAmount: 0.08, ao: 0.12, bump: 0.06, roughVar: 0.08, grain: 0,\n    grainScale: 1, grainAxis: V(0, 1, 0), flat: false,\n    tile: 1, tileW: 1.2, tileH: 0.6, mortar: 0.006, bond: 0, round: 0,\n    tileJitter: 0.05, mortarColor: 0x9a9891, tileRelief: 0.03,\n  },\n  // Modern painted render: almost flat, just enough micro-variation to be a\n  // material at all. Colour it anything; satin sheen.\n  paint: {\n    baseColor: 0xdedbd2,\n    roughness: 0.6, metalness: 0, scale: 6.0, albedoVar: 0.04, tint: 0xb8b4a8,\n    tintAmount: 0.05, ao: 0.05, bump: 0.02, roughVar: 0.05, grain: 0,\n    grainScale: 1, grainAxis: V(0, 1, 0), flat: false,\n  },\n  // Polished marble: near-white slab, dark warped veins (the grain rings at a\n  // very low frequency), glossy — lobby floors and counters.\n  marble: {\n    baseColor: 0xe8e6e0,\n    roughness: 0.22, metalness: 0, scale: 1.6, albedoVar: 0.08, tint: 0x7a8494,\n    tintAmount: 0.12, ao: 0.08, bump: 0.04, roughVar: 0.08, grain: 0.5,\n    grainScale: 0.7, grainAxis: V(0.35, 1, 0.2), flat: false,\n  },\n  // Terrazzo: a cement field packed with tiny per-cell chips, a share of them\n  // in the accent tint — the classic speckled floor.\n  terrazzo: {\n    baseColor: 0xd8d2c6,\n    roughness: 0.35, metalness: 0, scale: 10.0, albedoVar: 0.1, tint: 0x6a604f,\n    tintAmount: 0.04, ao: 0.06, bump: 0.03, roughVar: 0.08, grain: 0,\n    grainScale: 1, grainAxis: V(0, 1, 0), flat: false,\n    tile: 1, tileW: 0.045, tileH: 0.045, mortar: 0.01, bond: 0, round: 1,\n    tileJitter: 0.35, mortarColor: 0xcfc9bd, tileRelief: 0.02, tileTint: 0.18,\n  },\n  // Brushed stainless steel: fine directional streaks (the grain machinery\n  // pointed at metal), cool and semi-gloss — railings, kick plates.\n  steel: {\n    baseColor: 0xaeb4bc,\n    roughness: 0.38, metalness: 0.92, scale: 8.0, albedoVar: 0.06, tint: 0x6a707a,\n    tintAmount: 0.08, ao: 0.06, bump: 0.03, roughVar: 0.18, grain: 0.3,\n    grainScale: 26.0, grainAxis: V(1, 0, 0), flat: false,\n  },\n  // Chrome: near-mirror metal — fittings and trim. (Stylized: no envmap, the\n  // lighting rig does the selling.)\n  chrome: {\n    baseColor: 0xc9ced4,\n    roughness: 0.08, metalness: 1.0, scale: 5.0, albedoVar: 0.04, tint: 0x8a9098,\n    tintAmount: 0.05, ao: 0.04, bump: 0.01, roughVar: 0.05, grain: 0,\n    grainScale: 1, grainAxis: V(0, 1, 0), flat: false,\n  },\n  // Powder-coated metal: coloured semi-gloss with a whisper of orange peel —\n  // gates, frames, railings. Colour it from the palette.\n  paintedMetal: {\n    baseColor: 0x44505c,\n    roughness: 0.42, metalness: 0.35, scale: 14.0, albedoVar: 0.04, tint: 0x222a30,\n    tintAmount: 0.06, ao: 0.06, bump: 0.04, roughVar: 0.08, grain: 0,\n    grainScale: 1, grainAxis: V(0, 1, 0), flat: false,\n  },\n  // Corten weathering steel: the even architectural oxide bloom, warmer and\n  // calmer than 'rust' — feature walls and planters.\n  corten: {\n    baseColor: 0x9a5a34,\n    roughness: 0.82, metalness: 0.18, scale: 3.2, albedoVar: 0.16, tint: 0x5a2e16,\n    tintAmount: 0.22, ao: 0.16, bump: 0.1, roughVar: 0.18, grain: 0,\n    grainScale: 1, grainAxis: V(0, 1, 0), flat: false,\n  },\n  // Oiled teak: warm decking/furniture wood under a varnish sheen.\n  teak: {\n    baseColor: 0x8a5c36,\n    roughness: 0.3, metalness: 0, scale: 6.0, albedoVar: 0.08, tint: 0x3c2614,\n    tintAmount: 0.12, ao: 0.1, bump: 0.05, roughVar: 0.08, grain: 0.45,\n    grainScale: 4.5, grainAxis: V(1, 0, 0), flat: false,\n  },\n  // Large-format porcelain: big glossy slabs, hairline grout, offset courses.\n  porcelain: {\n    baseColor: 0xd9d6cf,\n    roughness: 0.18, metalness: 0, scale: 3.0, albedoVar: 0.05, tint: 0x9a968c,\n    tintAmount: 0.06, ao: 0.08, bump: 0.03, roughVar: 0.06, grain: 0,\n    grainScale: 1, grainAxis: V(0, 1, 0), flat: false,\n    tile: 1, tileW: 1.2, tileH: 0.6, mortar: 0.005, bond: 0.5, round: 0,\n    tileJitter: 0.06, mortarColor: 0xb0aca2, tileRelief: 0.03,\n  },\n  // Vitreous glaze: sanitaryware. Note it is NOT 'porcelain' — that preset is\n  // large-format porcelain FLOOR TILE, complete with grout, and a bath shell\n  // built from it comes out looking like a tiled box rather than one fired\n  // piece. Glaze is a single unbroken skin: glossy, almost no variation, and\n  // no tiling at all.\n  glaze: {\n    baseColor: 0xf2f0ea,\n    roughness: 0.12, metalness: 0, scale: 5.0, albedoVar: 0.02, tint: 0xc8c6be,\n    tintAmount: 0.05, ao: 0.07, bump: 0.008, roughVar: 0.03, grain: 0,\n    grainScale: 1, grainAxis: V(0, 1, 0), flat: false,\n  },\n  // Glass mosaic: tiny gridded tesserae, strong per-chip variation, a share of\n  // accent-tint chips, pale grout — pools and feature walls.\n  mosaic: {\n    baseColor: 0x3f7fae,\n    roughness: 0.25, metalness: 0, scale: 8.0, albedoVar: 0.08, tint: 0x1d4e74,\n    tintAmount: 0.05, ao: 0.08, bump: 0.04, roughVar: 0.1, grain: 0,\n    grainScale: 1, grainAxis: V(0, 1, 0), flat: false,\n    tile: 1, tileW: 0.055, tileH: 0.055, mortar: 0.006, bond: 0, round: 0,\n    tileJitter: 0.3, mortarColor: 0xd8d4c8, tileRelief: 0.05, tileTint: 0.3,\n  },\n  // Chevron parquet: narrow varnished planks laid in alternating ±45° bands.\n  parquet: {\n    baseColor: 0x9a6b40,\n    roughness: 0.32, metalness: 0, scale: 6.0, albedoVar: 0.07, tint: 0x4a2f18,\n    tintAmount: 0.1, ao: 0.08, bump: 0.04, roughVar: 0.08, grain: 0.3,\n    grainScale: 7.0, grainAxis: V(1, 0, 0), flat: false,\n    tile: 1, tileW: 0.5, tileH: 0.09, mortar: 0.006, bond: 0, round: 0,\n    tileJitter: 0.14, mortarColor: 0x5a3b22, tileRelief: 0.04, chevron: 1,\n  },\n  // Patterned cement tiles: a cream field, each tile stamped with a ring-and-\n  // dot motif in the tint colour — verandas, courtyards, feature floors.\n  patternedTile: {\n    baseColor: 0xdcd7c9,\n    roughness: 0.3, metalness: 0, scale: 3.0, albedoVar: 0.05, tint: 0x365f74,\n    tintAmount: 0.04, ao: 0.08, bump: 0.03, roughVar: 0.06, grain: 0,\n    grainScale: 1, grainAxis: V(0, 1, 0), flat: false,\n    tile: 1, tileW: 0.33, tileH: 0.33, mortar: 0.008, bond: 0, round: 0,\n    tileJitter: 0.05, mortarColor: 0xa9a396, tileRelief: 0.035, motif: 0.9,\n  },\n\n  // --- Tier 5: industrial ------------------------------------------------\n  // Sheet steel rolled into a wave, galvanised, and left out in the rain.\n  // The corrugation is the ONLY reason a flat plane reads as a roof from\n  // fifty metres, and it is why this is the most recognisable industrial\n  // material there is: a shanty wall, a barn, a lock-up, a site hoarding.\n  corrugatedIron: {\n    baseColor: 0x9aa2a6,\n    roughness: 0.58, metalness: 0.5, scale: 9, albedoVar: 0.1, tint: 0x6a5545,\n    tintAmount: 0.16, ao: 0.16, bump: 0.35, roughVar: 0.18, grain: 0,\n    grainScale: 1, grainAxis: V(0, 1, 0), flat: false,\n    ribs: 1, ribScale: 5,\n    // Rust takes in the valleys, where the water sits — but a sheet that is\n    // more rust than iron reads as rust, not as a roof.\n    crust: 0.3, crustColor: 0x8a4a26, crustRough: 0.95,\n  },\n  // Stones in tar. The chips are the point: a smooth mottle is mud, and\n  // the reason a road reads as a road at all is that it is visibly made of\n  // gravel somebody poured glue over.\n  asphalt: {\n    baseColor: 0x3b3b3e,\n    roughness: 0.93, metalness: 0, scale: 14, albedoVar: 0.1, tint: 0x1e1e20,\n    tintAmount: 0.18, ao: 0.2, bump: 0.4, roughVar: 0.1, grain: 0,\n    grainScale: 1, grainAxis: V(0, 1, 0), flat: false,\n    speck: 0.42, speckScale: 40,\n  },\n  // Tread plate: raised studs in a diamond lattice, so a gantry floor has\n  // grip and a stair tread reads as a stair tread.\n  diamondPlate: {\n    baseColor: 0x8d9399,\n    roughness: 0.44, metalness: 0.55, scale: 12, albedoVar: 0.05, tint: 0x5c6166,\n    tintAmount: 0.1, ao: 0.1, bump: 0.5, roughVar: 0.1, grain: 0,\n    grainScale: 1, grainAxis: V(0, 1, 0), flat: false,\n    ribs: 1, ribScale: 6, ribCross: 1,\n  },\n  // THE SPANGLE is the whole material: hot-dip galvanising freezes into\n  // visible zinc crystals, each catching the light its own way, and no\n  // other metal has that.\n  galvanised: {\n    baseColor: 0xa9b1b5,\n    roughness: 0.46, metalness: 0.5, scale: 3.5, albedoVar: 0.04, tint: 0x7d868b,\n    tintAmount: 0.06, ao: 0.05, bump: 0.1, roughVar: 0.05, grain: 0,\n    grainScale: 1, grainAxis: V(0, 1, 0), flat: false,\n    // Grains you can SEE, each catching the light its own way. Real spangle\n    // is millimetres, but a crystal too small to resolve is not a crystal —\n    // it is per-pixel noise, and on a metal that is a sparkling mess.\n    cells: 1, cellScale: 6, cellEdge: 0.22, cellJitter: 0.4,\n  },\n  // Copper does not stay copper. Verdigris grows in the cavities and on\n  // the up-facing side, and where it grows the metal is gone — which is\n  // why a green roof is matte and a copper one is not.\n  copperPatina: {\n    baseColor: 0x9c5b34,\n    roughness: 0.42, metalness: 0.75, scale: 6, albedoVar: 0.08, tint: 0x6b3a1f,\n    tintAmount: 0.12, ao: 0.14, bump: 0.2, roughVar: 0.12, grain: 0,\n    grainScale: 1, grainAxis: V(0, 1, 0), flat: false,\n    crust: 0.95, crustColor: 0x4fa88a, crustRough: 0.92,\n  },\n  // Columnar jointing: lava that cooled slowly and cracked into polygons,\n  // then stood up as columns. Laid out in PLAN and extruded, because that\n  // is what the rock actually did.\n  basalt: {\n    baseColor: 0x54585e,\n    roughness: 0.86, metalness: 0.04, scale: 3, albedoVar: 0.06, tint: 0x2b2e33,\n    tintAmount: 0.12, ao: 0.16, bump: 0.5, roughVar: 0.1, grain: 0,\n    grainScale: 1, grainAxis: V(0, 1, 0), flat: true,\n    cells: 1, cellScale: 3.2, cellEdge: 0.85, cellJitter: 0.16, cellPlan: 1,\n  },\n\n  // --- Tier 6: physical --------------------------------------------------\n  // Each of these is defined by a light response the standard model has no\n  // term for. They are the one part of the catalogue that costs more than a\n  // MeshStandardMaterial, and they are worth it only because nothing else\n  // gets you there.\n\n  // THE RIM IS THE MATERIAL. Velvet is dark where you look straight at it\n  // and bright at every grazing edge, because the pile scatters sideways —\n  // and no amount of albedo and roughness produces that.\n  velvet: {\n    baseColor: 0x6d1730,\n    roughness: 0.92, metalness: 0, scale: 7, albedoVar: 0.05, tint: 0x3a0a19,\n    tintAmount: 0.14, ao: 0.12, bump: 0.015, roughVar: 0.03, grain: 0,\n    grainScale: 1, grainAxis: V(0, 1, 0), flat: false,\n    physical: true, sheen: 1, sheenColor: 0xd8869c, sheenRough: 0.32,\n  },\n  // A stretched highlight instead of a round one: the thread runs one way,\n  // so the light does too.\n  silk: {\n    baseColor: 0xc9b7d8,\n    roughness: 0.2, metalness: 0.05, scale: 6, albedoVar: 0.04, tint: 0x8f7fa6,\n    tintAmount: 0.08, ao: 0.06, bump: 0.01, roughVar: 0.02, grain: 0,\n    grainScale: 1, grainAxis: V(0, 1, 0), flat: false,\n    physical: true, anisotropy: 0.9, anisotropyRotation: 0,\n    sheen: 0.35, sheenColor: 0xffffff, sheenRough: 0.2,\n  },\n  // The linisher went one way. Brushed aluminium, a kitchen front, a lift\n  // door — the streak is the only thing separating it from plain steel.\n  brushedMetal: {\n    baseColor: 0xb4b9be,\n    roughness: 0.34, metalness: 0.7, scale: 5, albedoVar: 0.02, tint: 0x8b9196,\n    tintAmount: 0.04, ao: 0.03, bump: 0.008, roughVar: 0.02, grain: 0,\n    grainScale: 1, grainAxis: V(0, 1, 0), flat: false,\n    physical: true, anisotropy: 0.95, anisotropyRotation: Math.PI / 2,\n  },\n  // Thin-film interference: the hue depends on how thick the film is and\n  // which way you are looking, which is why a shell has no fixed colour.\n  nacre: {\n    baseColor: 0xdcd8d0,\n    roughness: 0.12, metalness: 0.2, scale: 4, albedoVar: 0.04, tint: 0xa8b0c0,\n    tintAmount: 0.18, ao: 0.05, bump: 0.02, roughVar: 0.02, grain: 0,\n    grainScale: 1, grainAxis: V(0, 1, 0), flat: false,\n    // Low metalness on purpose. Iridescence is strongest over a metallic\n    // F0, but a metal with no environment map to reflect renders as dead\n    // grey — so the film sits over a pale pearl instead, and a thick one\n    // (a high IOR) makes the highlight visibly COLOURED rather than white.\n    physical: true, iridescence: 1, iridescenceIOR: 2.4,\n    iridescenceThickness: [300, 900],\n  },\n  // Light goes THROUGH. The cells are the fracture planes inside it — ice\n  // is not clear, it is full of the cracks it froze around.\n  ice: {\n    baseColor: 0xcfe8f2,\n    roughness: 0.13, metalness: 0, scale: 2.5, albedoVar: 0.05, tint: 0x7fb4cc,\n    tintAmount: 0.14, ao: 0.08, bump: 0.06, roughVar: 0.03, grain: 0,\n    grainScale: 1, grainAxis: V(0, 1, 0), flat: false,\n    cells: 1, cellScale: 1.8, cellEdge: 0.22, cellJitter: 0.08,\n    physical: true, transmission: 0.85, thickness: 0.5, ior: 1.31,\n    attenuationColor: 0x9fd4e8, attenuationDistance: 1.4,\n  },\n  // WHY A STONE IS CUT AT ALL. Glass and diamond are both transparent; the\n  // difference you can see across a room is that diamond has a different\n  // index of refraction for every wavelength, so the white light that goes\n  // in comes out separated. Facets exist to make that happen more often.\n  //\n  // Both halves of that are here. `dispersion` does the splitting — and the\n  // spread scales with the IOR, so a gem-grade 2.2 throws far more colour\n  // than a window's 1.5 at the same setting. `flat: true` does the facets:\n  // flat shading on a low-poly solid IS a cut stone, and the coarse cells\n  // are the inclusions that stop it looking like moulded acrylic.\n  gemstone: {\n    baseColor: 0xe6f4ff,\n    roughness: 0.03, metalness: 0, scale: 3.5, albedoVar: 0.03, tint: 0x8fc2e8,\n    tintAmount: 0.08, ao: 0.02, bump: 0, roughVar: 0.015, grain: 0,\n    grainScale: 1, grainAxis: V(0, 1, 0), flat: true,\n    cells: 0.5, cellScale: 2.2, cellEdge: 0.12, cellJitter: 0.25,\n    // A long attenuation distance on purpose. The colour is supposed to come\n    // OUT of the stone, and one that swallows the light on its way through\n    // is a dark blob whatever the IOR is doing.\n    physical: true, transmission: 1, thickness: 0.55, ior: 2.2, dispersion: 14,\n    attenuationColor: 0xb8e4ff, attenuationDistance: 2.4,\n  },\n};\n\nexport interface SurfaceOptions extends Partial<SurfaceParams> {\n  /** Base colour (hex int or three Color). Defaults to a neutral grey. */\n  color?: number | Color;\n  /**\n   * Seed offset so two props with the same colour still weather\n   * differently. Any number; shifts the noise field.\n   */\n  seed?: number;\n}\n\n// ---- GLSL --------------------------------------------------------------\n\nconst NOISE_GLSL = /* glsl */ `\n// World-space coordinates get large (props far from the origin, plus the seed\n// offset), and mobile GPUs default the fragment stage to mediump — where\n// fract() of a big number loses precision and the noise/grain visibly swims.\n// Force highp on the world varyings and the noise maths so it stays put.\nvarying highp vec3 vSurfWorldPos;\nvarying highp vec3 vSurfWorldNormal;\nuniform highp vec3 uSurfSeed;\nuniform float uSurfScale;\nuniform float uSurfAlbedoVar;\nuniform vec3  uSurfTint;\nuniform float uSurfTintAmount;\nuniform float uSurfAO;\nuniform float uSurfBump;\nuniform float uSurfRoughVar;\nuniform float uSurfGrain;\nuniform float uSurfGrainScale;\nuniform vec3  uSurfGrainAxis;\nuniform float uSurfTile;\nuniform highp vec2 uSurfTileSize;\nuniform float uSurfMortar;\nuniform float uSurfTileBond;\nuniform float uSurfTileRound;\nuniform float uSurfTileJitter;\nuniform vec3  uSurfMortarColor;\nuniform float uSurfTileRelief;\nuniform float uSurfTileTint;\nuniform float uSurfTileChevron;\nuniform float uSurfTileMotif;\nuniform float uSurfCap;\nuniform vec3  uSurfCapColor;\nuniform float uSurfCapUp;\nuniform float uSurfCapSharp;\nuniform float uSurfCapRough;\nuniform float uSurfGlow;\nuniform vec3  uSurfGlowColor;\nuniform float uSurfGlowThresh;\nuniform float uSurfWet;\nuniform float uSurfWetCling;\nuniform float uSurfRibs;\nuniform float uSurfRibScale;\nuniform float uSurfRibTurn;\nuniform float uSurfRibCross;\nuniform float uSurfSpeck;\nuniform float uSurfSpeckScale;\nuniform float uSurfCells;\nuniform float uSurfCellScale;\nuniform float uSurfCellEdge;\nuniform float uSurfCellJitter;\nuniform float uSurfCellPlan;\nuniform float uSurfCrust;\nuniform vec3  uSurfCrustColor;\nuniform float uSurfCrustRough;\n\nfloat scenaHash13(highp vec3 p){\n  p = fract(p * 0.1031);\n  p += dot(p, p.yzx + 33.33);\n  return fract((p.x + p.y) * p.z);\n}\nfloat scenaVNoise(highp vec3 x){\n  highp vec3 i = floor(x); highp vec3 f = fract(x);\n  f = f * f * (3.0 - 2.0 * f);\n  float n000 = scenaHash13(i + vec3(0.0,0.0,0.0));\n  float n100 = scenaHash13(i + vec3(1.0,0.0,0.0));\n  float n010 = scenaHash13(i + vec3(0.0,1.0,0.0));\n  float n110 = scenaHash13(i + vec3(1.0,1.0,0.0));\n  float n001 = scenaHash13(i + vec3(0.0,0.0,1.0));\n  float n101 = scenaHash13(i + vec3(1.0,0.0,1.0));\n  float n011 = scenaHash13(i + vec3(0.0,1.0,1.0));\n  float n111 = scenaHash13(i + vec3(1.0,1.0,1.0));\n  return mix(mix(mix(n000,n100,f.x), mix(n010,n110,f.x), f.y),\n             mix(mix(n001,n101,f.x), mix(n011,n111,f.x), f.y), f.z);\n}\nfloat scenaFbm(highp vec3 p){\n  float a = 0.5, s = 0.0;\n  for (int i = 0; i < 4; i++){ s += a * scenaVNoise(p); p *= 2.02; a *= 0.5; }\n  return s;\n}\n// Triplanar fbm: blend three axis-projected samples by the world normal, so\n// box faces need no UVs and adjacent boxes share one continuous field.\nfloat scenaTri(highp vec3 wp, vec3 wn, float scale){\n  highp vec3 p = wp * scale + uSurfSeed;\n  vec3 w = abs(normalize(wn)); w = pow(w, vec3(4.0)); w /= (w.x + w.y + w.z + 1e-4);\n  return scenaFbm(p.yzx) * w.x + scenaFbm(p.zxy) * w.y + scenaFbm(p.xyz) * w.z;\n}\n// Concentric grain rings around the grain axis, warped by noise.\nfloat scenaGrain(highp vec3 wp){\n  highp vec3 ax = normalize(uSurfGrainAxis);\n  highp float along = dot(wp, ax);\n  highp vec3 perp = wp - ax * along;\n  highp float rings = length(perp) * uSurfGrainScale + scenaFbm(wp * uSurfGrainScale * 0.4) * 2.0;\n  return abs(fract(rings) - 0.5) * 2.0; // triangle wave 0..1\n}\n// A masonry grid on the dominant-axis face (so box walls/floors/roofs get a\n// clean 2D pattern and abutting boxes align). Running-bond rows, mortar bands\n// and per-cell jitter. Returns: x = mortar mask (1 in the joint), y = per-cell\n// hash (0..1), z = surface height (tile face high → joint low), w = the domed\n// stone height for cobbles.\nvec4 scenaTile(highp vec3 wp, vec3 wn){\n  vec3 an = abs(normalize(wn));\n  highp vec2 uv;\n  if (an.x >= an.y && an.x >= an.z) uv = wp.zy;\n  else if (an.y >= an.x && an.y >= an.z) uv = wp.xz;\n  else uv = wp.xy;\n  uv += uSurfSeed.xy;\n  highp vec2 ts = max(uSurfTileSize, vec2(1e-3));\n  // Chevron parquet: shear alternate column bands ±45° (about each band's own\n  // centre, so the offset stays small and mediump-safe far from the origin).\n  if (uSurfTileChevron > 0.5) {\n    highp float band = floor(uv.x / ts.x);\n    highp float local = uv.x - (band + 0.5) * ts.x;\n    uv.y += (mod(band, 2.0) * 2.0 - 1.0) * local;\n  }\n  highp float row = floor(uv.y / ts.y);\n  highp float bond = mod(row, 2.0) * uSurfTileBond * 0.5;\n  highp float cxf = uv.x / ts.x + bond;\n  highp float col = floor(cxf);\n  highp vec2 cell = vec2(col, row);\n  highp float fx = fract(cxf);\n  highp float fy = fract(uv.y / ts.y);\n  // Distance to the nearest cell edge, in world units → mortar band.\n  float ex = min(fx, 1.0 - fx) * ts.x;\n  float ey = min(fy, 1.0 - fy) * ts.y;\n  float edge = min(ex, ey);\n  float m = max(uSurfMortar, 1e-4);\n  float mortar = 1.0 - smoothstep(m, m * 1.7, edge);\n  // Domed profile for cobbles: peaks at the cell centre, falls to the joint.\n  float dome = clamp(1.0 - length(vec2(fx - 0.5, fy - 0.5)) * 2.0, 0.0, 1.0);\n  float flatH = 1.0 - mortar;\n  float height = mix(flatH, dome * (1.0 - mortar), uSurfTileRound);\n  float h = scenaHash13(vec3(cell + vec2(3.1, 7.3), 5.0));\n  return vec4(mortar, h, height, dome);\n}\n// Snow / moss cap: settles on up-facing surfaces, its edge broken up by the\n// noise the shader already sampled (no extra noise cost). Returns 0..1.\nfloat scenaCapMask(vec3 wn, float breakup){\n  float up = normalize(wn).y * 0.5 + 0.5;      // 0 (down) .. 1 (up)\n  float s = max(uSurfCapSharp, 1e-3);\n  return clamp(smoothstep(uSurfCapUp - s, uSurfCapUp + s, up + (breakup - 0.5) * 0.6), 0.0, 1.0);\n}\n// Parallel ridges along an axis — a corrugated sheet. Crossed with a second\n// set, the two lattices intersect in isolated studs: tread plate.\nfloat scenaRibs(highp vec3 wp, vec3 wn){\n  if (uSurfRibs <= 0.0) return 0.0;\n  // In the FACE's own plane, like the masonry grid. A world axis is no use\n  // here: on a wall, two different world axes project onto the same\n  // direction, which turns a crossed tread plate back into plain stripes.\n  vec3 an = abs(normalize(wn));\n  highp vec2 uv;\n  if (an.x >= an.y && an.x >= an.z) uv = wp.zy;\n  else if (an.y >= an.x && an.y >= an.z) uv = wp.xz;\n  else uv = wp.xy;\n  uv = (uSurfRibTurn > 0.5 ? uv.yx : uv) * uSurfRibScale;\n  float r = abs(fract(uv.x) - 0.5) * 2.0;\n  if (uSurfRibCross > 0.5) {\n    // Two sets at ±45° IN THAT PLANE. MIN, not max: crossed ridges are high\n    // together only where they actually cross, and that is a field of studs\n    // rather than a waffle grid.\n    highp vec2 d = vec2(uv.x + uv.y, uv.x - uv.y) * 0.7071;\n    r = min(abs(fract(d.x) - 0.5), abs(fract(d.y) - 0.5)) * 2.0;\n  }\n  return r * r * (3.0 - 2.0 * r);   // round the triangle off\n}\n// Aggregate. Everything else in this shader runs on smooth fbm, which reads\n// as mottling; asphalt is STONES IN TAR, and stones have edges.\nfloat scenaSpeck(highp vec3 wp){\n  if (uSurfSpeck <= 0.0) return 0.5;\n  return scenaHash13(floor(wp * uSurfSpeckScale + uSurfSeed));\n}\n// Warped Voronoi. Returns x = per-cell hash, y = distance to the nearest\n// seam (0 on it). Basalt's columnar jointing and the zinc spangle on\n// galvanised steel are this one function two orders of magnitude apart.\nvec2 scenaCells(highp vec3 wp, vec3 wn){\n  if (uSurfCells <= 0.0) return vec2(0.5, 1.0);\n  highp vec2 uv;\n  if (uSurfCellPlan > 0.5) {\n    // Columnar jointing is a crazy paving seen from ABOVE, pulled up into\n    // columns — so it is laid out in plan whatever the face is pointing at.\n    uv = wp.xz;\n  } else {\n    vec3 an = abs(normalize(wn));\n    if (an.x >= an.y && an.x >= an.z) uv = wp.zy;\n    else if (an.y >= an.x && an.y >= an.z) uv = wp.xz;\n    else uv = wp.xy;\n  }\n  uv = uv * uSurfCellScale + uSurfSeed.xy;\n  highp vec2 g = floor(uv);\n  highp vec2 f = uv - g;\n  float d1 = 8.0, d2 = 8.0, id = 0.5;\n  for (int j = -1; j <= 1; j++) {\n    for (int i = -1; i <= 1; i++) {\n      vec2 o = vec2(float(i), float(j));\n      float h = scenaHash13(vec3(g + o, 11.0));\n      vec2 seed = o + vec2(h, fract(h * 37.31));\n      float d = length(seed - f);\n      if (d < d1) { d2 = d1; d1 = d; id = h; }\n      else if (d < d2) { d2 = d; }\n    }\n  }\n  // d2 - d1 is 0 exactly on the boundary between two cells and grows inward,\n  // which is a seam that does not care how big the cells are.\n  return vec2(id, clamp(d2 - d1, 0.0, 1.0));\n}\n// A mineral crust — verdigris, a rust bloom, lichen — taking hold in the\n// cavities and on the up-facing side.\nfloat scenaCrustMask(vec3 wn, float low){\n  if (uSurfCrust <= 0.0) return 0.0;\n  float up = normalize(wn).y * 0.5 + 0.5;\n  return clamp(smoothstep(0.66, 0.28, low) * uSurfCrust * mix(0.5, 1.0, up), 0.0, 1.0);\n}\n// WATER FILLS FROM THE BOTTOM. Wetness is a LEVEL, not a multiply: every\n// point has a height (the surface's own low-frequency band, with the\n// mortar joints counted as the lowest ground there is), and it is wet when\n// the level is above it. That is what makes a light shower read as dark\n// glossy lines in the joints and hollows while the faces stay dry, and a\n// downpour sheet the whole wall — from one scalar.\n//\n// The level is lower on a vertical face than a horizontal one, because\n// rain falls down: a sill soaks while the wall beneath it is merely damp.\nfloat scenaWetMask(vec3 wn, float low, float mortar){\n  if (uSurfWet <= 0.0) return 0.0;\n  float up = normalize(wn).y * 0.5 + 0.5;\n  float level = uSurfWet * mix(clamp(uSurfWetCling, 0.0, 1.0), 1.0, up) * 1.4 - 0.2;\n  float height = min(low, 1.0 - mortar);\n  return clamp(smoothstep(height - 0.2, height + 0.2, level), 0.0, 1.0);\n}\n`;\n\nfunction vertexPatch(src: string): string {\n  return src\n    .replace(\n      '#include <common>',\n      '#include <common>\\nvarying highp vec3 vSurfWorldPos;\\nvarying highp vec3 vSurfWorldNormal;'\n    )\n    .replace(\n      '#include <begin_vertex>',\n      `#include <begin_vertex>\n      {\n        vec4 scenaWP = modelMatrix * vec4(transformed, 1.0);\n        #ifdef USE_INSTANCING\n          scenaWP = modelMatrix * instanceMatrix * vec4(transformed, 1.0);\n        #endif\n        vSurfWorldPos = scenaWP.xyz;\n      }`\n    )\n    .replace(\n      '#include <beginnormal_vertex>',\n      `#include <beginnormal_vertex>\n      {\n        vec3 scenaON = objectNormal;\n        #ifdef USE_INSTANCING\n          scenaON = mat3(instanceMatrix) * scenaON;\n        #endif\n        vSurfWorldNormal = normalize(mat3(modelMatrix) * scenaON);\n      }`\n    );\n}\n\nfunction fragmentPatch(src: string): string {\n  return src\n    .replace('#include <common>', '#include <common>\\n' + NOISE_GLSL)\n    .replace(\n      '#include <map_fragment>',\n      `#include <map_fragment>\n      float scenaN   = scenaTri(vSurfWorldPos, vSurfWorldNormal, uSurfScale);\n      float scenaLow = scenaTri(vSurfWorldPos, vSurfWorldNormal, uSurfScale * 0.25);\n      float scenaG   = scenaGrain(vSurfWorldPos);\n      float scenaRib = scenaRibs(vSurfWorldPos, vSurfWorldNormal);\n      float scenaSp  = scenaSpeck(vSurfWorldPos);\n      vec2  scenaC   = scenaCells(vSurfWorldPos, vSurfWorldNormal);\n      // Seam mask: 1 on the join between two cells, 0 inside one.\n      float scenaSeam = (1.0 - smoothstep(0.0, 0.085, scenaC.y)) * uSurfCells;\n      // masonry grid (no-op when uSurfTile == 0)\n      vec4  scenaT   = scenaTile(vSurfWorldPos, vSurfWorldNormal);\n      float scenaMortar = scenaT.x * uSurfTile;\n      // fine mottle\n      diffuseColor.rgb *= 1.0 + (scenaN - 0.5) * uSurfAlbedoVar;\n      // per-cell brightness jitter, so no two bricks/stones read the same\n      diffuseColor.rgb *= 1.0 + uSurfTileJitter * (scenaT.y - 0.5) * uSurfTile;\n      // cavity ambient occlusion (dark where the low band is low)\n      diffuseColor.rgb *= 1.0 - uSurfAO * (1.0 - scenaLow);\n      // cavity tint\n      diffuseColor.rgb = mix(diffuseColor.rgb, uSurfTint, uSurfTintAmount * (1.0 - scenaLow));\n      // grain darkening (no-op when uSurfGrain == 0)\n      diffuseColor.rgb *= 1.0 - uSurfGrain * scenaG * 0.5;\n      // aggregate chips — hard-edged, unlike everything else here\n      diffuseColor.rgb *= 1.0 + (scenaSp - 0.5) * uSurfSpeck;\n      // cells: each one its own shade, and the seams between them dark\n      diffuseColor.rgb *= 1.0 + (scenaC.x - 0.5) * uSurfCellJitter * uSurfCells;\n      diffuseColor.rgb *= 1.0 - scenaSeam * uSurfCellEdge;\n      // the ridge valleys hold shadow the lighting alone will not give them\n      diffuseColor.rgb *= 1.0 - uSurfRibs * (1.0 - scenaRib) * 0.22;\n      // accent cells (mosaic chips) painted solid tint — a no-op at 0\n      float scenaAccent = uSurfTile * uSurfTileTint;\n      diffuseColor.rgb = mix(diffuseColor.rgb, uSurfTint, step(scenaT.y, scenaAccent) * uSurfTile);\n      // per-cell ring + dot motif (patterned cement tiles) — a no-op at 0\n      float scenaMotifM = smoothstep(0.40, 0.47, scenaT.w) - smoothstep(0.60, 0.68, scenaT.w)\n        + smoothstep(0.86, 0.93, scenaT.w);\n      diffuseColor.rgb = mix(diffuseColor.rgb, uSurfTint,\n        clamp(scenaMotifM, 0.0, 1.0) * uSurfTileMotif * uSurfTile);\n      // recessed mortar joint: to the mortar colour, shadowed in the groove\n      diffuseColor.rgb = mix(diffuseColor.rgb, uSurfMortarColor, scenaMortar);\n      diffuseColor.rgb *= 1.0 - 0.35 * scenaMortar;\n      // snow / moss cap settling on the up-facing faces (over the mortar too)\n      float scenaCapM = scenaCapMask(vSurfWorldNormal, scenaN) * uSurfCap;\n      diffuseColor.rgb = mix(diffuseColor.rgb, uSurfCapColor, scenaCapM);\n      // WET. Water darkens a surface because it fills the pores: light gets\n      // in, scatters, and comes back out with less of it. So POROUS things\n      // darken hard and sealed ones barely change — a wet flagstone is\n      // almost black, wet chrome is just chrome — and metal, which has no\n      // subsurface to wet, does not darken at all.\n      // A CRUST, not a tint: verdigris, rust bloom, lichen. It goes over\n      // everything above it, because it grew on top of all of it.\n      float scenaCrustM = scenaCrustMask(vSurfWorldNormal, scenaLow);\n      diffuseColor.rgb = mix(diffuseColor.rgb, uSurfCrustColor, scenaCrustM);\n      float scenaWetM = scenaWetMask(vSurfWorldNormal, scenaLow, scenaMortar);\n      float scenaPorous = (1.0 - clamp(metalness, 0.0, 1.0)) * clamp(roughness, 0.0, 1.0);\n      diffuseColor.rgb *= mix(1.0, mix(0.93, 0.45, scenaPorous), scenaWetM);`\n    )\n    .replace(\n      '#include <roughnessmap_fragment>',\n      `#include <roughnessmap_fragment>\n      roughnessFactor = clamp(roughnessFactor + (scenaN - 0.5) * uSurfRoughVar + uSurfGrain * scenaG * 0.12\n        + scenaMortar * 0.25 + (scenaT.y - 0.5) * uSurfTileJitter * 0.3 * uSurfTile, 0.04, 1.0);\n      roughnessFactor = clamp(roughnessFactor + (scenaSp - 0.5) * uSurfSpeck * 0.35\n        + scenaSeam * 0.2, 0.04, 1.0);\n      roughnessFactor = mix(roughnessFactor, uSurfCrustRough, scenaCrustM);\n      roughnessFactor = mix(roughnessFactor, uSurfCapRough, scenaCapM);\n      // A film of water is a mirror, whatever is underneath it.\n      roughnessFactor = mix(roughnessFactor, 0.05, scenaWetM * 0.92);`\n    )\n    .replace(\n      '#include <metalnessmap_fragment>',\n      `#include <metalnessmap_fragment>\n      // A mineral scab does not reflect like the metal it grew on, so where\n      // the crust has taken hold the metal is simply not there any more.\n      // This is the difference between patina and green paint.\n      metalnessFactor = mix(metalnessFactor, 0.0, scenaCrustM);`\n    )\n    .replace(\n      '#include <normal_fragment_maps>',\n      `#include <normal_fragment_maps>\n      {\n        // three's perturbNormalArb, in view space, driven by the noise height\n        // plus the tile relief (a step down into each mortar joint).\n        // Standing water fills the micro-relief, so the bump flattens out\n        // under it — the puddle is smooth even where the stone is not.\n        float scenaH = (scenaN + uSurfGrain * scenaG * 0.5 + scenaT.z * uSurfTile * uSurfTileRelief\n          + scenaRib * uSurfRibs * 0.9 + scenaC.y * uSurfCells * uSurfCellEdge * 0.5)\n          * (1.0 - scenaWetM * 0.7);\n        vec3 sX = dFdx(-vViewPosition);\n        vec3 sY = dFdy(-vViewPosition);\n        vec3 sN = normal;\n        vec3 R1 = cross(sY, sN);\n        vec3 R2 = cross(sN, sX);\n        float det = dot(sX, R1);\n        vec3 grad = sign(det) * (dFdx(scenaH) * R1 + dFdy(scenaH) * R2);\n        normal = normalize(abs(det) * sN - uSurfBump * grad);\n      }`\n    )\n    .replace(\n      '#include <emissivemap_fragment>',\n      `#include <emissivemap_fragment>\n      {\n        // Procedural glow (lava cracks, crystal): drawn straight into the\n        // emissive radiance, NOT via material.emissive — so it burns constant\n        // and the day/night cycle (which scales emissiveIntensity) can't dim\n        // it. A no-op when uSurfGlow == 0. Glow fills the low-noise areas.\n        float scenaGlow = smoothstep(uSurfGlowThresh + 0.16, uSurfGlowThresh - 0.16, scenaLow) * uSurfGlow;\n        totalEmissiveRadiance += uSurfGlowColor * scenaGlow;\n      }`\n    );\n}\n\n/**\n * Build a procedural surface material. Pass a preset name for the defaults,\n * plus any overrides (colour, roughness, bump, seed, …).\n */\nexport function createSurface(kind: SurfaceKind, options: SurfaceOptions = {}): MeshStandardMaterial {\n  const preset = SURFACE_PRESETS[kind];\n  const p: SurfaceParams = { ...preset, ...options };\n  const seed = options.seed ?? 0;\n\n  const base = {\n    color: options.color ?? preset.baseColor ?? 0x9a9a9a,\n    roughness: p.roughness,\n    metalness: p.metalness,\n    flatShading: p.flat,\n  };\n  // A MeshPhysicalMaterial only when the preset genuinely needs one. It is a\n  // bigger shader, and `transmission` makes three render the scene a second\n  // time — so the other 52 kinds keep the cheap material they have always had.\n  const material: MeshStandardMaterial = p.physical\n    ? new MeshPhysicalMaterial({\n        ...base,\n        ...(p.sheen === undefined ? {} : {\n          sheen: p.sheen,\n          sheenColor: new Color(p.sheenColor ?? 0xffffff),\n          sheenRoughness: p.sheenRough ?? 0.3,\n        }),\n        ...(p.anisotropy === undefined ? {} : {\n          anisotropy: p.anisotropy,\n          anisotropyRotation: p.anisotropyRotation ?? 0,\n        }),\n        ...(p.iridescence === undefined ? {} : {\n          iridescence: p.iridescence,\n          iridescenceIOR: p.iridescenceIOR ?? 1.3,\n          iridescenceThicknessRange: p.iridescenceThickness ?? [100, 400],\n        }),\n        ...(p.transmission === undefined ? {} : {\n          transmission: p.transmission,\n          thickness: p.thickness ?? 0.5,\n          ior: p.ior ?? 1.5,\n          // Only when asked for: three compiles USE_DISPERSION the moment\n          // this crosses zero, and that is three transmission samples a\n          // pixel instead of one.\n          ...(p.dispersion ? { dispersion: p.dispersion } : {}),\n          ...(p.attenuationColor === undefined ? {} : {\n            attenuationColor: new Color(p.attenuationColor),\n            attenuationDistance: p.attenuationDistance ?? 1,\n          }),\n        }),\n      })\n    : new MeshStandardMaterial(base);\n\n  const uniforms = {\n    uSurfScale: { value: p.scale },\n    uSurfAlbedoVar: { value: p.albedoVar },\n    uSurfTint: { value: new Color(p.tint) },\n    uSurfTintAmount: { value: p.tintAmount },\n    uSurfAO: { value: p.ao },\n    uSurfBump: { value: p.bump },\n    uSurfRoughVar: { value: p.roughVar },\n    uSurfGrain: { value: p.grain },\n    uSurfGrainScale: { value: p.grainScale },\n    uSurfGrainAxis: { value: p.grainAxis.clone().normalize() },\n    // A large, seed-driven world-space offset so equal colours weather apart.\n    uSurfSeed: {\n      value: new Vector3(\n        Math.sin(seed * 12.9898) * 43.75,\n        Math.cos(seed * 78.233) * 51.13,\n        Math.sin(seed * 37.719) * 29.41\n      ),\n    },\n    // Masonry tiling (uSurfTile 0 disables the whole grid at no visual cost).\n    uSurfTile: { value: p.tile ?? 0 },\n    uSurfTileSize: { value: new Vector2(p.tileW ?? 0.25, p.tileH ?? 0.1) },\n    uSurfMortar: { value: p.mortar ?? 0.014 },\n    uSurfTileBond: { value: p.bond ?? 1 },\n    uSurfTileRound: { value: p.round ?? 0 },\n    uSurfTileJitter: { value: p.tileJitter ?? 0.12 },\n    uSurfMortarColor: { value: new Color(p.mortarColor ?? 0x3a3a3a) },\n    uSurfTileRelief: { value: p.tileRelief ?? 0.06 },\n    uSurfTileTint: { value: p.tileTint ?? 0 },\n    uSurfTileChevron: { value: p.chevron ?? 0 },\n    uSurfTileMotif: { value: p.motif ?? 0 },\n    // Snow/moss cap (uSurfCap 0 disables it).\n    uSurfCap: { value: p.cap ?? 0 },\n    uSurfCapColor: { value: new Color(p.capColor ?? 0xf2f6fa) },\n    uSurfCapUp: { value: p.capUp ?? 0.5 },\n    uSurfCapSharp: { value: p.capSharp ?? 0.28 },\n    uSurfCapRough: { value: p.capRough ?? 0.88 },\n    // Emissive glow (uSurfGlow 0 keeps it dark, day-cycle-safe).\n    uSurfGlow: { value: p.glow ?? 0 },\n    uSurfGlowColor: { value: new Color(p.glowColor ?? 0xff6a2a) },\n    uSurfGlowThresh: { value: p.glowThreshold ?? 0.45 },\n    // Wear: water (uSurfWet 0 is bone dry and costs one compare).\n    uSurfWet: { value: p.wet ?? 0 },\n    uSurfWetCling: { value: p.wetCling ?? 0.55 },\n    // Ribs, aggregate, cells and crust (each 0 = off, and off costs a compare).\n    uSurfRibs: { value: p.ribs ?? 0 },\n    uSurfRibScale: { value: p.ribScale ?? 8 },\n    uSurfRibTurn: { value: p.ribTurn ?? 0 },\n    uSurfRibCross: { value: p.ribCross ?? 0 },\n    uSurfSpeck: { value: p.speck ?? 0 },\n    uSurfSpeckScale: { value: p.speckScale ?? 40 },\n    uSurfCells: { value: p.cells ?? 0 },\n    uSurfCellScale: { value: p.cellScale ?? 4 },\n    uSurfCellEdge: { value: p.cellEdge ?? 0.4 },\n    uSurfCellJitter: { value: p.cellJitter ?? 0.18 },\n    uSurfCellPlan: { value: p.cellPlan ?? 0 },\n    uSurfCrust: { value: p.crust ?? 0 },\n    uSurfCrustColor: { value: new Color(p.crustColor ?? 0x4fa88a) },\n    uSurfCrustRough: { value: p.crustRough ?? 0.9 },\n  };\n\n  material.onBeforeCompile = (shader) => {\n    Object.assign(shader.uniforms, uniforms);\n    shader.vertexShader = vertexPatch(shader.vertexShader);\n    shader.fragmentShader = fragmentPatch(shader.fragmentShader);\n    // Keep the live shader so weather can drive uniforms after compilation —\n    // the object three actually uploads from, not just our pre-compile copy.\n    (material.userData as { scenaShader?: typeof shader }).scenaShader = shader;\n  };\n  // All surface materials inject identical source (uniforms carry the\n  // differences), so one cache key groups them — and, crucially, keeps them\n  // from colliding with a plain MeshStandardMaterial that has matching base\n  // params but no injection. three still appends its own feature key, so\n  // flat/smooth/instanced variants stay separate programs.\n  const cacheKey = p.physical ? 'scena-surface-v5-physical' : 'scena-surface-v5';\n  material.customProgramCacheKey = () => cacheKey;\n\n  // Expose the live uniforms so weather can drive them after the fact — e.g.\n  // snow settling ramps uSurfCap, rain darkens/glosses via the same handles.\n  (material.userData as { scenaSurface?: typeof uniforms }).scenaSurface = uniforms;\n\n  return material;\n}\n","import { BoxGeometry, Group, Mesh } from 'three';\nimport { Rng } from '../core/random';\nimport { DEFAULT_PALETTE, type Palette } from '../core/palette';\nimport { createSurface } from '../materials/surface';\nimport type { Carryable } from '../core/types';\n\nexport interface CrateOptions {\n  seed?: number;\n  size?: number;\n  /** 0–1 color wear. Default 0.3. */\n  weathering?: number;\n  palette?: Palette;\n}\n\n/**\n * A wooden crate: panel box with darker edge framing, seeded wear tint. It's\n * a **carryable** — hand it to ANIMA's `Carry` and a character hoists it to\n * the chest (`carry: 'crate'`), the hold point offset to the box's centre.\n */\nexport function createCrate(options: CrateOptions = {}): Carryable {\n  const rng = new Rng(options.seed ?? 1);\n  const palette = options.palette ?? DEFAULT_PALETTE;\n  const size = options.size ?? 1;\n  const wear = options.weathering ?? 0.3;\n\n  const group = new Group();\n  group.name = 'crate';\n\n  const panelMaterial = createSurface('plank', { color: palette.wood, seed: options.seed ?? 1 });\n  panelMaterial.color.offsetHSL(0, 0, -rng.range(0, wear * 0.18));\n  const frameMaterial = createSurface('wood', { color: palette.woodDark, seed: (options.seed ?? 1) + 3 });\n\n  const body = new Mesh(new BoxGeometry(size * 0.92, size * 0.92, size * 0.92), panelMaterial);\n  body.position.y = size / 2;\n  group.add(body);\n\n  const beam = size * 0.12;\n  const long = size * 1.0;\n  for (const y of [beam / 2, size - beam / 2]) {\n    for (const [rx, rz, w, d] of [\n      [0, size / 2 - beam / 2, long, beam],\n      [0, -(size / 2 - beam / 2), long, beam],\n      [size / 2 - beam / 2, 0, beam, long],\n      [-(size / 2 - beam / 2), 0, beam, long],\n    ] as const) {\n      const rail = new Mesh(new BoxGeometry(w, beam, d), frameMaterial);\n      rail.position.set(rx, y, rz);\n      group.add(rail);\n    }\n  }\n  for (const x of [-1, 1]) {\n    for (const z of [-1, 1]) {\n      const post = new Mesh(new BoxGeometry(beam, size, beam), frameMaterial);\n      post.position.set(x * (size / 2 - beam / 2), size / 2, z * (size / 2 - beam / 2));\n      group.add(post);\n    }\n  }\n  group.rotation.y = rng.range(0, Math.PI / 2);\n\n  return {\n    object: group,\n    obstacleRadius: size * 0.75,\n    carry: 'crate',\n    // Origin is the base: lift the hold point to the centre (y) and push it\n    // forward by half the depth (z) so the box rides IN FRONT of the chest,\n    // not merged into it.\n    grip: { y: -size / 2, z: size / 2 },\n  };\n}\n","import {\n  CylinderGeometry,\n  Group,\n  Mesh,\n  MeshStandardMaterial,\n  SphereGeometry,\n  TorusGeometry,\n} from 'three';\nimport { Rng } from '../core/random';\nimport { DEFAULT_PALETTE, type Palette } from '../core/palette';\nimport { createSurface } from '../materials/surface';\nimport type { Carryable } from '../core/types';\n\n/**\n * Carryable props — things a character picks up and carries. Each returns a\n * `Carryable` (a `Prop` plus a `carry` style and hold-point `grip`), so it\n * drops into ANIMA's `Carry`: `new Carry(rig, loco).pickUp(createBarrel())`.\n * Origins sit at the base (place them on the ground); `grip` puts the hold\n * point where the hands go, so no runtime IK is needed.\n */\n\nexport interface CarryableOptions {\n  seed?: number;\n  color?: number;\n  palette?: Palette;\n}\n\n/** A hooped wooden barrel — hugged to the chest (`crate` style). */\nexport function createBarrel(options: CarryableOptions = {}): Carryable {\n  const seed = options.seed ?? 1;\n  const palette = options.palette ?? DEFAULT_PALETTE;\n  const H = 0.86;\n  const R = 0.32;\n  const stave = createSurface('wood', { color: options.color ?? palette.wood, seed });\n  const iron = createSurface('steel', { seed: seed + 1 });\n\n  const group = new Group();\n  group.name = 'barrel';\n  const body = new Mesh(new CylinderGeometry(R * 0.86, R * 0.86, H, 14), stave);\n  body.position.y = H / 2;\n  const bulge = new Mesh(new CylinderGeometry(R, R, H * 0.5, 14), stave);\n  bulge.position.y = H / 2;\n  group.add(body, bulge);\n  for (const y of [H * 0.16, H * 0.5, H * 0.84]) {\n    const hoop = new Mesh(new TorusGeometry(R * (y === H * 0.5 ? 1.02 : 0.9), 0.022, 6, 16), iron);\n    hoop.rotation.x = Math.PI / 2;\n    hoop.position.y = y;\n    group.add(hoop);\n  }\n  return { object: group, obstacleRadius: R * 1.1, carry: 'crate', grip: { y: -H / 2, z: R } };\n}\n\n/** A woven basket with an arched handle — carried at the side, by the handle. */\nexport function createBasket(options: CarryableOptions = {}): Carryable {\n  const seed = options.seed ?? 1;\n  const palette = options.palette ?? DEFAULT_PALETTE;\n  const rng = new Rng(seed);\n  const bodyH = 0.3;\n  const rTop = 0.22;\n  const weave = createSurface('wood', { color: options.color ?? palette.woodDark, seed });\n\n  const group = new Group();\n  group.name = 'basket';\n  const body = new Mesh(new CylinderGeometry(rTop, rTop * 0.72, bodyH, 12, 1, true), weave);\n  body.position.y = bodyH / 2;\n  const base = new Mesh(new CylinderGeometry(rTop * 0.72, rTop * 0.72, 0.03, 12), weave);\n  base.position.y = 0.015;\n  const rim = new Mesh(new TorusGeometry(rTop, 0.02, 6, 14), weave);\n  rim.rotation.x = Math.PI / 2;\n  rim.position.y = bodyH;\n  group.add(body, base, rim);\n  // Arched handle over the top.\n  const handle = new Mesh(new TorusGeometry(rTop * 0.9, 0.016, 5, 12, Math.PI), weave);\n  handle.position.y = bodyH;\n  group.add(handle);\n  // A couple of loose contents for flavour.\n  for (let i = 0; i < 3; i++) {\n    const fruit = new Mesh(\n      new SphereGeometry(0.05, 6, 6),\n      new MeshStandardMaterial({ color: [0xd05a3a, 0xe0a52e, 0x6f8f3a][i], flatShading: true })\n    );\n    fruit.position.set(rng.range(-0.08, 0.08), bodyH - 0.03, rng.range(-0.08, 0.08));\n    group.add(fruit);\n  }\n  return { object: group, obstacleRadius: rTop, carry: 'side', grip: { y: -0.14 } };\n}\n\n/** A cinched sack — hoisted onto the shoulder (`shoulder` style). */\nexport function createSack(options: CarryableOptions = {}): Carryable {\n  const seed = options.seed ?? 1;\n  const cloth = createSurface('canvas', { color: options.color ?? 0xcdb98a, seed });\n  const cord = new MeshStandardMaterial({ color: 0x6b5a3a, roughness: 0.9, flatShading: true });\n\n  const group = new Group();\n  group.name = 'sack';\n  const belly = new Mesh(new SphereGeometry(0.24, 10, 10), cloth);\n  belly.scale.set(1, 1.25, 1);\n  belly.position.y = 0.26;\n  const neck = new Mesh(new CylinderGeometry(0.09, 0.14, 0.14, 8), cloth);\n  neck.position.y = 0.5;\n  const tie = new Mesh(new TorusGeometry(0.09, 0.02, 5, 10), cord);\n  tie.rotation.x = Math.PI / 2;\n  tie.position.y = 0.48;\n  group.add(belly, neck, tie);\n  return { object: group, obstacleRadius: 0.28, carry: 'shoulder', grip: { y: -0.26 } };\n}\n\nexport interface LanternOptions extends CarryableOptions {\n  /** Emissive glow colour. Default warm. */\n  glow?: number;\n}\n\n/** A hand lantern — carried at the side, hanging from its bail. Glass glows. */\nexport function createLantern(options: LanternOptions = {}): Carryable {\n  const seed = options.seed ?? 1;\n  const metal = createSurface('steel', { color: options.color ?? 0x2c2f36, seed });\n  const glowColor = options.glow ?? 0xffd48a;\n  const glass = new MeshStandardMaterial({\n    color: glowColor,\n    emissive: glowColor,\n    emissiveIntensity: 0.9,\n    transparent: true,\n    opacity: 0.85,\n  });\n\n  const group = new Group();\n  group.name = 'lantern';\n  const base = new Mesh(new CylinderGeometry(0.08, 0.1, 0.04, 8), metal);\n  base.position.y = 0.02;\n  const cage = new Mesh(new CylinderGeometry(0.075, 0.075, 0.16, 8, 1, true), glass);\n  cage.position.y = 0.13;\n  const cap = new Mesh(new CylinderGeometry(0.055, 0.09, 0.05, 8), metal);\n  cap.position.y = 0.235;\n  group.add(base, cage, cap);\n  // Corner posts + a bail handle.\n  for (let i = 0; i < 4; i++) {\n    const post = new Mesh(new CylinderGeometry(0.008, 0.008, 0.16, 4), metal);\n    const a = (i / 4) * Math.PI * 2;\n    post.position.set(Math.cos(a) * 0.072, 0.13, Math.sin(a) * 0.072);\n    group.add(post);\n  }\n  const bail = new Mesh(new TorusGeometry(0.05, 0.008, 5, 10, Math.PI), metal);\n  bail.position.y = 0.26;\n  group.add(bail);\n  return { object: group, obstacleRadius: 0.12, carry: 'side', grip: { y: -0.2 } };\n}\n","import {\n  BoxGeometry,\n  ConeGeometry,\n  CylinderGeometry,\n  Group,\n  IcosahedronGeometry,\n  InstancedMesh,\n  Matrix4,\n  Mesh,\n  MeshStandardMaterial,\n  Object3D,\n  Quaternion,\n  Vector3,\n} from 'three';\nimport { Rng } from '../core/random';\nimport { DEFAULT_PALETTE, type Palette } from '../core/palette';\nimport { createSurface } from '../materials/surface';\nimport { createSlot } from '../core/types';\nimport type { Prop, PropSlot } from '../core/types';\n\n/**\n * Rhythmic work stations — props built to be WORKED, not just used. A worker\n * stands at the `work` slot playing the station's `action` loop (ANIMA: chop,\n * mine, saw, stir), and each frame you drive `update(dt, working)`: the\n * station advances `progress` (0→1), throws a burst of effects on the impact\n * beat (chips, sparks, sawdust, steam) and fires `onYield` once per cycle —\n * the \"do work over time and produce something\" verb. Pair the yield with\n * GAMA's `Stockpile`:\n *\n * Walk the worker to the `work` slot, hold the tool, and layer the action\n * loop over the idle stance (the loop owns the arms — don't fight it with a\n * held pose):\n *\n * ```ts\n * const block = createChoppingBlock();\n * attach(rig, 'handRight', block.tool);                       // ANIMA holds the axe\n * const swing = loco.overlay(createLoopClip(rig, block.action)); // the chop, over idle\n * block.onYield = () => stock.add('wood');                    // GAMA counts the logs\n * game.onUpdate((t) => block.update(t.delta, working));       // effects + progress + yield\n * ```\n */\nexport interface WorkStation extends Prop {\n  /** The ANIMA loop the worker plays ('chop' | 'mine' | 'saw' | 'stir'). */\n  readonly action: string;\n  /** Progress toward the next yield, 0→1 (resets each cycle). */\n  readonly progress: number;\n  /** A tool the worker holds — `attach(rig, 'handRight', station.tool)`. */\n  readonly tool: Object3D;\n  /** Fired once per work cycle, with the running total produced. */\n  onYield?: (total: number) => void;\n  /** Advance the station. `working` (default true) gates progress + effects. */\n  update(dt: number, working?: boolean): void;\n}\n\nexport interface WorkStationOptions {\n  seed?: number;\n  palette?: Palette;\n}\n\n// ------------------------------------------------------------- burst pool\n\nexport interface Burst {\n  mesh: InstancedMesh;\n  emit(n: number): void;\n  update(dt: number): void;\n}\n\nexport interface BurstOptions {\n  origin: Vector3;\n  color: number;\n  count?: number;\n  size?: number;\n  speed?: number;\n  spread?: number;\n  up?: number;\n  gravity?: number;\n  life?: number;\n  /** Steam-like: drift up and swell instead of falling. Default false. */\n  rise?: boolean;\n}\n\n/**\n * A tiny CPU particle pool as an InstancedMesh (local to the station). Debris\n * (chips, sparks, dust) arcs under gravity and shrinks out; `rise` makes soft\n * steam that floats up and swells. Deterministic given a seeded Rng.\n */\n/** Internal — shared with the prep stations; not part of the public API. */\nexport function makeBurst(rng: Rng, options: BurstOptions): Burst {\n  const count = options.count ?? 24;\n  const size = options.size ?? 0.05;\n  const speed = options.speed ?? 1.6;\n  const spread = options.spread ?? 0.7;\n  const up = options.up ?? 1.4;\n  const rise = options.rise ?? false;\n  const gravity = options.gravity ?? (rise ? -1.2 : 6);\n  const lifeMax = options.life ?? 0.7;\n\n  const geo = options.rise ? new IcosahedronGeometry(size, 0) : new BoxGeometry(size, size, size);\n  const mat = new MeshStandardMaterial({\n    color: options.color,\n    flatShading: true,\n    transparent: rise,\n    opacity: rise ? 0.6 : 1,\n    emissive: options.color,\n    emissiveIntensity: rise ? 0 : 0.15,\n  });\n  const mesh = new InstancedMesh(geo, mat, count);\n  mesh.frustumCulled = false;\n  mesh.count = count;\n\n  const pos = Array.from({ length: count }, () => new Vector3());\n  const vel = Array.from({ length: count }, () => new Vector3());\n  const life = new Float32Array(count);\n  const m = new Matrix4();\n  const q = new Quaternion();\n  const one = new Vector3(1, 1, 1);\n  const parked = new Vector3(0, -9999, 0);\n  // Start all parked.\n  for (let i = 0; i < count; i++) {\n    m.compose(parked, q, one);\n    mesh.setMatrixAt(i, m);\n  }\n  mesh.instanceMatrix.needsUpdate = true;\n\n  return {\n    mesh,\n    emit(n: number) {\n      let spawned = 0;\n      for (let i = 0; i < count && spawned < n; i++) {\n        if (life[i] > 0) continue;\n        life[i] = lifeMax * (0.7 + rng.next() * 0.5);\n        pos[i].copy(options.origin);\n        vel[i].set(\n          (rng.next() - 0.5) * spread * speed,\n          (rise ? up * (0.6 + rng.next() * 0.6) : up * speed * (0.5 + rng.next())),\n          (rng.next() - 0.5) * spread * speed\n        );\n        spawned++;\n      }\n    },\n    update(dt: number) {\n      let dirty = false;\n      for (let i = 0; i < count; i++) {\n        if (life[i] <= 0) continue;\n        dirty = true;\n        life[i] -= dt;\n        vel[i].y -= gravity * dt;\n        pos[i].addScaledVector(vel[i], dt);\n        const t = Math.max(0, life[i] / lifeMax);\n        const s = rise ? (1.4 - t) * size * 8 : t; // steam swells, debris shrinks\n        if (life[i] <= 0) {\n          m.compose(parked, q, one);\n        } else {\n          m.compose(pos[i], q, one.set(s, s, s));\n        }\n        mesh.setMatrixAt(i, m);\n      }\n      if (dirty) mesh.instanceMatrix.needsUpdate = true;\n    },\n  };\n}\n\n// ------------------------------------------------------------- the driver\n\nexport interface StationCore {\n  action: string;\n  progress: number;\n  onYield?: (total: number) => void;\n  update(dt: number, working?: boolean): void;\n}\n\n/** Internal — shared with the prep stations; not part of the public API. */\nexport function drive(\n  action: string,\n  cycle: number,\n  impactAt: number,\n  emit: () => void,\n  bursts: Burst[]\n): StationCore {\n  let phase = 0;\n  let struck = false;\n  let total = 0;\n  const core: StationCore = {\n    action,\n    progress: 0,\n    onYield: undefined,\n    update(dt: number, working = true) {\n      if (working && dt > 0) {\n        phase += dt / cycle;\n        if (!struck && phase >= impactAt) {\n          struck = true;\n          total += 1;\n          emit();\n          core.onYield?.(total);\n        }\n        if (phase >= 1) {\n          phase -= 1;\n          struck = false;\n        }\n        core.progress = phase;\n      }\n      for (const b of bursts) b.update(dt);\n    },\n  };\n  return core;\n}\n\n// ------------------------------------------------------------------ tools\n\nconst DARK = () => new MeshStandardMaterial({ color: 0x2a2d33, metalness: 0.5, roughness: 0.5 });\n\n/** An axe held in the hand (origin at the grip; shaft up, head near the top). */\nfunction makeAxe(seed: number): Object3D {\n  const g = new Group();\n  g.name = 'axe';\n  const shaft = new Mesh(new CylinderGeometry(0.018, 0.022, 0.6, 6), createSurface('wood', { seed }));\n  shaft.position.y = 0.28;\n  const head = new Mesh(new BoxGeometry(0.04, 0.14, 0.16), createSurface('steel', { seed: seed + 1 }));\n  head.position.set(0, 0.54, 0.05);\n  g.add(shaft, head);\n  return g;\n}\n\nfunction makePickaxe(seed: number): Object3D {\n  const g = new Group();\n  g.name = 'pickaxe';\n  const shaft = new Mesh(new CylinderGeometry(0.018, 0.022, 0.62, 6), createSurface('wood', { seed }));\n  shaft.position.y = 0.29;\n  const head = new Mesh(new CylinderGeometry(0.02, 0.02, 0.44, 6), createSurface('steel', { seed: seed + 1 }));\n  head.rotation.z = Math.PI / 2;\n  head.position.y = 0.56;\n  for (const s of [-1, 1]) {\n    const tip = new Mesh(new ConeGeometry(0.03, 0.08, 5), createSurface('steel', { seed: seed + 2 }));\n    tip.rotation.z = (s * Math.PI) / 2;\n    tip.position.set(s * 0.24, 0.56, 0);\n    g.add(tip);\n  }\n  g.add(shaft, head);\n  return g;\n}\n\nfunction makeLadle(seed: number): Object3D {\n  const g = new Group();\n  g.name = 'ladle';\n  const shaft = new Mesh(new CylinderGeometry(0.014, 0.016, 0.5, 6), createSurface('wood', { seed }));\n  shaft.position.y = 0.24;\n  const bowl = new Mesh(new IcosahedronGeometry(0.06, 1), DARK());\n  bowl.scale.y = 0.55;\n  bowl.position.y = 0.5;\n  g.add(shaft, bowl);\n  return g;\n}\n\nfunction makeSaw(seed: number): Object3D {\n  const g = new Group();\n  g.name = 'saw';\n  const handle = new Mesh(new BoxGeometry(0.07, 0.1, 0.04), createSurface('wood', { seed }));\n  handle.position.y = 0.05;\n  const blade = new Mesh(new BoxGeometry(0.5, 0.09, 0.006), createSurface('steel', { seed: seed + 1 }));\n  blade.position.set(0.28, 0.05, 0);\n  g.add(handle, blade);\n  return g;\n}\n\n// ------------------------------------------------------------- the props\n\n/** Internal — shared with the prep stations; not part of the public API. */\nexport function workSlot(action: string, group: Group, x: number, z: number, rotY: number): PropSlot {\n  const s = createSlot('work', 'operate', group, x, 0, z, rotY);\n  s.loop = action; // the worker layers the action loop over the stand\n  return s;\n}\n\n/** A chopping block: a stump with a log to split, an axe, flying wood chips. */\nexport function createChoppingBlock(options: WorkStationOptions = {}): WorkStation {\n  const seed = options.seed ?? 1;\n  const palette = options.palette ?? DEFAULT_PALETTE;\n  const rng = new Rng(seed);\n  const bark = createSurface('bark', { color: palette.woodDark, seed });\n  const raw = createSurface('wood', { color: palette.wood, seed: seed + 1 });\n\n  const group = new Group();\n  group.name = 'chopping-block';\n  const stump = new Mesh(new CylinderGeometry(0.3, 0.34, 0.5, 10), bark);\n  stump.position.y = 0.25;\n  const log = new Mesh(new CylinderGeometry(0.11, 0.11, 0.44, 8), raw);\n  log.rotation.z = Math.PI / 2;\n  log.position.y = 0.56;\n  group.add(stump, log);\n  for (let i = 0; i < 4; i++) {\n    const split = new Mesh(new BoxGeometry(0.09, 0.09, 0.38), raw);\n    split.position.set(rng.jitter(0.42, 0.12), 0.05, rng.jitter(0.1, 0.3));\n    split.rotation.y = rng.range(0, Math.PI);\n    group.add(split);\n  }\n  const chips = makeBurst(rng, { origin: new Vector3(0, 0.6, 0), color: palette.wood, count: 20, size: 0.045, speed: 1.4, up: 1.2, life: 0.6 });\n  group.add(chips.mesh);\n\n  const core = drive('chop', 1.2, 0.6, () => chips.emit(14), [chips]);\n  return finish(group, 0.55, workSlot('chop', group, 0, 0.7, Math.PI), makeAxe(seed), core);\n}\n\n/** An ore vein: a boulder streaked with glowing ore, a pickaxe, dust + sparks. */\nexport function createOreVein(options: WorkStationOptions = {}): WorkStation {\n  const seed = options.seed ?? 1;\n  const rng = new Rng(seed);\n  const rock = createSurface('granite', { seed });\n  const oreMat = new MeshStandardMaterial({ color: 0xffb454, emissive: 0xd7791f, emissiveIntensity: 0.6, flatShading: true });\n\n  const group = new Group();\n  group.name = 'ore-vein';\n  const boulder = new Mesh(new IcosahedronGeometry(0.55, 0), rock);\n  boulder.scale.set(1.2, 1.0, 0.9);\n  boulder.position.y = 0.5;\n  group.add(boulder);\n  for (let i = 0; i < 6; i++) {\n    const ore = new Mesh(new IcosahedronGeometry(rng.range(0.05, 0.09), 0), oreMat);\n    const a = rng.range(0, Math.PI * 2);\n    ore.position.set(Math.cos(a) * 0.45, 0.5 + rng.range(-0.2, 0.3), 0.35 + rng.range(-0.1, 0.1));\n    group.add(ore);\n  }\n  const dust = makeBurst(rng, { origin: new Vector3(0, 0.55, 0.5), color: 0x9a8f82, count: 16, size: 0.04, speed: 1.2, up: 1.0, life: 0.6 });\n  const sparks = makeBurst(rng, { origin: new Vector3(0, 0.55, 0.5), color: 0xffd27a, count: 10, size: 0.03, speed: 2.4, up: 1.8, life: 0.4 });\n  group.add(dust.mesh, sparks.mesh);\n\n  const core = drive('mine', 1.05, 0.6, () => { dust.emit(12); sparks.emit(8); }, [dust, sparks]);\n  return finish(group, 0.7, workSlot('mine', group, 0, 1.0, Math.PI), makePickaxe(seed), core);\n}\n\n/** A cook-pot: a cauldron on a tripod over embers, a ladle, rising steam. */\nexport function createCookpot(options: WorkStationOptions = {}): WorkStation {\n  const seed = options.seed ?? 1;\n  const rng = new Rng(seed);\n  const iron = createSurface('metal', { seed });\n\n  const group = new Group();\n  group.name = 'cookpot';\n  const pot = new Mesh(new CylinderGeometry(0.32, 0.26, 0.4, 12), iron);\n  pot.position.y = 0.55;\n  const rim = new Mesh(new CylinderGeometry(0.34, 0.34, 0.06, 12), iron);\n  rim.position.y = 0.74;\n  group.add(pot, rim);\n  for (let i = 0; i < 3; i++) {\n    const a = (i / 3) * Math.PI * 2;\n    const leg = new Mesh(new CylinderGeometry(0.02, 0.02, 0.7, 5), iron);\n    leg.position.set(Math.cos(a) * 0.28, 0.3, Math.sin(a) * 0.28);\n    leg.rotation.set(Math.cos(a) * 0.3, 0, -Math.sin(a) * 0.3);\n    group.add(leg);\n  }\n  const embers = new Mesh(new CylinderGeometry(0.18, 0.2, 0.06, 8), new MeshStandardMaterial({ color: 0xff7b32, emissive: 0xff5a1a, emissiveIntensity: 0.9, flatShading: true }));\n  embers.position.y = 0.05;\n  group.add(embers);\n  const steam = makeBurst(rng, { origin: new Vector3(0, 0.78, 0), color: 0xf2f2f2, count: 18, size: 0.05, up: 0.5, spread: 0.5, speed: 0.5, life: 1.4, rise: true });\n  group.add(steam.mesh);\n\n  const core = drive('stir', 1.3, 0.5, () => steam.emit(6), [steam]);\n  return finish(group, 0.5, workSlot('stir', group, 0, 0.46, Math.PI), makeLadle(seed), core);\n}\n\n/** A sawhorse with a plank being cut, a hand-saw, and falling sawdust. */\nexport function createSawhorse(options: WorkStationOptions = {}): WorkStation {\n  const seed = options.seed ?? 1;\n  const palette = options.palette ?? DEFAULT_PALETTE;\n  const rng = new Rng(seed);\n  const timber = createSurface('wood', { color: palette.woodDark, seed });\n  const plankMat = createSurface('plank', { color: palette.wood, seed: seed + 1 });\n\n  const group = new Group();\n  group.name = 'sawhorse';\n  for (const zx of [-0.4, 0.4]) {\n    for (const s of [-1, 1]) {\n      const leg = new Mesh(new BoxGeometry(0.05, 0.7, 0.05), timber);\n      leg.position.set(zx, 0.33, s * 0.22);\n      leg.rotation.x = s * 0.35;\n      group.add(leg);\n    }\n  }\n  const beam = new Mesh(new BoxGeometry(1.0, 0.08, 0.1), timber);\n  beam.position.y = 0.64;\n  group.add(beam);\n  const plank = new Mesh(new BoxGeometry(1.3, 0.06, 0.24), plankMat);\n  plank.position.set(0.1, 0.72, 0);\n  group.add(plank);\n  const dust = makeBurst(rng, { origin: new Vector3(0.15, 0.7, 0.12), color: 0xd8c295, count: 18, size: 0.03, speed: 0.8, up: 0.4, spread: 0.5, life: 0.7 });\n  group.add(dust.mesh);\n\n  const core = drive('saw', 1.0, 0.5, () => dust.emit(12), [dust]);\n  return finish(group, 0.75, workSlot('saw', group, 0.15, 0.7, Math.PI), makeSaw(seed), core);\n}\n\n/** Assemble the common WorkStation shape (and mount any extra effect meshes). */\n/** Internal — shared with the prep stations; not part of the public API. */\nexport function finish(\n  group: Group,\n  obstacleRadius: number,\n  slot: PropSlot,\n  tool: Object3D,\n  core: StationCore\n): WorkStation {\n  return {\n    object: group,\n    obstacleRadius,\n    slots: [slot],\n    tool,\n    get action() {\n      return core.action;\n    },\n    get progress() {\n      return core.progress;\n    },\n    get onYield() {\n      return core.onYield;\n    },\n    set onYield(cb: ((total: number) => void) | undefined) {\n      core.onYield = cb;\n    },\n    update(dt: number, working = true) {\n      core.update(dt, working);\n    },\n  } as WorkStation;\n}\n","import { Object3D, Vector3, type Group } from 'three';\n\n/**\n * A steering obstacle in world space — structurally identical to GAMA's\n * `Obstacle`, so SCENA props plug straight into `ObstacleAvoidance`\n * without either library importing the other.\n */\nexport interface Obstacle {\n  center: Vector3;\n  radius: number;\n}\n\n/**\n * An interaction slot — where and how a character uses this prop.\n * Structurally identical to ANIMA's `InteractionSlot` (anchor at floor\n * level, +z the facing direction, pitched for lying poses), so a prop's\n * slot drops straight into `new Interaction(rig, loco).use(slot)` without\n * either library importing the other.\n */\nexport interface PropSlot {\n  /** Free label: 'sit', 'sleep', 'driver', 'run'… */\n  kind: string;\n  /** The transform target for the character's root (a child of the prop). */\n  anchor: Object3D;\n  /** ANIMA pose name ('sit', 'sleep', 'drive', 'cycle', …) or 'run'. */\n  pose: string;\n  /** Optional arms loop ('strum', 'hammer', 'knead'). */\n  loop?: string;\n  /**\n   * Where a character should *stand* before taking the slot — beside the\n   * chair, not on it. Nobody materialises into a seat: they walk here, turn,\n   * then lower. ANIMA's `Interaction.use(slot, { approach: true })` reads it\n   * to stage the sit; steering agents path to it rather than to the anchor.\n   */\n  approach?: Object3D;\n}\n\n/** How a character holds a carryable — structurally ANIMA's `CarryStyle`. */\nexport type CarryStyle = 'crate' | 'tray' | 'shoulder' | 'side';\n\n/**\n * A prop a character can pick up and carry. Structurally identical to ANIMA's\n * `Holdable`, so a SCENA crate drops into `new Carry(rig, loco).pickUp(crate)`\n * with no cross-imports. The object's origin stays at its base (natural for\n * ground placement); `grip` offsets the *hold point* — where it rides in the\n * hands — from that origin.\n */\nexport interface Carryable extends Prop {\n  /** The carry pose the holder adopts. */\n  carry: CarryStyle;\n  /** Hold-point offset from the object's origin (metres). */\n  grip?: { x?: number; y?: number; z?: number };\n}\n\n/**\n * A flat surface on a prop that things can be put down on: a tabletop, a\n * shelf board, the lid of a chest, a windowsill.\n *\n * The anchor sits **on** the surface with +y up, +x along its width and +z\n * along its depth, so `dress` only has to think in two dimensions and the\n * height of whatever it places.\n */\nexport interface PropSurface {\n  /** Free label: 'top', 'shelf', 'sill'. */\n  kind: string;\n  /** Anchor at surface level, a child of the prop. */\n  anchor: Object3D;\n  /** Usable extent along the anchor's local x and z, in metres. */\n  width: number;\n  depth: number;\n}\n\n/**\n * A body of water something can be in, in **world** coordinates.\n *\n * The swimming handshake, and it mirrors `terrain.heightAt` and\n * `ocean.heightAt`: the prop answers questions about the water and ANIMA\n * decides what a body does about it. `depthAt` returns 0 anywhere outside,\n * so \"am I in the water\" needs no separate `contains`.\n *\n * The interesting number is the **depth**, not the surface. Whether a\n * character wades or swims is a decision made against their own height, and\n * a pool with one depth everywhere cannot pose that question at all.\n */\nexport interface WaterBody {\n  /** World Y of the still surface. */\n  readonly surfaceY: number;\n  /** Water depth at a world point, in metres. 0 anywhere outside. */\n  depthAt(x: number, z: number): number;\n  /** Ripple it at a world point — a stroke, a dive, a hand going in. */\n  disturb(x: number, z: number, strength?: number): void;\n}\n\n/** What a prop generator returns: the visual plus gameplay metadata. */\nexport interface Prop {\n  object: Group;\n  /**\n   * Footprint radius for steering/placement, in the prop's local space\n   * (centered at its origin). 0 means walk-through (e.g. grass).\n   */\n  obstacleRadius: number;\n  /** Interaction slots, on props a character can use. */\n  slots?: PropSlot[];\n  /** Flat surfaces things can be set down on — feed these to `dress`. */\n  surfaces?: PropSurface[];\n  /**\n   * Which way up this comes to rest when it is set down on something.\n   *\n   * Props are authored in the orientation they are *used* in, which for a\n   * phone is upright in a hand — put one down as authored and it stands on\n   * its short edge like a domino. `dress` works this out for itself from the\n   * shape (a slab lies down, a candle does not); set this only to override.\n   */\n  rest?: 'upright' | 'flat';\n}\n\n/** Build a surface: an anchor parented into the prop at (x, y, z). */\nexport function createPropSurface(\n  kind: string,\n  parent: Group,\n  x: number,\n  y: number,\n  z: number,\n  width: number,\n  depth: number,\n  rotY = 0\n): PropSurface {\n  const anchor = new Object3D();\n  anchor.name = `surface:${kind}`;\n  anchor.position.set(x, y, z);\n  anchor.rotation.y = rotY;\n  parent.add(anchor);\n  return { kind, anchor, width, depth };\n}\n\n/**\n * A prop several characters use *together* — a dining table, a bench, a\n * game board. Beyond the seats it publishes a **focus**: the thing the\n * occupants attend to. Point every sitter's gaze at it and a row of bodies\n * becomes a group; without it they are strangers who happen to be adjacent.\n */\nexport interface Gathering extends Prop {\n  /** The places, in a stable order — index 0 is the head of the table. */\n  seats: PropSlot[];\n  /** What the occupants look at: table centre, game board, campfire. */\n  focus: Object3D;\n}\n\n/** Build a slot: an anchor Object3D parented into the prop at (x, y, z). */\nexport function createSlot(\n  kind: string,\n  pose: string,\n  parent: Group,\n  x: number,\n  y: number,\n  z: number,\n  rotY = 0,\n  rotX = 0\n): PropSlot {\n  const anchor = new Object3D();\n  anchor.name = `slot:${kind}`;\n  anchor.position.set(x, y, z);\n  anchor.rotation.set(rotX, rotY, 0);\n  parent.add(anchor);\n  return { kind, anchor, pose };\n}\n\n/**\n * Give a slot its standing-room-before: an approach anchor `distance` metres\n * from the seat, facing the same way. The character walks here, turns, and\n * lowers backwards into the slot — which is how sitting actually works.\n *\n * `from` picks the side the character comes at it from, and it must be the\n * side that is *open*. A dining chair is approached from behind (the table\n * is in front of it); a park bench is approached from the front (the\n * backrest is behind it). Get this backwards and characters walk through\n * the furniture to reach their seats.\n */\nexport function addApproach(\n  slot: PropSlot,\n  parent: Group,\n  distance = 0.7,\n  from: 'behind' | 'front' = 'behind'\n): PropSlot {\n  const anchor = new Object3D();\n  anchor.name = `approach:${slot.kind}`;\n  const rotY = slot.anchor.rotation.y;\n  const sign = from === 'front' ? 1 : -1;\n  anchor.position.set(\n    slot.anchor.position.x + Math.sin(rotY) * distance * sign,\n    slot.anchor.position.y,\n    slot.anchor.position.z + Math.cos(rotY) * distance * sign\n  );\n  anchor.rotation.y = rotY;\n  parent.add(anchor);\n  slot.approach = anchor;\n  return slot;\n}\n\n/** Collect world-space obstacles from placed props (call after positioning). */\nexport function collectObstacles(props: Iterable<Prop>): Obstacle[] {\n  const obstacles: Obstacle[] = [];\n  for (const prop of props) {\n    if (prop.obstacleRadius <= 0) continue;\n    prop.object.updateWorldMatrix(true, false);\n    obstacles.push({\n      center: prop.object.getWorldPosition(new Vector3()),\n      radius: prop.obstacleRadius * maxScale(prop.object),\n    });\n  }\n  return obstacles;\n}\n\nfunction maxScale(object: Object3D): number {\n  return Math.max(object.scale.x, object.scale.z);\n}\n","import { BoxGeometry, CylinderGeometry, Group, Mesh, MeshStandardMaterial } from 'three';\nimport { Rng } from '../core/random';\nimport { DEFAULT_PALETTE, type Palette } from '../core/palette';\nimport type { Prop } from '../core/types';\n\nexport interface FenceOptions {\n  seed?: number;\n  /** Run length along local +x. Default 6. */\n  length?: number;\n  postSpacing?: number;\n  height?: number;\n  palette?: Palette;\n}\n\n/**\n * A rustic fence run along local +x, centered at the origin: posts with\n * two slightly-crooked rails. Chain several and rotate to enclose areas.\n * The obstacle radius covers the whole run (rough but steering-safe);\n * for tight navigation, bake a navmesh — the geometry is authoritative.\n */\nexport function createFence(options: FenceOptions = {}): Prop {\n  const rng = new Rng(options.seed ?? 1);\n  const palette = options.palette ?? DEFAULT_PALETTE;\n  const length = options.length ?? 6;\n  const spacing = options.postSpacing ?? 1.5;\n  const height = options.height ?? 1.1;\n\n  const group = new Group();\n  group.name = 'fence';\n  const postMaterial = new MeshStandardMaterial({ color: palette.woodDark, flatShading: true });\n  const railMaterial = new MeshStandardMaterial({ color: palette.wood, flatShading: true });\n\n  const posts = Math.max(2, Math.round(length / spacing) + 1);\n  const step = length / (posts - 1);\n  for (let i = 0; i < posts; i++) {\n    const post = new Mesh(new CylinderGeometry(0.06, 0.075, height, 5), postMaterial);\n    post.position.set(-length / 2 + i * step, height / 2, rng.jitter(0, 0.03));\n    post.rotation.z = rng.range(-0.04, 0.04);\n    group.add(post);\n  }\n  for (const railY of [height * 0.55, height * 0.85]) {\n    const rail = new Mesh(new BoxGeometry(length, 0.07, 0.05), railMaterial);\n    rail.position.y = rng.jitter(railY, 0.02);\n    rail.rotation.x = rng.range(-0.02, 0.02);\n    group.add(rail);\n  }\n\n  return { object: group, obstacleRadius: length / 2 };\n}\n","import {\n  BoxGeometry,\n  CylinderGeometry,\n  Group,\n  Mesh,\n  MeshStandardMaterial,\n  PointLight,\n  SphereGeometry,\n} from 'three';\nimport { Rng } from '../core/random';\nimport { DEFAULT_PALETTE, type Palette } from '../core/palette';\nimport type { Prop } from '../core/types';\n\nexport interface LampOptions {\n  seed?: number;\n  height?: number;\n  /** Add a real PointLight. Off by default — lights are a budget. */\n  light?: boolean;\n  lightIntensity?: number;\n  palette?: Palette;\n}\n\n/** A street lamp: post, head, glowing bulb, optional real PointLight. */\nexport function createLamp(options: LampOptions = {}): Prop {\n  const rng = new Rng(options.seed ?? 1);\n  const palette = options.palette ?? DEFAULT_PALETTE;\n  const height = options.height ?? rng.range(2.6, 3.1);\n\n  const group = new Group();\n  group.name = 'lamp';\n  const metal = new MeshStandardMaterial({ color: palette.metal, flatShading: true });\n\n  const post = new Mesh(new CylinderGeometry(0.05, 0.08, height, 6), metal);\n  post.position.y = height / 2;\n  group.add(post);\n\n  const head = new Mesh(new BoxGeometry(0.34, 0.26, 0.34), metal);\n  head.position.y = height + 0.1;\n  group.add(head);\n\n  const bulb = new Mesh(\n    new SphereGeometry(0.11, 8, 6),\n    new MeshStandardMaterial({\n      color: palette.lampGlow,\n      emissive: palette.lampGlow,\n      emissiveIntensity: 1.6,\n    })\n  );\n  bulb.position.y = height - 0.03;\n  group.add(bulb);\n\n  if (options.light) {\n    const light = new PointLight(palette.lampGlow, options.lightIntensity ?? 6, 12, 1.8);\n    light.position.y = height - 0.05;\n    group.add(light);\n  }\n\n  return { object: group, obstacleRadius: 0.25 };\n}\n","import { ConeGeometry, Group, IcosahedronGeometry, Mesh, MeshStandardMaterial } from 'three';\nimport { Rng } from '../core/random';\nimport { DEFAULT_PALETTE, type Palette } from '../core/palette';\nimport type { WindField } from '../environment/wind';\nimport type { Prop } from '../core/types';\n\nexport interface GrassOptions {\n  seed?: number;\n  /** Blades per tuft. Default 4–6 by seed. */\n  blades?: number;\n  /** A WindField to sway the blades in. */\n  wind?: WindField;\n  palette?: Palette;\n}\n\n/**\n * A tuft of grass blades — pure scatter fodder (zero obstacle footprint,\n * walk straight through). Sways beautifully under `applyWind`.\n */\nexport function createGrassTuft(options: GrassOptions = {}): Prop {\n  const rng = new Rng(options.seed ?? 1);\n  const palette = options.palette ?? DEFAULT_PALETTE;\n  const blades = options.blades ?? rng.int(4, 6);\n  const group = new Group();\n  group.name = 'grass';\n  const material = new MeshStandardMaterial({\n    color: rng.next() < 0.5 ? palette.grassHigh : rng.pick(palette.foliage),\n    flatShading: true,\n  });\n  for (let i = 0; i < blades; i++) {\n    const height = rng.range(0.25, 0.5);\n    const blade = new Mesh(new ConeGeometry(0.035, height, 3), material);\n    blade.position.set(rng.jitter(0, 0.12), height / 2, rng.jitter(0, 0.12));\n    blade.rotation.set(rng.range(-0.25, 0.25), rng.range(0, Math.PI), rng.range(-0.25, 0.25));\n    group.add(blade);\n  }\n  // Whole-blade sway from near the base (soft, stiffness ~1.2).\n  if (options.wind) options.wind.sway(group, { height: 0.5, stiffness: 1.2, anchor: 0.04 });\n  return { object: group, obstacleRadius: 0 };\n}\n\nexport interface BushOptions {\n  seed?: number;\n  size?: number;\n  /** A WindField to gently sway the foliage in. */\n  wind?: WindField;\n  palette?: Palette;\n}\n\n/** A low foliage bush: two or three squashed blobs. Small footprint. */\nexport function createBush(options: BushOptions = {}): Prop {\n  const rng = new Rng(options.seed ?? 1);\n  const palette = options.palette ?? DEFAULT_PALETTE;\n  const size = options.size ?? rng.range(0.4, 0.7);\n  const group = new Group();\n  group.name = 'bush';\n  const material = new MeshStandardMaterial({ color: rng.pick(palette.foliage), flatShading: true });\n  const blobs = rng.int(2, 3);\n  for (let i = 0; i < blobs; i++) {\n    const radius = size * rng.range(0.55, 0.85);\n    const blob = new Mesh(new IcosahedronGeometry(radius, 0), material);\n    blob.position.set(rng.jitter(0, size * 0.4), radius * 0.7, rng.jitter(0, size * 0.4));\n    blob.scale.y = rng.range(0.7, 0.85);\n    blob.rotation.y = rng.range(0, Math.PI);\n    group.add(blob);\n  }\n  // Gentle, stiff sway — a bush barely nods.\n  if (options.wind) options.wind.sway(group, { height: size, stiffness: 2.2, anchor: size * 0.25 });\n  return { object: group, obstacleRadius: size * 0.6 };\n}\n","import {\n  BoxGeometry,\n  BufferAttribute,\n  BufferGeometry,\n  CylinderGeometry,\n  Group,\n  Mesh,\n  MeshStandardMaterial,\n} from 'three';\nimport { Rng } from '../core/random';\nimport { DEFAULT_PALETTE, type Palette } from '../core/palette';\nimport { createSurface } from '../materials/surface';\nimport type { Prop } from '../core/types';\n\n/** A gabled-roof prism: ridge along local z, base resting on y = 0. */\nfunction prismGeometry(width: number, height: number, depth: number): BufferGeometry {\n  const w = width / 2;\n  const d = depth / 2;\n  // prettier-ignore\n  const positions = new Float32Array([\n    // front gable (z = +d)\n    -w, 0, d,   w, 0, d,   0, height, d,\n    // back gable (z = -d)\n    w, 0, -d,  -w, 0, -d,   0, height, -d,\n    // left slope\n    -w, 0, -d,  -w, 0, d,   0, height, d,\n    -w, 0, -d,   0, height, d,   0, height, -d,\n    // right slope\n    w, 0, d,   w, 0, -d,   0, height, -d,\n    w, 0, d,   0, height, -d,   0, height, d,\n    // bottom\n    -w, 0, -d,   w, 0, -d,   w, 0, d,\n    -w, 0, -d,   w, 0, d,  -w, 0, d,\n  ]);\n  const geometry = new BufferGeometry();\n  geometry.setAttribute('position', new BufferAttribute(positions, 3));\n  geometry.computeVertexNormals();\n  return geometry;\n}\n\nexport type WallStyle = 'plaster' | 'brick' | 'ashlar';\nexport type RoofStyle = 'tile' | 'shingle' | 'thatch';\n\nexport interface HouseOptions {\n  seed?: number;\n  /** Footprint width (gable side). Default seeded 3.2–4.2. */\n  width?: number;\n  depth?: number;\n  wallHeight?: number;\n  /** Wall surface. Default seeded (mostly plaster, some brick / ashlar). */\n  wall?: WallStyle;\n  /** Roof surface. Default seeded (tile, wooden shingle or straw thatch). */\n  roof?: RoofStyle;\n  palette?: Palette;\n}\n\n// Seed-weighted so a row of houses varies without any caller doing the work.\nconst WALL_STYLES: WallStyle[] = ['plaster', 'plaster', 'plaster', 'brick', 'ashlar'];\nconst ROOF_STYLES: RoofStyle[] = ['tile', 'tile', 'shingle', 'thatch'];\n\n/**\n * A cottage: plastered walls, gabled roof, door, chimney and emissive\n * windows. Pass the house in `createDayCycle`'s `lamps` list and its\n * windows glow at night along with the street lamps. A stone foundation\n * extends below ground so sloped terrain never shows a gap.\n */\nexport function createHouse(options: HouseOptions = {}): Prop {\n  const rng = new Rng(options.seed ?? 1);\n  const palette = options.palette ?? DEFAULT_PALETTE;\n  const width = options.width ?? rng.range(3.2, 4.2);\n  const depth = options.depth ?? width * rng.range(0.75, 0.9);\n  const wallHeight = options.wallHeight ?? rng.range(2.1, 2.4);\n\n  const group = new Group();\n  group.name = 'house';\n  const seed = options.seed ?? 1;\n  // Procedural surfaces: walls (plaster / brick / ashlar), roof (clay tile /\n  // wooden shingle / straw thatch), weathered stone foundation, planked door —\n  // all detail generated in-shader. Style is seeded, so a street of houses\n  // varies on its own.\n  const wallStyle = options.wall ?? rng.pick(WALL_STYLES);\n  const roofStyle = options.roof ?? rng.pick(ROOF_STYLES);\n  const wallColor =\n    wallStyle === 'brick' ? 0x9e4a34 : wallStyle === 'ashlar' ? palette.rock[0] : palette.wall;\n  const wall = createSurface(wallStyle, { color: wallColor, seed });\n  wall.color.offsetHSL(0, 0, rng.range(-0.03, 0.03));\n  const roofColor =\n    roofStyle === 'thatch' ? 0xb39a5c : roofStyle === 'shingle' ? palette.woodDark : palette.roof;\n  const roof = createSurface(roofStyle, { color: roofColor, seed: seed + 7 });\n  roof.color.offsetHSL(0, 0, rng.range(-0.04, 0.04));\n  const stone = createSurface('stone', { color: palette.rock[0], seed: seed + 13 });\n  const wood = createSurface('plank', { color: palette.woodDark, seed: seed + 21 });\n\n  const foundation = new Mesh(new BoxGeometry(width + 0.3, 1.6, depth + 0.3), stone);\n  foundation.position.y = -0.55;\n  group.add(foundation);\n\n  const body = new Mesh(new BoxGeometry(width, wallHeight, depth), wall);\n  body.position.y = wallHeight / 2;\n  group.add(body);\n\n  const ridgeHeight = width * rng.range(0.32, 0.4);\n  const roofMesh = new Mesh(prismGeometry(width + 0.5, ridgeHeight, depth + 0.6), roof);\n  roofMesh.position.y = wallHeight - 0.02;\n  group.add(roofMesh);\n\n  const chimney = new Mesh(new BoxGeometry(0.34, ridgeHeight + 0.8, 0.34), stone);\n  chimney.position.set(rng.pick([-1, 1]) * width * 0.22, wallHeight + ridgeHeight * 0.45, depth * 0.12);\n  group.add(chimney);\n\n  // Door on the front face (+z).\n  const door = new Mesh(new BoxGeometry(0.85, 1.5, 0.08), wood);\n  door.position.set(rng.range(-0.4, 0.4), 0.75, depth / 2 + 0.02);\n  group.add(door);\n\n  // Emissive windows — createDayCycle treats these like lamp bulbs.\n  const glass = new MeshStandardMaterial({\n    color: palette.lampGlow,\n    emissive: palette.lampGlow,\n    emissiveIntensity: 1.0,\n  });\n  const windowGeometry = new BoxGeometry(0.6, 0.62, 0.08);\n  const front = new Mesh(windowGeometry, glass);\n  front.position.set(door.position.x < 0 ? width * 0.28 : -width * 0.28, 1.35, depth / 2 + 0.02);\n  group.add(front);\n  for (const side of [-1, 1]) {\n    if (rng.next() < 0.35) continue;\n    const pane = new Mesh(windowGeometry, glass);\n    pane.position.set(side * (width / 2 + 0.02), 1.35, rng.range(-0.3, 0.3) * depth);\n    pane.rotation.y = Math.PI / 2;\n    group.add(pane);\n  }\n\n  return { object: group, obstacleRadius: Math.hypot(width + 0.5, depth + 0.5) / 2 };\n}\n\nexport interface TowerOptions {\n  seed?: number;\n  height?: number;\n  palette?: Palette;\n}\n\n/** A wooden watchtower: splayed legs, platform with railing, pyramid roof. */\nexport function createTower(options: TowerOptions = {}): Prop {\n  const rng = new Rng(options.seed ?? 1);\n  const palette = options.palette ?? DEFAULT_PALETTE;\n  const height = options.height ?? rng.range(4.2, 5.2);\n\n  const group = new Group();\n  group.name = 'tower';\n  const seed = options.seed ?? 1;\n  const wood = createSurface('wood', { color: palette.wood, seed });\n  const woodDark = createSurface('wood', { color: palette.woodDark, seed: seed + 9 });\n  const roof = createSurface('tile', { color: palette.roof, seed: seed + 17 });\n\n  const spread = 1.0;\n  for (const x of [-1, 1]) {\n    for (const z of [-1, 1]) {\n      const leg = new Mesh(new CylinderGeometry(0.09, 0.12, height, 6), woodDark);\n      leg.position.set(x * spread * 0.75, height / 2 - 0.6, z * spread * 0.75);\n      leg.rotation.z = -x * 0.1;\n      leg.rotation.x = z * 0.1;\n      group.add(leg);\n    }\n  }\n  // Cross-braces.\n  for (const level of [0.3, 0.62]) {\n    const brace = new Mesh(new BoxGeometry(spread * 2.1, 0.09, 0.07), wood);\n    brace.position.set(0, height * level, spread * 0.82 * (1 - level * 0.35));\n    brace.rotation.z = rng.pick([-0.5, 0.5]);\n    group.add(brace);\n    const braceSide = new Mesh(new BoxGeometry(0.07, 0.09, spread * 2.1), wood);\n    braceSide.position.set(spread * 0.82 * (1 - level * 0.35), height * level, 0);\n    braceSide.rotation.x = rng.pick([-0.5, 0.5]);\n    group.add(braceSide);\n  }\n\n  const platform = new Mesh(new BoxGeometry(spread * 2.2, 0.14, spread * 2.2), wood);\n  platform.position.y = height - 0.5;\n  group.add(platform);\n  for (const x of [-1, 1]) {\n    for (const z of [-1, 1]) {\n      const post = new Mesh(new BoxGeometry(0.08, 0.9, 0.08), woodDark);\n      post.position.set(x * spread * 1.0, height - 0.05, z * spread * 1.0);\n      group.add(post);\n    }\n  }\n  for (const [rx, rz, w, d] of [\n    [0, 1, spread * 2.1, 0.06],\n    [0, -1, spread * 2.1, 0.06],\n    [1, 0, 0.06, spread * 2.1],\n    [-1, 0, 0.06, spread * 2.1],\n  ] as const) {\n    const rail = new Mesh(new BoxGeometry(w, 0.07, d), wood);\n    rail.position.set(rx * spread, height + 0.28, rz * spread);\n    group.add(rail);\n  }\n\n  const cap = new Mesh(new CylinderGeometry(0, spread * 1.55, 1.0, 4), roof);\n  cap.position.y = height + 1.15;\n  cap.rotation.y = Math.PI / 4;\n  group.add(cap);\n\n  return { object: group, obstacleRadius: spread * 1.35 };\n}\n\nexport interface WellOptions {\n  seed?: number;\n  palette?: Palette;\n}\n\n/** A stone well: ring, posts, little gabled roof, hanging bucket. */\nexport function createWell(options: WellOptions = {}): Prop {\n  const rng = new Rng(options.seed ?? 1);\n  const palette = options.palette ?? DEFAULT_PALETTE;\n\n  const group = new Group();\n  group.name = 'well';\n  const seed = options.seed ?? 1;\n  // A little moss on the old rim, thin (high capUp) so only the very tops take.\n  const stone = createSurface('stone', {\n    color: rng.pick(palette.rock),\n    seed,\n    cap: 0.4,\n    capColor: 0x445a2e,\n    capUp: 0.5,\n  });\n  const wood = createSurface('wood', { color: palette.woodDark, seed: seed + 5 });\n  const roof = createSurface('tile', { color: palette.roof, seed: seed + 11 });\n\n  const ring = new Mesh(new CylinderGeometry(0.85, 0.95, 0.75, 10), stone);\n  ring.position.y = 0.375;\n  group.add(ring);\n  const inner = new Mesh(\n    new CylinderGeometry(0.62, 0.62, 0.05, 10),\n    new MeshStandardMaterial({ color: 0x16222e })\n  );\n  inner.position.y = 0.76;\n  group.add(inner);\n\n  for (const side of [-1, 1]) {\n    const post = new Mesh(new CylinderGeometry(0.06, 0.075, 1.9, 5), wood);\n    post.position.set(side * 0.72, 0.95, 0);\n    group.add(post);\n  }\n  const bar = new Mesh(new CylinderGeometry(0.045, 0.045, 1.5, 5), wood);\n  bar.rotation.z = Math.PI / 2;\n  bar.position.y = 1.72;\n  group.add(bar);\n\n  const cap = new Mesh(prismGeometry(2.0, 0.55, 0.65), roof);\n  cap.position.y = 1.86;\n  cap.rotation.y = Math.PI / 2;\n  group.add(cap);\n\n  const rope = new Mesh(new CylinderGeometry(0.012, 0.012, 0.6, 4), wood);\n  rope.position.y = 1.42;\n  group.add(rope);\n  const bucket = new Mesh(new CylinderGeometry(0.13, 0.1, 0.2, 7), wood);\n  bucket.position.y = 1.05;\n  group.add(bucket);\n\n  return { object: group, obstacleRadius: 1.0 };\n}\n\nexport interface RuinOptions {\n  seed?: number;\n  /** Footprint width. Default seeded 3.5–5. */\n  size?: number;\n  /** Moss reclaiming the up-facing stone. Default true. */\n  mossy?: boolean;\n  palette?: Palette;\n}\n\n/**\n * A ruined building: a partial rectangle of crumbling wall segments with\n * seeded gaps and heights, and tumbled blocks around the floor.\n */\nexport function createRuin(options: RuinOptions = {}): Prop {\n  const rng = new Rng(options.seed ?? 1);\n  const palette = options.palette ?? DEFAULT_PALETTE;\n  const size = options.size ?? rng.range(3.5, 5);\n  const depth = size * rng.range(0.7, 0.9);\n\n  const group = new Group();\n  group.name = 'ruin';\n  // Abandoned stone, reclaimed by moss on the up-facing tops and shoulders.\n  const mossy = options.mossy ?? true;\n  const stone = createSurface('stone', {\n    color: rng.pick(palette.rock),\n    seed: options.seed ?? 1,\n    ...(mossy ? { cap: 0.6, capColor: 0x415a2a, capUp: 0.3, capSharp: 0.32 } : {}),\n  });\n  stone.color.offsetHSL(0, 0, rng.range(-0.04, 0.02));\n\n  const thickness = 0.35;\n  // Wall runs: [centerX, centerZ, length, alongX]. Front wall mostly gone.\n  const runs: Array<[number, number, number, boolean]> = [\n    [0, -depth / 2, size, true],\n    [-size / 2, 0, depth, false],\n    [size / 2, 0, depth, false],\n    [size * 0.3, depth / 2, size * 0.35, true],\n  ];\n  for (const [cx, cz, length, alongX] of runs) {\n    const segments = Math.max(2, Math.round(length / 1.1));\n    const step = length / segments;\n    for (let i = 0; i < segments; i++) {\n      if (rng.next() < 0.22) continue; // collapsed gap\n      const height = rng.range(0.5, 2.2);\n      const wall = new Mesh(\n        new BoxGeometry(alongX ? step * 0.96 : thickness, height, alongX ? thickness : step * 0.96),\n        stone\n      );\n      const offset = -length / 2 + step * (i + 0.5);\n      wall.position.set(alongX ? cx + offset : cx, height / 2, alongX ? cz : cz + offset);\n      wall.rotation.y = rng.range(-0.03, 0.03);\n      group.add(wall);\n    }\n  }\n  // Tumbled blocks.\n  const blocks = rng.int(4, 7);\n  for (let i = 0; i < blocks; i++) {\n    const s = rng.range(0.25, 0.55);\n    const block = new Mesh(new BoxGeometry(s, s * rng.range(0.6, 1), s * rng.range(0.7, 1.2)), stone);\n    block.position.set(rng.range(-size * 0.6, size * 0.6), s * 0.3, rng.range(-depth * 0.6, depth * 0.7));\n    block.rotation.set(rng.range(-0.3, 0.3), rng.range(0, Math.PI), rng.range(-0.3, 0.3));\n    group.add(block);\n  }\n\n  return { object: group, obstacleRadius: Math.hypot(size, depth) / 2 };\n}\n","import {\n  BoxGeometry,\n  CylinderGeometry,\n  Group,\n  IcosahedronGeometry,\n  Mesh,\n  MeshStandardMaterial,\n  type BufferGeometry,\n  type Material,\n} from 'three';\nimport { Rng } from '../core/random';\nimport { DEFAULT_PALETTE, type Palette } from '../core/palette';\nimport { createSurface } from '../materials/surface';\nimport { sharedBy } from '../materials/shared';\nimport type { Prop } from '../core/types';\n\nexport type StallGoods = 'produce' | 'pottery' | 'bakery' | 'textiles';\n\nexport interface StallOptions {\n  seed?: number;\n  /** What the stall sells. Default seeded. */\n  goods?: StallGoods;\n  /** Awning fabric colour (the coloured stripe). Default seeded. */\n  clothColor?: number;\n  palette?: Palette;\n}\n\n// Awning stripe colours (the pale stripe is shared cream). Market-canvas hues.\nconst CLOTH_COLORS = [0xb5372f, 0x2f5fa8, 0x3f7a4a, 0xc98a2f, 0x7a3f6a, 0x2f8f8a];\nconst CLOTH_CREAM = 0xe8dcc0;\nconst FRUIT_COLORS = [0xc0392b, 0xe0812c, 0x9ab52f, 0x7a3f6a, 0xe0c23c, 0xd05a2f];\nconst BREAD_COLORS = [0xc79a5b, 0xb5854a, 0xd8b477];\n\nconst ALL_GOODS: StallGoods[] = ['produce', 'pottery', 'bakery', 'textiles'];\n\n/**\n * A market stall: four posts, a forward-sloping striped canvas awning with a\n * fringed valance, a plank counter and back shelf, stocked with seeded goods.\n * Four trades — `produce`, `pottery`, `bakery`, `textiles` — each stocks the\n * counter differently, so a market row reads as a bustling variety rather\n * than one stall repeated.\n */\nexport function createStall(options: StallOptions = {}): Prop {\n  const rng = new Rng(options.seed ?? 1);\n  const palette = options.palette ?? DEFAULT_PALETTE;\n  const seed = options.seed ?? 1;\n  const goods = options.goods ?? rng.pick(ALL_GOODS);\n  const clothColor = options.clothColor ?? rng.pick(CLOTH_COLORS);\n\n  const group = new Group();\n  group.name = 'stall';\n\n  const wood = createSurface('wood', { color: palette.woodDark, seed });\n  const plank = createSurface('plank', { color: palette.wood, seed: seed + 3 });\n  const stripe = new MeshStandardMaterial({ color: clothColor, roughness: 0.95, flatShading: true });\n  const cream = new MeshStandardMaterial({ color: CLOTH_CREAM, roughness: 0.95, flatShading: true });\n  // The goods are drawn from small colour palettes, so a material built per\n  // loaf or per bolt is mostly a duplicate of the last one. One per COLOUR,\n  // cached for this stall only — see `sharedBy` for why not at module scope.\n  const matte = sharedBy(matteMaterial);\n\n  const W = 2.6; // width (x)\n  const D = 1.7; // depth (z), front at +D/2\n  const backH = 2.5;\n  const frontH = 2.05;\n\n  // Four posts (front pair shorter → the awning sheds forward).\n  for (const sx of [-1, 1]) {\n    for (const sz of [-1, 1]) {\n      const h = sz < 0 ? backH : frontH;\n      const post = new Mesh(new CylinderGeometry(0.055, 0.07, h, 6), wood);\n      post.position.set(sx * (W / 2 - 0.1), h / 2, sz * (D / 2 - 0.1));\n      group.add(post);\n    }\n  }\n\n  // Sloping striped awning: strips run front-to-back across the width.\n  const overhang = 0.32;\n  const backZ = -D / 2 + 0.05;\n  const frontZ = D / 2 + overhang;\n  const dz = frontZ - backZ;\n  const dy = frontH + 0.06 - (backH + 0.06);\n  const slopeLen = Math.hypot(dz, dy);\n  const tilt = Math.atan2(backH - frontH, dz); // +ve: front edge dips\n  const midZ = (backZ + frontZ) / 2;\n  const midY = (backH + frontH) / 2 + 0.06;\n  const strips = 11;\n  const stripW = (W + 0.5) / strips;\n  for (let i = 0; i < strips; i++) {\n    const canvas = new Mesh(\n      new BoxGeometry(stripW * 0.97, 0.04, slopeLen),\n      i % 2 === 0 ? stripe : cream\n    );\n    canvas.position.set(-((W + 0.5) / 2) + stripW * (i + 0.5), midY, midZ);\n    canvas.rotation.x = tilt;\n    group.add(canvas);\n    // Fringed valance hanging off the front edge, continuing the stripe.\n    const fringe = new Mesh(new BoxGeometry(stripW * 0.97, 0.2, 0.03), i % 2 === 0 ? stripe : cream);\n    fringe.position.set(canvas.position.x, frontH - 0.04, frontZ);\n    group.add(fringe);\n  }\n\n  // Plank counter at the front, and a back shelf.\n  const counter = new Group();\n  const top = new Mesh(new BoxGeometry(W - 0.1, 0.09, 0.62), plank);\n  top.position.set(0, 0.96, D / 2 - 0.42);\n  counter.add(top);\n  const apron = new Mesh(new BoxGeometry(W - 0.1, 0.5, 0.05), plank);\n  apron.position.set(0, 0.68, D / 2 - 0.12);\n  counter.add(apron);\n  group.add(counter);\n\n  const shelf = new Mesh(new BoxGeometry(W - 0.3, 0.07, 0.28), plank);\n  shelf.position.set(0, 1.45, -D / 2 + 0.22);\n  group.add(shelf);\n\n  // Stock the counter (and, for some trades, the ground) by trade.\n  const counterY = 1.05;\n  const spanX = W - 0.7;\n  const acrossCounter = (n: number): number[] =>\n    Array.from({ length: n }, (_, i) => -spanX / 2 + (spanX * (i + 0.5)) / n + rng.jitter(0, 0.05));\n\n  if (goods === 'produce') {\n    for (const x of acrossCounter(3)) {\n      group.add(basket(rng, x, counterY, D / 2 - 0.42, palette, seed));\n      fruitPile(rng, x, counterY + 0.16, D / 2 - 0.42, matte).forEach((f) => group.add(f));\n    }\n  } else if (goods === 'bakery') {\n    for (const x of acrossCounter(3)) {\n      group.add(basket(rng, x, counterY, D / 2 - 0.42, palette, seed));\n      for (let k = 0; k < rng.int(3, 5); k++) {\n        const loaf = new Mesh(roundedLoaf(), matte(rng.pick(BREAD_COLORS)));\n        loaf.position.set(x + rng.jitter(0, 0.09), counterY + 0.17, D / 2 - 0.42 + rng.jitter(0, 0.09));\n        loaf.rotation.y = rng.range(0, Math.PI);\n        group.add(loaf);\n      }\n    }\n  } else if (goods === 'pottery') {\n    const terracotta = createSurface('tile', { color: 0xb5623f, seed: seed + 5 });\n    for (const x of acrossCounter(4)) {\n      group.add(urn(rng, x, counterY, D / 2 - 0.42, terracotta));\n    }\n    // Big urns on the ground beside the stall.\n    for (let k = 0; k < rng.int(2, 3); k++) {\n      const scale = rng.range(1.6, 2.3);\n      const big = urn(rng, rng.pick([-1, 1]) * (W / 2 + rng.range(0.2, 0.5)), 0, rng.range(-0.3, 0.5), terracotta);\n      big.scale.setScalar(scale);\n      group.add(big);\n    }\n  } else {\n    // textiles: stacked folded bolts + a couple of rolls.\n    for (const x of acrossCounter(3)) {\n      let y = counterY;\n      for (let k = 0, n = rng.int(2, 4); k < n; k++) {\n        const bolt = new Mesh(new BoxGeometry(0.5, 0.12, 0.42), matte(rng.pick(CLOTH_COLORS)));\n        bolt.position.set(x + rng.jitter(0, 0.04), y + 0.06, D / 2 - 0.42);\n        bolt.rotation.y = rng.jitter(0, 0.08);\n        group.add(bolt);\n        y += 0.13;\n      }\n    }\n    for (let k = 0; k < 2; k++) {\n      const roll = new Mesh(new CylinderGeometry(0.11, 0.11, 0.5, 8), matte(rng.pick(CLOTH_COLORS)));\n      roll.rotation.z = Math.PI / 2;\n      roll.position.set(rng.range(-spanX / 2, spanX / 2), 1.52, -D / 2 + 0.22);\n      group.add(roll);\n    }\n  }\n\n  return { object: group, obstacleRadius: Math.hypot(W, D) / 2 };\n}\n\n// ---- goods helpers -----------------------------------------------------\n\nfunction matteMaterial(color: number): MeshStandardMaterial {\n  return new MeshStandardMaterial({ color, roughness: 0.85, flatShading: true });\n}\n\nfunction basket(rng: Rng, x: number, y: number, z: number, palette: Palette, seed: number): Mesh {\n  // A weathering seed per basket, so three baskets on one counter do not look\n  // stamped out. They ARE three materials and that is deliberate — the seed\n  // reaches the shader as `uSurfSeed`, which is why `npm run geometry` reads\n  // the surface uniform bag rather than trusting the standard fields.\n  const b = new Mesh(\n    new CylinderGeometry(0.2, 0.16, 0.2, 9),\n    createSurface('wood', { color: palette.wood, seed: seed + Math.floor(x * 100) })\n  );\n  b.position.set(x, y + 0.1, z + rng.jitter(0, 0.03));\n  return b;\n}\n\nfunction fruitPile(\n  rng: Rng,\n  x: number,\n  y: number,\n  z: number,\n  matte: (color: number) => Material\n): Mesh[] {\n  const mat = matte(rng.pick(FRUIT_COLORS));\n  const out: Mesh[] = [];\n  const n = rng.int(5, 8);\n  for (let i = 0; i < n; i++) {\n    const r = rng.range(0.05, 0.075);\n    const fruit = new Mesh(new IcosahedronGeometry(r, 0), mat);\n    const a = (i / n) * Math.PI * 2;\n    const ring = i === 0 ? 0 : rng.range(0.04, 0.13);\n    fruit.position.set(x + Math.cos(a) * ring, y + (i === 0 ? 0.05 : rng.range(-0.02, 0.02)), z + Math.sin(a) * ring);\n    out.push(fruit);\n  }\n  return out;\n}\n\nfunction roundedLoaf(): BufferGeometry {\n  const g = new BoxGeometry(0.22, 0.12, 0.14, 1, 1, 1);\n  return g; // low-poly loaf; kept boxy on purpose for the flat-shaded look\n}\n\nfunction urn(rng: Rng, x: number, y: number, z: number, mat: Material): Group {\n  const g = new Group();\n  const h = rng.range(0.22, 0.34);\n  const body = new Mesh(new CylinderGeometry(0.1, 0.07, h, 9), mat);\n  body.position.y = h / 2;\n  g.add(body);\n  const shoulder = new Mesh(new CylinderGeometry(0.06, 0.11, h * 0.35, 9), mat);\n  shoulder.position.y = h + h * 0.15;\n  g.add(shoulder);\n  const neck = new Mesh(new CylinderGeometry(0.055, 0.05, 0.06, 8), mat);\n  neck.position.y = h + h * 0.35;\n  g.add(neck);\n  g.position.set(x + rng.jitter(0, 0.03), y, z + rng.jitter(0, 0.03));\n  g.rotation.y = rng.range(0, Math.PI);\n  return g;\n}\n","import type { Material } from 'three';\n\n/**\n * Build a material once per distinct key, not once per part.\n *\n * A prop that decorates a shelf with eight loaves, or glazes a balcony with\n * seven identical panes, naturally writes the material construction inside the\n * loop. Every iteration then allocates a `MeshStandardMaterial` that is\n * byte-identical to the last one — the renderer binds each separately, they\n * cannot be batched, and changing one afterwards changes exactly one pane.\n *\n * `npm run geometry` counts them: a bungalow shipped 25 material instances for\n * 13 distinct materials, and a stall 18 for 8.\n *\n * ```ts\n * const matte = sharedBy((color: number) =>\n *   new MeshStandardMaterial({ color, roughness: 0.85, flatShading: true }));\n * for (const loaf of loaves) meshes.push(new Mesh(geo, matte(loaf.color)));\n * ```\n *\n * ## Call it inside the factory, never at module scope\n *\n * The cache has to live for one prop, so build it where the prop is built. A\n * module-level cache would hand the same material to every crate in the world,\n * and the first game to tint one crate would tint all of them — the sharing\n * would stop being an optimisation and become a surprise.\n *\n * ## And not for anything animated\n *\n * A material that owns a time uniform must not be shared, or every copy moves\n * in unison. Those carry their state as `userData.*Uniforms`, which is both\n * how they stay unshared and how the gate knows to exempt them.\n */\nexport function sharedBy<K, M extends Material>(make: (key: K) => M): (key: K) => M {\n  const cache = new Map<K, M>();\n  return (key: K): M => {\n    let material = cache.get(key);\n    if (!material) {\n      material = make(key);\n      cache.set(key, material);\n    }\n    return material;\n  };\n}\n","import {\n  BufferAttribute,\n  BufferGeometry,\n  Color,\n  ConeGeometry,\n  CylinderGeometry,\n  Group,\n  Mesh,\n  MeshStandardMaterial,\n  SphereGeometry,\n} from 'three';\nimport { Rng } from '../core/random';\nimport { DEFAULT_PALETTE, type Palette } from '../core/palette';\nimport { createSurface } from '../materials/surface';\nimport { wavingClothMaterial } from '../materials/clothWave';\nimport type { Prop } from '../core/types';\n\nexport type BannerStyle = 'flag' | 'banner' | 'pennant';\nexport type BannerPattern =\n  | 'solid'\n  | 'bands'\n  | 'stripes'\n  | 'bicolor'\n  | 'cross'\n  | 'saltire'\n  | 'diamond';\n\nexport interface BannerOptions {\n  seed?: number;\n  /** flag (flies from a pole), banner (hangs from a crossbar), pennant (triangular). */\n  style?: BannerStyle;\n  /** Heraldic device. Default seeded. */\n  pattern?: BannerPattern;\n  /** Field colour and charge colour (hex). Default seeded from a heraldic set. */\n  colors?: [number, number];\n  /** Pole height in metres. Default seeded ~3.2–3.8. */\n  poleHeight?: number;\n  /** Wind strength (ripple amplitude multiplier). Default 1. */\n  wind?: number;\n  palette?: Palette;\n}\n\n// Heraldic tinctures — gules, azure, or, argent, vert, sable, purpure.\nconst TINCTURES = [0xb5372f, 0x2f5fa8, 0xd8a93c, 0xe8dcc0, 0x2f7a4a, 0x2a2a2e, 0x6a3f7a];\nconst ALL_STYLES: BannerStyle[] = ['flag', 'banner', 'pennant'];\nconst ALL_PATTERNS: BannerPattern[] = ['solid', 'bands', 'stripes', 'bicolor', 'cross', 'saltire', 'diamond'];\n\n/**\n * A flag, banner or pennant on a pole — real cloth, not a stiff board. The\n * fabric is a subdivided plane rippled by a GPU vertex wave: a travelling\n * fold that grows from the fixed edge to the free fly, droops under its own\n * weight, and carries a seeded phase so a row of flags never waves in\n * lockstep. Flat-shaded facets catch the light of each fold, and the whole\n * thing animates itself from the render loop — no per-frame wiring, so it\n * works dropped straight into `scatter` or a village. Heraldic devices\n * (cross, saltire, bands, diamond…) are baked as vertex colours, so there\n * are no textures to fetch.\n */\nexport function createBanner(options: BannerOptions = {}): Prop {\n  const rng = new Rng(options.seed ?? 1);\n  const palette = options.palette ?? DEFAULT_PALETTE;\n  const seed = options.seed ?? 1;\n  const style = options.style ?? rng.pick(ALL_STYLES);\n  const pattern = options.pattern ?? rng.pick(ALL_PATTERNS);\n  const wind = options.wind ?? 1;\n  const poleH = options.poleHeight ?? rng.range(3.2, 3.8);\n\n  // Two contrasting tinctures.\n  let c1 = options.colors?.[0];\n  let c2 = options.colors?.[1];\n  if (c1 === undefined || c2 === undefined) {\n    c1 = rng.pick(TINCTURES);\n    do {\n      c2 = rng.pick(TINCTURES);\n    } while (c2 === c1);\n  }\n\n  const group = new Group();\n  group.name = 'banner';\n\n  // --- Pole + finial (and crossbar for a hanging banner).\n  const pole = new Mesh(\n    new CylinderGeometry(0.045, 0.06, poleH, 8),\n    createSurface('wood', { color: palette.woodDark, seed })\n  );\n  pole.position.y = poleH / 2;\n  group.add(pole);\n  const gold = createSurface('metal', { color: 0xd8a93c, tint: 0x7a5a1f, tintAmount: 0.3, seed: seed + 2 });\n  const finial = new Mesh(new ConeGeometry(0.075, 0.28, 8), gold);\n  finial.position.y = poleH + 0.14;\n  group.add(finial);\n  const knob = new Mesh(new SphereGeometry(0.06, 8, 6), gold);\n  knob.position.y = poleH;\n  group.add(knob);\n\n  // --- Cloth dimensions per style (free = length along the wave, cross = span).\n  let freeLen: number;\n  let crossLen: number;\n  let geometry: BufferGeometry;\n  if (style === 'pennant') {\n    freeLen = rng.range(2.0, 2.6);\n    crossLen = rng.range(0.6, 0.8);\n    geometry = clothGrid(freeLen, crossLen, 20, 5, 'taper');\n  } else if (style === 'banner') {\n    freeLen = rng.range(1.9, 2.4); // hangs down\n    crossLen = rng.range(1.0, 1.3);\n    geometry = clothGrid(freeLen, crossLen, 16, 9, 'swallow');\n  } else {\n    freeLen = rng.range(1.5, 1.9);\n    crossLen = rng.range(0.95, 1.15);\n    geometry = clothGrid(freeLen, crossLen, 16, 9, 'rect');\n  }\n  paintPattern(geometry, freeLen, crossLen, pattern, new Color(c1), new Color(c2));\n\n  const clothMat = wavingCloth(freeLen, crossLen, wind, style, seed);\n  const cloth = new Mesh(geometry, clothMat);\n  // Self-animate from the render loop: the shared uniform is advanced just\n  // before the cloth draws, so a banner ripples with no per-frame wiring —\n  // even inside scatter or a village that never calls an update().\n  const waveUniforms = clothMat.userData.waveUniforms as { uTime: { value: number } };\n  cloth.onBeforeRender = () => {\n    waveUniforms.uTime.value = performance.now() * 0.001;\n  };\n  if (style === 'banner') {\n    // Crossbar along world X, cloth hangs beneath it.\n    const crossbar = new Mesh(\n      new CylinderGeometry(0.035, 0.035, crossLen + 0.3, 7),\n      createSurface('wood', { color: palette.woodDark, seed: seed + 4 })\n    );\n    crossbar.rotation.z = Math.PI / 2;\n    crossbar.position.y = poleH - 0.12;\n    group.add(crossbar);\n    cloth.rotation.z = -Math.PI / 2; // local +X (free) → world −Y (down)\n    cloth.position.set(0, poleH - 0.16, 0);\n  } else {\n    // Flag/pennant: fixed edge at the pole, flies along +X.\n    cloth.position.set(0.05, poleH - 0.2 - crossLen / 2, 0);\n  }\n  group.add(cloth);\n\n  return { object: group, obstacleRadius: 0.4 };\n}\n\n// ---- cloth geometry ----------------------------------------------------\n\ntype ClothShape = 'rect' | 'taper' | 'swallow';\n\n/**\n * A subdivided cloth in the XY plane: x from 0 (fixed edge) to freeLen (fly),\n * y centred on 0. `taper` converges to a point (pennant); `swallow` cuts a V\n * into the fly edge (swallow-tailed banner).\n */\nfunction clothGrid(freeLen: number, crossLen: number, segF: number, segC: number, shape: ClothShape): BufferGeometry {\n  const geo = new BufferGeometry();\n  const cols = segF + 1;\n  const rows = segC + 1;\n  const pos = new Float32Array(cols * rows * 3);\n  const uv = new Float32Array(cols * rows * 2);\n  for (let i = 0; i < cols; i++) {\n    const u = i / segF; // 0 at fixed edge → 1 at fly\n    let half = crossLen / 2;\n    if (shape === 'taper') half = (crossLen / 2) * (1 - u * 0.94); // triangle\n    for (let j = 0; j < rows; j++) {\n      const v = j / segC; // 0..1 across\n      const idx = i * rows + j;\n      let x = u * freeLen;\n      if (shape === 'swallow') {\n        const edge = Math.abs(v - 0.5) * 2; // 0 centre → 1 rim\n        const cut = Math.max(0, (u - 0.7) / 0.3);\n        x = u * freeLen - cut * cut * (1 - edge) * crossLen * 0.5;\n      }\n      const y = (v - 0.5) * half * 2;\n      pos[idx * 3] = x;\n      pos[idx * 3 + 1] = y;\n      pos[idx * 3 + 2] = 0;\n      uv[idx * 2] = u;\n      uv[idx * 2 + 1] = v;\n    }\n  }\n  const index: number[] = [];\n  for (let i = 0; i < segF; i++) {\n    for (let j = 0; j < segC; j++) {\n      const a = i * rows + j;\n      const b = (i + 1) * rows + j;\n      const c = (i + 1) * rows + (j + 1);\n      const d = i * rows + (j + 1);\n      index.push(a, b, d, b, c, d);\n    }\n  }\n  geo.setAttribute('position', new BufferAttribute(pos, 3));\n  geo.setAttribute('uv', new BufferAttribute(uv, 2));\n  geo.setIndex(index);\n  geo.computeVertexNormals();\n  return geo;\n}\n\n/** Bake a heraldic device into per-vertex colours. */\nfunction paintPattern(\n  geo: BufferGeometry,\n  freeLen: number,\n  crossLen: number,\n  pattern: BannerPattern,\n  a: Color,\n  b: Color\n): void {\n  const uvAttr = geo.getAttribute('uv');\n  const colors = new Float32Array(uvAttr.count * 3);\n  const pick = (u: number, v: number): Color => {\n    switch (pattern) {\n      case 'bicolor':\n        return u < 0.5 ? a : b;\n      case 'bands':\n        return Math.floor(v * 3) % 2 === 0 ? a : b;\n      case 'stripes':\n        return Math.floor(u * 5) % 2 === 0 ? a : b;\n      case 'cross':\n        return Math.abs(v - 0.5) < 0.16 || Math.abs(u - 0.42) < 0.14 ? b : a;\n      case 'saltire':\n        return Math.abs(u - v) < 0.17 || Math.abs(u - (1 - v)) < 0.17 ? b : a;\n      case 'diamond':\n        return Math.abs(u - 0.5) + Math.abs(v - 0.5) < 0.3 ? b : a;\n      default:\n        return a;\n    }\n  };\n  for (let i = 0; i < uvAttr.count; i++) {\n    const c = pick(uvAttr.getX(i), uvAttr.getY(i));\n    colors[i * 3] = c.r;\n    colors[i * 3 + 1] = c.g;\n    colors[i * 3 + 2] = c.b;\n  }\n  geo.setAttribute('color', new BufferAttribute(colors, 3));\n}\n\n// ---- waving cloth material --------------------------------------------\n\n/**\n * A double-sided, flat-shaded, vertex-coloured cloth rippled in the shader —\n * built on the shared cloth-wave material (also used by bunting).\n */\nfunction wavingCloth(\n  freeLen: number,\n  crossLen: number,\n  wind: number,\n  style: BannerStyle,\n  seed: number\n): MeshStandardMaterial {\n  return wavingClothMaterial({\n    freeLen,\n    crossLen,\n    amp: (style === 'pennant' ? 0.16 : 0.13) * wind,\n    waves: style === 'pennant' ? 7.0 : 5.0,\n    speed: 3.4 + (seed % 7) * 0.12,\n    sag: style === 'banner' ? 0 : 0.14,\n    phase: (seed % 100) * 0.183,\n    cacheKey: 'scena-banner-v1',\n    vertexColors: true,\n  });\n}\n","import { Color, DoubleSide, MeshStandardMaterial } from 'three';\n\n/**\n * The shared cloth-wave material behind flags, banners and bunting: a plain\n * flat-shaded MeshStandardMaterial whose vertices are rippled in the shader\n * by a travelling fold that grows from the fixed edge (x = 0) to the free fly\n * (x = freeLen), droops under gravity, and shortens as it slackens. Because\n * it stays a standard material, PBR lighting, fog and flatShading (which\n * relights the folds from the displaced positions) all keep working.\n *\n * Phase comes either from a uniform (one flag) or a per-vertex `aPhase`\n * attribute (a whole string of bunting in one draw call), so a row never\n * waves in lockstep. The `uTime` uniform is exposed on\n * `material.userData.waveUniforms` for the caller to advance from the render\n * loop.\n */\nexport interface ClothWaveOptions {\n  /** Length from the fixed edge to the free fly (local +X). */\n  freeLen: number;\n  /** Span across the cloth (local Y). */\n  crossLen: number;\n  /** Ripple amplitude. */\n  amp: number;\n  /** Number of folds along the free length. */\n  waves: number;\n  /** Wave travel speed. */\n  speed: number;\n  /** Gravity droop toward the fly (0 for cloth that already hangs). */\n  sag: number;\n  /** Fixed phase offset (ignored when perVertexPhase is set). */\n  phase?: number;\n  /** Take the phase from a per-vertex `aPhase` attribute instead. */\n  perVertexPhase?: boolean;\n  /** Program cache key — keeps this family from colliding with other patches. */\n  cacheKey: string;\n  /** Read a baked per-vertex `color` attribute (heraldic devices). */\n  vertexColors?: boolean;\n  /** Base colour when not vertex-coloured. */\n  color?: number | Color;\n  roughness?: number;\n}\n\nexport function wavingClothMaterial(o: ClothWaveOptions): MeshStandardMaterial {\n  const material = new MeshStandardMaterial({\n    color: o.color ?? 0xffffff,\n    vertexColors: o.vertexColors ?? false,\n    flatShading: true,\n    side: DoubleSide,\n    roughness: o.roughness ?? 0.92,\n    metalness: 0,\n  });\n\n  const uniforms: Record<string, { value: number }> = {\n    uTime: { value: 0 },\n    uAmp: { value: o.amp },\n    uFreeLen: { value: o.freeLen },\n    uCrossLen: { value: o.crossLen },\n    uWaves: { value: o.waves },\n    uSpeed: { value: o.speed },\n    uSag: { value: o.sag },\n  };\n  if (!o.perVertexPhase) uniforms.uPhase = { value: o.phase ?? 0 };\n\n  const phaseDecl = o.perVertexPhase ? 'attribute float aPhase;' : '';\n  const uniformList = o.perVertexPhase\n    ? 'uniform float uTime, uAmp, uFreeLen, uCrossLen, uWaves, uSpeed, uSag;'\n    : 'uniform float uTime, uAmp, uFreeLen, uCrossLen, uWaves, uSpeed, uSag, uPhase;';\n  const phaseExpr = o.perVertexPhase ? 'aPhase' : 'uPhase';\n\n  material.onBeforeCompile = (shader) => {\n    Object.assign(shader.uniforms, uniforms);\n    shader.vertexShader = shader.vertexShader\n      .replace('#include <common>', `#include <common>\\n${phaseDecl}\\n${uniformList}`)\n      .replace(\n        '#include <begin_vertex>',\n        `#include <begin_vertex>\n        {\n          float uf = clamp(position.x / uFreeLen, 0.0, 1.0);   // 0 fixed → 1 fly\n          float vc = position.y / uCrossLen + 0.5;              // 0..1 across\n          float base = uf * uWaves - uTime * uSpeed + ${phaseExpr};\n          float a = uAmp * uf;                                  // pinned at the fixed edge\n          float z = a * (sin(base + vc * 1.7) + 0.35 * sin(base * 2.3 + vc * 3.1 + 1.0));\n          transformed.z += z;\n          transformed.y -= uSag * uf * uf;                      // gravity droop\n          transformed.x -= uAmp * 0.25 * uf * (1.0 - cos(base));// slack shortening\n        }`\n      );\n    // flatShading recomputes normals from the displaced positions, so the\n    // folds are lit correctly with no analytic-normal maths.\n  };\n  material.customProgramCacheKey = () => o.cacheKey;\n  material.userData.waveUniforms = uniforms;\n\n  return material;\n}\n","import {\n  AdditiveBlending,\n  BufferAttribute,\n  BufferGeometry,\n  Color,\n  CylinderGeometry,\n  DoubleSide,\n  Group,\n  IcosahedronGeometry,\n  Mesh,\n  MeshStandardMaterial,\n  Points,\n  PointLight,\n  ShaderMaterial,\n} from 'three';\nimport { Rng } from '../core/random';\nimport { DEFAULT_PALETTE, type Palette } from '../core/palette';\nimport { createSurface } from '../materials/surface';\nimport type { Prop } from '../core/types';\n\nexport interface FireOptions {\n  seed?: number;\n  /** Add a flickering warm PointLight. Default true. */\n  light?: boolean;\n  /** Overall flame scale multiplier. Default 1. */\n  scale?: number;\n  palette?: Palette;\n}\n\n// ---- flame geometry (hand-merged so we need no BufferGeometryUtils) ----\n\ninterface Tongue {\n  cx: number;\n  cz: number;\n  r: number;\n  h: number;\n  phase: number;\n}\n\n/**\n * Merge several tapering \"tongues\" into one flame mesh. Each vertex carries\n * `aY` (0 at the base, 1 at the tip) and `aPhase` (per tongue), which the\n * shader uses to wobble the tips and flicker the height.\n */\nfunction flameGeometry(tongues: Tongue[], R = 5): BufferGeometry {\n  const position: number[] = [];\n  const aY: number[] = [];\n  const aPhase: number[] = [];\n  const index: number[] = [];\n  for (const t of tongues) {\n    const base = position.length / 3;\n    const rings = [\n      { y: 0, rad: t.r },\n      { y: t.h * 0.5, rad: t.r * 0.62 },\n    ];\n    for (const ring of rings) {\n      for (let i = 0; i < R; i++) {\n        const a = (i / R) * Math.PI * 2;\n        position.push(t.cx + Math.cos(a) * ring.rad, ring.y, t.cz + Math.sin(a) * ring.rad);\n        aY.push(ring.y / t.h);\n        aPhase.push(t.phase);\n      }\n    }\n    const apex = base + R * 2;\n    position.push(t.cx, t.h, t.cz);\n    aY.push(1);\n    aPhase.push(t.phase);\n    for (let i = 0; i < R; i++) {\n      const i0 = base + i;\n      const i1 = base + ((i + 1) % R);\n      const j0 = base + R + i;\n      const j1 = base + R + ((i + 1) % R);\n      index.push(i0, i1, j1, i0, j1, j0); // ring0 → ring1\n      index.push(j0, j1, apex); //           ring1 → apex\n    }\n  }\n  const geo = new BufferGeometry();\n  geo.setAttribute('position', new BufferAttribute(new Float32Array(position), 3));\n  geo.setAttribute('aY', new BufferAttribute(new Float32Array(aY), 1));\n  geo.setAttribute('aPhase', new BufferAttribute(new Float32Array(aPhase), 1));\n  geo.setIndex(index);\n  return geo;\n}\n\nconst FLAME_VERT = /* glsl */ `\nattribute float aY;\nattribute float aPhase;\nuniform float uTime;\nvarying float vY;\nvoid main() {\n  vY = aY;\n  vec3 p = position;\n  float w = aY * aY;                 // tips sway most, base is pinned\n  p.x += sin(uTime * 7.0 + aPhase + aY * 4.0) * 0.09 * w;\n  p.z += cos(uTime * 6.0 + aPhase * 1.3 + aY * 4.0) * 0.09 * w;\n  p.y *= 0.82 + 0.18 * sin(uTime * 13.0 + aPhase * 2.0); // lick up and down\n  gl_Position = projectionMatrix * modelViewMatrix * vec4(p, 1.0);\n}`;\n\nconst FLAME_FRAG = /* glsl */ `\nuniform vec3 uHot;\nuniform vec3 uCool;\nvarying float vY;\nvoid main() {\n  vec3 col = mix(uHot, uCool, vY);   // white-hot base → cool orange tip\n  float alpha = 1.0 - vY;            // fade out toward the tip\n  gl_FragColor = vec4(col * (1.2 - vY * 0.4), alpha);\n}`;\n\nconst EMBER_VERT = /* glsl */ `\nattribute float aPhase;\nattribute float aSpeed;\nattribute float aRad;\nattribute float aAng;\nuniform float uTime;\nuniform float uRise;\nuniform float uSize;\nvarying float vLife;\nvoid main() {\n  float life = fract(uTime * aSpeed + aPhase); // 0 born → 1 dead\n  vLife = life;\n  float ang = aAng + life * 2.2;\n  float rad = aRad * (1.0 - life * 0.35);\n  vec3 p = vec3(cos(ang) * rad, life * uRise, sin(ang) * rad);\n  vec4 mv = modelViewMatrix * vec4(p, 1.0);\n  gl_PointSize = uSize * (1.0 - life) * (260.0 / -mv.z);\n  gl_Position = projectionMatrix * mv;\n}`;\n\nconst EMBER_FRAG = /* glsl */ `\nuniform vec3 uColor;\nvarying float vLife;\nvoid main() {\n  float d = length(gl_PointCoord - 0.5);\n  if (d > 0.5) discard;\n  gl_FragColor = vec4(uColor, (1.0 - vLife) * (1.0 - d * 2.0));\n}`;\n\n/**\n * Build the animated flame + embers, plus the uniforms driving them.\n * Internal — shared with the room hearth; not part of the public API.\n */\nexport function makeFlame(\n  rng: Rng,\n  scale: number,\n  tongues: number,\n  spread: number,\n  baseH: number\n): { group: Group; flameU: { uTime: { value: number } }; emberU: { uTime: { value: number } } } {\n  const list: Tongue[] = [];\n  for (let i = 0; i < tongues; i++) {\n    const a = (i / tongues) * Math.PI * 2 + rng.range(0, 1);\n    const rad = i === 0 ? 0 : rng.range(0.3, 1) * spread;\n    list.push({\n      cx: Math.cos(a) * rad,\n      cz: Math.sin(a) * rad,\n      r: rng.range(0.1, 0.16) * scale,\n      h: baseH * rng.range(0.7, 1.15) * scale,\n      phase: rng.range(0, Math.PI * 2),\n    });\n  }\n  const flameMat = new ShaderMaterial({\n    uniforms: {\n      uTime: { value: 0 },\n      uHot: { value: new Color(0xffe89a) },\n      uCool: { value: new Color(0xe0400c) },\n    },\n    vertexShader: FLAME_VERT,\n    fragmentShader: FLAME_FRAG,\n    transparent: true,\n    depthWrite: false,\n    blending: AdditiveBlending,\n    side: DoubleSide,\n  });\n  const flame = new Mesh(flameGeometry(list), flameMat);\n\n  // Embers.\n  const N = Math.round(10 + tongues * 2);\n  const ep = new Float32Array(N * 3);\n  const aPhase = new Float32Array(N);\n  const aSpeed = new Float32Array(N);\n  const aRad = new Float32Array(N);\n  const aAng = new Float32Array(N);\n  for (let i = 0; i < N; i++) {\n    aPhase[i] = rng.next();\n    aSpeed[i] = rng.range(0.25, 0.5);\n    aRad[i] = rng.range(0.02, spread * 0.9);\n    aAng[i] = rng.range(0, Math.PI * 2);\n  }\n  const emberGeo = new BufferGeometry();\n  emberGeo.setAttribute('position', new BufferAttribute(ep, 3));\n  emberGeo.setAttribute('aPhase', new BufferAttribute(aPhase, 1));\n  emberGeo.setAttribute('aSpeed', new BufferAttribute(aSpeed, 1));\n  emberGeo.setAttribute('aRad', new BufferAttribute(aRad, 1));\n  emberGeo.setAttribute('aAng', new BufferAttribute(aAng, 1));\n  const emberMat = new ShaderMaterial({\n    uniforms: {\n      uTime: { value: 0 },\n      uRise: { value: baseH * 1.9 * scale },\n      uSize: { value: 3.2 * scale },\n      uColor: { value: new Color(0xff8a3c) },\n    },\n    vertexShader: EMBER_VERT,\n    fragmentShader: EMBER_FRAG,\n    transparent: true,\n    depthWrite: false,\n    blending: AdditiveBlending,\n  });\n  const embers = new Points(emberGeo, emberMat);\n  embers.frustumCulled = false;\n\n  const group = new Group();\n  group.add(flame, embers);\n  return { group, flameU: flameMat.uniforms as { uTime: { value: number } }, emberU: emberMat.uniforms as { uTime: { value: number } } };\n}\n\n/**\n * Wire self-animation onto a fire: the flame shader clock, the ember clock,\n * the glowing coals and an optional flickering PointLight are all advanced\n * from the render loop, so a fire lives on its own with no per-frame code —\n * drop it in `scatter` or a village and it burns.\n * Internal — shared with the room hearth; not part of the public API.\n */\nexport function animateFire(\n  driver: Mesh,\n  flameU: { uTime: { value: number } },\n  emberU: { uTime: { value: number } },\n  coals: MeshStandardMaterial,\n  coalBase: number,\n  light: PointLight | null,\n  lightBase: number\n): void {\n  driver.onBeforeRender = () => {\n    const t = performance.now() * 0.001;\n    flameU.uTime.value = t;\n    emberU.uTime.value = t;\n    // Pseudo-noise flicker from a few incommensurate sines.\n    const flick =\n      0.74 + 0.15 * Math.sin(t * 11.0) + 0.1 * Math.sin(t * 23.3 + 1.7) + 0.06 * Math.sin(t * 41.0 + 0.5);\n    coals.emissiveIntensity = coalBase * (0.8 + 0.3 * (flick - 0.74) * 3);\n    if (light) light.intensity = lightBase * Math.max(0.4, flick);\n  };\n}\n\n// ---- braziers & campfires ---------------------------------------------\n\n/**\n * A standing brazier: a metal fire-bowl on splayed legs, filled with glowing\n * coals under a live flame, ringed by rising embers and casting a flickering\n * warm light. Self-animating.\n */\nexport function createBrazier(options: FireOptions = {}): Prop {\n  const rng = new Rng(options.seed ?? 1);\n  const palette = options.palette ?? DEFAULT_PALETTE;\n  const seed = options.seed ?? 1;\n  const scale = options.scale ?? 1;\n  const withLight = options.light ?? true;\n\n  const group = new Group();\n  group.name = 'brazier';\n\n  const metal = createSurface('metal', { color: palette.metal, seed });\n  const bowlH = 0.9;\n  // Three splayed legs.\n  for (let i = 0; i < 3; i++) {\n    const a = (i / 3) * Math.PI * 2 + 0.5;\n    const leg = new Mesh(new CylinderGeometry(0.03, 0.04, bowlH, 5), metal);\n    leg.position.set(Math.cos(a) * 0.22, bowlH / 2, Math.sin(a) * 0.22);\n    leg.rotation.z = Math.cos(a) * 0.18;\n    leg.rotation.x = -Math.sin(a) * 0.18;\n    group.add(leg);\n  }\n  const bowl = new Mesh(new CylinderGeometry(0.42, 0.24, 0.32, 12, 1, true), metal);\n  bowl.position.y = bowlH + 0.02;\n  group.add(bowl);\n  const base = new Mesh(new CylinderGeometry(0.24, 0.24, 0.05, 12), metal);\n  base.position.y = bowlH - 0.13;\n  group.add(base);\n\n  const coalMat = new MeshStandardMaterial({\n    color: 0x1a1109,\n    emissive: 0xff5a1e,\n    emissiveIntensity: 1.4,\n    flatShading: true,\n  });\n  for (let i = 0; i < 5; i++) {\n    const coal = new Mesh(new IcosahedronGeometry(rng.range(0.07, 0.12), 0), coalMat);\n    coal.position.set(rng.jitter(0, 0.16), bowlH + 0.06 + rng.range(0, 0.04), rng.jitter(0, 0.16));\n    group.add(coal);\n  }\n\n  const fire = makeFlame(rng, scale, 5, 0.2, 0.5);\n  fire.group.position.y = bowlH + 0.1;\n  group.add(fire.group);\n\n  let light: PointLight | null = null;\n  if (withLight) {\n    light = new PointLight(0xff8a3a, 7, 9, 2);\n    light.position.set(0, bowlH + 0.4, 0);\n    group.add(light);\n  }\n  animateFire(fire.group.children[0] as Mesh, fire.flameU, fire.emberU, coalMat, 1.4, light, 7);\n\n  return { object: group, obstacleRadius: 0.45 };\n}\n\n/**\n * A campfire: a ring of stones around charred logs stacked in a lean, a live\n * flame with rising embers, glowing under a flickering warm light.\n * Self-animating.\n */\nexport function createCampfire(options: FireOptions = {}): Prop {\n  const rng = new Rng(options.seed ?? 1);\n  const palette = options.palette ?? DEFAULT_PALETTE;\n  const seed = options.seed ?? 1;\n  const scale = options.scale ?? 1;\n  const withLight = options.light ?? true;\n\n  const group = new Group();\n  group.name = 'campfire';\n\n  // Stone ring.\n  const stone = createSurface('stone', { color: palette.rock[0], seed });\n  const ringR = 0.7;\n  const stones = rng.int(7, 9);\n  for (let i = 0; i < stones; i++) {\n    const a = (i / stones) * Math.PI * 2;\n    const s = rng.range(0.16, 0.24);\n    const rock = new Mesh(new IcosahedronGeometry(s, 0), stone);\n    rock.position.set(Math.cos(a) * ringR, s * 0.5, Math.sin(a) * ringR);\n    rock.rotation.set(rng.range(0, 3), rng.range(0, 3), rng.range(0, 3));\n    rock.scale.y = 0.75;\n    group.add(rock);\n  }\n\n  // Charred logs stacked in a lean.\n  const wood = createSurface('wood', { color: palette.woodDark, seed: seed + 3 });\n  const charMat = new MeshStandardMaterial({ color: 0x1c140f, flatShading: true });\n  const logs = rng.int(3, 4);\n  for (let i = 0; i < logs; i++) {\n    const a = (i / logs) * Math.PI * 2 + rng.range(0, 0.4);\n    const log = new Mesh(new CylinderGeometry(0.07, 0.08, 0.95, 6), i % 2 ? charMat : wood);\n    log.position.set(Math.cos(a) * 0.18, 0.28, Math.sin(a) * 0.18);\n    log.rotation.set(Math.PI / 2 - 0.55, a, 0);\n    group.add(log);\n  }\n\n  const coalMat = new MeshStandardMaterial({\n    color: 0x1a1008,\n    emissive: 0xff5518,\n    emissiveIntensity: 1.6,\n    flatShading: true,\n  });\n  for (let i = 0; i < 6; i++) {\n    const coal = new Mesh(new IcosahedronGeometry(rng.range(0.08, 0.14), 0), coalMat);\n    coal.position.set(rng.jitter(0, 0.24), 0.08 + rng.range(0, 0.05), rng.jitter(0, 0.24));\n    group.add(coal);\n  }\n\n  const fire = makeFlame(rng, scale, 7, 0.42, 0.85);\n  fire.group.position.y = 0.14;\n  group.add(fire.group);\n\n  let light: PointLight | null = null;\n  if (withLight) {\n    light = new PointLight(0xff8636, 9, 12, 2);\n    light.position.set(0, 0.9, 0);\n    group.add(light);\n  }\n  animateFire(fire.group.children[0] as Mesh, fire.flameU, fire.emberU, coalMat, 1.6, light, 9);\n\n  return { object: group, obstacleRadius: 0.9 };\n}\n","import {\n  BoxGeometry,\n  CylinderGeometry,\n  Group,\n  IcosahedronGeometry,\n  Mesh,\n  MeshStandardMaterial,\n  PointLight,\n  SphereGeometry,\n  TorusGeometry,\n} from 'three';\nimport { Rng } from '../core/random';\nimport { DEFAULT_PALETTE, type Palette } from '../core/palette';\nimport { createSurface } from '../materials/surface';\nimport { createPropSurface, createSlot } from '../core/types';\nimport type { Prop, PropSlot, PropSurface } from '../core/types';\n\n/**\n * Interior furniture — the cottage set. Every piece follows the Prop\n * contract (seeded, palette-themed, origin at floor level, honest\n * obstacleRadius), so it scatters, steers and re-themes like any other\n * SCENA prop; it just happens to live indoors.\n */\n\n// ---- tables ------------------------------------------------------------\n\nexport type TableStyle = 'round' | 'trestle' | 'desk';\n\nexport interface TableOptions {\n  seed?: number;\n  /** 'round' pedestal table, long 'trestle' board, or a small 'desk'. */\n  style?: TableStyle;\n  palette?: Palette;\n}\n\n/** A wooden table: round pedestal, long trestle board, or writing desk. */\nexport function createTable(options: TableOptions = {}): Prop {\n  const seed = options.seed ?? 1;\n  const rng = new Rng(seed);\n  const style = options.style ?? 'trestle';\n  const palette = options.palette ?? DEFAULT_PALETTE;\n  const top = createSurface('plank', { color: palette.wood, seed });\n  const legWood = createSurface('wood', { color: palette.woodDark, seed: seed + 1 });\n\n  const group = new Group();\n  group.name = `table-${style}`;\n  const h = 0.74 + rng.range(-0.02, 0.02);\n  const surfaces: PropSurface[] = [];\n  let radius = 0.8;\n\n  if (style === 'round') {\n    const board = new Mesh(new CylinderGeometry(0.72, 0.72, 0.07, 10), top);\n    board.position.y = h;\n    const stem = new Mesh(new CylinderGeometry(0.09, 0.13, h, 7), legWood);\n    stem.position.y = h / 2;\n    const foot = new Mesh(new CylinderGeometry(0.34, 0.4, 0.08, 8), legWood);\n    foot.position.y = 0.04;\n    group.add(board, stem, foot);\n    surfaces.push(createPropSurface('top', group, 0, h + 0.035, 0, 1.24, 1.24));\n    radius = 0.78;\n  } else if (style === 'trestle') {\n    const board = new Mesh(new BoxGeometry(2.0, 0.08, 0.9), top);\n    board.position.y = h;\n    group.add(board);\n    for (const side of [-1, 1]) {\n      for (const lean of [-1, 1]) {\n        const leg = new Mesh(new BoxGeometry(0.09, h, 0.12), legWood);\n        leg.position.set(side * 0.78, h / 2, 0);\n        leg.rotation.x = lean * 0.32;\n        group.add(leg);\n      }\n    }\n    const stretcher = new Mesh(new BoxGeometry(1.66, 0.08, 0.1), legWood);\n    stretcher.position.y = 0.24;\n    group.add(stretcher);\n    surfaces.push(createPropSurface('top', group, 0, h + 0.04, 0, 2.0, 0.9));\n    radius = 1.05;\n  } else {\n    const board = new Mesh(new BoxGeometry(1.3, 0.06, 0.68), top);\n    board.position.y = h;\n    group.add(board);\n    const apron = new Mesh(new BoxGeometry(1.18, 0.16, 0.56), legWood);\n    apron.position.y = h - 0.11;\n    group.add(apron);\n    for (const sx of [-1, 1]) {\n      for (const sz of [-1, 1]) {\n        const leg = new Mesh(new BoxGeometry(0.07, h, 0.07), legWood);\n        leg.position.set(sx * 0.56, h / 2, sz * 0.26);\n        group.add(leg);\n      }\n    }\n    surfaces.push(createPropSurface('top', group, 0, h + 0.03, 0, 1.3, 0.68));\n    radius = 0.72;\n  }\n  return { object: group, obstacleRadius: radius, surfaces };\n}\n\n// ---- seats -------------------------------------------------------------\n\nexport type SeatStyle = 'chair' | 'bench' | 'stool';\n\nexport interface SeatOptions {\n  seed?: number;\n  /** A slat-back 'chair', a long 'bench', or a three-legged 'stool'. */\n  style?: SeatStyle;\n  palette?: Palette;\n}\n\n/** Something to sit on: chair, bench or stool. Seat height ≈ 0.45. */\nexport function createSeat(options: SeatOptions = {}): Prop {\n  const seed = options.seed ?? 1;\n  const rng = new Rng(seed);\n  const style = options.style ?? 'chair';\n  const palette = options.palette ?? DEFAULT_PALETTE;\n  const wood = createSurface('wood', { color: palette.wood, seed });\n  const dark = createSurface('wood', { color: palette.woodDark, seed: seed + 1 });\n\n  const group = new Group();\n  group.name = `seat-${style}`;\n  const h = 0.45;\n  let radius = 0.3;\n\n  if (style === 'stool') {\n    const disc = new Mesh(new CylinderGeometry(0.24, 0.22, 0.06, 8), wood);\n    disc.position.y = h;\n    group.add(disc);\n    for (let i = 0; i < 3; i++) {\n      const a = (i / 3) * Math.PI * 2 + rng.range(0, 0.4);\n      const leg = new Mesh(new CylinderGeometry(0.035, 0.045, h, 5), dark);\n      leg.position.set(Math.cos(a) * 0.13, h / 2, Math.sin(a) * 0.13);\n      leg.rotation.z = Math.cos(a) * 0.22;\n      leg.rotation.x = -Math.sin(a) * 0.22;\n      group.add(leg);\n    }\n    radius = 0.26;\n  } else if (style === 'bench') {\n    const seat = new Mesh(new BoxGeometry(1.5, 0.06, 0.36), wood);\n    seat.position.y = h;\n    group.add(seat);\n    for (const side of [-1, 1]) {\n      const leg = new Mesh(new BoxGeometry(0.08, h, 0.3), dark);\n      leg.position.set(side * 0.6, h / 2, 0);\n      leg.rotation.z = side * 0.06;\n      group.add(leg);\n    }\n    radius = 0.78;\n  } else {\n    const seat = new Mesh(new BoxGeometry(0.44, 0.05, 0.42), wood);\n    seat.position.y = h;\n    group.add(seat);\n    for (const sx of [-1, 1]) {\n      for (const sz of [-1, 1]) {\n        const back = sz < 0;\n        const leg = new Mesh(new BoxGeometry(0.05, back ? 0.98 : h, 0.05), dark);\n        leg.position.set(sx * 0.18, back ? 0.49 : h / 2, sz * 0.17);\n        group.add(leg);\n      }\n    }\n    for (const y of [0.72, 0.88]) {\n      const slat = new Mesh(new BoxGeometry(0.36, 0.08, 0.03), wood);\n      slat.position.set(0, y, -0.17);\n      group.add(slat);\n    }\n    radius = 0.3;\n  }\n  // Sitting places — chairs and stools seat one, benches two.\n  const slots: PropSlot[] =\n    style === 'bench'\n      ? [createSlot('sit', 'sit', group, -0.4, 0, 0), createSlot('sit', 'sit', group, 0.4, 0, 0)]\n      : [createSlot('sit', 'sit', group, 0, 0, 0)];\n  return { object: group, obstacleRadius: radius, slots };\n}\n\n// ---- beds --------------------------------------------------------------\n\nexport type BedSize = 'single' | 'double' | 'bunk';\n\nexport interface BedOptions {\n  seed?: number;\n  /** 'single', wide 'double', or stacked 'bunk'. */\n  size?: BedSize;\n  palette?: Palette;\n}\n\n/** A post bed with mattress, quilt and pillow. Bunks stack two. */\nexport function createBed(options: BedOptions = {}): Prop {\n  const seed = options.seed ?? 1;\n  const rng = new Rng(seed);\n  const size = options.size ?? 'single';\n  const palette = options.palette ?? DEFAULT_PALETTE;\n  const frame = createSurface('wood', { color: palette.woodDark, seed });\n  const linen = new MeshStandardMaterial({ color: 0xefe6d2, flatShading: true });\n  const quiltMat = createSurface('canvas', { color: palette.roof, seed: seed + 2 });\n\n  const w = size === 'double' ? 1.6 : 0.95;\n  const l = 2.05;\n  const group = new Group();\n  group.name = `bed-${size}`;\n\n  const deck = (baseY: number): void => {\n    const base = new Mesh(new BoxGeometry(w, 0.1, l), frame);\n    base.position.y = baseY;\n    const mattress = new Mesh(new BoxGeometry(w - 0.08, 0.14, l - 0.08), linen);\n    mattress.position.y = baseY + 0.12;\n    const quilt = new Mesh(new BoxGeometry(w - 0.04, 0.08, l * 0.62), quiltMat);\n    quilt.position.set(0, baseY + 0.21, l * 0.16);\n    group.add(base, mattress, quilt);\n    const pillows = size === 'double' ? [-w / 4, w / 4] : [0];\n    for (const px of pillows) {\n      const pillow = new Mesh(new BoxGeometry(w * (size === 'double' ? 0.38 : 0.6), 0.09, 0.34), linen);\n      pillow.position.set(px, baseY + 0.22, -l / 2 + 0.28);\n      pillow.rotation.y = rng.jitter(0, 0.06);\n      group.add(pillow);\n    }\n    const head = new Mesh(new BoxGeometry(w, 0.5, 0.07), frame);\n    head.position.set(0, baseY + 0.3, -l / 2 + 0.03);\n    group.add(head);\n  };\n\n  const postH = size === 'bunk' ? 1.9 : 0.75;\n  for (const sx of [-1, 1]) {\n    for (const sz of [-1, 1]) {\n      const post = new Mesh(new BoxGeometry(0.09, postH, 0.09), frame);\n      post.position.set(sx * (w / 2 - 0.045), postH / 2, sz * (l / 2 - 0.045));\n      group.add(post);\n    }\n  }\n  deck(0.32);\n  if (size === 'bunk') {\n    deck(1.35);\n    // Ladder up the side.\n    for (const y of [0.55, 0.9, 1.25]) {\n      const rung = new Mesh(new CylinderGeometry(0.025, 0.025, 0.4, 5), frame);\n      rung.rotation.z = Math.PI / 2;\n      rung.position.set(w / 2 + 0.02, y, l * 0.22);\n      group.add(rung);\n    }\n  }\n  // Sleeping places: anchor at the foot end on the mattress, pitched flat\n  // so the body extends toward the headboard (ANIMA's sleep convention).\n  const sleepAt = (x: number, deckY: number): PropSlot =>\n    createSlot('sleep', 'sleep', group, x, deckY + 0.22, l / 2 - 0.3, 0, -Math.PI / 2);\n  const slots: PropSlot[] =\n    size === 'bunk'\n      ? [sleepAt(0, 0.32), sleepAt(0, 1.35)]\n      : size === 'double'\n        ? [sleepAt(-w / 4, 0.32), sleepAt(w / 4, 0.32)]\n        : [sleepAt(0, 0.32)];\n  return { object: group, obstacleRadius: size === 'double' ? 1.25 : 1.1, slots };\n}\n\n// ---- shelves -----------------------------------------------------------\n\nexport type ShelfStock = 'books' | 'pottery' | 'food' | 'empty';\n\nexport interface ShelfOptions {\n  seed?: number;\n  /** What lines the boards: 'books', 'pottery', 'food' or 'empty'. */\n  stock?: ShelfStock;\n  palette?: Palette;\n}\n\n/** A tall open shelf, boards lined with seeded books, pots or provisions. */\nexport function createShelf(options: ShelfOptions = {}): Prop {\n  const seed = options.seed ?? 1;\n  const rng = new Rng(seed);\n  const stock = options.stock ?? 'books';\n  const palette = options.palette ?? DEFAULT_PALETTE;\n  const wood = createSurface('wood', { color: palette.woodDark, seed });\n  const board = createSurface('plank', { color: palette.wood, seed: seed + 1 });\n\n  const W = 1.25;\n  const H = 1.85;\n  const D = 0.34;\n  const group = new Group();\n  group.name = `shelf-${stock}`;\n\n  for (const side of [-1, 1]) {\n    const panel = new Mesh(new BoxGeometry(0.06, H, D), wood);\n    panel.position.set(side * (W / 2 - 0.03), H / 2, 0);\n    group.add(panel);\n  }\n  const back = new Mesh(new BoxGeometry(W, H, 0.04), wood);\n  back.position.set(0, H / 2, -D / 2 + 0.02);\n  group.add(back);\n\n  const boardYs = [0.28, 0.78, 1.28, 1.72];\n  const surfaces: PropSurface[] = [];\n  // The top of the carcass is a surface too, and the most used one in any\n  // real room.\n  surfaces.push(createPropSurface('top', group, 0, H, 0, W - 0.14, D - 0.06));\n  for (const y of boardYs) {\n    const shelfBoard = new Mesh(new BoxGeometry(W - 0.1, 0.05, D - 0.04), board);\n    shelfBoard.position.set(0, y, 0);\n    group.add(shelfBoard);\n  }\n  // Only the boards that are not already stocked: dressing a shelf of books\n  // puts a mug inside the books.\n  const free = (options.stock ?? 'books') === 'empty' ? boardYs : boardYs.slice(3);\n  for (const y of free) {\n    surfaces.push(createPropSurface('shelf', group, 0, y + 0.025, 0, W - 0.14, D - 0.08));\n  }\n\n  if (stock !== 'empty') {\n    const hues = [palette.roof, palette.water, palette.foliage[0], palette.trunk, palette.metal, palette.path];\n    for (const y of boardYs.slice(0, 3)) {\n      let x = -W / 2 + 0.14;\n      while (x < W / 2 - 0.16) {\n        if (stock === 'books') {\n          const bh = rng.range(0.16, 0.26);\n          const bw = rng.range(0.035, 0.06);\n          const bookMat = new MeshStandardMaterial({ color: rng.pick(hues), flatShading: true });\n          const tilt = rng.next() < 0.12 ? rng.range(0.1, 0.22) : 0;\n          const bk = new Mesh(new BoxGeometry(bw, bh, 0.2), bookMat);\n          bk.position.set(x, y + 0.025 + bh / 2, 0);\n          bk.rotation.z = tilt;\n          group.add(bk);\n          x += bw + 0.012 + tilt * 0.1;\n        } else if (stock === 'pottery') {\n          const r = rng.range(0.05, 0.09);\n          const ph = rng.range(0.12, 0.22);\n          const pot = new Mesh(\n            new CylinderGeometry(r * rng.range(0.5, 0.8), r, ph, 7),\n            createSurface('terracotta', { seed: rng.int(1, 1e9) })\n          );\n          pot.position.set(x + r, y + 0.025 + ph / 2, rng.jitter(0, 0.04));\n          group.add(pot);\n          x += r * 2 + rng.range(0.05, 0.12);\n        } else {\n          // food: sacks and round loaves\n          const r = rng.range(0.07, 0.1);\n          const isSack = rng.next() < 0.5;\n          const item = new Mesh(\n            isSack ? new IcosahedronGeometry(r, 0) : new SphereGeometry(r, 7, 5),\n            isSack\n              ? createSurface('canvas', { color: palette.sand, seed: rng.int(1, 1e9) })\n              : new MeshStandardMaterial({ color: 0xb8874f, flatShading: true })\n          );\n          item.scale.y = 0.72;\n          item.position.set(x + r, y + 0.025 + r * 0.6, rng.jitter(0, 0.04));\n          group.add(item);\n          x += r * 2 + rng.range(0.04, 0.1);\n        }\n      }\n    }\n  }\n  return { object: group, obstacleRadius: 0.65, surfaces };\n}\n\n// ---- chests ------------------------------------------------------------\n\nexport interface ChestOptions {\n  seed?: number;\n  /** Tilt the lid open. Default false. */\n  open?: boolean;\n  palette?: Palette;\n}\n\n/** A banded storage chest with a domed lid; `open` tilts it back. */\nexport function createChest(options: ChestOptions = {}): Prop {\n  const seed = options.seed ?? 1;\n  const palette = options.palette ?? DEFAULT_PALETTE;\n  const wood = createSurface('plank', { color: palette.wood, seed });\n  const metal = new MeshStandardMaterial({ color: palette.metal, flatShading: true, metalness: 0.5, roughness: 0.5 });\n\n  const W = 0.95;\n  const H = 0.5;\n  const D = 0.55;\n  const group = new Group();\n  group.name = 'chest';\n\n  const body = new Mesh(new BoxGeometry(W, H, D), wood);\n  body.position.y = H / 2;\n  group.add(body);\n  for (const x of [-W * 0.32, W * 0.32]) {\n    const band = new Mesh(new BoxGeometry(0.06, H + 0.02, D + 0.02), metal);\n    band.position.set(x, H / 2, 0);\n    group.add(band);\n  }\n\n  // Lid: a slab hinged at the back edge, with its own metal bands.\n  const lid = new Group();\n  lid.name = 'lid';\n  const slab = new Mesh(new BoxGeometry(W + 0.04, 0.12, D + 0.04), wood);\n  slab.position.set(0, 0.06, D / 2);\n  lid.add(slab);\n  for (const x of [-W * 0.32, W * 0.32]) {\n    const band = new Mesh(new BoxGeometry(0.06, 0.14, D + 0.06), metal);\n    band.position.set(x, 0.06, D / 2);\n    lid.add(band);\n  }\n  lid.position.set(0, H, -D / 2);\n  if (options.open) lid.rotation.x = -1.1;\n  group.add(lid);\n\n  const hasp = new Mesh(new BoxGeometry(0.08, 0.14, 0.03), metal);\n  hasp.position.set(0, H - 0.02, D / 2 + 0.015);\n  group.add(hasp);\n\n  // A closed chest is a surface; an open one is a hole. Publishing the lid\n  // top regardless would stand a candle in mid-air over an open box.\n  const surfaces = options.open\n    ? []\n    : [createPropSurface('top', group, 0, H + 0.12, 0, W - 0.08, D - 0.08)];\n\n  return { object: group, obstacleRadius: 0.55, surfaces };\n}\n\n// ---- candles -----------------------------------------------------------\n\nexport type CandleStyle = 'single' | 'candelabra' | 'chandelier';\n\nexport interface CandleOptions {\n  seed?: number;\n  /**\n   * 'single' tabletop candle on a dish, a standing 'candelabra', or a\n   * 'chandelier' meant to hang (origin at the hook — position it at the\n   * ceiling and it hangs down).\n   */\n  style?: CandleStyle;\n  /** Add one real PointLight. Default false — glow is free, lights are not. */\n  light?: boolean;\n  palette?: Palette;\n}\n\n/** Candlelight: glowing flames with a gentle flicker; real light opt-in. */\nexport function createCandle(options: CandleOptions = {}): Prop {\n  const seed = options.seed ?? 1;\n  const rng = new Rng(seed);\n  const style = options.style ?? 'single';\n  const palette = options.palette ?? DEFAULT_PALETTE;\n  const wax = new MeshStandardMaterial({ color: 0xf2e8d0, flatShading: true });\n  const metal = new MeshStandardMaterial({ color: palette.metal, flatShading: true, metalness: 0.4, roughness: 0.55 });\n  const flameMat = new MeshStandardMaterial({\n    color: palette.lampGlow,\n    emissive: palette.lampGlow,\n    emissiveIntensity: 1.9,\n    flatShading: true,\n  });\n\n  const group = new Group();\n  group.name = `candle-${style}`;\n  let lightY = 0.3;\n  let radius = 0;\n\n  const candleAt = (x: number, y: number, z: number, h: number): void => {\n    const stick = new Mesh(new CylinderGeometry(0.025, 0.03, h, 6), wax);\n    stick.position.set(x, y + h / 2, z);\n    const flame = new Mesh(new IcosahedronGeometry(0.035, 0), flameMat);\n    flame.scale.y = 1.7;\n    flame.position.set(x, y + h + 0.05, z);\n    group.add(stick, flame);\n  };\n\n  if (style === 'single') {\n    const dish = new Mesh(new CylinderGeometry(0.09, 0.11, 0.025, 8), metal);\n    dish.position.y = 0.012;\n    group.add(dish);\n    candleAt(0, 0.025, 0, rng.range(0.14, 0.22));\n    lightY = 0.3;\n  } else if (style === 'candelabra') {\n    const foot = new Mesh(new CylinderGeometry(0.14, 0.18, 0.04, 8), metal);\n    foot.position.y = 0.02;\n    const stem = new Mesh(new CylinderGeometry(0.03, 0.04, 1.15, 6), metal);\n    stem.position.y = 0.6;\n    group.add(foot, stem);\n    const arm = new Mesh(new BoxGeometry(0.72, 0.04, 0.04), metal);\n    arm.position.y = 1.18;\n    group.add(arm);\n    for (const x of [-0.34, 0, 0.34]) candleAt(x, x === 0 ? 1.24 : 1.2, 0, 0.16);\n    lightY = 1.5;\n    radius = 0.24;\n  } else {\n    // chandelier: origin at the hook, hangs downward.\n    const chain = new Mesh(new CylinderGeometry(0.015, 0.015, 0.7, 5), metal);\n    chain.position.y = -0.35;\n    const ring = new Mesh(new TorusGeometry(0.5, 0.035, 6, 10), metal);\n    ring.rotation.x = Math.PI / 2;\n    ring.position.y = -0.75;\n    group.add(chain, ring);\n    const n = 6;\n    for (let i = 0; i < n; i++) {\n      const a = (i / n) * Math.PI * 2;\n      candleAt(Math.cos(a) * 0.5, -0.75, Math.sin(a) * 0.5, 0.14);\n    }\n    lightY = -0.45;\n  }\n\n  let light: PointLight | null = null;\n  if (options.light) {\n    light = new PointLight(palette.lampGlow, style === 'single' ? 1.6 : 3.5, 7, 2);\n    light.position.y = lightY;\n    group.add(light);\n  }\n\n  // A gentle wax-flame flicker, self-driving like every SCENA fire.\n  const phase = rng.range(0, 20);\n  const flames = group.children.filter(\n    (child) => (child as Mesh).material === flameMat\n  ) as Mesh[];\n  if (flames.length > 0) {\n    const base = light?.intensity ?? 0;\n    flames[0].onBeforeRender = () => {\n      const t = performance.now() * 0.001 + phase;\n      const flick = 0.86 + 0.09 * Math.sin(t * 9.0) + 0.05 * Math.sin(t * 17.3 + 1.2);\n      flameMat.emissiveIntensity = 1.9 * flick;\n      if (light) light.intensity = base * flick;\n    };\n  }\n\n  return { object: group, obstacleRadius: radius };\n}\n\n// ---- rugs --------------------------------------------------------------\n\nexport type RugShape = 'round' | 'square' | 'runner';\n\nexport interface RugOptions {\n  seed?: number;\n  /** 'round' banded disc, 'square' bordered mat, or a long 'runner'. */\n  shape?: RugShape;\n  palette?: Palette;\n}\n\n/** A woven rug: banded, palette-dyed, and walk-through (radius 0). */\nexport function createRug(options: RugOptions = {}): Prop {\n  const seed = options.seed ?? 1;\n  const rng = new Rng(seed);\n  const shape = options.shape ?? 'round';\n  const palette = options.palette ?? DEFAULT_PALETTE;\n  const dyes = [palette.roof, palette.sand, palette.water, palette.path];\n  const group = new Group();\n  group.name = `rug-${shape}`;\n\n  if (shape === 'round') {\n    const rings = [1.0, 0.78, 0.5];\n    rings.forEach((r, i) => {\n      const disc = new Mesh(\n        new CylinderGeometry(r, r, 0.02 + i * 0.006, 10),\n        new MeshStandardMaterial({ color: dyes[(i + rng.int(0, 3)) % dyes.length], flatShading: true })\n      );\n      disc.position.y = 0.011 + i * 0.004;\n      disc.rotation.y = rng.range(0, Math.PI / 5);\n      group.add(disc);\n    });\n  } else {\n    const long = shape === 'runner' ? 2.6 : 1.6;\n    const wide = shape === 'runner' ? 1.0 : 1.6;\n    const border = new Mesh(\n      new BoxGeometry(long, 0.02, wide),\n      new MeshStandardMaterial({ color: dyes[rng.int(0, 3)], flatShading: true })\n    );\n    border.position.y = 0.01;\n    group.add(border);\n    const bands = shape === 'runner' ? 5 : 3;\n    for (let i = 0; i < bands; i++) {\n      const band = new Mesh(\n        new BoxGeometry((long - 0.3) / bands - 0.06, 0.02, wide - 0.3),\n        new MeshStandardMaterial({ color: dyes[(i + 1 + rng.int(0, 2)) % dyes.length], flatShading: true })\n      );\n      band.position.set(-((long - 0.3) / 2) + (i + 0.5) * ((long - 0.3) / bands), 0.02, 0);\n      group.add(band);\n    }\n  }\n  return { object: group, obstacleRadius: 0 };\n}\n","import {\n  BoxGeometry,\n  CylinderGeometry,\n  Group,\n  InstancedMesh,\n  Matrix4,\n  Mesh,\n  Object3D,\n  SphereGeometry,\n} from 'three';\nimport { Rng } from '../core/random';\nimport { DEFAULT_PALETTE, type Palette } from '../core/palette';\nimport { createSurface } from '../materials/surface';\nimport { addApproach, createSlot } from '../core/types';\nimport type { Gathering, PropSlot } from '../core/types';\nimport { createSeat, createTable } from './furniture';\n\n/**\n * Props that seat *several* characters at once — the dining table, the\n * park bench, the game board, the ring of logs round a fire.\n *\n * The geometry is the easy half. What makes a group of bodies read as\n * people rather than mannequins is the detail these generators encode:\n *\n * - **Nothing is square.** Every chair is nudged off its ideal angle and\n *   pushed back a different amount, because nobody in the history of\n *   dining has left a chair exactly where they found it. The seat slot\n *   inherits that crookedness, so the sitters land crooked too — and one\n *   seeded radian of it does more for realism than another thousand\n *   triangles.\n * - **Every seat has an approach.** A slot's `approach` anchor stands a\n *   pace behind the chair. Characters walk *there*, then turn and lower.\n * - **Every gathering has a focus.** The bowl in the middle, the board,\n *   the fire. Aim the occupants' gaze at it (ANIMA's `LookAt`, or a\n *   `Conversation`) and adjacency becomes company.\n */\n\nexport interface GatheringOptions {\n  seed?: number;\n  palette?: Palette;\n}\n\n/** Place a focus marker (what occupants attend to) at a local point. */\nfunction focusAt(parent: Group, x: number, y: number, z: number): Object3D {\n  const focus = new Object3D();\n  focus.name = 'focus';\n  focus.position.set(x, y, z);\n  parent.add(focus);\n  return focus;\n}\n\n/**\n * Seat a chair at (x, z) facing `rotY`, crooked by a believable amount,\n * and hand back its slot (with approach) re-parented into the chair so it\n * carries every bit of that jitter.\n */\nfunction seatChair(\n  group: Group,\n  rng: Rng,\n  x: number,\n  z: number,\n  rotY: number,\n  options: { seed: number; palette: Palette; style?: 'chair' | 'stool' }\n): PropSlot {\n  // Pushed back from the table by a hand's width or two, and never square on.\n  const back = rng.range(0.0, 0.16);\n  const skew = rng.range(-0.17, 0.17);\n  const chair = createSeat({\n    seed: options.seed + Math.floor(rng.next() * 1000),\n    style: options.style ?? 'chair',\n    palette: options.palette,\n  });\n  chair.object.position.set(x - Math.sin(rotY) * back, 0, z - Math.cos(rotY) * back);\n  chair.object.rotation.y = rotY + skew;\n  group.add(chair.object);\n  const slot = chair.slots![0];\n  slot.kind = 'seat';\n  return addApproach(slot, chair.object, rng.range(0.62, 0.82));\n}\n\n/** A plate-and-cup place setting on the table in front of a seat. */\nfunction placeSetting(\n  group: Group,\n  rng: Rng,\n  x: number,\n  z: number,\n  rotY: number,\n  height: number,\n  palette: Palette,\n  seed: number\n): void {\n  const reach = rng.range(0.4, 0.5);\n  const px = x + Math.sin(rotY) * reach;\n  const pz = z + Math.cos(rotY) * reach;\n  const clay = createSurface('plaster', { color: 0xd9cdb8, seed });\n  const plate = new Mesh(new CylinderGeometry(0.11, 0.09, 0.02, 10), clay);\n  plate.position.set(px, height + 0.01, pz);\n  group.add(plate);\n  // The cup lands wherever the hand put it — off to one side, never centred.\n  const side = rng.pick([-1, 1]) * rng.range(0.13, 0.2);\n  const cup = new Mesh(new CylinderGeometry(0.04, 0.035, 0.08, 8), clay);\n  cup.position.set(px + Math.cos(rotY) * side, height + 0.04, pz - Math.sin(rotY) * side);\n  cup.rotation.z = rng.range(-0.04, 0.04);\n  group.add(cup);\n}\n\n// ---- dining table ------------------------------------------------------\n\nexport interface DiningTableOptions extends GatheringOptions {\n  /** How many places to lay. Round tables ring them; trestles line them up. */\n  seats?: number;\n  /** 'round' pedestal or long 'trestle' board. */\n  style?: 'round' | 'trestle';\n  /** Lay plates and cups. Default true. */\n  settings?: boolean;\n}\n\n/**\n * A table with chairs round it and the meal laid out — the archetypal\n * gathering. Round tables seat everyone equally; trestles have a head.\n */\nexport function createDiningTable(options: DiningTableOptions = {}): Gathering {\n  const seed = options.seed ?? 1;\n  const rng = new Rng(seed);\n  const palette = options.palette ?? DEFAULT_PALETTE;\n  const style = options.style ?? 'round';\n  const count = Math.max(2, Math.min(10, options.seats ?? 6));\n\n  const group = new Group();\n  group.name = `dining-${style}`;\n  const table = createTable({ seed, style, palette });\n  group.add(table.object);\n  const height = 0.74;\n\n  const seats: PropSlot[] = [];\n  const spots: Array<{ x: number; z: number; rotY: number }> = [];\n\n  if (style === 'round') {\n    const ring = 1.12;\n    for (let i = 0; i < count; i++) {\n      const a = (i / count) * Math.PI * 2 + rng.range(-0.08, 0.08);\n      spots.push({ x: Math.sin(a) * ring, z: Math.cos(a) * ring, rotY: a + Math.PI });\n    }\n  } else {\n    // Two long sides first, then the heads — the way a board fills up.\n    const perSide = Math.floor(count / 2);\n    const heads = count - perSide * 2;\n    for (const side of [1, -1]) {\n      for (let i = 0; i < perSide; i++) {\n        const t = perSide === 1 ? 0.5 : i / (perSide - 1);\n        spots.push({ x: (t - 0.5) * 1.5, z: side * 0.86, rotY: side > 0 ? Math.PI : 0 });\n      }\n    }\n    for (let i = 0; i < heads; i++) {\n      const end = i === 0 ? 1 : -1;\n      spots.push({ x: end * 1.28, z: 0, rotY: end > 0 ? -Math.PI / 2 : Math.PI / 2 });\n    }\n  }\n\n  for (const spot of spots) {\n    seats.push(seatChair(group, rng, spot.x, spot.z, spot.rotY, { seed, palette }));\n    if (options.settings !== false) {\n      placeSetting(group, rng, spot.x, spot.z, spot.rotY, height, palette, seed);\n    }\n  }\n\n  // The shared dish in the middle: what hands reach for and eyes come back to.\n  if (options.settings !== false) {\n    const clay = createSurface('plaster', { color: 0xc9b79c, seed: seed + 4 });\n    const bowl = new Mesh(new SphereGeometry(0.17, 10, 6, 0, Math.PI * 2, 0, Math.PI / 2), clay);\n    bowl.rotation.x = Math.PI;\n    bowl.position.y = height + 0.17;\n    group.add(bowl);\n  }\n\n  const focus = focusAt(group, 0, height + 0.12, 0);\n  return {\n    object: group,\n    obstacleRadius: style === 'round' ? 1.35 : 1.65,\n    slots: seats,\n    seats,\n    focus,\n  };\n}\n\n// ---- picnic table ------------------------------------------------------\n\nexport interface PicnicTableOptions extends GatheringOptions {\n  /** Places, split between the two benches. Default 6. */\n  seats?: number;\n}\n\n/** A trestle top with the benches built on — six round it, elbow to elbow. */\nexport function createPicnicTable(options: PicnicTableOptions = {}): Gathering {\n  const seed = options.seed ?? 1;\n  const rng = new Rng(seed);\n  const palette = options.palette ?? DEFAULT_PALETTE;\n  const count = Math.max(2, Math.min(8, options.seats ?? 6));\n  const perSide = Math.ceil(count / 2);\n  const length = Math.max(1.8, perSide * 0.62 + 0.4);\n\n  const group = new Group();\n  group.name = 'picnic-table';\n  const plank = createSurface('plank', { color: palette.wood, seed });\n  const dark = createSurface('wood', { color: palette.woodDark, seed: seed + 1 });\n  const topY = 0.74;\n  const seatY = 0.45;\n\n  const board = new Mesh(new BoxGeometry(length, 0.07, 0.78), plank);\n  board.position.y = topY;\n  group.add(board);\n  for (const side of [-1, 1]) {\n    const bench = new Mesh(new BoxGeometry(length, 0.06, 0.3), plank);\n    bench.position.set(0, seatY, side * 0.72);\n    group.add(bench);\n  }\n  // A-frames: the splayed legs that make a picnic table a picnic table.\n  for (const end of [-1, 1]) {\n    for (const side of [-1, 1]) {\n      const leg = new Mesh(new BoxGeometry(0.09, 1.0, 0.1), dark);\n      leg.position.set(end * (length / 2 - 0.24), topY / 2, side * 0.42);\n      leg.rotation.x = -side * 0.62;\n      group.add(leg);\n    }\n    const brace = new Mesh(new BoxGeometry(0.08, 0.08, 1.5), dark);\n    brace.position.set(end * (length / 2 - 0.24), seatY + 0.02, 0);\n    group.add(brace);\n  }\n\n  const seats: PropSlot[] = [];\n  for (let i = 0; i < count; i++) {\n    const side = i % 2 === 0 ? 1 : -1;\n    const index = Math.floor(i / 2);\n    const span = perSide === 1 ? 0 : (index / (perSide - 1) - 0.5) * (length - 0.7);\n    // Benches have no chair to shove about, so the slack shows up as people\n    // sitting a little apart, or a little too close.\n    const x = span + rng.range(-0.07, 0.07);\n    const z = side * 0.72;\n    const rotY = side > 0 ? Math.PI : 0;\n    const slot = createSlot('seat', 'sit', group, x, 0, z, rotY + rng.range(-0.12, 0.12));\n    seats.push(addApproach(slot, group, rng.range(0.6, 0.8)));\n  }\n\n  const focus = focusAt(group, 0, topY + 0.1, 0);\n  return { object: group, obstacleRadius: length / 2 + 0.5, slots: seats, seats, focus };\n}\n\n// ---- park bench --------------------------------------------------------\n\nexport interface LongBenchOptions extends GatheringOptions {\n  /** Places along the bench. Default 3. */\n  seats?: number;\n  /** Slatted back and armrests. Default true. */\n  back?: boolean;\n}\n\n/**\n * The park bench: several places on one continuous seat. Its slots are\n * deliberately *loose* — real strangers do not sit at even spacing, they\n * take the ends first and leave the middle for last. GAMA's `Occupancy`\n * does the choosing; the bench just offers the room.\n */\nexport function createLongBench(options: LongBenchOptions = {}): Gathering {\n  const seed = options.seed ?? 1;\n  const rng = new Rng(seed);\n  const palette = options.palette ?? DEFAULT_PALETTE;\n  const count = Math.max(2, Math.min(6, options.seats ?? 3));\n  const hasBack = options.back !== false;\n  const length = count * 0.58 + 0.34;\n\n  const group = new Group();\n  group.name = 'long-bench';\n  const plank = createSurface('plank', { color: palette.wood, seed });\n  const iron = createSurface('metal', { color: palette.metal, seed: seed + 1 });\n  const seatY = 0.44;\n\n  for (let i = 0; i < 3; i++) {\n    const slat = new Mesh(new BoxGeometry(length, 0.045, 0.14), plank);\n    slat.position.set(0, seatY, (i - 1) * 0.16);\n    group.add(slat);\n  }\n  if (hasBack) {\n    for (let i = 0; i < 3; i++) {\n      const slat = new Mesh(new BoxGeometry(length, 0.12, 0.04), plank);\n      slat.position.set(0, seatY + 0.22 + i * 0.16, -0.26);\n      slat.rotation.x = 0.14;\n      group.add(slat);\n    }\n  }\n  for (const end of [-1, 1]) {\n    const frame = new Mesh(new BoxGeometry(0.06, seatY, 0.42), iron);\n    frame.position.set(end * (length / 2 - 0.09), seatY / 2, 0);\n    group.add(frame);\n    if (hasBack) {\n      const post = new Mesh(new BoxGeometry(0.05, 0.56, 0.05), iron);\n      post.position.set(end * (length / 2 - 0.09), seatY + 0.28, -0.24);\n      post.rotation.x = 0.14;\n      group.add(post);\n      const arm = new Mesh(new BoxGeometry(0.05, 0.05, 0.44), iron);\n      arm.position.set(end * (length / 2 - 0.09), seatY + 0.24, -0.02);\n      group.add(arm);\n    }\n  }\n\n  const seats: PropSlot[] = [];\n  for (let i = 0; i < count; i++) {\n    const x = (i / (count - 1) - 0.5) * (length - 0.62);\n    const slot = createSlot('seat', 'sit', group, x, 0, 0.02, rng.range(-0.1, 0.1));\n    // Approached from the front: the backrest is behind, so that is the only\n    // way onto it — walk up, turn round, sit down.\n    seats.push(addApproach(slot, group, rng.range(0.6, 0.78), 'front'));\n  }\n\n  const focus = focusAt(group, 0, 1.2, 2.4); // what a bench faces: the view\n  return { object: group, obstacleRadius: length / 2 + 0.2, slots: seats, seats, focus };\n}\n\n// ---- two-player game ---------------------------------------------------\n\nexport type BoardGame = 'chess' | 'cards' | 'dice';\n\nexport interface GameTableOptions extends GatheringOptions {\n  /** What is being played. Default 'chess'. */\n  game?: BoardGame;\n}\n\n/**\n * Two stools and a small table between them — the two-player prop. Both\n * seats face each other across a shared `focus` (the board), which is\n * what makes the pair read as *opponents* rather than two people who both\n * happen to be sitting down.\n */\nexport function createGameTable(options: GameTableOptions = {}): Gathering {\n  const seed = options.seed ?? 1;\n  const rng = new Rng(seed);\n  const palette = options.palette ?? DEFAULT_PALETTE;\n  const game = options.game ?? 'chess';\n\n  const group = new Group();\n  group.name = `game-${game}`;\n  const plank = createSurface('plank', { color: palette.wood, seed });\n  const dark = createSurface('wood', { color: palette.woodDark, seed: seed + 1 });\n  const topY = 0.72;\n\n  const board = new Mesh(new BoxGeometry(0.82, 0.06, 0.82), plank);\n  board.position.y = topY;\n  group.add(board);\n  const stem = new Mesh(new CylinderGeometry(0.08, 0.11, topY, 7), dark);\n  stem.position.y = topY / 2;\n  const foot = new Mesh(new CylinderGeometry(0.3, 0.34, 0.06, 8), dark);\n  foot.position.y = 0.03;\n  group.add(stem, foot);\n\n  const surfaceY = topY + 0.035;\n  if (game === 'chess') {\n    const light = createSurface('plaster', { color: 0xe6dcc6, seed: seed + 2 });\n    const shade = createSurface('wood', { color: 0x4a3729, seed: seed + 3 });\n    const field = new Mesh(new BoxGeometry(0.56, 0.012, 0.56), light);\n    field.position.y = surfaceY;\n    field.rotation.y = rng.range(-0.05, 0.05); // never laid down square\n    group.add(field);\n    const square = new InstancedMesh(new BoxGeometry(0.068, 0.014, 0.068), shade, 32);\n    const m = new Matrix4();\n    let n = 0;\n    for (let row = 0; row < 8; row++) {\n      for (let col = 0; col < 8; col++) {\n        if ((row + col) % 2 === 0) continue;\n        m.setPosition((col - 3.5) * 0.07, surfaceY + 0.002, (row - 3.5) * 0.07);\n        square.setMatrixAt(n++, m);\n      }\n    }\n    square.instanceMatrix.needsUpdate = true;\n    square.rotation.y = field.rotation.y;\n    group.add(square);\n    // Men on the board — thinned out, because a game in progress has losses.\n    for (const side of [-1, 1]) {\n      const men = new InstancedMesh(\n        new CylinderGeometry(0.017, 0.023, 0.05, 6),\n        side > 0 ? light : shade,\n        8\n      );\n      let k = 0;\n      for (let col = 0; col < 8; col++) {\n        if (rng.next() < 0.25) continue;\n        m.makeTranslation(\n          (col - 3.5) * 0.07,\n          surfaceY + 0.03,\n          side * (2.5 - Math.floor(rng.next() * 2)) * 0.07\n        );\n        men.setMatrixAt(k++, m);\n      }\n      for (let rest = k; rest < 8; rest++) men.setMatrixAt(rest, m.makeScale(0, 0, 0));\n      men.instanceMatrix.needsUpdate = true;\n      men.rotation.y = field.rotation.y;\n      group.add(men);\n    }\n  } else if (game === 'cards') {\n    const face = createSurface('plaster', { color: 0xf2ead8, seed: seed + 2 });\n    for (let i = 0; i < 7; i++) {\n      const card = new Mesh(new BoxGeometry(0.09, 0.004, 0.13), face);\n      card.position.set(rng.range(-0.22, 0.22), surfaceY + 0.004 * i, rng.range(-0.18, 0.18));\n      card.rotation.y = rng.range(0, Math.PI);\n      group.add(card);\n    }\n  } else {\n    const bone = createSurface('plaster', { color: 0xefe6d2, seed: seed + 2 });\n    const cup = new Mesh(new CylinderGeometry(0.05, 0.06, 0.1, 8), dark);\n    cup.position.set(rng.range(-0.2, 0.2), surfaceY + 0.05, rng.range(-0.2, 0.2));\n    group.add(cup);\n    for (let i = 0; i < 3; i++) {\n      const die = new Mesh(new BoxGeometry(0.035, 0.035, 0.035), bone);\n      die.position.set(rng.range(-0.24, 0.24), surfaceY + 0.018, rng.range(-0.24, 0.24));\n      die.rotation.set(0, rng.range(0, Math.PI), 0);\n      group.add(die);\n    }\n  }\n\n  const seats: PropSlot[] = [];\n  for (const side of [1, -1]) {\n    const z = side * 0.78;\n    seats.push(\n      seatChair(group, rng, rng.range(-0.06, 0.06), z, side > 0 ? Math.PI : 0, {\n        seed,\n        palette,\n        style: 'stool',\n      })\n    );\n  }\n\n  const focus = focusAt(group, 0, surfaceY + 0.05, 0);\n  return { object: group, obstacleRadius: 1.15, slots: seats, seats, focus };\n}\n\n// ---- ring of seats round a fire ---------------------------------------\n\nexport interface CampCircleOptions extends GatheringOptions {\n  /** Log seats in the ring. Default 5. */\n  seats?: number;\n  /** Ring radius in metres. Default 1.9. */\n  radius?: number;\n}\n\n/**\n * Logs and stumps ringing a fire pit — the oldest gathering there is.\n * The ring is deliberately gappy and uneven; drop a `createCampfire` at\n * the origin and the `focus` is already aimed at the flames.\n */\nexport function createCampCircle(options: CampCircleOptions = {}): Gathering {\n  const seed = options.seed ?? 1;\n  const rng = new Rng(seed);\n  const palette = options.palette ?? DEFAULT_PALETTE;\n  const count = Math.max(2, Math.min(9, options.seats ?? 5));\n  const radius = options.radius ?? 1.9;\n\n  const group = new Group();\n  group.name = 'camp-circle';\n  const bark = createSurface('wood', { color: palette.trunk, seed });\n  const stone = createSurface('stone', { color: palette.rock[0], seed: seed + 1 });\n\n  // The fire ring: stones set by hand, so no two the same or evenly spaced.\n  for (let i = 0; i < 9; i++) {\n    const a = (i / 9) * Math.PI * 2 + rng.range(-0.2, 0.2);\n    const r = rng.range(0.5, 0.6);\n    const size = rng.range(0.09, 0.16);\n    const rock = new Mesh(new BoxGeometry(size, size * 0.8, size), stone);\n    rock.position.set(Math.sin(a) * r, size * 0.35, Math.cos(a) * r);\n    rock.rotation.set(rng.range(-0.2, 0.2), a, rng.range(-0.2, 0.2));\n    group.add(rock);\n  }\n\n  const seats: PropSlot[] = [];\n  for (let i = 0; i < count; i++) {\n    // A gap in the ring where the wood ran out — rings are never closed.\n    const a = (i / count) * Math.PI * 2 + rng.range(-0.16, 0.16);\n    const r = radius + rng.range(-0.15, 0.15);\n    const x = Math.sin(a) * r;\n    const z = Math.cos(a) * r;\n    const rotY = a + Math.PI;\n    const logLength = rng.range(0.7, 1.15);\n    const log = new Mesh(new CylinderGeometry(0.17, 0.19, logLength, 7), bark);\n    log.position.set(x, 0.17, z);\n    log.rotation.set(0, rotY, Math.PI / 2); // felled: lying across the facing\n    group.add(log);\n    const slot = createSlot('seat', 'sitLow', group, x, 0, z, rotY + rng.range(-0.14, 0.14));\n    seats.push(addApproach(slot, group, rng.range(0.6, 0.85)));\n  }\n\n  const focus = focusAt(group, 0, 0.4, 0);\n  return { object: group, obstacleRadius: radius + 0.4, slots: seats, seats, focus };\n}\n","import {\n  BufferAttribute,\n  BufferGeometry,\n  CatmullRomCurve3,\n  CylinderGeometry,\n  Group,\n  Mesh,\n  MeshStandardMaterial,\n  TubeGeometry,\n  Vector3,\n} from 'three';\nimport { Rng } from '../core/random';\nimport { DEFAULT_PALETTE, type Palette } from '../core/palette';\nimport { createSurface } from '../materials/surface';\nimport { wavingClothMaterial } from '../materials/clothWave';\nimport type { Prop } from '../core/types';\n\nexport interface BuntingOptions {\n  seed?: number;\n  /** Distance between the two poles (metres). Default seeded ~4.5–6. */\n  span?: number;\n  /** Pole height. Default seeded ~2.6–3.2. */\n  poleHeight?: number;\n  /** Number of hanging flaglets. Default scales with span. */\n  flags?: number;\n  /** Festive colours to cycle through. Default a bright fair palette. */\n  colors?: number[];\n  palette?: Palette;\n}\n\nconst FAIR_COLORS = [0xd23b32, 0xe8dcc0, 0x2f6fb0, 0xe0b53a, 0x3f8a52, 0xffffff];\n\n/**\n * A string of festive bunting slung between two poles: a rope in a natural\n * catenary droop, hung with little triangular pennants that flutter on the\n * same GPU cloth wave as the flags — each with its own phase, so the whole\n * line ripples like a real garland in a breeze. Self-animating: it advances\n * its own clock from the render loop, so it just flutters wherever you drop\n * it.\n */\nexport function createBunting(options: BuntingOptions = {}): Prop {\n  const rng = new Rng(options.seed ?? 1);\n  const palette = options.palette ?? DEFAULT_PALETTE;\n  const seed = options.seed ?? 1;\n  const span = options.span ?? rng.range(4.5, 6);\n  const poleH = options.poleHeight ?? rng.range(2.6, 3.2);\n  const flags = options.flags ?? Math.max(5, Math.round(span * 1.6));\n  const colors = options.colors ?? FAIR_COLORS;\n\n  const group = new Group();\n  group.name = 'bunting';\n\n  // Two poles.\n  const woodMat = createSurface('wood', { color: palette.woodDark, seed });\n  for (const sx of [-1, 1]) {\n    const pole = new Mesh(new CylinderGeometry(0.05, 0.06, poleH, 7), woodMat);\n    pole.position.set(sx * (span / 2), poleH / 2, 0);\n    group.add(pole);\n  }\n\n  // The rope: a catenary droop between the pole tops as a smooth tube.\n  const attachY = poleH - 0.1;\n  const sag = span * rng.range(0.12, 0.18);\n  const CURVE_PTS = 24;\n  const pts: Vector3[] = [];\n  for (let i = 0; i <= CURVE_PTS; i++) {\n    const t = i / CURVE_PTS;\n    const x = -span / 2 + t * span;\n    const y = attachY - 4 * sag * t * (1 - t); // parabolic droop\n    pts.push(new Vector3(x, y, 0));\n  }\n  const curve = new CatmullRomCurve3(pts);\n  const rope = new Mesh(\n    new TubeGeometry(curve, CURVE_PTS, 0.016, 5, false),\n    new MeshStandardMaterial({ color: palette.woodDark, roughness: 0.9, flatShading: true })\n  );\n  group.add(rope);\n\n  // Hanging flaglets, evenly spaced, each a tiny point-down pennant that\n  // flutters on the shared cloth wave with its own phase.\n  const flagLen = 0.42;\n  const flagW = 0.34;\n  const drivers: Array<{ uTime: { value: number } }> = [];\n  let driverMesh: Mesh | undefined;\n  for (let i = 0; i < flags; i++) {\n    const t = (i + 1) / (flags + 1);\n    const p = curve.getPoint(t);\n    const mat = wavingClothMaterial({\n      freeLen: flagLen,\n      crossLen: flagW,\n      amp: 0.05,\n      waves: 2.4,\n      speed: 2.6 + (seed % 5) * 0.1,\n      sag: 0,\n      phase: i * 0.7 + (seed % 10) * 0.3,\n      cacheKey: 'scena-bunting-v1',\n      color: colors[i % colors.length],\n      roughness: 0.9,\n    });\n    const flag = new Mesh(flagletGeometry(flagLen, flagW), mat);\n    flag.rotation.z = -Math.PI / 2; // local +X (free) → world −Y (hangs down)\n    flag.position.set(p.x, p.y - 0.01, p.z);\n    group.add(flag);\n    drivers.push(mat.userData.waveUniforms as { uTime: { value: number } });\n    if (!driverMesh) driverMesh = flag;\n  }\n\n  // One flaglet drives the shared clock for the whole string each frame.\n  if (driverMesh) {\n    driverMesh.onBeforeRender = () => {\n      const now = performance.now() * 0.001;\n      for (const u of drivers) u.uTime.value = now;\n    };\n  }\n\n  return { object: group, obstacleRadius: 0 };\n}\n\n/** A little point-down pennant in the XY plane: x from 0 (top, wide) to len (tip). */\nfunction flagletGeometry(len: number, width: number, segF = 4, segC = 2): BufferGeometry {\n  const cols = segF + 1;\n  const rows = segC + 1;\n  const position: number[] = [];\n  for (let i = 0; i < cols; i++) {\n    const u = i / segF;\n    const half = (width / 2) * (1 - u * 0.92);\n    for (let j = 0; j < rows; j++) {\n      const v = j / segC;\n      position.push(u * len, (v - 0.5) * half * 2, 0);\n    }\n  }\n  const index: number[] = [];\n  for (let i = 0; i < segF; i++) {\n    for (let j = 0; j < segC; j++) {\n      const a = i * rows + j;\n      const b = (i + 1) * rows + j;\n      const c = (i + 1) * rows + (j + 1);\n      const d = i * rows + (j + 1);\n      index.push(a, b, d, b, c, d);\n    }\n  }\n  const geo = new BufferGeometry();\n  geo.setAttribute('position', new BufferAttribute(new Float32Array(position), 3));\n  geo.setIndex(index);\n  geo.computeVertexNormals();\n  return geo;\n}\n","import { BoxGeometry, CylinderGeometry, Group, Mesh } from 'three';\nimport { Rng } from '../core/random';\nimport { DEFAULT_PALETTE, type Palette } from '../core/palette';\nimport { createSurface } from '../materials/surface';\nimport { createWater } from '../environment/water';\nimport { createDroplets } from '../materials/waterFlow';\nimport { createStream, type Stream } from './waterworks';\nimport { createStatue, type StatueFigure } from './statue';\nimport type { Prop } from '../core/types';\n\nexport interface FountainOptions {\n  seed?: number;\n  /** Basin width (square). Default seeded ~3–3.6. */\n  size?: number;\n  /** Centrepiece figure. Default seeded (small figures suit a fountain). */\n  figure?: StatueFigure;\n  /** Material of the centrepiece. Default 'stone'. */\n  centrepiece?: 'stone' | 'bronze';\n  palette?: Palette;\n}\n\nconst FOUNTAIN_FIGURES: StatueFigure[] = ['orb', 'figure', 'obelisk', 'bust'];\n\n/**\n * A tiered town fountain: a square stone basin brimming with animated water\n * (SCENA's own `createWater`, self-driven here), a central pedestal carrying\n * a small statue that spouts, an upper catch-bowl, sheets of water falling\n * between the tiers and a fine spray of droplets at the jet. Self-animating —\n * the water ripples and the spray falls with no per-frame code.\n */\nexport function createFountain(options: FountainOptions = {}): Prop {\n  const rng = new Rng(options.seed ?? 1);\n  const palette = options.palette ?? DEFAULT_PALETTE;\n  const seed = options.seed ?? 1;\n  const size = options.size ?? rng.range(3, 3.6);\n  const figure = options.figure ?? rng.pick(FOUNTAIN_FIGURES);\n\n  const group = new Group();\n  group.name = 'fountain';\n\n  const stone = createSurface('stone', { color: palette.rock[0], seed });\n  const stone2 = createSurface('stone', { color: palette.rock[1] ?? palette.rock[0], seed: seed + 5 });\n\n  // --- Square lower basin: floor + four low walls.\n  const wallH = 0.55;\n  const wallT = 0.22;\n  const half = size / 2;\n  const floor = new Mesh(new CylinderGeometry(half * 0.98, half * 0.98, 0.12, 4), stone2);\n  floor.rotation.y = Math.PI / 4;\n  floor.position.y = 0.06;\n  group.add(floor);\n  // Four low coping walls around the rim.\n  const walls: Array<[number, number, number, number]> = [\n    [0, half - wallT / 2, size, wallT],\n    [0, -(half - wallT / 2), size, wallT],\n    [half - wallT / 2, 0, wallT, size],\n    [-(half - wallT / 2), 0, wallT, size],\n  ];\n  for (const [x, z, w, d] of walls) {\n    const wall = new Mesh(new BoxGeometry(w, wallH, d), stone);\n    wall.position.set(x, wallH / 2, z);\n    group.add(wall);\n  }\n\n  // --- Lower pool: createWater, sized to the basin interior, self-driven.\n  const lowerLevel = wallH - 0.12;\n  const water = createWater({\n    level: lowerLevel,\n    size: size - wallT * 1.4,\n    resolution: 12,\n    amplitude: 0.02,\n    speed: 1.4,\n    palette,\n  });\n  group.add(water.mesh);\n\n  // --- Central pedestal + upper catch-bowl + spouting statue.\n  const pedR = size * 0.16;\n  const pedH = wallH + size * 0.24;\n  const pedestal = new Mesh(new CylinderGeometry(pedR * 0.8, pedR, pedH, 10), stone);\n  pedestal.position.y = pedH / 2;\n  group.add(pedestal);\n\n  const bowlY = pedH;\n  const bowl = new Mesh(new CylinderGeometry(size * 0.3, size * 0.14, 0.16, 12), stone);\n  bowl.position.y = bowlY;\n  group.add(bowl);\n  const bowlWater = createWater({\n    level: bowlY + 0.09,\n    size: size * 0.34, // fits inside the round catch-bowl, no corners peeking\n    resolution: 6,\n    amplitude: 0.012,\n    speed: 1.9,\n    palette,\n  });\n  group.add(bowlWater.mesh);\n\n  const statue = createStatue({\n    seed: seed + 3,\n    figure,\n    material: options.centrepiece ?? 'stone',\n    height: size * 0.62,\n    palette,\n  });\n  statue.object.position.y = bowlY + 0.08;\n  statue.object.scale.setScalar(0.9);\n  group.add(statue.object);\n\n  // --- Falling water from the bowl rim to the pool.\n  //\n  // These were STATIC translucent cylinders until 0.52 — at rest that reads\n  // as eight glass rods, because what says \"water\" is not the tint, it is\n  // that the surface travels downward and comes apart as it falls.\n  const fallHeight = bowlY - lowerLevel - 0.05;\n  const falls: Stream[] = [];\n  for (let i = 0; i < 8; i++) {\n    const a = (i / 8) * Math.PI * 2;\n    const fall = createStream({\n      height: fallHeight,\n      radius: 0.022,\n      splash: false,\n      seed: seed + i,\n      palette,\n    });\n    fall.object.position.set(Math.cos(a) * size * 0.28, bowlY - 0.05, Math.sin(a) * size * 0.28);\n    group.add(fall.object);\n    falls.push(fall);\n  }\n\n  // --- Jet spray: droplets rising from the spout and falling back.\n  const spray = createDroplets({\n    count: 22,\n    spread: size * 0.14,\n    rise: (bowlY + size * 0.2) * 0.42,\n    size: 0.28,\n    seed,\n  });\n  spray.mesh.position.y = bowlY + 0.12;\n  group.add(spray.mesh);\n\n  // --- Self-animation: ripple both pools and rain the spray, from the loop.\n  let last = performance.now() * 0.001;\n  water.mesh.onBeforeRender = () => {\n    const now = performance.now() * 0.001;\n    const dt = Math.min(0.05, Math.max(0, now - last));\n    last = now;\n    water.update(dt);\n    bowlWater.update(dt);\n    spray.update(dt);\n    for (const fall of falls) fall.update(dt);\n  };\n\n  return { object: group, obstacleRadius: half + 0.1 };\n}\n\n// ---- helpers -----------------------------------------------------------\n","import { BufferAttribute, Mesh, MeshStandardMaterial, PlaneGeometry } from 'three';\nimport { DEFAULT_PALETTE, type Palette } from '../core/palette';\nimport type { Terrain } from './terrain';\n\nexport interface WaterOptions {\n  /** World-space water surface height. Default 0.8. */\n  level?: number;\n  size?: number;\n  resolution?: number;\n  /** Wave height. Default 0.06. */\n  amplitude?: number;\n  /** Wave speed multiplier. Default 1. */\n  speed?: number;\n  palette?: Palette;\n}\n\nexport interface Water {\n  mesh: Mesh;\n  level: number;\n  /** Advance the wave animation. Call from your frame loop. */\n  update(dt: number): void;\n  /** Is ground at this height below the surface? */\n  isUnderwater(groundHeight: number): boolean;\n}\n\n/**\n * A low-poly animated water plane at a fixed level. Pair it with a\n * terrain built using the same `waterLevel` so shores blend to sand, and\n * keep scatter/agents ashore with `aboveWater(terrain, water)`.\n */\nexport function createWater(options: WaterOptions = {}): Water {\n  const level = options.level ?? 0.8;\n  const size = options.size ?? 200;\n  const resolution = options.resolution ?? 40;\n  const amplitude = options.amplitude ?? 0.06;\n  const speed = options.speed ?? 1;\n  const palette = options.palette ?? DEFAULT_PALETTE;\n\n  const geometry = new PlaneGeometry(size, size, resolution, resolution);\n  geometry.rotateX(-Math.PI / 2);\n  const positions = geometry.getAttribute('position') as BufferAttribute;\n  const mesh = new Mesh(\n    geometry,\n    new MeshStandardMaterial({\n      color: palette.water,\n      transparent: true,\n      opacity: 0.85,\n      flatShading: true,\n      metalness: 0.35,\n      roughness: 0.4,\n    })\n  );\n  mesh.name = 'water';\n  mesh.position.y = level;\n\n  let time = 0;\n  const update = (dt: number): void => {\n    time += dt * speed;\n    for (let i = 0; i < positions.count; i++) {\n      const x = positions.getX(i);\n      const z = positions.getZ(i);\n      positions.setY(\n        i,\n        Math.sin(x * 0.35 + time) * Math.cos(z * 0.3 + time * 0.8) * amplitude\n      );\n    }\n    positions.needsUpdate = true;\n    geometry.computeVertexNormals();\n  };\n  update(0);\n\n  return {\n    mesh,\n    level,\n    update,\n    isUnderwater: (groundHeight) => groundHeight < level,\n  };\n}\n\n/**\n * A scatter mask keeping placements on dry land: true when the terrain\n * at (x, z) sits above the water level plus `margin`.\n */\nexport function aboveWater(\n  terrain: Terrain,\n  water: Pick<Water, 'level'>,\n  margin = 0.25\n): (x: number, z: number) => boolean {\n  return (x, z) => terrain.heightAt(x, z) > water.level + margin;\n}\n","import {\n  AdditiveBlending,\n  BufferAttribute,\n  BufferGeometry,\n  Color,\n  DoubleSide,\n  MeshStandardMaterial,\n  Points,\n  ShaderMaterial,\n} from 'three';\nimport { Rng } from '../core/random';\n\n/**\n * Moving water — the shared material behind streams, spouts, showers and\n * spray.\n *\n * This is the same extraction `clothWave` was: the fountain has had falling\n * water and a jet since 0.9, and every tap, shower and cascade wants both.\n * Pulling them out here is what stops the bathroom set growing a second\n * water shader.\n *\n * It also fixes what was there. The fountain's \"falling water\" was a\n * **static** translucent cylinder — at rest it reads as a glass rod, and no\n * amount of tinting fixes that, because the thing that says *water* is not\n * the colour, it is that the surface is **travelling downward and breaking\n * up as it goes**. Real falling water accelerates, so it narrows and\n * stretches, and past a certain distance it stops being a sheet and becomes\n * strands.\n */\n\nexport interface FlowOptions {\n  /** Fall height in metres — sets how far down the break-up develops. */\n  length?: number;\n  /** Downward travel, in UV lengths per second. Default 1.6. */\n  speed?: number;\n  /**\n   * How far down the fall it comes apart, 0–1. Default 0.35. Low for a thin\n   * tap stream (it breaks up almost at once); high for a thick weir.\n   */\n  breakUp?: number;\n  /** How many strands across the width. Default 7. */\n  strands?: number;\n  /** Base opacity at full flow. Default 0.55. */\n  opacity?: number;\n  color?: number | Color;\n}\n\nconst FLOW_HELPERS = /* glsl */ `\n  float flowHash(vec2 p) {\n    return fract(sin(dot(p, vec2(127.1, 311.7))) * 43758.5453123);\n  }\n  float flowNoise(vec2 p) {\n    vec2 i = floor(p); vec2 f = fract(p);\n    f = f * f * (3.0 - 2.0 * f);\n    return mix(mix(flowHash(i), flowHash(i + vec2(1.0, 0.0)), f.x),\n               mix(flowHash(i + vec2(0.0, 1.0)), flowHash(i + vec2(1.0, 1.0)), f.x), f.y);\n  }\n`;\n\nconst FLOW_FRAG = /* glsl */ `\n  {\n    // Cylinder UVs run v = 0 at the bottom, 1 at the top; down below is how\n    // far the water has fallen.\n    float down = 1.0 - vUv.y;\n\n    // Falling water ACCELERATES, so equal spans of time cover longer spans of\n    // distance further down: the pattern has to stretch, not merely scroll.\n    // Scrolling at a constant rate is what makes a stream read as a barber's\n    // pole.\n    float stretched = down * down * 0.6 + down * 0.4;\n    float travel = stretched * 6.0 - uFlowTime * uFlowSpeed;\n\n    // Strands: bands around the column, wobbling as they fall.\n    float across = vUv.x * uFlowStrands;\n    float strand = flowNoise(vec2(across, travel));\n    float fine = flowNoise(vec2(across * 2.7, travel * 1.9 + 4.0));\n    float texture = strand * 0.65 + fine * 0.35;\n\n    // Break-up grows with distance fallen. Above the threshold it is a\n    // sheet; below it, holes open and it becomes separate ropes of water.\n    float apart = smoothstep(uFlowBreak, 1.0, down);\n    float mask = mix(1.0, smoothstep(0.28, 0.62, texture), apart);\n\n    // The leading edges catch the light — the bright rim is most of what\n    // makes water read as wet rather than as coloured glass. It has to be a\n    // strong, LOCAL highlight: a uniformly pale tube is a rod, whatever it is\n    // tinted, because what the eye reads as water is the variation along the\n    // length and not the colour.\n    float edge = smoothstep(0.38, 0.78, texture) * (0.4 + apart * 0.6);\n    diffuseColor.rgb = mix(uFlowColor * 0.8, vec3(1.25), edge);\n\n    // Fade in at the lip and out at the bottom, where it meets whatever it\n    // is falling into. A stream with a hard end looks cut off.\n    float ends = smoothstep(0.0, 0.06, down) * (1.0 - smoothstep(0.86, 1.0, down));\n    // The body of the water is quite transparent and the lit edges are not —\n    // that contrast is what separates a stream from a glass rod.\n    float body = mix(0.45, 1.0, edge);\n    diffuseColor.a *= uFlowOpacity * uFlowRate * mask * ends * body;\n  }\n`;\n\n/**\n * A material for water in motion down a surface — a spout's stream, a weir,\n * a shower's column.\n *\n * Drive it with `material.userData.flowUniforms`: `uFlowTime` every frame,\n * `uFlowRate` for how hard it is running (0 turns it off completely, which is\n * what a closed tap should look like).\n */\nexport function flowingWaterMaterial(options: FlowOptions = {}): MeshStandardMaterial {\n  const uniforms = {\n    uFlowTime: { value: 0 },\n    uFlowRate: { value: 1 },\n    uFlowSpeed: { value: options.speed ?? 1.6 },\n    uFlowBreak: { value: options.breakUp ?? 0.35 },\n    uFlowStrands: { value: options.strands ?? 7 },\n    uFlowOpacity: { value: options.opacity ?? 0.55 },\n    uFlowColor: { value: new Color(options.color ?? 0x9fd0e0) },\n  };\n\n  const material = new MeshStandardMaterial({\n    color: 0xffffff,\n    transparent: true,\n    // Water is see-through from both sides, and a stream is a thin tube: the\n    // far wall is in shot through the near one.\n    side: DoubleSide,\n    // Never write depth. Two overlapping streams sort wrong for one frame\n    // and look solid for the rest of the shot.\n    depthWrite: false,\n    roughness: 0.12,\n    metalness: 0.1,\n  });\n  material.defines = { ...(material.defines ?? {}), USE_UV: '' };\n  material.onBeforeCompile = (shader) => {\n    Object.assign(shader.uniforms, uniforms);\n    shader.fragmentShader = shader.fragmentShader\n      .replace(\n        'void main() {',\n        `uniform float uFlowTime;\n         uniform float uFlowRate;\n         uniform float uFlowSpeed;\n         uniform float uFlowBreak;\n         uniform float uFlowStrands;\n         uniform float uFlowOpacity;\n         uniform vec3 uFlowColor;\n         ${FLOW_HELPERS}\n         void main() {`\n      )\n      .replace('#include <map_fragment>', `#include <map_fragment>\\n${FLOW_FRAG}`);\n  };\n  material.customProgramCacheKey = () => 'scenaWaterFlow';\n  material.userData.flowUniforms = uniforms;\n  return material;\n}\n\n// --- droplets ------------------------------------------------------------\n\nexport interface DropletOptions {\n  /** How many points. Default 24. Each is one billboard, so keep it small. */\n  count?: number;\n  /** How far out they spread from the origin, in metres. */\n  spread?: number;\n  /**\n   * Ballistic rise before falling, in metres. A fountain jet throws water UP;\n   * a shower and a splash do not. Zero gives a pure fall.\n   */\n  rise?: number;\n  /** How far they fall, in metres. Default 0.4. */\n  fall?: number;\n  /** Point size. Default 0.28. */\n  size?: number;\n  /**\n   * Largest a droplet may get on screen, in pixels. Default 22. Point sprites\n   * scale with 1/distance and have no upper bound, so without this a splash\n   * viewed from close up becomes a screenful of glowing beach balls.\n   */\n  maxPixels?: number;\n  color?: number | Color;\n  seed?: number;\n}\n\nexport interface Droplets {\n  mesh: Points;\n  /** Advance the simulation. */\n  update(dt: number): void;\n  /** How hard it is spraying, 0–1. At 0 nothing is drawn. */\n  setRate(rate: number): void;\n}\n\nconst DROPLET_VERT = /* glsl */ `\nattribute float aPhase;\nattribute float aSpeed;\nattribute float aRad;\nattribute float aAng;\nuniform float uTime;\nuniform float uRise;\nuniform float uFall;\nuniform float uSpread;\nuniform float uSize;\nuniform float uMaxPixels;\nvarying float vLife;\nvoid main() {\n  float life = fract(uTime * aSpeed + aPhase);\n  vLife = life;\n  // Up-then-down when uRise > 0; a straight accelerating fall when it is 0.\n  // Gravity is what makes droplets read as droplets: constant-speed points\n  // are a snow effect.\n  float h = uRise > 0.0\n    ? 4.0 * life * (1.0 - life) * uRise\n    : -life * life * uFall;\n  float rad = aRad * uSpread * (uRise > 0.0 ? life : 0.35 + life * 0.65);\n  vec3 p = vec3(cos(aAng) * rad, h, sin(aAng) * rad);\n  vec4 mv = modelViewMatrix * vec4(p, 1.0);\n  // Point sprites grow without bound as the camera closes in, and a splash\n  // seen from 60 cm turns into a screenful of glowing beach balls. Cap it.\n  gl_PointSize = min(uSize * (240.0 / -mv.z), uMaxPixels);\n  gl_Position = projectionMatrix * mv;\n}`;\n\nconst DROPLET_FRAG = /* glsl */ `\nuniform vec3 uColor;\nuniform float uRate;\nvarying float vLife;\nvoid main() {\n  float d = length(gl_PointCoord - 0.5);\n  if (d > 0.5) discard;\n  // Fade in at birth, out at death; soft round dot; kept dim so many\n  // droplets read as a fine spray rather than a blown-out bloom.\n  float fade = max(0.0, 0.5 - abs(vLife - 0.5));\n  gl_FragColor = vec4(uColor, (1.0 - d * 2.0) * fade * 0.8 * uRate);\n}`;\n\n/**\n * A puff of droplets: a fountain jet, a shower's mist, the splash where a\n * stream lands.\n *\n * The only particles in the whole water set. Everything else here is shader\n * work on geometry that was going to be drawn anyway, so this is the one\n * piece with a real frame cost — keep the counts low.\n */\nexport function createDroplets(options: DropletOptions = {}): Droplets {\n  const rng = new Rng(options.seed ?? 1);\n  const count = options.count ?? 24;\n  const pos = new Float32Array(count * 3);\n  const aPhase = new Float32Array(count);\n  const aSpeed = new Float32Array(count);\n  const aRad = new Float32Array(count);\n  const aAng = new Float32Array(count);\n  for (let i = 0; i < count; i++) {\n    aPhase[i] = rng.next();\n    aSpeed[i] = rng.range(0.35, 0.7);\n    aRad[i] = rng.range(0.25, 1);\n    aAng[i] = rng.range(0, Math.PI * 2);\n  }\n  const geometry = new BufferGeometry();\n  geometry.setAttribute('position', new BufferAttribute(pos, 3));\n  geometry.setAttribute('aPhase', new BufferAttribute(aPhase, 1));\n  geometry.setAttribute('aSpeed', new BufferAttribute(aSpeed, 1));\n  geometry.setAttribute('aRad', new BufferAttribute(aRad, 1));\n  geometry.setAttribute('aAng', new BufferAttribute(aAng, 1));\n\n  const material = new ShaderMaterial({\n    uniforms: {\n      uTime: { value: 0 },\n      uRise: { value: options.rise ?? 0 },\n      uFall: { value: options.fall ?? 0.4 },\n      uSpread: { value: options.spread ?? 0.12 },\n      uSize: { value: options.size ?? 0.28 },\n      uMaxPixels: { value: options.maxPixels ?? 22 },\n      uRate: { value: 1 },\n      uColor: { value: new Color(options.color ?? 0xbfe0ee) },\n    },\n    vertexShader: DROPLET_VERT,\n    fragmentShader: DROPLET_FRAG,\n    transparent: true,\n    depthWrite: false,\n    blending: AdditiveBlending,\n  });\n  const mesh = new Points(geometry, material);\n  mesh.frustumCulled = false;\n\n  return {\n    mesh,\n    update(dt: number) {\n      material.uniforms.uTime.value += dt;\n    },\n    setRate(rate: number) {\n      const r = Math.min(1, Math.max(0, rate));\n      material.uniforms.uRate.value = r;\n      mesh.visible = r > 0.001;\n    },\n  };\n}\n","import {\n  AdditiveBlending,\n  BufferAttribute,\n  BufferGeometry,\n  CircleGeometry,\n  Color,\n  CylinderGeometry,\n  DoubleSide,\n  Group,\n  Mesh,\n  MeshStandardMaterial,\n  PlaneGeometry,\n  Points,\n  ShaderMaterial,\n} from 'three';\nimport { Rng } from '../core/random';\nimport { DEFAULT_PALETTE, type Palette } from '../core/palette';\nimport { createDroplets, flowingWaterMaterial, type Droplets } from '../materials/waterFlow';\nimport type { Prop } from '../core/types';\n\n/**\n * Waterworks — water that is doing something.\n *\n * The porcelain in a bathroom is trivial: a basin is a lathe and a tub is a\n * box with a hole in it. What makes any of it read is **water behaving** —\n * a stream that falls and breaks up, a shower's cone, a level that rises in\n * a bowl while it fills and settles when it stops. Without these, the whole\n * bathroom set is dry ceramic, which is exactly what it has been.\n *\n * Everything here takes a **flow or a level from outside**, so a tap\n * (`createValve` is already a `Manipulable` with an eased `state`) or GAMA's\n * `Automation` can drive it with no library importing another:\n *\n * ```ts\n * const stream = createStream({ height: 0.3 });\n * const basin = createFill({ radius: 0.18, depth: 0.1 });\n * game.onUpdate((t) => {\n *   stream.setFlow(tap.state);\n *   basin.fillBy(tap.state * t.delta * 0.4);\n *   stream.update(t.delta);\n *   basin.update(t.delta);\n * });\n * ```\n */\n\nexport interface StreamOptions {\n  /** Fall height in metres. Default 0.25. */\n  height?: number;\n  /** Radius at the lip. Default 0.012 — a tap, not a waterfall. */\n  radius?: number;\n  /** Flow to start at, 0–1. Default 1. */\n  flow?: number;\n  /** Add a splash where it lands. Default true. */\n  splash?: boolean;\n  color?: number;\n  seed?: number;\n  palette?: Palette;\n}\n\nexport interface Stream extends Prop {\n  /** How hard it is running, 0–1. At 0 nothing is drawn at all. */\n  setFlow(flow: number): void;\n  readonly flow: number;\n  update(dt: number): void;\n  height: number;\n}\n\n/**\n * A falling column of water: a tap, a spout, a weir.\n *\n * The origin is at the **lip**, with the water falling to `-height`, because\n * a stream is positioned by where it comes out.\n *\n * The column **narrows as it falls**, which is not decoration: falling water\n * accelerates, and the same volume per second through a faster-moving column\n * means a thinner one. Straight-sided falling water looks like a pipe.\n */\nexport function createStream(options: StreamOptions = {}): Stream {\n  const height = options.height ?? 0.25;\n  const radius = options.radius ?? 0.012;\n  const palette = options.palette ?? DEFAULT_PALETTE;\n  const seed = options.seed ?? 1;\n\n  const group = new Group();\n  group.name = 'stream';\n  const material = flowingWaterMaterial({\n    length: height,\n    color: options.color ?? new Color(palette.water).lerp(new Color(0xffffff), 0.55).getHex(),\n    // A thin stream comes apart almost at once; a thick one holds together.\n    // Note the direction: `breakUp` is HOW FAR DOWN the break-up starts, so a\n    // thin stream wants a LOW value. The first version had this inverted and\n    // gave tap water that held as a sheet all the way to the basin while a\n    // weir shattered at the lip.\n    breakUp: Math.min(0.7, 0.08 + radius * 14),\n    strands: Math.max(3, Math.round(radius * 260)),\n    speed: 1.4 + height,\n  });\n  const column = new Mesh(\n    new CylinderGeometry(radius, radius * 0.62, height, 8, 1, true),\n    material\n  );\n  column.name = 'column';\n  column.position.y = -height / 2;\n  group.add(column);\n\n  let splash: Droplets | null = null;\n  if (options.splash ?? true) {\n    splash = createDroplets({\n      count: 12,\n      spread: radius * 6,\n      rise: radius * 4,\n      fall: radius * 5,\n      // Scaled to the stream: a splash from a 5 mm tap and one from a weir\n      // are not the same size, and a constant reads as fairy lights on one\n      // and as nothing on the other.\n      size: Math.max(0.03, radius * 4),\n      maxPixels: 14,\n      seed: seed + 3,\n    });\n    splash.mesh.position.y = -height;\n    group.add(splash.mesh);\n  }\n\n  const uniforms = material.userData.flowUniforms as {\n    uFlowTime: { value: number };\n    uFlowRate: { value: number };\n  };\n  let flow = options.flow ?? 1;\n  const apply = (): void => {\n    uniforms.uFlowRate.value = flow;\n    // A closed tap must draw NOTHING. Leaving a fully transparent column in\n    // the scene still costs a transparent draw and still sorts against\n    // everything behind it.\n    column.visible = flow > 0.001;\n    splash?.setRate(flow);\n  };\n  apply();\n\n  return {\n    object: group,\n    obstacleRadius: 0,\n    height,\n    get flow() {\n      return flow;\n    },\n    setFlow(next: number) {\n      flow = Math.min(1, Math.max(0, next));\n      apply();\n    },\n    update(dt: number) {\n      uniforms.uFlowTime.value += dt;\n      splash?.update(dt);\n    },\n  };\n}\n\nexport interface SprayOptions {\n  /** How far the spray reaches down, in metres. Default 1.6. */\n  height?: number;\n  /** Radius of the head. Default 0.06. */\n  radius?: number;\n  /** Radius the cone has opened to at the bottom. Default 0.26. */\n  spread?: number;\n  flow?: number;\n  color?: number;\n  seed?: number;\n  palette?: Palette;\n}\n\nexport interface Spray extends Prop {\n  setFlow(flow: number): void;\n  readonly flow: number;\n  update(dt: number): void;\n  height: number;\n}\n\n/**\n * A shower's cone of water.\n *\n * A stream and a spray are the same material on different geometry — one is\n * a narrowing tube, the other a widening cone that comes apart far sooner,\n * because a shower head is *designed* to break the water up. Getting that\n * backwards gives a shower that looks like a poured bucket.\n */\nexport function createSpray(options: SprayOptions = {}): Spray {\n  const height = options.height ?? 1.6;\n  const radius = options.radius ?? 0.06;\n  const spread = options.spread ?? 0.26;\n  const palette = options.palette ?? DEFAULT_PALETTE;\n  const seed = options.seed ?? 1;\n\n  const group = new Group();\n  group.name = 'spray';\n  const material = flowingWaterMaterial({\n    length: height,\n    color: options.color ?? new Color(palette.water).lerp(new Color(0xffffff), 0.7).getHex(),\n    // Breaks up almost immediately: that is what a shower head is FOR.\n    breakUp: 0.06,\n    strands: 22,\n    speed: 2.6,\n    opacity: 0.3,\n  });\n  const cone = new Mesh(new CylinderGeometry(radius, spread, height, 14, 1, true), material);\n  cone.name = 'cone';\n  cone.position.y = -height / 2;\n  group.add(cone);\n\n  // Mist near the floor, where the spray has broken down entirely.\n  const mist = createDroplets({\n    count: 26,\n    spread: spread * 1.15,\n    rise: 0,\n    fall: 0.22,\n    size: 0.5,\n    maxPixels: 46,\n    color: 0xdff0f6,\n    seed: seed + 7,\n  });\n  mist.mesh.position.y = -height + 0.18;\n  group.add(mist.mesh);\n\n  const uniforms = material.userData.flowUniforms as {\n    uFlowTime: { value: number };\n    uFlowRate: { value: number };\n  };\n  let flow = options.flow ?? 1;\n  const apply = (): void => {\n    uniforms.uFlowRate.value = flow;\n    cone.visible = flow > 0.001;\n    mist.setRate(flow * 0.8);\n  };\n  apply();\n\n  return {\n    object: group,\n    obstacleRadius: 0,\n    height,\n    get flow() {\n      return flow;\n    },\n    setFlow(next: number) {\n      flow = Math.min(1, Math.max(0, next));\n      apply();\n    },\n    update(dt: number) {\n      uniforms.uFlowTime.value += dt;\n      mist.update(dt);\n    },\n  };\n}\n\nexport interface FillOptions {\n  /** Round surface of this radius. Give this OR width/depth. */\n  radius?: number;\n  /** Rectangular surface. */\n  width?: number;\n  length?: number;\n  /** How deep the container is: level 1 sits this far above the origin. */\n  depth?: number;\n  /** Starting level, 0–1. Default 0. */\n  level?: number;\n  color?: number;\n  seed?: number;\n  palette?: Palette;\n}\n\nexport interface Fill extends Prop {\n  /** Where the surface sits, 0 (empty) to 1 (brim). */\n  readonly level: number;\n  /** Set the level directly. */\n  setLevel(level: number): void;\n  /** Add (or, negative, drain) this much level. Disturbs the surface. */\n  fillBy(amount: number): void;\n  /** Splash it — a hand going in, something dropped. */\n  disturb(amount?: number): void;\n  update(dt: number): void;\n}\n\n\n/**\n * The water inside a container — a basin, a tub, a bucket, a pool.\n *\n * The level is the whole prop. But the detail that actually sells it is that\n * **the surface is agitated while it is filling and settles when it stops**:\n * a still disc of blue is a disc of blue, and a rippling one that goes calm\n * a few seconds after the tap closes is water. `fillBy` and `disturb` both\n * stir it; the stir decays on its own.\n *\n * The origin is the **bottom** of the container, so `depth` is the height of\n * the brim above it.\n */\nexport function createFill(options: FillOptions = {}): Fill {\n  const depth = options.depth ?? 0.12;\n  const palette = options.palette ?? DEFAULT_PALETTE;\n  const round = options.radius !== undefined;\n\n  const group = new Group();\n  group.name = 'fill';\n\n  const uniforms = {\n    uFillTime: { value: 0 },\n    uFillStir: { value: 0 },\n  };\n  // Its OWN material, not a re-patched `flowingWaterMaterial`. Replacing that\n  // one's onBeforeCompile throws away the colour and alpha patch along with\n  // the motion, and what is left renders as a plain white disc — the reuse\n  // reads well and produces nothing.\n  const material = new MeshStandardMaterial({\n    color: options.color ?? palette.water,\n    transparent: true,\n    opacity: 0.82,\n    depthWrite: false,\n    roughness: 0.08,\n    metalness: 0.25,\n    side: DoubleSide,\n  });\n  material.onBeforeCompile = (shader) => {\n    Object.assign(shader.uniforms, uniforms);\n    shader.vertexShader = shader.vertexShader\n      .replace(\n        '#include <common>',\n        '#include <common>\\nuniform float uFillTime;\\nuniform float uFillStir;'\n      )\n      .replace(\n        '#include <begin_vertex>',\n        `#include <begin_vertex>\n         {\n           // Concentric ripple plus a cross-chop, scaled by how stirred it is.\n           // The geometry is a plane in XY that gets laid flat, so the height\n           // to displace is z.\n           float r = length(position.xy);\n           float ring = sin(r * 34.0 - uFillTime * 5.0);\n           float chop = sin(position.x * 21.0 + uFillTime * 3.1)\n                      * cos(position.y * 19.0 - uFillTime * 2.4);\n           transformed.z += (ring * 0.55 + chop * 0.45) * 0.008 * uFillStir;\n         }`\n      );\n  };\n  material.customProgramCacheKey = () => 'scenaFillRipple';\n\n  const surface = new Mesh(\n    round\n      // Segments matter: a CircleGeometry is a fan from one centre vertex, so\n      // a ripple has almost nothing to displace. Rings give it something.\n      ? new CircleGeometry(options.radius ?? 0.18, 20, 0, Math.PI * 2)\n      : new PlaneGeometry(options.width ?? 0.4, options.length ?? 0.3, 8, 6),\n    material\n  );\n  surface.name = 'surface';\n  surface.rotation.x = -Math.PI / 2;\n  group.add(surface);\n\n  let level = Math.min(1, Math.max(0, options.level ?? 0));\n  let stir = 0;\n  const apply = (): void => {\n    surface.position.y = level * depth;\n    // An empty container shows no water at all — not a flat disc on the floor.\n    surface.visible = level > 0.002;\n  };\n  apply();\n\n  return {\n    object: group,\n    obstacleRadius: 0,\n    get level() {\n      return level;\n    },\n    setLevel(next: number) {\n      const clamped = Math.min(1, Math.max(0, next));\n      if (clamped !== level) stir = Math.min(1, stir + Math.abs(clamped - level) * 4);\n      level = clamped;\n      apply();\n    },\n    fillBy(amount: number) {\n      if (amount === 0) return;\n      level = Math.min(1, Math.max(0, level + amount));\n      // Running water keeps the surface moving the whole time it is running.\n      stir = Math.min(1, stir + Math.abs(amount) * 30);\n      apply();\n    },\n    disturb(amount = 0.6) {\n      stir = Math.min(1, stir + amount);\n    },\n    update(dt: number) {\n      uniforms.uFillTime.value += dt;\n      // Settles on its own. This decay is the difference between water and a\n      // permanently choppy blue disc.\n      stir = Math.max(0, stir - dt * 0.55);\n      uniforms.uFillStir.value = stir;\n    },\n  };\n}\n\nexport interface SteamOptions {\n  /** Radius of the source. Default 0.3. */\n  radius?: number;\n  /** How high it rises. Default 1.2. */\n  height?: number;\n  /** How many puffs. Default 14. */\n  count?: number;\n  /** Starting density, 0–1. Default 0. */\n  density?: number;\n  seed?: number;\n}\n\nexport interface Steam extends Prop {\n  /** How thick it is, 0–1. Builds and clears over `update`. */\n  readonly density: number;\n  /** Where it is heading. Steam takes time to fill a room and time to clear. */\n  setTarget(density: number): void;\n  update(dt: number): void;\n}\n\nconst STEAM_VERT = /* glsl */ `\nattribute float aPhase;\nattribute float aSpeed;\nattribute float aRad;\nattribute float aAng;\nuniform float uTime;\nuniform float uHeight;\nuniform float uRadius;\nuniform float uSize;\nvarying float vLife;\nvoid main() {\n  float life = fract(uTime * aSpeed + aPhase);\n  vLife = life;\n  // Rises and spreads as it goes, and slows near the top the way warm air\n  // does when it reaches the ceiling.\n  float rise = sqrt(life);\n  float rad = aRad * uRadius * (0.4 + rise * 1.5);\n  vec3 p = vec3(cos(aAng + life * 1.2) * rad, rise * uHeight, sin(aAng + life * 1.2) * rad);\n  vec4 mv = modelViewMatrix * vec4(p, 1.0);\n  gl_PointSize = uSize * (1.0 + life * 2.2) * (240.0 / -mv.z);\n  gl_Position = projectionMatrix * mv;\n}`;\n\nconst STEAM_FRAG = /* glsl */ `\nuniform float uDensity;\nvarying float vLife;\nvoid main() {\n  float d = length(gl_PointCoord - 0.5);\n  if (d > 0.5) discard;\n  // Thins as it rises, and never gets sharp — a hard-edged puff reads as a\n  // cotton ball.\n  float fade = max(0.0, 0.5 - abs(vLife - 0.5)) * (1.0 - vLife * 0.55);\n  gl_FragColor = vec4(1.0, 1.0, 1.0, (1.0 - d * 2.0) * fade * 0.34 * uDensity);\n}`;\n\n/**\n * Steam.\n *\n * The only particle system in the water set, so the only piece with a real\n * frame cost. It is worth it for one reason: steam is the only thing that\n * shows a shower has been running for a *while*. It **builds and clears\n * slowly** — a room that fogs the instant the tap opens is a smoke machine.\n */\nexport function createSteam(options: SteamOptions = {}): Steam {\n  const rng = new Rng(options.seed ?? 1);\n  const count = options.count ?? 14;\n  const radius = options.radius ?? 0.3;\n  const height = options.height ?? 1.2;\n\n  const pos = new Float32Array(count * 3);\n  const aPhase = new Float32Array(count);\n  const aSpeed = new Float32Array(count);\n  const aRad = new Float32Array(count);\n  const aAng = new Float32Array(count);\n  for (let i = 0; i < count; i++) {\n    aPhase[i] = rng.next();\n    aSpeed[i] = rng.range(0.08, 0.18);\n    aRad[i] = rng.range(0.2, 1);\n    aAng[i] = rng.range(0, Math.PI * 2);\n  }\n  const geometry = new BufferGeometry();\n  geometry.setAttribute('position', new BufferAttribute(pos, 3));\n  geometry.setAttribute('aPhase', new BufferAttribute(aPhase, 1));\n  geometry.setAttribute('aSpeed', new BufferAttribute(aSpeed, 1));\n  geometry.setAttribute('aRad', new BufferAttribute(aRad, 1));\n  geometry.setAttribute('aAng', new BufferAttribute(aAng, 1));\n\n  const material = new ShaderMaterial({\n    uniforms: {\n      uTime: { value: 0 },\n      uHeight: { value: height },\n      uRadius: { value: radius },\n      uSize: { value: 1.4 },\n      uDensity: { value: options.density ?? 0 },\n    },\n    vertexShader: STEAM_VERT,\n    fragmentShader: STEAM_FRAG,\n    transparent: true,\n    depthWrite: false,\n    blending: AdditiveBlending,\n  });\n  const mesh = new Points(geometry, material);\n  mesh.frustumCulled = false;\n\n  const group = new Group();\n  group.name = 'steam';\n  group.add(mesh);\n\n  let density = options.density ?? 0;\n  let target = density;\n\n  return {\n    object: group,\n    obstacleRadius: 0,\n    get density() {\n      return density;\n    },\n    setTarget(next: number) {\n      target = Math.min(1, Math.max(0, next));\n    },\n    update(dt: number) {\n      material.uniforms.uTime.value += dt;\n      // Builds slowly, clears slower. Neither is instant, and the asymmetry\n      // is why a bathroom stays fogged after the shower stops.\n      const rate = target > density ? 0.32 : 0.14;\n      const step = rate * dt;\n      density = target > density ? Math.min(target, density + step) : Math.max(target, density - step);\n      material.uniforms.uDensity.value = density;\n      mesh.visible = density > 0.002;\n    },\n  };\n}\n","import {\n  BoxGeometry,\n  ConeGeometry,\n  CylinderGeometry,\n  Group,\n  Mesh,\n  SphereGeometry,\n  type Material,\n} from 'three';\nimport { Rng } from '../core/random';\nimport { DEFAULT_PALETTE, type Palette } from '../core/palette';\nimport { createSurface } from '../materials/surface';\nimport type { Prop } from '../core/types';\n\nexport type StatueFigure = 'obelisk' | 'figure' | 'orb' | 'bust' | 'beast';\nexport type StatueMaterial = 'stone' | 'bronze';\n\nexport interface StatueOptions {\n  seed?: number;\n  /** What stands on the pedestal. Default seeded. */\n  figure?: StatueFigure;\n  /** Sculpture material. Default seeded (mostly stone). */\n  material?: StatueMaterial;\n  /** Overall height in metres (pedestal + figure). Default ~3.4. */\n  height?: number;\n  palette?: Palette;\n}\n\nconst ALL_FIGURES: StatueFigure[] = ['obelisk', 'figure', 'orb', 'bust', 'beast'];\n\n/**\n * A town statue or monument: a stepped stone pedestal carrying one of five\n * seeded figures — an `obelisk`, a robed `figure`, an `orb` monument, a\n * `bust`, or a guardian `beast`. Sculpted in weathered `stone` or patinated\n * `bronze`. A natural centrepiece for a plaza or the heart of a village.\n */\nexport function createStatue(options: StatueOptions = {}): Prop {\n  const rng = new Rng(options.seed ?? 1);\n  const palette = options.palette ?? DEFAULT_PALETTE;\n  const seed = options.seed ?? 1;\n  const figure = options.figure ?? rng.pick(ALL_FIGURES);\n  const material = options.material ?? (rng.next() < 0.72 ? 'stone' : 'bronze');\n  const totalH = options.height ?? rng.range(3.1, 3.7);\n\n  const group = new Group();\n  group.name = 'statue';\n\n  const stone = createSurface('stone', { color: rng.pick(palette.rock), seed });\n  // Bronze: warm metal with a green patina drawn into the cavities.\n  const sculptMat: Material =\n    material === 'bronze'\n      ? createSurface('metal', { color: 0x9a7b46, tint: 0x3f5f43, tintAmount: 0.34, seed: seed + 4 })\n      : createSurface('stone', { color: rng.pick(palette.rock), seed: seed + 7 });\n\n  // --- Stepped pedestal (always stone).\n  const pedH = totalH * rng.range(0.32, 0.4);\n  const baseW = totalH * 0.34;\n  const tiers = 3;\n  let y = 0;\n  for (let i = 0; i < tiers; i++) {\n    const t = i / (tiers - 1);\n    const w = baseW * (1 - t * 0.34);\n    const th = (pedH * 0.42) / tiers + (i === 0 ? 0.06 : 0);\n    const step = new Mesh(new BoxGeometry(w, th, w), stone);\n    step.position.y = y + th / 2;\n    group.add(step);\n    y += th;\n  }\n  // Plinth the figure stands on.\n  const plinthW = baseW * 0.5;\n  const plinthH = pedH - y;\n  const plinth = new Mesh(new BoxGeometry(plinthW, plinthH, plinthW), stone);\n  plinth.position.y = y + plinthH / 2;\n  group.add(plinth);\n  const topY = pedH;\n  const figH = totalH - pedH;\n\n  // --- The figure.\n  const fig = new Group();\n  fig.position.y = topY;\n  group.add(fig);\n\n  if (figure === 'obelisk') {\n    const shaftH = figH * 0.86;\n    const shaft = new Mesh(new CylinderGeometry(plinthW * 0.24, plinthW * 0.34, shaftH, 4), sculptMat);\n    shaft.position.y = shaftH / 2;\n    shaft.rotation.y = Math.PI / 4;\n    fig.add(shaft);\n    const cap = new Mesh(new ConeGeometry(plinthW * 0.24 * 1.35, figH * 0.16, 4), sculptMat);\n    cap.position.y = shaftH + figH * 0.08;\n    cap.rotation.y = Math.PI / 4;\n    fig.add(cap);\n  } else if (figure === 'orb') {\n    const colH = figH * 0.62;\n    const col = new Mesh(new CylinderGeometry(plinthW * 0.2, plinthW * 0.26, colH, 10), sculptMat);\n    col.position.y = colH / 2;\n    fig.add(col);\n    const orb = new Mesh(new SphereGeometry(figH * 0.22, 16, 12), sculptMat);\n    orb.position.y = colH + figH * 0.22;\n    fig.add(orb);\n    // A tilted ring around it (an armillary hint).\n    const ring = new Mesh(new CylinderGeometry(figH * 0.28, figH * 0.28, 0.04, 20, 1, true), sculptMat);\n    ring.position.copy(orb.position);\n    ring.rotation.set(Math.PI / 2.4, 0, 0.2);\n    fig.add(ring);\n  } else if (figure === 'bust') {\n    const colH = figH * 0.52;\n    const col = new Mesh(new CylinderGeometry(plinthW * 0.22, plinthW * 0.3, colH, 8), sculptMat);\n    col.position.y = colH / 2;\n    fig.add(col);\n    const shoulders = new Mesh(new CylinderGeometry(figH * 0.2, figH * 0.26, figH * 0.2, 7), sculptMat);\n    shoulders.position.y = colH + figH * 0.1;\n    fig.add(shoulders);\n    fig.add(head(sculptMat, figH * 0.13, colH + figH * 0.32, rng));\n  } else if (figure === 'beast') {\n    // A seated guardian lion: haunches folded, chest upright, proud head.\n    const s = figH * 0.5;\n    // Rump low at the back, rising to an upright chest at the front.\n    const rump = new Mesh(new BoxGeometry(s * 0.78, s * 0.62, s * 0.9), sculptMat);\n    rump.position.set(0, s * 0.42, -s * 0.42);\n    fig.add(rump);\n    const chest = new Mesh(new BoxGeometry(s * 0.62, s * 0.95, s * 0.5), sculptMat);\n    chest.position.set(0, s * 0.62, s * 0.32);\n    fig.add(chest);\n    // Brisket fills the centre between the forelegs (no see-through gap).\n    const brisket = new Mesh(new BoxGeometry(s * 0.32, s * 0.78, s * 0.34), sculptMat);\n    brisket.position.set(0, s * 0.3, s * 0.44);\n    fig.add(brisket);\n    for (const sx of [-1, 1]) {\n      // Folded rear haunch.\n      const haunch = new Mesh(new BoxGeometry(s * 0.26, s * 0.5, s * 0.7), sculptMat);\n      haunch.position.set(sx * s * 0.32, s * 0.34, -s * 0.34);\n      fig.add(haunch);\n      // Straight foreleg down to a paw.\n      const foreleg = new Mesh(new BoxGeometry(s * 0.2, s * 0.62, s * 0.22), sculptMat);\n      foreleg.position.set(sx * s * 0.2, s * 0.31, s * 0.5);\n      fig.add(foreleg);\n      const paw = new Mesh(new BoxGeometry(s * 0.24, s * 0.14, s * 0.36), sculptMat);\n      paw.position.set(sx * s * 0.2, s * 0.07, s * 0.62);\n      fig.add(paw);\n    }\n    // Maned head over the chest.\n    const mane = new Mesh(new SphereGeometry(s * 0.36, 10, 8), sculptMat);\n    mane.position.set(0, s * 1.16, s * 0.36);\n    mane.scale.set(1, 1, 0.9);\n    fig.add(mane);\n    const muzzle = new Mesh(new BoxGeometry(s * 0.22, s * 0.2, s * 0.28), sculptMat);\n    muzzle.position.set(0, s * 1.08, s * 0.64);\n    fig.add(muzzle);\n    for (const sx of [-1, 1]) {\n      const ear = new Mesh(new BoxGeometry(s * 0.09, s * 0.11, s * 0.05), sculptMat);\n      ear.position.set(sx * s * 0.17, s * 1.4, s * 0.32);\n      fig.add(ear);\n    }\n    const tail = new Mesh(new CylinderGeometry(s * 0.045, s * 0.07, s * 0.9, 6), sculptMat);\n    tail.position.set(s * 0.34, s * 0.42, -s * 0.62);\n    tail.rotation.set(0.6, 0, -0.5);\n    fig.add(tail);\n  } else {\n    // 'figure': a robed standing figure.\n    const robeH = figH * 0.62;\n    const robe = new Mesh(new CylinderGeometry(figH * 0.14, figH * 0.24, robeH, 9), sculptMat);\n    robe.position.y = robeH / 2;\n    fig.add(robe);\n    const torso = new Mesh(new CylinderGeometry(figH * 0.13, figH * 0.15, figH * 0.18, 8), sculptMat);\n    torso.position.y = robeH + figH * 0.06;\n    fig.add(torso);\n    // Arms: one at the side, one raised or across (seeded pose).\n    const raised = rng.next() < 0.5;\n    for (const sx of [-1, 1]) {\n      const arm = new Mesh(new CylinderGeometry(figH * 0.045, figH * 0.05, figH * 0.34, 6), sculptMat);\n      if (raised && sx === 1) {\n        arm.position.set(sx * figH * 0.16, robeH + figH * 0.12, figH * 0.02);\n        arm.rotation.z = -0.9;\n      } else {\n        arm.position.set(sx * figH * 0.15, robeH - figH * 0.04, 0);\n        arm.rotation.z = sx * 0.12;\n      }\n      fig.add(arm);\n    }\n    fig.add(head(sculptMat, figH * 0.1, robeH + figH * 0.24, rng));\n  }\n\n  return { object: group, obstacleRadius: baseW * 0.72 };\n}\n\nfunction head(mat: Material, r: number, y: number, rng: Rng): Group {\n  const g = new Group();\n  const skull = new Mesh(new SphereGeometry(r, 12, 10), mat);\n  skull.scale.set(0.92, 1.08, 0.95);\n  g.add(skull);\n  g.position.y = y;\n  g.rotation.y = rng.jitter(0, 0.15);\n  return g;\n}\n","import {\n  BoxGeometry,\n  CylinderGeometry,\n  Group,\n  IcosahedronGeometry,\n  Mesh,\n  type Material,\n  TorusGeometry,\n} from 'three';\nimport { Rng } from '../core/random';\nimport { DEFAULT_PALETTE, type Palette } from '../core/palette';\nimport { createSurface } from '../materials/surface';\nimport { createCrate } from './crate';\nimport type { Prop } from '../core/types';\n\nexport type CartStyle = 'cart' | 'wagon';\nexport type CartCargo = 'empty' | 'crates' | 'barrels' | 'sacks' | 'hay';\n\nexport interface CartOptions {\n  seed?: number;\n  /** Two-wheel hand `cart` (with shafts) or four-wheel `wagon`. Default seeded. */\n  style?: CartStyle;\n  /** What it carries. Default seeded. */\n  cargo?: CartCargo;\n  palette?: Palette;\n}\n\nconst ALL_STYLES: CartStyle[] = ['cart', 'wagon'];\nconst ALL_CARGO: CartCargo[] = ['empty', 'crates', 'barrels', 'sacks', 'hay'];\n\n/**\n * A wooden cart or wagon: spoked wheels with iron tyres, a planked bed with\n * low sideboards, and either two pull-shafts (a hand `cart`) or four wheels\n * (a `wagon`). Optionally loaded with crates, barrels, sacks or hay. Forward\n * is +X.\n */\nexport function createCart(options: CartOptions = {}): Prop {\n  const rng = new Rng(options.seed ?? 1);\n  const palette = options.palette ?? DEFAULT_PALETTE;\n  const seed = options.seed ?? 1;\n  const style = options.style ?? rng.pick(ALL_STYLES);\n  const cargo = options.cargo ?? rng.pick(ALL_CARGO);\n\n  const group = new Group();\n  group.name = 'cart';\n\n  const plank = createSurface('plank', { color: palette.wood, seed });\n  const wood = createSurface('wood', { color: palette.woodDark, seed: seed + 2 });\n  const iron = createSurface('metal', { color: palette.metal, seed: seed + 4 });\n\n  const bedL = style === 'wagon' ? 2.6 : 2.0; // along X (forward)\n  const bedW = 1.3; // along Z\n  const wheelR = style === 'wagon' ? 0.5 : 0.56;\n  const TYRE = 1.11; // outer radius factor (rim + tyre tube) → contact lift\n  const bedY = wheelR * TYRE + 0.18;\n\n  // --- Bed + sideboards.\n  const bed = new Mesh(new BoxGeometry(bedL, 0.12, bedW), plank);\n  bed.position.y = bedY;\n  group.add(bed);\n  const boards: Array<[number, number, number, number]> = [\n    [0, bedW / 2 - 0.04, bedL, 0.08],\n    [0, -(bedW / 2 - 0.04), bedL, 0.08],\n    [bedL / 2 - 0.04, 0, 0.08, bedW],\n    [-(bedL / 2 - 0.04), 0, 0.08, bedW],\n  ];\n  for (const [x, z, w, d] of boards) {\n    const board = new Mesh(new BoxGeometry(w, 0.32, d), plank);\n    board.position.set(x, bedY + 0.22, z);\n    group.add(board);\n  }\n\n  // --- Wheels.\n  const wheelZ = bedW / 2 + 0.09;\n  const axleXs = style === 'wagon' ? [bedL * 0.32, -bedL * 0.32] : [-bedL * 0.05];\n  for (const ax of axleXs) {\n    // Front wagon wheels a touch smaller for that hand-built look.\n    const r = style === 'wagon' && ax > 0 ? wheelR * 0.82 : wheelR;\n    for (const sz of [1, -1]) {\n      const wheel = makeWheel(r, wood, iron, rng);\n      wheel.position.set(ax, r * TYRE, sz * wheelZ); // tyre contact rests at y = 0\n      group.add(wheel);\n    }\n    // Axle beam.\n    const axle = new Mesh(new CylinderGeometry(0.05, 0.05, wheelZ * 2, 6), wood);\n    axle.rotation.x = Math.PI / 2;\n    axle.position.set(ax, r * TYRE, 0);\n    group.add(axle);\n  }\n\n  // --- Two pull-shafts angling down from the front (hand cart only).\n  if (style === 'cart') {\n    for (const sz of [1, -1]) {\n      const shaft = new Mesh(new CylinderGeometry(0.045, 0.055, 1.5, 6), wood);\n      shaft.position.set(bedL / 2 + 0.55, bedY - 0.35, sz * (bedW / 2 - 0.2));\n      shaft.rotation.z = Math.PI / 2 - 0.32;\n      group.add(shaft);\n    }\n  }\n\n  // --- Cargo on the bed.\n  loadCargo(group, cargo, rng, seed, palette, bedL, bedW, bedY + 0.06, wood);\n\n  const obstacleRadius = Math.hypot(bedL, bedW) / 2 + 0.15;\n  return { object: group, obstacleRadius };\n}\n\n// ---- wheel -------------------------------------------------------------\n\n/** A spoked wheel in the XY plane (axle along Z), iron tyre + wood felloe. */\nfunction makeWheel(r: number, wood: Material, iron: Material, rng: Rng): Group {\n  const g = new Group();\n  const tyre = new Mesh(new TorusGeometry(r, r * 0.11, 6, 16), iron);\n  g.add(tyre);\n  const felloe = new Mesh(new TorusGeometry(r * 0.84, r * 0.08, 5, 14), wood);\n  g.add(felloe);\n  const hub = new Mesh(new CylinderGeometry(r * 0.16, r * 0.16, r * 0.3, 8), wood);\n  hub.rotation.x = Math.PI / 2; // barrel along Z (the axle)\n  g.add(hub);\n  const spokes = rng.int(6, 8);\n  for (let i = 0; i < spokes; i++) {\n    const a = (i / spokes) * Math.PI * 2;\n    const spoke = new Mesh(new CylinderGeometry(r * 0.03, r * 0.04, r * 0.72, 5), wood);\n    spoke.position.set(Math.cos(a) * r * 0.44, Math.sin(a) * r * 0.44, 0);\n    spoke.rotation.z = a - Math.PI / 2; // point radially outward\n    g.add(spoke);\n  }\n  return g;\n}\n\n// ---- cargo -------------------------------------------------------------\n\nfunction loadCargo(\n  group: Group,\n  cargo: CartCargo,\n  rng: Rng,\n  seed: number,\n  palette: Palette,\n  bedL: number,\n  bedW: number,\n  y: number,\n  wood: Material\n): void {\n  if (cargo === 'empty') return;\n  const spread = (): [number, number] => [rng.jitter(0, bedL * 0.3), rng.jitter(0, bedW * 0.28)];\n\n  if (cargo === 'crates') {\n    const n = rng.int(2, 4);\n    for (let i = 0; i < n; i++) {\n      const crate = createCrate({ seed: seed + i * 7, size: rng.range(0.55, 0.7), palette });\n      const [x, z] = spread();\n      crate.object.position.set(x, y, z);\n      group.add(crate.object);\n    }\n  } else if (cargo === 'barrels') {\n    const barrelMat = createSurface('wood', { color: palette.wood, seed: seed + 9 });\n    const n = rng.int(3, 5);\n    for (let i = 0; i < n; i++) {\n      const barrel = new Group();\n      const body = new Mesh(new CylinderGeometry(0.24, 0.24, 0.62, 10), barrelMat);\n      body.scale.x = 1.08; // belly\n      body.position.y = 0.31;\n      barrel.add(body);\n      for (const by of [0.12, 0.5]) {\n        const band = new Mesh(new CylinderGeometry(0.255, 0.255, 0.05, 10), createSurface('metal', { color: palette.metal, seed: seed + 3 }));\n        band.position.y = by;\n        barrel.add(band);\n      }\n      const [x, z] = spread();\n      barrel.position.set(x, y, z);\n      group.add(barrel);\n    }\n  } else if (cargo === 'sacks') {\n    const sackMat = createSurface('plaster', { color: 0xbfa878, seed: seed + 5 });\n    const n = rng.int(4, 6);\n    for (let i = 0; i < n; i++) {\n      const sack = new Mesh(new IcosahedronGeometry(0.22, 1), sackMat);\n      const [x, z] = spread();\n      sack.position.set(x, y + 0.16, z);\n      sack.rotation.y = rng.range(0, Math.PI);\n      sack.scale.set(rng.range(0.9, 1.1), rng.range(1.0, 1.3), rng.range(0.9, 1.1)); // taller = plump sack\n      group.add(sack);\n    }\n  } else {\n    // hay: a heaped stack of golden blocks.\n    const hayMat = createSurface('thatch', { color: 0xc9a94a, seed: seed + 6 });\n    for (let i = 0; i < 3; i++) {\n      const bale = new Mesh(new BoxGeometry(bedL * 0.7, 0.34, bedW * 0.7), hayMat);\n      bale.position.set(rng.jitter(0, 0.1), y + 0.17 + i * 0.3, rng.jitter(0, 0.05));\n      bale.rotation.y = rng.jitter(0, 0.1);\n      bale.scale.setScalar(1 - i * 0.16);\n      group.add(bale);\n    }\n    void wood;\n  }\n}\n","import {\n  BufferAttribute,\n  BufferGeometry,\n  BoxGeometry,\n  Color,\n  CylinderGeometry,\n  Group,\n  Mesh,\n  MeshStandardMaterial,\n  SphereGeometry,\n  TorusGeometry,\n} from 'three';\nimport { Rng } from '../core/random';\nimport { DEFAULT_PALETTE, type Palette } from '../core/palette';\nimport { createSurface } from '../materials/surface';\nimport { buildTextGeometry, measureText } from '../text/textGeometry';\nimport type { Prop } from '../core/types';\n\nexport type SignKind = 'post' | 'hanging' | 'fingerpost' | 'milestone';\n\n/** One arm of a fingerpost: a place name and the way to it. */\nexport interface Direction {\n  text: string;\n  /** Compass-ish bearing in degrees the arm points (0 = +X, 90 = +Z). Default seeded. */\n  angle?: number;\n  /** Arm height up the post, in metres. Default stacked automatically. */\n  height?: number;\n}\n\nexport interface SignOptions {\n  seed?: number;\n  /** post (board on a post), hanging (a swaying shop sign), fingerpost (direction arms), milestone (carved stone). */\n  kind?: SignKind;\n  /** The words on the sign. Default a seeded place name. Ignored by fingerpost (use `directions`). */\n  text?: string;\n  /** Fingerpost arms. Default three seeded directions. */\n  directions?: Direction[];\n  /** Lettering colour (hex). Default seeded gold/cream. */\n  inkColor?: number;\n  /** Painted panel colour behind the lettering (hex). Default a seeded deep tone. */\n  panelColor?: number;\n  /** Board timber colour (hex). Default palette wood. */\n  boardColor?: number;\n  /** Overall height in metres (post top). Default per-kind. */\n  height?: number;\n  palette?: Palette;\n}\n\nconst PLACE_NAMES = ['HAVENBROOK', 'MILLFORD', 'OAKVALE', 'GREYMOOR', 'ASHFORD', 'WESTWATCH', 'THORNWICK'];\nconst DIR_NAMES = ['MARKET', 'HARBOUR', 'THE MILL', 'CASTLE', 'FORGE', 'CHAPEL', 'FERRY', 'THE INN'];\nconst INKS = [0xf3e2a8, 0xf6ecc9, 0xe8c66a, 0xf0dcae]; // gold, cream, amber, bone\nconst PANELS = [0x22392e, 0x1e3049, 0x4a1f22, 0x243a20, 0x2a231d]; // forest, navy, oxblood, moss, soot\n\n/**\n * A signpost with real, legible lettering — the \"stylised text on props\"\n * frontier. Letters are carved as bold, rounded relief from an embedded vector\n * font (no textures, no font files, no `three/examples` loaders) and set on a\n * painted panel so they read cleanly at a distance, day or dusk.\n *\n *  - `post`      a framed board on a post, lettered on both faces.\n *  - `hanging`   a shop sign on a bracket that sways gently on its hooks —\n *                self-animated from the render loop, like the banners.\n *  - `fingerpost` a cluster of pointed arms, each naming a place and pointing\n *                the way (\"MARKET →\", \"HARBOUR →\").\n *  - `milestone` a weathered stone marker with the name painted onto it.\n */\nexport function createSign(options: SignOptions = {}): Prop {\n  const rng = new Rng(options.seed ?? 1);\n  const palette = options.palette ?? DEFAULT_PALETTE;\n  const seed = options.seed ?? 1;\n  const kind = options.kind ?? 'post';\n  const ink = options.inkColor ?? rng.pick(INKS);\n  const panel = options.panelColor ?? rng.pick(PANELS);\n\n  const group = new Group();\n  group.name = 'sign';\n\n  const wood = () => createSurface('plank', { color: options.boardColor ?? palette.wood, seed });\n  const woodDark = createSurface('wood', { color: palette.woodDark, seed: seed + 3 });\n  const iron = createSurface('metal', { color: 0x2f333b, tint: 0x14161a, tintAmount: 0.35, seed: seed + 5 });\n\n  // Bright painted lettering: a little emissive keeps it readable at dusk, but\n  // below the day/night lamp threshold (0.5) so it never glows like a lamp.\n  const inkMat = () =>\n    new MeshStandardMaterial({\n      color: ink,\n      roughness: 0.55,\n      metalness: 0.0,\n      emissive: new Color(ink).multiplyScalar(0.5),\n      emissiveIntensity: 0.32,\n    });\n\n  if (kind === 'milestone') {\n    buildMilestone(group, options.text ?? rng.pick(PLACE_NAMES), palette, seed);\n    return { object: group, obstacleRadius: 0.42 };\n  }\n\n  if (kind === 'fingerpost') {\n    const directions =\n      options.directions ??\n      pickDirections(rng, options.text ? [options.text, ...DIR_NAMES] : DIR_NAMES);\n    const postH = options.height ?? 3.4;\n    const post = new Mesh(new CylinderGeometry(0.08, 0.1, postH, 10), woodDark);\n    post.position.y = postH / 2;\n    group.add(post);\n    const cap = new Mesh(new SphereGeometry(0.13, 12, 8), iron);\n    cap.position.y = postH + 0.03;\n    group.add(cap);\n\n    const n = directions.length;\n    directions.forEach((d, i) => {\n      const angle = d.angle ?? (i / n) * Math.PI * 2 + rng.range(-0.2, 0.2);\n      const y = d.height ?? postH - 0.55 - i * 0.66;\n      const arm = fingerArm(d.text, wood(), inkMat(), panel, iron);\n      arm.position.y = y;\n      arm.rotation.y = angle;\n      group.add(arm);\n    });\n    return { object: group, obstacleRadius: 0.4 };\n  }\n\n  const text = options.text ?? rng.pick(PLACE_NAMES);\n  const boardH = 0.72;\n  const textSize = boardH * 0.5;\n  const pad = 0.34;\n  const boardW = Math.max(1.5, measureText(text, { size: textSize }) + pad * 2);\n  const boardT = 0.1;\n\n  if (kind === 'hanging') {\n    const postH = options.height ?? 3.0;\n    const post = new Mesh(new CylinderGeometry(0.075, 0.09, postH, 10), woodDark);\n    post.position.y = postH / 2;\n    group.add(post);\n    // Bracket arm reaching out over the street, with a diagonal brace.\n    const armLen = boardW * 0.5 + 0.4;\n    const arm = new Mesh(new BoxGeometry(armLen, 0.1, 0.1), iron);\n    arm.position.set(armLen / 2, postH - 0.18, 0);\n    group.add(arm);\n    const scroll = new Mesh(new TorusGeometry(0.11, 0.022, 7, 12, Math.PI * 1.4), iron);\n    scroll.position.set(armLen - 0.1, postH - 0.32, 0);\n    scroll.rotation.z = -0.4;\n    group.add(scroll);\n    const brace = new Mesh(new CylinderGeometry(0.032, 0.032, 0.6, 6), iron);\n    brace.position.set(armLen * 0.4, postH - 0.52, 0);\n    brace.rotation.z = Math.PI / 4;\n    group.add(brace);\n\n    // The board hangs from two hooks and sways — a pivot group swung from the\n    // render loop, phase seeded so neighbouring signs never swing in lockstep.\n    const armTipX = armLen - 0.14;\n    const pivot = new Group();\n    pivot.name = 'signPivot';\n    pivot.position.set(armTipX, postH - 0.24, 0);\n    group.add(pivot);\n    for (const dx of [-boardW * 0.34, boardW * 0.34]) {\n      const link = new Mesh(new TorusGeometry(0.055, 0.018, 7, 12), iron);\n      link.position.set(dx, -0.15, 0);\n      link.rotation.x = Math.PI / 2;\n      pivot.add(link);\n      const chain = new Mesh(new CylinderGeometry(0.014, 0.014, 0.28, 6), iron);\n      chain.position.set(dx, -0.16, 0);\n      pivot.add(chain);\n    }\n    const board = letteredBoard(text, boardW, boardH, boardT, wood(), inkMat(), panel, iron, textSize, true);\n    board.position.y = -0.5;\n    pivot.add(board);\n\n    // three only fires onBeforeRender on rendered objects (a Group never gets\n    // it), so the driver rides the board mesh but swings the pivot above it —\n    // then re-solves the pivot's subtree so the board draws swung this frame.\n    const phase = (seed % 100) * 0.21;\n    board.children[0].onBeforeRender = () => {\n      const t = (typeof performance !== 'undefined' ? performance.now() : 0) * 0.001;\n      pivot.rotation.z = Math.sin(t * 1.6 + phase) * 0.05;\n      pivot.updateMatrixWorld(true);\n    };\n    return { object: group, obstacleRadius: 0.3 };\n  }\n\n  // kind === 'post'\n  const postH = options.height ?? 2.15;\n  const boardCenterY = postH - boardH / 2 - 0.06;\n  for (const dx of [-boardW * 0.33, boardW * 0.33]) {\n    const post = new Mesh(new CylinderGeometry(0.06, 0.075, postH, 9), woodDark);\n    post.position.set(dx, postH / 2, 0);\n    group.add(post);\n  }\n  const board = letteredBoard(text, boardW, boardH, boardT, wood(), inkMat(), panel, iron, textSize, true);\n  board.position.y = boardCenterY;\n  group.add(board);\n  // A peaked cap rail over the board.\n  const rail = new Mesh(new BoxGeometry(boardW + 0.14, 0.09, boardT + 0.14), woodDark);\n  rail.position.y = boardCenterY + boardH / 2 + 0.07;\n  group.add(rail);\n  return { object: group, obstacleRadius: 0.3 };\n}\n\n// ---- pieces ------------------------------------------------------------\n\n/**\n * A framed board: timber plank, a recessed painted panel set proud of it, the\n * lettering raised on the panel, and iron corner studs. Two-sided when asked,\n * so a hanging sign reads from either approach.\n */\nfunction letteredBoard(\n  text: string,\n  w: number,\n  h: number,\n  t: number,\n  boardMat: MeshStandardMaterial,\n  inkMat: MeshStandardMaterial,\n  panelColor: number,\n  ironMat: MeshStandardMaterial,\n  size: number,\n  twoSided: boolean\n): Group {\n  const g = new Group();\n  const board = new Mesh(new BoxGeometry(w, h, t), boardMat);\n  g.add(board);\n\n  const panelMat = new MeshStandardMaterial({ color: panelColor, roughness: 0.62, metalness: 0.0 });\n  const faces = twoSided ? [1, -1] : [1];\n  for (const s of faces) {\n    const panel = new Mesh(new BoxGeometry(w - 0.18, h - 0.18, 0.03), panelMat);\n    panel.position.z = s * (t / 2 + 0.012);\n    g.add(panel);\n    const label = new Mesh(buildTextGeometry(text, { size, align: 'center' }).geometry, inkMat);\n    label.position.z = s * (t / 2 + 0.035);\n    if (s < 0) label.rotation.y = Math.PI;\n    g.add(label);\n  }\n  // Iron corner studs.\n  const sx = w / 2 - 0.11;\n  const sy = h / 2 - 0.11;\n  for (const cx of [-sx, sx]) {\n    for (const cy of [-sy, sy]) {\n      const stud = new Mesh(new SphereGeometry(0.035, 8, 6), ironMat);\n      stud.position.set(cx, cy, t / 2 + 0.01);\n      g.add(stud);\n    }\n  }\n  return g;\n}\n\n/** A pointed direction arm: a plank tapering to a point, with a painted stripe and lettering. */\nfunction fingerArm(\n  text: string,\n  boardMat: MeshStandardMaterial,\n  inkMat: MeshStandardMaterial,\n  panelColor: number,\n  ironMat: MeshStandardMaterial\n): Group {\n  const g = new Group();\n  const h = 0.46;\n  const t = 0.08;\n  const size = h * 0.52;\n  const textW = measureText(text, { size });\n  const len = Math.max(1.6, textW + 0.8); // room for text + the point\n  const plank = extrudePolygon(\n    [\n      [0, -h / 2],\n      [len - h * 0.85, -h / 2],\n      [len, 0],\n      [len - h * 0.85, h / 2],\n      [0, h / 2],\n    ],\n    t\n  );\n  const arm = new Mesh(plank, boardMat);\n  g.add(arm);\n  // Painted stripe running the shaft so the lettering has contrast.\n  const panelMat = new MeshStandardMaterial({ color: panelColor, roughness: 0.62 });\n  const stripe = new Mesh(new BoxGeometry(len - 0.16, h - 0.14, 0.03), panelMat);\n  stripe.position.set((len - 0.16) / 2 - 0.02, 0, t / 2 + 0.012);\n  g.add(stripe);\n  const label = new Mesh(buildTextGeometry(text, { size, align: 'left' }).geometry, inkMat);\n  label.position.set(0.24, 0, t / 2 + 0.035);\n  g.add(label);\n  // A ring where the arm meets the post.\n  const ring = new Mesh(new TorusGeometry(0.06, 0.02, 6, 10), ironMat);\n  ring.position.set(0.03, 0, 0);\n  ring.rotation.y = Math.PI / 2;\n  g.add(ring);\n  return g;\n}\n\n/** A weathered stone marker with the name painted onto it. */\nfunction buildMilestone(group: Group, text: string, palette: Palette, seed: number): void {\n  const stone = createSurface('stone', { color: palette.rock[0], seed });\n  const h = 1.0;\n  const slab = new Mesh(\n    extrudePolygon(\n      [\n        [-0.44, 0],\n        [0.44, 0],\n        [0.44, h * 0.68],\n        [0.26, h],\n        [-0.26, h],\n        [-0.44, h * 0.68],\n      ],\n      0.28\n    ),\n    stone\n  );\n  group.add(slab);\n  // A painted band and weathered off-white letters — how a real milestone is\n  // marked. The band sizes itself to the name (long names also shrink to fit\n  // the slab), raised a touch so it catches the light on grey stone.\n  const maxW = 0.74;\n  let size = 0.19;\n  let textW = measureText(text, { size });\n  if (textW > maxW - 0.1) {\n    size *= (maxW - 0.1) / textW;\n    textW = maxW - 0.1;\n  }\n  const band = new Mesh(\n    new BoxGeometry(Math.min(maxW, textW + 0.14), size + 0.18, 0.02),\n    new MeshStandardMaterial({ color: 0x30302c, roughness: 0.8 })\n  );\n  band.position.set(0, h * 0.56, 0.145);\n  group.add(band);\n  const paint = new MeshStandardMaterial({\n    color: 0xe8e3d6,\n    roughness: 0.6,\n    emissive: 0x2a2824,\n    emissiveIntensity: 0.15,\n  });\n  const label = new Mesh(buildTextGeometry(text, { size, align: 'center', depth: 0.02 }).geometry, paint);\n  label.position.set(0, h * 0.56, 0.16);\n  group.add(label);\n}\n\n// ---- geometry helper ---------------------------------------------------\n\n/**\n * Extrude a convex 2D outline (XY, CCW) to a slab of thickness `depth`, centred\n * on z=0: front + back faces (triangle fans) plus the side walls. Hand-rolled\n * so the library never reaches into `three/examples` for a geometry util.\n */\nfunction extrudePolygon(points: [number, number][], depth: number): BufferGeometry {\n  const n = points.length;\n  const hz = depth / 2;\n  const pos: number[] = [];\n  const idx: number[] = [];\n  for (const [x, y] of points) pos.push(x, y, hz);\n  for (const [x, y] of points) pos.push(x, y, -hz);\n  for (let i = 1; i < n - 1; i++) {\n    idx.push(0, i, i + 1);\n    idx.push(n, n + i + 1, n + i);\n  }\n  for (let i = 0; i < n; i++) {\n    const j = (i + 1) % n;\n    idx.push(i, n + i, j, j, n + i, n + j);\n  }\n  const geo = new BufferGeometry();\n  geo.setAttribute('position', new BufferAttribute(new Float32Array(pos), 3));\n  geo.setIndex(idx);\n  geo.computeVertexNormals();\n  geo.computeBoundingBox();\n  geo.computeBoundingSphere();\n  return geo;\n}\n\nfunction pickDirections(rng: Rng, pool: string[]): Direction[] {\n  const names = [...pool];\n  const out: Direction[] = [];\n  for (let i = 0; i < 3 && names.length; i++) {\n    const k = Math.floor(rng.next() * names.length);\n    out.push({ text: names.splice(k, 1)[0] });\n  }\n  return out;\n}\n","import { BufferAttribute, BufferGeometry } from 'three';\nimport { CAP, FONT, MISSING, type Glyph } from './font';\n\nexport type TextAlign = 'left' | 'center' | 'right';\n\nexport interface TextOptions {\n  /** Cap height in metres. Default 0.5. */\n  size?: number;\n  /** Stroke width as a fraction of cap height. Default 0.22 (bold, signage-weight). */\n  weight?: number;\n  /** Relief depth in metres (how far the letters stand off the board). Default size*0.12. */\n  depth?: number;\n  /** Extra gap between letters, in grid units. Default 0.6. */\n  tracking?: number;\n  /** Horizontal anchor. Default 'center'. */\n  align?: TextAlign;\n  /** Vertical placement: 'baseline' puts y=0 at the baseline; 'center' centres the cap band on y=0. Default 'center'. */\n  baseline?: 'baseline' | 'center';\n}\n\nexport interface TextGeometry {\n  geometry: BufferGeometry;\n  /** Total advance width in metres. */\n  width: number;\n  /** Cap height in metres. */\n  height: number;\n}\n\nfunction glyphFor(ch: string): Glyph {\n  return FONT[ch] ?? FONT[ch.toUpperCase()] ?? MISSING;\n}\n\n/** Total pen advance of a string in grid units (before scaling), for measuring. */\nfunction advanceUnits(text: string, tracking: number): number {\n  let w = 0;\n  for (let i = 0; i < text.length; i++) {\n    w += glyphFor(text[i]).advance + (i < text.length - 1 ? tracking : 0);\n  }\n  return w;\n}\n\n/**\n * Turn a string into a single carved-relief `BufferGeometry`. Each polyline\n * stroke of the vector font becomes a **solid, constant-width ribbon** with\n * mitred corners — the way a bold typeface is drawn — extruded into a shallow\n * slab (front face, side walls and a back face) and merged into one draw call.\n * Butt ends are extended by half a stroke so crossing strokes (the bar of an H,\n * the arms of an E) weld into a solid joint instead of cracking open.\n *\n * It's pure geometry built from the embedded font, so it renders the same in a\n * browser, a headless capture and a Node test — no textures, no font files, no\n * loaders. The result sits in the XY plane facing +Z, ready to lay onto a\n * board; origin follows `align` (default centred) and `baseline` (default the\n * cap band centred on y=0).\n */\nexport function buildTextGeometry(text: string, options: TextOptions = {}): TextGeometry {\n  const size = options.size ?? 0.5;\n  const weight = options.weight ?? 0.22;\n  const depth = options.depth ?? size * 0.12;\n  const tracking = options.tracking ?? 0.6;\n  const align = options.align ?? 'center';\n  const baseline = options.baseline ?? 'center';\n\n  const unit = size / CAP; // grid units → metres\n  const hw = (weight * size) / 2; // half stroke width in metres\n  const widthUnits = advanceUnits(text, tracking);\n  const width = widthUnits * unit;\n\n  const xShift = align === 'center' ? -width / 2 : align === 'right' ? -width : 0;\n  const yShift = baseline === 'center' ? -size / 2 : 0;\n\n  const pos: number[] = [];\n  const idx: number[] = [];\n  let base = 0;\n\n  /**\n   * One stroke → a mitred ribbon slab. Cross-section i contributes four\n   * vertices at base+i*4: 0 right-front, 1 left-front, 2 right-back, 3\n   * left-back (\"left\" is +perpendicular of the travel direction). All\n   * windings are CCW from outside, verified against +X travel.\n   */\n  const ribbon = (stroke: number[], gx: number): void => {\n    const n = stroke.length / 2;\n    if (n < 2) return;\n    // Points in metres, with butt ends extended by hw to weld joints.\n    const px = new Float64Array(n);\n    const py = new Float64Array(n);\n    for (let i = 0; i < n; i++) {\n      px[i] = stroke[i * 2] * unit + gx;\n      py[i] = stroke[i * 2 + 1] * unit + yShift;\n    }\n    const d0x = px[1] - px[0];\n    const d0y = py[1] - py[0];\n    const l0 = Math.hypot(d0x, d0y) || 1e-6;\n    px[0] -= (d0x / l0) * hw;\n    py[0] -= (d0y / l0) * hw;\n    const dmx = px[n - 1] - px[n - 2];\n    const dmy = py[n - 1] - py[n - 2];\n    const lm = Math.hypot(dmx, dmy) || 1e-6;\n    px[n - 1] += (dmx / lm) * hw;\n    py[n - 1] += (dmy / lm) * hw;\n\n    // Unit direction of each segment.\n    const dx = new Float64Array(n - 1);\n    const dy = new Float64Array(n - 1);\n    for (let i = 0; i < n - 1; i++) {\n      const ex = px[i + 1] - px[i];\n      const ey = py[i + 1] - py[i];\n      const l = Math.hypot(ex, ey) || 1e-6;\n      dx[i] = ex / l;\n      dy[i] = ey / l;\n    }\n\n    // Offset each vertex along its (mitred) normal; clamp the miter so sharp\n    // corners thicken instead of spiking.\n    for (let i = 0; i < n; i++) {\n      const s0 = i === 0 ? 0 : i - 1;\n      const s1 = i === n - 1 ? n - 2 : i;\n      let mx = -dy[s0] - dy[s1];\n      let my = dx[s0] + dx[s1];\n      let ml = Math.hypot(mx, my);\n      if (ml < 1e-6) {\n        mx = -dy[s1];\n        my = dx[s1];\n        ml = 1;\n      }\n      mx /= ml;\n      my /= ml;\n      const scale = hw / Math.max(0.35, mx * -dy[s1] + my * dx[s1]);\n      const lx = px[i] + mx * scale;\n      const ly = py[i] + my * scale;\n      const rx = px[i] - mx * scale;\n      const ry = py[i] - my * scale;\n      // 0 right-front, 1 left-front, 2 right-back, 3 left-back\n      pos.push(rx, ry, depth, lx, ly, depth, rx, ry, 0, lx, ly, 0);\n    }\n\n    const v = (i: number, k: number) => base + i * 4 + k;\n    for (let i = 0; i < n - 1; i++) {\n      const j = i + 1;\n      // front face (+Z)\n      idx.push(v(i, 0), v(j, 0), v(j, 1), v(i, 0), v(j, 1), v(i, 1));\n      // back face (−Z)\n      idx.push(v(i, 2), v(j, 3), v(j, 2), v(i, 2), v(i, 3), v(j, 3));\n      // right wall\n      idx.push(v(i, 0), v(i, 2), v(j, 2), v(i, 0), v(j, 2), v(j, 0));\n      // left wall\n      idx.push(v(i, 1), v(j, 3), v(i, 3), v(i, 1), v(j, 1), v(j, 3));\n    }\n    // end caps\n    const m = n - 1;\n    idx.push(v(0, 0), v(0, 1), v(0, 3), v(0, 0), v(0, 3), v(0, 2));\n    idx.push(v(m, 0), v(m, 2), v(m, 3), v(m, 0), v(m, 3), v(m, 1));\n    base += n * 4;\n  };\n\n  let penUnits = 0;\n  for (let i = 0; i < text.length; i++) {\n    const glyph = glyphFor(text[i]);\n    const gx = penUnits * unit + xShift;\n    for (const stroke of glyph.strokes) ribbon(stroke, gx);\n    penUnits += glyph.advance + tracking;\n  }\n\n  const geometry = new BufferGeometry();\n  geometry.setAttribute('position', new BufferAttribute(new Float32Array(pos), 3));\n  geometry.setIndex(idx);\n  geometry.computeVertexNormals();\n  geometry.computeBoundingBox();\n  geometry.computeBoundingSphere();\n  return { geometry, width, height: size };\n}\n\n/** Measure a string without building geometry (metres). */\nexport function measureText(text: string, options: TextOptions = {}): number {\n  const size = options.size ?? 0.5;\n  const tracking = options.tracking ?? 0.6;\n  return advanceUnits(text, tracking) * (size / CAP);\n}\n","/**\n * A compact single-stroke vector font — the kind carved into a wooden sign or\n * a milestone. Each glyph is a set of polyline strokes on a fixed grid, so it\n * turns into geometry (no textures, no font files, no `three/examples` loaders)\n * and works identically in a browser, a headless render and a Node test.\n *\n * Grid: x runs left→right from 0, y is the baseline at 0 up to the cap height\n * (`CAP`). Commas and the tail of a `Q`/`J`/`,` dip below the baseline. Every\n * glyph also carries an `advance` (how far the pen moves on to the next\n * letter), so proportional spacing falls out for free.\n */\n\nexport const CAP = 7;\n\n/** A glyph: its polyline strokes (each a flat [x,y,x,y,…] run) and pen advance. */\nexport interface Glyph {\n  strokes: number[][];\n  advance: number;\n}\n\n// Authoring helper: strokes are written as arrays of [x, y] pairs for\n// legibility, then flattened once at module load.\ntype Pt = [number, number];\nfunction g(advance: number, ...strokes: Pt[][]): Glyph {\n  return { advance, strokes: strokes.map((s) => s.flat()) };\n}\n\n// A tiny filled dot (period, colon, the foot of ! and :) — a little square\n// loop so the stroke-thickener gives it body.\nconst DOT = (x: number, y: number): Pt[] => [\n  [x - 0.25, y],\n  [x + 0.25, y],\n  [x + 0.25, y + 0.5],\n  [x - 0.25, y + 0.5],\n  [x - 0.25, y],\n];\n\n/**\n * The glyph table — humanist capitals, digits and the punctuation a signpost\n * actually needs. Lowercase is mapped onto capitals at build time, so a mixed-\n * case string still renders (medieval signage is caps anyway).\n */\nexport const FONT: Record<string, Glyph> = {\n  ' ': g(3),\n  A: g(6, [[0, 0], [2.75, 7], [5.5, 0]], [[1.15, 2.6], [4.35, 2.6]]),\n  B: g(5.6,\n    [[0, 0], [0, 7]],\n    [[0, 7], [3.5, 7], [4.6, 6.2], [4.6, 4.7], [3.5, 3.9], [0, 3.9]],\n    [[0, 3.9], [3.9, 3.9], [5, 3], [5, 0.9], [3.9, 0], [0, 0]]),\n  C: g(5.6, [[5.2, 5.4], [4.1, 6.7], [2.2, 7], [0.7, 5.9], [0, 4], [0, 3], [0.7, 1.1], [2.2, 0], [4.1, 0.3], [5.2, 1.6]]),\n  D: g(5.8, [[0, 0], [0, 7]], [[0, 7], [2.8, 7], [4.6, 5.7], [5.2, 3.5], [4.6, 1.3], [2.8, 0], [0, 0]]),\n  E: g(5.2, [[5, 7], [0, 7], [0, 0], [5, 0]], [[0, 3.5], [3.6, 3.5]]),\n  F: g(5, [[5, 7], [0, 7], [0, 0]], [[0, 3.5], [3.4, 3.5]]),\n  G: g(6, [[5.2, 5.4], [4.1, 6.7], [2.2, 7], [0.7, 5.9], [0, 4], [0, 3], [0.7, 1.1], [2.2, 0], [4.2, 0.2], [5.2, 1.4], [5.2, 3], [3.2, 3]]),\n  H: g(5.6, [[0, 0], [0, 7]], [[5.4, 0], [5.4, 7]], [[0, 3.6], [5.4, 3.6]]),\n  I: g(2, [[1, 0], [1, 7]]),\n  J: g(4.6, [[4, 7], [4, 1.7], [3.2, 0.3], [1.9, 0], [0.7, 0.7], [0, 2]]),\n  K: g(5.4, [[0, 0], [0, 7]], [[5.2, 7], [0, 3.2]], [[1.7, 4.3], [5.4, 0]]),\n  L: g(4.8, [[0, 7], [0, 0], [4.8, 0]]),\n  M: g(6.6, [[0, 0], [0, 7], [3.3, 2.4], [6.6, 7], [6.6, 0]]),\n  N: g(5.8, [[0, 0], [0, 7], [5.6, 0], [5.6, 7]]),\n  O: g(6, [[2.3, 7], [0.8, 6.1], [0, 4], [0, 3], [0.8, 0.9], [2.3, 0], [3.3, 0], [4.8, 0.9], [5.6, 3], [5.6, 4], [4.8, 6.1], [3.3, 7], [2.3, 7]]),\n  P: g(5.4, [[0, 0], [0, 7]], [[0, 7], [3.7, 7], [4.8, 6], [4.8, 4.5], [3.7, 3.6], [0, 3.6]]),\n  Q: g(6,\n    [[2.3, 7], [0.8, 6.1], [0, 4], [0, 3], [0.8, 0.9], [2.3, 0], [3.3, 0], [4.8, 0.9], [5.6, 3], [5.6, 4], [4.8, 6.1], [3.3, 7], [2.3, 7]],\n    [[3.4, 1.9], [5.8, -0.5]]),\n  R: g(5.6,\n    [[0, 0], [0, 7]],\n    [[0, 7], [3.7, 7], [4.8, 6], [4.8, 4.5], [3.7, 3.6], [0, 3.6]],\n    [[2.7, 3.6], [5.4, 0]]),\n  S: g(5.2, [[5, 5.6], [3.9, 6.8], [1.7, 7], [0.5, 6], [0.5, 4.7], [1.5, 3.9], [3.7, 3.4], [4.7, 2.6], [4.7, 1], [3.5, 0], [1.2, 0.2], [0.2, 1.4]]),\n  T: g(5, [[0, 7], [5, 7]], [[2.5, 7], [2.5, 0]]),\n  U: g(5.6, [[0, 7], [0, 2], [0.8, 0.5], [2.6, 0], [4.6, 0.5], [5.4, 2], [5.4, 7]]),\n  V: g(5.6, [[0, 7], [2.8, 0], [5.6, 7]]),\n  W: g(7.4, [[0, 7], [1.4, 0], [3.7, 5], [6, 0], [7.4, 7]]),\n  X: g(5.4, [[0, 0], [5.4, 7]], [[0, 7], [5.4, 0]]),\n  Y: g(5.4, [[0, 7], [2.7, 3.5], [5.4, 7]], [[2.7, 3.5], [2.7, 0]]),\n  Z: g(5.2, [[0, 7], [5.2, 7], [0, 0], [5.2, 0]]),\n\n  '0': g(5.4, [[2.1, 7], [0.7, 6], [0, 3.5], [0.7, 1], [2.1, 0], [3.3, 0], [4.7, 1], [5.4, 3.5], [4.7, 6], [3.3, 7], [2.1, 7]], [[0.9, 1.3], [4.5, 5.7]]),\n  '1': g(4, [[1, 5.4], [2.6, 7], [2.6, 0]], [[0.9, 0], [4.2, 0]]),\n  '2': g(5.2, [[0.4, 5.4], [1.1, 6.5], [2.6, 7], [4, 6.7], [4.7, 5.6], [4.6, 4.3], [3.7, 3.1], [0.3, 0], [5, 0]]),\n  '3': g(5.2, [[0.5, 6.2], [2, 7], [3.7, 7], [4.7, 6], [4.7, 4.8], [3.6, 3.8], [2.4, 3.8]], [[3.6, 3.8], [4.9, 2.8], [4.9, 1.1], [3.7, 0], [1.8, 0], [0.3, 1]]),\n  '4': g(5.2, [[3.7, 0], [3.7, 7], [0, 2.4], [5, 2.4]]),\n  '5': g(5.2, [[4.7, 7], [0.9, 7], [0.5, 3.9], [1.6, 4.5], [3.5, 4.5], [4.7, 3.5], [4.7, 1.4], [3.5, 0.1], [1.6, 0.1], [0.4, 1.2]]),\n  '6': g(5.2, [[4.5, 6], [3.1, 7], [1.6, 6.6], [0.6, 4.8], [0.3, 2.6], [0.9, 0.8], [2.2, 0], [3.6, 0.3], [4.6, 1.5], [4.6, 2.9], [3.6, 4], [1.9, 4.2], [0.6, 3.2]]),\n  '7': g(5.2, [[0.4, 7], [5, 7], [2, 0]]),\n  '8': g(5.4,\n    [[2.6, 3.8], [1.3, 4.5], [1.3, 5.9], [2.6, 7], [3.9, 7], [5.1, 5.9], [5.1, 4.5], [3.9, 3.8], [2.6, 3.8]],\n    [[2.6, 3.8], [1, 3], [0.5, 1.6], [1.6, 0.2], [3.6, 0.2], [4.7, 1.6], [4.2, 3], [2.6, 3.8]]),\n  '9': g(5.2, [[0.7, 1], [2.1, 0], [3.6, 0.4], [4.6, 2.2], [4.9, 4.4], [4.3, 6.2], [3, 7], [1.6, 6.7], [0.6, 5.5], [0.6, 4.1], [1.6, 3], [3.3, 2.8], [4.6, 3.8]]),\n\n  '.': g(2, DOT(0.5, 0)),\n  ',': g(2, [[0.9, 0.6], [0.9, 0], [0.2, -1]]),\n  \"'\": g(2, [[0.6, 7], [0.6, 5.3]]),\n  '\"': g(3, [[0.6, 7], [0.6, 5.3]], [[1.9, 7], [1.9, 5.3]]),\n  '!': g(2, [[0.5, 7], [0.5, 2]], DOT(0.5, 0)),\n  '?': g(4.8, [[0.4, 5.6], [1.1, 6.6], [2.5, 7], [3.7, 6.6], [4.3, 5.5], [4.1, 4.3], [2.4, 3.2], [2.4, 2]], DOT(2.4, 0)),\n  '-': g(4, [[0.5, 3.5], [3.5, 3.5]]),\n  '&': g(6,\n    [[5.6, 0], [2, 3.6], [1, 4.8], [1, 5.9], [1.9, 6.8], [3.1, 6.6], [3.5, 5.5], [3, 4.4], [0.6, 1.6], [1.6, 0.1], [3.2, 0.1], [4.6, 1.4], [5.2, 2.9]]),\n  ':': g(2, DOT(0.5, 3.9), DOT(0.5, 0.9)),\n  '/': g(4, [[0, -0.5], [3.6, 7.2]]),\n  '(': g(2.8, [[2.2, 7.4], [0.7, 5], [0.7, 2], [2.2, -0.4]]),\n  ')': g(2.8, [[0.4, 7.4], [1.9, 5], [1.9, 2], [0.4, -0.4]]),\n};\n\n/** Fallback for an unknown character: the pen just advances (like a space). */\nexport const MISSING: Glyph = FONT[' '];\n","import {\n  AdditiveBlending,\n  BoxGeometry,\n  CircleGeometry,\n  ConeGeometry,\n  CylinderGeometry,\n  DoubleSide,\n  ExtrudeGeometry,\n  Group,\n  Mesh,\n  MeshBasicMaterial,\n  MeshStandardMaterial,\n  Object3D,\n  Shape,\n  Vector3,\n} from 'three';\nimport { Rng } from '../core/random';\nimport { DEFAULT_PALETTE, type Palette } from '../core/palette';\nimport { createSurface } from '../materials/surface';\nimport { createGlass } from '../materials/glass';\nimport { createSlot, type Prop, type PropSlot } from '../core/types';\nimport { makeHalo, type LuminousClaim } from './luminous';\n\n/**\n * Aircraft — the vehicle kit grows wings.\n *\n * Same contract as the cars and boats: the prop renders and animates;\n * WHO flies it is GAMA's problem. Feed `update(dt, input)` the flight\n * state and the airplane *shows* it — the propeller spins and becomes a\n * translucent blur disc past a third throttle, the control surfaces\n * deflect with the intent (elevator, differential ailerons, rudder),\n * retractable gear folds away, and the wingtip nav lights (red port,\n * green starboard, white tail, a seeded strobe) are luminous CLAIMS\n * that drop into a `LightBudget` like any street lamp.\n *\n * Authored nose toward +z, origin at the ground contact — park it,\n * taxi it, or hand its pose to a flight controller.\n */\n\nexport interface AircraftInput {\n  /** Engine setting 0..1. Props spin with it; blur past ~0.35. */\n  throttle?: number;\n  /** Elevator deflection, -1 (nose down) .. 1 (nose up). */\n  pitch?: number;\n  /** Aileron deflection, -1 .. 1 (differential, left stick left = -1). */\n  roll?: number;\n  /** Rudder deflection, -1 .. 1. */\n  yaw?: number;\n  /** Landing gear down. Default true. Retractables fold over ~1.5 s. */\n  gearDown?: boolean;\n}\n\nexport interface AircraftProp extends Prop {\n  update(dt: number, input?: AircraftInput): void;\n  /** Nav lights + strobe — register each with a LightBudget. */\n  claims: LuminousClaim[];\n  /** Master switch for the nav lights. */\n  setLit(on: boolean): void;\n  readonly lit: boolean;\n  wingspan: number;\n  length: number;\n}\n\nexport interface PlaneOptions {\n  style?: 'prop' | 'airliner';\n  seed?: number;\n  color?: number;\n  palette?: Palette;\n}\n\ninterface NavLight {\n  material: MeshStandardMaterial;\n  halo: ReturnType<typeof makeHalo>;\n  base: number;\n  /** Strobes blink; steady lights don't. */\n  strobe: boolean;\n}\n\nfunction navLight(\n  parent: Object3D,\n  color: number,\n  x: number,\n  y: number,\n  z: number,\n  strobe = false\n): { light: NavLight; claim: LuminousClaim; anchor: Object3D } {\n  const material = new MeshStandardMaterial({ color, emissive: color, emissiveIntensity: 2 });\n  const bulb = new Mesh(new BoxGeometry(0.07, 0.07, 0.07), material);\n  bulb.position.set(x, y, z);\n  const halo = makeHalo(color, 0.55);\n  halo.position.set(x, y, z);\n  const anchor = new Object3D();\n  anchor.position.set(x, y, z);\n  parent.add(bulb, halo, anchor);\n  return {\n    light: { material, halo, base: 2, strobe },\n    claim: { anchor, color, intensity: 1.2, radius: 4, priority: 0.6, isLit: () => true },\n    anchor,\n  };\n}\n\nexport function createPlane(options: PlaneOptions = {}): AircraftProp {\n  const style = options.style ?? 'prop';\n  const seed = options.seed ?? 1;\n  const rng = new Rng(seed);\n  const palette = options.palette ?? DEFAULT_PALETTE;\n  const bodyColor =\n    options.color ?? rng.pick([0xe8e2d4, 0xd8dee6, 0xc23b3b, 0x3a6ea5, palette.metal]);\n  const skin = createSurface('paintedMetal', { color: bodyColor, seed });\n  const accent = createSurface('paintedMetal', { color: 0x2b3340, seed: seed + 1 });\n  const glass = createGlass({ tint: 0x9fb8c8 });\n\n  const group = new Group();\n  group.name = `plane-${style}`;\n\n  const navLights: NavLight[] = [];\n  const claims: LuminousClaim[] = [];\n  let lit = true;\n  const addNav = (color: number, x: number, y: number, z: number, strobe = false): void => {\n    const { light, claim } = navLight(group, color, x, y, z, strobe);\n    claim.isLit = () => lit;\n    navLights.push(light);\n    claims.push(claim);\n  };\n\n  const spinners: Object3D[] = [];\n  const blurDiscs: Mesh[] = [];\n  let elevator: Object3D | null = null;\n  let rudder: Object3D | null = null;\n  let aileronL: Object3D | null = null;\n  let aileronR: Object3D | null = null;\n  let gear: Group | null = null;\n  let gearRetracts = false;\n  let wingspan = 0;\n  let length = 0;\n  const slots: PropSlot[] = [];\n\n  const blurMaterial = new MeshBasicMaterial({\n    color: 0xdadfe8,\n    transparent: true,\n    opacity: 0,\n    side: DoubleSide,\n    blending: AdditiveBlending,\n    depthWrite: false,\n  });\n\n  if (style === 'prop') {\n    // ---- A high-wing trainer, tail-to-nose about 6.5 m.\n    wingspan = 8.6;\n    length = 6.5;\n    const deckY = 1.05; // fuselage centreline height on its gear\n    const fuselage = new Mesh(new BoxGeometry(1.0, 1.0, 4.4), skin);\n    fuselage.position.set(0, deckY, 0.1);\n    const nose = new Mesh(new BoxGeometry(0.85, 0.8, 1.0), skin);\n    nose.position.set(0, deckY, 2.6);\n    const tailboom = new Mesh(new BoxGeometry(0.5, 0.55, 1.8), skin);\n    tailboom.position.set(0, deckY + 0.08, -2.7);\n    const canopy = new Mesh(new BoxGeometry(0.9, 0.5, 1.3), glass);\n    canopy.position.set(0, deckY + 0.62, 0.75);\n    group.add(fuselage, nose, tailboom, canopy);\n\n    // The high wing, one straight plank over the cabin.\n    const wing = new Mesh(new BoxGeometry(wingspan, 0.14, 1.5), skin);\n    wing.position.set(0, deckY + 0.95, 0.55);\n    group.add(wing);\n    for (const side of [-1, 1]) {\n      const strut = new Mesh(new CylinderGeometry(0.035, 0.035, 1.65, 5), accent);\n      strut.position.set(side * 1.7, deckY + 0.35, 0.55);\n      strut.rotation.z = side * 0.9;\n      group.add(strut);\n      // Ailerons on the outer third, hinged at their leading edge.\n      const aileron = new Mesh(new BoxGeometry(1.9, 0.09, 0.45), accent);\n      aileron.position.set(0, 0, -0.22);\n      const hinge = new Object3D();\n      hinge.position.set(side * 3.1, deckY + 0.95, -0.2);\n      hinge.add(aileron);\n      group.add(hinge);\n      if (side < 0) aileronL = hinge;\n      else aileronR = hinge;\n    }\n\n    // Tail feathers: fin + rudder, stabilizer + elevator.\n    const fin = new Mesh(new BoxGeometry(0.1, 1.15, 0.8), skin);\n    fin.position.set(0, deckY + 0.85, -3.35);\n    const stab = new Mesh(new BoxGeometry(2.5, 0.09, 0.7), skin);\n    stab.position.set(0, deckY + 0.25, -3.4);\n    group.add(fin, stab);\n    const rudderMesh = new Mesh(new BoxGeometry(0.08, 1.0, 0.45), accent);\n    rudderMesh.position.set(0, 0, -0.22);\n    rudder = new Object3D();\n    rudder.position.set(0, deckY + 0.85, -3.72);\n    rudder.add(rudderMesh);\n    const elevatorMesh = new Mesh(new BoxGeometry(2.4, 0.07, 0.4), accent);\n    elevatorMesh.position.set(0, 0, -0.2);\n    elevator = new Object3D();\n    elevator.position.set(0, deckY + 0.25, -3.72);\n    elevator.add(elevatorMesh);\n    group.add(rudder, elevator);\n\n    // The propeller: two blades, a spinner, and the blur disc behind them.\n    const propPivot = new Object3D();\n    propPivot.position.set(0, deckY, 3.15);\n    const spinner = new Mesh(new ConeGeometry(0.16, 0.35, 8), accent);\n    spinner.rotation.x = Math.PI / 2;\n    spinner.position.z = 0.15;\n    propPivot.add(spinner);\n    for (const angle of [0, Math.PI]) {\n      const blade = new Mesh(new BoxGeometry(0.16, 1.1, 0.05), accent);\n      blade.position.y = Math.cos(angle) * 0.55 * (angle === 0 ? 1 : -1);\n      blade.rotation.z = angle;\n      propPivot.add(blade);\n    }\n    group.add(propPivot);\n    spinners.push(propPivot);\n    const disc = new Mesh(new CircleGeometry(1.15, 20), blurMaterial);\n    disc.position.set(0, deckY, 3.12);\n    group.add(disc);\n    blurDiscs.push(disc);\n\n    // Fixed tricycle gear — trainers don't hide their legs.\n    gear = new Group();\n    const wheel = (x: number, z: number): void => {\n      const leg = new Mesh(new BoxGeometry(0.07, 0.5, 0.12), accent);\n      leg.position.set(x, 0.5, z);\n      const tire = new Mesh(new CylinderGeometry(0.22, 0.22, 0.16, 10), accent);\n      tire.rotation.z = Math.PI / 2;\n      tire.position.set(x, 0.24, z);\n      gear!.add(leg, tire);\n    };\n    wheel(-0.85, 0.4);\n    wheel(0.85, 0.4);\n    wheel(0, 2.4);\n    group.add(gear);\n    gearRetracts = false;\n\n    slots.push(createSlot('pilot', 'drive', group, -0.22, deckY - 0.42, 0.75));\n    addNav(0xff3b30, -wingspan / 2 + 0.1, deckY + 0.95, 0.55); // port red\n    addNav(0x34d058, wingspan / 2 - 0.1, deckY + 0.95, 0.55); // starboard green\n    addNav(0xffffff, 0, deckY + 1.42, -3.35, true); // tail strobe\n  } else {\n    // ---- A short-haul airliner, about 26 m of tube.\n    wingspan = 24;\n    length = 26;\n    const deckY = 2.3;\n    const tube = new Mesh(new CylinderGeometry(1.5, 1.5, 20, 12), skin);\n    tube.rotation.x = Math.PI / 2;\n    tube.position.set(0, deckY, 0);\n    const noseCone = new Mesh(new ConeGeometry(1.5, 3.2, 12), skin);\n    noseCone.rotation.x = Math.PI / 2;\n    noseCone.position.set(0, deckY, 11.6);\n    const tailCone = new Mesh(new ConeGeometry(1.5, 4.5, 12), skin);\n    tailCone.rotation.x = -Math.PI / 2;\n    tailCone.position.set(0, deckY + 0.25, -12.2);\n    tailCone.rotation.z = Math.PI; // ugly seam down, roughly\n    const cockpit = new Mesh(new BoxGeometry(1.9, 0.6, 1.4), glass);\n    cockpit.position.set(0, deckY + 0.75, 9.6);\n    group.add(tube, noseCone, tailCone, cockpit);\n\n    // Low swept wings and their engines.\n    for (const side of [-1, 1]) {\n      const wing = new Mesh(new BoxGeometry(11, 0.3, 3.4), skin);\n      wing.position.set(side * 6.4, deckY - 0.8, -1.2);\n      wing.rotation.y = side * 0.42; // sweep\n      wing.rotation.z = side * -0.06; // dihedral\n      group.add(wing);\n      const pod = new Mesh(new CylinderGeometry(0.62, 0.55, 2.4, 10), accent);\n      pod.rotation.x = Math.PI / 2;\n      pod.position.set(side * 4.6, deckY - 1.35, 1.4);\n      group.add(pod);\n      const fan = new Object3D();\n      fan.position.set(side * 4.6, deckY - 1.35, 2.62);\n      for (const angle of [0, Math.PI / 2]) {\n        const blade = new Mesh(new BoxGeometry(0.1, 1.0, 0.04), accent);\n        blade.rotation.z = angle;\n        fan.add(blade);\n      }\n      group.add(fan);\n      spinners.push(fan);\n      const disc = new Mesh(new CircleGeometry(0.55, 16), blurMaterial);\n      disc.position.set(side * 4.6, deckY - 1.35, 2.6);\n      group.add(disc);\n      blurDiscs.push(disc);\n    }\n\n    // Swept tail: fin with rudder, stabs with one shared elevator.\n    const fin = new Mesh(new BoxGeometry(0.25, 4.2, 2.6), skin);\n    fin.position.set(0, deckY + 2.3, -11.3);\n    fin.rotation.x = -0.35;\n    group.add(fin);\n    const rudderMesh = new Mesh(new BoxGeometry(0.18, 3.2, 0.9), accent);\n    rudderMesh.position.set(0, 1.2, -0.5);\n    rudder = new Object3D();\n    rudder.position.set(0, deckY + 1.4, -12.2);\n    rudder.add(rudderMesh);\n    group.add(rudder);\n    const stab = new Mesh(new BoxGeometry(8, 0.2, 1.8), skin);\n    stab.position.set(0, deckY + 0.6, -11.4);\n    group.add(stab);\n    const elevatorMesh = new Mesh(new BoxGeometry(7.6, 0.15, 0.7), accent);\n    elevatorMesh.position.set(0, 0, -0.35);\n    elevator = new Object3D();\n    elevator.position.set(0, deckY + 0.6, -12.3);\n    elevator.add(elevatorMesh);\n    group.add(elevator);\n\n    // Retractable gear: two mains and a nose leg that fold away.\n    gear = new Group();\n    const leg = (x: number, z: number): void => {\n      const strut = new Mesh(new BoxGeometry(0.14, 1.6, 0.2), accent);\n      strut.position.set(x, 1.5, z);\n      const tire = new Mesh(new CylinderGeometry(0.45, 0.45, 0.35, 10), accent);\n      tire.rotation.z = Math.PI / 2;\n      tire.position.set(x, 0.5, z);\n      gear!.add(strut, tire);\n    };\n    leg(-1.6, -1.6);\n    leg(1.6, -1.6);\n    leg(0, 8.2);\n    group.add(gear);\n    gearRetracts = true;\n\n    slots.push(createSlot('pilot', 'drive', group, -0.45, deckY - 1.1, 9.4));\n    slots.push(createSlot('copilot', 'drive', group, 0.45, deckY - 1.1, 9.4));\n    addNav(0xff3b30, -11.6, deckY - 0.35, -3.6); // port red\n    addNav(0x34d058, 11.6, deckY - 0.35, -3.6); // starboard green\n    addNav(0xffffff, 0, deckY + 0.3, -13.8, true); // tail strobe\n    addNav(0xff3b30, 0, deckY + 1.55, 0, true); // top beacon\n  }\n\n  let spin = 0;\n  let gearState = 1; // 1 = down\n  let strobeClock = rng.range(0, 2);\n\n  const setLit = (on: boolean): void => {\n    lit = on;\n    for (const nav of navLights) {\n      nav.material.emissiveIntensity = on ? nav.base : 0.05;\n      nav.halo.visible = on;\n    }\n  };\n\n  return {\n    object: group,\n    obstacleRadius: style === 'prop' ? 4 : 12,\n    slots,\n    claims,\n    wingspan,\n    length,\n    get lit() {\n      return lit;\n    },\n    setLit,\n    update(dt, input = {}) {\n      const step = Number.isFinite(dt) ? Math.max(dt, 0) : 0;\n      const throttle = Math.min(Math.max(input.throttle ?? 0, 0), 1);\n      spin += step * (4 + throttle * 55);\n      for (const pivot of spinners) pivot.rotation.z = spin;\n      // Past a third throttle the blades read as a disc, not blades.\n      const blur = Math.min(Math.max((throttle - 0.35) / 0.3, 0), 1);\n      blurMaterial.opacity = blur * 0.28;\n      for (const disc of blurDiscs) disc.visible = blur > 0;\n\n      const pitch = Math.min(Math.max(input.pitch ?? 0, -1), 1);\n      const roll = Math.min(Math.max(input.roll ?? 0, -1), 1);\n      const yawIn = Math.min(Math.max(input.yaw ?? 0, -1), 1);\n      if (elevator) elevator.rotation.x = -pitch * 0.5;\n      if (rudder) rudder.rotation.y = -yawIn * 0.5;\n      if (aileronL) aileronL.rotation.x = roll * 0.45;\n      if (aileronR) aileronR.rotation.x = -roll * 0.45;\n\n      if (gear && gearRetracts) {\n        const target = (input.gearDown ?? true) ? 1 : 0;\n        gearState += Math.min(Math.max(target - gearState, -step / 1.5), step / 1.5);\n        gear.position.y = (1 - gearState) * 1.4; // legs fold up into the belly\n        gear.visible = gearState > 0.02;\n      }\n\n      // The strobe: two quick white pops a second, aviation-style.\n      strobeClock += step;\n      const flash = strobeClock % 1.1;\n      const strobeOn = flash < 0.06 || (flash > 0.16 && flash < 0.22);\n      for (const nav of navLights) {\n        if (!nav.strobe) continue;\n        nav.material.emissiveIntensity = lit && strobeOn ? nav.base * 1.6 : 0.05;\n        nav.halo.visible = lit && strobeOn;\n      }\n    },\n  };\n}\n\n// ---------------------------------------------------------------------------\n// Helicopter\n\nexport interface HelicopterInput {\n  /** Rotor spool, 0..1 — blades blur past ~0.5, and droop when parked. */\n  rotor?: number;\n  /** Cyclic: tilts the rotor disc to show intent, -1..1 each. */\n  cyclicPitch?: number;\n  cyclicRoll?: number;\n  /** The nose searchlight. */\n  light?: boolean;\n}\n\nexport interface HelicopterProp extends Prop {\n  update(dt: number, input?: HelicopterInput): void;\n  /** Nav lights + the searchlight — register with a LightBudget. */\n  claims: LuminousClaim[];\n  /** Aim pivot for the searchlight: rotate to sweep the beam. */\n  searchlight: Object3D;\n  /** Searchlight on/off (the claim and beam follow). */\n  setSearchlight(on: boolean): void;\n  readonly searchlightOn: boolean;\n  /** Current rotor spool, 0..1 (lerps toward the input). */\n  readonly rotor: number;\n}\n\nexport interface HelicopterOptions {\n  seed?: number;\n  color?: number;\n  palette?: Palette;\n}\n\n/**\n * A utility helicopter: cabin, boom, skids, a main rotor that droops\n * when parked and blurs into a disc when spooled, a tail rotor doing\n * the same sideways, and a nose SEARCHLIGHT — an aimable pivot with an\n * additive beam and a luminous claim, ready to be the visible half of a\n * GAMA `Flashlight` sweeping an `Illumination` field.\n */\nexport function createHelicopter(options: HelicopterOptions = {}): HelicopterProp {\n  const seed = options.seed ?? 1;\n  const rng = new Rng(seed);\n  const palette = options.palette ?? DEFAULT_PALETTE;\n  const bodyColor = options.color ?? rng.pick([0xd8a13a, 0xc23b3b, 0x3a6ea5, palette.metal]);\n  const skin = createSurface('paintedMetal', { color: bodyColor, seed });\n  const dark = createSurface('paintedMetal', { color: 0x2b3340, seed: seed + 1 });\n  const glass = createGlass({ tint: 0x9fb8c8 });\n\n  const group = new Group();\n  group.name = 'helicopter';\n  const deckY = 1.0;\n\n  // Cabin + boom + fin.\n  const cabin = new Mesh(new BoxGeometry(1.5, 1.3, 2.6), skin);\n  cabin.position.set(0, deckY + 0.35, 0.5);\n  const nose = new Mesh(new BoxGeometry(1.2, 0.9, 0.8), glass);\n  nose.position.set(0, deckY + 0.3, 1.95);\n  const boom = new Mesh(new BoxGeometry(0.4, 0.45, 3.2), skin);\n  boom.position.set(0, deckY + 0.5, -2.2);\n  const fin = new Mesh(new BoxGeometry(0.09, 0.9, 0.6), skin);\n  fin.position.set(0, deckY + 1.0, -3.7);\n  group.add(cabin, nose, boom, fin);\n\n  // Skids.\n  for (const side of [-1, 1]) {\n    const rail = new Mesh(new BoxGeometry(0.09, 0.09, 2.6), dark);\n    rail.position.set(side * 0.85, 0.1, 0.4);\n    group.add(rail);\n    for (const z of [-0.4, 1.2]) {\n      const strut = new Mesh(new CylinderGeometry(0.04, 0.04, 0.85, 5), dark);\n      strut.position.set(side * 0.75, 0.55, z);\n      strut.rotation.z = side * 0.25;\n      group.add(strut);\n    }\n  }\n\n  // The main rotor: mast, hub, blades on their own pivots (for droop),\n  // and the blur disc that replaces them at speed.\n  const mast = new Group(); // tilts with the cyclic\n  mast.position.set(0, deckY + 1.1, 0.3);\n  const mastPole = new Mesh(new CylinderGeometry(0.07, 0.09, 0.5, 6), dark);\n  mastPole.position.y = 0.1;\n  mast.add(mastPole);\n  const rotorHead = new Group(); // spins\n  rotorHead.position.y = 0.35;\n  const bladePivots: Object3D[] = [];\n  for (let i = 0; i < 3; i++) {\n    const pivot = new Object3D();\n    pivot.rotation.y = (i / 3) * Math.PI * 2;\n    const blade = new Mesh(new BoxGeometry(0.24, 0.04, 3.4), dark);\n    blade.position.z = 1.75;\n    pivot.add(blade);\n    rotorHead.add(pivot);\n    bladePivots.push(pivot);\n  }\n  mast.add(rotorHead);\n  const mainBlurMaterial = new MeshBasicMaterial({\n    color: 0xdadfe8,\n    transparent: true,\n    opacity: 0,\n    side: DoubleSide,\n    blending: AdditiveBlending,\n    depthWrite: false,\n  });\n  const mainBlur = new Mesh(new CircleGeometry(3.55, 24), mainBlurMaterial);\n  mainBlur.rotation.x = -Math.PI / 2;\n  mainBlur.position.y = 0.36;\n  mast.add(mainBlur);\n  group.add(mast);\n\n  // The tail rotor, doing the same job sideways.\n  const tailRotor = new Group();\n  tailRotor.position.set(0.28, deckY + 1.0, -3.7);\n  for (const angle of [0, Math.PI / 2]) {\n    const blade = new Mesh(new BoxGeometry(0.05, 0.9, 0.12), dark);\n    blade.rotation.x = angle;\n    tailRotor.add(blade);\n  }\n  const tailBlur = new Mesh(new CircleGeometry(0.55, 14), mainBlurMaterial);\n  tailBlur.rotation.y = Math.PI / 2;\n  tailRotor.add(tailBlur);\n  group.add(tailRotor);\n\n  // Nav lights, off the shared helper.\n  const navLights: NavLight[] = [];\n  const claims: LuminousClaim[] = [];\n  let lit = true;\n  for (const [color, x, strobe] of [\n    [0xff3b30, -0.8, false],\n    [0x34d058, 0.8, false],\n    [0xffffff, 0, true],\n  ] as Array<[number, number, boolean]>) {\n    const { light, claim } = navLight(group, color, x, deckY + 0.95, strobe ? -3.9 : 0.6, strobe);\n    claim.isLit = () => lit;\n    navLights.push(light);\n    claims.push(claim);\n  }\n\n  // The searchlight: an aimable pivot under the nose with a lens, a\n  // long additive beam, and a claim that outranks the street below.\n  const searchlight = new Object3D();\n  searchlight.position.set(0, deckY - 0.35, 1.7);\n  const lensMaterial = new MeshStandardMaterial({\n    color: 0xfff6d8,\n    emissive: 0xfff6d8,\n    emissiveIntensity: 2.4,\n  });\n  const housing = new Mesh(new CylinderGeometry(0.16, 0.2, 0.3, 10), dark);\n  housing.rotation.x = Math.PI / 2;\n  const lens = new Mesh(new CircleGeometry(0.17, 10), lensMaterial);\n  lens.position.z = 0.16;\n  const beamMaterial = new MeshBasicMaterial({\n    color: 0xfff2c0,\n    transparent: true,\n    opacity: 0.16,\n    blending: AdditiveBlending,\n    depthWrite: false,\n  });\n  const beam = new Mesh(new ConeGeometry(2.4, 14, 14, 1, true), beamMaterial);\n  beam.rotation.x = -Math.PI / 2;\n  beam.position.z = 7.16;\n  const beamHalo = makeHalo(0xfff6d8, 1.1);\n  const lightAnchor = new Object3D();\n  lightAnchor.position.z = 0.3;\n  searchlight.add(housing, lens, beam, beamHalo, lightAnchor);\n  searchlight.rotation.x = 0.5; // resting aim: down and ahead\n  group.add(searchlight);\n  let lightOn = false;\n  claims.push({\n    anchor: lightAnchor,\n    color: 0xfff6d8,\n    intensity: 5,\n    radius: 16,\n    priority: 1.5,\n    isLit: () => lightOn,\n  });\n\n  let rotorSpeed = 0;\n  let spin = 0;\n  let strobeClock = rng.range(0, 2);\n\n  const setSearchlight = (on: boolean): void => {\n    lightOn = on;\n    lensMaterial.emissiveIntensity = on ? 2.4 : 0.1;\n    beam.visible = on;\n    beamHalo.visible = on;\n  };\n  setSearchlight(false);\n\n  return {\n    object: group,\n    obstacleRadius: 3.6,\n    slots: [createSlot('pilot', 'drive', group, -0.35, deckY - 0.35, 0.9)],\n    claims,\n    searchlight,\n    setSearchlight,\n    get searchlightOn() {\n      return lightOn;\n    },\n    get rotor() {\n      return rotorSpeed;\n    },\n    update(dt, input = {}) {\n      const step = Number.isFinite(dt) ? Math.max(dt, 0) : 0;\n      const target = Math.min(Math.max(input.rotor ?? 0, 0), 1);\n      rotorSpeed += Math.min(Math.max(target - rotorSpeed, -step / 3), step / 3); // spool takes time\n      spin += step * rotorSpeed * 28;\n      rotorHead.rotation.y = spin;\n      tailRotor.rotation.x = spin * 4.7;\n\n      // Parked blades droop; spun blades cone flat with the lift.\n      const droop = 0.09 * (1 - Math.min(rotorSpeed * 1.6, 1));\n      for (const pivot of bladePivots) pivot.rotation.x = droop;\n\n      // Past half spool the blades read as a disc.\n      const blur = Math.min(Math.max((rotorSpeed - 0.5) / 0.25, 0), 1);\n      mainBlurMaterial.opacity = blur * 0.26;\n      mainBlur.visible = blur > 0;\n      tailBlur.visible = blur > 0;\n\n      // The cyclic tilts the DISC — the fuselage follows it elsewhere.\n      const cp = Math.min(Math.max(input.cyclicPitch ?? 0, -1), 1);\n      const cr = Math.min(Math.max(input.cyclicRoll ?? 0, -1), 1);\n      mast.rotation.x = cp * 0.12;\n      mast.rotation.z = -cr * 0.12;\n\n      if (input.light !== undefined && input.light !== lightOn) setSearchlight(input.light);\n\n      strobeClock += step;\n      const flash = strobeClock % 1.1;\n      const strobeOn = flash < 0.06 || (flash > 0.16 && flash < 0.22);\n      for (const nav of navLights) {\n        if (!nav.strobe) continue;\n        nav.material.emissiveIntensity = lit && strobeOn ? nav.base * 1.6 : 0.05;\n        nav.halo.visible = lit && strobeOn;\n      }\n    },\n  };\n}\n\n// ---------------------------------------------------------------------------\n// Fighter jet\n\nexport interface FighterInput extends AircraftInput {\n  /** Light the burner regardless of throttle (default: throttle > 0.8). */\n  afterburner?: boolean;\n}\n\nexport interface FighterProp extends Prop {\n  update(dt: number, input?: FighterInput): void;\n  claims: LuminousClaim[];\n  setLit(on: boolean): void;\n  readonly lit: boolean;\n  /** Under-wing anchors, each carrying a dummy round until launched. */\n  hardpoints: Object3D[];\n  /** Rounds still hanging. */\n  readonly armed: number;\n  /**\n   * Take the round off hardpoint `i`: hides the dummy and returns the\n   * launch pose in WORLD space — hand it straight to GAMA `Missiles.fire`.\n   * Null if that rail is already empty.\n   */\n  launchFrom(i: number): { position: { x: number; y: number; z: number };\n    direction: { x: number; y: number; z: number } } | null;\n  /** Hang fresh rounds on every rail. */\n  rearm(): void;\n  wingspan: number;\n  length: number;\n}\n\nexport interface FighterOptions {\n  seed?: number;\n  color?: number;\n  palette?: Palette;\n  /** Rails under the wings. Default 2. */\n  hardpoints?: number;\n}\n\n/**\n * A delta-wing fighter: extruded delta, ELEVONS (each surface mixes\n * pitch and roll — that's what elevons are), a big fin, retractable\n * gear, and an afterburner whose flame lights past 80% throttle and\n * flickers on its own seeded nerve. The under-wing hardpoints carry\n * dummy rounds; `launchFrom(i)` hands GAMA's `Missiles` a world-space\n * launch pose and hides the round, so the missile the game flies is\n * the missile the wing stops carrying.\n */\nexport function createFighterJet(options: FighterOptions = {}): FighterProp {\n  const seed = options.seed ?? 1;\n  const rng = new Rng(seed);\n  const palette = options.palette ?? DEFAULT_PALETTE;\n  const bodyColor = options.color ?? rng.pick([0x5d6a78, 0x3a4550, 0x6e7a68, palette.metal]);\n  const skin = createSurface('paintedMetal', { color: bodyColor, seed });\n  const dark = createSurface('paintedMetal', { color: 0x262c33, seed: seed + 1 });\n  const glass = createGlass({ tint: 0x88b0c8 });\n\n  const group = new Group();\n  group.name = 'fighter';\n  const deckY = 1.35;\n  const railCount = Math.min(Math.max(options.hardpoints ?? 2, 1), 4);\n\n  // Fuselage: a long box with a needle nose and a canopy bump.\n  const body = new Mesh(new BoxGeometry(1.1, 0.9, 9), skin);\n  body.position.set(0, deckY, 0);\n  const noseCone = new Mesh(new ConeGeometry(0.5, 2.6, 8), skin);\n  noseCone.rotation.x = Math.PI / 2;\n  noseCone.position.set(0, deckY, 5.8);\n  const canopy = new Mesh(new BoxGeometry(0.7, 0.5, 1.7), glass);\n  canopy.position.set(0, deckY + 0.6, 2.6);\n  const intakeL = new Mesh(new BoxGeometry(0.5, 0.6, 2.4), dark);\n  intakeL.position.set(-0.8, deckY - 0.1, 1.2);\n  const intakeR = intakeL.clone();\n  intakeR.position.x = 0.8;\n  group.add(body, noseCone, canopy, intakeL, intakeR);\n\n  // The delta: one thin extruded triangle across both sides.\n  const half = 4.6;\n  const chord = 5.6;\n  const deltaShape = new Shape();\n  deltaShape.moveTo(-half, -chord / 2);\n  deltaShape.lineTo(half, -chord / 2);\n  deltaShape.lineTo(0, chord / 2);\n  deltaShape.lineTo(-half, -chord / 2);\n  const deltaGeometry = new ExtrudeGeometry(deltaShape, { depth: 0.12, bevelEnabled: false });\n  deltaGeometry.rotateX(-Math.PI / 2);\n  const delta = new Mesh(deltaGeometry, skin);\n  delta.position.set(0, deckY - 0.15, -1.2);\n  group.add(delta);\n\n  // Elevons: two trailing surfaces that MIX pitch and roll.\n  const elevons: Object3D[] = [];\n  for (const side of [-1, 1]) {\n    const surface = new Mesh(new BoxGeometry(2.6, 0.08, 0.7), dark);\n    surface.position.set(0, 0, -0.35);\n    const hinge = new Object3D();\n    hinge.position.set(side * 2.2, deckY - 0.1, -3.9);\n    hinge.add(surface);\n    group.add(hinge);\n    elevons.push(hinge);\n  }\n  const fin = new Mesh(new BoxGeometry(0.12, 2.1, 1.9), skin);\n  fin.position.set(0, deckY + 1.15, -3.6);\n  fin.rotation.x = -0.4;\n  group.add(fin);\n  const rudderMesh = new Mesh(new BoxGeometry(0.1, 1.5, 0.6), dark);\n  rudderMesh.position.set(0, 0.7, -0.3);\n  const rudder = new Object3D();\n  rudder.position.set(0, deckY + 0.6, -4.35);\n  rudder.add(rudderMesh);\n  group.add(rudder);\n\n  // The burner: nozzle, hot core, and the flame that lights past 80%.\n  const nozzle = new Mesh(new CylinderGeometry(0.42, 0.36, 0.7, 10), dark);\n  nozzle.rotation.x = Math.PI / 2;\n  nozzle.position.set(0, deckY, -4.6);\n  group.add(nozzle);\n  const flameMaterial = new MeshBasicMaterial({\n    color: 0xffa242,\n    transparent: true,\n    opacity: 0,\n    blending: AdditiveBlending,\n    depthWrite: false,\n  });\n  const flame = new Mesh(new ConeGeometry(0.34, 2.6, 10, 1, true), flameMaterial);\n  flame.rotation.x = Math.PI / 2;\n  flame.position.set(0, deckY, -6.2);\n  const flameHalo = makeHalo(0xffa242, 1.3);\n  flameHalo.position.set(0, deckY, -5.2);\n  flameHalo.visible = false;\n  group.add(flame, flameHalo);\n\n  // Hardpoints: rails under the delta, each with a dummy round hanging.\n  const hardpoints: Object3D[] = [];\n  const rounds: Mesh[] = [];\n  for (let i = 0; i < railCount; i++) {\n    const side = i % 2 === 0 ? -1 : 1;\n    const spread = 1.3 + Math.floor(i / 2) * 1.1;\n    const rail = new Object3D();\n    rail.position.set(side * spread, deckY - 0.55, -1.4);\n    const pylon = new Mesh(new BoxGeometry(0.08, 0.28, 0.6), dark);\n    pylon.position.y = 0.14;\n    const round = new Mesh(new ConeGeometry(0.13, 1.6, 6), dark);\n    round.rotation.x = Math.PI / 2;\n    rail.add(pylon, round);\n    group.add(rail);\n    hardpoints.push(rail);\n    rounds.push(round);\n  }\n\n  // Gear, folding like the airliner's.\n  const gear = new Group();\n  for (const [x, z] of [\n    [-0.9, -0.8],\n    [0.9, -0.8],\n    [0, 4.2],\n  ]) {\n    const strut = new Mesh(new BoxGeometry(0.1, 1.1, 0.14), dark);\n    strut.position.set(x, 0.75, z);\n    const tire = new Mesh(new CylinderGeometry(0.28, 0.28, 0.2, 10), dark);\n    tire.rotation.z = Math.PI / 2;\n    tire.position.set(x, 0.28, z);\n    gear.add(strut, tire);\n  }\n  group.add(gear);\n\n  const navLights: NavLight[] = [];\n  const claims: LuminousClaim[] = [];\n  let lit = true;\n  for (const [color, x, z, strobe] of [\n    [0xff3b30, -half, -3.9, false],\n    [0x34d058, half, -3.9, false],\n    [0xffffff, 0, -4.6, true],\n  ] as Array<[number, number, number, boolean]>) {\n    const { light, claim } = navLight(group, color, x, deckY - 0.1, z, strobe);\n    claim.isLit = () => lit;\n    navLights.push(light);\n    claims.push(claim);\n  }\n\n  let gearState = 1;\n  let strobeClock = rng.range(0, 2);\n  let flick = rng.range(0, 10);\n  const launchScratch = new Vector3();\n  const dirScratch = new Vector3();\n\n  return {\n    object: group,\n    obstacleRadius: 6,\n    slots: [createSlot('pilot', 'drive', group, 0, deckY - 0.55, 2.5)],\n    claims,\n    hardpoints,\n    wingspan: half * 2,\n    length: 12,\n    get lit() {\n      return lit;\n    },\n    get armed() {\n      return rounds.filter((r) => r.visible).length;\n    },\n    setLit(on: boolean) {\n      lit = on;\n      for (const nav of navLights) {\n        nav.material.emissiveIntensity = on ? nav.base : 0.05;\n        nav.halo.visible = on;\n      }\n    },\n    launchFrom(i: number) {\n      const round = rounds[i];\n      if (!round || !round.visible) return null;\n      round.visible = false;\n      round.getWorldPosition(launchScratch);\n      dirScratch.set(0, 0, 1).applyQuaternion(group.quaternion);\n      return {\n        position: { x: launchScratch.x, y: launchScratch.y, z: launchScratch.z },\n        direction: { x: dirScratch.x, y: dirScratch.y, z: dirScratch.z },\n      };\n    },\n    rearm() {\n      for (const round of rounds) round.visible = true;\n    },\n    update(dt, input = {}) {\n      const step = Number.isFinite(dt) ? Math.max(dt, 0) : 0;\n      const throttle = Math.min(Math.max(input.throttle ?? 0, 0), 1);\n      const pitch = Math.min(Math.max(input.pitch ?? 0, -1), 1);\n      const roll = Math.min(Math.max(input.roll ?? 0, -1), 1);\n      const yawIn = Math.min(Math.max(input.yaw ?? 0, -1), 1);\n\n      // Elevons: each side is pitch PLUS its share of roll.\n      elevons[0].rotation.x = -(pitch + roll) * 0.4;\n      elevons[1].rotation.x = -(pitch - roll) * 0.4;\n      rudder.rotation.y = -yawIn * 0.45;\n\n      // The burner: past 80% throttle (or commanded), flame and flicker.\n      const burning = input.afterburner ?? throttle > 0.8;\n      flick += step;\n      const wave = 0.85 + Math.sin(flick * 31) * Math.sin(flick * 17) * 0.15;\n      flameMaterial.opacity = burning ? 0.55 * wave : 0;\n      flame.visible = burning;\n      flame.scale.set(1, wave * (0.8 + throttle * 0.5), 1);\n      flameHalo.visible = burning;\n\n      const target = (input.gearDown ?? true) ? 1 : 0;\n      gearState += Math.min(Math.max(target - gearState, -step / 1.2), step / 1.2);\n      gear.position.y = (1 - gearState) * 1.2;\n      gear.visible = gearState > 0.02;\n\n      strobeClock += step;\n      const flash = strobeClock % 1.1;\n      const strobeOn = flash < 0.06 || (flash > 0.16 && flash < 0.22);\n      for (const nav of navLights) {\n        if (!nav.strobe) continue;\n        nav.material.emissiveIntensity = lit && strobeOn ? nav.base * 1.6 : 0.05;\n        nav.halo.visible = lit && strobeOn;\n      }\n    },\n  };\n}\n","import { Color, MeshStandardMaterial } from 'three';\n\n/**\n * Stylized architectural glass — the facade material for modern windows,\n * balustrades, doors and curtain walls.\n *\n * Real transmission is far too heavy for whole facades, so this is a\n * transparent `MeshStandardMaterial` with two shader tricks patched in:\n *\n * - **Fresnel opacity**: face-on the pane stays see-through; edge-on it\n *   turns opaque and reflective, exactly how glass reads in life.\n * - **A procedural sky streak**: the reflected view direction samples a tiny\n *   built-in sky gradient, so panes carry a believable reflection with no\n *   environment map, no cube camera, no setup.\n *\n * `nightGlow` follows the house-window convention: the material's emissive\n * is set at the intensity `createDayCycle` scans for, so listing the mesh\n * (or its building) in the cycle's `lamps` makes the glass ignite at dusk —\n * the classic lit-window skyline, free.\n */\nexport interface GlassOptions {\n  /** Glass tint. Default a cool clear blue-grey. */\n  tint?: number | Color;\n  /** Face-on opacity (0–1). Default 0.24 (clear); frosted overrides higher. */\n  opacity?: number;\n  /** Milky translucent finish: higher opacity, rough, muted reflection. */\n  frosted?: boolean;\n  /** Sky-reflection strength (0–1). Default 0.55. */\n  reflect?: number;\n  /**\n   * Warm interior glow for `createDayCycle` to ignite at dusk (adds an\n   * emissive at lamp-scan intensity). Default false.\n   */\n  nightGlow?: boolean;\n  /** Sky gradient the reflection samples: zenith / horizon colours. */\n  sky?: number;\n  horizon?: number;\n}\n\nconst GLASS_FRAG_ALPHA = /* glsl */ `\n  // Fresnel: see-through face-on, mirror-like edge-on.\n  vec3 scenaV = normalize(vViewPosition);\n  float scenaFresnel = pow(1.0 - clamp(dot(normal, scenaV), 0.0, 1.0), 3.0);\n  diffuseColor.a = clamp(uGlassOpacity + (1.0 - uGlassOpacity) * scenaFresnel, 0.0, 1.0);\n`;\n\nconst GLASS_FRAG_SKY = /* glsl */ `\n  {\n    // Reflect the view ray and sample a tiny procedural sky by its height —\n    // an environment map's worth of \"glassiness\" for two mixes. View-space\n    // reflection is fine at this stylization level.\n    vec3 scenaR = reflect(-scenaV, normal);\n    float scenaUp = clamp(scenaR.y * 0.5 + 0.5, 0.0, 1.0);\n    vec3 scenaSky = mix(uGlassHorizon, uGlassSky, scenaUp);\n    totalEmissiveRadiance += scenaSky * uGlassReflect * (0.25 + 0.75 * scenaFresnel);\n  }\n`;\n\nexport function createGlass(options: GlassOptions = {}): MeshStandardMaterial {\n  const frosted = options.frosted ?? false;\n  const tint = new Color(options.tint ?? 0x9fc4d8);\n  const opacity = options.opacity ?? (frosted ? 0.62 : 0.24);\n  const reflect = (options.reflect ?? 0.55) * (frosted ? 0.35 : 1);\n\n  const material = new MeshStandardMaterial({\n    color: tint,\n    roughness: frosted ? 0.55 : 0.08,\n    metalness: 0.1,\n    transparent: true,\n    opacity,\n    depthWrite: false,\n  });\n  if (options.nightGlow) {\n    // The lamp-scan convention: emissiveIntensity > 0.5 means \"adopt me\" —\n    // createDayCycle dims it by day and ignites it at night.\n    material.emissive.set(0xffc978);\n    material.emissiveIntensity = 1.1;\n  }\n\n  const uniforms = {\n    uGlassOpacity: { value: opacity },\n    uGlassReflect: { value: reflect },\n    uGlassSky: { value: new Color(options.sky ?? 0x87a8c8) },\n    uGlassHorizon: { value: new Color(options.horizon ?? 0xd8e2e8) },\n  };\n\n  material.onBeforeCompile = (shader) => {\n    Object.assign(shader.uniforms, uniforms);\n    shader.fragmentShader = shader.fragmentShader\n      .replace(\n        '#include <common>',\n        `#include <common>\n        uniform float uGlassOpacity;\n        uniform float uGlassReflect;\n        uniform vec3 uGlassSky;\n        uniform vec3 uGlassHorizon;`\n      )\n      // After the normal is final, before lighting: fresnel drives alpha…\n      .replace('#include <normal_fragment_maps>', '#include <normal_fragment_maps>\\n' + GLASS_FRAG_ALPHA)\n      // …and the sky streak lands with the emissive term.\n      .replace('#include <emissivemap_fragment>', '#include <emissivemap_fragment>\\n' + GLASS_FRAG_SKY);\n  };\n  material.customProgramCacheKey = () => 'scena-glass-v1';\n  (material.userData as { scenaGlass?: typeof uniforms }).scenaGlass = uniforms;\n\n  return material;\n}\n","import {\n  AdditiveBlending,\n  BoxGeometry,\n  Color,\n  ConeGeometry,\n  CylinderGeometry,\n  DataTexture,\n  Group,\n  InstancedMesh,\n  Mesh,\n  MeshBasicMaterial,\n  MeshStandardMaterial,\n  Object3D,\n  RGBAFormat,\n  SphereGeometry,\n  Sprite,\n  SpriteMaterial,\n  Vector3,\n} from 'three';\nimport { Rng } from '../core/random';\nimport { DEFAULT_PALETTE, type Palette } from '../core/palette';\nimport { FONT, MISSING, CAP } from '../text/font';\nimport type { Prop } from '../core/types';\n\n/**\n * Luminous props — things that are lights, whether or not they get one.\n *\n * Every fixture here has three faces: a **body** (the mesh), a **glow**\n * (emissive bulb + additive halo sprite — always visible, costs nothing),\n * and a **claim** — the `{ anchor, color, intensity, radius, priority,\n * isLit }` it hands to a `LightBudget`, which may or may not grant it a\n * real PointLight. The claim's `isLit` closes over the fixture's own\n * state, so `setLit(false)` both darkens the prop *and* frees its slot in\n * the budget with no wiring.\n *\n * `setLit` is deliberately the same verb-shape a GAMA `linkMechanism`\n * boolean drives — a lever wired to a lamp is a lighting puzzle with no\n * imports between the libraries.\n */\n\nexport interface LuminousClaim {\n  anchor: Object3D;\n  color: number;\n  intensity: number;\n  radius: number;\n  priority: number;\n  isLit: () => boolean;\n}\n\nexport interface Luminous extends Prop {\n  readonly lit: boolean;\n  setLit(on: boolean): void;\n  /** Hand this to `createLightBudget().register(...)`. */\n  claim: LuminousClaim;\n  /** Fixtures with motion (twinkle, buzz, beam sweep) advance here. */\n  update?(dt: number): void;\n}\n\n// ---------------------------------------------------------------------------\n// The halo: one shared radial-gradient texture, built from bytes so it works\n// headless and in node tests alike — no canvas, no DOM.\n\nlet haloMap: DataTexture | null = null;\n\nfunction getHaloTexture(): DataTexture {\n  if (haloMap) return haloMap;\n  const size = 64;\n  const data = new Uint8Array(size * size * 4);\n  for (let y = 0; y < size; y++) {\n    for (let x = 0; x < size; x++) {\n      const dx = (x + 0.5) / size - 0.5;\n      const dy = (y + 0.5) / size - 0.5;\n      const r = Math.min(Math.sqrt(dx * dx + dy * dy) * 2, 1);\n      const a = Math.pow(1 - r, 2.2);\n      const i = (y * size + x) * 4;\n      data[i] = data[i + 1] = data[i + 2] = 255;\n      data[i + 3] = Math.round(a * 255);\n    }\n  }\n  haloMap = new DataTexture(data, size, size, RGBAFormat);\n  haloMap.needsUpdate = true;\n  return haloMap;\n}\n\n/** An additive glow sprite — the light you can see from across the map. */\nexport function makeHalo(color: number, scale: number): Sprite {\n  const sprite = new Sprite(\n    new SpriteMaterial({\n      map: getHaloTexture(),\n      color,\n      transparent: true,\n      opacity: 0.55,\n      blending: AdditiveBlending,\n      depthWrite: false,\n    })\n  );\n  sprite.scale.setScalar(scale);\n  return sprite;\n}\n\ninterface GlowParts {\n  bulbs: MeshStandardMaterial[];\n  halos: Sprite[];\n  baseEmissive: number[];\n}\n\nfunction makeLitness(parts: GlowParts): { lit: () => boolean; setLit: (on: boolean) => void } {\n  let lit = true;\n  return {\n    lit: () => lit,\n    setLit(on: boolean) {\n      lit = on;\n      parts.bulbs.forEach((m, i) => (m.emissiveIntensity = on ? parts.baseEmissive[i] : 0.04));\n      for (const halo of parts.halos) halo.visible = on;\n    },\n  };\n}\n\n// ---------------------------------------------------------------------------\n// Street light\n\nexport interface StreetLightOptions {\n  style?: 'village' | 'modern';\n  seed?: number;\n  height?: number;\n  palette?: Palette;\n}\n\n/**\n * A street light. `village` is a dark post with a lantern cage and a warm\n * mantle; `modern` is a slim pole whose arm cranes a cool flat head over\n * the road (light the +x side).\n */\nexport function createStreetLight(options: StreetLightOptions = {}): Luminous {\n  const style = options.style ?? 'village';\n  const rng = new Rng(options.seed ?? 1);\n  const palette = options.palette ?? DEFAULT_PALETTE;\n  const group = new Group();\n  group.name = `street-light-${style}`;\n  const metal = new MeshStandardMaterial({\n    color: style === 'village' ? 0x2c2f34 : 0x8b939c,\n    flatShading: true,\n    roughness: 0.6,\n  });\n  const glow = style === 'village' ? palette.lampGlow : 0xdfe8ff;\n  const height = options.height ?? (style === 'village' ? rng.range(2.7, 3.1) : rng.range(4.2, 4.8));\n\n  const bulbMat = new MeshStandardMaterial({\n    color: glow,\n    emissive: glow,\n    emissiveIntensity: 1.8,\n  });\n  const anchor = new Object3D();\n  let haloScale = 1.6;\n\n  if (style === 'village') {\n    const post = new Mesh(new CylinderGeometry(0.045, 0.075, height, 6), metal);\n    post.position.y = height / 2;\n    const cage = new Mesh(new BoxGeometry(0.3, 0.34, 0.3), metal);\n    cage.position.y = height + 0.12;\n    const roof = new Mesh(new ConeGeometry(0.26, 0.18, 4), metal);\n    roof.rotation.y = Math.PI / 4;\n    roof.position.y = height + 0.36;\n    const mantle = new Mesh(new SphereGeometry(0.09, 8, 6), bulbMat);\n    mantle.position.y = height + 0.1;\n    anchor.position.set(0, height + 0.05, 0);\n    group.add(post, cage, roof, mantle);\n  } else {\n    const pole = new Mesh(new CylinderGeometry(0.055, 0.08, height, 8), metal);\n    pole.position.y = height / 2;\n    const arm = new Mesh(new BoxGeometry(1.3, 0.07, 0.09), metal);\n    arm.position.set(0.6, height - 0.03, 0);\n    const head = new Mesh(new BoxGeometry(0.62, 0.09, 0.2), metal);\n    head.position.set(1.15, height - 0.08, 0);\n    const panel = new Mesh(new BoxGeometry(0.54, 0.03, 0.14), bulbMat);\n    panel.position.set(1.15, height - 0.13, 0);\n    anchor.position.set(1.15, height - 0.35, 0);\n    haloScale = 2.0;\n    group.add(pole, arm, head, panel);\n  }\n\n  const halo = makeHalo(glow, haloScale);\n  halo.position.copy(anchor.position);\n  group.add(halo, anchor);\n\n  const litness = makeLitness({ bulbs: [bulbMat], halos: [halo], baseEmissive: [1.8] });\n  return {\n    object: group,\n    obstacleRadius: 0.25,\n    get lit() {\n      return litness.lit();\n    },\n    setLit: litness.setLit,\n    claim: {\n      anchor,\n      color: glow,\n      intensity: style === 'village' ? 5 : 7,\n      radius: style === 'village' ? 10 : 14,\n      priority: 1,\n      isLit: litness.lit,\n    },\n  };\n}\n\n// ---------------------------------------------------------------------------\n// Lantern\n\nexport interface LanternLightOptions {\n  /** Hanging (hook at the origin, lantern below) or standing on its base. */\n  hanging?: boolean;\n  seed?: number;\n  color?: number;\n  palette?: Palette;\n}\n\n/** A small warm lantern — the light a hand, a porch or a market stall carries. */\nexport function createLanternLight(options: LanternLightOptions = {}): Luminous {\n  const rng = new Rng(options.seed ?? 1);\n  const palette = options.palette ?? DEFAULT_PALETTE;\n  const color = options.color ?? palette.lampGlow;\n  const group = new Group();\n  group.name = 'lantern';\n  const metal = new MeshStandardMaterial({ color: 0x33373d, flatShading: true, roughness: 0.55 });\n\n  const body = new Group();\n  const cage = new Mesh(new BoxGeometry(0.16, 0.2, 0.16), metal);\n  cage.position.y = 0.13;\n  const cap = new Mesh(new ConeGeometry(0.13, 0.09, 4), metal);\n  cap.rotation.y = Math.PI / 4;\n  cap.position.y = 0.27;\n  const base = new Mesh(new BoxGeometry(0.14, 0.03, 0.14), metal);\n  base.position.y = 0.015;\n  const bulbMat = new MeshStandardMaterial({ color, emissive: color, emissiveIntensity: 1.9 });\n  const flame = new Mesh(new SphereGeometry(0.05, 6, 5), bulbMat);\n  flame.position.y = 0.13;\n  flame.scale.y = rng.range(1.1, 1.35);\n  const halo = makeHalo(color, 0.9);\n  halo.position.y = 0.13;\n  body.add(cage, cap, base, flame, halo);\n\n  const anchor = new Object3D();\n  if (options.hanging) {\n    // Origin is the hook; the lantern swings just below it.\n    body.position.y = -0.34;\n    const loop = new Mesh(new CylinderGeometry(0.025, 0.025, 0.05, 6), metal);\n    loop.position.y = -0.03;\n    group.add(loop);\n    anchor.position.set(0, -0.21, 0);\n  } else {\n    anchor.position.set(0, 0.13, 0);\n  }\n  group.add(body, anchor);\n\n  const litness = makeLitness({ bulbs: [bulbMat], halos: [halo], baseEmissive: [1.9] });\n  return {\n    object: group,\n    obstacleRadius: 0.1,\n    get lit() {\n      return litness.lit();\n    },\n    setLit: litness.setLit,\n    claim: { anchor, color, intensity: 2.6, radius: 6, priority: 0.8, isLit: litness.lit },\n  };\n}\n\n// ---------------------------------------------------------------------------\n// Neon sign\n\nexport interface NeonSignOptions {\n  color?: number;\n  /** Cap height of the letters, metres. Default 0.5. */\n  height?: number;\n  seed?: number;\n  /** Mount a dark backboard behind the tubes. Default true. */\n  backboard?: boolean;\n}\n\nexport interface NeonSign extends Luminous {\n  /** Tube segments built — a legibility smoke signal for tests. */\n  segments: number;\n}\n\n/**\n * A neon sign: the vector font's glyph strokes re-materialized as glowing\n * tube runs. One seeded letter *buzzes* — every real neon sign has one —\n * dipping and reigniting on its own nervous rhythm in `update(dt)`.\n * Authored facing +z with the origin at the sign's center.\n */\nexport function createNeonSign(text: string, options: NeonSignOptions = {}): NeonSign {\n  const color = options.color ?? 0xff4fa3;\n  const height = options.height ?? 0.5;\n  const rng = new Rng(options.seed ?? 1);\n  const scale = height / CAP;\n  const tracking = 1.6;\n\n  const group = new Group();\n  group.name = `neon-${text}`;\n\n  const steady = new MeshStandardMaterial({ color: 0x1a1216, emissive: color, emissiveIntensity: 2.3 });\n  const buzzy = steady.clone();\n  const glyphs = [...text.toUpperCase()].map((ch) => FONT[ch] ?? MISSING);\n  const buzzIndex = glyphs.length > 1 ? rng.int(0, glyphs.length - 1) : -1;\n\n  // Lay the tubes: a thin cylinder per stroke segment, a bead per joint.\n  const tube = 0.028;\n  const jointGeometry = new SphereGeometry(tube, 6, 5);\n  const a = new Vector3();\n  const b = new Vector3();\n  let pen = 0;\n  let segments = 0;\n  glyphs.forEach((glyph, gi) => {\n    const material = gi === buzzIndex ? buzzy : steady;\n    for (const stroke of glyph.strokes) {\n      for (let i = 0; i + 3 < stroke.length; i += 2) {\n        a.set(pen + stroke[i] * scale, stroke[i + 1] * scale, 0);\n        b.set(pen + stroke[i + 2] * scale, stroke[i + 3] * scale, 0);\n        const length = a.distanceTo(b);\n        if (length < 1e-5) continue;\n        const segment = new Mesh(new CylinderGeometry(tube, tube, length, 6), material);\n        segment.position.copy(a).add(b).multiplyScalar(0.5);\n        segment.rotation.z = Math.atan2(b.y - a.y, b.x - a.x) - Math.PI / 2;\n        group.add(segment);\n        segments++;\n        const joint = new Mesh(jointGeometry, material);\n        joint.position.copy(b);\n        group.add(joint);\n      }\n    }\n    pen += (glyph.advance + tracking) * scale;\n  });\n\n  const width = Math.max(pen - tracking * scale, scale);\n  // Center the run on the origin.\n  for (const child of [...group.children]) child.position.x -= width / 2;\n\n  if (options.backboard !== false) {\n    const board = new Mesh(\n      new BoxGeometry(width + height * 0.5, height * 1.7, 0.05),\n      new MeshStandardMaterial({ color: 0x14171c, roughness: 0.85 })\n    );\n    board.position.set(0, height * 0.5, -0.05);\n    group.add(board);\n  }\n\n  const halo = makeHalo(color, Math.max(width, height) * 1.15);\n  halo.position.set(0, height * 0.5, 0.1);\n  group.add(halo);\n\n  const anchor = new Object3D();\n  anchor.position.set(0, height * 0.5, 0.35);\n  group.add(anchor);\n\n  const litness = makeLitness({\n    bulbs: [steady, buzzy],\n    halos: [halo],\n    baseEmissive: [2.3, 2.3],\n  });\n  let clock = rng.range(0, 10);\n  return {\n    object: group,\n    obstacleRadius: 0,\n    get lit() {\n      return litness.lit();\n    },\n    setLit: litness.setLit,\n    update(dt: number) {\n      if (!litness.lit()) return;\n      clock += Number.isFinite(dt) ? Math.max(dt, 0) : 0;\n      // The nervous rhythm: mostly on, occasional sputters, never periodic-looking.\n      const w = Math.sin(clock * 7.3) * Math.sin(clock * 12.7) * Math.sin(clock * 0.83);\n      buzzy.emissiveIntensity = w > 0.42 ? 0.25 : 2.3;\n    },\n    claim: {\n      anchor,\n      color,\n      intensity: 2.2,\n      radius: 6,\n      priority: 1.2,\n      isLit: litness.lit,\n    },\n    segments,\n  };\n}\n\n// ---------------------------------------------------------------------------\n// String lights\n\nexport interface StringLightsOptions {\n  /** Horizontal span between the two hang points, metres. Default 6. */\n  span?: number;\n  /** How far the middle droops. Default 0.45. */\n  sag?: number;\n  count?: number;\n  /** Bulb colors, cycled. Default a warm festival mix. */\n  colors?: number[];\n  seed?: number;\n  /** Bulbs breathe brightness in update(dt). Default true. */\n  twinkle?: boolean;\n}\n\nconst FESTIVAL = [0xffd889, 0xff9d5c, 0x9dd1ff, 0xffe1f2, 0xb8ffc8];\n\n/**\n * A sagging run of festival bulbs. Authored along local x, hang points at\n * (±span/2, 0, 0) — position and rotate the group to string it between\n * anything. Bulbs are one InstancedMesh with per-instance color; `update`\n * makes them breathe out of phase.\n */\nexport function createStringLights(options: StringLightsOptions = {}): Luminous {\n  const span = options.span ?? 6;\n  const sag = options.sag ?? 0.45;\n  const count = Math.max(options.count ?? 11, 2);\n  const colors = options.colors ?? FESTIVAL;\n  const rng = new Rng(options.seed ?? 1);\n  const twinkle = options.twinkle !== false;\n\n  const group = new Group();\n  group.name = 'string-lights';\n  const droop = (u: number): number => -4 * sag * u * (1 - u);\n\n  // The wire: short dark cylinders chasing the parabola.\n  const wireMaterial = new MeshStandardMaterial({ color: 0x1c1e22, roughness: 0.8 });\n  const wireSegments = 16;\n  const a = new Vector3();\n  const b = new Vector3();\n  for (let i = 0; i < wireSegments; i++) {\n    const u0 = i / wireSegments;\n    const u1 = (i + 1) / wireSegments;\n    a.set((u0 - 0.5) * span, droop(u0), 0);\n    b.set((u1 - 0.5) * span, droop(u1), 0);\n    const length = a.distanceTo(b);\n    const segment = new Mesh(new CylinderGeometry(0.008, 0.008, length, 4), wireMaterial);\n    segment.position.copy(a).add(b).multiplyScalar(0.5);\n    segment.rotation.z = Math.atan2(b.y - a.y, b.x - a.x) - Math.PI / 2;\n    group.add(segment);\n  }\n\n  // The bulbs: basic material so they read as sources, not surfaces.\n  const bulbs = new InstancedMesh(\n    new SphereGeometry(0.05, 6, 5),\n    new MeshBasicMaterial({ color: 0xffffff }),\n    count\n  );\n  const dummy = new Object3D();\n  const base: Color[] = [];\n  const phase: number[] = [];\n  for (let i = 0; i < count; i++) {\n    const u = (i + 0.5) / count;\n    dummy.position.set((u - 0.5) * span, droop(u) - 0.07, 0);\n    dummy.updateMatrix();\n    bulbs.setMatrixAt(i, dummy.matrix);\n    const color = new Color(colors[i % colors.length]);\n    base.push(color);\n    phase.push(rng.range(0, Math.PI * 2));\n    bulbs.setColorAt(i, color);\n  }\n  bulbs.instanceMatrix.needsUpdate = true;\n  if (bulbs.instanceColor) bulbs.instanceColor.needsUpdate = true;\n  group.add(bulbs);\n\n  const halo = makeHalo(0xffd9a0, span * 0.45);\n  halo.material.opacity = 0.22;\n  halo.position.y = droop(0.5) - 0.05;\n  group.add(halo);\n\n  const anchor = new Object3D();\n  anchor.position.set(0, droop(0.5) - 0.2, 0);\n  group.add(anchor);\n\n  let lit = true;\n  const scratch = new Color();\n  const paint = (time: number): void => {\n    for (let i = 0; i < count; i++) {\n      if (!lit) {\n        scratch.setHex(0x15171a);\n      } else {\n        const breathe = twinkle ? 0.72 + 0.28 * Math.sin(time * 2.1 + phase[i]) : 1;\n        scratch.copy(base[i]).multiplyScalar(breathe);\n      }\n      bulbs.setColorAt(i, scratch);\n    }\n    if (bulbs.instanceColor) bulbs.instanceColor.needsUpdate = true;\n  };\n  let clock = rng.range(0, 10);\n\n  return {\n    object: group,\n    obstacleRadius: 0,\n    get lit() {\n      return lit;\n    },\n    setLit(on: boolean) {\n      lit = on;\n      halo.visible = on;\n      paint(clock);\n    },\n    update(dt: number) {\n      if (!lit || !twinkle) return;\n      clock += Number.isFinite(dt) ? Math.max(dt, 0) : 0;\n      paint(clock);\n    },\n    claim: {\n      anchor,\n      color: 0xffd9a0,\n      intensity: 1.8,\n      radius: 7,\n      priority: 0.7,\n      isLit: () => lit,\n    },\n  };\n}\n\n// ---------------------------------------------------------------------------\n// Beacon\n\nexport interface RevolvingBeaconOptions {\n  /** Height of the head above the origin. Default 3.5. */\n  height?: number;\n  color?: number;\n  /** Beam revolutions per second. Default 0.15. */\n  speed?: number;\n  seed?: number;\n}\n\n/**\n * A rotating beacon — the lighthouse move at any scale. Two opposed\n * additive beam cones sweep with the head; the volumetric look is just\n * geometry, no shader tricks. Feed `update(dt)` to turn it.\n */\nexport function createRevolvingBeacon(options: RevolvingBeaconOptions = {}): Luminous {\n  const height = options.height ?? 3.5;\n  const color = options.color ?? 0xfff2c8;\n  const speed = (options.speed ?? 0.15) * Math.PI * 2;\n  const group = new Group();\n  group.name = 'beacon';\n\n  const tower = new Mesh(\n    new CylinderGeometry(0.32, 0.45, height, 8),\n    new MeshStandardMaterial({ color: 0x9aa2ac, flatShading: true, roughness: 0.7 })\n  );\n  tower.position.y = height / 2;\n  const cap = new Mesh(\n    new ConeGeometry(0.4, 0.3, 8),\n    new MeshStandardMaterial({ color: 0x3a3f46, flatShading: true })\n  );\n  cap.position.y = height + 0.42;\n  group.add(tower, cap);\n\n  const head = new Group();\n  head.position.y = height + 0.18;\n  const lensMat = new MeshStandardMaterial({ color, emissive: color, emissiveIntensity: 2.4 });\n  const lens = new Mesh(new SphereGeometry(0.16, 10, 8), lensMat);\n  head.add(lens);\n  const beamMaterial = new MeshBasicMaterial({\n    color,\n    transparent: true,\n    opacity: 0.16,\n    blending: AdditiveBlending,\n    depthWrite: false,\n  });\n  const beamLength = 7;\n  for (const dir of [1, -1]) {\n    const beam = new Mesh(new ConeGeometry(0.55, beamLength, 10, 1, true), beamMaterial);\n    beam.rotation.z = (dir * Math.PI) / 2;\n    beam.position.x = (dir * beamLength) / 2;\n    head.add(beam);\n  }\n  const halo = makeHalo(color, 1.4);\n  head.add(halo);\n  group.add(head);\n\n  const anchor = new Object3D();\n  anchor.position.y = height + 0.18;\n  group.add(anchor);\n\n  const litness = makeLitness({ bulbs: [lensMat], halos: [halo], baseEmissive: [2.4] });\n  const rng = new Rng(options.seed ?? 1);\n  head.rotation.y = rng.range(0, Math.PI * 2);\n  return {\n    object: group,\n    obstacleRadius: 0.5,\n    get lit() {\n      return litness.lit();\n    },\n    setLit(on: boolean) {\n      litness.setLit(on);\n      for (const child of head.children) {\n        if ((child as Mesh).material === beamMaterial) child.visible = on;\n      }\n    },\n    update(dt: number) {\n      if (!litness.lit()) return;\n      head.rotation.y += (Number.isFinite(dt) ? Math.max(dt, 0) : 0) * speed;\n    },\n    claim: { anchor, color, intensity: 3, radius: 15, priority: 1.4, isLit: litness.lit },\n  };\n}\n\n// ---------------------------------------------------------------------------\n// Photocell\n\nexport interface PhotocellOptions {\n  seed?: number;\n  /** Longest ignition straggle after dusk, seconds. Default 3. */\n  spread?: number;\n  /** Sun elevation where dusk trips. Default 0.04 (just above the horizon). */\n  threshold?: number;\n}\n\nexport interface Photocell {\n  /** 'day' | 'night' — which side of dusk the cell believes it is. */\n  readonly state: 'day' | 'night';\n  /** Switch orders scheduled but not yet fired. */\n  readonly pending: number;\n  update(dt: number): void;\n}\n\n/**\n * The photocell — why streets ripple alight instead of blinking on as one.\n *\n * Watches anything with a `sunElevation` (a `DayCycle`, structurally) and\n * flips each fixture's `setLit` when dusk or dawn trips, each after its own\n * seeded delay within `spread`. The thresholds are hysteretic — dusk trips\n * a touch above the horizon, dawn well after — so a sun grazing the\n * threshold can't make the street flap.\n */\nexport function createPhotocell(\n  sky: { sunElevation: number },\n  fixtures: ReadonlyArray<{ setLit(on: boolean): void }>,\n  options: PhotocellOptions = {}\n): Photocell {\n  const seed = options.seed ?? 1;\n  const spread = Math.max(options.spread ?? 3, 0);\n  const threshold = options.threshold ?? 0.04;\n\n  let state: 'day' | 'night' = sky.sunElevation < threshold ? 'night' : 'day';\n  let clock = 0;\n  let transitions = 0;\n  const pending: Array<{ at: number; on: boolean; fixture: { setLit(on: boolean): void } }> = [];\n\n  const schedule = (on: boolean): void => {\n    transitions++;\n    const rng = new Rng(seed + transitions * 101);\n    pending.length = 0;\n    for (const fixture of fixtures) {\n      pending.push({ at: clock + rng.range(0, spread), on, fixture });\n    }\n    pending.sort((a, b) => a.at - b.at);\n  };\n  // Apply the initial belief immediately, no straggle.\n  for (const fixture of fixtures) fixture.setLit(state === 'night');\n\n  return {\n    get state() {\n      return state;\n    },\n    get pending() {\n      return pending.length;\n    },\n    update(dt: number) {\n      clock += Number.isFinite(dt) ? Math.max(dt, 0) : 0;\n      const elevation = sky.sunElevation;\n      if (state === 'day' && elevation < threshold) {\n        state = 'night';\n        schedule(true);\n      } else if (state === 'night' && elevation > threshold + 0.08) {\n        state = 'day';\n        schedule(false);\n      }\n      while (pending.length && pending[0].at <= clock) {\n        const order = pending.shift()!;\n        order.fixture.setLit(order.on);\n      }\n    },\n  };\n}\n","import {\n  BoxGeometry,\n  CircleGeometry,\n  CylinderGeometry,\n  Group,\n  Mesh,\n  MeshStandardMaterial,\n  RingGeometry,\n  TorusGeometry,\n} from 'three';\nimport { Rng } from '../core/random';\nimport { DEFAULT_PALETTE, type Palette } from '../core/palette';\nimport { createSurface } from '../materials/surface';\nimport { buildTextGeometry } from '../text/textGeometry';\nimport type { Prop } from '../core/types';\n\n/**\n * The airfield — everything an airplane parks beside.\n *\n * A runway with real markings (the vector font finally lying flat: the\n * numbers are the heading in tens of degrees, and the far end reads the\n * reciprocal, because that is what runways DO), a windsock that reads an\n * actual `WindField` structurally — its swing is the wind's direction\n * and its droop the wind's strength, which makes it weather\n * instrumentation you can unit-test — a hangar to hide from it in, and\n * a helipad for the release after this one.\n */\n\n// ---------------------------------------------------------------------------\n// Runway\n\nexport interface RunwayOptions {\n  /** Strip length, metres. Default 60. */\n  length?: number;\n  /** Strip width, metres. Default 8. */\n  width?: number;\n  /**\n   * Runway number at the NEAR end (heading in tens of degrees, 1–36).\n   * The far end shows the reciprocal automatically. Default 27.\n   */\n  number?: number;\n  seed?: number;\n}\n\nexport interface Runway extends Prop {\n  /** The number painted at the near end. */\n  number: number;\n  /** The far end's designation — always the reciprocal. */\n  reciprocal: number;\n}\n\nexport function createRunway(options: RunwayOptions = {}): Runway {\n  const length = options.length ?? 60;\n  const width = options.width ?? 8;\n  const number = Math.min(Math.max(Math.round(options.number ?? 27), 1), 36);\n  const reciprocal = ((number + 17) % 36) + 1;\n  const seed = options.seed ?? 1;\n\n  const group = new Group();\n  group.name = `runway-${number}`;\n  const strip = new Mesh(new BoxGeometry(width, 0.08, length), createSurface('asphalt', { seed }));\n  strip.position.y = 0.04;\n  group.add(strip);\n\n  const paint = new MeshStandardMaterial({ color: 0xe8e6dc, roughness: 0.8 });\n  // Centreline dashes.\n  const dashCount = Math.floor(length / 6);\n  for (let i = 0; i < dashCount; i++) {\n    const dash = new Mesh(new BoxGeometry(0.3, 0.02, 2.6), paint);\n    dash.position.set(0, 0.09, -length / 2 + 4 + i * 6);\n    group.add(dash);\n  }\n  // Threshold bars (\"piano keys\") at both ends.\n  for (const end of [-1, 1]) {\n    for (let i = 0; i < 6; i++) {\n      const bar = new Mesh(new BoxGeometry(0.55, 0.02, 2.2), paint);\n      bar.position.set(-width / 2 + 0.9 + i * ((width - 1.8) / 5), 0.09, end * (length / 2 - 1.6));\n      group.add(bar);\n    }\n  }\n  // The numbers, flat on the deck, each readable to a pilot on approach.\n  const pad = (n: number): string => (n < 10 ? '0' + n : String(n));\n  for (const [value, end] of [\n    [number, -1],\n    [reciprocal, 1],\n  ] as Array<[number, number]>) {\n    const text = buildTextGeometry(pad(value), { size: 2.2, depth: 0.02 });\n    const mesh = new Mesh(text.geometry, paint);\n    mesh.rotation.x = -Math.PI / 2;\n    mesh.rotation.z = end > 0 ? Math.PI : 0; // the far number faces the far approach\n    mesh.position.set(0, 0.1, end * (length / 2 - 6));\n    group.add(mesh);\n  }\n\n  return { object: group, obstacleRadius: 0, number, reciprocal };\n}\n\n// ---------------------------------------------------------------------------\n// Windsock\n\nexport interface WindsockOptions {\n  /** Pole height, metres. Default 4. */\n  pole?: number;\n  seed?: number;\n}\n\nexport interface Windsock extends Prop {\n  /** Where the sock points (radians, world XZ) — DOWNwind, like the real thing. */\n  readonly angle: number;\n  /** How far the sock hangs off horizontal (0 = flying straight, ~1.2 = limp). */\n  readonly droop: number;\n  /** Feed it the wind (a WindField, structurally) every frame. */\n  update(dt: number, wind?: { direction: { x: number; y: number }; strength: number }): void;\n}\n\nexport function createWindsock(options: WindsockOptions = {}): Windsock {\n  const rng = new Rng(options.seed ?? 1);\n  const poleHeight = options.pole ?? 4;\n  const group = new Group();\n  group.name = 'windsock';\n\n  const pole = new Mesh(\n    new CylinderGeometry(0.05, 0.07, poleHeight, 6),\n    new MeshStandardMaterial({ color: 0x9aa2ac, flatShading: true })\n  );\n  pole.position.y = poleHeight / 2;\n  const ring = new Mesh(\n    new TorusGeometry(0.22, 0.03, 6, 12),\n    new MeshStandardMaterial({ color: 0x60666e, flatShading: true })\n  );\n  ring.position.y = poleHeight;\n  ring.rotation.y = Math.PI / 2;\n  group.add(pole, ring);\n\n  // The swivel carries the sock; the sock is banded frustums, orange/white.\n  const swivel = new Group();\n  swivel.position.y = poleHeight;\n  const sock = new Group();\n  const orange = new MeshStandardMaterial({ color: 0xe8762e, roughness: 0.85, flatShading: true });\n  const white = new MeshStandardMaterial({ color: 0xe8e6dc, roughness: 0.85, flatShading: true });\n  const segments: Mesh[] = [];\n  let z = 0;\n  const radii = [0.22, 0.18, 0.145, 0.11, 0.08];\n  for (let i = 0; i < 4; i++) {\n    const segment = new Mesh(\n      new CylinderGeometry(radii[i + 1], radii[i], 0.34, 8, 1, true),\n      i % 2 === 0 ? orange : white\n    );\n    segment.rotation.x = -Math.PI / 2;\n    segment.position.z = z + 0.17;\n    z += 0.33;\n    sock.add(segment);\n    segments.push(segment);\n  }\n  swivel.add(sock);\n  group.add(swivel);\n\n  let angle = rng.range(0, Math.PI * 2);\n  let droop = 1.1;\n  let clock = rng.range(0, 10);\n\n  const apply = (): void => {\n    swivel.rotation.y = angle;\n    sock.rotation.x = droop;\n    // The tail segments flutter more than the throat.\n    for (let i = 0; i < segments.length; i++) {\n      const flutter = Math.sin(clock * (5 + i * 1.7) + i) * 0.05 * (i + 1) * Math.min(droop + 0.3, 1);\n      segments[i].rotation.x = -Math.PI / 2 + flutter;\n    }\n  };\n  apply();\n\n  return {\n    object: group,\n    obstacleRadius: 0.15,\n    get angle() {\n      return angle;\n    },\n    get droop() {\n      return droop;\n    },\n    update(dt, wind) {\n      const step = Number.isFinite(dt) ? Math.max(dt, 0) : 0;\n      clock += step;\n      if (wind) {\n        const target = Math.atan2(wind.direction.x, wind.direction.y);\n        let diff = target - angle;\n        while (diff > Math.PI) diff -= Math.PI * 2;\n        while (diff < -Math.PI) diff += Math.PI * 2;\n        angle += diff * Math.min(step * 2.5, 1); // socks swing, they don't snap\n        const strength = Math.min(Math.max(wind.strength, 0), 1);\n        const targetDroop = 1.15 * (1 - Math.min(strength * 1.8, 1));\n        droop += (targetDroop - droop) * Math.min(step * 2, 1);\n      }\n      apply();\n    },\n  };\n}\n\n// ---------------------------------------------------------------------------\n// Hangar\n\nexport interface HangarOptions {\n  width?: number;\n  depth?: number;\n  seed?: number;\n  palette?: Palette;\n}\n\n/** An open-front arch hangar — park the trainer out of the weather. */\nexport function createHangar(options: HangarOptions = {}): Prop {\n  const width = options.width ?? 12;\n  const depth = options.depth ?? 10;\n  const seed = options.seed ?? 1;\n  const palette = options.palette ?? DEFAULT_PALETTE;\n  const group = new Group();\n  group.name = 'hangar';\n\n  const slab = new Mesh(\n    new BoxGeometry(width + 1, 0.12, depth + 1),\n    createSurface('concrete', { seed })\n  );\n  slab.position.y = 0.06;\n  group.add(slab);\n\n  // The arch: a half-open cylinder rotated in GEOMETRY space so the\n  // arc springs over the top with its axis down the hangar's depth.\n  const shellGeometry = new CylinderGeometry(width / 2, width / 2, depth, 14, 1, true, 0, Math.PI);\n  shellGeometry.rotateX(-Math.PI / 2);\n  shellGeometry.rotateZ(Math.PI / 2);\n  const shellSkin = createSurface('steel', { seed: seed + 1 });\n  shellSkin.side = 2; // seen from inside AND out\n  const shell = new Mesh(shellGeometry, shellSkin);\n  shell.position.y = 0.1;\n  group.add(shell);\n\n  const backSkin = createSurface('paintedMetal', { color: palette.metal, seed: seed + 2 });\n  backSkin.side = 2;\n  const back = new Mesh(new CircleGeometry(width / 2, 14, 0, Math.PI), backSkin);\n  back.position.set(0, 0.1, -depth / 2);\n  group.add(back);\n\n  return { object: group, obstacleRadius: Math.max(width, depth) / 2 };\n}\n\n// ---------------------------------------------------------------------------\n// Helipad\n\nexport interface HelipadOptions {\n  radius?: number;\n  seed?: number;\n}\n\n/** A round pad with the ring and the H — the font's flattest job yet. */\nexport function createHelipad(options: HelipadOptions = {}): Prop {\n  const radius = options.radius ?? 3.2;\n  const seed = options.seed ?? 1;\n  const group = new Group();\n  group.name = 'helipad';\n\n  const slab = new Mesh(\n    new CylinderGeometry(radius, radius, 0.14, 24),\n    createSurface('concrete', { seed })\n  );\n  slab.position.y = 0.07;\n  group.add(slab);\n\n  const paint = new MeshStandardMaterial({ color: 0xe8e6dc, roughness: 0.8 });\n  const ring = new Mesh(new RingGeometry(radius * 0.78, radius * 0.9, 28), paint);\n  ring.rotation.x = -Math.PI / 2;\n  ring.position.y = 0.15;\n  group.add(ring);\n\n  const h = buildTextGeometry('H', { size: radius * 0.75, depth: 0.02 });\n  const mesh = new Mesh(h.geometry, paint);\n  mesh.rotation.x = -Math.PI / 2;\n  mesh.position.y = 0.15;\n  group.add(mesh);\n\n  return { object: group, obstacleRadius: radius };\n}\n","import {\n  BoxGeometry,\n  ConeGeometry,\n  CylinderGeometry,\n  ExtrudeGeometry,\n  Group,\n  IcosahedronGeometry,\n  InstancedMesh,\n  Matrix4,\n  Mesh,\n  OctahedronGeometry,\n  Quaternion,\n  Shape,\n  SphereGeometry,\n  TorusGeometry,\n  Vector3,\n  type BufferGeometry,\n  type Material,\n} from 'three';\nimport { Rng } from '../core/random';\nimport { createSurface } from '../materials/surface';\nimport type { Obstacle } from '../core/types';\n\n/**\n * Pickups — the things a game loop is made of.\n *\n * A pickup is a small seeded prop with a built-in idle (spin at a seeded\n * phase plus a sine bob — a field of coins must never tick in lockstep)\n * and two transitions: `collect()` pops it out of the world and\n * `respawn()` shimmers it back, each returning its duration so the caller\n * can schedule the consequences. The gem wears the `gemstone` surface —\n * dispersion doing the \"this one is valuable\" work games usually fake\n * with a glow sprite.\n *\n * The gameplay handshake is the house rule: `trigger` is structurally an\n * `Obstacle` (`{center, radius}`), with `center` a LIVE reference to the\n * prop's root position — hand it to GAMA's proximity queries and neither\n * library imports the other. SCENA renders the pickup; who gets credit\n * for touching it is the game loop's business.\n *\n * ```ts\n * const gem = createPickup('gem', { seed: 7 });\n * gem.group.position.set(4, 0.8, -2);\n * scene.add(gem.group);\n * // per frame:\n * gem.update(dt);\n * // when the game loop says so:\n * const wait = gem.collect();\n * ```\n */\n\nexport type PickupKind = 'coin' | 'gem' | 'key' | 'heart' | 'star' | 'orb' | 'potion';\n\nexport interface PickupOptions {\n  seed?: number;\n  /** Overall size multiplier. Default 1. */\n  scale?: number;\n  /** Tint override for the body material. */\n  color?: number;\n  /** Bob amplitude in metres. Default 0.07. */\n  bob?: number;\n  /** Idle spin speed, radians/second. Default 1.6. */\n  spin?: number;\n}\n\nexport type PickupState = 'idle' | 'collecting' | 'collected' | 'respawning';\n\nexport interface Pickup {\n  group: Group;\n  kind: PickupKind;\n  /** Where the game loop should test proximity: live centre + pick radius. */\n  trigger: Obstacle;\n  readonly state: PickupState;\n  /** Pop out of the world. Returns the animation's seconds; 0 if not idle. */\n  collect(): number;\n  /** Shimmer back in. Returns the animation's seconds; 0 unless collected. */\n  respawn(): number;\n  update(dt: number): void;\n}\n\nconst COLLECT_TIME = 0.35;\nconst RESPAWN_TIME = 0.45;\n\ninterface BuiltBody {\n  nodes: Mesh[];\n  radius: number;\n}\n\n/**\n * Make a metal READ as treasure with no environment map in sight. A pure\n * metal shows only reflections, and a pickup cannot demand the caller set\n * up IBL before a coin looks like a coin — so the gold kinds trade some\n * physical purity for readability: part-dielectric, with a warm ember of\n * emissive that keeps them golden in any light. Game tokens, not bullion.\n */\nfunction treasure(material: { metalness: number; emissive: { setHex(hex: number): unknown } }): void {\n  material.metalness = 0.55;\n  material.emissive.setHex(0x402c06);\n}\n\n/** One geometry + material per kind — shared by fields, cloned by nobody. */\nfunction buildBody(kind: PickupKind, seed: number, tint: number | undefined): BuiltBody {\n  const paint = (fallback: number) => tint ?? fallback;\n  switch (kind) {\n    case 'coin': {\n      const geometry = new CylinderGeometry(0.3, 0.3, 0.07, 16);\n      geometry.rotateX(Math.PI / 2); // a coin STANDS, faces out, spins about Y\n      const material = createSurface('brass', { seed, color: paint(0xd9a53c) });\n      treasure(material);\n      return { nodes: [new Mesh(geometry, material)], radius: 0.32 };\n    }\n    case 'gem': {\n      const material = createSurface('gemstone', { seed, ...(tint ? { color: tint } : {}) });\n      return { nodes: [new Mesh(new OctahedronGeometry(0.3, 0), material)], radius: 0.32 };\n    }\n    case 'star': {\n      // A five-point star extruded thin — the shape is ten points on two radii.\n      const shape = new Shape();\n      for (let i = 0; i < 10; i++) {\n        const r = i % 2 === 0 ? 0.32 : 0.13;\n        const a = (i / 10) * Math.PI * 2 + Math.PI / 2;\n        const x = Math.cos(a) * r;\n        const y = Math.sin(a) * r;\n        if (i === 0) shape.moveTo(x, y);\n        else shape.lineTo(x, y);\n      }\n      const geometry = new ExtrudeGeometry(shape, { depth: 0.08, bevelEnabled: false });\n      geometry.translate(0, 0, -0.04);\n      const material = createSurface('brass', { seed: seed + 1, color: paint(0xf3c94e) });\n      treasure(material);\n      return { nodes: [new Mesh(geometry, material)], radius: 0.34 };\n    }\n    case 'orb': {\n      const material = createSurface('crystal', { seed, ...(tint ? { color: tint } : {}) });\n      return { nodes: [new Mesh(new IcosahedronGeometry(0.26, 1), material)], radius: 0.28 };\n    }\n    case 'heart': {\n      // Two lobes and a point — reads as a heart at any poly count.\n      const material = createSurface('paint', { seed, color: paint(0xd94a5e) });\n      const lobe = new SphereGeometry(0.16, 12, 10);\n      const left = new Mesh(lobe, material);\n      left.position.set(-0.11, 0.1, 0);\n      const right = new Mesh(lobe, material);\n      right.position.set(0.11, 0.1, 0);\n      const point = new Mesh(new ConeGeometry(0.21, 0.34, 4), material);\n      point.rotation.set(Math.PI, Math.PI / 4, 0);\n      point.position.y = -0.09;\n      point.scale.z = 0.55;\n      return { nodes: [left, right, point], radius: 0.3 };\n    }\n    case 'key': {\n      const material = createSurface('brass', { seed, color: paint(0xc9a23f) });\n      treasure(material);\n      const bow = new Mesh(new TorusGeometry(0.12, 0.045, 8, 14), material);\n      bow.position.y = 0.18;\n      const shaft = new Mesh(new BoxGeometry(0.07, 0.34, 0.05), material);\n      shaft.position.y = -0.05;\n      const teeth1 = new Mesh(new BoxGeometry(0.11, 0.05, 0.05), material);\n      teeth1.position.set(0.08, -0.2, 0);\n      const teeth2 = new Mesh(new BoxGeometry(0.08, 0.05, 0.05), material);\n      teeth2.position.set(0.065, -0.1, 0);\n      return { nodes: [bow, shaft, teeth1, teeth2], radius: 0.3 };\n    }\n    case 'potion': {\n      const glass = createSurface('crystal', { seed, ...(tint ? { color: tint } : { color: 0x7fd486 }) });\n      const body = new Mesh(new SphereGeometry(0.18, 12, 10), glass);\n      body.scale.y = 1.15;\n      const neck = new Mesh(new CylinderGeometry(0.06, 0.07, 0.14, 10), glass);\n      neck.position.y = 0.22;\n      const cork = new Mesh(\n        new CylinderGeometry(0.055, 0.05, 0.07, 8),\n        createSurface('wood', { seed: seed + 2 })\n      );\n      cork.position.y = 0.31;\n      return { nodes: [body, neck, cork], radius: 0.28 };\n    }\n  }\n}\n\nexport function createPickup(kind: PickupKind, options: PickupOptions = {}): Pickup {\n  const seed = options.seed ?? 1;\n  const rng = new Rng(seed);\n  const scale = options.scale ?? 1;\n  const bobHeight = options.bob ?? 0.07;\n  const spinSpeed = options.spin ?? 1.6;\n\n  const group = new Group();\n  group.name = `pickup-${kind}`;\n  // The spinner is a child so collect/respawn scaling never fights the\n  // caller's own transform on `group`.\n  const spinner = new Group();\n  group.add(spinner);\n  const body = buildBody(kind, seed, options.color);\n  for (const node of body.nodes) spinner.add(node);\n  spinner.scale.setScalar(scale);\n\n  const phase = rng.range(0, Math.PI * 2);\n  let state: PickupState = 'idle';\n  let animT = 0;\n  let clock = rng.range(0, 10);\n\n  const trigger: Obstacle = { center: group.position, radius: body.radius * scale + 0.25 };\n\n  return {\n    group,\n    kind,\n    trigger,\n    get state() {\n      return state;\n    },\n    collect() {\n      if (state !== 'idle') return 0;\n      state = 'collecting';\n      animT = 0;\n      return COLLECT_TIME;\n    },\n    respawn() {\n      if (state !== 'collected') return 0;\n      state = 'respawning';\n      animT = 0;\n      return RESPAWN_TIME;\n    },\n    update(dt: number) {\n      const step = Number.isFinite(dt) ? Math.max(dt, 0) : 0;\n      clock += step;\n      if (state === 'collected') return;\n\n      let size = 1;\n      let spin = spinSpeed;\n      if (state === 'collecting') {\n        animT += step;\n        const t = Math.min(animT / COLLECT_TIME, 1);\n        // Pop first, then shrink to nothing; the spin doubles on the way out.\n        size = t < 0.3 ? 1 + t * 1.2 : Math.max(1.36 * (1 - (t - 0.3) / 0.7), 0);\n        spin = spinSpeed * 4;\n        if (t >= 1) {\n          state = 'collected';\n          spinner.visible = false;\n        }\n      } else if (state === 'respawning') {\n        animT += step;\n        const t = Math.min(animT / RESPAWN_TIME, 1);\n        spinner.visible = true;\n        // Overshoot and settle — arriving, not fading in.\n        size = t < 0.7 ? (t / 0.7) * 1.15 : 1.15 - 0.15 * ((t - 0.7) / 0.3);\n        if (t >= 1) state = 'idle';\n      }\n      spinner.scale.setScalar(Math.max(size * scale, 1e-4));\n      spinner.rotation.y = clock * spin + phase;\n      spinner.position.y = Math.sin(clock * 2 + phase) * bobHeight;\n    },\n  };\n}\n\n// ---------------------------------------------------------------------------\n// The field — coin-run density in one draw call.\n// ---------------------------------------------------------------------------\n\nexport interface PickupFieldOptions {\n  seed?: number;\n  scale?: number;\n  color?: number;\n  bob?: number;\n  spin?: number;\n}\n\nexport interface FieldTrigger extends Obstacle {\n  /** Which instance this trigger belongs to. */\n  index: number;\n}\n\nexport interface PickupField {\n  mesh: InstancedMesh;\n  /** One live trigger per position; collected entries stay but stop mattering. */\n  triggers: FieldTrigger[];\n  /** How many are still collectable. */\n  readonly remaining: number;\n  isActive(index: number): boolean;\n  collect(index: number): number;\n  respawn(index: number): number;\n  update(dt: number): void;\n}\n\n/** Kinds whose body is a single geometry — what an InstancedMesh can carry. */\nconst FIELD_KINDS: ReadonlySet<PickupKind> = new Set(['coin', 'gem', 'star', 'orb']);\n\n/**\n * A hundred coins, one draw call. Positions are fixed at creation (they\n * are the level design); each instance idles at its own seeded phase and\n * collapses when collected. Composite kinds (key, heart, potion) need a\n * mesh per pickup — use `createPickup` for those; this throws rather than\n * silently rendering the wrong thing.\n */\nexport function createPickupField(\n  kind: PickupKind,\n  positions: readonly Vector3[],\n  options: PickupFieldOptions = {}\n): PickupField {\n  if (!FIELD_KINDS.has(kind)) {\n    throw new Error(`createPickupField: '${kind}' is a composite body — use createPickup per instance.`);\n  }\n  const seed = options.seed ?? 1;\n  const rng = new Rng(seed);\n  const scale = options.scale ?? 1;\n  const bobHeight = options.bob ?? 0.07;\n  const spinSpeed = options.spin ?? 1.6;\n\n  const body = buildBody(kind, seed, options.color);\n  const source = body.nodes[0];\n  const mesh = new InstancedMesh(\n    source.geometry as BufferGeometry,\n    source.material as Material,\n    positions.length\n  );\n  mesh.name = `pickups-${kind}`;\n  mesh.frustumCulled = false;\n\n  const phases = positions.map(() => rng.range(0, Math.PI * 2));\n  const states: PickupState[] = positions.map(() => 'idle');\n  const anims = positions.map(() => 0);\n  let clock = 0;\n  let alive = positions.length;\n\n  const triggers: FieldTrigger[] = positions.map((p, index) => ({\n    center: p.clone(),\n    radius: body.radius * scale + 0.25,\n    index,\n  }));\n\n  const matrix = new Matrix4();\n  const quat = new Quaternion();\n  const size = new Vector3();\n  const pos = new Vector3();\n  const UP = new Vector3(0, 1, 0);\n\n  const compose = (): void => {\n    for (let i = 0; i < positions.length; i++) {\n      let s = 1;\n      if (states[i] === 'collected') s = 0;\n      else if (states[i] === 'collecting') {\n        const t = Math.min(anims[i] / COLLECT_TIME, 1);\n        s = t < 0.3 ? 1 + t * 1.2 : Math.max(1.36 * (1 - (t - 0.3) / 0.7), 0);\n      } else if (states[i] === 'respawning') {\n        const t = Math.min(anims[i] / RESPAWN_TIME, 1);\n        s = t < 0.7 ? (t / 0.7) * 1.15 : 1.15 - 0.15 * ((t - 0.7) / 0.3);\n      }\n      quat.setFromAxisAngle(UP, clock * (states[i] === 'collecting' ? spinSpeed * 4 : spinSpeed) + phases[i]);\n      pos.copy(positions[i]);\n      pos.y += Math.sin(clock * 2 + phases[i]) * bobHeight;\n      size.setScalar(Math.max(s * scale, 1e-4));\n      matrix.compose(pos, quat, size);\n      mesh.setMatrixAt(i, matrix);\n    }\n    mesh.instanceMatrix.needsUpdate = true;\n  };\n  compose();\n\n  return {\n    mesh,\n    triggers,\n    get remaining() {\n      return alive;\n    },\n    isActive(index: number) {\n      return states[index] === 'idle';\n    },\n    collect(index: number) {\n      if (states[index] !== 'idle') return 0;\n      states[index] = 'collecting';\n      anims[index] = 0;\n      alive--;\n      return COLLECT_TIME;\n    },\n    respawn(index: number) {\n      if (states[index] !== 'collected') return 0;\n      states[index] = 'respawning';\n      anims[index] = 0;\n      return RESPAWN_TIME;\n    },\n    update(dt: number) {\n      const step = Number.isFinite(dt) ? Math.max(dt, 0) : 0;\n      clock += step;\n      for (let i = 0; i < states.length; i++) {\n        if (states[i] === 'collecting') {\n          anims[i] += step;\n          if (anims[i] >= COLLECT_TIME) states[i] = 'collected';\n        } else if (states[i] === 'respawning') {\n          anims[i] += step;\n          if (anims[i] >= RESPAWN_TIME) {\n            states[i] = 'idle';\n            alive++;\n          }\n        }\n      }\n      compose();\n    },\n  };\n}\n","import {\n  AdditiveBlending,\n  BoxGeometry,\n  CylinderGeometry,\n  DoubleSide,\n  Group,\n  InstancedMesh,\n  Matrix4,\n  Mesh,\n  MeshBasicMaterial,\n  MeshStandardMaterial,\n  Quaternion,\n  RingGeometry,\n  TorusGeometry,\n  Vector3,\n} from 'three';\nimport { Rng } from '../core/random';\nimport { createSurface } from '../materials/surface';\nimport type { Obstacle } from '../core/types';\n\n/**\n * Markers — the furniture of objectives. A checkpoint arch that knows\n * whether it is next, a capture zone that turns on the ground, a beacon\n * readable across a whole map, and a chequered finish gate. Almost pure\n * state machine: the geometry is cheap and all the value is in the\n * transitions, because a player reads a checkpoint's STATE at a glance\n * or not at all.\n *\n * Every marker exposes `trigger` — structurally an `Obstacle`\n * (`{center, radius}`, centre a live reference to the marker's root) —\n * so GAMA's Circuit and trigger queries consume them without imports.\n */\n\nexport type CheckpointState = 'upcoming' | 'active' | 'passed';\n\nexport interface CheckpointOptions {\n  seed?: number;\n  /** Clear width between the pillars, metres. Default 4. */\n  width?: number;\n  /** Height to the underside of the beam. Default 3. */\n  height?: number;\n  /** Emissive colour when active. Default 0x53c7f0. */\n  color?: number;\n}\n\nexport interface Checkpoint {\n  group: Group;\n  trigger: Obstacle;\n  readonly state: CheckpointState;\n  /** upcoming = slow pulse · active = bright · passed = dim green. */\n  setState(state: CheckpointState): void;\n  update(dt: number): void;\n}\n\nexport function createCheckpoint(options: CheckpointOptions = {}): Checkpoint {\n  const seed = options.seed ?? 1;\n  const width = options.width ?? 4;\n  const height = options.height ?? 3;\n  const activeColor = options.color ?? 0x53c7f0;\n\n  const group = new Group();\n  group.name = 'checkpoint';\n\n  const pillarMaterial = createSurface('steel', { seed });\n  const pillar = new CylinderGeometry(0.14, 0.18, height, 10);\n  for (const side of [-1, 1]) {\n    const post = new Mesh(pillar, pillarMaterial);\n    post.position.set((side * width) / 2, height / 2, 0);\n    group.add(post);\n  }\n  const beam = new Mesh(new BoxGeometry(width + 0.6, 0.24, 0.24), pillarMaterial);\n  beam.position.y = height + 0.12;\n  group.add(beam);\n\n  // The glow strip under the beam is the state display. MeshBasic on\n  // purpose: state must read identically at noon and at midnight, so it\n  // cannot be at the mercy of the lighting rig.\n  const strip = new MeshBasicMaterial({ color: activeColor, transparent: true });\n  const glow = new Mesh(new BoxGeometry(width, 0.1, 0.1), strip);\n  glow.position.y = height - 0.08;\n  group.add(glow);\n\n  let state: CheckpointState = 'upcoming';\n  let clock = new Rng(seed).range(0, 6);\n\n  const trigger: Obstacle = { center: group.position, radius: width / 2 };\n\n  return {\n    group,\n    trigger,\n    get state() {\n      return state;\n    },\n    setState(next: CheckpointState) {\n      state = next;\n      if (state === 'active') strip.color.setHex(activeColor);\n      else if (state === 'passed') strip.color.setHex(0x4caf6e);\n      else strip.color.setHex(activeColor);\n    },\n    update(dt: number) {\n      const step = Number.isFinite(dt) ? Math.max(dt, 0) : 0;\n      clock += step;\n      if (state === 'upcoming') strip.opacity = 0.35 + 0.25 * Math.sin(clock * 2.2);\n      else if (state === 'active') strip.opacity = 0.9 + 0.1 * Math.sin(clock * 6);\n      else strip.opacity = 0.4;\n    },\n  };\n}\n\n// ---------------------------------------------------------------------------\n\nexport interface ZoneOptions {\n  seed?: number;\n  /** Zone radius, metres. Default 2.2. */\n  radius?: number;\n  color?: number;\n  /** Rotating dash count. Default 14. */\n  dashes?: number;\n}\n\nexport interface Zone {\n  group: Group;\n  trigger: Obstacle;\n  /** 0..1 — how \"captured\"/charged the zone reads. Drives the fill ring. */\n  setProgress(value: number): void;\n  update(dt: number): void;\n}\n\n/**\n * A flat ground ring with rotating dashes — spawn pad, capture area,\n * charge circle. `setProgress` fills an inner ring so the game loop can\n * show how long you have stood in it.\n */\nexport function createZone(options: ZoneOptions = {}): Zone {\n  const seed = options.seed ?? 1;\n  const radius = options.radius ?? 2.2;\n  const color = options.color ?? 0x53c7f0;\n  const dashCount = options.dashes ?? 14;\n\n  const group = new Group();\n  group.name = 'zone';\n\n  const edge = new MeshBasicMaterial({ color, transparent: true, opacity: 0.75 });\n  const dashes = new Group();\n  const dashGeometry = new BoxGeometry((2 * Math.PI * radius) / dashCount * 0.55, 0.04, 0.16);\n  for (let i = 0; i < dashCount; i++) {\n    const dash = new Mesh(dashGeometry, edge);\n    const a = (i / dashCount) * Math.PI * 2;\n    dash.position.set(Math.cos(a) * radius, 0.03, Math.sin(a) * radius);\n    dash.rotation.y = -a + Math.PI / 2;\n    dashes.add(dash);\n  }\n  group.add(dashes);\n\n  const fillMaterial = new MeshBasicMaterial({\n    color,\n    transparent: true,\n    opacity: 0.28,\n    side: DoubleSide,\n  });\n  const fill = new Mesh(new RingGeometry(0.01, radius * 0.92, 40), fillMaterial);\n  fill.rotation.x = -Math.PI / 2;\n  fill.position.y = 0.02;\n  fill.scale.setScalar(0.001);\n  group.add(fill);\n\n  let clock = new Rng(seed).range(0, 6);\n  const trigger: Obstacle = { center: group.position, radius };\n\n  return {\n    group,\n    trigger,\n    setProgress(value: number) {\n      const v = Number.isFinite(value) ? Math.min(Math.max(value, 0), 1) : 0;\n      fill.scale.setScalar(Math.max(v, 0.001));\n      fillMaterial.opacity = 0.18 + v * 0.25;\n    },\n    update(dt: number) {\n      const step = Number.isFinite(dt) ? Math.max(dt, 0) : 0;\n      clock += step;\n      dashes.rotation.y = clock * 0.6;\n      edge.opacity = 0.6 + 0.2 * Math.sin(clock * 3);\n    },\n  };\n}\n\n// ---------------------------------------------------------------------------\n\nexport interface BeaconOptions {\n  seed?: number;\n  /** Pillar height, metres. Default 9. */\n  height?: number;\n  color?: number;\n}\n\nexport interface Beacon {\n  group: Group;\n  trigger: Obstacle;\n  update(dt: number): void;\n}\n\n/**\n * A pillar of light readable across the map — the \"go HERE\" a radar can\n * only hint at. Additive, double-sided, fading with height; a small base\n * ring anchors it to the ground so it reads as placed, not painted.\n */\nexport function createBeacon(options: BeaconOptions = {}): Beacon {\n  const seed = options.seed ?? 1;\n  const height = options.height ?? 9;\n  const color = options.color ?? 0xf3c94e;\n\n  const group = new Group();\n  group.name = 'beacon';\n\n  const shaft = new MeshBasicMaterial({\n    color,\n    transparent: true,\n    opacity: 0.4,\n    blending: AdditiveBlending,\n    depthWrite: false,\n    side: DoubleSide,\n  });\n  // Two nested tapers beat one: the parallax between them is what makes\n  // the pillar read as VOLUME rather than a painted stripe.\n  for (const [r0, r1, o] of [\n    [0.5, 0.14, 0.35],\n    [0.28, 0.06, 0.55],\n  ]) {\n    const cone = new Mesh(new CylinderGeometry(r1, r0, height, 12, 1, true), shaft.clone());\n    (cone.material as MeshBasicMaterial).opacity = o;\n    cone.position.y = height / 2;\n    group.add(cone);\n  }\n  const ring = new Mesh(new TorusGeometry(0.62, 0.05, 8, 24), new MeshBasicMaterial({ color }));\n  ring.rotation.x = Math.PI / 2;\n  ring.position.y = 0.06;\n  group.add(ring);\n\n  let clock = new Rng(seed).range(0, 6);\n  const trigger: Obstacle = { center: group.position, radius: 1.2 };\n\n  return {\n    group,\n    trigger,\n    update(dt: number) {\n      const step = Number.isFinite(dt) ? Math.max(dt, 0) : 0;\n      clock += step;\n      const breathe = 0.85 + 0.15 * Math.sin(clock * 1.7);\n      group.children.forEach((child, i) => {\n        if (i < 2) (child as Mesh).scale.set(breathe, 1, breathe);\n      });\n      group.rotation.y = clock * 0.4;\n    },\n  };\n}\n\n// ---------------------------------------------------------------------------\n\nexport interface FinishGateOptions {\n  seed?: number;\n  /** Clear width between posts. Default 6. */\n  width?: number;\n  /** Height to the banner's underside. Default 3.2. */\n  height?: number;\n}\n\nexport interface FinishGate {\n  group: Group;\n  trigger: Obstacle;\n  update(dt: number): void;\n}\n\n/**\n * The chequered line. The banner is real geometry — one InstancedMesh of\n * alternating cells, no texture — so it stays crisp at any distance and\n * dresses both sides.\n */\nexport function createFinishGate(options: FinishGateOptions = {}): FinishGate {\n  const seed = options.seed ?? 1;\n  const width = options.width ?? 6;\n  const height = options.height ?? 3.2;\n\n  const group = new Group();\n  group.name = 'finish-gate';\n\n  const postMaterial = createSurface('steel', { seed });\n  const post = new CylinderGeometry(0.16, 0.2, height + 0.9, 10);\n  for (const side of [-1, 1]) {\n    const p = new Mesh(post, postMaterial);\n    p.position.set((side * (width + 0.5)) / 2, (height + 0.9) / 2, 0);\n    group.add(p);\n  }\n\n  const rows = 2;\n  const columns = Math.max(Math.round(width / 0.45), 6);\n  const cell = width / columns;\n  const cellGeometry = new BoxGeometry(cell, cell, 0.06);\n  const white = new MeshStandardMaterial({ color: 0xf2f2ee });\n  const black = new MeshStandardMaterial({ color: 0x181a1e });\n  const whites = new InstancedMesh(cellGeometry, white, Math.ceil((rows * columns) / 2));\n  const blacks = new InstancedMesh(cellGeometry, black, Math.floor((rows * columns) / 2) + 1);\n  const matrix = new Matrix4();\n  const quat = new Quaternion();\n  const one = new Vector3(1, 1, 1);\n  const pos = new Vector3();\n  let wi = 0;\n  let bi = 0;\n  for (let row = 0; row < rows; row++) {\n    for (let column = 0; column < columns; column++) {\n      pos.set(-width / 2 + cell * (column + 0.5), height + 0.9 - cell * (row + 0.5) - 0.45, 0);\n      matrix.compose(pos, quat, one);\n      if ((row + column) % 2 === 0) whites.setMatrixAt(wi++, matrix);\n      else blacks.setMatrixAt(bi++, matrix);\n    }\n  }\n  whites.count = wi;\n  blacks.count = bi;\n  group.add(whites, blacks);\n\n  const trigger: Obstacle = { center: group.position, radius: width / 2 };\n\n  return {\n    group,\n    trigger,\n    update() {\n      /* the line does not blink — it only waits */\n    },\n  };\n}\n","import {\n  BoxGeometry,\n  ConeGeometry,\n  CylinderGeometry,\n  Group,\n  InstancedMesh,\n  Matrix4,\n  Mesh,\n  Quaternion,\n  Vector3,\n} from 'three';\nimport { Rng } from '../core/random';\nimport { createSurface } from '../materials/surface';\nimport type { Obstacle } from '../core/types';\n\n/**\n * Hazards — the props where movement itself is the game.\n *\n * Platforms that carry you, floors that give way, pads that launch you,\n * blades that swing where you wanted to walk, belts that move the ground,\n * and the pressure plate that turns all of SCENA's doors and gates into\n * puzzle vocabulary. Everything speaks the trilogy's structural dialect:\n * `{center, radius}` triggers for proximity, live `delta`/`velocity`\n * vectors for riders, and the plate is shaped exactly like GAMA's\n * `MechanismSource` — `linkMechanism(plate, door)` and the level has its\n * first circuit, with no imports between the libraries.\n */\n\n// ---------------------------------------------------------------------------\n// Moving platform\n// ---------------------------------------------------------------------------\n\nexport type PlatformMotion = 'linear' | 'orbit' | 'pendulum';\n\nexport interface PlatformOptions {\n  seed?: number;\n  /** Top surface size, metres. Default [2.4, 1.8] (x, z). */\n  size?: [number, number];\n  motion?: PlatformMotion;\n  /** linear: the two ends. Defaults ±3 on x. */\n  from?: Vector3;\n  to?: Vector3;\n  /** orbit/pendulum: swing radius, metres. Default 3. */\n  radius?: number;\n  /** Seconds for a full cycle (there AND back for linear). Default 6. */\n  period?: number;\n}\n\nexport interface MovingPlatform {\n  group: Group;\n  /** Height of the standing surface above the group origin. */\n  top: number;\n  /**\n   * How far the platform moved LAST update — add it to whoever stands on\n   * top and they ride; skip it and they moonwalk off the edge.\n   */\n  delta: Vector3;\n  /** Current velocity, m/s — for launching off the edge with momentum. */\n  velocity: Vector3;\n  trigger: Obstacle;\n  update(dt: number): void;\n}\n\nexport function createPlatform(options: PlatformOptions = {}): MovingPlatform {\n  const seed = options.seed ?? 1;\n  const rng = new Rng(seed);\n  const [sx, sz] = options.size ?? [2.4, 1.8];\n  const motion = options.motion ?? 'linear';\n  const from = options.from ?? new Vector3(-3, 0, 0);\n  const to = options.to ?? new Vector3(3, 0, 0);\n  const radius = options.radius ?? 3;\n  const period = Math.max(options.period ?? 6, 0.5);\n\n  const group = new Group();\n  group.name = 'platform';\n  const slab = new Mesh(new BoxGeometry(sx, 0.3, sz), createSurface('plank', { seed }));\n  slab.position.y = 0.15;\n  group.add(slab);\n  const trim = new Mesh(new BoxGeometry(sx * 1.04, 0.08, sz * 1.04), createSurface('steel', { seed: seed + 1 }));\n  trim.position.y = 0.04;\n  group.add(trim);\n\n  let clock = rng.range(0, period);\n  const previous = new Vector3();\n  const delta = new Vector3();\n  const velocity = new Vector3();\n  const place = (t: number, out: Vector3): void => {\n    const w = (t % period) / period;\n    if (motion === 'linear') {\n      // Smooth there-and-back: no jerk at the turnarounds.\n      const s = 0.5 - 0.5 * Math.cos(w * Math.PI * 2);\n      out.copy(from).lerp(to, s);\n    } else if (motion === 'orbit') {\n      const a = w * Math.PI * 2;\n      out.set(Math.cos(a) * radius, 0, Math.sin(a) * radius);\n    } else {\n      // Pendulum: a swing through ±72° hanging below the group origin.\n      const a = Math.sin(w * Math.PI * 2) * 1.25;\n      out.set(Math.sin(a) * radius, -Math.cos(a) * radius + radius, 0);\n    }\n  };\n  place(clock, group.position);\n  previous.copy(group.position);\n\n  const trigger: Obstacle = { center: group.position, radius: Math.max(sx, sz) * 0.6 };\n\n  return {\n    group,\n    top: 0.3,\n    delta,\n    velocity,\n    trigger,\n    update(dt: number) {\n      const step = Number.isFinite(dt) ? Math.max(dt, 0) : 0;\n      clock += step;\n      place(clock, group.position);\n      delta.subVectors(group.position, previous);\n      velocity.copy(delta).multiplyScalar(step > 1e-6 ? 1 / step : 0);\n      previous.copy(group.position);\n    },\n  };\n}\n\n// ---------------------------------------------------------------------------\n// Crumbling platform\n// ---------------------------------------------------------------------------\n\nexport type CrumbleState = 'solid' | 'shaking' | 'falling' | 'gone' | 'returning';\n\nexport interface CrumbleOptions {\n  seed?: number;\n  size?: [number, number];\n  /** Seconds of warning shudder after being disturbed. Default 0.7. */\n  delay?: number;\n  /** Seconds gone before it returns. Default 3. */\n  respawn?: number;\n}\n\nexport interface CrumblingPlatform {\n  group: Group;\n  top: number;\n  trigger: Obstacle;\n  readonly state: CrumbleState;\n  /** Someone stood on it. Starts the shudder (once). */\n  disturb(): void;\n  /** Is it currently safe to stand on? */\n  readonly solid: boolean;\n  update(dt: number): void;\n}\n\nexport function createCrumblingPlatform(options: CrumbleOptions = {}): CrumblingPlatform {\n  const seed = options.seed ?? 1;\n  const rng = new Rng(seed);\n  const [sx, sz] = options.size ?? [2, 2];\n  const delay = Math.max(options.delay ?? 0.7, 0.05);\n  const respawn = Math.max(options.respawn ?? 3, 0.5);\n\n  const group = new Group();\n  group.name = 'crumbling-platform';\n  const slab = new Mesh(new BoxGeometry(sx, 0.26, sz), createSurface('ashlar', { seed }));\n  slab.position.y = 0.13;\n  group.add(slab);\n\n  let state: CrumbleState = 'solid';\n  let timer = 0;\n  const home = new Vector3();\n  let homed = false;\n  const phase = rng.range(0, Math.PI * 2);\n\n  const trigger: Obstacle = { center: group.position, radius: Math.max(sx, sz) * 0.6 };\n\n  return {\n    group,\n    top: 0.26,\n    trigger,\n    get state() {\n      return state;\n    },\n    get solid() {\n      return state === 'solid' || state === 'shaking';\n    },\n    disturb() {\n      if (state !== 'solid') return;\n      state = 'shaking';\n      timer = 0;\n    },\n    update(dt: number) {\n      const step = Number.isFinite(dt) ? Math.max(dt, 0) : 0;\n      if (!homed) {\n        home.copy(group.position);\n        homed = true;\n      }\n      timer += step;\n      if (state === 'shaking') {\n        // The warning IS the gameplay: a floor that drops unannounced is\n        // unfair; one that shudders first is a decision you made.\n        slab.position.x = Math.sin(timer * 46 + phase) * 0.03;\n        slab.position.z = Math.cos(timer * 39 + phase) * 0.03;\n        if (timer >= delay) {\n          state = 'falling';\n          timer = 0;\n          slab.position.x = 0;\n          slab.position.z = 0;\n        }\n      } else if (state === 'falling') {\n        group.position.y = home.y - timer * timer * 9.8 * 0.5;\n        slab.rotation.x += step * 1.4;\n        if (timer > 0.9) {\n          state = 'gone';\n          timer = 0;\n          group.visible = false;\n        }\n      } else if (state === 'gone') {\n        if (timer >= respawn) {\n          state = 'returning';\n          timer = 0;\n          group.visible = true;\n          slab.rotation.x = 0;\n          group.position.copy(home).y = home.y - 1.2;\n        }\n      } else if (state === 'returning') {\n        const w = Math.min(timer / 0.5, 1);\n        group.position.y = home.y - 1.2 * (1 - w * w * (3 - 2 * w));\n        if (w >= 1) {\n          group.position.copy(home);\n          state = 'solid';\n        }\n      }\n    },\n  };\n}\n\n// ---------------------------------------------------------------------------\n// Bounce pad\n// ---------------------------------------------------------------------------\n\nexport interface BouncePadOptions {\n  seed?: number;\n  /** Pad radius, metres. Default 0.9. */\n  radius?: number;\n  /** Launch speed handed back by bounce(), m/s. Default 11. */\n  strength?: number;\n  color?: number;\n}\n\nexport interface BouncePad {\n  group: Group;\n  trigger: Obstacle;\n  /** Squash, stretch, and return the launch speed for the caller to apply. */\n  bounce(): number;\n  update(dt: number): void;\n}\n\nexport function createBouncePad(options: BouncePadOptions = {}): BouncePad {\n  const seed = options.seed ?? 1;\n  const radius = options.radius ?? 0.9;\n  const strength = options.strength ?? 11;\n\n  const group = new Group();\n  group.name = 'bounce-pad';\n  const base = new Mesh(new CylinderGeometry(radius, radius * 1.12, 0.18, 18), createSurface('steel', { seed }));\n  base.position.y = 0.09;\n  group.add(base);\n  const cushion = new Mesh(\n    new CylinderGeometry(radius * 0.88, radius * 0.92, 0.16, 18),\n    createSurface('paint', { seed: seed + 1, color: options.color ?? 0xd9903c })\n  );\n  cushion.position.y = 0.24;\n  group.add(cushion);\n\n  let anim = 1; // spring phase: 1 = at rest\n\n  const trigger: Obstacle = { center: group.position, radius };\n\n  return {\n    group,\n    trigger,\n    bounce() {\n      anim = 0;\n      return strength;\n    },\n    update(dt: number) {\n      const step = Number.isFinite(dt) ? Math.max(dt, 0) : 0;\n      anim = Math.min(anim + step / 0.45, 1);\n      // Squash hard and instantly, then overshoot tall, then settle —\n      // the classic squash-and-stretch envelope in one damped sine.\n      const s = anim;\n      const scale = 1 + Math.sin(s * Math.PI * 3) * (1 - s) * 0.55 * (s < 0.12 ? -2.2 : 1);\n      cushion.scale.set(1 + (1 - scale) * 0.5, Math.max(scale, 0.25), 1 + (1 - scale) * 0.5);\n      cushion.position.y = 0.09 + 0.15 * Math.max(scale, 0.25);\n    },\n  };\n}\n\n// ---------------------------------------------------------------------------\n// Pendulum blade\n// ---------------------------------------------------------------------------\n\nexport interface PendulumOptions {\n  seed?: number;\n  /** Arm length, metres. Default 3. */\n  length?: number;\n  /** Swing half-angle, radians. Default 1.05 (~60°). */\n  amplitude?: number;\n  /** Seconds per full swing there and back. Default 2.6. */\n  period?: number;\n}\n\nexport interface Pendulum {\n  group: Group;\n  /** The blade's LIVE world-offset circle (relative to group position). */\n  hazard: Obstacle;\n  update(dt: number): void;\n}\n\n/** Hang the group from a beam; the blade swings below and `hazard` follows it. */\nexport function createPendulum(options: PendulumOptions = {}): Pendulum {\n  const seed = options.seed ?? 1;\n  const rng = new Rng(seed);\n  const length = options.length ?? 3;\n  const amplitude = options.amplitude ?? 1.05;\n  const period = Math.max(options.period ?? 2.6, 0.4);\n\n  const group = new Group();\n  group.name = 'pendulum';\n  const arm = new Group();\n  group.add(arm);\n  const rod = new Mesh(new CylinderGeometry(0.06, 0.06, length, 8), createSurface('steel', { seed }));\n  rod.position.y = -length / 2;\n  arm.add(rod);\n  const blade = new Mesh(new ConeGeometry(0.55, 0.5, 4), createSurface('brushedMetal', { seed: seed + 1 }));\n  blade.rotation.set(Math.PI, Math.PI / 4, 0);\n  blade.position.y = -length;\n  blade.scale.z = 0.3;\n  arm.add(blade);\n\n  let clock = rng.range(0, period);\n  const hazard: Obstacle = { center: new Vector3(), radius: 0.6 };\n\n  const settle = (): void => {\n    const a = Math.sin((clock / period) * Math.PI * 2) * amplitude;\n    arm.rotation.z = a;\n    // The hazard rides the blade tip, in the group's local frame plus its\n    // world position — cheap and exact for an unrotated group.\n    hazard.center\n      .set(Math.sin(a) * length, -Math.cos(a) * length, 0)\n      .add(group.position);\n  };\n  settle();\n\n  return {\n    group,\n    hazard,\n    update(dt: number) {\n      const step = Number.isFinite(dt) ? Math.max(dt, 0) : 0;\n      clock += step;\n      settle();\n    },\n  };\n}\n\n// ---------------------------------------------------------------------------\n// Spike trap\n// ---------------------------------------------------------------------------\n\nexport interface SpikeTrapOptions {\n  seed?: number;\n  /** Plate size, metres. Default [1.6, 1.6]. */\n  size?: [number, number];\n  /** 'cycling' extends on a timer; 'triggered' waits for spring(). Default 'cycling'. */\n  mode?: 'cycling' | 'triggered';\n  /** Cycling: seconds per full cycle. Default 2.4. */\n  period?: number;\n}\n\nexport interface SpikeTrap {\n  group: Group;\n  trigger: Obstacle;\n  /** True while the spikes are OUT — the only time this square hurts. */\n  readonly dangerous: boolean;\n  /** Triggered mode: spring the trap now. */\n  spring(): void;\n  update(dt: number): void;\n}\n\nexport function createSpikeTrap(options: SpikeTrapOptions = {}): SpikeTrap {\n  const seed = options.seed ?? 1;\n  const rng = new Rng(seed);\n  const [sx, sz] = options.size ?? [1.6, 1.6];\n  const mode = options.mode ?? 'cycling';\n  const period = Math.max(options.period ?? 2.4, 0.6);\n\n  const group = new Group();\n  group.name = 'spike-trap';\n  const plate = new Mesh(new BoxGeometry(sx, 0.1, sz), createSurface('diamondPlate', { seed }));\n  plate.position.y = 0.05;\n  group.add(plate);\n\n  const columns = 3;\n  const rows = 3;\n  const spikes = new InstancedMesh(\n    new ConeGeometry(0.09, 0.55, 6),\n    createSurface('steel', { seed: seed + 1 }),\n    columns * rows\n  );\n  group.add(spikes);\n  const matrix = new Matrix4();\n  const quat = new Quaternion();\n  const one = new Vector3(1, 1, 1);\n  const pos = new Vector3();\n  const setSpikes = (out: number): void => {\n    let i = 0;\n    for (let r = 0; r < rows; r++) {\n      for (let c = 0; c < columns; c++) {\n        pos.set(\n          (c - (columns - 1) / 2) * (sx / columns) * 0.8,\n          -0.28 + out * 0.55,\n          (r - (rows - 1) / 2) * (sz / rows) * 0.8\n        );\n        matrix.compose(pos, quat, one);\n        spikes.setMatrixAt(i++, matrix);\n      }\n    }\n    spikes.instanceMatrix.needsUpdate = true;\n  };\n  setSpikes(0);\n\n  let clock = rng.range(0, period);\n  let out = 0;\n  let springing = 0;\n\n  const trigger: Obstacle = { center: group.position, radius: Math.max(sx, sz) * 0.6 };\n\n  return {\n    group,\n    trigger,\n    get dangerous() {\n      return out > 0.6;\n    },\n    spring() {\n      if (mode === 'triggered' && springing === 0) springing = 1e-6;\n    },\n    update(dt: number) {\n      const step = Number.isFinite(dt) ? Math.max(dt, 0) : 0;\n      if (mode === 'cycling') {\n        clock += step;\n        const w = (clock % period) / period;\n        // Out FAST (the danger), in slow (the tell): 20% snap, 45% hold,\n        // 35% withdraw.\n        out = w < 0.2 ? w / 0.2 : w < 0.65 ? 1 : 1 - (w - 0.65) / 0.35;\n      } else if (springing > 0) {\n        springing += step;\n        out = springing < 0.12 ? springing / 0.12 : springing < 0.9 ? 1 : Math.max(1 - (springing - 0.9) / 0.5, 0);\n        if (out === 0) springing = 0;\n      }\n      setSpikes(out);\n    },\n  };\n}\n\n// ---------------------------------------------------------------------------\n// Conveyor\n// ---------------------------------------------------------------------------\n\nexport interface ConveyorOptions {\n  seed?: number;\n  /** Belt length and width, metres. Default 6 × 1.6. */\n  length?: number;\n  width?: number;\n  /** Surface speed along local +x, m/s (negative reverses). Default 1.6. */\n  speed?: number;\n}\n\nexport interface Conveyor {\n  group: Group;\n  /** Live surface velocity in WORLD space — add `velocity * dt` to riders. */\n  velocity: Vector3;\n  trigger: Obstacle;\n  /** Change the belt speed (chevrons and velocity follow). */\n  setSpeed(speed: number): void;\n  update(dt: number): void;\n}\n\nexport function createConveyor(options: ConveyorOptions = {}): Conveyor {\n  const seed = options.seed ?? 1;\n  const length = options.length ?? 6;\n  const width = options.width ?? 1.6;\n  let speed = options.speed ?? 1.6;\n\n  const group = new Group();\n  group.name = 'conveyor';\n  const bed = new Mesh(new BoxGeometry(length, 0.22, width), createSurface('steel', { seed }));\n  bed.position.y = 0.11;\n  group.add(bed);\n\n  // The motion is CHEVRONS, not a texture scroll: instanced bars that ride\n  // along and wrap, readable at any angle and cheap as one draw call.\n  const count = Math.max(Math.round(length / 0.55), 4);\n  const chevrons = new InstancedMesh(\n    new BoxGeometry(0.12, 0.03, width * 0.82),\n    createSurface('paint', { seed: seed + 1, color: 0xe8c645 }),\n    count\n  );\n  group.add(chevrons);\n  const matrix = new Matrix4();\n  const quat = new Quaternion();\n  const one = new Vector3(1, 1, 1);\n  const pos = new Vector3();\n  let offset = 0;\n  const settle = (): void => {\n    for (let i = 0; i < count; i++) {\n      let x = ((i / count) * length + offset) % length;\n      if (x < 0) x += length;\n      pos.set(x - length / 2, 0.235, 0);\n      matrix.compose(pos, quat, one);\n      chevrons.setMatrixAt(i, matrix);\n    }\n    chevrons.instanceMatrix.needsUpdate = true;\n  };\n  settle();\n\n  const velocity = new Vector3(speed, 0, 0);\n  const trigger: Obstacle = { center: group.position, radius: Math.max(length, width) * 0.55 };\n\n  return {\n    group,\n    velocity,\n    trigger,\n    setSpeed(next: number) {\n      speed = Number.isFinite(next) ? next : 0;\n    },\n    update(dt: number) {\n      const step = Number.isFinite(dt) ? Math.max(dt, 0) : 0;\n      offset = (offset + speed * step) % length;\n      settle();\n      // World-space velocity: local +x through the group's yaw.\n      velocity.set(speed, 0, 0).applyQuaternion(group.quaternion);\n    },\n  };\n}\n\n// ---------------------------------------------------------------------------\n// Pressure plate\n// ---------------------------------------------------------------------------\n\nexport interface PressurePlateOptions {\n  seed?: number;\n  /** Plate size, metres. Default [1.3, 1.3]. */\n  size?: [number, number];\n  /**\n   * Latching plates stay pressed once stood on (a puzzle solved); momentary\n   * plates release when everyone steps off (a door held). Default false.\n   */\n  latching?: boolean;\n}\n\nexport interface PressurePlate {\n  group: Group;\n  trigger: Obstacle;\n  /** GAMA MechanismSource, structurally: pressed = open = powering the link. */\n  readonly open: boolean;\n  toggle(): boolean;\n  set(target: number | boolean): void;\n  onChange?: (open: boolean) => void;\n  /** Tell the plate how many stand on it this frame (0 releases momentary). */\n  occupy(count: number): void;\n  update(dt: number): void;\n}\n\n/**\n * The keystone: it depresses under weight and speaks GAMA's mechanism\n * dialect, so `linkMechanism(plate, door)` wires it to every door, gate\n * and drawbridge SCENA already ships. Feed it an occupancy count each\n * frame — GAMA's `Occupancy` or a plain trigger test both know it.\n */\nexport function createPressurePlate(options: PressurePlateOptions = {}): PressurePlate {\n  const seed = options.seed ?? 1;\n  const [sx, sz] = options.size ?? [1.3, 1.3];\n  const latching = options.latching ?? false;\n\n  const group = new Group();\n  group.name = 'pressure-plate';\n  const frame = new Mesh(new BoxGeometry(sx * 1.16, 0.08, sz * 1.16), createSurface('ashlar', { seed }));\n  frame.position.y = 0.04;\n  group.add(frame);\n  const plate = new Mesh(new BoxGeometry(sx, 0.09, sz), createSurface('brass', { seed: seed + 1 }));\n  plate.position.y = 0.1;\n  group.add(plate);\n\n  let pressed = false;\n  let sink = 0;\n\n  const trigger: Obstacle = { center: group.position, radius: Math.max(sx, sz) * 0.62 };\n\n  const self: PressurePlate = {\n    group,\n    trigger,\n    get open() {\n      return pressed;\n    },\n    toggle() {\n      self.set(!pressed);\n      return pressed;\n    },\n    set(target: number | boolean) {\n      const next = typeof target === 'number' ? target > 0.5 : target;\n      if (next === pressed) return;\n      pressed = next;\n      self.onChange?.(pressed);\n    },\n    occupy(count: number) {\n      const on = Number.isFinite(count) && count > 0;\n      if (on && !pressed) self.set(true);\n      else if (!on && pressed && !latching) self.set(false);\n    },\n    update(dt: number) {\n      const step = Number.isFinite(dt) ? Math.max(dt, 0) : 0;\n      const target = pressed ? 1 : 0;\n      sink += (target - sink) * Math.min(step * 14, 1);\n      plate.position.y = 0.1 - sink * 0.055;\n    },\n  };\n  return self;\n}\n","import {\n  BoxGeometry,\n  CylinderGeometry,\n  Group,\n  Mesh,\n  SphereGeometry,\n  TetrahedronGeometry,\n  Vector3,\n} from 'three';\nimport { Rng } from '../core/random';\nimport { createSurface } from '../materials/surface';\nimport { buildTextGeometry } from '../text/textGeometry';\nimport type { Obstacle } from '../core/types';\n\n/**\n * Destructibles — the props that give feedback by coming apart.\n *\n * A breakable is two props in one: the intact shell everyone sees, and\n * the seeded pre-fractured shards hiding inside it. `break()` swaps one\n * for the other and lets the pieces fly, bounce, and settle into debris\n * — the classic loop-closer, with a `loot` position where a pickup\n * should appear. The target dummy wobbles by the blow and topples on\n * command; the scoreboard gives the vector font a job with moving\n * parts; and the stumps finally do the thing cricket feedback is FOR:\n * the bails fly.\n */\n\nconst GRAVITY = 9.8;\n\ninterface Piece {\n  mesh: Mesh;\n  vel: Vector3;\n  spin: Vector3;\n  home: Vector3;\n  homeQuat: [number, number, number, number];\n  resting: boolean;\n}\n\n/** Shared shard flight: gravity, one soft floor bounce, then rest. */\nfunction flyPieces(pieces: Piece[], dt: number, floorY: number): void {\n  for (const piece of pieces) {\n    if (piece.resting) continue;\n    piece.vel.y -= GRAVITY * dt;\n    piece.mesh.position.addScaledVector(piece.vel, dt);\n    piece.mesh.rotation.x += piece.spin.x * dt;\n    piece.mesh.rotation.y += piece.spin.y * dt;\n    piece.mesh.rotation.z += piece.spin.z * dt;\n    if (piece.mesh.position.y <= floorY && piece.vel.y < 0) {\n      piece.mesh.position.y = floorY;\n      if (Math.abs(piece.vel.y) > 1.2) {\n        piece.vel.y *= -0.3;\n        piece.vel.x *= 0.5;\n        piece.vel.z *= 0.5;\n        piece.spin.multiplyScalar(0.5);\n      } else {\n        piece.resting = true;\n        piece.vel.set(0, 0, 0);\n      }\n    }\n  }\n}\n\nfunction resetPieces(pieces: Piece[]): void {\n  for (const piece of pieces) {\n    piece.mesh.position.copy(piece.home);\n    piece.mesh.quaternion.set(...piece.homeQuat);\n    piece.mesh.rotation.setFromQuaternion(piece.mesh.quaternion);\n    piece.vel.set(0, 0, 0);\n    piece.resting = false;\n  }\n}\n\n// ---------------------------------------------------------------------------\n// Breakables\n// ---------------------------------------------------------------------------\n\nexport type BreakableKind = 'crate' | 'barrel' | 'pot';\nexport type BreakableState = 'intact' | 'breaking' | 'debris';\n\nexport interface BreakableOptions {\n  seed?: number;\n  /** Overall size, metres. Default 0.9. */\n  size?: number;\n  /** Shard count. Default 9. */\n  shards?: number;\n}\n\nexport interface Breakable {\n  group: Group;\n  kind: BreakableKind;\n  trigger: Obstacle;\n  readonly state: BreakableState;\n  /**\n   * Where dropped loot belongs, in the group's local frame — hand it to\n   * a pickup's position when the shards fly.\n   */\n  loot: Vector3;\n  /** Come apart. `impulse` biases the shards' flight (a hit direction). */\n  break(impulse?: { x: number; y?: number; z: number }): void;\n  /** Back in one piece — pooled levels reuse their props. */\n  reset(): void;\n  update(dt: number): void;\n}\n\nexport function createBreakable(kind: BreakableKind, options: BreakableOptions = {}): Breakable {\n  const seed = options.seed ?? 1;\n  const rng = new Rng(seed);\n  const size = options.size ?? 0.9;\n  const shardCount = Math.max(options.shards ?? 9, 4);\n\n  const group = new Group();\n  group.name = `breakable-${kind}`;\n\n  // The intact shell.\n  const shell = new Group();\n  group.add(shell);\n  let material;\n  if (kind === 'crate') {\n    material = createSurface('plank', { seed });\n    const body = new Mesh(new BoxGeometry(size, size, size), material);\n    body.position.y = size / 2;\n    shell.add(body);\n  } else if (kind === 'barrel') {\n    material = createSurface('wood', { seed });\n    const body = new Mesh(\n      new CylinderGeometry(size * 0.42, size * 0.42, size, 12),\n      material\n    );\n    body.position.y = size / 2;\n    shell.add(body);\n    const hoop = createSurface('steel', { seed: seed + 1 });\n    for (const y of [size * 0.22, size * 0.78]) {\n      const ring = new Mesh(new CylinderGeometry(size * 0.44, size * 0.44, size * 0.06, 12), hoop);\n      ring.position.y = y;\n      shell.add(ring);\n    }\n  } else {\n    material = createSurface('terracotta', { seed });\n    const body = new Mesh(new SphereGeometry(size * 0.45, 12, 9), material);\n    body.scale.y = 1.1;\n    body.position.y = size * 0.5;\n    shell.add(body);\n    const neck = new Mesh(new CylinderGeometry(size * 0.2, size * 0.26, size * 0.16, 10), material);\n    neck.position.y = size * 0.98;\n    shell.add(neck);\n  }\n\n  // The shards, pre-fractured and hidden. Seeded once: the same crate\n  // always breaks into the same pieces, which is what makes a break\n  // replayable and a save-file honest.\n  const debris = new Group();\n  debris.visible = false;\n  group.add(debris);\n  const pieces: Piece[] = [];\n  for (let i = 0; i < shardCount; i++) {\n    const shard = new Mesh(\n      new TetrahedronGeometry(size * rng.range(0.12, 0.24), 0),\n      material\n    );\n    shard.position.set(\n      rng.range(-0.25, 0.25) * size,\n      rng.range(0.2, 0.85) * size,\n      rng.range(-0.25, 0.25) * size\n    );\n    shard.rotation.set(rng.range(0, Math.PI), rng.range(0, Math.PI), rng.range(0, Math.PI));\n    debris.add(shard);\n    pieces.push({\n      mesh: shard,\n      vel: new Vector3(),\n      spin: new Vector3(),\n      home: shard.position.clone(),\n      homeQuat: [shard.quaternion.x, shard.quaternion.y, shard.quaternion.z, shard.quaternion.w],\n      resting: false,\n    });\n  }\n\n  let state: BreakableState = 'intact';\n  let settleClock = 0;\n\n  const trigger: Obstacle = { center: group.position, radius: size * 0.7 };\n\n  return {\n    group,\n    kind,\n    trigger,\n    loot: new Vector3(0, size * 0.5, 0),\n    get state() {\n      return state;\n    },\n    break(impulse) {\n      if (state !== 'intact') return;\n      state = 'breaking';\n      settleClock = 0;\n      shell.visible = false;\n      debris.visible = true;\n      const bias = new Vector3(impulse?.x ?? 0, impulse?.y ?? 0, impulse?.z ?? 0);\n      if (bias.length() > 6) bias.setLength(6);\n      for (const piece of pieces) {\n        // Outward from the centre, up, plus the hit's own push.\n        piece.vel\n          .copy(piece.home)\n          .setY(0)\n          .normalize()\n          .multiplyScalar(rng.range(1.2, 2.6))\n          .add(bias);\n        piece.vel.y = rng.range(2, 4);\n        piece.spin.set(rng.range(-8, 8), rng.range(-8, 8), rng.range(-8, 8));\n        piece.resting = false;\n      }\n    },\n    reset() {\n      state = 'intact';\n      shell.visible = true;\n      debris.visible = false;\n      resetPieces(pieces);\n    },\n    update(dt) {\n      if (state === 'intact') return;\n      const step = Number.isFinite(dt) ? Math.min(Math.max(dt, 0), 0.1) : 0;\n      flyPieces(pieces, step, 0.05);\n      if (state === 'breaking') {\n        settleClock += step;\n        if (settleClock > 1 && pieces.every((p) => p.resting)) state = 'debris';\n      }\n    },\n  };\n}\n\n// ---------------------------------------------------------------------------\n// Target dummy\n// ---------------------------------------------------------------------------\n\nexport interface TargetDummyOptions {\n  seed?: number;\n  /** Total height, metres. Default 1.7. */\n  height?: number;\n}\n\nexport interface TargetDummy {\n  group: Group;\n  trigger: Obstacle;\n  readonly toppled: boolean;\n  /** Wobble away from the blow. `power` scales the swing. */\n  hit(from?: { x: number; y?: number; z: number }, power?: number): void;\n  /** Over it goes — the KO. */\n  topple(): void;\n  reset(): void;\n  update(dt: number): void;\n}\n\n/**\n * The training-yard prop: a post, a torso, a head, and a spring. Hits\n * wobble it (a damped pendulum about its base); `topple()` lays it\n * down and it stays down. Wire its trigger to GAMA's Projectiles and\n * its `hit` to the impact event, and the yard teaches aim.\n */\nexport function createTargetDummy(options: TargetDummyOptions = {}): TargetDummy {\n  const seed = options.seed ?? 1;\n  const height = options.height ?? 1.7;\n\n  const group = new Group();\n  group.name = 'target-dummy';\n  const pivot = new Group();\n  group.add(pivot);\n  const post = new Mesh(\n    new CylinderGeometry(0.06, 0.08, height * 0.55, 8),\n    createSurface('wood', { seed })\n  );\n  post.position.y = height * 0.275;\n  pivot.add(post);\n  const torso = new Mesh(\n    new CylinderGeometry(0.2, 0.16, height * 0.36, 10),\n    createSurface('canvas', { seed: seed + 1 })\n  );\n  torso.position.y = height * 0.68;\n  pivot.add(torso);\n  const head = new Mesh(new SphereGeometry(0.13, 10, 8), createSurface('canvas', { seed: seed + 2 }));\n  head.position.y = height * 0.95;\n  pivot.add(head);\n\n  // The wobble spring: angle + angular velocity about a seeded-fixed axis.\n  let angle = 0;\n  let omega = 0;\n  const axis = new Vector3(1, 0, 0);\n  let toppled = false;\n\n  const trigger: Obstacle = { center: group.position, radius: 0.45 };\n\n  return {\n    group,\n    trigger,\n    get toppled() {\n      return toppled;\n    },\n    hit(from, power = 1) {\n      if (toppled) return;\n      // Swing away from the blow, in the vertical plane containing it.\n      if (from) {\n        const dx = group.position.x - from.x;\n        const dz = group.position.z - from.z;\n        const len = Math.hypot(dx, dz) || 1;\n        axis.set(dz / len, 0, -dx / len);\n      } else {\n        axis.set(1, 0, 0);\n      }\n      omega += Math.min(Math.max(power, 0.2), 3) * 3.2;\n    },\n    topple() {\n      toppled = true;\n    },\n    reset() {\n      toppled = false;\n      angle = 0;\n      omega = 0;\n      pivot.rotation.set(0, 0, 0);\n    },\n    update(dt) {\n      const step = Number.isFinite(dt) ? Math.min(Math.max(dt, 0), 0.1) : 0;\n      if (toppled) {\n        // Fall to the ground and stay: ease the angle to 90°.\n        angle += (Math.PI / 2 - angle) * Math.min(step * 6, 1);\n      } else {\n        // A damped pendulum: stiffness pulls home, damping bleeds it off.\n        omega += (-angle * 28 - omega * 4.5) * step;\n        angle += omega * step;\n      }\n      pivot.quaternion.setFromAxisAngle(axis, angle);\n    },\n  };\n}\n\n// ---------------------------------------------------------------------------\n// Scoreboard\n// ---------------------------------------------------------------------------\n\nexport interface ScoreboardOptions {\n  seed?: number;\n  /** Digit count. Default 3. */\n  digits?: number;\n  /** Digit height, metres. Default 0.42. */\n  size?: number;\n  /** Board colour. Default deep green, like the ground's own boards. */\n  color?: number;\n  digitColor?: number;\n}\n\nexport interface Scoreboard {\n  group: Group;\n  /** Show a value (clamped to what the digits can hold). Flips animate. */\n  set(value: number): void;\n  readonly value: number;\n  update(dt: number): void;\n}\n\n/**\n * The vector font's first job with moving parts. Each digit slot flips —\n * the old number rotates away, the new one rotates in — because a board\n * that just swaps text reads as a texture, and one that MOVES reads as a\n * machine somebody built. Ten carved geometries are built once per size\n * and shared by every slot and every board.\n */\nconst digitCache = new Map<number, ReturnType<typeof buildTextGeometry>[]>();\nfunction digitGeometries(size: number) {\n  const key = Math.round(size * 1000);\n  let geoms = digitCache.get(key);\n  if (!geoms) {\n    geoms = Array.from({ length: 10 }, (_, d) =>\n      buildTextGeometry(String(d), { size, depth: size * 0.18 })\n    );\n    digitCache.set(key, geoms);\n  }\n  return geoms;\n}\n\nexport function createScoreboard(options: ScoreboardOptions = {}): Scoreboard {\n  const seed = options.seed ?? 1;\n  const digits = Math.max(options.digits ?? 3, 1);\n  const size = options.size ?? 0.42;\n  const geoms = digitGeometries(size);\n\n  const group = new Group();\n  group.name = 'scoreboard';\n  const slotW = size * 0.95;\n  const boardW = slotW * digits + size * 0.6;\n  const boardH = size * 1.7;\n  const board = new Mesh(\n    new BoxGeometry(boardW, boardH, 0.1),\n    createSurface('paint', { seed, color: options.color ?? 0x18321f })\n  );\n  board.position.y = boardH / 2 + size * 1.2;\n  group.add(board);\n  const postMaterial = createSurface('wood', { seed: seed + 1 });\n  for (const side of [-1, 1]) {\n    const post = new Mesh(\n      new CylinderGeometry(0.05, 0.06, size * 1.3 + boardH * 0.5, 8),\n      postMaterial\n    );\n    post.position.set((side * boardW) / 2.4, (size * 1.3 + boardH * 0.5) / 2, 0);\n    group.add(post);\n  }\n\n  const digitMaterial = createSurface('paint', {\n    seed: seed + 2,\n    color: options.digitColor ?? 0xf2ede0,\n  });\n  interface Slot {\n    holder: Group;\n    mesh: Mesh;\n    showing: number;\n    next: number | null;\n    flip: number; // 0 = at rest; >0 animating\n  }\n  const slots: Slot[] = Array.from({ length: digits }, (_, i) => {\n    const holder = new Group();\n    holder.position.set((i - (digits - 1) / 2) * slotW, board.position.y, 0.08);\n    group.add(holder);\n    const mesh = new Mesh(geoms[0].geometry, digitMaterial);\n    holder.add(mesh);\n    return { holder, mesh, showing: 0, next: null, flip: 0 };\n  });\n\n  let current = 0;\n  const max = 10 ** digits - 1;\n\n  return {\n    group,\n    get value() {\n      return current;\n    },\n    set(value: number) {\n      const v = Number.isFinite(value) ? Math.min(Math.max(Math.round(value), 0), max) : 0;\n      if (v === current) return;\n      current = v;\n      const text = String(v).padStart(digits, '0');\n      slots.forEach((slot, i) => {\n        const digit = Number(text[i]);\n        if (digit !== slot.showing) {\n          slot.next = digit;\n          slot.flip = 1; // restart the flip for this slot\n        }\n      });\n    },\n    update(dt) {\n      const step = Number.isFinite(dt) ? Math.max(dt, 0) : 0;\n      for (const slot of slots) {\n        if (slot.flip <= 0) continue;\n        slot.flip = Math.max(slot.flip - step / 0.28, 0);\n        const w = 1 - slot.flip; // 0 → 1 over the flip\n        // First half: the old digit tips away. Midpoint: swap. Second\n        // half: the new digit tips in from the other side.\n        if (w < 0.5) {\n          slot.holder.rotation.x = -w * Math.PI;\n        } else {\n          if (slot.next !== null) {\n            slot.showing = slot.next;\n            slot.mesh.geometry = geoms[slot.showing].geometry;\n            slot.next = null;\n          }\n          slot.holder.rotation.x = (1 - w) * Math.PI;\n        }\n        if (slot.flip === 0) slot.holder.rotation.x = 0;\n      }\n    },\n  };\n}\n\n// ---------------------------------------------------------------------------\n// Stumps — the cricket retrofit\n// ---------------------------------------------------------------------------\n\nexport interface StumpsOptions {\n  seed?: number;\n  /** Stump height, metres. Default 0.71 (the laws'). */\n  height?: number;\n}\n\nexport interface Stumps {\n  group: Group;\n  trigger: Obstacle;\n  readonly struck: boolean;\n  /**\n   * The ball arrives. Bails FLY (each on its own arc and spin), the hit\n   * stumps lean. `direction` is the ball's travel; `power` scales it.\n   */\n  strike(direction?: { x: number; y?: number; z: number }, power?: number): void;\n  reset(): void;\n  update(dt: number): void;\n}\n\n/**\n * Three stumps, two bails, and the single most satisfying piece of\n * feedback in cricket: the bails coming off. Until now the trilogy's\n * wickets were scenery; these are an event.\n */\nexport function createStumps(options: StumpsOptions = {}): Stumps {\n  const seed = options.seed ?? 1;\n  const rng = new Rng(seed);\n  const height = options.height ?? 0.71;\n\n  const group = new Group();\n  group.name = 'stumps';\n  const wood = createSurface('wood', { seed, color: 0xd9c9a3 });\n  const gap = 0.055;\n\n  const stumps: Mesh[] = [];\n  for (let i = 0; i < 3; i++) {\n    const stump = new Mesh(new CylinderGeometry(0.019, 0.022, height, 8), wood);\n    stump.position.set((i - 1) * gap * 2, height / 2, 0);\n    group.add(stump);\n    stumps.push(stump);\n  }\n\n  const bails: Piece[] = [];\n  for (let i = 0; i < 2; i++) {\n    const bail = new Mesh(new CylinderGeometry(0.012, 0.012, gap * 2 * 0.96, 6), wood);\n    bail.rotation.z = Math.PI / 2;\n    bail.position.set((i === 0 ? -1 : 1) * gap, height + 0.015, 0);\n    group.add(bail);\n    bails.push({\n      mesh: bail,\n      vel: new Vector3(),\n      spin: new Vector3(),\n      home: bail.position.clone(),\n      homeQuat: [bail.quaternion.x, bail.quaternion.y, bail.quaternion.z, bail.quaternion.w],\n      resting: false,\n    });\n  }\n\n  let struck = false;\n  const leans = stumps.map(() => 0);\n  const leanTargets = stumps.map(() => 0);\n\n  const trigger: Obstacle = { center: group.position, radius: 0.18 };\n\n  return {\n    group,\n    trigger,\n    get struck() {\n      return struck;\n    },\n    strike(direction, power = 1) {\n      if (struck) return;\n      struck = true;\n      const p = Math.min(Math.max(power, 0.3), 2);\n      const dir = new Vector3(direction?.x ?? 0, 0, direction?.z ?? 1);\n      if (dir.lengthSq() < 1e-8) dir.set(0, 0, 1);\n      dir.normalize();\n      for (const bail of bails) {\n        // Up first, along the ball second, apart from each other third —\n        // two bails that fly identically read as one drawn twice.\n        bail.vel\n          .copy(dir)\n          .multiplyScalar(p * rng.range(1, 1.8))\n          .add(new Vector3(rng.range(-0.6, 0.6), p * rng.range(2.4, 3.4), rng.range(-0.3, 0.3)));\n        bail.spin.set(rng.range(-14, 14), rng.range(-10, 10), rng.range(-14, 14));\n        bail.resting = false;\n      }\n      // One or two stumps knocked back, seeded.\n      const knocked = rng.int(1, 2);\n      for (let k = 0; k < knocked; k++) {\n        leanTargets[rng.int(0, 2)] = rng.range(0.35, 0.7);\n      }\n    },\n    reset() {\n      struck = false;\n      resetPieces(bails);\n      for (let i = 0; i < stumps.length; i++) {\n        leanTargets[i] = 0;\n        leans[i] = 0;\n        stumps[i].rotation.x = 0;\n      }\n    },\n    update(dt) {\n      if (!struck && bails.every((b) => !b.resting && b.vel.lengthSq() === 0)) return;\n      const step = Number.isFinite(dt) ? Math.min(Math.max(dt, 0), 0.1) : 0;\n      flyPieces(bails, step, 0.012);\n      for (let i = 0; i < stumps.length; i++) {\n        if (Math.abs(leans[i] - leanTargets[i]) < 1e-4) continue;\n        leans[i] += (leanTargets[i] - leans[i]) * Math.min(step * 10, 1);\n        stumps[i].rotation.x = -leans[i];\n        // A leaning stump pivots at its base, not its middle.\n        stumps[i].position.y = (Math.cos(leans[i]) * (stumps[i].geometry as CylinderGeometry).parameters.height) / 2;\n        stumps[i].position.z = (Math.sin(leans[i]) * (stumps[i].geometry as CylinderGeometry).parameters.height) / 2;\n      }\n    },\n  };\n}\n","import {\n  BoxGeometry,\n  CylinderGeometry,\n  Group,\n  IcosahedronGeometry,\n  Mesh,\n  MeshStandardMaterial,\n  PointLight,\n  SphereGeometry,\n} from 'three';\nimport { Rng } from '../core/random';\nimport { DEFAULT_PALETTE, type Palette } from '../core/palette';\nimport { createSurface } from '../materials/surface';\nimport type { Prop } from '../core/types';\n\n/**\n * Trade utilities — the props that give a room a job: a smith's forge, a\n * baker's oven, a weaver's loom, a taverner's counter. Same Prop contract\n * as everything else; `furnishRoom` places them by role.\n */\n\nexport interface WorkshopOptions {\n  seed?: number;\n  /** Forge only: add the real flickering PointLight. Default true. */\n  light?: boolean;\n  palette?: Palette;\n}\n\n/** Glowing-coal material + a flicker driver shared by forge and oven. */\nfunction glowingCoals(\n  group: Group,\n  rng: Rng,\n  count: number,\n  cx: number,\n  cy: number,\n  cz: number,\n  spread: number,\n  light: PointLight | null\n): void {\n  const coalMat = new MeshStandardMaterial({\n    color: 0x1a1008,\n    emissive: 0xff5a1a,\n    emissiveIntensity: 1.7,\n    flatShading: true,\n  });\n  for (let i = 0; i < count; i++) {\n    const coal = new Mesh(new IcosahedronGeometry(rng.range(0.05, 0.09), 0), coalMat);\n    coal.position.set(cx + rng.jitter(0, spread), cy + rng.range(0, 0.05), cz + rng.jitter(0, spread));\n    group.add(coal);\n  }\n  const phase = rng.range(0, 20);\n  const base = light?.intensity ?? 0;\n  group.children[group.children.length - 1].onBeforeRender = () => {\n    const t = performance.now() * 0.001 + phase;\n    const flick = 0.8 + 0.12 * Math.sin(t * 10.0) + 0.08 * Math.sin(t * 21.7 + 1.4);\n    coalMat.emissiveIntensity = 1.7 * flick;\n    if (light) light.intensity = base * flick;\n  };\n}\n\n/** A smith's corner: coal forge, anvil on a stump, quench barrel. */\nexport function createForge(options: WorkshopOptions = {}): Prop {\n  const seed = options.seed ?? 1;\n  const rng = new Rng(seed);\n  const palette = options.palette ?? DEFAULT_PALETTE;\n  const stone = createSurface('stone', { color: palette.rock[0], seed });\n  const metal = new MeshStandardMaterial({ color: palette.metal, flatShading: true, metalness: 0.55, roughness: 0.45 });\n\n  const group = new Group();\n  group.name = 'forge';\n\n  // The coal hearth: a waist-high stone box with a bed of burning coals.\n  const bed = new Mesh(new BoxGeometry(1.0, 0.75, 0.85), stone);\n  bed.position.set(-0.35, 0.375, 0);\n  group.add(bed);\n  const lip = new Mesh(new BoxGeometry(1.08, 0.1, 0.93), stone);\n  lip.position.set(-0.35, 0.78, 0);\n  group.add(lip);\n\n  let light: PointLight | null = null;\n  if (options.light ?? true) {\n    light = new PointLight(0xff7a28, 4, 6, 2);\n    light.position.set(-0.35, 1.1, 0);\n    group.add(light);\n  }\n  glowingCoals(group, rng, 6, -0.35, 0.85, 0, 0.24, light);\n\n  // Anvil on a stump.\n  const stump = new Mesh(new CylinderGeometry(0.2, 0.24, 0.45, 8), createSurface('wood', { color: palette.woodDark, seed: seed + 1 }));\n  stump.position.set(0.55, 0.225, 0.1);\n  group.add(stump);\n  const anvilBody = new Mesh(new BoxGeometry(0.5, 0.14, 0.16), metal);\n  anvilBody.position.set(0.55, 0.53, 0.1);\n  const anvilWaist = new Mesh(new BoxGeometry(0.2, 0.1, 0.12), metal);\n  anvilWaist.position.set(0.55, 0.5 - 0.05, 0.1);\n  const horn = new Mesh(new CylinderGeometry(0.028, 0.06, 0.22, 6), metal);\n  horn.rotation.z = Math.PI / 2 + 0.15;\n  horn.position.set(0.86, 0.55, 0.1);\n  group.add(anvilBody, anvilWaist, horn);\n\n  // Quench barrel.\n  const barrel = new Mesh(new CylinderGeometry(0.19, 0.17, 0.5, 9), createSurface('plank', { color: palette.woodDark, seed: seed + 2 }));\n  barrel.position.set(0.35, 0.25, -0.55);\n  const water = new Mesh(new CylinderGeometry(0.16, 0.16, 0.02, 9), new MeshStandardMaterial({ color: 0x1c2c33, roughness: 0.2 }));\n  water.position.set(0.35, 0.49, -0.55);\n  group.add(barrel, water);\n\n  return { object: group, obstacleRadius: 1.05 };\n}\n\n/** A baker's dome oven: stone dome, ember-lit mouth, chimney stub. */\nexport function createOven(options: WorkshopOptions = {}): Prop {\n  const seed = options.seed ?? 1;\n  const rng = new Rng(seed);\n  const palette = options.palette ?? DEFAULT_PALETTE;\n  const stone = createSurface('stone', { color: palette.rock[1] ?? palette.rock[0], seed });\n  const brick = createSurface('brick', { color: palette.roof, seed: seed + 1 });\n\n  const group = new Group();\n  group.name = 'oven';\n\n  const plinth = new Mesh(new BoxGeometry(1.2, 0.7, 1.0), stone);\n  plinth.position.y = 0.35;\n  group.add(plinth);\n  const dome = new Mesh(new SphereGeometry(0.52, 9, 6), brick);\n  dome.scale.y = 0.72;\n  dome.position.y = 0.72;\n  group.add(dome);\n  const chimney = new Mesh(new BoxGeometry(0.16, 0.5, 0.16), brick);\n  chimney.position.set(0, 1.2, -0.2);\n  group.add(chimney);\n\n  // The glowing mouth: a dark arch with embers inside — faces +z.\n  const mouth = new Mesh(\n    new CylinderGeometry(0.24, 0.24, 0.1, 8, 1, false, Math.PI, Math.PI),\n    new MeshStandardMaterial({ color: 0x140d08, flatShading: true })\n  );\n  mouth.rotation.x = Math.PI / 2;\n  mouth.rotation.y = Math.PI / 2;\n  mouth.position.set(0, 0.74, 0.44);\n  group.add(mouth);\n  glowingCoals(group, rng, 4, 0, 0.72, 0.42, 0.12, null);\n\n  // A peel (baker's paddle) leaning on the side.\n  const peelWood = createSurface('wood', { color: palette.wood, seed: seed + 2 });\n  const handle = new Mesh(new CylinderGeometry(0.02, 0.02, 1.3, 5), peelWood);\n  handle.position.set(0.68, 0.7, 0.1);\n  handle.rotation.z = 0.28;\n  const blade = new Mesh(new BoxGeometry(0.2, 0.02, 0.28), peelWood);\n  blade.position.set(0.5, 0.1, 0.1);\n  group.add(handle, blade);\n\n  return { object: group, obstacleRadius: 0.95 };\n}\n\n/** A weaver's upright loom: frame, warp threads, cloth growing up it. */\nexport function createLoom(options: WorkshopOptions = {}): Prop {\n  const seed = options.seed ?? 1;\n  const rng = new Rng(seed);\n  const palette = options.palette ?? DEFAULT_PALETTE;\n  const wood = createSurface('wood', { color: palette.wood, seed });\n  const dark = createSurface('wood', { color: palette.woodDark, seed: seed + 1 });\n\n  const group = new Group();\n  group.name = 'loom';\n  const W = 1.1;\n  const H = 1.7;\n\n  for (const side of [-1, 1]) {\n    const upright = new Mesh(new BoxGeometry(0.08, H, 0.1), dark);\n    upright.position.set(side * W / 2, H / 2, 0);\n    upright.rotation.x = -0.14;\n    group.add(upright);\n    const foot = new Mesh(new BoxGeometry(0.09, 0.07, 0.5), dark);\n    foot.position.set(side * W / 2, 0.035, 0.05);\n    group.add(foot);\n  }\n  for (const y of [H - 0.08, 0.35]) {\n    const beam = new Mesh(new CylinderGeometry(0.05, 0.05, W + 0.1, 7), wood);\n    beam.rotation.z = Math.PI / 2;\n    beam.position.set(0, y, (H / 2 - y) * 0.14);\n    group.add(beam);\n  }\n  // Warp threads.\n  const thread = new MeshStandardMaterial({ color: 0xe8dfc8, flatShading: true });\n  const n = 9;\n  for (let i = 0; i < n; i++) {\n    const x = -W / 2 + 0.12 + (i / (n - 1)) * (W - 0.24);\n    const t = new Mesh(new BoxGeometry(0.012, H - 0.5, 0.012), thread);\n    t.position.set(x, (H - 0.5) / 2 + 0.35, (H / 2 - ((H - 0.5) / 2 + 0.35)) * 0.14);\n    t.rotation.x = -0.14;\n    group.add(t);\n  }\n  // The woven cloth climbing the lower half, dyed from the palette.\n  const cloth = new Mesh(\n    new BoxGeometry(W - 0.2, 0.55, 0.03),\n    createSurface('canvas', { color: rng.pick([palette.roof, palette.water, palette.sand]), seed: seed + 2 })\n  );\n  cloth.position.set(0, 0.66, (H / 2 - 0.66) * 0.14 + 0.012);\n  cloth.rotation.x = -0.14;\n  group.add(cloth);\n\n  return { object: group, obstacleRadius: 0.68 };\n}\n\n/** A taverner's counter: paneled bar with mugs and a jug on top. */\nexport function createCounter(options: WorkshopOptions = {}): Prop {\n  const seed = options.seed ?? 1;\n  const rng = new Rng(seed);\n  const palette = options.palette ?? DEFAULT_PALETTE;\n  const top = createSurface('plank', { color: palette.wood, seed });\n  const panel = createSurface('wood', { color: palette.woodDark, seed: seed + 1 });\n\n  const group = new Group();\n  group.name = 'counter';\n  const L = 2.2;\n  const H = 1.0;\n\n  const base = new Mesh(new BoxGeometry(L - 0.15, H - 0.08, 0.5), panel);\n  base.position.y = (H - 0.08) / 2;\n  group.add(base);\n  const slab = new Mesh(new BoxGeometry(L, 0.08, 0.68), top);\n  slab.position.y = H - 0.04;\n  group.add(slab);\n  const rail = new Mesh(new CylinderGeometry(0.025, 0.025, L - 0.3, 6), panel);\n  rail.rotation.z = Math.PI / 2;\n  rail.position.set(0, 0.16, 0.32);\n  group.add(rail);\n\n  // Mugs and a jug along the top.\n  const glaze = new MeshStandardMaterial({ color: palette.path, flatShading: true });\n  const mugs = rng.int(2, 4);\n  for (let i = 0; i < mugs; i++) {\n    const mug = new Mesh(new CylinderGeometry(0.045, 0.05, 0.1, 7), glaze);\n    mug.position.set(rng.range(-L / 2 + 0.3, L / 2 - 0.3), H + 0.05, rng.jitter(0, 0.16));\n    group.add(mug);\n  }\n  const jug = new Mesh(\n    new CylinderGeometry(0.06, 0.1, 0.24, 8),\n    createSurface('terracotta', { seed: seed + 3 })\n  );\n  jug.position.set(rng.range(-L / 2 + 0.3, L / 2 - 0.3), H + 0.12, 0);\n  group.add(jug);\n\n  return { object: group, obstacleRadius: 1.15 };\n}\n","import {\n  BoxGeometry,\n  CylinderGeometry,\n  Group,\n  InstancedMesh,\n  Matrix4,\n  Mesh,\n  MeshStandardMaterial,\n  TorusGeometry,\n} from 'three';\nimport { DEFAULT_PALETTE, type Palette } from '../core/palette';\nimport { createSurface } from '../materials/surface';\nimport { createSlot } from '../core/types';\nimport type { Prop } from '../core/types';\n\n/**\n * Interaction stations — props built to be USED. Each publishes `slots`\n * (the ANIMA-compatible handshake) and conforms to ANIMA's GRIPS geometry:\n * seat surfaces at 0.45, anchors at floor level facing +z.\n */\n\nconst slot = createSlot;\n\n// ---- treadmill ---------------------------------------------------------\n\nexport interface TreadmillOptions {\n  seed?: number;\n  /** Belt speed in m/s — feed the same number to the runner's Locomotion. */\n  speed?: number;\n  palette?: Palette;\n}\n\nexport interface TreadmillProp extends Prop {\n  /** Current belt speed (m/s). */\n  speed: number;\n  /** Change the belt speed; the tread bars follow. */\n  setSpeed(speed: number): void;\n}\n\n/**\n * A gym treadmill with a genuinely moving belt — instanced tread bars\n * marching toward the runner. Stand a character on the `run` slot and\n * drive its `Locomotion` with `treadmill.speed`: running without going\n * anywhere, which is the whole idea.\n */\nexport function createTreadmill(options: TreadmillOptions = {}): TreadmillProp {\n  const seed = options.seed ?? 1;\n  const palette = options.palette ?? DEFAULT_PALETTE;\n  let speed = options.speed ?? 2.4;\n\n  const group = new Group();\n  group.name = 'treadmill';\n  const coat = createSurface('paintedMetal', { color: palette.metal, seed });\n  const steel = createSurface('steel', { seed: seed + 1 });\n\n  const DECK_L = 1.7;\n  const DECK_W = 0.72;\n  const deck = new Mesh(new BoxGeometry(DECK_W, 0.14, DECK_L), coat);\n  deck.position.set(0, 0.09, 0.1);\n  group.add(deck);\n\n  // The belt: tread bars that march (looping along the deck).\n  const BARS = 12;\n  const bars = new InstancedMesh(\n    new BoxGeometry(DECK_W - 0.12, 0.022, 0.09),\n    new MeshStandardMaterial({ color: 0x1d2126, roughness: 0.85 }),\n    BARS\n  );\n  group.add(bars);\n  const matrix = new Matrix4();\n  let scroll = 0;\n  bars.onBeforeRender = () => {\n    const now = performance.now() * 0.001;\n    scroll = (now * speed) % 1;\n    for (let i = 0; i < BARS; i++) {\n      const t = (i / BARS + scroll / (DECK_L - 0.2)) % 1;\n      matrix.makeTranslation(0, 0.172, 0.1 + (DECK_L - 0.2) * (t - 0.5));\n      bars.setMatrixAt(i, matrix);\n    }\n    bars.instanceMatrix.needsUpdate = true;\n  };\n  bars.frustumCulled = false;\n\n  // Uprights, handrails, console.\n  for (const side of [-1, 1]) {\n    const upright = new Mesh(new BoxGeometry(0.06, 1.15, 0.06), steel);\n    upright.position.set(side * (DECK_W / 2 - 0.03), 0.58, -0.62);\n    upright.rotation.x = 0.18;\n    group.add(upright);\n    const rail = new Mesh(new CylinderGeometry(0.022, 0.022, 0.7, 6), steel);\n    rail.rotation.x = Math.PI / 2;\n    rail.position.set(side * (DECK_W / 2 - 0.03), 1.08, -0.32);\n    group.add(rail);\n  }\n  const console_ = new Mesh(new BoxGeometry(0.56, 0.3, 0.08), coat);\n  console_.position.set(0, 1.24, -0.66);\n  console_.rotation.x = -0.5;\n  group.add(console_);\n  const screen = new Mesh(\n    new BoxGeometry(0.3, 0.16, 0.02),\n    new MeshStandardMaterial({ color: 0x223540, emissive: 0x3fd6c0, emissiveIntensity: 0.7 })\n  );\n  screen.position.set(0, 1.27, -0.62);\n  screen.rotation.x = -0.5;\n  group.add(screen);\n\n  // The runner faces the console (-z), standing mid-deck.\n  const runSlot = slot('run', 'run', group, 0, 0.19, 0.25, Math.PI);\n\n  return {\n    object: group,\n    obstacleRadius: 0.95,\n    slots: [runSlot],\n    get speed() {\n      return speed;\n    },\n    setSpeed(s: number) {\n      speed = Math.max(0, s);\n    },\n  } as TreadmillProp;\n}\n\n// ---- guitar ------------------------------------------------------------\n\nexport interface GuitarOptions {\n  seed?: number;\n  /** Body finish. Default warm 'teak'; try palette colors for electrics. */\n  color?: number;\n  palette?: Palette;\n}\n\n/**\n * An acoustic guitar, origin at the body's centre, neck up +y — sized to\n * ANIMA's GRIPS.guitar so it sits right across a strumming character's\n * chest (position it there and add the `strum` loop), or lean it on a\n * wall/stand as décor.\n */\nexport function createGuitar(options: GuitarOptions = {}): Prop {\n  const seed = options.seed ?? 1;\n  const wood = createSurface('teak', { color: options.color, seed });\n  const dark = new MeshStandardMaterial({ color: 0x2a1c12, flatShading: true });\n\n  const group = new Group();\n  group.name = 'guitar';\n  const lower = new Mesh(new CylinderGeometry(0.19, 0.19, 0.07, 12), wood);\n  lower.rotation.x = Math.PI / 2;\n  lower.position.y = -0.05;\n  const upper = new Mesh(new CylinderGeometry(0.145, 0.145, 0.07, 12), wood);\n  upper.rotation.x = Math.PI / 2;\n  upper.position.y = 0.14;\n  const hole = new Mesh(new CylinderGeometry(0.055, 0.055, 0.075, 10), dark);\n  hole.rotation.x = Math.PI / 2;\n  hole.position.y = 0.05;\n  group.add(lower, upper, hole);\n  const neck = new Mesh(new BoxGeometry(0.05, 0.5, 0.03), dark);\n  neck.position.set(0, 0.42, -0.005);\n  group.add(neck);\n  const head = new Mesh(new BoxGeometry(0.07, 0.12, 0.025), wood);\n  head.position.set(0, 0.72, -0.005);\n  group.add(head);\n  const bridge = new Mesh(new BoxGeometry(0.12, 0.02, 0.02), dark);\n  bridge.position.set(0, -0.12, 0.035);\n  group.add(bridge);\n  // Strings: one thin bright box reads as the course of six.\n  const strings = new Mesh(\n    new BoxGeometry(0.045, 0.84, 0.004),\n    new MeshStandardMaterial({ color: 0xd8d2c0, metalness: 0.6, roughness: 0.3 })\n  );\n  strings.position.set(0, 0.28, 0.042);\n  group.add(strings);\n\n  return { object: group, obstacleRadius: 0 };\n}\n\n// ---- bathroom set ------------------------------------------------------\n\nexport interface BathroomOptions {\n  seed?: number;\n  palette?: Palette;\n}\n\n/** A ceramic toilet: pedestal, bowl, seat at sit height, tank. */\nexport function createToilet(options: BathroomOptions = {}): Prop {\n  const seed = options.seed ?? 1;\n  const ceramic = createSurface('paint', { color: 0xeceae4, seed });\n  const group = new Group();\n  group.name = 'toilet';\n\n  const pedestal = new Mesh(new BoxGeometry(0.3, 0.34, 0.34), ceramic);\n  pedestal.position.set(0, 0.17, -0.04);\n  const bowl = new Mesh(new CylinderGeometry(0.2, 0.15, 0.16, 10), ceramic);\n  bowl.position.set(0, 0.35, 0.02);\n  const seat = new Mesh(new TorusGeometry(0.16, 0.045, 6, 12), ceramic);\n  seat.rotation.x = Math.PI / 2;\n  seat.position.set(0, 0.44, 0.02);\n  const tank = new Mesh(new BoxGeometry(0.4, 0.36, 0.14), ceramic);\n  tank.position.set(0, 0.62, -0.24);\n  const lid = new Mesh(new BoxGeometry(0.42, 0.04, 0.16), ceramic);\n  lid.position.set(0, 0.82, -0.24);\n  group.add(pedestal, bowl, seat, tank, lid);\n\n  const sitSlot = slot('sit', 'sit', group, 0, 0, 0.06);\n  return { object: group, obstacleRadius: 0.35, slots: [sitSlot] };\n}\n\n/** A pedestal sink with a chrome tap. */\nexport function createSink(options: BathroomOptions = {}): Prop {\n  const seed = options.seed ?? 1;\n  const ceramic = createSurface('paint', { color: 0xeceae4, seed });\n  const chrome = createSurface('chrome', { seed: seed + 1 });\n  const group = new Group();\n  group.name = 'sink';\n\n  const column = new Mesh(new BoxGeometry(0.16, 0.78, 0.16), ceramic);\n  column.position.y = 0.39;\n  const basin = new Mesh(new CylinderGeometry(0.24, 0.17, 0.14, 10), ceramic);\n  basin.position.y = 0.84;\n  group.add(column, basin);\n  const tap = new Mesh(new BoxGeometry(0.035, 0.14, 0.035), chrome);\n  tap.position.set(0, 0.97, -0.17);\n  const spout = new Mesh(new BoxGeometry(0.035, 0.035, 0.12), chrome);\n  spout.position.set(0, 1.03, -0.12);\n  group.add(tap, spout);\n\n  return { object: group, obstacleRadius: 0.3 };\n}\n\n/** A freestanding bathtub on feet — with a `soak` slot (the sleep pose). */\nexport function createBathtub(options: BathroomOptions = {}): Prop {\n  const seed = options.seed ?? 1;\n  const palette = options.palette ?? DEFAULT_PALETTE;\n  const ceramic = createSurface('paint', { color: 0xeceae4, seed });\n  const group = new Group();\n  group.name = 'bathtub';\n\n  const shell = new Mesh(new BoxGeometry(0.74, 0.52, 1.62), ceramic);\n  shell.position.y = 0.36;\n  const rim = new Mesh(new BoxGeometry(0.82, 0.07, 1.7), ceramic);\n  rim.position.y = 0.62;\n  const inner = new Mesh(\n    new BoxGeometry(0.6, 0.06, 1.46),\n    new MeshStandardMaterial({ color: 0x9fc9d8, roughness: 0.15 }) // still water\n  );\n  inner.position.y = 0.56;\n  group.add(shell, rim, inner);\n  for (const sx of [-1, 1]) {\n    for (const sz of [-1, 1]) {\n      const foot = new Mesh(new BoxGeometry(0.09, 0.12, 0.09), createSurface('brass', { seed: seed + 2, color: palette.metal }));\n      foot.position.set(sx * 0.28, 0.05, sz * 0.68);\n      group.add(foot);\n    }\n  }\n\n  // Soaking = the sleep pose, reclined into the tub (anchor pitched flat,\n  // body extending along -z toward the head end).\n  const soak = slot('soak', 'sleep', group, 0, 0.62, 0.6, 0, -Math.PI / 2);\n  return { object: group, obstacleRadius: 0.95, slots: [soak] };\n}\n","import {\n  BoxGeometry,\n  CylinderGeometry,\n  Group,\n  Mesh,\n  MeshStandardMaterial,\n  Object3D,\n  TorusGeometry,\n  type Material,\n} from 'three';\nimport { Rng } from '../core/random';\nimport { DEFAULT_PALETTE, type Palette } from '../core/palette';\nimport { createSurface } from '../materials/surface';\nimport { sharedBy } from '../materials/shared';\nimport { createGlass } from '../materials/glass';\nimport { createSlot } from '../core/types';\nimport type { Prop } from '../core/types';\n\n/**\n * Land vehicles — low-poly, palette-themed, and ALIVE: every vehicle\n * exposes a kinematic `update(dt, { speed, steer })` that spins the wheels\n * radius-correctly, turns the fronts and twirls the steering wheel, plus\n * GRIPS-conformant `slots` so an ANIMA character drops into the driver's\n * seat with the `drive` (or `cycle`) pose and their hands land on the\n * controls by construction. GAMA steering output plugs straight in:\n * speed from `agent.velocity.length()`, steer from the heading change.\n */\n\nexport interface VehicleInput {\n  /** Ground speed in m/s (wheels spin to match). */\n  speed?: number;\n  /** Steering angle in radians (front wheels + steering wheel follow). */\n  steer?: number;\n}\n\nexport interface VehicleProp extends Prop {\n  /** Advance the running gear. Call from your game loop when it moves. */\n  update(dt: number, input?: VehicleInput): void;\n}\n\nexport interface VehicleOptions {\n  seed?: number;\n  /** Body colour. Defaults to a seeded pick from the palette. */\n  color?: number;\n  palette?: Palette;\n}\n\ninterface Wheel {\n  node: Object3D;\n  radius: number;\n  steers: boolean;\n}\n\n/** Tire rubber. One per vehicle, shared by all of its wheels. */\nconst tireRubber = (): MeshStandardMaterial =>\n  new MeshStandardMaterial({ color: 0x1d2126, roughness: 0.9 });\n\n/** A lamp lens, keyed on its colour so a pair of headlamps is one material. */\nconst lampMaterial = (lit: number): MeshStandardMaterial =>\n  new MeshStandardMaterial({ color: lit, emissive: lit, emissiveIntensity: 0.5 });\n\n/** A tire + hub on a spin pivot, axle along local x. */\nfunction makeWheel(\n  radius: number,\n  width: number,\n  seed: number,\n  rubber: Material\n): { pivot: Object3D; spin: Object3D } {\n  const pivot = new Object3D(); // yaw pivot (steering)\n  const spin = new Object3D(); // roll pivot (speed)\n  pivot.add(spin);\n  // The rubber comes in from the vehicle, one for all four wheels. Built here\n  // it was four identical materials per car — see `npm run geometry`.\n  const tire = new Mesh(new TorusGeometry(radius * 0.78, radius * 0.24, 6, 12), rubber);\n  tire.rotation.y = Math.PI / 2;\n  const hub = new Mesh(\n    new CylinderGeometry(radius * 0.55, radius * 0.55, width, 8),\n    createSurface('steel', { seed })\n  );\n  hub.rotation.z = Math.PI / 2;\n  spin.add(tire, hub);\n  return { pivot, spin };\n}\n\n/** Wire the shared running-gear update. */\nfunction running(\n  wheels: Wheel[],\n  spins: Object3D[],\n  steeringWheel: Object3D | null\n): VehicleProp['update'] {\n  return (dt, input = {}) => {\n    const speed = input.speed ?? 0;\n    const steer = Math.max(-0.6, Math.min(0.6, input.steer ?? 0));\n    wheels.forEach((wheel, i) => {\n      spins[i].rotation.x += (speed / wheel.radius) * dt;\n      if (wheel.steers) wheel.node.rotation.y = steer;\n    });\n    if (steeringWheel) steeringWheel.rotation.z = -steer * 2.2;\n  };\n}\n\n/** A compact modern car: powder-coat body, glass cabin, driver's slot. */\nexport function createCar(options: VehicleOptions = {}): VehicleProp {\n  const seed = options.seed ?? 1;\n  const rng = new Rng(seed);\n  const palette = options.palette ?? DEFAULT_PALETTE;\n  const lampGlow = sharedBy(lampMaterial);\n  const bodyColor = options.color ?? rng.pick([0xb8433a, 0x3a6ea5, 0x3f7f5c, 0xd8d5cc, palette.metal]);\n  const body = createSurface('paintedMetal', { color: bodyColor, seed });\n  const trim = new MeshStandardMaterial({ color: 0x22262b, flatShading: true });\n  const glass = createGlass({ tint: 0x9fb8c8 });\n\n  const group = new Group();\n  group.name = 'car';\n  const chassis = new Mesh(new BoxGeometry(1.8, 0.52, 4.0), body);\n  chassis.position.y = 0.62;\n  const nose = new Mesh(new BoxGeometry(1.7, 0.3, 0.9), body);\n  nose.position.set(0, 0.98, 1.5);\n  const cabin = new Mesh(new BoxGeometry(1.62, 0.56, 2.1), body);\n  cabin.position.set(0, 1.14, -0.35);\n  group.add(chassis, nose, cabin);\n  const windshield = new Mesh(new BoxGeometry(1.5, 0.5, 0.06), glass);\n  windshield.position.set(0, 1.16, 0.72);\n  windshield.rotation.x = -0.42;\n  const rear = windshield.clone();\n  rear.position.set(0, 1.16, -1.42);\n  rear.rotation.x = 0.42;\n  group.add(windshield, rear);\n  for (const side of [-1, 1]) {\n    const pane = new Mesh(new BoxGeometry(0.05, 0.42, 1.9), glass);\n    pane.position.set(side * 0.82, 1.18, -0.35);\n    group.add(pane);\n    for (const [z, lit] of [[1.95, 0xfff2cc], [-1.95, 0xd8402a]] as const) {\n      // Keyed on the colour: a car has two headlamps and two tail lamps, and\n      // that is two materials, not four.\n      const lamp = new Mesh(new BoxGeometry(0.3, 0.12, 0.06), lampGlow(lit));\n      lamp.position.set(side * 0.6, 0.78, z);\n      group.add(lamp);\n    }\n  }\n  const bumperF = new Mesh(new BoxGeometry(1.84, 0.16, 0.2), trim);\n  bumperF.position.set(0, 0.44, 2.0);\n  const bumperR = bumperF.clone();\n  bumperR.position.z = -2.0;\n  group.add(bumperF, bumperR);\n\n  const rubber = tireRubber();\n  const wheels: Wheel[] = [];\n  const spins: Object3D[] = [];\n  const R = 0.34;\n  for (const [x, z, steers] of [[-0.86, 1.32, true], [0.86, 1.32, true], [-0.86, -1.32, false], [0.86, -1.32, false]] as const) {\n    const { pivot, spin } = makeWheel(R, 0.16, seed + wheels.length, rubber);\n    pivot.position.set(x, R, z);\n    group.add(pivot);\n    wheels.push({ node: pivot, radius: R, steers });\n    spins.push(spin);\n  }\n\n  // Driver's seat + the standard wheel at ANIMA's GRIPS offsets.\n  const driver = createSlot('driver', 'drive', group, -0.42, 0.12, -0.15);\n  const passenger = createSlot('passenger', 'sit', group, 0.42, 0.12, -0.15);\n  const wheelMesh = new Mesh(new TorusGeometry(0.19, 0.025, 6, 12), trim);\n  const column = new Object3D();\n  column.position.set(-0.42, 0.12 + 0.75, -0.15 + 0.45);\n  column.rotation.x = -0.5;\n  column.add(wheelMesh);\n  group.add(column);\n\n  return {\n    object: group,\n    obstacleRadius: 2.2,\n    slots: [driver, passenger],\n    update: running(wheels, spins, wheelMesh),\n  };\n}\n\n/** A bicycle: frame, saddle at GRIPS height, handlebar, cranking pedals. */\nexport function createBike(options: VehicleOptions = {}): VehicleProp {\n  const seed = options.seed ?? 1;\n  const frame = createSurface('paintedMetal', { color: options.color ?? 0xc24d38, seed });\n  const dark = new MeshStandardMaterial({ color: 0x22262b, flatShading: true });\n\n  const group = new Group();\n  group.name = 'bike';\n  const R = 0.34;\n  const tube = (x1: number, y1: number, z1: number, y2: number, z2: number): void => {\n    const length = Math.hypot(y2 - y1, z2 - z1);\n    const bar = new Mesh(new CylinderGeometry(0.022, 0.022, length, 6), frame);\n    bar.position.set(x1, (y1 + y2) / 2, (z1 + z2) / 2);\n    bar.rotation.x = Math.atan2(z2 - z1, y2 - y1);\n    group.add(bar);\n  };\n  tube(0, R, 0.62, 0.72, 0.5); //   head tube line\n  tube(0, 0.68, 0.48, 0.42, -0.12); // top tube (sloped)\n  tube(0, R, -0.62, 0.75, -0.55); // seat stay\n  tube(0, 0.36, -0.05, 0.75, -0.55); // seat tube\n  tube(0, R, 0.62, 0.36, -0.05); // down tube\n\n  const saddle = new Mesh(new BoxGeometry(0.24, 0.05, 0.3), dark);\n  saddle.position.set(0, 0.8, -0.55); // GRIPS.saddleHeight\n  group.add(saddle);\n  const bars = new Mesh(new CylinderGeometry(0.018, 0.018, 0.5, 6), dark);\n  bars.rotation.z = Math.PI / 2;\n  bars.position.set(0, 1.0, 0.45); // GRIPS.handlebar\n  group.add(bars);\n\n  const rubber = tireRubber();\n  const wheels: Wheel[] = [];\n  const spins: Object3D[] = [];\n  for (const [z, steers] of [[0.62, true], [-0.62, false]] as const) {\n    const { pivot, spin } = makeWheel(R, 0.05, seed + wheels.length, rubber);\n    pivot.position.set(0, R, z);\n    group.add(pivot);\n    wheels.push({ node: pivot, radius: R, steers });\n    spins.push(spin);\n  }\n  // Pedal cranks, geared to the wheels (roughly 1:2).\n  const crank = new Object3D();\n  crank.position.set(0, 0.36, -0.05);\n  for (const s of [-1, 1]) {\n    const pedal = new Mesh(new BoxGeometry(0.1, 0.03, 0.14), dark);\n    pedal.position.set(s * 0.14, s * 0.16, 0);\n    crank.add(pedal);\n  }\n  group.add(crank);\n\n  const rider = createSlot('rider', 'cycle', group, 0, 0.05, -0.5);\n  const base = running(wheels, spins, null);\n  return {\n    object: group,\n    obstacleRadius: 0.85,\n    slots: [rider],\n    update: (dt, input = {}) => {\n      base(dt, input);\n      crank.rotation.x += ((input.speed ?? 0) / 0.34) * 0.5 * dt;\n      // The bike leans gently into a steer.\n      group.rotation.z = -(input.steer ?? 0) * 0.25;\n    },\n  };\n}\n\n/** A farm tractor: big rears, small steering fronts, open perch, stack. */\nexport function createTractor(options: VehicleOptions = {}): VehicleProp {\n  const seed = options.seed ?? 1;\n  const body = createSurface('paintedMetal', { color: options.color ?? 0x3f7f3a, seed });\n  const trim = new MeshStandardMaterial({ color: 0x22262b, flatShading: true });\n\n  const group = new Group();\n  group.name = 'tractor';\n  const hull = new Mesh(new BoxGeometry(1.1, 0.7, 2.6), body);\n  hull.position.set(0, 0.85, 0.2);\n  const hood = new Mesh(new BoxGeometry(0.86, 0.5, 1.3), body);\n  hood.position.set(0, 1.25, 0.85);\n  group.add(hull, hood);\n  const stack = new Mesh(new CylinderGeometry(0.05, 0.05, 0.7, 6), trim);\n  stack.position.set(0.28, 1.8, 1.2);\n  group.add(stack);\n  const arch = new Mesh(new BoxGeometry(1.3, 0.12, 0.12), body);\n  arch.position.set(0, 1.9, -0.9);\n  group.add(arch);\n  for (const side of [-1, 1]) {\n    const post = new Mesh(new BoxGeometry(0.08, 1.0, 0.08), trim);\n    post.position.set(side * 0.6, 1.45, -0.9);\n    group.add(post);\n  }\n\n  const rubber = tireRubber();\n  const wheels: Wheel[] = [];\n  const spins: Object3D[] = [];\n  for (const [x, z, radius, steers] of [\n    [-0.62, 1.05, 0.36, true], [0.62, 1.05, 0.36, true],\n    [-0.72, -0.75, 0.68, false], [0.72, -0.75, 0.68, false],\n  ] as const) {\n    const { pivot, spin } = makeWheel(radius, radius * 0.5, seed + wheels.length, rubber);\n    pivot.position.set(x, radius, z);\n    group.add(pivot);\n    wheels.push({ node: pivot, radius, steers });\n    spins.push(spin);\n  }\n\n  const driver = createSlot('driver', 'drive', group, 0, 0.75, -0.55);\n  const wheelMesh = new Mesh(new TorusGeometry(0.19, 0.025, 6, 12), trim);\n  const column = new Object3D();\n  column.position.set(0, 1.5, -0.1);\n  column.rotation.x = -0.6;\n  column.add(wheelMesh);\n  group.add(column);\n\n  return {\n    object: group,\n    obstacleRadius: 1.7,\n    slots: [driver],\n    update: running(wheels, spins, wheelMesh),\n  };\n}\n\n/** A box truck: cab, cargo box, six wheels, driver's slot up front. */\nexport function createTruck(options: VehicleOptions = {}): VehicleProp {\n  const seed = options.seed ?? 1;\n  const cabPaint = createSurface('paintedMetal', { color: options.color ?? 0x3a6ea5, seed });\n  const boxPaint = createSurface('paint', { color: 0xdcd9d0, seed: seed + 1 });\n  const trim = new MeshStandardMaterial({ color: 0x22262b, flatShading: true });\n  const glass = createGlass({ tint: 0x9fb8c8 });\n\n  const group = new Group();\n  group.name = 'truck';\n  const cab = new Mesh(new BoxGeometry(2.0, 1.3, 1.7), cabPaint);\n  cab.position.set(0, 1.25, 2.2);\n  group.add(cab);\n  const windshield = new Mesh(new BoxGeometry(1.8, 0.6, 0.06), glass);\n  windshield.position.set(0, 1.5, 3.06);\n  windshield.rotation.x = -0.15;\n  group.add(windshield);\n  const cargo = new Mesh(new BoxGeometry(2.2, 2.0, 4.2), boxPaint);\n  cargo.position.set(0, 1.65, -0.9);\n  group.add(cargo);\n  const frameRail = new Mesh(new BoxGeometry(2.0, 0.2, 6.4), trim);\n  frameRail.position.set(0, 0.6, 0.2);\n  group.add(frameRail);\n\n  const rubber = tireRubber();\n  const wheels: Wheel[] = [];\n  const spins: Object3D[] = [];\n  const R = 0.42;\n  for (const [x, z, steers] of [\n    [-1.0, 2.3, true], [1.0, 2.3, true],\n    [-1.0, -0.4, false], [1.0, -0.4, false],\n    [-1.0, -1.6, false], [1.0, -1.6, false],\n  ] as const) {\n    const { pivot, spin } = makeWheel(R, 0.24, seed + wheels.length, rubber);\n    pivot.position.set(x, R, z);\n    group.add(pivot);\n    wheels.push({ node: pivot, radius: R, steers });\n    spins.push(spin);\n  }\n\n  const driver = createSlot('driver', 'drive', group, -0.55, 0.68, 2.0);\n  const wheelMesh = new Mesh(new TorusGeometry(0.19, 0.025, 6, 12), trim);\n  const column = new Object3D();\n  column.position.set(-0.55, 1.43, 2.45);\n  column.rotation.x = -0.55;\n  column.add(wheelMesh);\n  group.add(column);\n\n  return {\n    object: group,\n    obstacleRadius: 3.4,\n    slots: [driver],\n    update: running(wheels, spins, wheelMesh),\n  };\n}\n","import {\n  BoxGeometry,\n  CylinderGeometry,\n  Group,\n  Mesh,\n  MeshStandardMaterial,\n} from 'three';\nimport { DEFAULT_PALETTE, type Palette } from '../core/palette';\nimport { createSurface } from '../materials/surface';\nimport { createSlot } from '../core/types';\nimport { createRailing } from './modern';\nimport type { Prop } from '../core/types';\n\n/**\n * Watercraft — hulls that genuinely ride the sea. `float(heightAt)` binds a\n * water sampler (`createOcean(...).heightAt` or `createWater`'s level) and\n * `update(dt, { speed })` bobs, pitches and rolls the hull on the waves\n * under it while it makes way. Helm slots seat an ANIMA character.\n */\n\nexport interface CraftInput {\n  /** Way through the water, m/s. */\n  speed?: number;\n}\n\nexport interface CraftProp extends Prop {\n  /** Bind the water: a sampler like `ocean.heightAt(x, z)`. */\n  float(heightAt: (x: number, z: number) => number): void;\n  /** Ride the waves + advance. Call from the game loop. */\n  update(dt: number, input?: CraftInput): void;\n}\n\nexport interface CraftOptions {\n  seed?: number;\n  color?: number;\n  palette?: Palette;\n}\n\n/** Shared wave-riding: sample bow/stern/beam, set height, pitch and roll. */\nfunction floating(group: Group, length: number, beam: number, draft: number): Pick<CraftProp, 'float' | 'update'> {\n  let sampler: ((x: number, z: number) => number) | null = null;\n  return {\n    float(heightAt) {\n      sampler = heightAt;\n    },\n    update() {\n      if (!sampler) return;\n      const { x, z } = group.position;\n      const sin = Math.sin(group.rotation.y);\n      const cos = Math.cos(group.rotation.y);\n      const bow = sampler(x + sin * length * 0.4, z + cos * length * 0.4);\n      const stern = sampler(x - sin * length * 0.4, z - cos * length * 0.4);\n      const port = sampler(x - cos * beam * 0.5, z + sin * beam * 0.5);\n      const starboard = sampler(x + cos * beam * 0.5, z - sin * beam * 0.5);\n      group.position.y = (bow + stern + port + starboard) / 4 - draft;\n      group.rotation.x = Math.atan2(stern - bow, length * 0.8) * 0.9;\n      group.rotation.z = Math.atan2(port - starboard, beam) * 0.8;\n    },\n  };\n}\n\n/** An open motor boat: planked hull, bench seats, outboard, helm slot. */\nexport function createBoat(options: CraftOptions = {}): CraftProp {\n  const seed = options.seed ?? 1;\n  const palette = options.palette ?? DEFAULT_PALETTE;\n  const hullPaint = createSurface('paintedMetal', { color: options.color ?? 0x2f6d8c, seed });\n  const deck = createSurface('plank', { color: palette.wood, seed: seed + 1 });\n\n  const group = new Group();\n  group.name = 'boat';\n  const L = 3.4;\n  const hull = new Mesh(new BoxGeometry(1.3, 0.55, L), hullPaint);\n  hull.position.y = 0.28;\n  const bow = new Mesh(new BoxGeometry(0.9, 0.5, 0.8), hullPaint);\n  bow.position.set(0, 0.33, L / 2 + 0.25);\n  bow.rotation.x = 0.25;\n  const sole = new Mesh(new BoxGeometry(1.1, 0.06, L - 0.3), deck);\n  sole.position.y = 0.58;\n  group.add(hull, bow, sole);\n  for (const z of [0.5, -0.5]) {\n    const bench = new Mesh(new BoxGeometry(1.1, 0.07, 0.3), deck);\n    bench.position.set(0, 0.62 + 0.45 - 0.45, z); // thwart at GRIPS seat height above sole\n    bench.position.y = 0.62;\n    group.add(bench);\n  }\n  const outboard = new Mesh(new BoxGeometry(0.24, 0.5, 0.2), new MeshStandardMaterial({ color: 0x22262b, flatShading: true }));\n  outboard.position.set(0, 0.62, -L / 2 - 0.08);\n  group.add(outboard);\n\n  // The helm: seated at the stern bench, hand on the tiller.\n  const helm = createSlot('helm', 'sit', group, 0, 0.17, -0.5, Math.PI);\n  const rider = createSlot('passenger', 'sit', group, 0, 0.17, 0.5);\n  const base = floating(group, L, 1.3, 0.12);\n  return { object: group, obstacleRadius: 2.0, slots: [helm, rider], ...base };\n}\n\n/** A small coastal ship: high hull, deckhouse, mast, railed deck. */\nexport function createShip(options: CraftOptions = {}): CraftProp {\n  const seed = options.seed ?? 1;\n  const palette = options.palette ?? DEFAULT_PALETTE;\n  const hullPaint = createSurface('paintedMetal', { color: options.color ?? 0x8c3b32, seed });\n  const white = createSurface('paint', { color: 0xe8e5dc, seed: seed + 1 });\n  const deck = createSurface('plank', { color: palette.wood, seed: seed + 2 });\n\n  const group = new Group();\n  group.name = 'ship';\n  const L = 11;\n  const hull = new Mesh(new BoxGeometry(3.4, 1.7, L), hullPaint);\n  hull.position.y = 0.8;\n  const bow = new Mesh(new BoxGeometry(2.2, 1.5, 2.2), hullPaint);\n  bow.position.set(0, 0.9, L / 2 + 0.7);\n  bow.rotation.y = Math.PI / 4;\n  const deckPlate = new Mesh(new BoxGeometry(3.3, 0.1, L - 0.2), deck);\n  deckPlate.position.y = 1.7;\n  group.add(hull, bow, deckPlate);\n  const house = new Mesh(new BoxGeometry(2.4, 1.5, 3.2), white);\n  house.position.set(0, 2.5, -1.6);\n  group.add(house);\n  const bridge = new Mesh(new BoxGeometry(2.6, 1.0, 1.2), white);\n  bridge.position.set(0, 3.7, -0.9);\n  group.add(bridge);\n  const funnel = new Mesh(new CylinderGeometry(0.3, 0.36, 1.1, 8), hullPaint);\n  funnel.position.set(0, 4.2, -2.4);\n  group.add(funnel);\n  const mast = new Mesh(new CylinderGeometry(0.05, 0.08, 3.4, 6), white);\n  mast.position.set(0, 3.4, 3.4);\n  group.add(mast);\n  // Deck rails — the modern railing run, doing marine duty.\n  for (const side of [-1, 1]) {\n    const rail = createRailing({ style: 'bars', length: L - 1.4, seed: seed + 3, height: 0.85 });\n    rail.object.position.set(side * 1.6, 1.75, 0);\n    rail.object.rotation.y = Math.PI / 2;\n    group.add(rail.object);\n  }\n\n  const helm = createSlot('helm', 'drive', group, 0, 3.25, -0.7);\n  const base = floating(group, L, 3.4, 0.35);\n  return { object: group, obstacleRadius: 6.0, slots: [helm], ...base };\n}\n","import {\n  BoxGeometry,\n  CylinderGeometry,\n  Group,\n  IcosahedronGeometry,\n  Mesh,\n  MeshStandardMaterial,\n  PointLight,\n} from 'three';\nimport { Rng } from '../core/random';\nimport { DEFAULT_PALETTE, type Palette } from '../core/palette';\nimport { createSurface } from '../materials/surface';\nimport { createGlass } from '../materials/glass';\nimport type { Prop } from '../core/types';\n\n/**\n * Modern building components — the steel-railing tier. Everything is on the\n * standard Prop contract and themed by the Tier-4 surfaces: brushed steel,\n * powder-coat, teak, corten, concrete and architectural glass.\n */\n\n// ---- railings ----------------------------------------------------------\n\nexport type RailingStyle = 'bars' | 'cable' | 'glass' | 'panel';\n\nexport interface RailingOptions {\n  seed?: number;\n  /** Vertical 'bars', horizontal 'cable', frameless 'glass', or a decorative laser-cut 'panel'. */\n  style?: RailingStyle;\n  /** Run length along local +x. Default 4. */\n  length?: number;\n  /** Rail height. Default 1.05. */\n  height?: number;\n  palette?: Palette;\n}\n\n/** A modern railing run — balconies, terraces, stairs. Like `createFence`,\n * the run lies along local +x and the obstacle circle spans it. */\nexport function createRailing(options: RailingOptions = {}): Prop {\n  const seed = options.seed ?? 1;\n  const style = options.style ?? 'bars';\n  const length = options.length ?? 4;\n  const height = options.height ?? 1.05;\n  const palette = options.palette ?? DEFAULT_PALETTE;\n  const steel = createSurface('steel', { seed });\n  const coat = createSurface('paintedMetal', { color: palette.metal, seed: seed + 1 });\n\n  const group = new Group();\n  group.name = `railing-${style}`;\n\n  const bays = Math.max(1, Math.round(length / 1.1));\n  const bayW = length / bays;\n  for (let i = 0; i <= bays; i++) {\n    const post = new Mesh(new BoxGeometry(0.05, height, 0.05), style === 'glass' ? steel : coat);\n    post.position.set(-length / 2 + i * bayW, height / 2, 0);\n    group.add(post);\n  }\n  const rail = new Mesh(new CylinderGeometry(0.03, 0.03, length + 0.06, 8), steel);\n  rail.rotation.z = Math.PI / 2;\n  rail.position.y = height;\n  group.add(rail);\n\n  if (style === 'bars') {\n    const n = Math.round(length / 0.13);\n    for (let i = 1; i < n; i++) {\n      const bar = new Mesh(new CylinderGeometry(0.011, 0.011, height - 0.12, 5), coat);\n      bar.position.set(-length / 2 + (i / n) * length, (height - 0.12) / 2 + 0.02, 0);\n      group.add(bar);\n    }\n  } else if (style === 'cable') {\n    for (let i = 1; i <= 5; i++) {\n      const cable = new Mesh(new CylinderGeometry(0.007, 0.007, length, 5), steel);\n      cable.rotation.z = Math.PI / 2;\n      cable.position.y = (i / 6) * height;\n      group.add(cable);\n    }\n  } else if (style === 'glass') {\n    // ONE glass for the whole run. Every bay in a balustrade is the same pane,\n    // and building it inside the loop gave a seven-bay railing seven identical\n    // materials for the renderer to bind separately — `npm run geometry`\n    // counts exactly this.\n    const glass = createGlass();\n    for (let i = 0; i < bays; i++) {\n      const pane = new Mesh(new BoxGeometry(bayW - 0.12, height - 0.2, 0.02), glass);\n      pane.position.set(-length / 2 + (i + 0.5) * bayW, (height - 0.2) / 2 + 0.06, 0);\n      group.add(pane);\n    }\n  } else {\n    // Decorative laser-cut sheet: the per-cell motif stamped in a darker tone.\n    const sheet = createSurface('paintedMetal', {\n      color: palette.metal, seed: seed + 2,\n      tile: 1, tileW: 0.18, tileH: 0.18, mortar: 0.002, bond: 0,\n      motif: 0.85, tint: 0x14181c, tileJitter: 0.02, tileRelief: 0.02,\n    });\n    const panel = new Mesh(new BoxGeometry(length - 0.08, height - 0.18, 0.02), sheet);\n    panel.position.y = (height - 0.18) / 2 + 0.04;\n    group.add(panel);\n  }\n  return { object: group, obstacleRadius: length / 2 };\n}\n\n// ---- windows -----------------------------------------------------------\n\nexport type ModernWindowStyle = 'fixed' | 'sliding';\n\nexport interface ModernWindowOptions {\n  seed?: number;\n  width?: number;\n  height?: number;\n  /** Mullion grid: [columns, rows] of panes. Default [2, 1]. */\n  mullions?: [number, number];\n  /** 'fixed' glazing or 'sliding' (two offset panes on a track). */\n  style?: ModernWindowStyle;\n  /** Glass options passthrough. */\n  tint?: number;\n  frosted?: boolean;\n  /** Emissive pane the day cycle ignites at dusk. Default true. */\n  nightGlow?: boolean;\n  palette?: Palette;\n}\n\nexport interface ModernWindowProp extends Prop {\n  /** The glass material — hand it to a day cycle via the building's lamps. */\n  pane: MeshStandardMaterial;\n}\n\n/** A framed modern window standing on local origin, facing ±z. */\nexport function createModernWindow(options: ModernWindowOptions = {}): ModernWindowProp {\n  const seed = options.seed ?? 1;\n  const width = options.width ?? 1.8;\n  const height = options.height ?? 1.5;\n  const [cols, rows] = options.mullions ?? [2, 1];\n  const style = options.style ?? 'fixed';\n  const palette = options.palette ?? DEFAULT_PALETTE;\n  const frame = createSurface('paintedMetal', { color: palette.metal, seed });\n  const pane = createGlass({\n    tint: options.tint,\n    frosted: options.frosted,\n    nightGlow: options.nightGlow ?? true,\n  });\n\n  const group = new Group();\n  group.name = `window-${style}`;\n  const t = 0.06; // frame thickness\n\n  const bar = (w: number, h: number, x: number, y: number, z = 0): void => {\n    const m = new Mesh(new BoxGeometry(w, h, 0.07), frame);\n    m.position.set(x, y, z);\n    group.add(m);\n  };\n  bar(width, t, 0, t / 2);\n  bar(width, t, 0, height - t / 2);\n  bar(t, height, -width / 2 + t / 2, height / 2);\n  bar(t, height, width / 2 - t / 2, height / 2);\n\n  if (style === 'fixed') {\n    for (let i = 1; i < cols; i++) bar(t * 0.7, height, -width / 2 + (i / cols) * width, height / 2);\n    for (let j = 1; j < rows; j++) bar(width, t * 0.7, 0, (j / rows) * height);\n    const glassPane = new Mesh(new BoxGeometry(width - t * 2, height - t * 2, 0.02), pane);\n    glassPane.position.y = height / 2;\n    group.add(glassPane);\n  } else {\n    // Two sliding leaves on a visible track, one offset behind the other.\n    const track = new Mesh(new BoxGeometry(width, 0.04, 0.12), frame);\n    track.position.y = 0.02;\n    group.add(track);\n    for (const [dir, dz] of [[-1, 0.025], [1, -0.025]] as const) {\n      const leafW = width / 2 + t;\n      const leaf = new Group();\n      const lf = new Mesh(new BoxGeometry(leafW, height - 0.08, 0.03), frame);\n      leaf.add(lf);\n      const lg = new Mesh(new BoxGeometry(leafW - t * 2, height - 0.08 - t * 2, 0.015), pane);\n      lg.position.z = 0.012;\n      leaf.add(lg);\n      leaf.position.set((dir * (width - leafW)) / 2, height / 2, dz);\n      group.add(leaf);\n    }\n  }\n  return { object: group, obstacleRadius: 0, pane };\n}\n\n// ---- gates -------------------------------------------------------------\n\nexport type GateStyle = 'slat' | 'bars' | 'panel';\n\nexport interface GateOptions {\n  seed?: number;\n  /** Horizontal 'slat' (teak or steel), vertical 'bars', or motif 'panel'. */\n  style?: GateStyle;\n  /** Clear opening width. Default 3.2. */\n  width?: number;\n  /** Leaf height. Default 1.6. */\n  height?: number;\n  /** Masonry pillars flanking the gate (with warm cap lamps). Default true. */\n  pillars?: boolean;\n  /** 0 closed … 1 fully open. Default 0. */\n  open?: number;\n  /** One sliding leaf instead of two swing leaves. */\n  sliding?: boolean;\n  palette?: Palette;\n}\n\nexport interface GateProp extends Prop {\n  /** Drive the gate: 0 closed … 1 open (swing leaves rotate, sliders slide). */\n  setOpen(fraction: number): void;\n}\n\n/** A modern driveway gate between concrete pillars. */\nexport function createGate(options: GateOptions = {}): GateProp {\n  const seed = options.seed ?? 1;\n  const style = options.style ?? 'slat';\n  const width = options.width ?? 3.2;\n  const height = options.height ?? 1.6;\n  const withPillars = options.pillars ?? true;\n  const sliding = options.sliding ?? false;\n  const palette = options.palette ?? DEFAULT_PALETTE;\n  const coat = createSurface('paintedMetal', { color: palette.metal, seed });\n  const teak = createSurface('teak', { seed: seed + 1 });\n\n  const group = new Group();\n  group.name = `gate-${style}`;\n\n  if (withPillars) {\n    for (const side of [-1, 1]) {\n      const pillar = new Mesh(new BoxGeometry(0.45, height + 0.5, 0.45), createSurface('concrete', { seed: seed + 2 }));\n      pillar.position.set(side * (width / 2 + 0.24), (height + 0.5) / 2, 0);\n      group.add(pillar);\n      const cap = new Mesh(new BoxGeometry(0.3, 0.1, 0.3), new MeshStandardMaterial({\n        color: palette.lampGlow, emissive: palette.lampGlow, emissiveIntensity: 1.2,\n      }));\n      cap.position.set(side * (width / 2 + 0.24), height + 0.56, 0);\n      group.add(cap);\n      if (side === 1) {\n        const lamp = new PointLight(palette.lampGlow, 0, 7, 2); // day cycle drives it\n        lamp.position.set(side * (width / 2 + 0.24), height + 0.7, 0);\n        group.add(lamp);\n      }\n    }\n  }\n\n  const buildLeaf = (leafW: number): Group => {\n    const leaf = new Group();\n    const frame = (w: number, h: number, x: number, y: number): void => {\n      const m = new Mesh(new BoxGeometry(w, h, 0.05), coat);\n      m.position.set(x, y, 0);\n      leaf.add(m);\n    };\n    frame(leafW, 0.07, leafW / 2, 0.1);\n    frame(leafW, 0.07, leafW / 2, height - 0.05);\n    frame(0.07, height - 0.05, 0.035, height / 2);\n    frame(0.07, height - 0.05, leafW - 0.035, height / 2);\n    if (style === 'slat') {\n      const n = 7;\n      for (let i = 1; i < n; i++) {\n        const slat = new Mesh(new BoxGeometry(leafW - 0.1, 0.09, 0.03), teak);\n        slat.position.set(leafW / 2, 0.12 + (i / n) * (height - 0.2), 0);\n        leaf.add(slat);\n      }\n    } else if (style === 'bars') {\n      const n = Math.round(leafW / 0.13);\n      for (let i = 1; i < n; i++) {\n        const gbar = new Mesh(new CylinderGeometry(0.012, 0.012, height - 0.2, 5), coat);\n        gbar.position.set((i / n) * leafW, height / 2, 0);\n        leaf.add(gbar);\n      }\n    } else {\n      const sheet = createSurface('paintedMetal', {\n        color: palette.metal, seed: seed + 3,\n        tile: 1, tileW: 0.2, tileH: 0.2, mortar: 0.002, bond: 0,\n        motif: 0.85, tint: 0x14181c, tileJitter: 0.02, tileRelief: 0.02,\n      });\n      const panel = new Mesh(new BoxGeometry(leafW - 0.1, height - 0.22, 0.02), sheet);\n      panel.position.set(leafW / 2, height / 2, 0);\n      leaf.add(panel);\n    }\n    return leaf;\n  };\n\n  const leaves: Array<{ leaf: Group; dir: number }> = [];\n  if (sliding) {\n    const leaf = buildLeaf(width + 0.2);\n    leaf.position.set(-width / 2 - 0.1, 0, 0.16);\n    group.add(leaf);\n    leaves.push({ leaf, dir: 1 });\n  } else {\n    for (const dir of [-1, 1]) {\n      const leaf = buildLeaf(width / 2 + 0.02);\n      leaf.position.set(dir * (width / 2), 0, 0);\n      if (dir === 1) leaf.scale.x = -1; // hinge both leaves at the pillars\n      group.add(leaf);\n      leaves.push({ leaf, dir });\n    }\n  }\n\n  const setOpen = (fraction: number): void => {\n    const f = Math.min(1, Math.max(0, fraction));\n    for (const { leaf, dir } of leaves) {\n      if (sliding) leaf.position.x = -width / 2 - 0.1 - f * (width + 0.2);\n      else leaf.rotation.y = dir * f * 1.9;\n    }\n  };\n  setOpen(options.open ?? 0);\n\n  return { object: group, obstacleRadius: width / 2 + 0.5, setOpen };\n}\n\n// ---- cladding & pergola ------------------------------------------------\n\nexport type CladdingStyle = 'slats' | 'louvers' | 'stone';\n\nexport interface CladdingOptions {\n  seed?: number;\n  /** Vertical teak 'slats', angled 'louvers', or a 'stone' feature panel. */\n  style?: CladdingStyle;\n  width?: number;\n  height?: number;\n  palette?: Palette;\n}\n\n/** A facade accent panel — the modern-bungalow signature. Flat against ±z. */\nexport function createCladding(options: CladdingOptions = {}): Prop {\n  const seed = options.seed ?? 1;\n  const style = options.style ?? 'slats';\n  const width = options.width ?? 3;\n  const height = options.height ?? 3;\n  const group = new Group();\n  group.name = `cladding-${style}`;\n\n  if (style === 'stone') {\n    const panel = new Mesh(new BoxGeometry(width, height, 0.14), createSurface('slate', {\n      seed, tile: 1, tileW: 0.55, tileH: 0.14, mortar: 0.008, bond: 1,\n      tileJitter: 0.22, mortarColor: 0x22262b, tileRelief: 0.08,\n    }));\n    panel.position.y = height / 2;\n    group.add(panel);\n  } else {\n    const teak = createSurface('teak', { seed });\n    const n = Math.round(width / 0.16);\n    for (let i = 0; i < n; i++) {\n      const slat = new Mesh(new BoxGeometry(0.09, height, 0.04), teak);\n      slat.position.set(-width / 2 + (i + 0.5) * (width / n), height / 2, 0);\n      if (style === 'louvers') slat.rotation.y = 0.6;\n      group.add(slat);\n    }\n    for (const y of [0.06, height - 0.06]) {\n      const rail = new Mesh(new BoxGeometry(width, 0.06, 0.03), teak);\n      rail.position.set(0, y, -0.035);\n      group.add(rail);\n    }\n  }\n  return { object: group, obstacleRadius: 0 };\n}\n\nexport interface PergolaOptions {\n  seed?: number;\n  width?: number;\n  depth?: number;\n  palette?: Palette;\n}\n\n/** A teak pergola: four posts, doubled beams, rafter slats. Walk-through\n * (obstacleRadius 0) — feed the posts to steering yourself if needed. */\nexport function createPergola(options: PergolaOptions = {}): Prop {\n  const seed = options.seed ?? 1;\n  const width = options.width ?? 3.6;\n  const depth = options.depth ?? 3;\n  const teak = createSurface('teak', { seed });\n  const H = 2.5;\n\n  const group = new Group();\n  group.name = 'pergola';\n  for (const sx of [-1, 1]) {\n    for (const sz of [-1, 1]) {\n      const post = new Mesh(new BoxGeometry(0.14, H, 0.14), teak);\n      post.position.set(sx * (width / 2 - 0.1), H / 2, sz * (depth / 2 - 0.1));\n      group.add(post);\n    }\n  }\n  for (const sz of [-1, 1]) {\n    const beam = new Mesh(new BoxGeometry(width + 0.5, 0.16, 0.08), teak);\n    beam.position.set(0, H + 0.08, sz * (depth / 2 - 0.1));\n    group.add(beam);\n  }\n  const rafters = Math.round(width / 0.42);\n  for (let i = 0; i <= rafters; i++) {\n    const rafter = new Mesh(new BoxGeometry(0.06, 0.12, depth + 0.5), teak);\n    rafter.position.set(-width / 2 + (i / rafters) * width, H + 0.22, 0);\n    group.add(rafter);\n  }\n  return { object: group, obstacleRadius: 0 };\n}\n\nexport interface PlanterOptions {\n  seed?: number;\n  /** Trough length. Default 1.6. */\n  length?: number;\n  palette?: Palette;\n}\n\n/** A corten planter trough with low greenery. */\nexport function createPlanter(options: PlanterOptions = {}): Prop {\n  const seed = options.seed ?? 1;\n  const rng = new Rng(seed);\n  const length = options.length ?? 1.6;\n  const palette = options.palette ?? DEFAULT_PALETTE;\n\n  const group = new Group();\n  group.name = 'planter';\n  const box = new Mesh(new BoxGeometry(length, 0.5, 0.45), createSurface('corten', { seed }));\n  box.position.y = 0.25;\n  group.add(box);\n  const soil = new Mesh(new BoxGeometry(length - 0.06, 0.04, 0.39), createSurface('dirt', { seed: seed + 1 }));\n  soil.position.y = 0.5;\n  group.add(soil);\n  const leaf = new MeshStandardMaterial({ color: rng.pick(palette.foliage), flatShading: true });\n  const clumps = Math.max(2, Math.round(length / 0.4));\n  for (let i = 0; i < clumps; i++) {\n    const clump = new Mesh(new IcosahedronGeometry(rng.range(0.14, 0.22), 0), leaf);\n    clump.position.set(-length / 2 + (i + 0.5) * (length / clumps), 0.58 + rng.range(0, 0.06), rng.jitter(0, 0.08));\n    group.add(clump);\n  }\n  return { object: group, obstacleRadius: length / 2 };\n}\n","import {\n  BoxGeometry,\n  CylinderGeometry,\n  Group,\n  Mesh,\n  MeshStandardMaterial,\n  Object3D,\n  TorusGeometry,\n} from 'three';\nimport { DEFAULT_PALETTE, type Palette } from '../core/palette';\nimport { createSurface } from '../materials/surface';\nimport { createSlot } from '../core/types';\nimport type { Prop } from '../core/types';\n\n/**\n * Manipulables — props with a STATE that a character (or GAMA) actuates, and\n * that animate in response: doors swing, drawers slide, levers throw, valves\n * spin, hatches hinge, portcullises rise. This is the \"operate and the world\n * responds\" verb the interaction system was missing — until now props were\n * inert (except vehicles, which only spin wheels).\n *\n * Every manipulable exposes a small, uniform control surface:\n *\n * ```ts\n * const door = createDoor();\n * door.toggle();                 // flip open/closed\n * door.onChange = (open) => …;   // fires when the target flips\n * game.onUpdate((t) => door.update(t.delta));  // eases the joint toward target\n * ```\n *\n * `state` is the live eased position (0 = closed/rest, 1 = open/actuated);\n * `open` is the boolean target. The shape is structurally identical to GAMA's\n * `Mechanism`, so `Interactable`/`linkMechanism`/`Trigger` drive these without\n * either library importing the other. Props that a character stands at to\n * work (lever, valve, drawer, hatch) publish an `operate` slot at ANIMA's\n * floor-level anchor convention; doors and portcullises are pass-through.\n */\nexport interface Manipulable extends Prop {\n  /** Live eased position: 0 = closed/rest … 1 = open/actuated. */\n  readonly state: number;\n  /** The current target: true once set/toggled past halfway open. */\n  readonly open: boolean;\n  /** Flip open↔closed. Returns the new `open`. */\n  toggle(): boolean;\n  /** Drive to open (`true`/1), closed (`false`/0), or a partial target in [0,1]. */\n  set(target: number | boolean): void;\n  /** Ease the joint toward the target. Call every frame. */\n  update(dt: number): void;\n  /** Fired when the target flips open↔closed (after `set`/`toggle`). */\n  onChange?: (open: boolean) => void;\n}\n\nexport interface MechanismOptions {\n  seed?: number;\n  palette?: Palette;\n  /** Body/paint colour; defaults to a seeded or preset pick. */\n  color?: number;\n  /** How fast the joint travels toward its target (1/sec). Default 3. */\n  speed?: number;\n}\n\nconst smooth = (t: number): number => t * t * (3 - 2 * t);\nconst clamp01 = (v: number): number => (v < 0 ? 0 : v > 1 ? 1 : v);\n\n/**\n * The shared easing core: tracks a linear `state` chasing `target`, and calls\n * `apply(smooth(state))` each step so visuals start and stop softly. Returns\n * the full Manipulable once the caller attaches `object`/`slots`.\n */\nfunction makeManipulable(\n  object: Group,\n  obstacleRadius: number,\n  slots: Prop['slots'],\n  apply: (v: number) => void,\n  speed: number\n): Manipulable {\n  let target = 0;\n  let state = 0;\n  apply(0);\n\n  const core = {\n    object,\n    obstacleRadius,\n    slots,\n    onChange: undefined as ((open: boolean) => void) | undefined,\n    get state() {\n      return state;\n    },\n    get open() {\n      return target >= 0.5;\n    },\n    set(t: number | boolean) {\n      const next = typeof t === 'boolean' ? (t ? 1 : 0) : clamp01(t);\n      const was = target >= 0.5;\n      target = next;\n      const now = target >= 0.5;\n      if (now !== was) core.onChange?.(now);\n    },\n    toggle() {\n      core.set(target >= 0.5 ? 0 : 1);\n      return target >= 0.5;\n    },\n    update(dt: number) {\n      if (state === target) return;\n      const d = target - state;\n      const step = Math.max(0, speed) * dt;\n      state += Math.abs(d) <= step ? d : Math.sign(d) * step;\n      apply(smooth(state));\n    },\n  };\n  return core as Manipulable;\n}\n\n// ------------------------------------------------------------------- Door\n\nexport interface DoorOptions extends MechanismOptions {\n  width?: number;\n  height?: number;\n  /** Hinge on the 'left' (−x) or 'right' (+x) post. Default 'left'. */\n  hinge?: 'left' | 'right';\n  /** Swing-open angle in radians. Default ~1.9 (just past 90°). */\n  swing?: number;\n  /** Two leaves meeting in the middle (a gateway). Default false. */\n  double?: boolean;\n}\n\n/**\n * A framed door that swings on its hinge — the workhorse manipulable. Set\n * `double` for a two-leaf gateway (both leaves swing apart). Walk-through\n * when open; the frame is thin scenery.\n */\nexport function createDoor(options: DoorOptions = {}): Manipulable {\n  const seed = options.seed ?? 1;\n  const palette = options.palette ?? DEFAULT_PALETTE;\n  const width = options.width ?? 1.0;\n  const height = options.height ?? 2.1;\n  const swing = options.swing ?? 1.9;\n  const wood = createSurface('plank', { color: options.color ?? palette.wood, seed });\n  const post = createSurface('wood', { color: palette.wood, seed: seed + 5 });\n\n  const group = new Group();\n  group.name = 'door';\n  // Frame: two posts + a lintel around the opening.\n  const span = options.double ? width * 2 : width;\n  for (const s of [-1, 1]) {\n    const jamb = new Mesh(new BoxGeometry(0.12, height + 0.1, 0.16), post);\n    jamb.position.set((s * (span + 0.12)) / 2, (height + 0.1) / 2, 0);\n    group.add(jamb);\n  }\n  const lintel = new Mesh(new BoxGeometry(span + 0.36, 0.14, 0.16), post);\n  lintel.position.set(0, height + 0.07, 0);\n  group.add(lintel);\n\n  const leaf = (dir: number): Object3D => {\n    // A hinge pivot at the jamb; the slab hangs toward the opening centre.\n    const hinge = new Object3D();\n    hinge.position.set((dir * span) / 2, height / 2, 0);\n    const slab = new Mesh(new BoxGeometry(width - 0.04, height - 0.06, 0.06), wood);\n    slab.position.set((-dir * width) / 2, 0, 0);\n    const handle = new Mesh(\n      new CylinderGeometry(0.03, 0.03, 0.14, 6),\n      new MeshStandardMaterial({ color: 0x2a2d33, metalness: 0.6, roughness: 0.4 })\n    );\n    handle.rotation.x = Math.PI / 2;\n    handle.position.set(-dir * (width - 0.18), 0, 0.08);\n    slab.add(handle);\n    hinge.add(slab);\n    group.add(hinge);\n    return hinge;\n  };\n\n  if (options.double) {\n    const left = leaf(-1);\n    const right = leaf(1);\n    return makeManipulable(group, 0, undefined, (v) => {\n      left.rotation.y = swing * v;\n      right.rotation.y = -swing * v;\n    }, options.speed ?? 3);\n  }\n  const dir = options.hinge === 'right' ? 1 : -1;\n  const hinge = leaf(dir);\n  return makeManipulable(group, 0, undefined, (v) => {\n    hinge.rotation.y = -dir * swing * v;\n  }, options.speed ?? 3);\n}\n\n// ------------------------------------------------------------------ Drawer\n\nexport interface DrawerOptions extends MechanismOptions {\n  width?: number;\n  height?: number;\n  depth?: number;\n}\n\n/** A cabinet with a single drawer that slides out toward the front (+z). */\nexport function createDrawer(options: DrawerOptions = {}): Manipulable {\n  const seed = options.seed ?? 1;\n  const palette = options.palette ?? DEFAULT_PALETTE;\n  const w = options.width ?? 0.8;\n  const h = options.height ?? 0.7;\n  const d = options.depth ?? 0.55;\n  const body = createSurface('wood', { color: options.color ?? palette.wood, seed });\n  const face = createSurface('plank', { color: palette.wood, seed: seed + 3 });\n\n  const group = new Group();\n  group.name = 'drawer';\n  // Carcass: back + sides + top, open at the front.\n  const back = new Mesh(new BoxGeometry(w, h, 0.04), body);\n  back.position.set(0, h / 2, -d / 2);\n  const top = new Mesh(new BoxGeometry(w, 0.04, d), body);\n  top.position.set(0, h, 0);\n  group.add(back, top);\n  for (const s of [-1, 1]) {\n    const side = new Mesh(new BoxGeometry(0.04, h, d), body);\n    side.position.set((s * w) / 2, h / 2, 0);\n    group.add(side);\n  }\n\n  // The sliding drawer: a shallow tray + a front face with a pull.\n  const drawer = new Object3D();\n  const tray = new Mesh(new BoxGeometry(w - 0.12, h - 0.16, d - 0.1), body);\n  tray.position.set(0, h / 2, 0);\n  const front = new Mesh(new BoxGeometry(w - 0.06, h - 0.1, 0.05), face);\n  front.position.set(0, h / 2, d / 2);\n  const pull = new Mesh(\n    new TorusGeometry(0.05, 0.012, 6, 10),\n    new MeshStandardMaterial({ color: 0x2a2d33, metalness: 0.6, roughness: 0.4 })\n  );\n  pull.position.set(0, h / 2, d / 2 + 0.05);\n  drawer.add(tray, front, pull);\n  group.add(drawer);\n\n  const slot = createSlot('operate', 'operate', group, 0, 0, d / 2 + 0.75, Math.PI);\n  return makeManipulable(group, 0.6, [slot], (v) => {\n    drawer.position.z = (d * 0.8) * v; // slides out up to 80% of its depth\n  }, options.speed ?? 3.5);\n}\n\n// ------------------------------------------------------------------- Lever\n\nexport interface LeverOptions extends MechanismOptions {\n  /** Handle length. Default 0.6. */\n  length?: number;\n  /** Mount on a floor 'base' or a 'wall' plate. Default 'base'. */\n  mount?: 'base' | 'wall';\n}\n\n/**\n * A throw lever — the canonical switch. The handle swings from back to\n * forward as it actuates; wire its `onChange` to a gate/portcullis with\n * GAMA's `linkMechanism` for switch-driven level logic.\n */\nexport function createLever(options: LeverOptions = {}): Manipulable {\n  const seed = options.seed ?? 1;\n  const len = options.length ?? 0.6;\n  const metal = createSurface('steel', { color: options.color ?? 0x8b3a2f, seed });\n  const dark = new MeshStandardMaterial({ color: 0x2a2d33, metalness: 0.5, roughness: 0.5 });\n\n  const group = new Group();\n  group.name = 'lever';\n  const wall = options.mount === 'wall';\n  const base = wall\n    ? new Mesh(new BoxGeometry(0.34, 0.34, 0.08), createSurface('steel', { seed: seed + 1 }))\n    : new Mesh(new CylinderGeometry(0.16, 0.2, 0.14, 8), createSurface('steel', { seed: seed + 1 }));\n  base.position.y = wall ? 0.9 : 0.07;\n  group.add(base);\n\n  // Pivot near the base; handle points up-and-back at rest.\n  const pivot = new Object3D();\n  pivot.position.set(0, wall ? 0.9 : 0.14, 0);\n  const shaft = new Mesh(new CylinderGeometry(0.03, 0.035, len, 6), metal);\n  shaft.position.set(0, len / 2, 0);\n  const knob = new Mesh(new CylinderGeometry(0.06, 0.06, 0.1, 8), dark);\n  knob.position.set(0, len, 0);\n  pivot.add(shaft, knob);\n  group.add(pivot);\n\n  const throwFrom = 0.55; // leaning back at rest\n  const throwTo = -0.55; // thrown forward when open\n  const slot = createSlot('operate', 'operate', group, 0, 0, 0.75, Math.PI);\n  return makeManipulable(group, 0.3, [slot], (v) => {\n    pivot.rotation.x = throwFrom + (throwTo - throwFrom) * v;\n  }, options.speed ?? 6);\n}\n\n// ------------------------------------------------------------------- Valve\n\nexport interface ValveOptions extends MechanismOptions {\n  /** Wheel radius. Default 0.28. */\n  radius?: number;\n  /** Full turns from closed to open. Default 3. */\n  turns?: number;\n}\n\n/** A pipe valve — a hand-wheel that spins through several turns as it opens. */\nexport function createValve(options: ValveOptions = {}): Manipulable {\n  const seed = options.seed ?? 1;\n  const R = options.radius ?? 0.28;\n  const turns = options.turns ?? 3;\n  const metal = createSurface('steel', { color: options.color, seed });\n  const pipeMat = createSurface('paintedMetal', { color: 0x9a2f26, seed: seed + 2 });\n\n  const group = new Group();\n  group.name = 'valve';\n  const pipe = new Mesh(new CylinderGeometry(0.12, 0.12, 1.2, 10), pipeMat);\n  pipe.rotation.z = Math.PI / 2;\n  pipe.position.y = 0.6;\n  const body = new Mesh(new CylinderGeometry(0.16, 0.16, 0.3, 10), pipeMat);\n  body.position.y = 0.78;\n  group.add(pipe, body);\n\n  // The hand-wheel on a stem, spinning about local z (it faces +z).\n  const wheel = new Object3D();\n  wheel.position.set(0, 0.98, 0);\n  const rim = new Mesh(new TorusGeometry(R, 0.03, 6, 16), metal);\n  wheel.add(rim);\n  for (let i = 0; i < 4; i++) {\n    const spoke = new Mesh(new BoxGeometry(R * 2, 0.04, 0.04), metal);\n    spoke.rotation.z = (i / 4) * Math.PI;\n    wheel.add(spoke);\n  }\n  wheel.rotation.x = -Math.PI / 2; // face up-ish so it reads as a wheel on top\n  const stem = new Mesh(new CylinderGeometry(0.03, 0.03, 0.2, 6), metal);\n  stem.position.y = 0.88;\n  group.add(stem, wheel);\n\n  const slot = createSlot('operate', 'operate', group, 0, 0, 0.7, Math.PI);\n  return makeManipulable(group, 0.4, [slot], (v) => {\n    wheel.rotation.y = v * turns * Math.PI * 2; // spins about the stem\n  }, options.speed ?? 2.2);\n}\n\n// ------------------------------------------------------------------- Hatch\n\nexport interface HatchOptions extends MechanismOptions {\n  width?: number;\n  depth?: number;\n  /** Lid open angle in radians. Default ~2.0. */\n  angle?: number;\n}\n\n/**\n * A hinged lid — a chest, a crate top, a floor trapdoor. The lid hinges up\n * and back off its rear edge; a character stands at the front to open it.\n */\nexport function createHatch(options: HatchOptions = {}): Manipulable {\n  const seed = options.seed ?? 1;\n  const palette = options.palette ?? DEFAULT_PALETTE;\n  const w = options.width ?? 0.9;\n  const dp = options.depth ?? 0.6;\n  const angle = options.angle ?? 2.0;\n  const wood = createSurface('plank', { color: options.color ?? palette.wood, seed });\n  const iron = new MeshStandardMaterial({ color: 0x2a2d33, metalness: 0.5, roughness: 0.5 });\n\n  const group = new Group();\n  group.name = 'hatch';\n  const box = new Mesh(new BoxGeometry(w, 0.5, dp), wood);\n  box.position.y = 0.25;\n  group.add(box);\n  for (const s of [-1, 1]) {\n    const band = new Mesh(new BoxGeometry(0.05, 0.52, dp + 0.02), iron);\n    band.position.set((s * w) / 2 - s * 0.08, 0.25, 0);\n    group.add(band);\n  }\n\n  // Lid hinged at the back top edge (z = -dp/2), opening up and back.\n  const hinge = new Object3D();\n  hinge.position.set(0, 0.5, -dp / 2);\n  const lid = new Mesh(new BoxGeometry(w, 0.06, dp), wood);\n  lid.position.set(0, 0.03, dp / 2);\n  hinge.add(lid);\n  group.add(hinge);\n\n  const slot = createSlot('operate', 'operate', group, 0, 0, dp / 2 + 0.7, Math.PI);\n  return makeManipulable(group, 0.5, [slot], (v) => {\n    hinge.rotation.x = angle * v;\n  }, options.speed ?? 4);\n}\n\n// -------------------------------------------------------------- Portcullis\n\nexport interface PortcullisOptions extends MechanismOptions {\n  width?: number;\n  height?: number;\n}\n\n/**\n * A castle portcullis — a barred iron grille in a stone gateway that rises to\n * open. The medieval-village payoff for the switch/lever wiring: throw a\n * lever, raise the gate.\n */\nexport function createPortcullis(options: PortcullisOptions = {}): Manipulable {\n  const seed = options.seed ?? 1;\n  const w = options.width ?? 2.4;\n  const h = options.height ?? 3.0;\n  const stone = createSurface('ashlar', { seed });\n  const iron = createSurface('steel', { color: options.color ?? 0x3a3d42, seed: seed + 1 });\n\n  const group = new Group();\n  group.name = 'portcullis';\n  // Stone gateway: two piers + a lintel block.\n  for (const s of [-1, 1]) {\n    const pier = new Mesh(new BoxGeometry(0.6, h + 0.4, 0.8), stone);\n    pier.position.set((s * (w + 0.6)) / 2, (h + 0.4) / 2, 0);\n    group.add(pier);\n  }\n  const lintel = new Mesh(new BoxGeometry(w + 1.2, 0.7, 0.8), stone);\n  lintel.position.set(0, h + 0.35, 0);\n  group.add(lintel);\n\n  // The grille that slides up inside the gateway.\n  const grille = new Group();\n  const bars = Math.max(3, Math.round(w / 0.4));\n  for (let i = 0; i <= bars; i++) {\n    const bar = new Mesh(new CylinderGeometry(0.05, 0.05, h, 6), iron);\n    bar.position.set(-w / 2 + (i / bars) * w, h / 2, 0);\n    grille.add(bar);\n  }\n  for (const yy of [0.2, h * 0.5, h - 0.2]) {\n    const rung = new Mesh(new BoxGeometry(w, 0.08, 0.08), iron);\n    rung.position.set(0, yy, 0);\n    grille.add(rung);\n  }\n  // Spiked bottom — a nice silhouette when raised.\n  for (let i = 0; i <= bars; i++) {\n    const spike = new Mesh(new CylinderGeometry(0.001, 0.06, 0.2, 6), iron);\n    spike.position.set(-w / 2 + (i / bars) * w, -0.1, 0);\n    grille.add(spike);\n  }\n  group.add(grille);\n\n  return makeManipulable(group, 0, undefined, (v) => {\n    grille.position.y = (h - 0.2) * v; // rises nearly its full height\n  }, options.speed ?? 1.6);\n}\n","import { BoxGeometry, CylinderGeometry, Group, Mesh, Object3D, TorusGeometry } from 'three';\nimport { Rng } from '../core/random';\nimport { DEFAULT_PALETTE, type Palette } from '../core/palette';\nimport { createSurface } from '../materials/surface';\nimport type { Prop } from '../core/types';\n\n/**\n * Things to climb, and the tack that goes on a horse.\n *\n * Both exist to be *met* by an ANIMA character: the ladder publishes the\n * anchors its `Climb` controller needs, and the saddle and bridle are\n * built to the fixtures a `createQuadruped` already carries, so a rider\n * lands in the seat and the reins run to the mouth without any runtime IK.\n */\n\nexport type LadderStyle = 'wooden' | 'steel' | 'rope';\n\nexport interface LadderOptions {\n  seed?: number;\n  /** Height to the top rung, metres. Default 3.2. */\n  height?: number;\n  /** 'wooden' rungs, a 'steel' fixed ladder, or a 'rope' ladder. */\n  style?: LadderStyle;\n  /** Width between the rails. Default 0.44. */\n  width?: number;\n  palette?: Palette;\n}\n\n/**\n * A climbable ladder. Publishes `bottom`, `top` and `rungSpacing` —\n * structurally ANIMA's `Climbable`, so it drops straight into\n * `new Climb(rig, loco).start(ladder)` with no cross-imports.\n *\n * `rungSpacing` is the contract that matters: ANIMA drives the body up by\n * exactly that much per half-cycle of the climb loop, so hands land on\n * rungs rather than sliding past them.\n */\nexport interface Ladder extends Prop {\n  /** Floor-level anchor at the foot; +z faces INTO the rungs. */\n  bottom: Object3D;\n  /** Anchor level with the top rung, where the climber steps off. */\n  top: Object3D;\n  rungSpacing: number;\n  rungs: number;\n}\n\nexport function createLadder(options: LadderOptions = {}): Ladder {\n  const seed = options.seed ?? 1;\n  const rng = new Rng(seed);\n  const height = options.height ?? 3.2;\n  const style = options.style ?? 'wooden';\n  const width = options.width ?? 0.44;\n  const palette = options.palette ?? DEFAULT_PALETTE;\n\n  const group = new Group();\n  group.name = `ladder-${style}`;\n  // Rungs a comfortable stride apart — close enough that a climber never\n  // has to stretch, which is what makes the spacing look right.\n  const rungSpacing = style === 'rope' ? 0.32 : 0.3;\n  const rungs = Math.max(2, Math.floor(height / rungSpacing));\n\n  const wood = createSurface('wood', { color: palette.wood, seed });\n  const dark = createSurface('wood', { color: palette.woodDark, seed: seed + 1 });\n  const steel = createSurface('metal', { color: palette.metal, seed: seed + 2 });\n  const rope = createSurface('canvas', { color: 0xb9a274, seed: seed + 3 });\n\n  const railMat = style === 'steel' ? steel : style === 'rope' ? rope : wood;\n  const rungMat = style === 'steel' ? steel : style === 'rope' ? dark : dark;\n\n  if (style === 'rope') {\n    // A rope ladder hangs, so the rails sag a little between fixings.\n    for (const side of [-1, 1]) {\n      const rail = new Mesh(new CylinderGeometry(0.018, 0.018, height, 5), railMat);\n      rail.position.set(side * width * 0.5, height * 0.5, 0);\n      rail.rotation.z = side * 0.012;\n      group.add(rail);\n    }\n  } else {\n    for (const side of [-1, 1]) {\n      const rail =\n        style === 'steel'\n          ? new Mesh(new CylinderGeometry(0.026, 0.026, height, 7), railMat)\n          : new Mesh(new BoxGeometry(0.06, height, 0.045), railMat);\n      rail.position.set(side * width * 0.5, height * 0.5, 0);\n      group.add(rail);\n    }\n    // Steel ladders are bolted to a wall with standoff brackets.\n    if (style === 'steel') {\n      for (let i = 0; i < Math.max(2, Math.floor(height / 1.3)); i++) {\n        const bracket = new Mesh(new BoxGeometry(width + 0.12, 0.04, 0.14), steel);\n        bracket.position.set(0, 0.5 + i * 1.3, -0.08);\n        group.add(bracket);\n      }\n    }\n  }\n\n  for (let i = 0; i < rungs; i++) {\n    const y = (i + 1) * rungSpacing;\n    const rung =\n      style === 'wooden'\n        ? new Mesh(new BoxGeometry(width, 0.035, 0.05), rungMat)\n        : new Mesh(new CylinderGeometry(0.019, 0.019, width, 6), rungMat);\n    if (style !== 'wooden') rung.rotation.z = Math.PI / 2;\n    rung.position.set(0, y, 0);\n    if (style === 'rope') rung.position.y += rng.range(-0.012, 0.012);\n    if (style === 'wooden') rung.rotation.z = rng.range(-0.012, 0.012);\n    group.add(rung);\n  }\n\n  // The anchors ANIMA climbs between. +z faces into the ladder, so a\n  // climber standing on `bottom` is looking at the rungs.\n  const bottom = new Object3D();\n  bottom.name = 'ladder:bottom';\n  bottom.position.set(0, 0, 0);\n  group.add(bottom);\n  const top = new Object3D();\n  top.name = 'ladder:top';\n  top.position.set(0, rungs * rungSpacing, 0);\n  group.add(top);\n\n  return {\n    object: group,\n    obstacleRadius: 0.3,\n    bottom,\n    top,\n    rungSpacing,\n    rungs,\n  };\n}\n\n// ---- tack --------------------------------------------------------------\n\nexport type TackStyle = 'english' | 'western' | 'bareback';\n\nexport interface TackOptions {\n  seed?: number;\n  /** An 'english' saddle, a 'western' one with a horn, or 'bareback' pad. */\n  style?: TackStyle;\n  /** Withers height of the horse it goes on, metres. Default 1.62. */\n  horseHeight?: number;\n  /** Leather colour. */\n  color?: number;\n  palette?: Palette;\n}\n\n/**\n * A saddle, built to sit on ANIMA's `QuadrupedRig.saddle` fixture.\n *\n * ```ts\n * const tack = createSaddle({ horseHeight: horse.height });\n * horse.saddle.add(tack.object);        // it lands where the seat is\n * ```\n *\n * The stirrups hang where the rider's foot goes, which is the whole point:\n * ANIMA's ride pose puts the heel down at that height, so the two meet by\n * construction rather than by fiddling.\n */\nexport function createSaddle(options: TackOptions = {}): Prop {\n  const seed = options.seed ?? 1;\n  const style = options.style ?? 'english';\n  const H = options.horseHeight ?? 1.62;\n  const palette = options.palette ?? DEFAULT_PALETTE;\n  const leather = createSurface('leather', { color: options.color ?? 0x6b4326, seed });\n  const dark = createSurface('leather', { color: 0x4a2d19, seed: seed + 1 });\n  const iron = createSurface('metal', { color: palette.metal, seed: seed + 2 });\n\n  const group = new Group();\n  group.name = `saddle-${style}`;\n  const scale = H / 1.62;\n\n  if (style === 'bareback') {\n    const pad = new Mesh(new BoxGeometry(0.4 * scale, 0.03 * scale, 0.46 * scale), leather);\n    group.add(pad);\n  } else {\n    // Seat, with a cantle behind and a pommel in front — the dip between\n    // them is where the rider sits, and it is why a saddle has a shape.\n    const seat = new Mesh(new BoxGeometry(0.36 * scale, 0.06 * scale, 0.44 * scale), leather);\n    group.add(seat);\n    const cantle = new Mesh(new BoxGeometry(0.34 * scale, 0.11 * scale, 0.07 * scale), leather);\n    cantle.position.set(0, 0.06 * scale, -0.2 * scale);\n    cantle.rotation.x = -0.3;\n    group.add(cantle);\n    const pommel = new Mesh(new BoxGeometry(0.28 * scale, 0.08 * scale, 0.07 * scale), leather);\n    pommel.position.set(0, 0.05 * scale, 0.2 * scale);\n    pommel.rotation.x = 0.25;\n    group.add(pommel);\n    // Skirts down each side, and the girth that actually holds it on.\n    for (const side of [-1, 1]) {\n      const skirt = new Mesh(new BoxGeometry(0.04 * scale, 0.26 * scale, 0.34 * scale), dark);\n      skirt.position.set(side * 0.19 * scale, -0.13 * scale, 0);\n      group.add(skirt);\n      // Stirrup leather and iron, hung where a rider's foot goes.\n      const strap = new Mesh(new BoxGeometry(0.03 * scale, 0.34 * scale, 0.02 * scale), dark);\n      strap.position.set(side * 0.21 * scale, -0.3 * scale, 0.02 * scale);\n      group.add(strap);\n      const stirrup = new Mesh(new TorusGeometry(0.055 * scale, 0.012 * scale, 5, 8), iron);\n      stirrup.position.set(side * 0.21 * scale, -0.5 * scale, 0.02 * scale);\n      group.add(stirrup);\n    }\n    if (style === 'western') {\n      // The horn: the one silhouette difference everybody recognises.\n      const horn = new Mesh(new CylinderGeometry(0.028 * scale, 0.04 * scale, 0.1 * scale, 7), leather);\n      horn.position.set(0, 0.13 * scale, 0.19 * scale);\n      group.add(horn);\n      const cap = new Mesh(new CylinderGeometry(0.05 * scale, 0.032 * scale, 0.022 * scale, 8), leather);\n      cap.position.set(0, 0.19 * scale, 0.19 * scale);\n      group.add(cap);\n    }\n  }\n\n  return { object: group, obstacleRadius: 0 };\n}\n\n/**\n * A bridle: headstall, browband, bit and reins. Add it to the horse's\n * `Head` bone so it follows every nod.\n */\nexport function createBridle(options: TackOptions = {}): Prop {\n  const seed = options.seed ?? 1;\n  const H = options.horseHeight ?? 1.62;\n  const palette = options.palette ?? DEFAULT_PALETTE;\n  const leather = createSurface('leather', { color: options.color ?? 0x4a2d19, seed });\n  const iron = createSurface('metal', { color: palette.metal, seed: seed + 1 });\n  const scale = H / 1.62;\n\n  const group = new Group();\n  group.name = 'bridle';\n  // Browband across the forehead, cheekpieces down each side, noseband.\n  const brow = new Mesh(new BoxGeometry(0.13 * scale, 0.018 * scale, 0.02 * scale), leather);\n  brow.position.set(0, 0.055 * scale, -0.005 * scale);\n  group.add(brow);\n  for (const side of [-1, 1]) {\n    const cheek = new Mesh(new BoxGeometry(0.016 * scale, 0.2 * scale, 0.018 * scale), leather);\n    cheek.position.set(side * 0.062 * scale, -0.07 * scale, 0.07 * scale);\n    cheek.rotation.x = 0.5;\n    group.add(cheek);\n  }\n  const noseband = new Mesh(new BoxGeometry(0.1 * scale, 0.02 * scale, 0.075 * scale), leather);\n  noseband.position.set(0, -0.115 * scale, 0.19 * scale);\n  noseband.rotation.x = 0.52;\n  group.add(noseband);\n  // Bit, at the corner of the mouth.\n  const bit = new Mesh(new CylinderGeometry(0.008 * scale, 0.008 * scale, 0.12 * scale, 5), iron);\n  bit.rotation.z = Math.PI / 2;\n  bit.position.set(0, -0.16 * scale, 0.235 * scale);\n  group.add(bit);\n  // Reins, running back from the bit toward the rider's hands.\n  for (const side of [-1, 1]) {\n    const rein = new Mesh(new BoxGeometry(0.014 * scale, 0.012 * scale, 0.62 * scale), leather);\n    rein.position.set(side * 0.055 * scale, -0.05 * scale, -0.05 * scale);\n    rein.rotation.x = -0.62;\n    group.add(rein);\n  }\n\n  return { object: group, obstacleRadius: 0 };\n}\n","import {\n  BoxGeometry,\n  Color,\n  Group,\n  Mesh,\n  MeshStandardMaterial,\n  PlaneGeometry,\n  SpotLight,\n} from 'three';\nimport { Rng } from '../core/random';\nimport { DEFAULT_PALETTE, type Palette } from '../core/palette';\nimport { createSurface } from '../materials/surface';\nimport { createScreenPanel, type ScreenMode, type ScreenPanel } from '../materials/screen';\nimport type { Carryable, Prop } from '../core/types';\n\n/**\n * Electronics — the props that make an interior read as *now* rather than as\n * a period set. Everything here is a body plus a `ScreenPanel`: the panel is\n * the whole point, the chassis exists to hold it at the right height and\n * angle.\n *\n * Every one of these publishes `screen`, which is structurally ANIMA's\n * `Viewable` (a character can look at it) and GAMA's `DisplayTarget` (a\n * device can drive what it shows) — so the three libraries compose here with\n * no imports between them, the same handshake pattern as seats and ladders.\n *\n * ```ts\n * const tv = createTelevision({ diagonal: 1.4, mode: 'video' });\n * scene.add(tv.object);\n * const glow = createScreenLight(tv.screen);   // the room flickers with it\n * game.onUpdate((t) => { tv.screen.update(t.delta); glow.update(); });\n * ```\n */\nexport interface ScreenProp extends Prop {\n  /** The lit panel: gaze target, glow source, display target. */\n  screen: ScreenPanel;\n}\n\nexport interface ScreenPropOptions {\n  seed?: number;\n  /** Panel diagonal in metres. */\n  diagonal?: number;\n  /** What it shows on creation. */\n  mode?: ScreenMode;\n  /** UI accent colour. */\n  accent?: number;\n  /** Emissive gain — a television is brighter than a watch. */\n  brightness?: number;\n  /** Rows per second for 'feed'. */\n  scrollRate?: number;\n  palette?: Palette;\n}\n\n/** 16:9 from a diagonal: w = d·cos(atan(9/16)), h = d·sin(atan(9/16)). */\nfunction panelSize(diagonal: number): [number, number] {\n  return [diagonal * 0.8716, diagonal * 0.4903];\n}\n\n/** Build the lit face and wire it into the panel as its `surface`. */\nfunction attachPanel(\n  parent: Group,\n  width: number,\n  height: number,\n  options: ScreenPropOptions,\n  seedOffset = 0\n): ScreenPanel {\n  const panel = createScreenPanel(width, height, {\n    mode: options.mode ?? 'home',\n    seed: (options.seed ?? 1) + seedOffset,\n    accent: options.accent,\n    brightness: options.brightness,\n    scrollRate: options.scrollRate,\n  });\n  const mesh = new Mesh(new PlaneGeometry(width, height), panel.material);\n  mesh.name = 'screen';\n  parent.add(mesh);\n  panel.surface = mesh;\n  return panel;\n}\n\n/** Casing: the dark grey plastic/aluminium everything here is made of. */\nfunction shell(palette: Palette, tint = 0.0): MeshStandardMaterial {\n  const base = new Color(0x2b2f36).lerp(new Color(palette.metal), tint);\n  return createSurface('paintedMetal', { color: base.getHex(), roughness: 0.62 });\n}\n\n/**\n * A desk monitor. Origin at the base of the foot, so it stands on a desk\n * surface at y = 0.\n */\nexport function createMonitor(options: ScreenPropOptions = {}): ScreenProp {\n  const rng = new Rng(options.seed ?? 1);\n  const palette = options.palette ?? DEFAULT_PALETTE;\n  const diagonal = options.diagonal ?? 0.61; // 24\"\n  const [w, h] = panelSize(diagonal);\n  const casing = shell(palette);\n\n  const group = new Group();\n  group.name = 'monitor';\n\n  const foot = new Mesh(new BoxGeometry(w * 0.42, 0.014, h * 0.42), casing);\n  foot.position.y = 0.007;\n  group.add(foot);\n\n  const neck = new Mesh(new BoxGeometry(0.055, h * 0.44, 0.042), casing);\n  neck.position.set(0, h * 0.22 + 0.012, -0.01);\n  group.add(neck);\n\n  // The head tilts back a few degrees — nobody runs a monitor dead vertical.\n  const head = new Group();\n  head.position.set(0, h * 0.44 + h / 2 + 0.012, 0);\n  head.rotation.x = -rng.range(0.04, 0.09);\n  group.add(head);\n\n  const back = new Mesh(new BoxGeometry(w + 0.016, h + 0.016, 0.026), casing);\n  back.position.z = -0.014;\n  head.add(back);\n\n  const panel = attachPanel(head, w, h, options);\n  panel.surface.position.z = 0.0005;\n\n  return { object: group, obstacleRadius: 0, screen: panel };\n}\n\nexport interface TelevisionOptions extends ScreenPropOptions {\n  /**\n   * 'stand' rests on a pedestal (origin at the pedestal base — put it on a\n   * media unit); 'wall' has no support (origin at the panel's bottom edge,\n   * so you position it at the height you want it hung).\n   */\n  mount?: 'stand' | 'wall';\n}\n\n/** A television: a big thin panel, either on a pedestal or hung on a wall. */\nexport function createTelevision(options: TelevisionOptions = {}): ScreenProp {\n  const palette = options.palette ?? DEFAULT_PALETTE;\n  const diagonal = options.diagonal ?? 1.4; // 55\"\n  const mount = options.mount ?? 'stand';\n  const [w, h] = panelSize(diagonal);\n  const casing = shell(palette);\n\n  const group = new Group();\n  group.name = 'television';\n\n  let panelY = h / 2;\n  if (mount === 'stand') {\n    const plate = new Mesh(new BoxGeometry(w * 0.36, 0.016, h * 0.34), casing);\n    plate.position.y = 0.008;\n    group.add(plate);\n    const post = new Mesh(new BoxGeometry(0.09, 0.1, 0.05), casing);\n    post.position.set(0, 0.06, 0);\n    group.add(post);\n    panelY = 0.11 + h / 2;\n  }\n\n  const head = new Group();\n  head.position.y = panelY;\n  group.add(head);\n\n  // A modern set is nearly all panel: a 12 mm rim and a slightly deeper\n  // electronics hump across the lower back.\n  const bezel = new Mesh(new BoxGeometry(w + 0.024, h + 0.024, 0.016), casing);\n  bezel.position.z = -0.009;\n  head.add(bezel);\n  const hump = new Mesh(new BoxGeometry(w * 0.55, h * 0.4, 0.03), casing);\n  hump.position.set(0, -h * 0.22, -0.03);\n  head.add(hump);\n\n  const panel = attachPanel(head, w, h, { brightness: 1.15, ...options });\n  panel.surface.position.z = 0.0005;\n\n  return {\n    object: group,\n    obstacleRadius: mount === 'stand' ? w * 0.2 : 0,\n    screen: panel,\n  };\n}\n\nexport interface LaptopOptions extends ScreenPropOptions {\n  /** Lid angle: 0 shut, 1 fully open (~105°). Default 1. */\n  open?: number;\n}\n\n/**\n * A laptop. Origin at the base of the deck, so it sits on a desk at y = 0.\n * The lid hinges at the rear edge; `open` drives the angle.\n */\nexport function createLaptop(options: LaptopOptions = {}): ScreenProp {\n  const palette = options.palette ?? DEFAULT_PALETTE;\n  const diagonal = options.diagonal ?? 0.355; // 14\"\n  const [w, h] = panelSize(diagonal);\n  const open = options.open ?? 1;\n  const casing = shell(palette, 0.35);\n  const deep = new MeshStandardMaterial({ color: 0x15171c, roughness: 0.8, flatShading: true });\n\n  const group = new Group();\n  group.name = 'laptop';\n\n  const deckDepth = h * 0.94;\n  const deck = new Mesh(new BoxGeometry(w + 0.02, 0.014, deckDepth), casing);\n  deck.position.set(0, 0.007, deckDepth / 2 - h * 0.5);\n  group.add(deck);\n\n  // Keyboard well and trackpad — small dark insets, which is all that reads.\n  const keys = new Mesh(new BoxGeometry(w * 0.86, 0.002, deckDepth * 0.46), deep);\n  keys.position.set(0, 0.015, deckDepth * 0.22 - h * 0.5);\n  group.add(keys);\n  const pad = new Mesh(new BoxGeometry(w * 0.3, 0.002, deckDepth * 0.22), deep);\n  pad.position.set(0, 0.015, deckDepth * 0.72 - h * 0.5);\n  group.add(pad);\n\n  // Hinge at the deck's rear edge. The lid is built extending +y, so SHUT is\n  // +90° (it lies forward over the keyboard, screen face down) and opening\n  // rotates back through vertical to ~105° off the deck — a laptop screen\n  // leans a little past upright, it does not stand square.\n  const lid = new Group();\n  lid.position.set(0, 0.014, -h * 0.5);\n  lid.rotation.x = Math.PI / 2 - open * 1.83;\n  group.add(lid);\n\n  const back = new Mesh(new BoxGeometry(w + 0.02, h + 0.018, 0.008), casing);\n  back.position.set(0, h / 2 + 0.006, -0.005);\n  lid.add(back);\n\n  const panel = attachPanel(lid, w, h, { brightness: 0.9, ...options });\n  panel.surface.position.set(0, h / 2 + 0.006, 0);\n\n  return { object: group, obstacleRadius: 0, screen: panel };\n}\n\n/** A smart speaker with a face: fabric body, screen raked back to be read. */\nexport function createSmartDisplay(options: ScreenPropOptions = {}): ScreenProp {\n  const palette = options.palette ?? DEFAULT_PALETTE;\n  const diagonal = options.diagonal ?? 0.19;\n  const [w, h] = panelSize(diagonal);\n\n  const group = new Group();\n  group.name = 'smartDisplay';\n\n  // The speaker sits BEHIND the raked panel, not beside it. Because the\n  // screen leans back, its top edge is the furthest-back point of the face —\n  // a body flush with the base would stand in front of the top of its own\n  // screen, which is exactly the kind of thing that looks fine in a\n  // wireframe and wrong the moment it is lit.\n  const fabric = createSurface('canvas', { color: 0x6a6f78, roughness: 0.95 });\n  const body = new Mesh(new BoxGeometry(w + 0.03, h * 0.78, 0.075), fabric);\n  body.position.set(0, h * 0.39, -0.052);\n  group.add(body);\n\n  const head = new Group();\n  head.position.set(0, h * 0.55, 0.012);\n  head.rotation.x = -0.22; // raked back, the way these sit on a counter\n  group.add(head);\n\n  const rim = new Mesh(\n    new BoxGeometry(w + 0.014, h + 0.014, 0.012),\n    shell(palette, 0.2)\n  );\n  rim.position.z = -0.007;\n  head.add(rim);\n\n  const panel = attachPanel(head, w, h, { brightness: 0.75, ...options });\n  panel.surface.position.z = 0.0005;\n\n  return { object: group, obstacleRadius: 0, screen: panel };\n}\n\n/** A tablet: a screen you can pick up. Carryable + ScreenProp, no new verbs. */\nexport interface ScreenCarryable extends Carryable {\n  screen: ScreenPanel;\n}\n\n/**\n * A tablet. It is a `Carryable` with a `Screen` — which means pick-up,\n * carry-while-walking, put-down and hand-off all already work on it, from\n * the carryables track, with nothing added here.\n */\nexport function createTablet(options: ScreenPropOptions = {}): ScreenCarryable {\n  const palette = options.palette ?? DEFAULT_PALETTE;\n  const diagonal = options.diagonal ?? 0.275; // 11\"\n  const [w, h] = panelSize(diagonal);\n\n  const group = new Group();\n  group.name = 'tablet';\n\n  const back = new Mesh(new BoxGeometry(w + 0.012, h + 0.012, 0.008), shell(palette, 0.5));\n  back.position.z = -0.004;\n  group.add(back);\n\n  const panel = attachPanel(group, w, h, { brightness: 0.8, ...options });\n  panel.surface.position.z = 0.0009;\n\n  return {\n    object: group,\n    obstacleRadius: 0,\n    carry: 'tray',\n    grip: { y: 0, z: -0.01 },\n    screen: panel,\n  };\n}\n\nexport interface ScreenLightOptions {\n  /** Multiplier over the panel's own glow. Default 1. */\n  gain?: number;\n  /** Metres in front of the panel face. Default 0.04 — it emits AT the glass. */\n  distance?: number;\n  /** Falloff range. Default generous: a screen washes a whole room dimly. */\n  range?: number;\n  /** Cone half-angle, radians. Default 1.2 (~69°) — a screen is not a torch. */\n  spread?: number;\n  /** Attach to the panel surface so it tracks the prop. Default true. */\n  attach?: boolean;\n}\n\n/**\n * A real light that copies what a screen is showing.\n *\n * This is the whole reason to bother drawing content procedurally: because\n * the CPU knows the colour and level of the current shot, a light can carry\n * exactly that, and a television lights a dark room in flickers timed to its\n * own cuts. A static blue point light reads as a lamp; this reads as a TV.\n *\n * Lights are a budget, as everywhere else in SCENA — this is opt-in per\n * panel, and a room full of monitors should light one or two faces and let\n * the rest glow on their emissive alone.\n */\nexport interface ScreenLight {\n  light: SpotLight;\n  update(): void;\n}\n\nexport function createScreenLight(\n  panel: ScreenPanel,\n  options: ScreenLightOptions = {}\n): ScreenLight {\n  const gain = options.gain ?? 1;\n  const distance = options.distance ?? 0.04;\n  const diagonal = Math.hypot(panel.width, panel.height);\n  // Emission scales with AREA, not diagonal — a 55\" television puts out\n  // roughly twenty times what a tablet does, and a diagonal-based figure\n  // makes a television about twice a tablet and leaves a dark room dark.\n  const output = 3 + panel.width * panel.height * 62;\n\n  // A SPOT, not a point. This mattered more than anything else here: a point\n  // light radiates in every direction, so it lights the wall the television\n  // is standing against — 1.4 m away — five times harder than the person\n  // watching it 3.2 m away. The picture came out as a bright halo on the\n  // back wall with the viewer in shadow, which is precisely backwards.\n  //\n  // A screen only emits from its front face. A wide cone with full penumbra\n  // is a close enough stand-in for a flat Lambertian emitter at any distance\n  // you would actually sit, and unlike a RectAreaLight it needs no LTC\n  // tables (~400 KB of them) and still casts shadows if a caller wants them.\n  const light = new SpotLight(0xffffff, 0, options.range ?? Math.max(11, diagonal * 10));\n  light.name = 'screenLight';\n  light.angle = options.spread ?? 1.2;\n  light.penumbra = 1; // no visible cone edge — a screen has no beam\n  light.decay = 2;\n  light.position.z = distance;\n  // Aim it out of the glass. The target must be in the same space as the\n  // light, so it is parented alongside it rather than left at the origin.\n  light.target.position.set(0, 0, distance + 1);\n  if (options.attach !== false) {\n    panel.surface.add(light);\n    panel.surface.add(light.target);\n  }\n\n  return {\n    light,\n    update() {\n      light.color.copy(panel.glow.color);\n      light.intensity = panel.glow.intensity * gain * output;\n    },\n  };\n}\n\n/**\n * A phone. Portrait, unlike everything else here — modern handsets are about\n * 19.5:9 the tall way, and a 16:9 landscape panel scaled down reads as a\n * tiny television.\n *\n * It is a `Carryable` with a `Screen`, which means pick-up, carry, put-down\n * and hand-off already work on it. Handing someone your phone to show them a\n * photo needs no new verb: it is `handTo`.\n */\nexport function createPhone(options: ScreenPropOptions = {}): ScreenCarryable {\n  const palette = options.palette ?? DEFAULT_PALETTE;\n  const diagonal = options.diagonal ?? 0.155; // 6.1\"\n  // 19.5:9 portrait: h = d·19.5/√(19.5²+9²), w = d·9/√(…).\n  const h = diagonal * 0.9083;\n  const w = diagonal * 0.4192;\n\n  const group = new Group();\n  group.name = 'phone';\n\n  const body = new Mesh(new BoxGeometry(w + 0.005, h + 0.005, 0.008), shell(palette, 0.55));\n  body.position.z = -0.004;\n  group.add(body);\n  // The camera island, which is most of what you see of the back of a phone.\n  const camera = new Mesh(\n    new BoxGeometry(w * 0.42, w * 0.42, 0.003),\n    new MeshStandardMaterial({ color: 0x121418, roughness: 0.4, metalness: 0.5 })\n  );\n  camera.position.set(-w * 0.24, h * 0.34, -0.0095);\n  group.add(camera);\n\n  const panel = attachPanel(group, w, h, {\n    mode: 'home',\n    brightness: 0.85,\n    ...options,\n  });\n  panel.surface.position.z = 0.0009;\n\n  return {\n    object: group,\n    obstacleRadius: 0,\n    // Held in one hand out in front — the same hold the tray pose gives,\n    // scaled down. ANIMA's PhoneUse overrides the grip per pose anyway.\n    carry: 'tray',\n    grip: { z: -0.004 },\n    screen: panel,\n  };\n}\n\n/**\n * A smartwatch: the smallest screen the system draws, and a useful proof that\n * one content shader covers a 55\" television and a 40 mm watch face. Parent\n * it to an ANIMA hand socket.\n */\nexport function createSmartwatch(options: ScreenPropOptions = {}): ScreenProp {\n  const palette = options.palette ?? DEFAULT_PALETTE;\n  const size = options.diagonal ?? 0.042;\n  const w = size * 0.82;\n  const h = size;\n\n  const group = new Group();\n  group.name = 'smartwatch';\n\n  const strap = new Mesh(\n    new BoxGeometry(w * 0.78, h * 2.4, 0.006),\n    createSurface('leather', { color: 0x2c2f36, roughness: 0.85 })\n  );\n  strap.position.z = -0.007;\n  group.add(strap);\n\n  const caseBody = new Mesh(new BoxGeometry(w + 0.004, h + 0.004, 0.009), shell(palette, 0.7));\n  caseBody.position.z = -0.004;\n  group.add(caseBody);\n\n  const panel = attachPanel(group, w, h, { mode: 'chart', brightness: 0.6, ...options });\n  panel.surface.position.z = 0.0011;\n\n  return { object: group, obstacleRadius: 0, screen: panel };\n}\n","import { Color, MeshStandardMaterial, Object3D } from 'three';\n\n/**\n * Screens — the lit rectangles that make a scene read as modern.\n *\n * A screen is not a texture here. It is drawn procedurally in the fragment\n * shader from the panel's own UVs, the same way `createSurface` draws stone\n * and brick: nothing is fetched, every panel is unique, and a phone and a\n * television share one material path.\n *\n * The content is deliberately **not text**. At the size a screen occupies on\n * a monitor — a phone is a few pixels across at conversational distance —\n * you need the *impression* of an interface, not readable content: rows,\n * tiles, a scrubbing bar, a route line. Real glyphs would cost thousands of\n * triangles for something illegible, and look worse on the rare occasion the\n * camera got close enough to read them.\n *\n * ```ts\n * const panel = createScreenPanel(0.6, 0.34, { mode: 'feed' });\n * mesh.material = panel.material;\n * game.onUpdate((t) => panel.update(t.delta));\n * ```\n *\n * The content is written into **emissive radiance** rather than base colour,\n * so a screen lights up in a dark room and the day/night cycle cannot dim it\n * — a monitor at midnight is exactly as bright as one at noon, which is the\n * whole reason anyone notices screens at night.\n */\nexport type ScreenMode =\n  | 'off'\n  | 'standby'\n  | 'home'\n  | 'feed'\n  | 'video'\n  | 'map'\n  | 'chart'\n  | 'call'\n  | 'keypad';\n\n/** Mode → shader branch. Kept explicit so the GLSL never guesses. */\nconst MODE_ID: Record<ScreenMode, number> = {\n  off: 0,\n  standby: 1,\n  home: 2,\n  feed: 3,\n  video: 4,\n  map: 5,\n  chart: 6,\n  call: 7,\n  keypad: 8,\n};\n\nexport interface ScreenOptions {\n  /** What the screen is showing. Default 'home'. */\n  mode?: ScreenMode;\n  /** Varies icon colours, chart bars, the cut rhythm of video. Default 1. */\n  seed?: number;\n  /** UI accent colour (the highlighted bar, the answer pill). */\n  accent?: number;\n  /** Overall emissive gain. Default 1. Dim a phone, brighten a TV wall. */\n  brightness?: number;\n  /** Rows scrolled per second in 'feed'. Default 0 (a still screen). */\n  scrollRate?: number;\n}\n\n/**\n * A lit panel. Structurally what ANIMA's `Viewable` wants (`surface`,\n * `width`, `height`) so a character can look at one, and what GAMA's\n * `DisplayTarget` wants (`setMode`) so a device can drive one — with no\n * library importing another.\n */\nexport interface ScreenPanel {\n  /** The lit face. Set by the prop that owns it; the gaze target. */\n  surface: Object3D;\n  /** Panel size in metres. */\n  width: number;\n  height: number;\n  material: MeshStandardMaterial;\n  readonly mode: ScreenMode;\n  setMode(mode: ScreenMode): void;\n  /**\n   * What this screen is throwing into the room right now — colour and\n   * strength, updated every frame. A light that copies these flickers in\n   * time with the content, which is the difference between a television and\n   * a blue lamp.\n   */\n  readonly glow: { color: Color; intensity: number };\n  update(dt: number): void;\n}\n\n// --- the shader ---------------------------------------------------------\n//\n// GLSL ES 1.00 (three patches the standard chunks, which are GLSL1): no\n// `switch`, constant loop bounds only. Layout is done in UV space 0..1 with\n// x converted to y-units wherever roundness or squareness matters, so a\n// 16:9 panel's icons are square and its corners are round.\n\nconst SCREEN_HELPERS = /* glsl */ `\n  float scrHash(vec2 p) {\n    return fract(sin(dot(p, vec2(127.1, 311.7))) * 43758.5453123);\n  }\n  vec3 scrHue(float h) {\n    return 0.5 + 0.5 * cos(6.28318 * (h + vec3(0.0, 0.33, 0.67)));\n  }\n  float scrBand(float v, float lo, float hi) {\n    return step(lo, v) * step(v, hi);\n  }\n  // Rounded rect coverage. c/h in UV space, r in y-units.\n  float scrRound(vec2 uv, vec2 c, vec2 h, float r, float aspect) {\n    vec2 q = uv - c;\n    q.x *= aspect;\n    vec2 hh = vec2(h.x * aspect, h.y);\n    vec2 d = abs(q) - hh + r;\n    float dist = length(max(d, 0.0)) + min(max(d.x, d.y), 0.0) - r;\n    return 1.0 - smoothstep(0.0, 0.006, dist);\n  }\n  float scrSeg(vec2 p, vec2 a, vec2 b, float aspect) {\n    vec2 pa = p - a; vec2 ba = b - a;\n    pa.x *= aspect; ba.x *= aspect;\n    float h = clamp(dot(pa, ba) / max(dot(ba, ba), 1e-5), 0.0, 1.0);\n    return length(pa - ba * h);\n  }\n`;\n\nconst SCREEN_MODES = /* glsl */ `\n  // A phone/desktop home screen: status strip, a grid of app tiles, a dock.\n  vec3 scrHome(vec2 uv, float t, float seed, float aspect, vec3 accent) {\n    vec3 col = mix(vec3(0.03, 0.05, 0.11), vec3(0.07, 0.06, 0.15), uv.y);\n    // Status strip: a clock block left, two indicator pips right.\n    float bar = scrBand(uv.y, 0.945, 0.972);\n    col += vec3(0.55) * bar * (scrBand(uv.x, 0.06, 0.16) + scrBand(uv.x, 0.82, 0.94));\n    // 4 x 5 tile grid.\n    vec2 g = vec2(uv.x * 4.0, (uv.y - 0.17) / 0.155);\n    vec2 cell = floor(g);\n    if (uv.y > 0.17 && uv.y < 0.92) {\n      float id = scrHash(cell + seed);\n      float tile = scrRound(fract(g) - 0.5, vec2(0.0), vec2(0.30, 0.30), 0.09, aspect / 4.0 * 0.155 * 4.0);\n      col += scrHue(id) * tile * 0.85;\n      // A notification pip on one tile in six.\n      col += vec3(1.0, 0.25, 0.2) * step(0.84, id) * scrRound(fract(g) - vec2(0.78, 0.78), vec2(0.0), vec2(0.07, 0.07), 0.07, 1.0);\n    }\n    // Dock: a translucent slab holding four tiles.\n    float dock = scrRound(uv, vec2(0.5, 0.085), vec2(0.44, 0.062), 0.03, aspect);\n    col += vec3(0.10, 0.12, 0.20) * dock;\n    vec2 dg = vec2(uv.x * 4.0, 0.0);\n    if (uv.y > 0.035 && uv.y < 0.135) {\n      float did = scrHash(vec2(floor(dg.x), 9.0) + seed);\n      col += scrHue(did) * scrRound(vec2(fract(dg.x), uv.y) - vec2(0.5, 0.085), vec2(0.0), vec2(0.16, 0.036), 0.02, aspect / 4.0) * 0.9;\n    }\n    return col + accent * 0.04;\n  }\n\n  // The scrolling list everyone actually looks at: thumbnail, two text bars.\n  vec3 scrFeed(vec2 uv, float scroll, float seed, float aspect, vec3 accent) {\n    vec3 col = vec3(0.02, 0.025, 0.045);\n    float rowH = 0.235;\n    float fy = (uv.y + scroll) / rowH;\n    float row = floor(fy);\n    float ry = fract(fy);\n    float id = scrHash(vec2(row, seed));\n    if (uv.y < 0.93) {\n      // Card body.\n      col += vec3(0.055, 0.065, 0.10) * scrRound(vec2(uv.x, ry), vec2(0.5, 0.5), vec2(0.455, 0.40), 0.04, aspect * rowH);\n      // Thumbnail block, hue per row.\n      col += scrHue(id) * 0.75 * scrRound(vec2(uv.x, ry), vec2(0.16, 0.5), vec2(0.09, 0.30), 0.03, aspect * rowH);\n      // Two text bars: a long title and a short byline.\n      float w = 0.24 + id * 0.26;\n      col += vec3(0.62) * scrBand(ry, 0.55, 0.66) * scrBand(uv.x, 0.30, 0.30 + w);\n      col += vec3(0.30) * scrBand(ry, 0.36, 0.45) * scrBand(uv.x, 0.30, 0.30 + w * 0.55);\n      // Every fourth card carries the accent (a \"sponsored\" tint).\n      col += accent * 0.5 * step(0.88, id) * scrRound(vec2(uv.x, ry), vec2(0.86, 0.5), vec2(0.05, 0.16), 0.02, aspect * rowH);\n    }\n    // Fixed header above the scroll.\n    col += vec3(0.09, 0.10, 0.16) * scrBand(uv.y, 0.93, 1.0);\n    col += accent * 0.8 * scrBand(uv.y, 0.955, 0.978) * scrBand(uv.x, 0.06, 0.30);\n    return col;\n  }\n\n  // Video: letterboxed, soft moving fields, colour set by the CPU so the cuts\n  // and the light in the room are the same event.\n  vec3 scrVideo(vec2 uv, float t, float aspect, vec3 a, vec3 b) {\n    float inside = scrBand(uv.y, 0.13, 0.87);\n    vec2 p = uv - vec2(0.5);\n    p.x *= aspect;\n    // Two drifting blobs over a gradient — enough parallax to read as motion.\n    float d1 = length(p - vec2(sin(t * 0.7) * 0.28, cos(t * 0.53) * 0.14));\n    float d2 = length(p - vec2(cos(t * 0.41) * 0.34, sin(t * 0.9) * 0.10));\n    vec3 col = mix(a, b, clamp(uv.y * 1.2 - 0.1, 0.0, 1.0));\n    // Broad, overlapping washes rather than two tight spots — a tight\n    // falloff puts a single hot dot in the middle of the picture, which\n    // reads as a torch pointed at the wall, not as footage.\n    col += a * 0.30 * smoothstep(0.80, 0.06, d1);\n    col += b * 0.26 * smoothstep(0.68, 0.04, d2);\n    // A horizon: cooler above, warmer below. Almost any real frame has one,\n    // and without it the picture is a lava lamp.\n    col *= mix(vec3(1.06, 1.0, 0.92), vec3(0.72, 0.82, 1.0), smoothstep(0.4, 0.62, uv.y));\n    // Scanline-ish texture, very faint: sells \"screen\" over \"painted panel\".\n    col *= 0.93 + 0.07 * sin(uv.y * 420.0);\n    // The shot's own level, so a cut to a dark scene darkens the PICTURE and\n    // not merely the lamp in the room. Scaled to sit below clipping: emissive\n    // at 1.0 is pure white after tone mapping, which is a lightbox, not a\n    // television.\n    return col * inside * uScrLevel * 0.58;\n  }\n\n  // Navigation: a road grid, an arterial, a route, and you.\n  vec3 scrMap(vec2 uv, float t, float seed, float aspect, vec3 accent) {\n    vec3 col = vec3(0.055, 0.075, 0.075);\n    vec2 p = vec2(uv.x * aspect, uv.y);\n    // Minor grid.\n    vec2 gg = abs(fract(p * 7.0 + seed * 0.1) - 0.5);\n    float roads = (1.0 - smoothstep(0.0, 0.06, gg.x)) + (1.0 - smoothstep(0.0, 0.06, gg.y));\n    col += vec3(0.12, 0.13, 0.14) * clamp(roads, 0.0, 1.0);\n    // Two arterials.\n    col += vec3(0.22, 0.21, 0.18) * (1.0 - smoothstep(0.0, 0.02, abs(uv.y - 0.62)));\n    col += vec3(0.22, 0.21, 0.18) * (1.0 - smoothstep(0.0, 0.02, abs(uv.x - 0.38)));\n    // The route: three segments in the accent, thick and bright.\n    float r = min(\n      min(scrSeg(uv, vec2(0.20, 0.16), vec2(0.38, 0.42), aspect),\n          scrSeg(uv, vec2(0.38, 0.42), vec2(0.38, 0.62), aspect)),\n      scrSeg(uv, vec2(0.38, 0.62), vec2(0.78, 0.80), aspect));\n    col += accent * (1.0 - smoothstep(0.008, 0.022, r)) * 1.2;\n    // Position dot with a breathing accuracy halo.\n    float dot0 = length((uv - vec2(0.20, 0.16)) * vec2(aspect, 1.0));\n    col += vec3(0.35, 0.7, 1.0) * (1.0 - smoothstep(0.012, 0.02, dot0));\n    col += vec3(0.2, 0.45, 0.8) * (1.0 - smoothstep(0.03, 0.075, dot0)) * (0.25 + 0.15 * sin(t * 2.2));\n    return col;\n  }\n\n  // A dashboard: gridlines and a bar series, one column called out.\n  vec3 scrChart(vec2 uv, float t, float seed, float aspect, vec3 accent) {\n    vec3 col = vec3(0.035, 0.04, 0.06);\n    col += vec3(0.08) * scrBand(uv.y, 0.92, 1.0);\n    // Horizontal gridlines.\n    float grid = 1.0 - smoothstep(0.0, 0.004, abs(fract(uv.y * 5.0) - 0.5) * 0.2);\n    col += vec3(0.07, 0.08, 0.11) * grid * scrBand(uv.y, 0.12, 0.88);\n    // Bars.\n    float col0 = floor(uv.x * 9.0);\n    float h = 0.16 + 0.62 * scrHash(vec2(col0, seed));\n    float bar = scrBand(fract(uv.x * 9.0), 0.18, 0.82) * scrBand(uv.y, 0.12, 0.12 + h);\n    float hot = step(6.0, col0) * step(col0, 6.0);\n    col += mix(vec3(0.25, 0.45, 0.75), accent, hot) * bar;\n    // A moving read-head, because dashboards are never still.\n    col += accent * 0.5 * (1.0 - smoothstep(0.0, 0.006, abs(uv.x - fract(t * 0.13))));\n    return col;\n  }\n\n  // An incoming call: avatar, name plate, decline and answer.\n  vec3 scrCall(vec2 uv, float t, float seed, float aspect, vec3 accent) {\n    vec3 col = vec3(0.04, 0.05, 0.09);\n    float d = length((uv - vec2(0.5, 0.66)) * vec2(aspect, 1.0));\n    col += scrHue(scrHash(vec2(seed, 3.0))) * 0.8 * (1.0 - smoothstep(0.15, 0.16, d));\n    // Ring pulse radiating off the avatar.\n    float pulse = fract(t * 0.7);\n    col += accent * 0.35 * (1.0 - smoothstep(0.006, 0.02, abs(d - 0.16 - pulse * 0.16))) * (1.0 - pulse);\n    // Name plate.\n    col += vec3(0.55) * scrBand(uv.y, 0.40, 0.435) * scrBand(uv.x, 0.30, 0.70);\n    col += vec3(0.25) * scrBand(uv.y, 0.34, 0.365) * scrBand(uv.x, 0.38, 0.62);\n    // Decline / answer.\n    col += vec3(0.85, 0.15, 0.15) * scrRound(uv, vec2(0.30, 0.15), vec2(0.10, 0.055), 0.05, aspect);\n    col += vec3(0.15, 0.80, 0.35) * scrRound(uv, vec2(0.70, 0.15), vec2(0.10, 0.055), 0.05, aspect)\n           * (0.75 + 0.25 * sin(t * 6.0));\n    return col;\n  }\n\n  // A PIN pad — for the terminals, door locks and ATMs this sets up.\n  vec3 scrKeypad(vec2 uv, float t, float seed, float aspect, vec3 accent) {\n    vec3 col = vec3(0.03, 0.04, 0.05);\n    // Entry strip with masked digits.\n    col += vec3(0.09, 0.11, 0.13) * scrRound(uv, vec2(0.5, 0.87), vec2(0.40, 0.06), 0.02, aspect);\n    float typed = floor(mod(t * 0.8, 5.0));\n    float slot = floor((uv.x - 0.34) * 12.5);\n    float dotm = scrRound(vec2(fract((uv.x - 0.34) * 12.5), uv.y), vec2(0.5, 0.87), vec2(0.16, 0.016), 0.016, aspect / 12.5);\n    col += accent * dotm * step(0.0, slot) * step(slot, typed - 1.0) * scrBand(uv.x, 0.34, 0.66);\n    // 3 x 4 keys.\n    vec2 k = vec2((uv.x - 0.17) / 0.22, (uv.y - 0.06) / 0.185);\n    if (uv.x > 0.17 && uv.x < 0.83 && uv.y > 0.06 && uv.y < 0.80) {\n      vec2 kc = floor(k);\n      float lit = step(0.5, scrHash(vec2(kc.x + kc.y * 3.0, floor(t * 1.6) + seed)));\n      float key = scrRound(fract(k) - 0.5, vec2(0.0), vec2(0.36, 0.34), 0.06, aspect * 0.22 / 0.185);\n      col += mix(vec3(0.14, 0.16, 0.19), accent * 0.8, lit * 0.35) * key;\n    }\n    return col;\n  }\n`;\n\nconst SCREEN_FRAG = /* glsl */ `\n  {\n    vec2 scrUv = vUv;\n    vec3 scrCol = vec3(0.0);\n    if (uScrMode == 1) {\n      // Standby: one breathing pip, low in the corner. Everything else dark.\n      float d = length((scrUv - vec2(0.93, 0.07)) * vec2(uScrAspect, 1.0));\n      scrCol = uScrAccent * (1.0 - smoothstep(0.008, 0.014, d)) * (0.35 + 0.3 * sin(uScrTime * 1.6));\n    } else if (uScrMode == 2) {\n      scrCol = scrHome(scrUv, uScrTime, uScrSeed, uScrAspect, uScrAccent);\n    } else if (uScrMode == 3) {\n      scrCol = scrFeed(scrUv, uScrScroll, uScrSeed, uScrAspect, uScrAccent);\n    } else if (uScrMode == 4) {\n      scrCol = scrVideo(scrUv, uScrTime, uScrAspect, uScrShotA, uScrShotB);\n    } else if (uScrMode == 5) {\n      scrCol = scrMap(scrUv, uScrTime, uScrSeed, uScrAspect, uScrAccent);\n    } else if (uScrMode == 6) {\n      scrCol = scrChart(scrUv, uScrTime, uScrSeed, uScrAspect, uScrAccent);\n    } else if (uScrMode == 7) {\n      scrCol = scrCall(scrUv, uScrTime, uScrSeed, uScrAspect, uScrAccent);\n    } else if (uScrMode == 8) {\n      scrCol = scrKeypad(scrUv, uScrTime, uScrSeed, uScrAspect, uScrAccent);\n    }\n    // Written into radiance directly, NOT material.emissive, so the day/night\n    // cycle's emissiveIntensity scaling cannot dim a screen. A monitor at\n    // midnight is as bright as one at noon — that is the point of a screen.\n    totalEmissiveRadiance += scrCol * uScrBright;\n  }\n`;\n\n// --- the CPU half ------------------------------------------------------\n\n/** Per-mode resting glow: what the panel throws into the room. */\nconst MODE_GLOW: Record<ScreenMode, { color: number; intensity: number }> = {\n  off: { color: 0x000000, intensity: 0 },\n  standby: { color: 0x33ff88, intensity: 0.03 },\n  home: { color: 0x8fa6ff, intensity: 0.55 },\n  feed: { color: 0xcfd8ff, intensity: 0.7 },\n  video: { color: 0xffffff, intensity: 1.0 }, // overridden per shot\n  map: { color: 0x7fd0c0, intensity: 0.5 },\n  chart: { color: 0x6fa0e0, intensity: 0.45 },\n  call: { color: 0x9fd8ff, intensity: 0.65 },\n  keypad: { color: 0x7fc0d8, intensity: 0.35 },\n};\n\n/**\n * A shot list: the cuts a \"playing\" screen runs through. Durations vary\n * because real edits are not metronomic — a fixed cut length reads as a\n * strobe, and the room lighting gives it away long before the picture does.\n */\ninterface Shot {\n  at: number;\n  a: Color;\n  b: Color;\n  level: number;\n}\n\nfunction buildShots(seed: number, count = 48): Shot[] {\n  let s = (seed * 2654435761) >>> 0;\n  const rand = (): number => {\n    s = (s + 0x6d2b79f5) >>> 0;\n    let t = Math.imul(s ^ (s >>> 15), 1 | s);\n    t = (t + Math.imul(t ^ (t >>> 7), 61 | t)) ^ t;\n    return ((t ^ (t >>> 14)) >>> 0) / 4294967296;\n  };\n  const shots: Shot[] = [];\n  let at = 0;\n  for (let i = 0; i < count; i++) {\n    // Most cuts are short; a few hold. Squaring biases toward the short end.\n    const hold = 0.55 + Math.pow(rand(), 2) * 3.4;\n    const hue = rand();\n    // Mostly desaturated. Real footage is skin, sky, concrete and cloth; a\n    // run of fully saturated hues lights the room like a nightclub. Squaring\n    // keeps most shots muted and lets the occasional vivid one through.\n    const sat = 0.1 + Math.pow(rand(), 2) * 0.5;\n    const warm = new Color().setHSL(hue, sat, 0.52);\n    const cool = new Color().setHSL((hue + 0.1 + rand() * 0.16) % 1, sat * 0.8, 0.3);\n    shots.push({ at, a: warm, b: cool, level: 0.45 + rand() * 0.85 });\n    at += hold;\n  }\n  return shots;\n}\n\nexport interface ScreenPanelOptions extends ScreenOptions {\n  /** Aspect override. Defaults to width / height. */\n  aspect?: number;\n}\n\n/**\n * Build a screen's material and its live state. Callers own the mesh — the\n * panel only needs to know how big it is so its UI lays out square.\n */\nexport function createScreenPanel(\n  width: number,\n  height: number,\n  options: ScreenPanelOptions = {}\n): ScreenPanel {\n  const seed = options.seed ?? 1;\n  const aspect = options.aspect ?? width / Math.max(height, 1e-4);\n  const accent = new Color(options.accent ?? 0x4d9fff);\n  const brightness = options.brightness ?? 1;\n  const scrollRate = options.scrollRate ?? 0;\n  let mode: ScreenMode = options.mode ?? 'home';\n\n  const uniforms = {\n    uScrMode: { value: MODE_ID[mode] },\n    uScrTime: { value: 0 },\n    uScrSeed: { value: seed },\n    uScrAspect: { value: aspect },\n    uScrAccent: { value: accent.clone() },\n    uScrBright: { value: brightness },\n    uScrScroll: { value: 0 },\n    uScrShotA: { value: new Color(0.6, 0.6, 0.6) },\n    uScrShotB: { value: new Color(0.2, 0.2, 0.3) },\n    uScrLevel: { value: 1 },\n  };\n\n  // A powered-off screen is not black — it is a dark mirror. Low roughness\n  // over a near-black base gives the reflection that reads as glass.\n  const material = new MeshStandardMaterial({\n    color: 0x080a0e,\n    roughness: 0.18,\n    metalness: 0.35,\n  });\n  // Force vUv: without a map three omits the varying, and the whole UI is\n  // laid out in UV space.\n  material.defines = { ...(material.defines ?? {}), USE_UV: '' };\n  material.onBeforeCompile = (shader) => {\n    Object.assign(shader.uniforms, uniforms);\n    shader.fragmentShader = shader.fragmentShader\n      .replace(\n        'void main() {',\n        `uniform int uScrMode;\n         uniform float uScrTime;\n         uniform float uScrSeed;\n         uniform float uScrAspect;\n         uniform vec3 uScrAccent;\n         uniform float uScrBright;\n         uniform float uScrScroll;\n         uniform vec3 uScrShotA;\n         uniform vec3 uScrShotB;\n         uniform float uScrLevel;\n         ${SCREEN_HELPERS}\n         ${SCREEN_MODES}\n         void main() {`\n      )\n      .replace('#include <emissivemap_fragment>', `#include <emissivemap_fragment>\\n${SCREEN_FRAG}`);\n  };\n  // Distinct cache key per mode set, so two panels showing different things\n  // do not share a compiled program keyed only on material properties.\n  material.customProgramCacheKey = () => 'scenaScreen';\n\n  const shots = buildShots(seed);\n  const loop = shots[shots.length - 1].at;\n  const glow = { color: new Color(0, 0, 0), intensity: 0 };\n  let time = 0;\n  let scroll = 0;\n\n  const applyGlow = (): void => {\n    if (mode === 'video') {\n      // Find the current shot. Cheap linear scan over a small list, and it\n      // must be the SAME shot the shader is drawing — which it is, because\n      // the CPU pushes the shot colours in as uniforms rather than the\n      // shader picking its own. Light and picture cannot drift apart.\n      const t = time % loop;\n      let i = 0;\n      while (i + 1 < shots.length && shots[i + 1].at <= t) i++;\n      const shot = shots[i];\n      uniforms.uScrShotA.value.copy(shot.a);\n      uniforms.uScrShotB.value.copy(shot.b);\n      // Within a shot the level drifts a little (the camera moves, the\n      // picture breathes); at the cut it steps. That step is the flicker.\n      const into = t - shot.at;\n      const drift = 1 + 0.12 * Math.sin(into * 2.3 + shot.level * 6.0);\n      uniforms.uScrLevel.value = shot.level * drift;\n      glow.color.copy(shot.a).lerp(shot.b, 0.35);\n      glow.intensity = shot.level * drift * brightness;\n    } else {\n      uniforms.uScrLevel.value = 1;\n      const preset = MODE_GLOW[mode];\n      glow.color.set(preset.color);\n      glow.intensity = preset.intensity * brightness;\n    }\n  };\n  applyGlow();\n\n  return {\n    surface: new Object3D(), // replaced by the owning prop\n    width,\n    height,\n    material,\n    get mode() {\n      return mode;\n    },\n    setMode(next: ScreenMode) {\n      if (next === mode) return;\n      mode = next;\n      uniforms.uScrMode.value = MODE_ID[next];\n      applyGlow();\n    },\n    glow,\n    update(dt: number) {\n      time += dt;\n      uniforms.uScrTime.value = time;\n      if (mode === 'feed' && scrollRate !== 0) {\n        scroll += dt * scrollRate * 0.235;\n        uniforms.uScrScroll.value = scroll;\n      }\n      applyGlow();\n    },\n  };\n}\n","import {\n  BoxGeometry,\n  Color,\n  Group,\n  Mesh,\n  MeshStandardMaterial,\n  Object3D,\n  PlaneGeometry,\n} from 'three';\nimport { Rng } from '../core/random';\nimport { DEFAULT_PALETTE, type Palette } from '../core/palette';\nimport { createSurface } from '../materials/surface';\nimport { createScreenPanel, type ScreenMode, type ScreenPanel } from '../materials/screen';\nimport { addApproach, createSlot, type Prop, type PropSlot } from '../core/types';\n\n/**\n * Terminals — the machines you have to queue for.\n *\n * These are the first props in the kit that a character does not simply walk\n * up to and use: there may already be somebody at it, and a second person has\n * to wait. So besides the usual slot, every terminal publishes a **line** —\n * an anchor at the head of the queue, with the queue running back along its\n * local -z.\n *\n * ```ts\n * const atm = createTerminal({ style: 'atm' });\n * const queue = new Queue({ service: 14, spacing: atm.spacing });\n * // distance from GAMA's Queue -> a world position on the line\n * const at = atm.line.localToWorld(new Vector3(0, 0, -queue.distanceOf(person)));\n * ```\n *\n * That pairing is the whole handshake: SCENA says where the line is, GAMA\n * says who is where along it, and neither imports the other.\n */\nexport interface Terminal extends Prop {\n  /** The machine's display. */\n  screen: ScreenPanel;\n  /** Where the user stands to operate it. */\n  slot: PropSlot;\n  /**\n   * Head of the queue. The line runs BACK along this anchor's local -z, so a\n   * distance `d` from a queue maps to `line.localToWorld(new Vector3(0,0,-d))`.\n   * It faces the machine, so a character copying its rotation faces the right\n   * way while they wait.\n   */\n  line: Object3D;\n  /** Suggested metres between people in the line. */\n  spacing: number;\n}\n\nexport type TerminalStyle = 'atm' | 'kiosk' | 'vending';\n\nexport interface TerminalOptions {\n  style?: TerminalStyle;\n  seed?: number;\n  /** What the display shows. Defaults suit the style (an ATM shows a keypad). */\n  mode?: ScreenMode;\n  palette?: Palette;\n  /** Metres between people queueing. Default 0.62. */\n  spacing?: number;\n}\n\nconst DEFAULT_MODE: Record<TerminalStyle, ScreenMode> = {\n  atm: 'keypad',\n  kiosk: 'map',\n  vending: 'home',\n};\n\nfunction shell(palette: Palette, tint: number, rough = 0.55): MeshStandardMaterial {\n  // Light grey, deliberately. Started near-black, which looked fine as a\n  // colour swatch and rendered outdoors as a featureless black slab — none\n  // of the hood, shelf or slots that say \"cash machine\" survived. Public\n  // machines are pale for exactly this reason: they have to read at a\n  // glance from across a concourse.\n  const base = new Color(0xa8b0b8).lerp(new Color(palette.metal), tint * 0.5);\n  return createSurface('paintedMetal', { color: base.getHex(), roughness: rough });\n}\n\n/**\n * A machine with a screen, a place to stand, and a queue behind it.\n *\n * - `atm` — a wall unit with a hooded screen at eye height and a keypad shelf.\n * - `kiosk` — a freestanding pillar with the screen raked back to be read\n *   standing over it.\n * - `vending` — a glass-fronted cabinet with a small screen and a delivery\n *   flap at knee height.\n */\nexport function createTerminal(options: TerminalOptions = {}): Terminal {\n  const style = options.style ?? 'atm';\n  const seed = options.seed ?? 1;\n  const rng = new Rng(seed);\n  const palette = options.palette ?? DEFAULT_PALETTE;\n  const spacing = options.spacing ?? 0.62;\n  const mode = options.mode ?? DEFAULT_MODE[style];\n\n  const group = new Group();\n  group.name = `terminal-${style}`;\n  const body = shell(palette, 0.25);\n  const dark = new MeshStandardMaterial({ color: 0x1a1d23, roughness: 0.75, flatShading: true });\n\n  let screen: ScreenPanel;\n  let standAt = 0.85;\n  let radius = 0.5;\n\n  if (style === 'atm') {\n    // A cash machine reads from its hood and its two slots. The screen is\n    // set BACK under the hood — that recess is most of what says \"ATM\".\n    const cabinet = new Mesh(new BoxGeometry(0.92, 1.95, 0.34), body);\n    cabinet.position.set(0, 0.975, -0.17);\n    group.add(cabinet);\n\n    const hood = new Mesh(new BoxGeometry(0.98, 0.06, 0.26), shell(palette, 0.1));\n    hood.position.set(0, 1.62, 0.12);\n    group.add(hood);\n    for (const s of [-1, 1]) {\n      const cheek = new Mesh(new BoxGeometry(0.05, 0.34, 0.26), shell(palette, 0.1));\n      cheek.position.set(s * 0.465, 1.45, 0.12);\n      group.add(cheek);\n    }\n\n    const face = new Group();\n    face.position.set(0, 1.42, 0.005);\n    face.rotation.x = -0.18; // raked so a standing adult reads it\n    group.add(face);\n    screen = createScreenPanel(0.32, 0.24, { mode, seed, brightness: 0.9, accent: 0x59b0ff });\n    const panel = new Mesh(new PlaneGeometry(0.32, 0.24), screen.material);\n    panel.name = 'screen';\n    face.add(panel);\n    screen.surface = panel;\n\n    // Keypad shelf, card slot, cash slot — the three things hands go to.\n    const shelf = new Mesh(new BoxGeometry(0.62, 0.04, 0.22), shell(palette, 0.35));\n    shelf.position.set(0, 1.06, 0.1);\n    shelf.rotation.x = -0.3;\n    group.add(shelf);\n    const keys = new Mesh(new BoxGeometry(0.3, 0.012, 0.16), dark);\n    keys.position.set(-0.1, 1.09, 0.11);\n    keys.rotation.x = -0.3;\n    group.add(keys);\n    const card = new Mesh(new BoxGeometry(0.11, 0.02, 0.03), dark);\n    card.position.set(0.3, 1.2, 0.17);\n    group.add(card);\n    const cash = new Mesh(new BoxGeometry(0.26, 0.03, 0.03), dark);\n    cash.position.set(0, 0.86, 0.17);\n    group.add(cash);\n    standAt = 0.72;\n    radius = 0.55;\n  } else if (style === 'kiosk') {\n    const plinth = new Mesh(new BoxGeometry(0.66, 0.09, 0.5), shell(palette, 0.4));\n    plinth.position.set(0, 0.045, 0);\n    group.add(plinth);\n    const post = new Mesh(new BoxGeometry(0.5, 1.02, 0.3), body);\n    post.position.set(0, 0.6, -0.05);\n    group.add(post);\n\n    const face = new Group();\n    face.position.set(0, 1.18, 0.02);\n    face.rotation.x = -0.55; // a kiosk is read from above, so it lies well back\n    group.add(face);\n    screen = createScreenPanel(0.42, 0.3, { mode, seed, brightness: 0.95, accent: 0x4de0b0 });\n    const panel = new Mesh(new PlaneGeometry(0.42, 0.3), screen.material);\n    panel.name = 'screen';\n    face.add(panel);\n    screen.surface = panel;\n    const rim = new Mesh(new BoxGeometry(0.5, 0.38, 0.07), shell(palette, 0.15));\n    rim.position.set(0, 1.16, -0.03);\n    rim.rotation.x = -0.55;\n    group.add(rim);\n    standAt = 0.65;\n    radius = 0.42;\n  } else {\n    // Vending: a lit cabinet of goods, which is the point of it, plus a\n    // small screen and a flap you bend down to.\n    const cabinet = new Mesh(new BoxGeometry(1.02, 1.92, 0.72), body);\n    cabinet.position.set(0, 0.96, -0.36);\n    group.add(cabinet);\n    const glass = new Mesh(new BoxGeometry(0.82, 1.3, 0.02), new MeshStandardMaterial({\n      color: 0x9fd0e0,\n      roughness: 0.1,\n      metalness: 0.1,\n      transparent: true,\n      opacity: 0.3,\n    }));\n    glass.position.set(-0.06, 1.16, 0.005);\n    group.add(glass);\n    // Rows of product, seeded so no two machines are stocked alike.\n    for (let row = 0; row < 5; row++) {\n      for (let col = 0; col < 4; col++) {\n        const item = new Mesh(\n          new BoxGeometry(0.13, 0.16, 0.09),\n          new MeshStandardMaterial({\n            color: new Color().setHSL(rng.next(), 0.55, 0.5).getHex(),\n            roughness: 0.6,\n            flatShading: true,\n          })\n        );\n        item.position.set(-0.36 + col * 0.2, 0.62 + row * 0.24, -0.1);\n        // A machine is never quite full.\n        if (rng.next() > 0.12) group.add(item);\n      }\n    }\n    screen = createScreenPanel(0.2, 0.14, { mode, seed, brightness: 0.8, accent: 0xffb54d });\n    const panel = new Mesh(new PlaneGeometry(0.2, 0.14), screen.material);\n    panel.name = 'screen';\n    panel.position.set(0.37, 1.52, 0.008);\n    group.add(panel);\n    screen.surface = panel;\n    const flap = new Mesh(new BoxGeometry(0.42, 0.16, 0.03), dark);\n    flap.position.set(-0.06, 0.36, 0.005);\n    group.add(flap);\n    standAt = 0.78;\n    radius = 0.62;\n  }\n\n  // Where the user stands: in front, facing the machine. Slot anchors face\n  // their own +z, so a user at +z facing the machine at the origin is turned\n  // through half a turn.\n  const slot = createSlot('operate', 'stand', group, 0, 0, standAt, Math.PI);\n  addApproach(slot, group, 0.55, 'behind');\n\n  // The head of the queue sits just behind the user, facing the same way, and\n  // the line runs back along its -z (which, turned around, is away from the\n  // machine).\n  const line = new Object3D();\n  line.name = 'queue';\n  line.position.set(0, 0, standAt + 0.28);\n  line.rotation.y = Math.PI;\n  group.add(line);\n\n  return { object: group, obstacleRadius: radius, screen, slot, slots: [slot], line, spacing };\n}\n","import {\n  BoxGeometry,\n  Color,\n  CylinderGeometry,\n  Group,\n  Mesh,\n  MeshStandardMaterial,\n  Object3D,\n  PlaneGeometry,\n} from 'three';\nimport { Rng } from '../core/random';\nimport { DEFAULT_PALETTE, type Palette } from '../core/palette';\nimport { createSurface } from '../materials/surface';\nimport { createScreenPanel, type ScreenPanel } from '../materials/screen';\nimport { createSlot, type Prop, type PropSlot } from '../core/types';\n\n/**\n * Fixtures — the small wall-mounted things a smart home is made of.\n *\n * These are deliberately tiny. A switch is 8 cm across and a sensor smaller\n * than that, so almost none of the modelling budget goes on shape: what makes\n * them read is the **indicator** — a single lit pip whose colour says what the\n * device thinks is happening. That pip is the whole prop at any honest camera\n * distance, which is why every one of these publishes `setIndicator`.\n *\n * ```ts\n * const sensor = createFixture({ style: 'sensor' });\n * home.on('motion', (v) => sensor.setIndicator(v > 0.5 ? 0x44ff88 : 0x223026));\n * ```\n */\nexport interface Fixture extends Prop {\n  /** Set the indicator colour, and how hard it burns (0 = dark). */\n  setIndicator(color: number, strength?: number): void;\n  /** The panel, on the fixtures that carry one (thermostat only). */\n  screen?: ScreenPanel;\n  /** Where a character stands to reach it, on the ones you touch. */\n  slot?: PropSlot;\n  /** The mounting height this was built for, in metres. */\n  height: number;\n}\n\nexport type FixtureStyle = 'switch' | 'thermostat' | 'doorbell' | 'camera' | 'sensor';\n\nexport interface FixtureOptions {\n  style?: FixtureStyle;\n  seed?: number;\n  palette?: Palette;\n  /** Indicator colour to start with. */\n  indicator?: number;\n}\n\n/**\n * A wall fixture. The origin is at the **wall face**, with the device facing\n * +z — so parenting it to a wall and pushing it to the right height is the\n * whole placement job.\n *\n * - `switch` — a rocker plate at hand height, with a slot to stand at.\n * - `thermostat` — a small round dial with a screen in it.\n * - `doorbell` — a button with a bright ring, up beside a door.\n * - `camera` — a stub body angled down, with a lens and a status pip.\n * - `sensor` — a corner-mounted wedge; the smallest thing in the kit.\n */\nexport function createFixture(options: FixtureOptions = {}): Fixture {\n  const style = options.style ?? 'switch';\n  const seed = options.seed ?? 1;\n  const rng = new Rng(seed);\n  const palette = options.palette ?? DEFAULT_PALETTE;\n\n  const group = new Group();\n  group.name = `fixture-${style}`;\n  const plastic = createSurface('paintedMetal', {\n    color: new Color(0xe8eaec).lerp(new Color(palette.wall), 0.25).getHex(),\n    roughness: 0.55,\n  });\n  const dark = new MeshStandardMaterial({ color: 0x22262c, roughness: 0.6, flatShading: true });\n\n  // One shared indicator material — this is what actually reads.\n  const indicator = new MeshStandardMaterial({\n    color: 0x2a3038,\n    emissive: new Color(options.indicator ?? 0x2a3038),\n    emissiveIntensity: 1,\n    roughness: 0.35,\n  });\n\n  let screen: ScreenPanel | undefined;\n  let slot: PropSlot | undefined;\n  let height = 1.15;\n\n  if (style === 'switch') {\n    const plate = new Mesh(new BoxGeometry(0.086, 0.086, 0.011), plastic);\n    plate.position.z = 0.0055;\n    group.add(plate);\n    const rocker = new Mesh(new BoxGeometry(0.05, 0.062, 0.006), plastic);\n    rocker.position.set(0, 0, 0.013);\n    rocker.rotation.x = rng.range(-0.05, 0.05); // never quite level\n    group.add(rocker);\n    const pip = new Mesh(new BoxGeometry(0.006, 0.006, 0.002), indicator);\n    pip.position.set(0.03, -0.03, 0.014);\n    group.add(pip);\n    height = 1.15;\n    slot = createSlot('operate', 'stand', group, 0, -height, 0.62, Math.PI);\n  } else if (style === 'thermostat') {\n    const body = new Mesh(new CylinderGeometry(0.052, 0.052, 0.022, 20), plastic);\n    body.rotation.x = Math.PI / 2;\n    body.position.z = 0.011;\n    group.add(body);\n    screen = createScreenPanel(0.062, 0.062, {\n      mode: 'chart',\n      seed,\n      brightness: 0.55,\n      accent: 0xff9a4d,\n    });\n    const panel = new Mesh(new PlaneGeometry(0.062, 0.062), screen.material);\n    panel.name = 'screen';\n    panel.position.z = 0.0225;\n    group.add(panel);\n    const ring = new Mesh(new CylinderGeometry(0.056, 0.056, 0.004, 20), indicator);\n    ring.rotation.x = Math.PI / 2;\n    ring.position.z = 0.0015;\n    group.add(ring);\n    height = 1.42;\n    slot = createSlot('operate', 'stand', group, 0, -height, 0.58, Math.PI);\n  } else if (style === 'doorbell') {\n    const body = new Mesh(new BoxGeometry(0.042, 0.11, 0.016), dark);\n    body.position.z = 0.008;\n    group.add(body);\n    const button = new Mesh(new CylinderGeometry(0.013, 0.013, 0.004, 14), indicator);\n    button.rotation.x = Math.PI / 2;\n    button.position.set(0, -0.03, 0.018);\n    group.add(button);\n    const lens = new Mesh(new CylinderGeometry(0.008, 0.008, 0.003, 12), new MeshStandardMaterial({\n      color: 0x0b0d10,\n      roughness: 0.15,\n      metalness: 0.4,\n    }));\n    lens.rotation.x = Math.PI / 2;\n    lens.position.set(0, 0.028, 0.017);\n    group.add(lens);\n    height = 1.3;\n    slot = createSlot('operate', 'stand', group, 0, -height, 0.66, Math.PI);\n  } else if (style === 'camera') {\n    const mount = new Mesh(new BoxGeometry(0.03, 0.03, 0.03), plastic);\n    mount.position.z = 0.015;\n    group.add(mount);\n    const barrel = new Group();\n    barrel.position.z = 0.03;\n    barrel.rotation.x = -0.42; // angled down at the room\n    group.add(barrel);\n    const body = new Mesh(new CylinderGeometry(0.022, 0.026, 0.07, 14), plastic);\n    body.rotation.x = Math.PI / 2;\n    body.position.z = 0.035;\n    barrel.add(body);\n    const lens = new Mesh(new CylinderGeometry(0.014, 0.014, 0.005, 14), dark);\n    lens.rotation.x = Math.PI / 2;\n    lens.position.z = 0.071;\n    barrel.add(lens);\n    const pip = new Mesh(new BoxGeometry(0.005, 0.005, 0.002), indicator);\n    pip.position.set(0.016, 0.012, 0.069);\n    barrel.add(pip);\n    height = 2.35;\n  } else {\n    // A corner sensor: a wedge with one eye. Smallest prop in the kit.\n    // Tilted, so it must sit proud of the wall or its top corner ends up\n    // buried in the plaster — a rotated box needs clearance for its diagonal,\n    // not for its depth.\n    const body = new Mesh(new BoxGeometry(0.05, 0.062, 0.026), plastic);\n    body.position.z = 0.022;\n    body.rotation.x = -0.3;\n    group.add(body);\n    const eye = new Mesh(new BoxGeometry(0.026, 0.016, 0.004), dark);\n    eye.position.set(0, -0.012, 0.037);\n    eye.rotation.x = -0.3;\n    group.add(eye);\n    const pip = new Mesh(new BoxGeometry(0.005, 0.005, 0.002), indicator);\n    pip.position.set(0, 0.018, 0.035);\n    group.add(pip);\n    height = 2.3;\n  }\n\n  return {\n    object: group,\n    obstacleRadius: 0,\n    height,\n    screen,\n    slot,\n    slots: slot ? [slot] : undefined,\n    setIndicator(color: number, strength = 1) {\n      indicator.emissive.set(color);\n      indicator.emissiveIntensity = strength;\n    },\n  };\n}\n\n/**\n * A desk set: keyboard, mouse and a mug. What a character actually puts their\n * hands on, which the monitors and laptops so far did not give them.\n *\n * Origin at the desk surface. Publishes a `keyboard` anchor at the home row,\n * so ANIMA's desk poses have something to aim the wrists at rather than a\n * number somebody guessed.\n */\nexport interface DeskSet extends Prop {\n  /** Centre of the home row, on the desk surface. */\n  keyboard: Object3D;\n  /** Where the mouse sits. */\n  mouse: Object3D;\n}\n\nexport function createDeskSet(options: { seed?: number } = {}): DeskSet {\n  const seed = options.seed ?? 1;\n  const rng = new Rng(seed);\n\n  const group = new Group();\n  group.name = 'deskSet';\n  const shell = createSurface('paintedMetal', { color: 0x30343b, roughness: 0.62 });\n  const keycap = new MeshStandardMaterial({ color: 0x1b1e23, roughness: 0.8, flatShading: true });\n\n  const board = new Mesh(new BoxGeometry(0.44, 0.016, 0.14), shell);\n  board.position.set(0, 0.008, 0);\n  board.rotation.y = rng.range(-0.05, 0.05); // nobody squares their keyboard\n  group.add(board);\n  // Three bands of keys is all that reads; individual caps are invisible.\n  for (let row = 0; row < 3; row++) {\n    const band = new Mesh(new BoxGeometry(0.4, 0.003, 0.03), keycap);\n    band.position.set(0, 0.018, -0.04 + row * 0.038);\n    board.add(band);\n  }\n\n  const keyboard = new Object3D();\n  keyboard.name = 'keyboard';\n  keyboard.position.set(0, 0.02, 0.01);\n  group.add(keyboard);\n\n  const mouseBody = new Mesh(new BoxGeometry(0.055, 0.026, 0.09), shell);\n  mouseBody.position.set(0.33, 0.013, 0.01);\n  mouseBody.rotation.y = rng.range(-0.12, 0.12);\n  group.add(mouseBody);\n  const mouse = new Object3D();\n  mouse.name = 'mouse';\n  mouse.position.copy(mouseBody.position);\n  group.add(mouse);\n\n  const mug = new Mesh(\n    new CylinderGeometry(0.038, 0.033, 0.095, 12),\n    createSurface('porcelain', { color: 0xd8dde2, roughness: 0.4 })\n  );\n  mug.position.set(-0.34, 0.0475, -0.05);\n  group.add(mug);\n\n  return { object: group, obstacleRadius: 0, keyboard, mouse };\n}\n","import {\n  BoxGeometry,\n  Color,\n  CylinderGeometry,\n  Group,\n  Mesh,\n  MeshStandardMaterial,\n  Object3D,\n  PlaneGeometry,\n} from 'three';\nimport { Rng } from '../core/random';\nimport { DEFAULT_PALETTE, type Palette } from '../core/palette';\nimport { createSurface } from '../materials/surface';\nimport { createPicture, pickPictureStyle, type Picture, type PictureStyle } from '../materials/picture';\nimport type { Prop } from '../core/types';\n\n/**\n * Wall art — the things that go on a wall so it stops being plaster.\n *\n * Every room built with this kit so far has had bare walls, and in every\n * screenshot that is the loudest thing wrong with it: furniture, characters\n * and lighting all read, and then the background is a flat sheet of colour\n * that no inhabited room has ever had.\n *\n * All of these share one convention, the same one `createFixture` uses: the\n * **origin sits at the wall face and the art faces +z**, centred. So placing\n * one is a position and nothing else — and `hangOn` does even that for you.\n *\n * ```ts\n * const picture = createPainting({ width: 0.7, style: 'landscape', seed: 4 });\n * hangOn(room.walls[2], picture, { height: 1.55, seed: 4 });\n * ```\n */\nexport interface WallArt extends Prop {\n  /** Overall size including the frame, in metres. */\n  width: number;\n  height: number;\n  /** The image, on the pieces that carry one. */\n  picture?: Picture;\n}\n\n/**\n * Frame profiles.\n *\n * - `none` — a stretched canvas with its edges showing. Modern, cheap, right.\n * - `thin` — a narrow dark moulding. The safe default for prints and photos.\n * - `wide` — a broad flat face, painted. Reads as a gallery print.\n * - `ornate` — stepped gilt. The only one with any real geometry in it.\n * - `box` — a deep shadow box with the image recessed.\n * - `clip` — no frame at all: a bare sheet with four small clips.\n */\nexport type FrameStyle = 'none' | 'thin' | 'wide' | 'ornate' | 'box' | 'clip';\n\ninterface FrameSpec {\n  /** Moulding face width. */\n  face: number;\n  /** How far the frame stands off the wall. */\n  depth: number;\n  /** How far the image sits behind the front of the frame. */\n  recess: number;\n}\n\nconst FRAMES: Record<FrameStyle, FrameSpec> = {\n  // A negative recess on the bare canvas: the image has to sit PROUD of the\n  // stretcher body, not flush with its front face. Flush means the body wins\n  // the depth test and the picture disappears entirely behind a blank slab.\n  none: { face: 0, depth: 0.035, recess: -0.0015 },\n  thin: { face: 0.022, depth: 0.032, recess: 0.012 },\n  wide: { face: 0.062, depth: 0.042, recess: 0.016 },\n  ornate: { face: 0.055, depth: 0.05, recess: 0.018 },\n  box: { face: 0.03, depth: 0.09, recess: 0.062 },\n  clip: { face: 0, depth: 0.006, recess: 0 },\n};\n\nexport interface PaintingOptions {\n  /** Image width in metres (excluding the frame). Default 0.62. */\n  width?: number;\n  /** Image height. Defaults to a seeded portrait/landscape proportion. */\n  height?: number;\n  /** What it is a picture of. Defaults to a seeded pick. */\n  style?: PictureStyle;\n  /** Moulding. Default 'thin'. */\n  frame?: FrameStyle;\n  /** Frame colour. Defaults to gilt for `ornate`, dark wood otherwise. */\n  frameColor?: number;\n  /** Yellowing and darkened varnish (0–1). Default 0.25. */\n  age?: number;\n  /** A glass front that catches highlights. Default false for paintings. */\n  glazed?: boolean;\n  /** An inset mount board between frame and image, in metres. Default 0. */\n  mount?: number;\n  seed?: number;\n  palette?: Palette;\n}\n\n/** Build the four bars of a moulding around a `w` × `h` opening. */\nfunction buildFrame(\n  group: Group,\n  w: number,\n  h: number,\n  spec: FrameSpec,\n  material: MeshStandardMaterial,\n  steps = 1\n): void {\n  if (spec.face <= 0) return;\n  // The moulding fills the band between the opening and `face` beyond it.\n  // Split that band into concentric rings — each a proper ring that abuts\n  // its neighbours rather than overlapping them, so the frame's outer edge\n  // stays where `face` says it is however many steps it has. Stepping by\n  // scaling the whole frame instead grows it with every ring, and an ornate\n  // frame ends up swamping the picture it is around.\n  const bandW = spec.face / steps;\n  for (let s = 0; s < steps; s++) {\n    const hx = w / 2 + bandW * s;\n    const hy = h / 2 + bandW * s;\n    // Deepest at the outside, stepping down toward the picture — which is\n    // the direction real mouldings run, and the only reason the steps read\n    // as relief rather than as stripes.\n    const depth = spec.depth * (0.45 + (0.55 * (s + 1)) / steps);\n    for (const sign of [-1, 1]) {\n      const rail = new Mesh(new BoxGeometry((hx + bandW) * 2, bandW, depth), material);\n      rail.position.set(0, sign * (hy + bandW / 2), depth / 2);\n      group.add(rail);\n      const stile = new Mesh(new BoxGeometry(bandW, hy * 2, depth), material);\n      stile.position.set(sign * (hx + bandW / 2), 0, depth / 2);\n      group.add(stile);\n    }\n  }\n}\n\n/**\n * A picture on a wall.\n *\n * The proportion is seeded rather than square, because a wall of squares is\n * as obviously generated as a wall of identical images. Portrait and\n * landscape formats both turn up, and the `style` follows the format when\n * it is not asked for — a portrait picture in a landscape frame is a tell.\n */\nexport function createPainting(options: PaintingOptions = {}): WallArt {\n  const seed = options.seed ?? 1;\n  const rng = new Rng(seed);\n  const palette = options.palette ?? DEFAULT_PALETTE;\n  const frameStyle = options.frame ?? 'thin';\n  const spec = FRAMES[frameStyle];\n\n  const w = options.width ?? rng.range(0.4, 0.9);\n  // Formats people actually hang: a few standard ratios, upright or across.\n  const ratio = rng.pick([1.34, 1.5, 1.25, 1.62]);\n  const upright = options.height === undefined && rng.next() < 0.42;\n  const h = options.height ?? (upright ? w * ratio : w / ratio);\n\n  const style = options.style ?? (upright && rng.next() < 0.6 ? 'portrait' : pickPictureStyle(seed));\n  const mount = options.mount ?? 0;\n\n  const group = new Group();\n  group.name = `painting-${style}`;\n\n  const picture = createPicture(w, h, { style, seed, age: options.age ?? 0.25 });\n  const canvas = new Mesh(new PlaneGeometry(w, h), picture.material);\n  canvas.name = 'picture';\n  canvas.position.z = spec.depth - spec.recess;\n  group.add(canvas);\n\n  if (mount > 0) {\n    // Mount board: a pale border between image and moulding. At distance it\n    // is what separates a framed thing from a coloured rectangle, and it is\n    // one quad.\n    const board = new Mesh(\n      new PlaneGeometry(w + mount * 2, h + mount * 2),\n      new MeshStandardMaterial({ color: 0xece7dd, roughness: 0.95 })\n    );\n    board.position.z = canvas.position.z - 0.002;\n    group.add(board);\n  }\n  const openW = w + mount * 2;\n  const openH = h + mount * 2;\n\n  if (frameStyle === 'none') {\n    // A stretched canvas: the sides are visible, so it needs a body.\n    const body = new Mesh(\n      new BoxGeometry(w, h, spec.depth),\n      new MeshStandardMaterial({ color: 0xd8d2c4, roughness: 0.9, flatShading: true })\n    );\n    body.position.z = spec.depth / 2;\n    group.add(body);\n  } else if (frameStyle === 'clip') {\n    const clipMat = new MeshStandardMaterial({ color: 0x9aa2aa, roughness: 0.4, metalness: 0.6 });\n    for (const sx of [-1, 1]) {\n      for (const sy of [-1, 1]) {\n        const clip = new Mesh(new BoxGeometry(0.024, 0.014, 0.012), clipMat);\n        clip.position.set(sx * (w / 2 - 0.02), sy * (h / 2 - 0.008), 0.008);\n        group.add(clip);\n      }\n    }\n  } else {\n    const gilt = frameStyle === 'ornate';\n    // Plain gold rather than the `brass` surface: that shader's grain is\n    // scaled for a gate or a bell, and on a 2 cm moulding it reads as animated\n    // yellow static.\n    const frameMat = gilt\n      ? new MeshStandardMaterial({\n          color: options.frameColor ?? 0xc0a052,\n          roughness: 0.42,\n          metalness: 0.55,\n          flatShading: true,\n        })\n      : createSurface('wood', {\n          color: options.frameColor ?? new Color(palette.woodDark).getHex(),\n          roughness: 0.6,\n          seed,\n        });\n    buildFrame(group, openW, openH, spec, frameMat, gilt ? 3 : 1);\n    if (frameStyle === 'box') {\n      // A shadow box needs a back, or you see the wall through the recess.\n      const back = new Mesh(\n        new PlaneGeometry(openW, openH),\n        new MeshStandardMaterial({ color: 0x1b1a18, roughness: 0.95 })\n      );\n      back.position.z = 0.001;\n      group.add(back);\n    }\n  }\n\n  if (options.glazed) addGlazing(group, openW, openH, spec.depth);\n\n  const outer = spec.face * 2;\n  return {\n    object: group,\n    obstacleRadius: 0,\n    width: openW + outer,\n    height: openH + outer,\n    picture,\n  };\n}\n\n/** A sheet of glass across the front. Catches highlights; occludes nothing. */\nfunction addGlazing(group: Group, w: number, h: number, depth: number): void {\n  const glass = new Mesh(\n    new PlaneGeometry(w, h),\n    new MeshStandardMaterial({\n      color: 0xdce6ec,\n      roughness: 0.04,\n      metalness: 0.1,\n      transparent: true,\n      opacity: 0.11,\n    })\n  );\n  glass.name = 'glazing';\n  glass.position.z = depth + 0.001;\n  group.add(glass);\n}\n\nexport interface FramedPhotoOptions {\n  /** Long edge in metres. Default 0.16 — a photo is small. */\n  size?: number;\n  style?: PictureStyle;\n  /** Add a hinged back strut so it stands on a surface instead of hanging. */\n  standing?: boolean;\n  seed?: number;\n  palette?: Palette;\n}\n\n/**\n * A framed photograph: small, glazed, with a mount board.\n *\n * With `standing` its origin moves to the **base** rather than the wall face,\n * because a photo on a shelf is placed on the floor of that shelf and a photo\n * on a wall is placed on the wall. Getting that wrong buries it half a frame\n * into whatever it sits on.\n */\nexport function createFramedPhoto(options: FramedPhotoOptions = {}): WallArt {\n  const seed = options.seed ?? 1;\n  const rng = new Rng(seed);\n  const size = options.size ?? 0.16;\n  const upright = rng.next() < 0.55;\n  const w = upright ? size / 1.34 : size;\n  const h = upright ? size : size / 1.34;\n\n  const art = createPainting({\n    width: w,\n    height: h,\n    style: options.style ?? 'photo',\n    frame: 'thin',\n    frameColor: rng.pick([0x2b2724, 0x8d7a5f, 0xc9c4bc]),\n    glazed: true,\n    mount: size * 0.09,\n    age: 0.08,\n    seed,\n    palette: options.palette,\n  });\n\n  if (options.standing) {\n    // Lift it so the origin is at the base, then prop it up at a slight lean.\n    const stood = new Group();\n    stood.name = 'framedPhoto';\n    const lean = 0.16;\n    art.object.rotation.x = lean;\n    art.object.position.set(0, art.height / 2, 0);\n    stood.add(art.object);\n    const strut = new Mesh(\n      new BoxGeometry(0.02, art.height * 0.7, 0.004),\n      new MeshStandardMaterial({ color: 0x3a342c, roughness: 0.8 })\n    );\n    strut.position.set(0, art.height * 0.34, -art.height * 0.16);\n    strut.rotation.x = -0.42;\n    stood.add(strut);\n    return { object: stood, obstacleRadius: 0, width: art.width, height: art.height, picture: art.picture };\n  }\n  return art;\n}\n\nexport interface MirrorOptions {\n  /** Glass width. Default 0.5. */\n  width?: number;\n  /** Glass height. Default 0.72. */\n  height?: number;\n  frame?: FrameStyle;\n  frameColor?: number;\n  seed?: number;\n  palette?: Palette;\n}\n\n/**\n * A wall mirror.\n *\n * The glass is painted, not reflective — see `PictureStyle.mirror`. A real\n * one is a second render pass each, and a metal surface without an\n * environment map is simply black.\n */\nexport function createMirror(options: MirrorOptions = {}): WallArt {\n  return createPainting({\n    width: options.width ?? 0.5,\n    height: options.height ?? 0.72,\n    style: 'mirror',\n    frame: options.frame ?? 'ornate',\n    frameColor: options.frameColor,\n    age: 0,\n    seed: options.seed ?? 1,\n    palette: options.palette,\n  });\n}\n\nexport interface WallClock extends WallArt {\n  /** Advance the hands. */\n  update(dt: number): void;\n  /** Set the displayed time. Seconds are optional. */\n  setTime(hours: number, minutes: number, seconds?: number): void;\n  /** The displayed time in hours since midnight. */\n  readonly time: number;\n}\n\nexport interface WallClockOptions {\n  /** Face diameter. Default 0.3. */\n  diameter?: number;\n  /** Starting time, hours since midnight. Default 10.17 (a photogenic 10:10). */\n  time?: number;\n  /**\n   * How fast the hands run relative to real time. Default 60 — one minute of\n   * clock per second, so a clock is visibly moving in a demo. Set 1 for real\n   * time, 0 to stop it.\n   */\n  rate?: number;\n  /** Include a sweeping second hand. Default true. */\n  seconds?: boolean;\n  frameColor?: number;\n  seed?: number;\n}\n\n/**\n * A wall clock — the only piece here that moves, and worth the geometry for\n * exactly that reason. A room where nothing at all changes reads as a\n * photograph; one ticking hand is enough to break that.\n */\nexport function createWallClock(options: WallClockOptions = {}): WallClock {\n  const d = options.diameter ?? 0.3;\n  const r = d / 2;\n  const rate = options.rate ?? 60;\n  const withSeconds = options.seconds ?? true;\n  const seed = options.seed ?? 1;\n\n  const group = new Group();\n  group.name = 'wallClock';\n  const case_ = createSurface('paintedMetal', {\n    color: options.frameColor ?? 0x2c2f33,\n    roughness: 0.5,\n    seed,\n  });\n  const rim = new Mesh(new CylinderGeometry(r, r, 0.038, 28), case_);\n  rim.rotation.x = Math.PI / 2;\n  rim.position.z = 0.019;\n  group.add(rim);\n  const face = new Mesh(\n    new CylinderGeometry(r * 0.93, r * 0.93, 0.004, 28),\n    new MeshStandardMaterial({ color: 0xf2efe8, roughness: 0.85 })\n  );\n  face.rotation.x = Math.PI / 2;\n  face.position.z = 0.039;\n  group.add(face);\n\n  // Hour marks. Twelve of them, with the quarters longer — the difference is\n  // what makes a disc read as a clock rather than as a plate.\n  const markMat = new MeshStandardMaterial({ color: 0x24272b, roughness: 0.7 });\n  for (let i = 0; i < 12; i++) {\n    const quarter = i % 3 === 0;\n    const len = quarter ? r * 0.17 : r * 0.09;\n    const mark = new Mesh(new BoxGeometry(quarter ? 0.011 : 0.006, len, 0.002), markMat);\n    const a = (i / 12) * Math.PI * 2;\n    const at = r * 0.82 - len / 2;\n    mark.position.set(Math.sin(a) * at, Math.cos(a) * at, 0.0415);\n    mark.rotation.z = -a;\n    group.add(mark);\n  }\n\n  // Hands are pivoted at the centre and built pointing +y, so setting the\n  // rotation to -angle runs them clockwise.\n  const hand = (length: number, wide: number, z: number, color: number): Object3D => {\n    const pivot = new Object3D();\n    pivot.position.z = z;\n    const bar = new Mesh(new BoxGeometry(wide, length, 0.003), new MeshStandardMaterial({\n      color,\n      roughness: 0.6,\n    }));\n    // Offset so the pivot sits near the tail, not the middle.\n    bar.position.y = length / 2 - length * 0.14;\n    pivot.add(bar);\n    group.add(pivot);\n    return pivot;\n  };\n  const hourHand = hand(r * 0.52, 0.011, 0.0425, 0x24272b);\n  const minuteHand = hand(r * 0.78, 0.008, 0.0435, 0x24272b);\n  const secondHand = withSeconds ? hand(r * 0.84, 0.003, 0.0445, 0xc0392b) : null;\n  const boss = new Mesh(new CylinderGeometry(0.008, 0.008, 0.004, 12), markMat);\n  boss.rotation.x = Math.PI / 2;\n  boss.position.z = 0.045;\n  group.add(boss);\n\n  let time = options.time ?? 10.17;\n  const applyTime = (): void => {\n    const hours = ((time % 12) + 12) % 12;\n    hourHand.rotation.z = -(hours / 12) * Math.PI * 2;\n    const minutes = (hours * 60) % 60;\n    minuteHand.rotation.z = -(minutes / 60) * Math.PI * 2;\n    if (secondHand) {\n      const secs = (minutes * 60) % 60;\n      secondHand.rotation.z = -(secs / 60) * Math.PI * 2;\n    }\n  };\n  applyTime();\n\n  return {\n    object: group,\n    obstacleRadius: 0,\n    width: d,\n    height: d,\n    get time() {\n      return time;\n    },\n    setTime(hours: number, minutes: number, seconds = 0) {\n      time = hours + minutes / 60 + seconds / 3600;\n      applyTime();\n    },\n    update(dt: number) {\n      if (rate === 0) return;\n      time += (dt * rate) / 3600;\n      applyTime();\n    },\n  };\n}\n\nexport interface TapestryOptions {\n  /** Cloth width. Default 0.9. */\n  width?: number;\n  /** Cloth drop. Default 1.4. */\n  height?: number;\n  /** Hang it from a visible rod. Default true. */\n  rod?: boolean;\n  seed?: number;\n  palette?: Palette;\n}\n\n/**\n * A hanging cloth: tapestry, wall rug, banner-on-a-wall.\n *\n * The origin is at the wall face level with the **rod**, so the cloth drops\n * below it — which is how a hanging is actually positioned. Everything else\n * here is centred on itself; this one is not, and it would be wrong if it\n * were.\n */\nexport function createTapestry(options: TapestryOptions = {}): WallArt {\n  const seed = options.seed ?? 1;\n  const rng = new Rng(seed);\n  const palette = options.palette ?? DEFAULT_PALETTE;\n  const w = options.width ?? 0.9;\n  const h = options.height ?? 1.4;\n\n  const group = new Group();\n  group.name = 'tapestry';\n\n  // Woven bands rather than a picture: a tapestry read from across a hall is\n  // horizontal colour, and the pattern shader already does that far better\n  // than a plane of one colour.\n  const base = new Color(palette.wall).lerp(new Color(rng.pick([0x7d3b3b, 0x2f4a6b, 0x4a5a35, 0x6b4a2f])), 0.75);\n  const cloth = createSurface('canvas', { color: base.getHex(), roughness: 0.95, seed });\n  const segments = 7;\n  const panel = new Mesh(new PlaneGeometry(w, h, 1, segments), cloth);\n  // Sag: the cloth bows away from the wall toward the middle of its drop.\n  const pos = panel.geometry.attributes.position;\n  for (let i = 0; i < pos.count; i++) {\n    const y = pos.getY(i);\n    const t = 1 - (y + h / 2) / h; // 0 at the rod, 1 at the hem\n    pos.setZ(i, Math.sin(t * Math.PI) * 0.035 + t * 0.012);\n  }\n  pos.needsUpdate = true;\n  panel.geometry.computeVertexNormals();\n  panel.name = 'cloth';\n  panel.position.set(0, -h / 2 - 0.03, 0.02);\n  group.add(panel);\n\n  // Bands of a second colour across the drop — the pattern that says \"woven\".\n  const bandMat = new MeshStandardMaterial({\n    color: base.clone().offsetHSL(0.06, 0.05, 0.14).getHex(),\n    roughness: 0.95,\n    flatShading: true,\n  });\n  const bands = 2 + Math.floor(rng.next() * 3);\n  for (let i = 0; i < bands; i++) {\n    const at = -0.12 - ((i + 0.7) / bands) * (h - 0.2);\n    const band = new Mesh(new PlaneGeometry(w * 0.96, h * rng.range(0.03, 0.07)), bandMat);\n    band.position.set(0, at, 0.055 + i * 0.0005);\n    group.add(band);\n  }\n\n  if (options.rod ?? true) {\n    const rod = new Mesh(\n      new CylinderGeometry(0.016, 0.016, w + 0.12, 10),\n      createSurface('wood', { color: palette.woodDark, seed: seed + 1 })\n    );\n    rod.rotation.z = Math.PI / 2;\n    rod.position.set(0, 0, 0.03);\n    group.add(rod);\n    for (const s of [-1, 1]) {\n      const finial = new Mesh(\n        new CylinderGeometry(0.026, 0.026, 0.02, 10),\n        new MeshStandardMaterial({ color: 0xb8983f, roughness: 0.4, metalness: 0.6 })\n      );\n      finial.rotation.z = Math.PI / 2;\n      finial.position.set(s * (w / 2 + 0.07), 0, 0.03);\n      group.add(finial);\n    }\n  }\n\n  return { object: group, obstacleRadius: 0, width: w, height: h };\n}\n","import { MeshStandardMaterial } from 'three';\n\n/**\n * Pictures — the images that go on walls.\n *\n * This is `createScreenPanel`'s twin, and deliberately so: the same trick of\n * drawing content procedurally in the fragment shader from the panel's own\n * UVs, so a gallery of forty framed pictures fetches nothing, repeats\n * nothing, and costs one material path.\n *\n * The one structural difference matters more than everything else here. A\n * screen writes into **emissive radiance** — it is a light source, and the\n * day/night cycle must not dim it. A picture writes into **base colour**. It\n * has no light of its own; a painting in an unlit room is invisible, and one\n * that keeps glowing at midnight is the single loudest tell that a wall is\n * decorated with screenshots. So this patches `map_fragment`, not\n * `emissivemap_fragment`, and everything downstream — lighting, shadow, the\n * day cycle, fog — applies to it exactly as it does to plaster.\n *\n * ```ts\n * const picture = createPicture(0.6, 0.45, { style: 'landscape', seed: 7 });\n * mesh.material = picture.material;\n * ```\n *\n * Content is not representational in any detail. At the size a picture\n * occupies on screen — a framed photo is a couple of dozen pixels across\n * from the sofa — what reads is **value structure**: where the light is,\n * where the dark mass is, roughly what the subject's silhouette does. Paint\n * that correctly and the eye supplies a landscape. Paint individual leaves\n * and you get mush that costs more.\n */\nexport type PictureStyle =\n  /** Sky, horizon, receding hills. The default wall filler. */\n  | 'landscape'\n  /** A figure: shoulders, head, hair mass, warm and low-contrast. */\n  | 'portrait'\n  /** Dark ground, a table edge, lit objects — the old-master still life. */\n  | 'stillLife'\n  /** Soft bands of colour with blurred edges. */\n  | 'abstract'\n  /** Hard-edged shapes in a limited palette. */\n  | 'geometric'\n  /** Desaturated, vignetted, a bright window and a dark subject. */\n  | 'photo'\n  /** Flat colour field, a heavy band, and blocks where the type goes. */\n  | 'poster'\n  /** Mostly white with ruled lines of text and a stamp — a printed notice. */\n  | 'notice'\n  /**\n   * Not a picture at all: a pale gradient with a skewed bright patch where a\n   * window would land. A real mirror is a second render pass per mirror,\n   * which is an absurd price for set dressing, and a metal surface with no\n   * environment map renders black. A painted reflection reads correctly at\n   * any distance you would actually film a room from.\n   */\n  | 'mirror';\n\nconst STYLE_ID: Record<PictureStyle, number> = {\n  landscape: 0,\n  portrait: 1,\n  stillLife: 2,\n  abstract: 3,\n  geometric: 4,\n  photo: 5,\n  mirror: 6,\n  poster: 7,\n  notice: 8,\n};\n\nexport const PICTURE_STYLES: PictureStyle[] = [\n  'landscape',\n  'portrait',\n  'stillLife',\n  'abstract',\n  'geometric',\n  'photo',\n];\n\n/** Everything `createPicture` can draw, including the non-painting styles. */\nexport const ALL_PICTURE_STYLES: PictureStyle[] = [\n  ...PICTURE_STYLES,\n  'mirror',\n  'poster',\n  'notice',\n];\n\nexport interface PictureOptions {\n  /** What the picture is of. Default 'landscape'. */\n  style?: PictureStyle;\n  /** Drives every hue, layout and placement choice. Default 1. */\n  seed?: number;\n  /**\n   * Yellowing, darkened varnish and a heavier vignette (0–1). Default 0.25.\n   * Push it up for a manor, down for a new-build.\n   */\n  age?: number;\n  /** Overall value. Default 1. Below 1 for a picture in a dim corner. */\n  brightness?: number;\n  /** Aspect override. Defaults to width / height. */\n  aspect?: number;\n}\n\nexport interface Picture {\n  material: MeshStandardMaterial;\n  style: PictureStyle;\n  width: number;\n  height: number;\n}\n\n// --- the shader ---------------------------------------------------------\n//\n// GLSL ES 1.00, same constraints as the screen shader: no `switch`, constant\n// loop bounds. Laid out in UV space with x scaled by aspect wherever a shape\n// has to stay round.\n\nconst PIC_HELPERS = /* glsl */ `\n  float picHash(vec2 p) {\n    return fract(sin(dot(p, vec2(127.1, 311.7))) * 43758.5453123);\n  }\n  float picHash1(float x) { return picHash(vec2(x, 17.13)); }\n  // Value noise, for canvas weave and the softening of hard bands.\n  float picNoise(vec2 p) {\n    vec2 i = floor(p); vec2 f = fract(p);\n    f = f * f * (3.0 - 2.0 * f);\n    return mix(mix(picHash(i), picHash(i + vec2(1.0, 0.0)), f.x),\n               mix(picHash(i + vec2(0.0, 1.0)), picHash(i + vec2(1.0, 1.0)), f.x), f.y);\n  }\n  float picFbm(vec2 p) {\n    return picNoise(p) * 0.6 + picNoise(p * 2.3) * 0.26 + picNoise(p * 5.1) * 0.14;\n  }\n  // Ellipse coverage, soft-edged. Radii are in UV units on each axis, so a\n  // round shape wants r.x divided by the aspect; most shapes here are\n  // deliberately elliptical and pass their own.\n  float picBlob(vec2 uv, vec2 c, vec2 r, float soft, float aspect) {\n    vec2 q = (uv - c) / max(r, vec2(1e-4));\n    return 1.0 - smoothstep(1.0 - soft, 1.0 + soft, length(q));\n  }\n  float picStep(float v, float lo, float hi) {\n    return step(lo, v) * step(v, hi);\n  }\n  float picRect(vec2 uv, vec2 c, vec2 h, float soft) {\n    vec2 d = abs(uv - c) - h;\n    float dist = max(d.x, d.y);\n    return 1.0 - smoothstep(-soft, soft, dist);\n  }\n  // A head-and-shoulders silhouette, in units of head-heights, positioned at\n  // the base of the neck.\n  //\n  // Worth a helper because the naive version — a disc sitting on a soft blob\n  // — is a snowman, and it is a snowman at every size and in every palette.\n  // Shoulders have to WIDEN AS THEY FALL; that slope is the single feature\n  // that makes a dark shape read as a person.\n  float picBust(vec2 uv, vec2 at, float scale, float aspect) {\n    vec2 q = (uv - at) / max(scale, 1e-4);\n    q.x *= aspect;\n    float head = 1.0 - smoothstep(0.94, 1.06, length(vec2(q.x / 0.27, (q.y - 0.36) / 0.38)));\n    // Widen fast just under the neck, then stop. A spread that keeps growing\n    // all the way down is a pyramid, which is no more a person than the\n    // snowman was.\n    float spread = 0.11 + 0.80 * smoothstep(0.07, -0.26, q.y);\n    float body = (1.0 - smoothstep(spread - 0.03, spread + 0.03, abs(q.x)))\n               * smoothstep(0.10, 0.02, q.y);\n    return clamp(head + body, 0.0, 1.0);\n  }\n  // A muted painterly palette from a hue. Deliberately not saturated: full\n  // chroma on a wall reads as a poster of a colour swatch, never as paint.\n  vec3 picPigment(float h, float sat, float val) {\n    vec3 c = 0.5 + 0.5 * cos(6.28318 * (h + vec3(0.0, 0.33, 0.67)));\n    return mix(vec3(dot(c, vec3(0.33))), c, sat) * val;\n  }\n`;\n\nconst PIC_STYLES = /* glsl */ `\n  // Sky, horizon, hills going back into haze. The whole thing is value\n  // structure: light sky, mid hills, dark foreground.\n  vec3 picLandscape(vec2 uv, float seed, float aspect) {\n    float h = 0.36 + picHash1(seed) * 0.16;          // horizon height\n    float hue = 0.52 + picHash1(seed + 3.0) * 0.12;  // sky blue-ish\n    vec3 zenith = picPigment(hue, 0.42, 0.62);\n    vec3 haze = picPigment(hue + 0.06, 0.16, 0.88);\n    // Sky: darker at the top, pale at the horizon. Never the other way round.\n    vec3 col = mix(haze, zenith, smoothstep(h, 1.0, uv.y));\n    // Cloud banding, flattened horizontally the way real cloud reads.\n    float cloud = picFbm(vec2(uv.x * 3.2 + seed, uv.y * 7.0)) ;\n    col = mix(col, haze * 1.06, smoothstep(0.55, 0.85, cloud) * step(h, uv.y) * 0.55);\n    // A low sun on some of them.\n    float hasSun = step(0.55, picHash1(seed + 9.0));\n    vec2 sunAt = vec2(0.24 + picHash1(seed + 11.0) * 0.52, h + 0.10);\n    float sun = picBlob(uv, sunAt, vec2(0.035 / aspect, 0.035), 0.6, aspect);\n    col += picPigment(0.11, 0.5, 1.0) * sun * hasSun * 0.8;\n\n    // Three ridges. Each is nearer, darker and less hazy than the last —\n    // aerial perspective is doing all the work of saying \"distance\".\n    for (int i = 0; i < 3; i++) {\n      float fi = float(i);\n      float top = h - fi * 0.055 - 0.01;\n      float wob = (picFbm(vec2(uv.x * (1.6 + fi * 1.4) + seed * 0.7 + fi * 5.0, fi)) - 0.5) * (0.05 + fi * 0.035);\n      float land = step(uv.y, top + wob);\n      float depth = 1.0 - fi / 3.0;\n      vec3 hill = mix(picPigment(0.30 + picHash1(seed + fi) * 0.10, 0.30, 0.30 - fi * 0.055), haze, depth * 0.62);\n      col = mix(col, hill, land);\n    }\n    // Foreground: darkest band, slightly warmer — the ground you stand on.\n    float fg = step(uv.y, 0.085 + (picFbm(vec2(uv.x * 4.0 + seed, 9.0)) - 0.5) * 0.06);\n    col = mix(col, picPigment(0.18, 0.34, 0.16), fg);\n    return col;\n  }\n\n  // A figure. Warm, low contrast, lit from one side — that is the entire\n  // recipe, and it survives being four pixels tall.\n  vec3 picPortrait(vec2 uv, float seed, float aspect) {\n    float hue = picHash1(seed + 2.0);\n    // The value ladder is the whole picture, and it has to be a real ladder:\n    // ground ~0.10, clothes ~0.17, hair ~0.08, face ~0.62. Everything sitting\n    // inside one narrow band — which is what this did first — collapses into\n    // a ring of near-identical greys where a head should be.\n    vec3 col = picPigment(0.09 + hue * 0.05, 0.30, 0.10);\n    // A lighter wash behind the shoulder, off to one side. Centred behind the\n    // head it just outlines the hair and the figure reads as a doughnut.\n    float lit = 0.5 + (step(0.5, picHash1(seed + 17.0)) - 0.5) * 0.44;\n    col = mix(col, picPigment(0.10, 0.24, 0.26),\n      picBlob(uv, vec2(lit, 0.52), vec2(0.40, 0.42), 1.0, aspect) * 0.85);\n    // The figure, as one silhouette: neck, sloping shoulders, head. Muted,\n    // so the sitter's coat does not out-shout their face.\n    vec3 cloth = picPigment(hue, 0.22, 0.17 + picHash1(seed + 5.0) * 0.07);\n    col = mix(col, cloth, picBust(uv, vec2(0.5, 0.44), 0.40, aspect));\n    // Hair, as a CAP: the same ellipse pushed up, so it is thick over the\n    // crown and gone by the chin. Concentric with the head it comes out as\n    // an even ring, which is a helmet.\n    col = mix(col, picPigment(0.07, 0.40, 0.06 + picHash1(seed + 7.0) * 0.07),\n      picBlob(uv, vec2(0.5, 0.625), vec2(0.125, 0.150), 0.12, aspect));\n    // Face: much lighter, modelled from one side.\n    float side = smoothstep(0.60, 0.40, uv.x);\n    float head = picBlob(uv, vec2(0.5, 0.578), vec2(0.098, 0.132), 0.10, aspect);\n    vec3 skin = picPigment(0.055, 0.30, 0.50 + picHash1(seed + 13.0) * 0.22)\n      * (0.62 + side * 0.48);\n    col = mix(col, skin, head);\n    // A collar: the light note that stops it being a head balanced on a blob.\n    col = mix(col, skin * 0.9, picRect(uv, vec2(0.5, 0.425), vec2(0.085, 0.018), 0.022) * 0.8);\n    return col;\n  }\n\n  // Old-master still life: near-black ground, a table edge, three lit objects.\n  vec3 picStillLife(vec2 uv, float seed, float aspect) {\n    // A proper value ladder: near-black ground, mid table, and objects that\n    // are genuinely light where the light hits them. Everything within one\n    // narrow band — which is where this started — is a mauve rectangle with\n    // suggestions in it.\n    vec3 col = picPigment(0.08, 0.30, 0.045);\n    // The table: a horizontal edge, everything below it darker still.\n    float table = 0.30 + picHash1(seed) * 0.06;\n    col = mix(col, picPigment(0.07, 0.34, 0.10), step(uv.y, table));\n    col = mix(col, picPigment(0.09, 0.30, 0.26), picRect(uv, vec2(0.5, table), vec2(0.6, 0.006), 0.008));\n    // A vessel: tall, with a neck. Two stacked blobs is enough of a silhouette.\n    float vx = 0.34 + picHash1(seed + 4.0) * 0.10;\n    vec3 pot = picPigment(0.06 + picHash1(seed + 6.0) * 0.08, 0.26, 0.50);\n    float belly = picBlob(uv, vec2(vx, table + 0.115), vec2(0.105, 0.115), 0.10, aspect);\n    float neck = picRect(uv, vec2(vx, table + 0.235), vec2(0.030, 0.075), 0.012);\n    // Lit hard from one side: the falloff across a curved body is what says\n    // \"round\" without a single extra triangle.\n    float lit = smoothstep(vx + 0.09, vx - 0.10, uv.x) * 0.82 + 0.24;\n    col = mix(col, pot * lit, clamp(belly + neck, 0.0, 1.0));\n    // Fruit: two or three, sitting ON the table line, never floating above it.\n    for (int i = 0; i < 3; i++) {\n      float fi = float(i);\n      float r = 0.042 + picHash1(seed + fi * 3.0 + 21.0) * 0.028;\n      float fx = 0.56 + fi * 0.115 + picHash1(seed + fi + 31.0) * 0.04;\n      float f = picBlob(uv, vec2(fx, table + r * 0.92), vec2(r / aspect, r), 0.16, aspect);\n      vec3 fc = picPigment(0.02 + picHash1(seed + fi * 7.0) * 0.16, 0.52, 0.62);\n      float fl = smoothstep(fx + r * 1.1, fx - r, uv.x) * 0.78 + 0.26;\n      col = mix(col, fc * fl, f);\n    }\n    return col;\n  }\n\n  // Soft fields of colour. Blurred edges, related hues, one field dominant.\n  vec3 picAbstract(vec2 uv, float seed, float aspect) {\n    float hue = picHash1(seed);\n    // Two wandering boundaries cutting three fields, with a real spread of\n    // value between them. Stacking soft mixes on top of each other — the\n    // first attempt — averages everything back to one flat wash.\n    float wob = (picFbm(vec2(uv.x * 2.2 + seed, 3.0)) - 0.5) * 0.07;\n    float y = uv.y + wob;\n    float b1 = 0.28 + picHash1(seed + 1.0) * 0.14;\n    float b2 = b1 + 0.22 + picHash1(seed + 2.0) * 0.18;\n    vec3 col = picPigment(hue, 0.36, 0.18 + picHash1(seed + 5.0) * 0.09);\n    col = mix(col, picPigment(hue + 0.11, 0.44, 0.44 + picHash1(seed + 6.0) * 0.14),\n      smoothstep(b1 - 0.04, b1 + 0.04, y));\n    col = mix(col, picPigment(hue + 0.24, 0.26, 0.68 + picHash1(seed + 7.0) * 0.10),\n      smoothstep(b2 - 0.04, b2 + 0.04, y));\n    // A vertical cut on some of them. Without it, three horizontal fields\n    // with a light top is indistinguishable from the landscape.\n    float split = 0.32 + picHash1(seed + 8.0) * 0.36;\n    col = mix(col, col * 0.66 + picPigment(hue + 0.5, 0.5, 0.34) * 0.34,\n      step(0.5, picHash1(seed + 9.0)) * smoothstep(split - 0.012, split + 0.012, uv.x));\n    // Enough tooth that it reads as a surface and not a gradient fill.\n    col *= 0.94 + picFbm(vec2(uv.x * 40.0 * aspect, uv.y * 40.0)) * 0.12;\n    return col;\n  }\n\n  // Hard-edged shapes, limited palette, one accent. The modern-office print.\n  vec3 picGeometric(vec2 uv, float seed, float aspect) {\n    float hue = picHash1(seed + 8.0);\n    vec3 col = vec3(0.78, 0.76, 0.72) * (0.82 + picHash1(seed) * 0.2);\n    // A ground rectangle, then two shapes overlapping it.\n    col = mix(col, picPigment(hue, 0.42, 0.44),\n      picRect(uv, vec2(0.5, 0.5), vec2(0.40, 0.40), 0.004));\n    float cx = 0.36 + picHash1(seed + 2.0) * 0.2;\n    float cy = 0.40 + picHash1(seed + 4.0) * 0.2;\n    col = mix(col, picPigment(hue + 0.42, 0.55, 0.52),\n      picBlob(uv, vec2(cx, cy), vec2(0.20 / aspect, 0.20), 0.02, aspect));\n    // A bar, either upright or lying down, in the accent.\n    float upright = step(0.5, picHash1(seed + 6.0));\n    vec2 h = mix(vec2(0.30, 0.045), vec2(0.045, 0.30), upright);\n    col = mix(col, picPigment(hue + 0.14, 0.62, 0.60),\n      picRect(uv, vec2(0.5 + picHash1(seed + 10.0) * 0.16, 0.5), h, 0.004));\n    return col;\n  }\n\n  // A photograph: near-monochrome, cool, a bright window and a dark subject.\n  // Colour is what separates this from the paintings — a photo that is as\n  // chromatic as an oil reads as an oil.\n  vec3 picPhoto(vec2 uv, float seed, float aspect) {\n    float hue = 0.55 + picHash1(seed) * 0.1;\n    // Near-neutral. Colour is what separates a photograph from an oil, so\n    // almost all the chroma comes out of this one.\n    vec3 col = picPigment(hue, 0.09, 0.50 + picHash1(seed + 1.0) * 0.14);\n    // A bright region behind them: a window, a doorway, the sky.\n    vec2 at = vec2(0.28 + picHash1(seed + 3.0) * 0.44, 0.68);\n    col = mix(col, vec3(0.88, 0.89, 0.90), picBlob(uv, at, vec2(0.26, 0.28), 0.8, aspect) * 0.75);\n    // Two or three people, different sizes, none of them centred. One dark\n    // mass in the middle of the frame is not a photograph of anything.\n    float extra = step(0.5, picHash1(seed + 40.0));\n    for (int i = 0; i < 3; i++) {\n      float fi = float(i);\n      float here = step(fi, 1.0 + extra);\n      float x = 0.26 + fi * 0.23 + picHash1(seed + fi * 5.0 + 11.0) * 0.09;\n      float s = 0.30 + picHash1(seed + fi * 3.0 + 23.0) * 0.09;\n      col = mix(col, picPigment(hue - 0.05 + fi * 0.03, 0.20, 0.19 + fi * 0.045),\n        picBust(uv, vec2(x, 0.20), s, aspect) * here);\n    }\n    // Ground.\n    col = mix(col, picPigment(hue, 0.07, 0.30), 1.0 - smoothstep(0.06, 0.13, uv.y));\n    // Grain, which is the other half of \"photograph\".\n    col *= 0.93 + picHash(uv * vec2(520.0 * aspect, 520.0) + seed) * 0.14;\n    return col;\n  }\n\n  // Type, as TYPE — bands at the density a line of text has when you see it\n  // across a room, never glyph-shaped. There is no font here, and fake\n  // letterforms are the single most recognisable tell in a procedural scene:\n  // at any distance where you could tell they were letters, you can tell\n  // they are wrong.\n  float picType(vec2 uv, float top, float lines, float indent, float seed, float weight) {\n    float row = floor((top - uv.y) * lines);\n    if (row < 0.0 || row > lines - 1.0) return 0.0;\n    float band = fract((top - uv.y) * lines);\n    // Ink occupies the middle of each line's box, never the whole of it.\n    float ink = picStep(band, 0.28, 0.28 + weight);\n    // Ragged right edge: every line is a different length.\n    float len = 0.30 + picHash(vec2(row, seed)) * 0.62;\n    return ink * step(indent, uv.x) * step(uv.x, indent + len);\n  }\n\n  // A poster: one strong colour field, a heavy band, and type blocks.\n  vec3 picPoster(vec2 uv, float seed, float aspect) {\n    float hue = picHash1(seed);\n    vec3 ground = picPigment(hue, 0.45, 0.30 + picHash1(seed + 1.0) * 0.34);\n    vec3 col = ground;\n    // A band across, top or bottom, in a contrasting value.\n    float at = picHash1(seed + 3.0) > 0.5 ? 0.74 : 0.16;\n    vec3 bandCol = picPigment(hue + 0.45, 0.55, 0.72);\n    col = mix(col, bandCol, picRect(uv, vec2(0.5, at), vec2(0.6, 0.10), 0.004));\n    // A big shape: the poster's image.\n    col = mix(col, picPigment(hue + 0.18, 0.5, 0.20),\n      picBlob(uv, vec2(0.5, 0.5), vec2(0.26 / aspect, 0.26), 0.03, aspect));\n    // The headline: two heavy short bars, not letters.\n    vec3 ink = picPigment(hue + 0.5, 0.2, 0.12);\n    col = mix(col, ink, picRect(uv, vec2(0.32, at), vec2(0.16, 0.028), 0.003));\n    col = mix(col, ink, picRect(uv, vec2(0.26, at - 0.052), vec2(0.10, 0.016), 0.003));\n    // Small print at the foot.\n    col = mix(col, ink, picType(uv, at > 0.5 ? 0.14 : 0.92, 4.0, 0.16, seed, 0.34) * 0.75);\n    return col;\n  }\n\n  // A printed notice: white paper, a rule, a block of text, a stamp.\n  vec3 picNotice(vec2 uv, float seed, float aspect) {\n    vec3 col = vec3(0.80, 0.79, 0.75) * (0.94 + picHash1(seed) * 0.1);\n    vec3 ink = vec3(0.16, 0.15, 0.14);\n    // Heading, then a rule under it.\n    col = mix(col, ink, picRect(uv, vec2(0.5, 0.86), vec2(0.26, 0.026), 0.003));\n    col = mix(col, ink * 1.6, picRect(uv, vec2(0.5, 0.80), vec2(0.36, 0.004), 0.002));\n    // Body copy: ruled lines with a ragged right edge.\n    col = mix(col, ink, picType(uv, 0.74, 9.0, 0.14, seed, 0.3) * 0.85);\n    // A stamp or seal, off to one corner and never square to the page.\n    float d = length((uv - vec2(0.74, 0.20)) * vec2(aspect, 1.0));\n    vec3 stamp = picPigment(0.98, 0.55, 0.42);\n    col = mix(col, stamp, (1.0 - smoothstep(0.085, 0.095, d)) * 0.5);\n    col = mix(col, stamp, (1.0 - smoothstep(0.062, 0.07, d)) * 0.25);\n    return col;\n  }\n\n  // A mirror, painted. Pale, cool, a skewed bright patch where a window\n  // lands, and a darker lower half because the floor is darker than the sky.\n  vec3 picMirror(vec2 uv, float seed, float aspect) {\n    vec3 col = mix(vec3(0.30, 0.33, 0.36), vec3(0.56, 0.60, 0.64), uv.y);\n    // The window: a parallelogram, because a mirror is never square-on to one.\n    float skew = (uv.y - 0.5) * 0.34;\n    float win = picRect(vec2(uv.x + skew, uv.y), vec2(0.34, 0.66), vec2(0.13, 0.17), 0.02);\n    col = mix(col, vec3(0.90, 0.92, 0.95), win * 0.85);\n    // A soft second bounce, and a dark mass low down (furniture, the floor).\n    col = mix(col, vec3(0.72, 0.75, 0.79), picBlob(uv, vec2(0.72, 0.52), vec2(0.22, 0.30), 0.9, aspect) * 0.35);\n    col = mix(col, vec3(0.19, 0.21, 0.24), smoothstep(0.30, 0.02, uv.y) * 0.7);\n    // Glass is not perfectly clean.\n    col *= 0.97 + picFbm(vec2(uv.x * 6.0 * aspect, uv.y * 6.0) + seed) * 0.06;\n    return col;\n  }\n`;\n\nconst PIC_FRAG = /* glsl */ `\n  {\n    vec2 picUv = vUv;\n    vec3 picCol = vec3(0.5);\n    if (uPicStyle == 0) {\n      picCol = picLandscape(picUv, uPicSeed, uPicAspect);\n    } else if (uPicStyle == 1) {\n      picCol = picPortrait(picUv, uPicSeed, uPicAspect);\n    } else if (uPicStyle == 2) {\n      picCol = picStillLife(picUv, uPicSeed, uPicAspect);\n    } else if (uPicStyle == 3) {\n      picCol = picAbstract(picUv, uPicSeed, uPicAspect);\n    } else if (uPicStyle == 4) {\n      picCol = picGeometric(picUv, uPicSeed, uPicAspect);\n    } else if (uPicStyle == 5) {\n      picCol = picPhoto(picUv, uPicSeed, uPicAspect);\n    } else if (uPicStyle == 6) {\n      picCol = picMirror(picUv, uPicSeed, uPicAspect);\n    } else if (uPicStyle == 7) {\n      picCol = picPoster(picUv, uPicSeed, uPicAspect);\n    } else if (uPicStyle == 8) {\n      picCol = picNotice(picUv, uPicSeed, uPicAspect);\n    }\n\n    if (uPicStyle < 6) {\n      // Canvas weave: a fine cross-hatch in VALUE only. Visible close, and at\n      // distance it just stops the picture looking like flat vector art.\n      float weave = sin(picUv.x * 620.0 * uPicAspect) * sin(picUv.y * 620.0);\n      picCol *= 1.0 + weave * 0.035;\n      // Varnish: old pictures go yellow and go dark at the edges, and both\n      // happen together. Applied after the weave so the darkening reads as\n      // depth rather than as a painted border.\n      picCol = mix(picCol, picCol * vec3(1.18, 1.02, 0.72), uPicAge * 0.65);\n      float r = length((picUv - 0.5) * vec2(uPicAspect, 1.0) / max(uPicAspect, 1.0));\n      picCol *= 1.0 - smoothstep(0.30, 0.78, r) * (0.16 + uPicAge * 0.34);\n    }\n\n    diffuseColor.rgb = picCol * uPicBright;\n  }\n`;\n\n/**\n * Build a picture's material. The caller owns the mesh; the picture only\n * needs to know its own proportions so shapes inside it stay round.\n *\n * Whatever the style, the output stays inside a painterly value range —\n * nothing goes to white and nothing to black. A wall picture that clips at\n * either end stops looking like a made object and starts looking like a hole\n * in the wall.\n */\nexport function createPicture(\n  width: number,\n  height: number,\n  options: PictureOptions = {}\n): Picture {\n  const style = options.style ?? 'landscape';\n  const seed = options.seed ?? 1;\n  const aspect = options.aspect ?? width / Math.max(height, 1e-4);\n  const age = options.age ?? 0.25;\n  const brightness = options.brightness ?? 1;\n\n  const uniforms = {\n    uPicStyle: { value: STYLE_ID[style] },\n    uPicSeed: { value: seed },\n    uPicAspect: { value: aspect },\n    uPicAge: { value: age },\n    uPicBright: { value: brightness },\n  };\n\n  const material = new MeshStandardMaterial({\n    color: 0xffffff,\n    // Oil on canvas is matte; a mirror is not. This is the only PBR\n    // difference between the two, and it is the one that sells it.\n    // Paper is flatter than canvas and glass is not matte at all.\n    roughness: style === 'mirror' ? 0.12 : style === 'notice' || style === 'poster' ? 0.94 : 0.86,\n    metalness: style === 'mirror' ? 0.55 : 0,\n  });\n  // Force vUv: with no map three drops the varying and the layout has\n  // nothing to lay out against.\n  material.defines = { ...(material.defines ?? {}), USE_UV: '' };\n  material.onBeforeCompile = (shader) => {\n    Object.assign(shader.uniforms, uniforms);\n    shader.fragmentShader = shader.fragmentShader\n      .replace(\n        'void main() {',\n        `uniform int uPicStyle;\n         uniform float uPicSeed;\n         uniform float uPicAspect;\n         uniform float uPicAge;\n         uniform float uPicBright;\n         ${PIC_HELPERS}\n         ${PIC_STYLES}\n         void main() {`\n      )\n      // Base colour, NOT emissive. This one line is the whole difference\n      // between a painting and a television.\n      .replace('#include <map_fragment>', `#include <map_fragment>\\n${PIC_FRAG}`);\n  };\n  material.customProgramCacheKey = () => 'scenaPicture';\n\n  return { material, style, width, height };\n}\n\n/** Pick a picture style from a seed, excluding 'mirror'. */\nexport function pickPictureStyle(seed: number): PictureStyle {\n  const s = Math.abs(Math.floor(seed * 2654435761)) % PICTURE_STYLES.length;\n  return PICTURE_STYLES[s];\n}\n","import {\n  BackSide,\n  BoxGeometry,\n  CylinderGeometry,\n  Group,\n  Mesh,\n  MeshStandardMaterial,\n  Object3D,\n  TorusGeometry,\n} from 'three';\nimport { Rng } from '../core/random';\nimport { DEFAULT_PALETTE, type Palette } from '../core/palette';\nimport { createSurface } from '../materials/surface';\nimport { createGlass } from '../materials/glass';\nimport { createDroplets, type Droplets } from '../materials/waterFlow';\nimport { createCurtains, type Curtains } from './soft';\nimport { createFill, createSpray, createSteam, type Fill, type Spray, type Steam } from './waterworks';\nimport { createTap, type Tap } from './washing';\nimport {\n  addApproach,\n  createSlot,\n  type Gathering,\n  type Prop,\n  type PropSlot,\n} from '../core/types';\n\n/**\n * Bathing — showers, tubs and hot tubs.\n *\n * Everything expensive here was built already: the spray and the steam came\n * with the water layer, the enclosure screen is a `createCurtains` panel or\n * a sheet of `createGlass`, and a hot tub is a `Gathering` — seats around a\n * rim with a shared focus, which is what one actually is socially.\n *\n * What is new is **the wait**. A shower does not produce hot water the\n * instant you open it, and that pause is most of what makes one feel\n * plumbed rather than switched. The state machine below is deliberately the\n * same shape as GAMA's `Device` (off → warming → running), so a device\n * graph drives a shower with nothing importing anything.\n */\n\nexport type ShowerState = 'off' | 'warming' | 'running' | 'cooling';\n\nexport type ShowerStyle =\n  /** A glass cubicle with a tray. */\n  | 'enclosure'\n  /** A head and a rail over the end of a bath, with a curtain. */\n  | 'overBath'\n  /** A wet room: a head, a drain, and nothing else. */\n  | 'open';\n\nexport interface ShowerOptions {\n  style?: ShowerStyle;\n  /** Tray/footprint width in metres. Default 0.9. */\n  width?: number;\n  /** Head height above the floor. Default 2.05. */\n  head?: number;\n  /**\n   * Seconds of cold before it runs warm. Default 3.5. Zero makes it a\n   * switch, which is exactly what a shower is not.\n   */\n  warmUp?: number;\n  seed?: number;\n  palette?: Palette;\n}\n\nexport interface Shower extends Prop {\n  readonly state: ShowerState;\n  /** Turn it on or off. The warm-up happens on its own. */\n  setRunning(on: boolean): void;\n  readonly running: boolean;\n  spray: Spray;\n  steam: Steam;\n  /** The curtain, on the styles that have one. */\n  curtain: Curtains | null;\n  /** Where a character stands under it. */\n  slot: PropSlot;\n  /** Fires as the state changes — wire it to a sound or a light. */\n  onState?: (state: ShowerState) => void;\n  update(dt: number): void;\n}\n\n/**\n * A shower.\n *\n * The origin is on the floor at the centre of the tray, facing +z out of the\n * enclosure.\n */\nexport function createShower(options: ShowerOptions = {}): Shower {\n  const style = options.style ?? 'enclosure';\n  const width = options.width ?? 0.9;\n  const headY = options.head ?? 2.05;\n  const warmUp = options.warmUp ?? 3.5;\n  const seed = options.seed ?? 1;\n  const palette = options.palette ?? DEFAULT_PALETTE;\n\n  const group = new Group();\n  group.name = `shower-${style}`;\n  const chrome = new MeshStandardMaterial({ color: 0xc4cace, roughness: 0.2, metalness: 0.85 });\n  const depth = style === 'overBath' ? 0.72 : width;\n\n  if (style !== 'open') {\n    const tray = new Mesh(\n      new BoxGeometry(width, 0.07, depth),\n      createSurface('glaze', { color: 0xf1efe9, seed })\n    );\n    tray.position.y = 0.035;\n    group.add(tray);\n  }\n  // A drain, on every style — a shower without one is a puddle.\n  const drain = new Mesh(new CylinderGeometry(0.05, 0.05, 0.008, 12), chrome);\n  drain.position.y = style === 'open' ? 0.004 : 0.072;\n  group.add(drain);\n\n  // Riser and head.\n  const riser = new Mesh(new CylinderGeometry(0.014, 0.014, headY - 0.9, 8), chrome);\n  riser.position.set(0, 0.9 + (headY - 0.9) / 2, -depth / 2 + 0.06);\n  group.add(riser);\n  const arm = new Mesh(new CylinderGeometry(0.012, 0.012, 0.2, 8), chrome);\n  arm.rotation.x = Math.PI / 2;\n  arm.position.set(0, headY, -depth / 2 + 0.15);\n  group.add(arm);\n  const rose = new Mesh(new CylinderGeometry(0.075, 0.06, 0.03, 14), chrome);\n  rose.position.set(0, headY - 0.02, -depth / 2 + 0.25);\n  group.add(rose);\n\n  const control = createTap({ style: 'mixer', seed: seed + 1, palette });\n  control.object.position.set(width * 0.3, 1.1, -depth / 2 + 0.04);\n  group.add(control.object);\n\n  let curtain: Curtains | null = null;\n  if (style === 'enclosure') {\n    // Two fixed glass panels. Frosted, because a clear one shows the inside\n    // of a box.\n    const glass = createGlass({ frosted: true, tint: 0xa8c8d4 });\n    for (const [w, x, z, rot] of [\n      [depth, -width / 2, 0, Math.PI / 2],\n      [width, 0, -depth / 2, 0],\n    ] as Array<[number, number, number, number]>) {\n      const panel = new Mesh(new BoxGeometry(w, 1.85, 0.012), glass);\n      panel.position.set(x, 1.0, z);\n      panel.rotation.y = rot;\n      group.add(panel);\n    }\n  } else if (style === 'overBath') {\n    const rail = new Mesh(new CylinderGeometry(0.012, 0.012, width + 0.1, 8), chrome);\n    rail.rotation.z = Math.PI / 2;\n    rail.position.set(0, 1.95, depth / 2 - 0.04);\n    group.add(rail);\n    curtain = createCurtains({\n      width: width + 0.06,\n      drop: 1.5,\n      style: 'closed',\n      stir: 0.25,\n      seed: seed + 2,\n      palette,\n    });\n    curtain.object.position.set(0, 1.94, depth / 2 - 0.04);\n    group.add(curtain.object);\n  }\n\n  const spray = createSpray({\n    height: headY - 0.1,\n    radius: 0.07,\n    spread: Math.min(0.34, width * 0.36),\n    flow: 0,\n    seed,\n    palette,\n  });\n  spray.object.position.set(0, headY - 0.04, -depth / 2 + 0.25);\n  group.add(spray.object);\n\n  const steam = createSteam({\n    radius: width * 0.45,\n    height: headY * 0.85,\n    count: 16,\n    seed: seed + 4,\n  });\n  steam.object.position.y = 0.1;\n  group.add(steam.object);\n\n  const slot = createSlot('shower', 'operate', group, 0, style === 'open' ? 0 : 0.07, 0.05, 0);\n  addApproach(slot, group, 0.7, 'front');\n\n  let state: ShowerState = 'off';\n  let wantOn = false;\n  let warmed = 0;\n  const api: Shower = {\n    object: group,\n    obstacleRadius: Math.max(width, depth) * 0.55,\n    spray,\n    steam,\n    curtain,\n    slot,\n    slots: [slot],\n    get state() {\n      return state;\n    },\n    get running() {\n      return wantOn;\n    },\n    setRunning(on: boolean) {\n      wantOn = on;\n      control.set(on);\n    },\n    update(dt: number) {\n      if (dt <= 0) return;\n      control.update(dt);\n      const was = state;\n\n      if (wantOn) {\n        // Water arrives at once; HEAT does not. Both the steam and the state\n        // wait for the warm-up, which is the whole difference between a\n        // shower and a switch.\n        warmed = Math.min(warmUp, warmed + dt);\n        state = warmed >= warmUp ? 'running' : 'warming';\n      } else {\n        warmed = Math.max(0, warmed - dt * 1.6);\n        state = warmed > 0 ? 'cooling' : 'off';\n      }\n\n      spray.setFlow(control.state);\n      spray.update(dt);\n      // Steam only once it is actually hot, and it clears on its own long\n      // after the water stops.\n      steam.setTarget(state === 'running' ? 1 : 0);\n      steam.update(dt);\n      curtain?.update(dt);\n\n      if (state !== was) api.onState?.(state);\n    },\n  };\n  // Idle so a shower left alone still stirs its curtain.\n  return api;\n}\n\nexport type TubStyle =\n  /** A roll-top on four feet. */\n  | 'clawfoot'\n  /** A modern panelled bath built into the wall. */\n  | 'modern'\n  /** A tub set into the floor. */\n  | 'sunken'\n  /** A short high-sided hip bath — the one you fill by hand. */\n  | 'hip';\n\nexport interface TubOptions {\n  style?: TubStyle;\n  /** Length in metres. Defaults per style. */\n  length?: number;\n  /** How fast an open tap fills it. Default 0.12 — a bath takes a while. */\n  rate?: number;\n  seed?: number;\n  palette?: Palette;\n}\n\nexport interface Tub extends Prop {\n  style: TubStyle;\n  fill: Fill;\n  /** Empty on `hip` — you fill that one from a jug. */\n  taps: Tap[];\n  /** Lie in it. The reclined sleep pose. */\n  slot: PropSlot;\n  /** Rim height above the floor. */\n  rim: number;\n  pour(amount: number): void;\n  setDrain(open: boolean): void;\n  readonly draining: boolean;\n  update(dt: number): void;\n}\n\n/** A bath. */\nexport function createTub(options: TubOptions = {}): Tub {\n  const style = options.style ?? 'modern';\n  const seed = options.seed ?? 1;\n  const palette = options.palette ?? DEFAULT_PALETTE;\n  const length = options.length ?? (style === 'hip' ? 0.9 : 1.65);\n  const width = style === 'hip' ? 0.66 : 0.74;\n  const rate = options.rate ?? 0.12;\n\n  const group = new Group();\n  group.name = `tub-${style}`;\n  const ceramic = createSurface('glaze', { color: 0xf2f0ea, seed });\n  const taps: Tap[] = [];\n  let rim = 0.58;\n  let floorY = 0.12;\n\n  if (style === 'sunken') {\n    rim = 0.06;\n    floorY = -0.44;\n    // The lip is a FRAME, not a slab. A slab across the whole footprint is a\n    // lid: it caps the very well it is meant to surround, and the tub renders\n    // as a sheet of marble with two taps standing on it.\n    const marble = createSurface('marble', { seed });\n    const b = 0.14;\n    for (const [w, d, x, z] of [\n      [length + b * 2, b, 0, -(width + b) / 2],\n      [length + b * 2, b, 0, (width + b) / 2],\n      [b, width, -(length + b) / 2, 0],\n      [b, width, (length + b) / 2, 0],\n    ] as Array<[number, number, number, number]>) {\n      const lip = new Mesh(new BoxGeometry(w, 0.06, d), marble);\n      lip.position.set(x, 0.03, z);\n      group.add(lip);\n    }\n    // The well. Four walls, so it reads as a hole rather than a slab.\n    for (const [w, d, x, z] of [\n      [length, 0.05, 0, -width / 2],\n      [length, 0.05, 0, width / 2],\n      [0.05, width, -length / 2, 0],\n      [0.05, width, length / 2, 0],\n    ] as Array<[number, number, number, number]>) {\n      const wall = new Mesh(new BoxGeometry(w, 0.5, d), ceramic);\n      wall.position.set(x, -0.25, z);\n      group.add(wall);\n    }\n    const base = new Mesh(new BoxGeometry(length, 0.04, width), ceramic);\n    base.position.y = -0.48;\n    group.add(base);\n  } else {\n    // Built as four WALLS around an inner floor, not as a solid box with a\n    // smaller box inside it. The second one is invisible — it is hidden by\n    // the shell it sits in — and the tub renders as a plain white block with\n    // taps on top, which is exactly what the first version did.\n    const isHip = style === 'hip';\n    const stand = style === 'clawfoot' ? 0.15 : 0;\n    floorY = stand + 0.06;\n    rim = stand + (isHip ? 0.58 : 0.5);\n    const t = 0.05;\n\n    const base = new Mesh(new BoxGeometry(length, 0.06, width), ceramic);\n    base.position.y = floorY - 0.03;\n    group.add(base);\n    for (const [w, d, x, z] of [\n      [length, t, 0, -(width / 2 - t / 2)],\n      [length, t, 0, width / 2 - t / 2],\n      [t, width - t * 2, -(length / 2 - t / 2), 0],\n      [t, width - t * 2, length / 2 - t / 2, 0],\n    ] as Array<[number, number, number, number]>) {\n      const wall = new Mesh(new BoxGeometry(w, rim - stand, d), ceramic);\n      wall.position.set(x, stand + (rim - stand) / 2, z);\n      group.add(wall);\n    }\n    // Rolled rims down the long sides, which is most of a bath's silhouette.\n    for (const sz of [-1, 1]) {\n      const roll = new Mesh(new CylinderGeometry(0.032, 0.032, length, 6), ceramic);\n      roll.rotation.z = Math.PI / 2;\n      roll.position.set(0, rim, sz * (width / 2 - t / 2));\n      group.add(roll);\n    }\n\n    if (style === 'clawfoot') {\n      const feet = new MeshStandardMaterial({ color: 0xb89a52, roughness: 0.4, metalness: 0.7 });\n      for (const sx of [-1, 1]) {\n        for (const sz of [-1, 1]) {\n          const foot = new Mesh(new CylinderGeometry(0.032, 0.055, stand, 7), feet);\n          foot.position.set(sx * (length / 2 - 0.14), stand / 2, sz * (width / 2 - 0.1));\n          group.add(foot);\n        }\n      }\n    } else if (style === 'modern') {\n      const panel = new Mesh(\n        new BoxGeometry(length + 0.02, rim, 0.03),\n        createSurface('paintedMetal', { color: 0xe4e2dc, seed })\n      );\n      panel.position.set(0, rim / 2, width / 2 + 0.02);\n      group.add(panel);\n    }\n  }\n\n  // Taps at one end — except the hip bath, which is the whole point of it.\n  if (style !== 'hip') {\n    const chrome = new MeshStandardMaterial({ color: 0xc4cace, roughness: 0.2, metalness: 0.85 });\n    for (const side of [-1, 1]) {\n      const tap = createTap({\n        style: style === 'clawfoot' ? 'crosshead' : 'pillar',\n        seed: seed + (side > 0 ? 1 : 2),\n        palette,\n      });\n      // On a sunken tub the taps stand on the deck BESIDE the well; the same\n      // inset that works on a rim would hang them over open water.\n      const tapX = style === 'sunken' ? -(length / 2 + 0.07) : -length / 2 + 0.1;\n      tap.object.position.set(tapX, rim + 0.01, side * 0.14);\n      group.add(tap.object);\n      taps.push(tap);\n    }\n    const spout = new Mesh(new CylinderGeometry(0.014, 0.014, 0.12, 8), chrome);\n    spout.rotation.z = Math.PI / 2.4;\n    spout.position.set(style === 'sunken' ? -(length / 2 + 0.01) : -length / 2 + 0.16, rim + 0.06, 0);\n    group.add(spout);\n  }\n\n  const fill = createFill({\n    width: length - 0.12,\n    length: width - 0.12,\n    depth: rim - floorY - 0.04,\n    palette,\n  });\n  fill.object.position.y = floorY;\n  group.add(fill.object);\n\n  // Lie in it: the reclined sleep pose, head at the tap end's opposite.\n  const slot = createSlot('soak', 'sleep', group, length * 0.06, floorY + 0.05, 0, Math.PI / 2, -0.28);\n  addApproach(slot, group, width / 2 + 0.42, 'front');\n\n  let draining = false;\n  return {\n    object: group,\n    obstacleRadius: Math.max(length, width) * 0.55,\n    style,\n    fill,\n    taps,\n    slot,\n    slots: [slot],\n    rim,\n    pour(amount: number) {\n      fill.fillBy(amount);\n    },\n    setDrain(open: boolean) {\n      draining = open;\n    },\n    get draining() {\n      return draining;\n    },\n    update(dt: number) {\n      if (dt <= 0) return;\n      let flow = 0;\n      for (const tap of taps) {\n        tap.update(dt);\n        flow = Math.max(flow, tap.state);\n      }\n      const change = flow * rate * dt - (draining ? rate * 2.4 * dt : 0);\n      if (change !== 0) fill.fillBy(change);\n      fill.update(dt);\n    },\n  };\n}\n\nexport interface JacuzziOptions {\n  /** How many people it seats. Default 4. */\n  seats?: number;\n  /** Radius in metres. Default 1.1. */\n  radius?: number;\n  seed?: number;\n  palette?: Palette;\n}\n\nexport interface Jacuzzi extends Gathering {\n  fill: Fill;\n  steam: Steam;\n  /** How hard the jets are running, 0–1. */\n  readonly jets: number;\n  setJets(power: number): void;\n  update(dt: number): void;\n}\n\n/**\n * A hot tub.\n *\n * A `Gathering` — seats around a rim with a shared focus — because that is\n * what one is socially, and it means GAMA's `Occupancy` fills it and ANIMA's\n * `Conversation` runs in it with nothing new written.\n *\n * The jets are the whole prop: they **agitate the surface** continuously\n * while they run, so the water is visibly churning rather than being a still\n * blue disc with bubbles drawn over it.\n */\nexport function createJacuzzi(options: JacuzziOptions = {}): Jacuzzi {\n  const seatCount = options.seats ?? 4;\n  const radius = options.radius ?? 1.1;\n  const seed = options.seed ?? 1;\n  const rng = new Rng(seed);\n  const palette = options.palette ?? DEFAULT_PALETTE;\n\n  const group = new Group();\n  group.name = 'jacuzzi';\n  const shell = createSurface('paintedMetal', { color: 0x3c4249, roughness: 0.5, seed });\n  const rimH = 0.72;\n\n  // OPEN-ENDED, and this matters more than it looks: a default\n  // CylinderGeometry is capped, so a closed drum has a LID at rim height. It\n  // seals the tub, and every jet, every seat and the entire body of water\n  // render underneath a disc of shell material. Nothing numeric notices.\n  const body = new Mesh(new CylinderGeometry(radius, radius * 0.92, rimH, 20, 1, true), shell);\n  body.position.y = rimH / 2;\n  group.add(body);\n  const under = new Mesh(new CylinderGeometry(radius * 0.92, radius * 0.92, 0.04, 20), shell);\n  under.position.y = 0.02;\n  group.add(under);\n  const cap = new Mesh(\n    new TorusGeometry(radius, 0.055, 6, 22),\n    createSurface('teak', { color: 0x8a6a47, seed: seed + 1 })\n  );\n  cap.rotation.x = Math.PI / 2;\n  cap.position.y = rimH;\n  group.add(cap);\n  // The liner is seen from INSIDE, so it has to be back-faced. An open\n  // cylinder's normals point outward; left alone this one sits inside the\n  // body with every face turned away from the only camera that can ever see\n  // it, which makes it a mesh that costs a draw call and renders nothing.\n  const linerMat = createSurface('glaze', { color: 0xdfe6e8, seed });\n  linerMat.side = BackSide;\n  const inner = new Mesh(\n    new CylinderGeometry(radius - 0.02, radius - 0.1, rimH - 0.06, 20, 1, true),\n    linerMat\n  );\n  inner.position.y = (rimH - 0.06) / 2;\n  group.add(inner);\n\n  const fill = createFill({\n    radius: radius - 0.13,\n    depth: 0.42,\n    level: 0.85,\n    palette,\n  });\n  fill.object.position.y = rimH - 0.52;\n  group.add(fill.object);\n\n  // Jets: droplets rising THROUGH the surface, so they read as coming from\n  // under it rather than raining onto it.\n  const jetPuffs: Droplets[] = [];\n  for (let i = 0; i < seatCount; i++) {\n    const a = (i / seatCount) * Math.PI * 2 + rng.range(-0.2, 0.2);\n    const puff = createDroplets({\n      count: 10,\n      spread: 0.16,\n      rise: 0.12,\n      size: 0.4,\n      maxPixels: 30,\n      color: 0xe8f4f8,\n      seed: seed + i * 3,\n    });\n    puff.mesh.position.set(Math.cos(a) * radius * 0.6, rimH - 0.16, Math.sin(a) * radius * 0.6);\n    group.add(puff.mesh);\n    jetPuffs.push(puff);\n  }\n\n  const steam = createSteam({ radius: radius * 0.7, height: 1.0, count: 12, seed: seed + 9 });\n  steam.object.position.y = rimH - 0.1;\n  group.add(steam.object);\n\n  // Seats around the rim, all facing the middle.\n  const seats: PropSlot[] = [];\n  for (let i = 0; i < seatCount; i++) {\n    const a = (i / seatCount) * Math.PI * 2;\n    const x = Math.cos(a) * (radius - 0.3);\n    const z = Math.sin(a) * (radius - 0.3);\n    const bench = new Mesh(new BoxGeometry(0.34, 0.06, 0.28), shell);\n    bench.position.set(x, rimH - 0.42, z);\n    bench.rotation.y = -a;\n    group.add(bench);\n    // Facing INWARD. A slot anchor faces its own +z, so a seat placed on the\n    // rim without turning it puts the bather's back to everyone else — which\n    // is the single most repeated mistake in this whole session.\n    const slot = createSlot('soak', 'sitLow', group, x, rimH - 0.38, z, Math.atan2(-x, -z));\n    addApproach(slot, group, 0.6, 'behind');\n    seats.push(slot);\n  }\n  const focus = new Object3D();\n  focus.name = 'focus';\n  focus.position.set(0, rimH - 0.02, 0);\n  group.add(focus);\n\n  let jets = 0;\n  return {\n    object: group,\n    obstacleRadius: radius + 0.1,\n    seats,\n    slots: seats,\n    focus,\n    fill,\n    steam,\n    get jets() {\n      return jets;\n    },\n    setJets(power: number) {\n      jets = Math.min(1, Math.max(0, power));\n      for (const puff of jetPuffs) puff.setRate(jets);\n    },\n    update(dt: number) {\n      if (dt <= 0) return;\n      for (const puff of jetPuffs) puff.update(dt);\n      // Churning, continuously, for as long as they run. The surface settling\n      // while the jets are on would be the giveaway.\n      if (jets > 0) fill.disturb(jets * dt * 3.2);\n      fill.update(dt);\n      steam.setTarget(0.35 + jets * 0.55);\n      steam.update(dt);\n    },\n  };\n}\n","import {\n  BoxGeometry,\n  Color,\n  DoubleSide,\n  CylinderGeometry,\n  Group,\n  Mesh,\n  MeshStandardMaterial,\n  PlaneGeometry,\n  TorusGeometry,\n} from 'three';\nimport { Rng } from '../core/random';\nimport { DEFAULT_PALETTE, type Palette } from '../core/palette';\nimport { wavingClothMaterial } from '../materials/clothWave';\nimport type { Prop } from '../core/types';\n\n/**\n * Soft furnishing — curtains, cushions, throws.\n *\n * Curtains are the highest-value item in the whole decoration set and cost\n * almost nothing, because the hard part is already built: `clothWave` has\n * driven the flags, banners and bunting since 0.9. A curtain is that same\n * material stood on its end — fixed along the top edge, free at the hem —\n * and a curtain stirring in a draught is one of the very few things that\n * makes an interior read as *alive* rather than as a photograph of one.\n *\n * ```ts\n * const curtains = createCurtains({ width: 1.2, drop: 1.6, seed: 3 });\n * window.add(curtains.object);\n * game.onUpdate((t) => curtains.update(t.delta));\n * ```\n */\n\nexport type CurtainStyle =\n  /** Two panels drawn back to either side. */\n  | 'open'\n  /** Two panels meeting in the middle. */\n  | 'closed'\n  /** A single sheer panel across the whole opening. */\n  | 'sheer';\n\nexport interface CurtainsOptions {\n  /** Width of the opening being dressed, in metres. Default 1.2. */\n  width?: number;\n  /** Drop from the rail to the hem. Default 1.6. */\n  drop?: number;\n  style?: CurtainStyle;\n  /** Cloth colour. Defaults to a seeded pick. */\n  color?: number;\n  /** Show the rail and rings. Default true. */\n  rail?: boolean;\n  /** How hard the draught blows, 0–1. Default 0.5. */\n  stir?: number;\n  seed?: number;\n  palette?: Palette;\n}\n\nexport interface Curtains extends Prop {\n  /** Advance the stir. Nothing moves without this. */\n  update(dt: number): void;\n  width: number;\n  drop: number;\n}\n\n/**\n * Curtains at a window.\n *\n * The origin is at the **rail**, centred, with everything hanging below —\n * the same convention as the tapestry, and for the same reason: a hanging\n * thing is placed by where it hangs from.\n */\nexport function createCurtains(options: CurtainsOptions = {}): Curtains {\n  const seed = options.seed ?? 1;\n  const rng = new Rng(seed);\n  const palette = options.palette ?? DEFAULT_PALETTE;\n  const width = options.width ?? 1.2;\n  const drop = options.drop ?? 1.6;\n  const style = options.style ?? 'open';\n  const stir = options.stir ?? 0.5;\n\n  const group = new Group();\n  group.name = `curtains-${style}`;\n  const sheer = style === 'sheer';\n  const base = new Color(\n    options.color ??\n      rng.pick([0xb8ae9a, 0x8d9aa6, 0xa8927e, 0x94a08c, new Color(palette.wall).getHex()])\n  );\n\n  const panels = sheer ? 1 : 2;\n  // A drawn-back panel is gathered to about a third of the opening; a closed\n  // one covers half of it each. Either way the cloth is WIDER than the space\n  // it covers, because a curtain is pleated — a panel cut to the exact\n  // opening is a bedsheet nailed to the wall.\n  const cover = sheer ? width : style === 'open' ? width * 0.32 : width * 0.52;\n  const cloth = cover * 1.5;\n\n  const updates: Array<{ uTime: { value: number } }> = [];\n\n  for (let i = 0; i < panels; i++) {\n    const side = panels === 1 ? 0 : i === 0 ? -1 : 1;\n    // The cloth material ripples along its local +X from a fixed edge at\n    // x = 0. A curtain is fixed at the TOP, so the panel is built with +X\n    // running down the drop and then turned to stand up.\n    const material = wavingClothMaterial({\n      freeLen: drop,\n      crossLen: cloth,\n      amp: (sheer ? 0.05 : 0.03) * stir,\n      waves: 1.4 + rng.range(-0.3, 0.3),\n      speed: 0.5 + rng.range(-0.15, 0.15),\n      // Zero: this cloth already hangs, and sag pulls toward the free edge,\n      // which for a curtain is straight down. Adding gravity to gravity\n      // stretches the hem into a spike.\n      sag: 0,\n      phase: rng.next() * 6.28,\n      cacheKey: 'scenaCurtain',\n      color: base.clone().offsetHSL(0, 0, rng.range(-0.04, 0.04)).getHex(),\n      roughness: 0.95,\n    });\n    if (sheer) {\n      material.transparent = true;\n      material.opacity = 0.42;\n    }\n\n    const segsX = 14;\n    const segsY = Math.max(6, Math.round(cloth / 0.06));\n    const geometry = new PlaneGeometry(drop, cloth, segsX, segsY);\n    // Move the fixed edge to x = 0, which is where the wave expects it.\n    geometry.translate(drop / 2, 0, 0);\n    // Pleats: a standing ripple across the width, baked in, deepening a\n    // little toward the hem. This is what the wave rides on top of, and\n    // without it a curtain is a flat sheet however well it moves.\n    const pos = geometry.attributes.position;\n    const folds = Math.max(3, Math.round(cover / 0.09));\n    for (let v = 0; v < pos.count; v++) {\n      const down = pos.getX(v) / drop;\n      const across = pos.getY(v) / cloth + 0.5;\n      pos.setZ(v, Math.sin(across * Math.PI * 2 * folds) * cover * 0.055 * (0.6 + down * 0.5));\n    }\n    pos.needsUpdate = true;\n    geometry.computeVertexNormals();\n\n    const panel = new Mesh(geometry, material);\n    panel.name = 'panel';\n    // +x down, +y across.\n    panel.rotation.z = -Math.PI / 2;\n    panel.position.set(side * (width / 2 - cover / 2), -0.02, 0);\n    group.add(panel);\n    updates.push(material.userData.waveUniforms as { uTime: { value: number } });\n  }\n\n  if (options.rail ?? true) {\n    const metal = new MeshStandardMaterial({ color: 0x8d8578, roughness: 0.45, metalness: 0.6 });\n    const rod = new Mesh(new CylinderGeometry(0.012, 0.012, width + 0.18, 8), metal);\n    rod.rotation.z = Math.PI / 2;\n    group.add(rod);\n    for (const s of [-1, 1]) {\n      const finial = new Mesh(new CylinderGeometry(0.022, 0.022, 0.024, 8), metal);\n      finial.rotation.z = Math.PI / 2;\n      finial.position.x = s * (width / 2 + 0.1);\n      group.add(finial);\n    }\n    // Rings, spaced across whatever the cloth actually covers.\n    const rings = Math.max(4, Math.round(width / 0.14));\n    for (let i = 0; i < rings; i++) {\n      const t = (i + 0.5) / rings;\n      const ring = new Mesh(new TorusGeometry(0.017, 0.004, 4, 10), metal);\n      ring.position.set(-width / 2 + t * width, -0.014, 0);\n      group.add(ring);\n    }\n  }\n\n  return {\n    object: group,\n    obstacleRadius: 0,\n    width,\n    drop,\n    update(dt: number) {\n      for (const u of updates) u.uTime.value += dt;\n    },\n  };\n}\n\nexport interface CushionOptions {\n  /** Edge length in metres. Default 0.4. */\n  size?: number;\n  color?: number;\n  seed?: number;\n  palette?: Palette;\n}\n\n/**\n * A cushion.\n *\n * A box is a brick. What makes a cushion is that it is **fatter in the\n * middle than at the corners**, so the geometry is a box with its corner\n * vertices pulled in and its face centres pushed out.\n */\nexport function createCushion(options: CushionOptions = {}): Prop {\n  const seed = options.seed ?? 1;\n  const rng = new Rng(seed);\n  const palette = options.palette ?? DEFAULT_PALETTE;\n  const size = (options.size ?? 0.4) * rng.range(0.88, 1.12);\n  const thick = size * rng.range(0.26, 0.36);\n\n  const group = new Group();\n  group.name = 'cushion';\n  // An EVEN segment count, so there is a vertex at the centre of each face to\n  // plump. With three there is no middle, and the cushion comes out a box\n  // with slightly rounded corners.\n  const geometry = new BoxGeometry(size, thick, size * rng.range(0.9, 1.05), 4, 2, 4);\n  const pos = geometry.attributes.position;\n  const half = size / 2;\n  for (let i = 0; i < pos.count; i++) {\n    const x = pos.getX(i);\n    const y = pos.getY(i);\n    const z = pos.getZ(i);\n    // How near the middle of the face is this vertex? Corners get squeezed,\n    // the middle gets plumped.\n    const edge = Math.max(Math.abs(x), Math.abs(z)) / half;\n    const plump = 1 - edge * edge;\n    pos.setY(i, y * (1 + plump * 0.55));\n    pos.setX(i, x * (1 - plump * 0.06));\n    pos.setZ(i, z * (1 - plump * 0.06));\n  }\n  pos.needsUpdate = true;\n  geometry.computeVertexNormals();\n\n  const colour = new Color(\n    options.color ?? rng.pick([0x8d6a5a, 0x6b7d8a, 0x9a8a6b, 0x7d6b7a, new Color(palette.roof).getHex()])\n  );\n  // Flat-shaded plain colour, not the `canvas` surface: that shader's grain\n  // is scaled for a tent or a sack, and on a 40 cm cushion it reads as\n  // sandstone. Faceting the plumped geometry is what says \"soft\" here.\n  const cushion = new Mesh(\n    geometry,\n    new MeshStandardMaterial({ color: colour.getHex(), roughness: 0.95, flatShading: true })\n  );\n  cushion.position.y = (thick * 1.55) / 2;\n  cushion.rotation.y = rng.range(-0.3, 0.3);\n  group.add(cushion);\n  return { object: group, obstacleRadius: 0 };\n}\n\nexport interface ThrowOptions {\n  /** How wide the throw lies. Default 0.9. */\n  width?: number;\n  /** How far it hangs down the front of whatever it is over. Default 0.35. */\n  hang?: number;\n  color?: number;\n  seed?: number;\n  palette?: Palette;\n}\n\n/**\n * A throw or blanket draped over an edge: flat along the top, folding over,\n * then hanging down the front with the hem uneven.\n *\n * The origin is the top surface it lies on, so it drops straight onto the\n * end of a bed or the arm of a sofa.\n */\nexport function createThrow(options: ThrowOptions = {}): Prop {\n  const seed = options.seed ?? 1;\n  const rng = new Rng(seed);\n  const palette = options.palette ?? DEFAULT_PALETTE;\n  const width = options.width ?? 0.9;\n  const hang = options.hang ?? 0.35;\n  const lie = width * rng.range(0.4, 0.55);\n\n  const group = new Group();\n  group.name = 'throw';\n  const colour = new Color(\n    options.color ?? rng.pick([0x8a7d6b, 0x6b7a8a, 0x9a8578, 0x7a8a70, new Color(palette.wall).getHex()])\n  );\n  const material = new MeshStandardMaterial({\n    color: colour.getHex(),\n    roughness: 0.96,\n    flatShading: true,\n  });\n\n  const segs = 10;\n  const geometry = new PlaneGeometry(width, lie + hang, 4, segs);\n  const pos = geometry.attributes.position;\n  for (let i = 0; i < pos.count; i++) {\n    const x = pos.getX(i);\n    const along = pos.getY(i) + (lie + hang) / 2; // 0 at the hanging hem\n    let y: number;\n    let z: number;\n    if (along < hang) {\n      // The hanging part: straight down the front face.\n      y = along - hang;\n      z = lie / 2;\n    } else {\n      // The lying part: flat along the top, folding over the edge.\n      const on = along - hang;\n      y = -Math.max(0, 0.02 - on) * 0.5;\n      z = lie / 2 - on;\n    }\n    // A rumple across the width, and an uneven hem — a throw with a straight\n    // edge is a tablecloth.\n    const ripple = Math.sin((x / width) * Math.PI * 5 + seed) * 0.012;\n    pos.setXYZ(i, x, y + ripple + (along < hang ? 0 : 0.008), z + ripple * 0.6);\n    if (along < 0.02) pos.setY(i, y - Math.abs(Math.sin(x * 9 + seed)) * 0.03);\n  }\n  pos.needsUpdate = true;\n  geometry.computeVertexNormals();\n\n  const cloth = new Mesh(geometry, material);\n  // The underside of the fold is in shot the moment the camera drops below\n  // the edge it is draped over.\n  cloth.material.side = DoubleSide;\n  cloth.name = 'cloth';\n  group.add(cloth);\n  return { object: group, obstacleRadius: 0 };\n}\n","import {\n  BoxGeometry,\n  CylinderGeometry,\n  Group,\n  Mesh,\n  MeshStandardMaterial,\n  Object3D,\n  TorusGeometry,\n} from 'three';\nimport { Rng } from '../core/random';\nimport { DEFAULT_PALETTE, type Palette } from '../core/palette';\nimport { createSurface } from '../materials/surface';\nimport { createVessel } from './vessels';\nimport { createFill, createStream, type Fill, type Stream } from './waterworks';\nimport { addApproach, createSlot, type Carryable, type Prop, type PropSlot } from '../core/types';\n\n/**\n * Washing — basins, taps and the vessels you carry water in.\n *\n * The era axis here is a **gameplay** axis, not a styling one, and that is\n * the whole reason this track is worth its own file:\n *\n * - `medieval` — no plumbing at all. Water arrives *in a vessel*, is poured\n *   in by hand, and is thrown out. `pour()` is the entire interface, and the\n *   loop is a fetch-and-carry chore.\n * - `victorian` — a pair of taps over a pedestal, and a plug. Two controls,\n *   because hot and cold arrived separately and mixing was your problem.\n * - `modern` — one mixer lever and a drain. Water on demand.\n *\n * The same three meshes with different textures would be a re-skin. These\n * differ in *what the player does*, which is why `taps` is empty on one of\n * them and `pour` does nothing on another.\n */\n\nexport type BasinEra = 'medieval' | 'victorian' | 'modern';\n\nexport const BASIN_ERAS: BasinEra[] = ['medieval', 'victorian', 'modern'];\n\n/**\n * A tap. Structurally a `Manipulable`, the same as doors and valves, so\n * anything that can operate one of those can operate this.\n */\nexport interface Tap extends Prop {\n  /** Live eased position: 0 shut … 1 wide open. */\n  readonly state: number;\n  readonly open: boolean;\n  toggle(): boolean;\n  set(target: number | boolean): void;\n  update(dt: number): void;\n  onChange?: (open: boolean) => void;\n}\n\nexport type TapStyle =\n  /** A crossed capstan handle that turns. Victorian, and always in pairs. */\n  | 'crosshead'\n  /** A single lever that lifts. Modern. */\n  | 'mixer'\n  /** A small round knurled knob. */\n  | 'pillar'\n  /** A long pump handle that swings down — the thing before plumbing. */\n  | 'pump';\n\nexport interface TapOptions {\n  style?: TapStyle;\n  /** Metal colour. Defaults per style. */\n  color?: number;\n  /** How fast the handle travels toward its target (1/sec). Default 3.5. */\n  speed?: number;\n  seed?: number;\n  palette?: Palette;\n}\n\n/** A tap, valve or pump handle you can turn. */\nexport function createTap(options: TapOptions = {}): Tap {\n  const style = options.style ?? 'pillar';\n  const seed = options.seed ?? 1;\n  const rng = new Rng(seed);\n  const speed = options.speed ?? 3.5;\n\n  const group = new Group();\n  group.name = `tap-${style}`;\n  const brass = style === 'crosshead' || style === 'pump';\n  const metal = new MeshStandardMaterial({\n    color: options.color ?? (brass ? 0xb89a52 : 0xc0c6cc),\n    roughness: brass ? 0.38 : 0.22,\n    metalness: 0.85,\n  });\n\n  // The moving part is always a child of `handle`, so one transform drives\n  // every style and the shape below only has to describe what it looks like.\n  const handle = new Object3D();\n  handle.name = 'handle';\n  let motion: 'turn' | 'lift' | 'swing' = 'turn';\n\n  if (style === 'crosshead') {\n    const stem = new Mesh(new CylinderGeometry(0.008, 0.01, 0.05, 8), metal);\n    stem.position.y = 0.025;\n    group.add(stem);\n    handle.position.y = 0.055;\n    for (let i = 0; i < 2; i++) {\n      const bar = new Mesh(new BoxGeometry(0.056, 0.008, 0.012), metal);\n      bar.rotation.y = (i * Math.PI) / 2;\n      handle.add(bar);\n    }\n    const boss = new Mesh(new CylinderGeometry(0.011, 0.011, 0.012, 8), metal);\n    handle.add(boss);\n    group.add(handle);\n  } else if (style === 'mixer') {\n    const body = new Mesh(new CylinderGeometry(0.017, 0.021, 0.09, 10), metal);\n    body.position.y = 0.045;\n    group.add(body);\n    handle.position.y = 0.09;\n    const lever = new Mesh(new BoxGeometry(0.014, 0.012, 0.075), metal);\n    lever.position.z = 0.032;\n    handle.add(lever);\n    group.add(handle);\n    motion = 'lift';\n  } else if (style === 'pillar') {\n    const body = new Mesh(new CylinderGeometry(0.014, 0.017, 0.055, 10), metal);\n    body.position.y = 0.028;\n    group.add(body);\n    handle.position.y = 0.062;\n    const knob = new Mesh(new CylinderGeometry(0.019, 0.016, 0.018, 10), metal);\n    handle.add(knob);\n    // Knurling: a few ribs, so a turned knob visibly turns. A smooth\n    // cylinder rotating about its own axis is indistinguishable from a\n    // stationary one, which makes the whole control invisible.\n    for (let i = 0; i < 6; i++) {\n      const rib = new Mesh(new BoxGeometry(0.004, 0.02, 0.04), metal);\n      rib.rotation.y = (i / 6) * Math.PI;\n      handle.add(rib);\n    }\n    group.add(handle);\n  } else {\n    const post = new Mesh(new CylinderGeometry(0.03, 0.036, 0.5, 10), metal);\n    post.position.y = 0.25;\n    group.add(post);\n    handle.position.y = 0.46;\n    const arm = new Mesh(\n      new BoxGeometry(0.03, 0.026, 0.34),\n      createSurface('wood', { color: 0x6b4a33, seed })\n    );\n    arm.position.z = 0.15;\n    handle.add(arm);\n    group.add(handle);\n    motion = 'swing';\n  }\n\n  let target = 0;\n  let state = 0;\n  let wasOpen = false;\n  const applyHandle = (): void => {\n    if (motion === 'turn') handle.rotation.y = state * 2.3 + rng.range(0, 0.001);\n    else if (motion === 'lift') handle.rotation.x = -state * 0.6;\n    else handle.rotation.x = state * 0.75;\n  };\n  applyHandle();\n\n  const api: Tap = {\n    object: group,\n    obstacleRadius: 0,\n    get state() {\n      return state;\n    },\n    get open() {\n      return target > 0.5;\n    },\n    toggle() {\n      target = target > 0.5 ? 0 : 1;\n      return target > 0.5;\n    },\n    set(next: number | boolean) {\n      target = typeof next === 'boolean' ? (next ? 1 : 0) : Math.min(1, Math.max(0, next));\n    },\n    update(dt: number) {\n      if (dt <= 0) return;\n      const step = speed * dt;\n      state = target > state ? Math.min(target, state + step) : Math.max(target, state - step);\n      applyHandle();\n      const nowOpen = target > 0.5;\n      if (nowOpen !== wasOpen) {\n        wasOpen = nowOpen;\n        api.onChange?.(nowOpen);\n      }\n    },\n  };\n  return api;\n}\n\nexport interface BasinOptions {\n  era?: BasinEra;\n  /** How fast a fully open tap fills it, in levels per second. Default 0.25. */\n  rate?: number;\n  /** How fast an open drain empties it. Default 0.4. */\n  drainRate?: number;\n  seed?: number;\n  palette?: Palette;\n}\n\nexport interface Basin extends Prop {\n  era: BasinEra;\n  /** The water in the bowl. */\n  fill: Fill;\n  /** Water coming out, on the eras that have plumbing. */\n  stream: Stream | null;\n  /** Taps to operate. **Empty on `medieval`** — that is the point of it. */\n  taps: Tap[];\n  /** Where a character stands to use it. */\n  slot: PropSlot;\n  /** Height of the rim above the floor — where the hands go. */\n  rim: number;\n  /** Tip water in by hand. The medieval loop; works on any era. */\n  pour(amount: number): void;\n  /** Open or close the plug. Medieval basins have none, and ignore this. */\n  setDrain(open: boolean): void;\n  readonly draining: boolean;\n  /** Runs the taps, the stream and the level. Nothing happens without it. */\n  update(dt: number): void;\n}\n\n/**\n * A wash basin, of its era.\n *\n * The whole tap → stream → level loop is wired **inside** the prop, so the\n * caller only ever operates the taps — `basin.taps[0].toggle()` — and calls\n * `update`. It still composes outward: the taps are `Manipulable`s, so\n * GAMA's `Automation` or an interaction system drives them without knowing\n * what a basin is.\n */\nexport function createBasin(options: BasinOptions = {}): Basin {\n  const era = options.era ?? 'modern';\n  const seed = options.seed ?? 1;\n  const rng = new Rng(seed);\n  const palette = options.palette ?? DEFAULT_PALETTE;\n  const rate = options.rate ?? 0.25;\n  const drainRate = options.drainRate ?? 0.4;\n\n  const group = new Group();\n  group.name = `basin-${era}`;\n  const taps: Tap[] = [];\n  let stream: Stream | null = null;\n  let bowlRadius = 0.17;\n  let rim = 0.85;\n  let hasDrain = true;\n\n  if (era === 'medieval') {\n    // A pottery laver in a wooden stand. No plumbing, no plug: the water\n    // comes in from a ewer and goes out of the door.\n    rim = 0.78;\n    hasDrain = false;\n    const wood = createSurface('wood', { color: palette.woodDark, seed });\n    for (let i = 0; i < 3; i++) {\n      const a = (i / 3) * Math.PI * 2 + rng.range(-0.1, 0.1);\n      const leg = new Mesh(new BoxGeometry(0.05, rim, 0.05), wood);\n      leg.position.set(Math.cos(a) * 0.19, rim / 2, Math.sin(a) * 0.19);\n      leg.rotation.set(Math.sin(a) * 0.07, -a, -Math.cos(a) * 0.07);\n      group.add(leg);\n    }\n    const ring = new Mesh(new TorusGeometry(0.2, 0.022, 5, 14), wood);\n    ring.rotation.x = Math.PI / 2;\n    ring.position.y = rim;\n    group.add(ring);\n    const bowl = createVessel({\n      style: 'bowl',\n      height: 0.16,\n      seed: seed + 5,\n      surface: 'terracotta',\n      palette,\n    });\n    bowl.object.position.y = rim - 0.05;\n    group.add(bowl.object);\n    bowlRadius = bowl.radius;\n  } else if (era === 'victorian') {\n    // Pedestal, oval bowl, splashback, and TWO taps — hot and cold arrived\n    // separately and mixing them was the user's problem.\n    rim = 0.84;\n    const ceramic = createSurface('glaze', { color: 0xeeeae2, seed });\n    const pedestal = new Mesh(new CylinderGeometry(0.11, 0.16, rim - 0.14, 12), ceramic);\n    pedestal.position.y = (rim - 0.14) / 2;\n    group.add(pedestal);\n    const bowl = new Mesh(new CylinderGeometry(0.24, 0.17, 0.16, 16), ceramic);\n    bowl.position.y = rim - 0.08;\n    group.add(bowl);\n    const lip = new Mesh(new TorusGeometry(0.24, 0.02, 5, 18), ceramic);\n    lip.rotation.x = Math.PI / 2;\n    lip.position.y = rim;\n    group.add(lip);\n    const splash = new Mesh(new BoxGeometry(0.44, 0.12, 0.03), ceramic);\n    splash.position.set(0, rim + 0.06, -0.2);\n    group.add(splash);\n    bowlRadius = 0.2;\n\n    for (const side of [-1, 1]) {\n      const tap = createTap({ style: 'crosshead', seed: seed + (side > 0 ? 1 : 2), palette });\n      tap.object.position.set(side * 0.13, rim + 0.01, -0.17);\n      group.add(tap.object);\n      taps.push(tap);\n    }\n    const spoutBody = new Mesh(new CylinderGeometry(0.011, 0.011, 0.1, 8), new MeshStandardMaterial({\n      color: 0xb89a52,\n      roughness: 0.38,\n      metalness: 0.85,\n    }));\n    spoutBody.rotation.x = Math.PI / 2.6;\n    spoutBody.position.set(0, rim + 0.07, -0.15);\n    group.add(spoutBody);\n  } else {\n    // A vanity counter with a vessel basin standing on it, and one mixer.\n    rim = 0.92;\n    const counterH = 0.8;\n    const counter = new Mesh(\n      new BoxGeometry(0.72, 0.05, 0.46),\n      createSurface('teak', { color: 0x8a6a47, seed })\n    );\n    counter.position.y = counterH;\n    group.add(counter);\n    for (const side of [-1, 1]) {\n      const panel = new Mesh(\n        new BoxGeometry(0.04, counterH, 0.4),\n        createSurface('paintedMetal', { color: 0x4a5158, seed })\n      );\n      panel.position.set(side * 0.32, counterH / 2, 0);\n      group.add(panel);\n    }\n    const bowl = new Mesh(\n      new CylinderGeometry(0.19, 0.15, 0.12, 18),\n      createSurface('glaze', { color: 0xf4f2ee, seed })\n    );\n    bowl.position.y = counterH + 0.085;\n    group.add(bowl);\n    bowlRadius = 0.16;\n\n    const mixer = createTap({ style: 'mixer', seed: seed + 1, palette });\n    mixer.object.position.set(0, counterH + 0.025, -0.16);\n    group.add(mixer.object);\n    taps.push(mixer);\n    const neck = new Mesh(\n      new CylinderGeometry(0.012, 0.012, 0.16, 8),\n      new MeshStandardMaterial({ color: 0xc0c6cc, roughness: 0.22, metalness: 0.85 })\n    );\n    neck.rotation.x = Math.PI / 2.3;\n    neck.position.set(0, counterH + 0.14, -0.12);\n    group.add(neck);\n  }\n\n  // Where the water goes in. The fill radius has to match the bowl's\n  // INTERIOR — cut to the widest point it pokes out through the sides as a\n  // ring around the outside.\n  const fill = createFill({\n    radius: bowlRadius * 0.86,\n    depth: 0.1,\n    palette,\n  });\n  fill.object.position.y = rim - 0.11;\n  group.add(fill.object);\n\n  // The stream, on the eras that have one. A medieval laver has no spout at\n  // all, so there is nothing to draw and nothing to turn on.\n  if (era !== 'medieval') {\n    stream = createStream({\n      height: rim - (rim - 0.11) - 0.02,\n      radius: 0.009,\n      flow: 0,\n      seed,\n      palette,\n    });\n    stream.object.position.set(0, rim + (era === 'victorian' ? 0.02 : 0.06), -0.09);\n    group.add(stream.object);\n  }\n\n  const slot = createSlot('wash', 'operate', group, 0, 0, 0.46, Math.PI);\n  addApproach(slot, group, 0.4, 'front');\n\n  let draining = false;\n\n  return {\n    object: group,\n    obstacleRadius: 0.4,\n    era,\n    fill,\n    stream,\n    taps,\n    slot,\n    slots: [slot],\n    rim,\n    pour(amount: number) {\n      fill.fillBy(amount);\n    },\n    setDrain(open: boolean) {\n      // A basin with no plug cannot be drained, and quietly pretending it can\n      // would let a medieval scene empty itself.\n      draining = hasDrain && open;\n    },\n    get draining() {\n      return draining;\n    },\n    update(dt: number) {\n      if (dt <= 0) return;\n      let flow = 0;\n      for (const tap of taps) {\n        tap.update(dt);\n        flow = Math.max(flow, tap.state);\n      }\n      if (stream) {\n        stream.setFlow(flow);\n        stream.update(dt);\n      }\n      const change = flow * rate * dt - (draining ? drainRate * dt : 0);\n      if (change !== 0) fill.fillBy(change);\n      fill.update(dt);\n    },\n  };\n}\n\nexport interface EwerOptions {\n  seed?: number;\n  palette?: Palette;\n}\n\n/**\n * A ewer — the jug water arrives in before plumbing does.\n *\n * A `Carryable`, so ANIMA's `Carry` picks it up with no adapter: this is the\n * medieval half of the era axis, and it is a carry loop rather than a switch.\n */\nexport function createEwer(options: EwerOptions = {}): Carryable {\n  const seed = options.seed ?? 1;\n  const jug = createVessel({\n    style: 'jug',\n    height: 0.3,\n    seed,\n    surface: 'terracotta',\n    palette: options.palette,\n  });\n  jug.object.name = 'ewer';\n  return {\n    object: jug.object,\n    obstacleRadius: 0,\n    carry: 'side',\n    grip: { y: jug.height * 0.6 },\n  };\n}\n","import {\n  BufferGeometry,\n  Color,\n  Group,\n  LatheGeometry,\n  Mesh,\n  MeshStandardMaterial,\n  TorusGeometry,\n  Vector2,\n} from 'three';\nimport { Rng } from '../core/random';\nimport { DEFAULT_PALETTE, type Palette } from '../core/palette';\nimport { createSurface, type SurfaceKind } from '../materials/surface';\nimport type { Prop } from '../core/types';\n\n/**\n * Vessels — everything round, from one generator.\n *\n * This kit is otherwise made of boxes, and it shows: a room of props built\n * from `BoxGeometry` has no curves in it anywhere, which reads as a *style*\n * right up until you put a bowl of fruit on the table and discover there is\n * no bowl.\n *\n * A **surface of revolution** fixes that with almost no code. Sample a\n * seeded radius profile up the height, spin it, and the same twenty lines\n * produce a vase, an urn, a bottle, a goblet, a bowl and a candlestick —\n * shapes that would each be a separate hand-modelled prop otherwise. The\n * style is nothing but the list of control points.\n *\n * ```ts\n * const vase = createVessel({ style: 'vase', seed: 4 });\n * dress(table.surfaces[0], [vase, ...], { seed: 4 });\n * ```\n */\nexport type VesselStyle =\n  | 'vase'\n  | 'urn'\n  | 'bottle'\n  | 'jug'\n  | 'goblet'\n  | 'bowl'\n  | 'pot'\n  | 'candlestick';\n\ninterface Recipe {\n  /** Control points as (height fraction, radius as a fraction of height). */\n  stops: Array<[number, number]>;\n  /**\n   * How far down the inside the cavity runs, as a fraction of the height.\n   * 0 leaves it solid — which is fine for a bottle and completely wrong for\n   * a bowl, because the whole of a bowl is the hole in it.\n   */\n  hollow: number;\n  /** Natural height in metres. */\n  height: number;\n  /** Radial segments. Low, and flat-shaded, to match everything else. */\n  segments: number;\n  /** A strap handle down one side. */\n  handle?: boolean;\n  surface: SurfaceKind;\n}\n\nconst RECIPES: Record<VesselStyle, Recipe> = {\n  // Foot, belly, waisted neck, flared lip.\n  vase: {\n    stops: [[0, 0.26], [0.06, 0.31], [0.3, 0.44], [0.56, 0.37], [0.78, 0.23], [0.93, 0.20], [1, 0.25]],\n    hollow: 0.62,\n    height: 0.3,\n    segments: 14,\n    surface: 'terracotta',\n  },\n  // Small foot, wide shoulders high up, short neck. The classic silhouette.\n  urn: {\n    stops: [[0, 0.20], [0.05, 0.27], [0.36, 0.47], [0.6, 0.44], [0.82, 0.28], [0.93, 0.31], [1, 0.29]],\n    hollow: 0.5,\n    height: 0.34,\n    segments: 16,\n    surface: 'terracotta',\n  },\n  // Straight body, hard shoulder, long thin neck.\n  bottle: {\n    stops: [[0, 0.28], [0.08, 0.30], [0.44, 0.30], [0.56, 0.22], [0.68, 0.10], [0.95, 0.09], [1, 0.11]],\n    hollow: 0.2,\n    height: 0.26,\n    segments: 12,\n    surface: 'porcelain',\n  },\n  // A fat bottle with a handle: the thing that actually pours.\n  jug: {\n    stops: [[0, 0.30], [0.07, 0.36], [0.4, 0.42], [0.66, 0.34], [0.82, 0.20], [0.95, 0.19], [1, 0.24]],\n    hollow: 0.55,\n    height: 0.24,\n    segments: 14,\n    handle: true,\n    surface: 'porcelain',\n  },\n  // Foot, stem, cup. Three quite different radii in a short height, which is\n  // exactly what a profile curve is good at and a box is hopeless at.\n  goblet: {\n    stops: [[0, 0.24], [0.05, 0.26], [0.14, 0.07], [0.52, 0.06], [0.6, 0.10], [0.72, 0.26], [1, 0.29]],\n    hollow: 0.34,\n    height: 0.17,\n    segments: 14,\n    surface: 'bronze',\n  },\n  // Wide and shallow, and mostly cavity.\n  bowl: {\n    stops: [[0, 0.34], [0.08, 0.40], [0.45, 0.66], [1, 0.80]],\n    hollow: 0.78,\n    height: 0.1,\n    segments: 16,\n    surface: 'porcelain',\n  },\n  // A plain kitchen pot: slight taper, rolled rim.\n  pot: {\n    stops: [[0, 0.34], [0.08, 0.40], [0.55, 0.44], [0.9, 0.40], [1, 0.44]],\n    hollow: 0.72,\n    height: 0.16,\n    segments: 14,\n    surface: 'terracotta',\n  },\n  // Broad foot, knopped stem, a socket at the top.\n  candlestick: {\n    stops: [\n      [0, 0.32], [0.05, 0.35], [0.13, 0.09], [0.4, 0.075], [0.5, 0.14],\n      [0.6, 0.08], [0.86, 0.075], [0.93, 0.19], [1, 0.16],\n    ],\n    hollow: 0.12,\n    height: 0.22,\n    segments: 12,\n    surface: 'bronze',\n  },\n};\n\n/** Catmull-Rom through the stops, clamped so a bulge cannot invert the wall. */\nfunction sampleProfile(stops: Array<[number, number]>, at: number): number {\n  let i = 0;\n  while (i < stops.length - 2 && stops[i + 1][0] < at) i++;\n  const p0 = stops[Math.max(0, i - 1)];\n  const p1 = stops[i];\n  const p2 = stops[Math.min(stops.length - 1, i + 1)];\n  const p3 = stops[Math.min(stops.length - 1, i + 2)];\n  const span = p2[0] - p1[0];\n  const t = span <= 1e-6 ? 0 : Math.min(1, Math.max(0, (at - p1[0]) / span));\n  const t2 = t * t;\n  const t3 = t2 * t;\n  const r =\n    0.5 *\n    (2 * p1[1] +\n      (-p0[1] + p2[1]) * t +\n      (2 * p0[1] - 5 * p1[1] + 4 * p2[1] - p3[1]) * t2 +\n      (-p0[1] + 3 * p1[1] - 3 * p2[1] + p3[1]) * t3);\n  return Math.max(0.012, r);\n}\n\n/**\n * Build the lathe profile: up the outside, over the rim, and back down the\n * inside.\n *\n * The descent down the inside is what makes a vessel read as a vessel. Stop\n * at the rim and the lathe caps it flat, and a vase becomes an egg — which\n * is fine at fifty metres and obviously wrong the moment anything is put\n * next to it.\n */\nfunction buildProfile(recipe: Recipe, rng: Rng, height: number): Vector2[] {\n  const jitter = (v: number, amount: number): number => v * (1 + rng.range(-amount, amount));\n  const stops = recipe.stops.map(\n    ([y, r], i) =>\n      [i === 0 || i === recipe.stops.length - 1 ? y : jitter(y, 0.03), jitter(r, 0.07)] as [\n        number,\n        number\n      ]\n  );\n\n  const points: Vector2[] = [];\n  const steps = 22;\n  // Bottom: centre out to the foot, so the base is capped.\n  points.push(new Vector2(0, 0));\n  for (let i = 0; i <= steps; i++) {\n    const t = i / steps;\n    points.push(new Vector2(sampleProfile(stops, t) * height, t * height));\n  }\n\n  if (recipe.hollow > 0) {\n    const rim = points[points.length - 1].x;\n    const wall = Math.min(rim * 0.22, height * 0.02);\n    const floor = height * (1 - recipe.hollow);\n    const innerSteps = 12;\n    for (let i = 0; i <= innerSteps; i++) {\n      const t = 1 - i / innerSteps;\n      const y = floor + (height - floor) * t;\n      // Follow the outside in, so the wall keeps a roughly even thickness\n      // instead of a bowl having a rim you could stand on.\n      const outer = sampleProfile(stops, y / height) * height;\n      points.push(new Vector2(Math.max(0.004, outer - wall), y));\n    }\n    points.push(new Vector2(0, floor));\n  }\n  return points;\n}\n\nexport interface VesselOptions {\n  style?: VesselStyle;\n  /** Overall height in metres. Defaults to something sensible per style. */\n  height?: number;\n  /** Base colour. Defaults to the surface's own. */\n  color?: number;\n  /** Override the finish. */\n  surface?: SurfaceKind;\n  seed?: number;\n  palette?: Palette;\n}\n\nexport interface Vessel extends Prop {\n  /** Height in metres, after any seeded variation. */\n  height: number;\n  /** Widest radius, in metres. */\n  radius: number;\n  style: VesselStyle;\n}\n\n/** A round thing: vase, urn, bottle, jug, goblet, bowl, pot or candlestick. */\nexport function createVessel(options: VesselOptions = {}): Vessel {\n  const style = options.style ?? 'vase';\n  const recipe = RECIPES[style];\n  const seed = options.seed ?? 1;\n  const rng = new Rng(seed);\n  const palette = options.palette ?? DEFAULT_PALETTE;\n  // Not every pot is the same pot. A shelf of identical vases is exactly the\n  // repetition this whole track exists to avoid.\n  const height = (options.height ?? recipe.height) * rng.range(0.86, 1.16);\n\n  const group = new Group();\n  group.name = `vessel-${style}`;\n  const material = createSurface(options.surface ?? recipe.surface, {\n    color: options.color,\n    seed,\n    roughness: recipe.surface === 'bronze' ? 0.42 : 0.7,\n  });\n\n  const points = buildProfile(recipe, rng, height);\n  const geometry: BufferGeometry = new LatheGeometry(points, recipe.segments);\n  geometry.computeVertexNormals();\n  const body = new Mesh(geometry, material);\n  body.name = 'body';\n  group.add(body);\n\n  let radius = 0;\n  for (const p of points) radius = Math.max(radius, p.x);\n\n  if (recipe.handle) {\n    // A strap handle: an arc in the plane that contains the vessel's axis and\n    // the outward direction, bulging AWAY from the body with both ends\n    // meeting it. A torus is already in that plane; the first version turned\n    // it a quarter turn about y, which stood the loop across the jug and left\n    // a nub sticking out of its side.\n    const r = height * 0.26;\n    const handle = new Mesh(\n      new TorusGeometry(r, height * 0.042, 6, 14, Math.PI * 1.2),\n      material\n    );\n    handle.position.set(radius * 0.82, height * 0.62, 0);\n    handle.rotation.z = -Math.PI * 0.6;\n    group.add(handle);\n    radius += r * 0.75;\n  }\n\n  if (style === 'candlestick') {\n    // The candle is the point of a candlestick.\n    const candle = new Mesh(\n      new LatheGeometry(\n        [\n          new Vector2(0, 0),\n          new Vector2(height * 0.055, 0),\n          new Vector2(height * 0.05, height * 0.32),\n          new Vector2(0, height * 0.35),\n        ],\n        8\n      ),\n      new MeshStandardMaterial({\n        color: new Color(0xf2e8d0).lerp(new Color(palette.wall), 0.25).getHex(),\n        roughness: 0.85,\n        flatShading: true,\n      })\n    );\n    candle.position.y = height * 0.96;\n    group.add(candle);\n  }\n\n  return {\n    object: group,\n    obstacleRadius: 0,\n    height,\n    radius,\n    style,\n  };\n}\n\nexport const VESSEL_STYLES: VesselStyle[] = [\n  'vase',\n  'urn',\n  'bottle',\n  'jug',\n  'goblet',\n  'bowl',\n  'pot',\n  'candlestick',\n];\n","import {\n  BoxGeometry,\n  CylinderGeometry,\n  DoubleSide,\n  Group,\n  Mesh,\n  MeshStandardMaterial,\n  Object3D,\n  PlaneGeometry,\n  Vector3,\n} from 'three';\nimport { Rng } from '../core/random';\nimport { DEFAULT_PALETTE, type Palette } from '../core/palette';\nimport { createSurface, type SurfaceKind } from '../materials/surface';\nimport {\n  addApproach,\n  createSlot,\n  type Prop,\n  type PropSlot,\n  type WaterBody,\n} from '../core/types';\n\n/**\n * Swimming pools.\n *\n * The prop is the easy half. A pool is a hole with walls, and the trilogy\n * has built holes before — the mistakes are already catalogued: build the\n * shell as **walls around a floor**, never as a solid with a smaller solid\n * inside it; frame the coping, never slab it; and remember a default\n * `CylinderGeometry` has a lid on it.\n *\n * What a pool has that a tub does not is a **floor that slopes**, and that\n * one difference is what makes it a gameplay prop rather than a big bath.\n * `depthAt` is the whole handshake: ANIMA asks how deep the water is where\n * a body is standing, and decides for itself whether that body wades or\n * swims. A pool with one depth everywhere cannot pose the question, which\n * is why the shallow and deep ends are not decoration.\n *\n * ```ts\n * const pool = createPool({ style: 'lido' });\n * scene.add(pool.object);\n * game.onUpdate((t) => pool.update(t.delta));\n * pool.depthAt(swimmer.x, swimmer.z);   // ANIMA's Swimming reads this\n * ```\n */\n\nexport type PoolStyle =\n  /** A small stone plunge bath: steep sides, one depth, steps all round. */\n  | 'plunge'\n  /** A mosaic-lined bathing hall pool, shallow and wide. */\n  | 'bathhouse'\n  /** A mid-century tiled lido: lanes, a sloping floor, a board at the deep end. */\n  | 'lido'\n  /** A modern deck-level pool with a spill edge. */\n  | 'infinity';\n\ninterface StyleSpec {\n  length: number;\n  width: number;\n  shallow: number;\n  deep: number;\n  /** How far the water sits below the coping. An infinity edge is brim-full. */\n  freeboard: number;\n  lining: SurfaceKind;\n  liningColor: number;\n  deck: SurfaceKind;\n  deckColor: number;\n  water: number;\n  lanes: number;\n  ladder: boolean;\n  board: boolean;\n  /** Paved apron beyond the coping. */\n  apron: number;\n}\n\nconst STYLES: Record<PoolStyle, StyleSpec> = {\n  plunge: {\n    length: 3.2, width: 2.4, shallow: 1.1, deep: 1.25, freeboard: 0.14,\n    lining: 'ashlar', liningColor: 0xa8a094, deck: 'stone', deckColor: 0x9c948a,\n    water: 0x2f6d7a, lanes: 0, ladder: false, board: false, apron: 0.9,\n  },\n  bathhouse: {\n    length: 6.0, width: 4.0, shallow: 0.9, deep: 1.2, freeboard: 0.12,\n    lining: 'mosaic', liningColor: 0x3f7fae, deck: 'marble', deckColor: 0xd8d2c4,\n    water: 0x2c7d94, lanes: 0, ladder: false, board: false, apron: 1.4,\n  },\n  lido: {\n    length: 12.0, width: 6.0, shallow: 0.95, deep: 2.4, freeboard: 0.12,\n    lining: 'floortile', liningColor: 0xdcdfe2, deck: 'concrete', deckColor: 0xc6c2b8,\n    water: 0x2b83a6, lanes: 4, ladder: true, board: true, apron: 1.8,\n  },\n  infinity: {\n    length: 8.0, width: 3.4, shallow: 1.3, deep: 1.5, freeboard: 0.015,\n    lining: 'porcelain', liningColor: 0x39434a, deck: 'teak', deckColor: 0x8a6a47,\n    water: 0x1f5f74, lanes: 0, ladder: true, board: false, apron: 1.2,\n  },\n};\n\nexport interface PoolOptions {\n  style?: PoolStyle;\n  /** Long axis (x), metres. Defaults per style. */\n  length?: number;\n  /** Short axis (z), metres. Defaults per style. */\n  width?: number;\n  /** Water depth at the -x end. Defaults per style. */\n  shallow?: number;\n  /** Water depth at the +x end. Defaults per style. */\n  deep?: number;\n  /** Lane markings on the floor. Defaults per style; 0 turns them off. */\n  lanes?: number;\n  /**\n   * Paved apron around the coping, metres. Defaults per style; 0 for none.\n   *\n   * A pool is a **hole**, and a hole cannot be dropped onto a solid ground\n   * plane — the ground is a lid over it, and every pool in the first render\n   * of this prop was an empty frame lying on the tarmac for exactly that\n   * reason. The apron is the prop bringing its own surround, so it reads\n   * correctly the moment it is added to a scene; a caller with real ground\n   * still has to leave a hole for it.\n   */\n  deck?: number;\n  seed?: number;\n  palette?: Palette;\n}\n\n/**\n * Anything with a bottom, a top and rungs — structurally ANIMA's\n * `Climbable`, the same contract `createLadder` publishes.\n */\nexport interface PoolLadder {\n  bottom: Object3D;\n  top: Object3D;\n  rungSpacing: number;\n}\n\nexport interface Pool extends Prop, WaterBody {\n  style: PoolStyle;\n  /** Water depth at each end, in metres. */\n  shallow: number;\n  deep: number;\n  length: number;\n  width: number;\n  /** Standing on the deck at the top of the steps, facing the water. */\n  entry: PropSlot;\n  /** A pool ladder at the deep end, on the styles that have one. */\n  ladder: PoolLadder | null;\n  /** The end of the springboard, on the styles that have one. */\n  board: PropSlot | null;\n  /** Sitting on the edge with your legs in — the most-used pool pose there is. */\n  edges: PropSlot[];\n  update(dt: number): void;\n}\n\n/** How many ripple sources the surface shader tracks at once. */\nconst RIPPLES = 4;\n\n/** Blend two packed hex colours, `t` of the way from `a` to `b`. */\nfunction mixHex(a: number, b: number, t: number): number {\n  const lerp = (shift: number): number =>\n    Math.round(((a >> shift) & 255) * (1 - t) + ((b >> shift) & 255) * t) << shift;\n  return lerp(16) | lerp(8) | lerp(0);\n}\n\n/**\n * The lining shader reads a vertex's height **in the pool's space** to decide\n * what is underwater, so every mesh it is applied to has to be authored in\n * that space: transforms baked into the geometry, meshes left at the origin.\n *\n * Position a lined mesh the ordinary way and the varying carries the *mesh's*\n * own local y instead — a wall centred on its own middle reports heights\n * either side of zero however deep it is sunk, so the waterline lands\n * halfway up every wall independently and the caustics climb the coping.\n */\n\n/**\n * The lining shader: what is underwater looks underwater.\n *\n * Two effects, both keyed off the object-space height against the\n * waterline, because the alternative — tinting the whole mesh — makes the\n * part of the wall *above* the water look wet as well, and a pool whose dry\n * coping is the same colour as its floor reads as a painted trench.\n *\n * The caustics are the part that does the work. A still blue rectangle is a\n * blue rectangle at any level of tinting; a floor with a moving net of\n * light on it is underwater even in a screenshot.\n */\nfunction lineWater(\n  material: MeshStandardMaterial,\n  uniforms: Record<string, { value: number }>,\n  key: string\n): void {\n  const patched = material.onBeforeCompile;\n  material.onBeforeCompile = (shader, renderer) => {\n    patched?.(shader, renderer);\n    Object.assign(shader.uniforms, uniforms);\n    shader.vertexShader = shader.vertexShader\n      .replace(\n        '#include <common>',\n        '#include <common>\\nvarying vec3 vPoolPos;\\nvarying vec3 vPoolNrm;'\n      )\n      .replace(\n        '#include <begin_vertex>',\n        '#include <begin_vertex>\\nvPoolPos = position;\\nvPoolNrm = normal;'\n      );\n    shader.fragmentShader = shader.fragmentShader\n      .replace(\n        '#include <common>',\n        `#include <common>\n         varying vec3 vPoolPos;\n         varying vec3 vPoolNrm;\n         uniform float uPoolTime;\n         uniform float uPoolWaterY;\n         uniform float uPoolCaustic;\n         uniform float uPoolLane;`\n      )\n      .replace(\n        // AFTER the tiling, not before it. createSurface patches map_fragment\n        // and then keeps working on diffuseColor for another twenty lines —\n        // mortar joints, cavity tint, per-cell jitter — so caustics injected\n        // at map_fragment are painted over by the grout of the very tiles\n        // they are supposed to be dancing on. emissivemap_fragment is the\n        // first hook after all of that, and diffuseColor is still in scope.\n        '#include <emissivemap_fragment>',\n        `#include <emissivemap_fragment>\n         {\n           // Underwater fraction. A hard step banding across a sloping floor\n           // is visible as a stair; the smoothstep is 4 cm of waterline.\n           float sub = smoothstep(uPoolWaterY + 0.02, uPoolWaterY - 0.02, vPoolPos.y);\n           // Lane markings, drawn INTO the lining rather than laid on it as\n           // strips of geometry, so they follow the slope of the floor exactly\n           // and stop dead at the waterline like paint does.\n           float lane = 0.0;\n           if (uPoolLane > 0.0) {\n             float band = abs(fract(vPoolPos.z / uPoolLane + 0.5) - 0.5) * uPoolLane;\n             // Only along the floor, and only under water.\n             lane = (1.0 - smoothstep(0.05, 0.10, band))\n                  * smoothstep(uPoolWaterY - 0.35, uPoolWaterY - 0.9, vPoolPos.y);\n           }\n           // Caustics: two interference fields multiplied together. The\n           // product is what gives the branching net; either field on its own\n           // is a corrugation. Cell size matters as much as the shape — at a\n           // two-metre wavelength this reads as a dirty floor.\n           vec2 q = vPoolPos.xz * 6.0;\n           float t = uPoolTime;\n           float a = sin(q.x * 1.1 + t * 1.5) + sin(q.y * 1.3 - t * 1.2)\n                   + sin((q.x + q.y) * 0.7 + t * 0.9);\n           float b = sin((q.x - q.y) * 0.9 - t * 1.1) + sin(q.y * 0.8 + t * 0.6)\n                   + sin(q.x * 0.6 - t * 0.8);\n           // Bright along the ZERO SET of the product, not at its peaks. The\n           // zero set of a*b is the union of two families of curves, which is\n           // a net; thresholding the peaks instead lights up the extrema and\n           // gives a field of round blobs that reads as a dirty floor.\n           float net = pow(1.0 - clamp(abs(a * b) * 0.5, 0.0, 1.0), 3.0);\n           // Depth tint, then the light, then the paint. Painting the lanes\n           // BEFORE the caustics loses them entirely: an additive net at full\n           // strength washes a dark line straight out, and a lane pool with no\n           // lanes in it is just a pool.\n           diffuseColor.rgb *= mix(1.0, 0.62, sub);\n           // Caustics are projected straight down, so on a near-vertical\n           // wall the pattern barely changes over its whole height and comes\n           // out as vertical streaks. Fade them towards the walls: the light\n           // pools on the floor anyway, and a wall gets a wash, not a net.\n           float up = mix(0.22, 1.0, clamp(vPoolNrm.y, 0.0, 1.0));\n           diffuseColor.rgb += net * sub * up * uPoolCaustic * vec3(0.36, 0.62, 0.66)\n                             * (1.0 - lane * 0.65);\n           diffuseColor.rgb = mix(diffuseColor.rgb, vec3(0.07, 0.13, 0.21), lane * 0.85);\n         }`\n      );\n  };\n  material.customProgramCacheKey = () => key;\n}\n\n/** A pool. The origin is at the centre, at **deck** level. */\nexport function createPool(options: PoolOptions = {}): Pool {\n  const style = options.style ?? 'lido';\n  const spec = STYLES[style];\n  const seed = options.seed ?? 1;\n  const rng = new Rng(seed);\n  const palette = options.palette ?? DEFAULT_PALETTE;\n  const length = options.length ?? spec.length;\n  const width = options.width ?? spec.width;\n  const shallow = options.shallow ?? spec.shallow;\n  const deep = options.deep ?? spec.deep;\n  const lanes = options.lanes ?? spec.lanes;\n  const apron = Math.max(0, options.deck ?? spec.apron);\n\n  const group = new Group();\n  group.name = `pool-${style}`;\n\n  // Local geometry. The deck is y = 0, the water sits `freeboard` below it,\n  // and the floor is another `depth` below the water.\n  const waterY = -spec.freeboard;\n  const depthAt = (x: number): number => {\n    const u = Math.min(1, Math.max(0, x / length + 0.5));\n    return shallow + (deep - shallow) * u;\n  };\n  const floorAt = (x: number): number => waterY - depthAt(x);\n  const deepest = Math.max(shallow, deep);\n\n  const uniforms = {\n    uPoolTime: { value: 0 },\n    uPoolWaterY: { value: waterY },\n    uPoolCaustic: { value: 0.85 },\n    uPoolLane: { value: lanes > 0 ? width / lanes : 0 },\n  };\n\n  const lining = createSurface(spec.lining, { color: spec.liningColor, seed });\n  lineWater(lining, uniforms, `scenaPoolLining-${spec.lining}`);\n\n  // --- The tank: four walls round a sloping floor. Not a solid with a\n  // smaller solid inside it, which is invisible, and not a box with a lid.\n  const t = 0.22;\n  const wallH = deepest + 0.4;\n  for (const [w, d, x, z] of [\n    [length + t * 2, t, 0, -(width + t) / 2],\n    [length + t * 2, t, 0, (width + t) / 2],\n    [t, width, -(length + t) / 2, 0],\n    [t, width, (length + t) / 2, 0],\n  ] as Array<[number, number, number, number]>) {\n    const geom = new BoxGeometry(w, wallH, d);\n    geom.translate(x, -wallH / 2, z); // baked, not positioned — see lineWater\n    group.add(new Mesh(geom, lining));\n  }\n\n  // The floor really slopes: a plane with its vertices dropped onto the\n  // depth profile. A flat floor with a \"deep end\" written in the docs is the\n  // version that fails the moment anyone walks into it.\n  const floorGeom = new PlaneGeometry(length, width, 16, 8);\n  const pos = floorGeom.attributes.position;\n  for (let i = 0; i < pos.count; i++) {\n    // Pre-rotation the plane lies in XY, so its x is the pool's x and its\n    // own z is the height that becomes world y once it is laid flat.\n    pos.setZ(i, floorAt(pos.getX(i)));\n  }\n  floorGeom.rotateX(-Math.PI / 2); // baked, not a mesh rotation\n  floorGeom.computeVertexNormals();\n  const floor = new Mesh(floorGeom, lining);\n  floor.name = 'floor';\n  group.add(floor);\n\n  // --- Coping: a FRAME, for the same reason the sunken tub's is. A slab\n  // across the footprint is a lid over the pool.\n  const deckMat = createSurface(spec.deck, { color: spec.deckColor, seed: seed + 1 });\n  const cope = style === 'infinity' ? 0.3 : 0.36;\n  for (const [w, d, x, z] of [\n    [length + cope * 2, cope, 0, -(width + cope) / 2],\n    [length + cope * 2, cope, 0, (width + cope) / 2],\n    [cope, width, -(length + cope) / 2, 0],\n    [cope, width, (length + cope) / 2, 0],\n  ] as Array<[number, number, number, number]>) {\n    const slab = new Mesh(new BoxGeometry(w, 0.08, d), deckMat);\n    slab.position.set(x, -0.04, z);\n    group.add(slab);\n  }\n\n  // The apron. A frame again, for the third time in two tracks: a slab across\n  // the footprint would be a lid on the pool.\n  if (apron > 0) {\n    const ol = length + cope * 2;\n    const ow = width + cope * 2;\n    for (const [w, d, x, z] of [\n      [ol + apron * 2, apron, 0, -(ow + apron) / 2],\n      [ol + apron * 2, apron, 0, (ow + apron) / 2],\n      [apron, ow, -(ol + apron) / 2, 0],\n      [apron, ow, (ol + apron) / 2, 0],\n    ] as Array<[number, number, number, number]>) {\n      const paving = new Mesh(new BoxGeometry(w, 0.06, d), deckMat);\n      paving.position.set(x, -0.05, z);\n      group.add(paving);\n    }\n  }\n\n  // --- The water. A big plane with a travelling chop plus ripple rings that\n  // spread from wherever something disturbed it.\n  const ripples: number[] = [];\n  for (let i = 0; i < RIPPLES; i++) ripples.push(0, 0, -99, 0);\n  const surfaceUniforms = {\n    uPoolTime: uniforms.uPoolTime,\n    uRipples: { value: ripples },\n    uShallow: { value: shallow },\n    uDeep: { value: deep },\n    uLen: { value: length },\n  };\n  const waterMat = new MeshStandardMaterial({\n    // The style's tint is the deliberate one — a plunge bath in shadow and a\n    // lit lido are not the same colour of water — but a scene-wide palette\n    // still gets a say, so the pool belongs to the world it is dropped in.\n    color: mixHex(spec.water, palette.water, 0.25),\n    transparent: true,\n    opacity: 0.8,\n    depthWrite: false,\n    roughness: 0.06,\n    metalness: 0.3,\n    side: DoubleSide,\n  });\n  waterMat.onBeforeCompile = (shader) => {\n    Object.assign(shader.uniforms, surfaceUniforms);\n    shader.vertexShader = shader.vertexShader\n      .replace(\n        '#include <common>',\n        `#include <common>\n         varying vec2 vPoolSurf;\n         uniform float uPoolTime;\n         uniform vec4 uRipples[${RIPPLES}];`\n      )\n      .replace(\n        '#include <begin_vertex>',\n        `#include <begin_vertex>\n         {\n           vPoolSurf = position.xy;\n           // Ambient chop, always there — a mirror-flat pool is a mirror.\n           float chop = sin(position.x * 2.1 + uPoolTime * 1.4)\n                      * cos(position.y * 2.7 - uPoolTime * 1.1);\n           transformed.z += chop * 0.012;\n           // Ripple rings. Each source carries where it was struck, when, and\n           // how hard; the ring travels outward and fades with both distance\n           // and age, which is the difference between a splash and a texture.\n           for (int i = 0; i < ${RIPPLES}; i++) {\n             vec4 r = uRipples[i];\n             float age = uPoolTime - r.z;\n             if (age < 0.0 || age > 4.0) continue;\n             float dist = length(position.xy - r.xy);\n             float front = age * 1.9;\n             float ring = sin((dist - front) * 9.0);\n             float near = exp(-abs(dist - front) * 2.2);\n             transformed.z += ring * near * r.w * 0.05 * (1.0 - age / 4.0);\n           }\n         }`\n      );\n    shader.fragmentShader = shader.fragmentShader\n      .replace(\n        '#include <common>',\n        `#include <common>\n         varying vec2 vPoolSurf;\n         uniform float uShallow;\n         uniform float uDeep;\n         uniform float uLen;`\n      )\n      .replace(\n        '#include <map_fragment>',\n        `#include <map_fragment>\n         {\n           // THE deep end. A pool whose water is one flat colour has a deep\n           // end only in the documentation — from above, depth is read almost\n           // entirely off how much of the floor you can still see through the\n           // water, so the alpha has to follow the floor rather than sit at a\n           // constant. This is the single change that made the prop read as a\n           // pool rather than a blue rectangle.\n           float dep = mix(uShallow, uDeep, clamp(vPoolSurf.x / uLen + 0.5, 0.0, 1.0));\n           float murk = smoothstep(0.5, 2.6, dep);\n           diffuseColor.a *= mix(0.62, 0.97, murk);\n           diffuseColor.rgb *= mix(1.18, 0.52, murk);\n         }`\n      )\n      .replace(\n        '#include <emissivemap_fragment>',\n        `#include <emissivemap_fragment>\n         {\n           // Fresnel. Without it there is no evidence a surface is there at\n           // all: you see straight through to the tiles and the pool reads as\n           // a dry tank painted blue. Water announces itself by going bright\n           // and opaque at a glancing angle, which is why a pool looks like\n           // glass from the far end and like nothing from directly above.\n           float fres = pow(1.0 - clamp(dot(normalize(vViewPosition), normal), 0.0, 1.0), 4.0);\n           totalEmissiveRadiance += vec3(0.20, 0.27, 0.31) * fres;\n           diffuseColor.a = clamp(diffuseColor.a + fres * 0.5, 0.0, 1.0);\n         }`\n      );\n  };\n  waterMat.customProgramCacheKey = () => 'scenaPoolSurface';\n  const surface = new Mesh(new PlaneGeometry(length, width, 48, 24), waterMat);\n  surface.name = 'surface';\n  surface.rotation.x = -Math.PI / 2;\n  surface.position.y = waterY;\n  group.add(surface);\n\n  // --- Steps down into the shallow end.\n  const stepCount = Math.max(2, Math.round(shallow / 0.3));\n  const stepW = Math.min(width * 0.55, 1.6);\n  for (let i = 0; i < stepCount; i++) {\n    const y = -((i + 1) / stepCount) * shallow;\n    const geom = new BoxGeometry(0.34, 0.09, stepW);\n    geom.translate(-length / 2 + 0.17 + i * 0.34, waterY + y + 0.045, 0);\n    group.add(new Mesh(geom, lining));\n  }\n\n  const entry = createSlot('poolEntry', 'stand', group, -length / 2 - cope * 0.6, 0, 0, Math.PI / 2);\n  addApproach(entry, group, 0.8, 'behind');\n\n  // --- A ladder at the deep end, publishing ANIMA's Climbable contract, so\n  // getting out of a pool is the ladder code that already exists.\n  let ladder: PoolLadder | null = null;\n  if (spec.ladder) {\n    const chrome = new MeshStandardMaterial({ color: 0xc4cace, roughness: 0.2, metalness: 0.85 });\n    const rungSpacing = 0.3;\n    const top = 0.85;\n    const foot = floorAt(length / 2 - 0.3) + 0.1;\n    const lg = new Group();\n    lg.name = 'pool:ladder';\n    lg.position.set(length / 2 - 0.45, 0, width / 2 - 0.28);\n    // Facing the water, so a climber on `bottom` is looking at the rungs.\n    lg.rotation.y = Math.PI;\n    group.add(lg);\n    for (const sx of [-1, 1]) {\n      const rail = new Mesh(\n        new CylinderGeometry(0.024, 0.024, top - foot, 8),\n        chrome\n      );\n      rail.position.set(sx * 0.22, (top + foot) / 2, 0);\n      lg.add(rail);\n      // The grab handle above the deck — the bit you actually haul on.\n      const bend = new Mesh(new CylinderGeometry(0.024, 0.024, 0.3, 8), chrome);\n      bend.rotation.z = Math.PI / 2;\n      bend.position.set(sx * 0.22, top, -0.15);\n      lg.add(bend);\n    }\n    for (let y = foot + rungSpacing; y < 0; y += rungSpacing) {\n      const rung = new Mesh(new CylinderGeometry(0.018, 0.018, 0.44, 8), chrome);\n      rung.rotation.z = Math.PI / 2;\n      rung.position.set(0, y, 0);\n      lg.add(rung);\n    }\n    const bottom = new Object3D();\n    bottom.name = 'ladder:bottom';\n    bottom.position.set(0, foot, 0);\n    lg.add(bottom);\n    const topAnchor = new Object3D();\n    topAnchor.name = 'ladder:top';\n    topAnchor.position.set(0, 0, -0.4);\n    lg.add(topAnchor);\n    ladder = { bottom, top: topAnchor, rungSpacing };\n  }\n\n  // --- Springboard over the deep end.\n  let board: PropSlot | null = null;\n  if (spec.board) {\n    const bg = new Group();\n    bg.name = 'pool:board';\n    bg.position.set(length / 2 + cope * 0.5, 0, 0);\n    group.add(bg);\n    const plinth = new Mesh(\n      new BoxGeometry(0.4, 0.55, 0.5),\n      createSurface('paintedMetal', { color: 0xb8bcc0, seed: seed + 2 })\n    );\n    plinth.position.y = 0.275;\n    bg.add(plinth);\n    const plank = new Mesh(\n      new BoxGeometry(1.9, 0.06, 0.44),\n      createSurface('paintedMetal', { color: 0xe8e4d8, seed: seed + 3 })\n    );\n    // Cantilevered OVER the water, not sitting beside it.\n    plank.position.set(-0.75, 0.56, 0);\n    bg.add(plank);\n    board = createSlot('dive', 'stand', bg, -1.5, 0.59, 0, Math.PI / 2);\n    addApproach(board, bg, 1.4, 'behind');\n  }\n\n  // --- Sitting on the edge with your legs in the water. This is the pose\n  // people in pools are actually in most of the time.\n  const edges: PropSlot[] = [];\n  const perSide = style === 'plunge' ? 1 : 2;\n  for (const sz of [-1, 1]) {\n    for (let i = 0; i < perSide; i++) {\n      const x = perSide === 1 ? 0 : (i / (perSide - 1) - 0.5) * length * 0.5;\n      const seat = createSlot(\n        'poolEdge',\n        'sitLow',\n        group,\n        x + rng.range(-0.2, 0.2),\n        0.04,\n        sz * (width / 2 + cope * 0.4),\n        // Facing IN over the water. A slot anchor faces its own +z, so an\n        // edge seat placed without turning it sits everyone facing the car\n        // park.\n        sz > 0 ? Math.PI : 0\n      );\n      addApproach(seat, group, 0.7, 'behind');\n      edges.push(seat);\n    }\n  }\n\n  const local = new Vector3();\n  let nextRipple = 0;\n  let time = 0;\n\n  return {\n    object: group,\n    obstacleRadius: 0,\n    style,\n    shallow,\n    deep,\n    length,\n    width,\n    entry,\n    ladder,\n    board,\n    edges,\n    slots: [entry, ...edges, ...(board ? [board] : [])],\n    get surfaceY() {\n      group.updateWorldMatrix(true, false);\n      return group.localToWorld(new Vector3(0, waterY, 0)).y;\n    },\n    depthAt(x: number, z: number) {\n      group.updateWorldMatrix(true, false);\n      local.set(x, 0, z);\n      group.worldToLocal(local);\n      // Outside the tank there is no water, which is what makes this the\n      // whole \"am I swimming\" test on ANIMA's side.\n      if (Math.abs(local.x) > length / 2 || Math.abs(local.z) > width / 2) return 0;\n      return depthAt(local.x);\n    },\n    disturb(x: number, z: number, strength = 1) {\n      group.updateWorldMatrix(true, false);\n      local.set(x, 0, z);\n      group.worldToLocal(local);\n      // The plane is authored in XY and laid flat, so its own y is the pool's\n      // z — and it is NEGATED by the -90 degree rotation about x.\n      const at = nextRipple * 4;\n      ripples[at] = local.x;\n      ripples[at + 1] = -local.z;\n      ripples[at + 2] = time;\n      ripples[at + 3] = Math.min(1.5, strength);\n      nextRipple = (nextRipple + 1) % RIPPLES;\n    },\n    update(dt: number) {\n      if (dt <= 0) return;\n      time += dt;\n      uniforms.uPoolTime.value = time;\n    },\n  };\n}\n","import {\n  AdditiveBlending,\n  BoxGeometry,\n  CylinderGeometry,\n  DoubleSide,\n  Group,\n  Mesh,\n  MeshBasicMaterial,\n  MeshStandardMaterial,\n  Object3D,\n  TorusGeometry,\n  Vector3,\n} from 'three';\nimport { Rng } from '../core/random';\nimport { DEFAULT_PALETTE, type Palette } from '../core/palette';\nimport { createSurface } from '../materials/surface';\nimport { createGlass } from '../materials/glass';\nimport { makeFlame } from './fire';\nimport { addApproach, createSlot, type Prop, type PropSlot } from '../core/types';\n\n/**\n * Heat: the hearth-to-induction axis.\n *\n * The era is not a texture here, it is **what you have to do to cook**, and\n * it is the same discovery the basins turned on. A medieval fire has no\n * dial: you control it by feeding it and by moving the pot nearer or further\n * away, so heat has to be a **field in space** rather than a number on a\n * device. A gas ring has a knob and heat exists only in a 9 cm circle. Those\n * are different games, not different materials.\n *\n * So the handshake is a spatial query, and it is deliberately the same shape\n * as the pool's:\n *\n * ```ts\n * heatAt(x, z): number   // 0 (cold) .. 1 (full), 0 anywhere out of reach\n * ```\n *\n * mirroring `WaterBody.depthAt`. SCENA answers where the heat is; GAMA and\n * whatever is in the pot decide what that means.\n *\n * The state machine — cold → heating → hot → cooling — is the same shape as\n * the shower's and as GAMA's `Device`, for the third time, because it keeps\n * being the right shape.\n *\n * ```ts\n * const stove = createHeatSource({ era: 'gas' });\n * stove.setPower(1);\n * game.onUpdate((t) => stove.update(t.delta));\n * stove.heatAt(pot.x, pot.z);\n * ```\n */\n\nexport type HeatEra =\n  /** An open fire on a stone hearth, with a swinging crane to hang a pot. */\n  | 'hearth'\n  /** A cast-iron range: enclosed firebox, a damper, graded hotplates, an oven. */\n  | 'range'\n  /** A gas hob: four rings, four knobs, a visible flame, instant. */\n  | 'gas'\n  /** Induction: no flame at all, and heat that outlives the switch. */\n  | 'induction';\n\nexport type HeatState = 'cold' | 'heating' | 'hot' | 'cooling';\n\n/**\n * Where the heat is, in **world** coordinates.\n *\n * The cooking mirror of `WaterBody.depthAt`, and for the same reason: a\n * fire's heat is a place, not a property of a device, and anything that\n * wants to know whether it is cooking should be able to ask about a point.\n */\nexport interface HeatField {\n  /** 0 (cold) to 1 (full heat) at a world point. 0 anywhere out of reach. */\n  heatAt(x: number, z: number): number;\n}\n\n/**\n * Somewhere a pot goes.\n *\n * A zone is a **place**, not a source. Its `heat` is sampled from the field\n * at wherever the zone currently is, which is what lets the hearth's crane\n * work at all: swing the hook away from the fire and it cools, with nothing\n * about it special-cased. Conflate the two — let the hook carry its own heat\n * around with it — and a pot swung out over the flagstones is still boiling.\n */\nexport interface HeatZone {\n  /** Free label: 'hook', 'plate', 'ring'. */\n  kind: string;\n  /** Sits at the surface a pan rests on (or the hook a pot hangs from). */\n  anchor: Object3D;\n  /** How far the zone's heat reaches, in metres. */\n  radius: number;\n  /** This zone's own heat right now, 0–1. */\n  readonly heat: number;\n  /** Demand for this zone, 0–1. Ignored where the era has no separate controls. */\n  setPower(level: number): void;\n  readonly power: number;\n}\n\n/** A control you can operate — structurally a `Manipulable`, like a tap. */\nexport interface HeatControl {\n  readonly state: number;\n  readonly open: boolean;\n  toggle(): boolean;\n  set(target: number | boolean): void;\n  update(dt: number): void;\n  onChange?: (open: boolean) => void;\n  object: Object3D;\n}\n\nexport interface HeatSource extends Prop, HeatField {\n  era: HeatEra;\n  readonly state: HeatState;\n  /** The hottest reading anywhere on it, 0–1. */\n  readonly temperature: number;\n  /** Demand, 0–1. On a fire this is how hard it is burning, not a setting. */\n  readonly power: number;\n  /** Set the demand. With a zone index, on the eras whose rings are separate. */\n  setPower(level: number | boolean, zone?: number): void;\n  zones: HeatZone[];\n  /**\n   * Does it burn fuel? On `hearth` and `range` this is the whole loop: no\n   * fuel, no fire, and `feed` is how it gets there.\n   */\n  readonly burnsFuel: boolean;\n  /** Fuel left, 0–1. Always 1 on the eras that are plumbed or wired. */\n  readonly fuel: number;\n  /** Put another log on. A no-op where there is nothing to burn. */\n  feed(amount?: number): void;\n  /** The knob, damper or crane. Null on an open hearth with neither. */\n  control: HeatControl | null;\n  /** Swing the pot off the fire — the medieval heat control. Hearth only. */\n  crane: HeatControl | null;\n  /** The oven cavity door, on the eras that have an oven. */\n  ovenDoor: HeatControl | null;\n  /** Where a cook stands. */\n  slot: PropSlot;\n  onState?: (state: HeatState) => void;\n  update(dt: number): void;\n}\n\ninterface EraSpec {\n  /** Seconds from cold to hot at full demand. */\n  rise: number;\n  /** Seconds from hot back to cold with the demand off. */\n  fall: number;\n  burnsFuel: boolean;\n  /** Seconds of burn in a full load of fuel. */\n  burnFor: number;\n  /** Can each zone be set separately? */\n  independent: boolean;\n  hasOven: boolean;\n  width: number;\n  depth: number;\n  height: number;\n}\n\n/**\n * The era table, and every number in it is a gameplay decision.\n *\n * Rise and fall are the shape of the thing. A hearth takes twenty seconds to\n * come up and four MINUTES to go down, because embers hold heat; a gas ring\n * is up in under two seconds and gone in six. Induction is as instant as gas\n * going up and deliberately slow going down — the plate is still hot long\n * after the light says off, which is the most interesting property in the\n * set and the only one that can hurt you.\n */\nconst ERAS: Record<HeatEra, EraSpec> = {\n  hearth: { rise: 22, fall: 240, burnsFuel: true, burnFor: 180, independent: false, hasOven: false, width: 1.5, depth: 0.8, height: 0.35 },\n  range: { rise: 70, fall: 320, burnsFuel: true, burnFor: 300, independent: false, hasOven: true, width: 1.25, depth: 0.68, height: 0.92 },\n  gas: { rise: 1.6, fall: 6, burnsFuel: false, burnFor: Infinity, independent: true, hasOven: true, width: 0.9, depth: 0.62, height: 0.92 },\n  induction: { rise: 1.2, fall: 34, burnsFuel: false, burnFor: Infinity, independent: true, hasOven: true, width: 0.9, depth: 0.62, height: 0.92 },\n};\n\nexport interface HeatOptions {\n  era?: HeatEra;\n  /** Rings/plates/hooks. Defaults per era. */\n  zones?: number;\n  /** Start with the fuel bunker full. Default true. */\n  fuelled?: boolean;\n  seed?: number;\n  palette?: Palette;\n}\n\nconst clamp01 = (t: number): number => Math.max(0, Math.min(1, t));\n\n/**\n * A control that eases toward a target, shaped exactly like `Manipulable`.\n *\n * The pointer notch is not decoration. A smooth knob rotating about its own\n * axis is pixel-identical to a stationary one, so the entire control would\n * be invisible — the same trap as the knurled tap handle, and it catches\n * every round thing that turns.\n */\nfunction makeKnob(color: number, speed = 4): HeatControl & { object: Group } {\n  const group = new Group();\n  group.name = 'knob';\n  const metal = new MeshStandardMaterial({ color, roughness: 0.3, metalness: 0.6 });\n  const body = new Mesh(new CylinderGeometry(0.026, 0.03, 0.022, 12), metal);\n  body.rotation.x = Math.PI / 2;\n  group.add(body);\n  const notch = new Mesh(\n    new BoxGeometry(0.006, 0.024, 0.012),\n    new MeshStandardMaterial({ color: 0x1b1b1e, roughness: 0.7 })\n  );\n  notch.position.set(0, 0.016, 0.012);\n  group.add(notch);\n\n  let target = 0;\n  let state = 0;\n  const api: HeatControl & { object: Group } = {\n    object: group,\n    get state() {\n      return state;\n    },\n    get open() {\n      return target > 0.5;\n    },\n    toggle() {\n      const next = !(target > 0.5);\n      api.set(next);\n      return next;\n    },\n    set(value: number | boolean) {\n      const was = target > 0.5;\n      target = typeof value === 'boolean' ? (value ? 1 : 0) : clamp01(value);\n      if (was !== target > 0.5) api.onChange?.(target > 0.5);\n    },\n    update(dt: number) {\n      state += (target - state) * Math.min(1, dt * speed);\n      // Three quarters of a turn from off to full.\n      group.rotation.z = -state * Math.PI * 1.5;\n    },\n  };\n  return api;\n}\n\n/** A pivoting arm — the crane over a hearth, or a hinged door. */\nfunction makeHinge(pivot: Group, axis: 'y' | 'x', swing: number, speed = 2.2): HeatControl {\n  let target = 0;\n  let state = 0;\n  const api: HeatControl = {\n    object: pivot,\n    get state() {\n      return state;\n    },\n    get open() {\n      return target > 0.5;\n    },\n    toggle() {\n      const next = !(target > 0.5);\n      api.set(next);\n      return next;\n    },\n    set(value: number | boolean) {\n      const was = target > 0.5;\n      target = typeof value === 'boolean' ? (value ? 1 : 0) : clamp01(value);\n      if (was !== target > 0.5) api.onChange?.(target > 0.5);\n    },\n    update(dt: number) {\n      state += (target - state) * Math.min(1, dt * speed);\n      pivot.rotation[axis] = state * swing;\n    },\n  };\n  return api;\n}\n\n/**\n * A stove, hob, range or hearth.\n *\n * The origin is on the floor at the centre of the front face, facing +z out\n * into the room.\n */\nexport function createHeatSource(options: HeatOptions = {}): HeatSource {\n  const era = options.era ?? 'gas';\n  const spec = ERAS[era];\n  const seed = options.seed ?? 1;\n  const rng = new Rng(seed);\n  const palette = options.palette ?? DEFAULT_PALETTE;\n  const zoneCount = options.zones ?? (era === 'hearth' ? 2 : era === 'range' ? 2 : 4);\n\n  const group = new Group();\n  group.name = `heat-${era}`;\n\n  const iron = new MeshStandardMaterial({ color: 0x2e3033, roughness: 0.55, metalness: 0.5 });\n  const steel = new MeshStandardMaterial({ color: 0xb8bec4, roughness: 0.28, metalness: 0.8 });\n\n  interface ZoneState {\n    kind: string;\n    anchor: Object3D;\n    radius: number;\n    /** Fraction of the source's heat this zone gets, where they are not separate. */\n    share: number;\n    power: number;\n    heat: number;\n    /** The glowing ring / flame that shows it is on. */\n    show: Object3D | null;\n    material: MeshStandardMaterial | null;\n  }\n  /** What actually produces heat: the fire, the rings, the hotplates. */\n  const emitters: ZoneState[] = [];\n  /** Where a pot goes. Reads the field; may or may not also be an emitter. */\n  const places: Array<{ kind: string; anchor: Object3D; radius: number; source: number | null }> = [];\n  const controls: HeatControl[] = [];\n  let crane: HeatControl | null = null;\n  let ovenDoor: HeatControl | null = null;\n  let control: HeatControl | null = null;\n\n  /** A ring or plate: it emits, and it is also where the pan sits. */\n  const addEmitter = (\n    kind: string,\n    x: number,\n    y: number,\n    z: number,\n    radius: number,\n    share: number\n  ): ZoneState => {\n    const anchor = new Object3D();\n    anchor.name = `zone:${kind}`;\n    anchor.position.set(x, y, z);\n    group.add(anchor);\n    const zone: ZoneState = { kind, anchor, radius, share, power: 0, heat: 0, show: null, material: null };\n    emitters.push(zone);\n    places.push({ kind, anchor, radius, source: emitters.length - 1 });\n    return zone;\n  };\n\n  let flameGroup: Group | null = null;\n  let flameU: { uTime: { value: number } } | null = null;\n  let emberU: { uTime: { value: number } } | null = null;\n\n  if (era === 'hearth') {\n    // A stone back and a raised hearthstone, with the fire on it.\n    const stone = createSurface('stone', { color: palette.rock[0], seed });\n    const back = new Mesh(new BoxGeometry(spec.width, 1.5, 0.16), stone);\n    back.position.set(0, 0.75, -spec.depth / 2 - 0.08);\n    group.add(back);\n    const slab = new Mesh(new BoxGeometry(spec.width, spec.height, spec.depth), stone);\n    slab.position.set(0, spec.height / 2, 0);\n    group.add(slab);\n    for (const sx of [-1, 1]) {\n      const cheek = new Mesh(new BoxGeometry(0.16, 1.1, spec.depth), stone);\n      cheek.position.set(sx * (spec.width / 2 - 0.08), spec.height + 0.55, 0);\n      group.add(cheek);\n    }\n    // Logs and coals.\n    const coals = new MeshStandardMaterial({\n      color: 0x2a1a12,\n      roughness: 0.9,\n      emissive: 0xff5a1e,\n      emissiveIntensity: 0,\n    });\n    const bed = new Mesh(new CylinderGeometry(0.26, 0.3, 0.07, 10), coals);\n    bed.position.set(0, spec.height + 0.035, 0);\n    group.add(bed);\n    for (let i = 0; i < 4; i++) {\n      const log = new Mesh(\n        new CylinderGeometry(0.045, 0.05, rng.range(0.4, 0.55), 6),\n        createSurface('bark', { color: 0x5a4632, seed: seed + i })\n      );\n      log.rotation.set(0, rng.range(0, Math.PI), Math.PI / 2 + rng.range(-0.2, 0.2));\n      log.position.set(rng.range(-0.1, 0.1), spec.height + 0.08, rng.range(-0.08, 0.08));\n      group.add(log);\n    }\n    // Sized to sit INSIDE the opening. The first version was a column of\n    // flame twice the height of the chimney breast, which reads as a house\n    // fire rather than something you would hang a pot over.\n    const fire = makeFlame(rng, 0.5, 5, 0.16, 0.4);\n    fire.group.position.set(0, spec.height + 0.06, 0);\n    group.add(fire.group);\n    flameGroup = fire.group;\n    flameU = fire.flameU;\n    emberU = fire.emberU;\n\n    // The CRANE: a pivoting iron arm with a chain and hook. On a medieval\n    // fire this IS the heat control — there is no dial, you swing the pot\n    // off the flames. It only works because heat is a field: the hook's\n    // reading falls as it moves away, with nothing special-cased.\n    const pivot = new Group();\n    pivot.name = 'crane';\n    pivot.position.set(-spec.width / 2 + 0.14, spec.height, -spec.depth / 2 + 0.1);\n    group.add(pivot);\n    const post = new Mesh(new CylinderGeometry(0.022, 0.022, 1.1, 8), iron);\n    post.position.y = 0.55;\n    pivot.add(post);\n    const arm = new Mesh(new CylinderGeometry(0.018, 0.018, 0.72, 6), iron);\n    arm.rotation.z = Math.PI / 2;\n    arm.position.set(0.36, 1.02, 0);\n    pivot.add(arm);\n    // Long enough to bring a pot DOWN INTO the fire. The first version hung\n    // it level with the crane arm, a metre above the flames, which is a pot\n    // stored on a bracket rather than one being cooked in.\n    const chain = new Mesh(new CylinderGeometry(0.008, 0.008, 0.66, 5), iron);\n    chain.position.set(0.66, 0.69, 0);\n    pivot.add(chain);\n    const hookIron = new Mesh(new TorusGeometry(0.03, 0.007, 4, 10, Math.PI * 1.4), iron);\n    hookIron.rotation.y = Math.PI / 2;\n    hookIron.position.set(0.66, 0.345, 0);\n    pivot.add(hookIron);\n    const hook = new Object3D();\n    hook.name = 'zone:hook';\n    // Where a pot's BASE goes — cookware is authored base-at-origin like\n    // everything else in the library, so the anchor has to be the bottom of\n    // the pot, not the point the bail hangs from.\n    hook.position.set(0.66, 0.3, 0);\n    pivot.add(hook);\n    // The hook is a PLACE, not an emitter. Its anchor rides on the crane, so\n    // swinging the crane moves it through the fire's field and heatAt does\n    // the rest. Give the hook its own heat instead and it carries the fire\n    // around with it: a pot swung out over the flagstones stays boiling.\n    places.push({ kind: 'hook', anchor: hook, radius: 0.28, source: null });\n    crane = makeHinge(pivot, 'y', -Math.PI * 0.55);\n\n    // The fire itself, fixed over the hearthstone. One emitter with a wide,\n    // soft reach — which is exactly what an open fire is.\n    const fireZone = addEmitter('fire', 0, spec.height + 0.1, 0, 1.15, 1);\n    void fireZone;\n\n    // A trivet on the hearthstone — always warm, never hot. Somewhere to\n    // keep a pot without cooking it.\n    if (zoneCount > 1) {\n      const trivet = new Mesh(new TorusGeometry(0.1, 0.012, 4, 10), iron);\n      trivet.rotation.x = Math.PI / 2;\n      trivet.position.set(spec.width / 2 - 0.28, spec.height + 0.06, 0.1);\n      group.add(trivet);\n      const trivetAt = new Object3D();\n      trivetAt.name = 'zone:trivet';\n      trivetAt.position.set(spec.width / 2 - 0.28, spec.height + 0.07, 0.1);\n      group.add(trivetAt);\n      places.push({ kind: 'trivet', anchor: trivetAt, radius: 0.22, source: null });\n    }\n  } else {\n    // A box with a top: range, gas hob, induction. The oven cavity goes in\n    // below, and it is a CAVITY — four walls round a void, never a smaller\n    // box inside a bigger one, which is invisible.\n    const shellMat =\n      era === 'range'\n        ? iron\n        : // A plain material, deliberately. Both procedural options are wrong\n          // here: 'steel' is a high-metalness preset and renders near-BLACK\n          // with nothing in the scene for it to reflect, and 'paintedMetal'\n          // puts a pitted render finish on what should be a smooth enamelled\n          // panel. A modern appliance front has no texture worth simulating.\n          new MeshStandardMaterial({\n            color: era === 'gas' ? 0xd9dbdf : 0x2b2f33,\n            roughness: 0.36,\n            metalness: 0.22,\n          });\n    const t = 0.05;\n    const cavityW = spec.width - 0.22;\n    const cavityH = 0.42;\n    const cavityFloor = 0.2;\n    // Sides, back, base, and the strip above the oven mouth.\n    for (const [w, h, d, x, y, z] of [\n      [t, spec.height, spec.depth, -(spec.width - t) / 2, spec.height / 2, 0],\n      [t, spec.height, spec.depth, (spec.width - t) / 2, spec.height / 2, 0],\n      [spec.width, spec.height, t, 0, spec.height / 2, -(spec.depth - t) / 2],\n      [cavityW, cavityFloor, spec.depth - t, 0, cavityFloor / 2, t / 2],\n      [cavityW, spec.height - cavityFloor - cavityH, spec.depth - t, 0,\n        (spec.height + cavityFloor + cavityH) / 2, t / 2],\n    ] as Array<[number, number, number, number, number, number]>) {\n      const panel = new Mesh(new BoxGeometry(w, h, d), shellMat);\n      panel.position.set(x, y, z);\n      group.add(panel);\n    }\n    const worktop = new Mesh(\n      new BoxGeometry(spec.width, 0.035, spec.depth),\n      era === 'induction'\n        ? createGlass({ frosted: false, tint: 0x14171a })\n        : era === 'gas'\n          ? steel\n          : iron\n    );\n    worktop.name = 'worktop';\n    worktop.position.set(0, spec.height + 0.018, 0);\n    group.add(worktop);\n\n    // The oven door, hinged along its bottom edge so it falls open.\n    const doorPivot = new Group();\n    doorPivot.name = 'ovenDoor';\n    doorPivot.position.set(0, cavityFloor, spec.depth / 2);\n    group.add(doorPivot);\n    const door = new Mesh(new BoxGeometry(cavityW, cavityH, 0.03), shellMat);\n    door.position.set(0, cavityH / 2, 0.015);\n    doorPivot.add(door);\n    if (era !== 'range') {\n      const win = new Mesh(\n        new BoxGeometry(cavityW * 0.62, cavityH * 0.5, 0.006),\n        createGlass({ frosted: true, tint: 0x2a2f33 })\n      );\n      win.position.set(0, cavityH / 2, 0.034);\n      doorPivot.add(win);\n    }\n    const handle = new Mesh(new CylinderGeometry(0.012, 0.012, cavityW * 0.8, 8), steel);\n    handle.rotation.z = Math.PI / 2;\n    handle.position.set(0, cavityH - 0.05, 0.06);\n    doorPivot.add(handle);\n    ovenDoor = makeHinge(doorPivot, 'x', Math.PI / 2, 2.4);\n\n    // Rings on top.\n    const cols = Math.min(2, zoneCount);\n    const rows = Math.ceil(zoneCount / cols);\n    for (let i = 0; i < zoneCount; i++) {\n      const cx = ((i % cols) - (cols - 1) / 2) * (spec.width * 0.42);\n      const cz = (Math.floor(i / cols) - (rows - 1) / 2) * (spec.depth * 0.36);\n      const y = spec.height + 0.036;\n      // On a range the plates are NOT controllable: they are graded by how\n      // near they sit to the firebox, and moving the pan is how you turn one\n      // down. On a hob each ring is its own.\n      const share = era === 'range' ? (i === 0 ? 1 : 0.55) : 1;\n      const zone = addEmitter(era === 'range' ? 'plate' : 'ring', cx, y, cz, era === 'range' ? 0.16 : 0.11, share);\n\n      if (era === 'gas') {\n        const burner = new Mesh(new TorusGeometry(0.055, 0.012, 5, 14), iron);\n        burner.rotation.x = Math.PI / 2;\n        burner.position.set(cx, y, cz);\n        group.add(burner);\n        // A gas ring is a SHORT BLUE CROWN, four centimetres tall. Built\n        // from the wood-fire flame it comes out as a yellow dome a quarter\n        // of a metre across — a bonfire sitting on a worktop, which is what\n        // the first version rendered. Height is the reading: you can see how\n        // hard gas is going, and that is the whole point of it.\n        const crown = new Group();\n        for (const [rb, rt, h, col, op] of [\n          [0.03, 0.058, 0.045, 0x3d7bff, 0.85],\n          [0.016, 0.032, 0.028, 0xcfe6ff, 0.9],\n        ] as Array<[number, number, number, number, number]>) {\n          const cone = new Mesh(\n            new CylinderGeometry(rt, rb, h, 14, 1, true),\n            new MeshBasicMaterial({\n              color: col,\n              transparent: true,\n              opacity: op,\n              blending: AdditiveBlending,\n              depthWrite: false,\n              side: DoubleSide,\n            })\n          );\n          cone.position.y = h / 2;\n          crown.add(cone);\n        }\n        crown.position.set(cx, y + 0.004, cz);\n        crown.visible = false;\n        group.add(crown);\n        zone.show = crown;\n      } else if (era === 'induction') {\n        // No flame at all. A ring painted under the glass that glows.\n        const mat = new MeshStandardMaterial({\n          color: 0x24282c,\n          roughness: 0.5,\n          emissive: 0xff3a10,\n          emissiveIntensity: 0,\n        });\n        const ring = new Mesh(new TorusGeometry(0.085, 0.006, 4, 20), mat);\n        ring.rotation.x = Math.PI / 2;\n        ring.position.set(cx, spec.height + 0.006, cz);\n        group.add(ring);\n        zone.show = ring;\n        zone.material = mat;\n      } else {\n        const mat = new MeshStandardMaterial({\n          color: 0x222427,\n          roughness: 0.7,\n          emissive: 0xff4a12,\n          emissiveIntensity: 0,\n        });\n        const plate = new Mesh(new CylinderGeometry(0.15, 0.15, 0.012, 16), mat);\n        plate.position.set(cx, spec.height + 0.04, cz);\n        group.add(plate);\n        zone.show = plate;\n        zone.material = mat;\n      }\n    }\n\n    // Controls along the front.\n    if (spec.independent) {\n      for (let i = 0; i < zoneCount; i++) {\n        const knob = makeKnob(era === 'gas' ? 0x9aa0a6 : 0x60666c);\n        knob.object.position.set(\n          (i - (zoneCount - 1) / 2) * 0.1,\n          spec.height - 0.02,\n          spec.depth / 2 + 0.01\n        );\n        group.add(knob.object);\n        controls.push(knob);\n      }\n      control = controls[0] ?? null;\n    } else {\n      // One damper for the whole firebox. That is the range's era in a\n      // single object: you can make the fire hotter, and that is all.\n      const damper = makeKnob(0xb89a52, 2.2);\n      damper.object.position.set(spec.width / 2 - 0.14, spec.height - 0.06, spec.depth / 2 + 0.01);\n      group.add(damper.object);\n      controls.push(damper);\n      control = damper;\n      // A firebox door, so it is visibly a thing you feed.\n      const fireDoor = new Mesh(new BoxGeometry(0.26, 0.2, 0.02), iron);\n      fireDoor.position.set(-spec.width / 2 + 0.22, spec.height - 0.16, spec.depth / 2 + 0.01);\n      group.add(fireDoor);\n      const glow = new MeshStandardMaterial({\n        color: 0x1a1210,\n        roughness: 0.9,\n        emissive: 0xff5a1e,\n        emissiveIntensity: 0,\n      });\n      const slot = new Mesh(new BoxGeometry(0.16, 0.03, 0.006), glow);\n      slot.position.set(-spec.width / 2 + 0.22, spec.height - 0.16, spec.depth / 2 + 0.023);\n      group.add(slot);\n      // The firebox glow is an INDICATOR, not somewhere a pan goes: zero\n      // reach, so it never shows up in heatAt, and no entry in `places`.\n      emitters.push({\n        kind: 'firebox', anchor: slot, radius: 0, share: 1, power: 0, heat: 0,\n        show: slot, material: glow,\n      });\n    }\n  }\n\n  const cookAt = createSlot('cook', 'work', group, 0, 0, spec.depth / 2 + 0.42, Math.PI);\n  addApproach(cookAt, group, 0.5, 'behind');\n\n  // ---- state -----------------------------------------------------------\n  let power = 0;\n  let fuel = options.fuelled === false ? 0 : 1;\n  let state: HeatState = 'cold';\n  const world = new Vector3();\n  const probe = new Vector3();\n\n  const setZonePower = (level: number, index?: number): void => {\n    const v = clamp01(level);\n    const target = index === undefined ? null : places[index]?.source ?? null;\n    if (spec.independent && target !== null) {\n      emitters[target].power = v;\n      power = Math.max(...emitters.map((e) => e.power));\n      return;\n    }\n    power = v;\n    for (const e of emitters) e.power = v;\n  };\n\n  const api: HeatSource = {\n    object: group,\n    obstacleRadius: Math.max(spec.width, spec.depth) * 0.55,\n    era,\n    zones: places.map((place, i) => ({\n      kind: place.kind,\n      anchor: place.anchor,\n      radius: place.radius,\n      get heat() {\n        // SAMPLED from the field where the place currently is, never carried.\n        place.anchor.updateWorldMatrix(true, false);\n        const at = place.anchor.getWorldPosition(new Vector3());\n        return api.heatAt(at.x, at.z);\n      },\n      get power() {\n        return place.source === null ? power : emitters[place.source].power;\n      },\n      setPower(level: number) {\n        setZonePower(level, i);\n        const c = place.source === null ? null : controls[place.source];\n        if (spec.independent && c) c.set(clamp01(level));\n      },\n    })),\n    control,\n    crane,\n    ovenDoor,\n    slot: cookAt,\n    slots: [cookAt],\n    burnsFuel: spec.burnsFuel,\n    get fuel() {\n      return spec.burnsFuel ? fuel : 1;\n    },\n    get state() {\n      return state;\n    },\n    get power() {\n      return power;\n    },\n    get temperature() {\n      // What the SOURCE is doing, so a hearth still reads hot while its\n      // pot is swung out over the flagstones.\n      return emitters.reduce((m, e) => Math.max(m, e.heat), 0);\n    },\n    setPower(level: number | boolean, zone?: number) {\n      const v = typeof level === 'boolean' ? (level ? 1 : 0) : level;\n      setZonePower(v, zone);\n      if (spec.independent && zone !== undefined) controls[zone]?.set(clamp01(v));\n      else for (const c of controls) c.set(clamp01(v));\n    },\n    feed(amount = 0.5) {\n      // A no-op where there is nothing to burn, and that IS the era axis:\n      // the same call keeps a hearth alive and does nothing to a gas hob.\n      if (!spec.burnsFuel) return;\n      fuel = clamp01(fuel + amount);\n    },\n    heatAt(x: number, z: number) {\n      group.updateWorldMatrix(true, false);\n      probe.set(x, 0, z);\n      let best = 0;\n      for (const zone of emitters) {\n        if (zone.heat <= 0.001 || zone.radius <= 0) continue;\n        zone.anchor.getWorldPosition(world);\n        const d = Math.hypot(world.x - probe.x, world.z - probe.z);\n        if (d > zone.radius) continue;\n        // Falls off toward the edge rather than stopping at it, so moving a\n        // pot nearer the fire actually does something.\n        best = Math.max(best, zone.heat * (1 - (d / zone.radius) ** 2));\n      }\n      return best;\n    },\n    update(dt: number) {\n      if (dt <= 0) return;\n      const was = state;\n      for (const c of controls) c.update(dt);\n      crane?.update(dt);\n      ovenDoor?.update(dt);\n\n      // Fuel. A fire with nothing left in it goes out however hard the\n      // damper is open, which is the difference between burning and being\n      // switched on.\n      let demand = power;\n      if (spec.burnsFuel) {\n        if (fuel > 0) fuel = Math.max(0, fuel - (dt / spec.burnFor) * (0.3 + power * 0.7));\n        if (fuel <= 0) demand = 0;\n      }\n\n      for (const zone of emitters) {\n        const want = (spec.independent ? zone.power : demand) * zone.share;\n        const rate = want > zone.heat ? dt / spec.rise : dt / spec.fall;\n        zone.heat += Math.sign(want - zone.heat) * Math.min(Math.abs(want - zone.heat), rate);\n        zone.heat = clamp01(zone.heat);\n        if (zone.material) zone.material.emissiveIntensity = zone.heat * 1.05;\n        if (zone.show && !zone.material) {\n          // A gas flame: visible only while there is gas, and its SIZE is\n          // the reading. Drawing a full flame at 10% is a hob that lies.\n          zone.show.visible = want > 0.02;\n          const s = 0.35 + want * 0.65;\n          zone.show.scale.set(1, s, 1);\n        }\n      }\n      if (flameGroup) {\n        // The hearth's fire is the fuel, not the demand.\n        const alive = spec.burnsFuel ? Math.max(fuel > 0 ? 0.35 : 0, api.temperature) : api.temperature;\n        flameGroup.visible = alive > 0.02;\n        flameGroup.scale.set(0.6 + alive * 0.4, 0.45 + alive * 0.55, 0.6 + alive * 0.4);\n      }\n      const t = api.temperature;\n      const wanted = spec.independent ? Math.max(...emitters.map((e) => e.power)) : demand;\n      if (t < 0.03) state = 'cold';\n      else if (wanted > t + 0.02) state = 'heating';\n      else if (wanted > 0.02) state = 'hot';\n      else state = 'cooling';\n      if (state !== was) api.onState?.(state);\n\n      if (flameU && emberU) {\n        const clock = (flameU.uTime.value += dt);\n        emberU.uTime.value = clock;\n      }\n    },\n  };\n  return api;\n}\n\n/** An open cooking hearth: a fire on a stone, with a crane to hang a pot. */\nexport function createHearth(options: Omit<HeatOptions, 'era'> = {}): HeatSource {\n  return createHeatSource({ ...options, era: 'hearth' });\n}\n\n/** A cast-iron range: one firebox, one damper, graded plates and an oven. */\nexport function createRange(options: Omit<HeatOptions, 'era'> = {}): HeatSource {\n  return createHeatSource({ ...options, era: 'range' });\n}\n\n/** A modern hob and oven — `gas` burns visibly, `induction` does not burn. */\nexport function createHob(\n  options: Omit<HeatOptions, 'era'> & { era?: 'gas' | 'induction' } = {}\n): HeatSource {\n  return createHeatSource({ ...options, era: options.era ?? 'gas' });\n}\n","import {\n  BoxGeometry,\n  CylinderGeometry,\n  DoubleSide,\n  Group,\n  Mesh,\n  MeshStandardMaterial,\n  SphereGeometry,\n  TorusGeometry,\n  Vector3,\n} from 'three';\nimport { Rng } from '../core/random';\nimport { DEFAULT_PALETTE, type Palette } from '../core/palette';\nimport { createFill, createSteam, type Fill, type Steam } from './waterworks';\nimport type { HeatControl, HeatField } from './heat';\nimport type { Carryable, CarryStyle } from '../core/types';\n\n/**\n * Cookware, and what is in it.\n *\n * The heat track made a field; this is the thing that reads it. A pan is a\n * container with **contents that change**, and the change is the whole prop:\n * raw → cooking → done → burnt, driven entirely by how hot it is where the\n * pan is standing.\n *\n * Two things make it behave rather than tick:\n *\n * - **The pan has its own temperature**, and it lags. Food does not start\n *   cooking the instant a ring is lit, and a cauldron takes far longer to\n *   come up than a frying pan, because there is a great deal more iron in\n *   it. Drive `progress` straight off `heatAt` and everything cooks the\n *   moment it is put down, which is a timer, not a stove.\n * - **Water boils away.** A pot left on goes dry, and a dry pot burns. That\n *   one rule is what turns \"wait for the bar to fill\" into something you\n *   have to watch.\n *\n * ```ts\n * const pot = createCookware({ kind: 'pot' });\n * pot.add(0.8, { cookFor: 40 });\n * game.onUpdate((t) => pot.update(t.delta, stove));  // reads heatAt itself\n * ```\n */\n\nexport type CookwareKind =\n  /** A deep lidded pot with two loop handles. */\n  | 'pot'\n  /** A shallow frying pan with one long handle. */\n  | 'pan'\n  /** A kettle: spout, swing handle, and it whistles. */\n  | 'kettle'\n  /** A big bellied cauldron on three feet, for hanging over a fire. */\n  | 'cauldron'\n  /** An oven tray. */\n  | 'tray';\n\nexport type CookState = 'raw' | 'cooking' | 'done' | 'burnt';\n\ninterface KindSpec {\n  radius: number;\n  height: number;\n  /** Seconds for the vessel itself to come up to the heat under it. */\n  mass: number;\n  /** Fraction of the level boiled off per second at a rolling boil. */\n  boilOff: number;\n  lid: boolean;\n  carry: CarryStyle;\n  metal: number;\n  rough: number;\n}\n\n/**\n * Mass is the interesting column. A frying pan is up in four seconds and a\n * cauldron takes nearly a minute, which is the difference between searing\n * something and putting a stew on.\n */\nconst KINDS: Record<CookwareKind, KindSpec> = {\n  pot: { radius: 0.115, height: 0.15, mass: 12, boilOff: 0.012, lid: true, carry: 'crate', metal: 0xb9bec4, rough: 0.35 },\n  pan: { radius: 0.13, height: 0.055, mass: 4, boilOff: 0.05, lid: false, carry: 'tray', metal: 0x3a3d41, rough: 0.5 },\n  kettle: { radius: 0.09, height: 0.12, mass: 7, boilOff: 0.02, lid: true, carry: 'side', metal: 0xc2c8ce, rough: 0.3 },\n  cauldron: { radius: 0.19, height: 0.24, mass: 52, boilOff: 0.006, lid: false, carry: 'crate', metal: 0x2b2c2e, rough: 0.72 },\n  tray: { radius: 0.16, height: 0.035, mass: 3, boilOff: 0.03, lid: false, carry: 'tray', metal: 0x54585c, rough: 0.62 },\n};\n\n/** Colours the contents pass through. Raw food is pale; burnt food is not. */\nconst RAW = new Vector3(0.63, 0.55, 0.4);\nconst DONE = new Vector3(0.55, 0.33, 0.14);\nconst BURNT = new Vector3(0.07, 0.06, 0.055);\n\nexport interface CookwareOptions {\n  kind?: CookwareKind;\n  /** Seconds at a good heat to go from raw to done. Default 30. */\n  cookFor?: number;\n  /** Starting contents, 0–1. Default 0 (empty). */\n  level?: number;\n  seed?: number;\n  palette?: Palette;\n}\n\nexport interface Cookware extends Carryable {\n  kind: CookwareKind;\n  /** How hot the VESSEL is, 0–1. Lags the heat under it by its own mass. */\n  readonly temperature: number;\n  readonly state: CookState;\n  /** 0 raw … 1 done, and on past 1 toward burnt. */\n  readonly progress: number;\n  /** How full it is, 0–1. Falls while it boils. */\n  readonly level: number;\n  readonly boiling: boolean;\n  /** A kettle at the boil, until somebody takes it off. */\n  readonly whistling: boolean;\n  fill: Fill;\n  steam: Steam;\n  /** The lid, on the kinds that have one. Closed cooks faster. */\n  lid: HeatControl | null;\n  /** Put food or water in. `cookFor` overrides how long this batch takes. */\n  add(amount?: number, options?: { cookFor?: number }): void;\n  /** Tip it out and start again. */\n  empty(): void;\n  onState?: (state: CookState) => void;\n  /** Fires once each time a kettle comes to the boil. */\n  onWhistle?: () => void;\n  /**\n   * Advance it. Pass the stove — it reads `heatAt` at its own world\n   * position, so moving the pan is all it takes — or a number if the caller\n   * has already sampled the field.\n   */\n  update(dt: number, heat?: HeatField | number): void;\n}\n\nconst clamp01 = (t: number): number => Math.max(0, Math.min(1, t));\n\n/**\n * An open-topped vessel body: a wall you can see BOTH sides of, plus a base.\n *\n * `DoubleSide` on an open cylinder is the cheap answer to the shape that has\n * now produced defects in three separate tracks. A solid cylinder with a\n * smaller one hollowed out of it is invisible; a capped one is a tin.\n */\nfunction bowlBody(\n  rTop: number,\n  rBottom: number,\n  height: number,\n  material: MeshStandardMaterial\n): Group {\n  const g = new Group();\n  const wall = new Mesh(new CylinderGeometry(rTop, rBottom, height, 18, 1, true), material);\n  wall.position.y = height / 2;\n  g.add(wall);\n  const base = new Mesh(new CylinderGeometry(rBottom, rBottom, 0.008, 18), material);\n  base.position.y = 0.004;\n  g.add(base);\n  const rim = new Mesh(new TorusGeometry(rTop, 0.006, 4, 18), material);\n  rim.rotation.x = Math.PI / 2;\n  rim.position.y = height;\n  g.add(rim);\n  return g;\n}\n\n/** A pot, pan, kettle, cauldron or tray, with contents that cook. */\nexport function createCookware(options: CookwareOptions = {}): Cookware {\n  const kind = options.kind ?? 'pot';\n  const spec = KINDS[kind];\n  const seed = options.seed ?? 1;\n  const rng = new Rng(seed);\n  const palette = options.palette ?? DEFAULT_PALETTE;\n\n  const group = new Group();\n  group.name = `cookware-${kind}`;\n  const metal = new MeshStandardMaterial({\n    color: spec.metal,\n    roughness: spec.rough,\n    metalness: kind === 'cauldron' ? 0.35 : 0.72,\n  });\n  const dark = new MeshStandardMaterial({ color: 0x1e2022, roughness: 0.6, metalness: 0.4 });\n\n  let lid: HeatControl | null = null;\n  const innerR = spec.radius * 0.9;\n\n  if (kind === 'tray') {\n    // Four walls round a floor, for the same reason as everything else.\n    const w = spec.radius * 2;\n    const d = spec.radius * 1.4;\n    const t = 0.008;\n    const floor = new Mesh(new BoxGeometry(w, t, d), metal);\n    floor.position.y = t / 2;\n    group.add(floor);\n    for (const [bw, bd, x, z] of [\n      [w, t, 0, -(d - t) / 2],\n      [w, t, 0, (d - t) / 2],\n      [t, d - t * 2, -(w - t) / 2, 0],\n      [t, d - t * 2, (w - t) / 2, 0],\n    ] as Array<[number, number, number, number]>) {\n      const wall = new Mesh(new BoxGeometry(bw, spec.height, bd), metal);\n      wall.position.set(x, spec.height / 2, z);\n      group.add(wall);\n    }\n  } else if (kind === 'cauldron') {\n    // A belly: wide in the middle, narrower at the mouth and the base.\n    const belly = new Mesh(\n      new SphereGeometry(spec.radius, 16, 10, 0, Math.PI * 2, Math.PI * 0.32, Math.PI * 0.68),\n      metal\n    );\n    belly.material.side = DoubleSide;\n    belly.position.y = spec.radius * 0.86;\n    group.add(belly);\n    const rim = new Mesh(new TorusGeometry(spec.radius * 0.83, 0.009, 4, 18), metal);\n    rim.rotation.x = Math.PI / 2;\n    rim.position.y = spec.height;\n    group.add(rim);\n    for (let i = 0; i < 3; i++) {\n      const a = (i / 3) * Math.PI * 2;\n      const foot = new Mesh(new CylinderGeometry(0.012, 0.016, 0.06, 5), metal);\n      foot.position.set(Math.cos(a) * spec.radius * 0.6, 0.03, Math.sin(a) * spec.radius * 0.6);\n      group.add(foot);\n    }\n    // The bail handle, which is how it hangs on a crane hook.\n    const bail = new Mesh(new TorusGeometry(spec.radius * 0.92, 0.008, 4, 16, Math.PI), metal);\n    bail.rotation.y = Math.PI / 2;\n    bail.position.y = spec.height;\n    group.add(bail);\n  } else {\n    group.add(bowlBody(spec.radius, spec.radius * 0.88, spec.height, metal));\n    if (kind === 'pan') {\n      const handle = new Mesh(new CylinderGeometry(0.011, 0.013, 0.22, 7), dark);\n      handle.rotation.z = Math.PI / 2;\n      handle.rotation.y = 0;\n      handle.position.set(spec.radius + 0.11, spec.height * 0.75, 0);\n      group.add(handle);\n    } else if (kind === 'kettle') {\n      // A spout, angled up so it would actually pour.\n      const spout = new Mesh(new CylinderGeometry(0.012, 0.022, 0.11, 8), metal);\n      spout.rotation.z = -Math.PI * 0.34;\n      spout.position.set(spec.radius + 0.03, spec.height * 0.78, 0);\n      group.add(spout);\n      const swing = new Mesh(new TorusGeometry(spec.radius * 0.95, 0.007, 4, 14, Math.PI), metal);\n      swing.rotation.y = Math.PI / 2;\n      swing.position.y = spec.height;\n      group.add(swing);\n    } else {\n      for (const sx of [-1, 1]) {\n        const ear = new Mesh(new TorusGeometry(0.026, 0.006, 4, 10, Math.PI), metal);\n        ear.rotation.set(Math.PI / 2, 0, sx > 0 ? 0 : Math.PI);\n        ear.position.set(sx * (spec.radius + 0.012), spec.height * 0.8, 0);\n        group.add(ear);\n      }\n    }\n  }\n\n  // ---- contents --------------------------------------------------------\n  const fill = createFill({\n    radius: innerR * 0.94,\n    depth: spec.height * 0.85,\n    level: options.level ?? 0,\n    color: 0xa08c66,\n    palette,\n  });\n  fill.object.position.y = kind === 'cauldron' ? spec.height * 0.24 : 0.01;\n  group.add(fill.object);\n  // The fill's colour is fixed at construction, and the whole point here is\n  // that it is not: reach the surface material so the contents can darken\n  // from raw through done to burnt.\n  const surfaceMesh = fill.object.children.find((c) => c.name === 'surface') as\n    | (Mesh & { material: MeshStandardMaterial })\n    | undefined;\n\n  // Sized to the pan. A pot's steam is a wisp off a 20 cm mouth, not the\n  // column a bathroom shower makes, and the default was reading as fog\n  // hanging in the air a metre and a half above the stove.\n  const steam = createSteam({\n    radius: spec.radius * 0.5,\n    height: 0.3 + spec.radius,\n    count: 8,\n    seed: seed + 3,\n  });\n  steam.object.position.y = spec.height + 0.02;\n  group.add(steam.object);\n\n  // ---- the lid ---------------------------------------------------------\n  if (spec.lid) {\n    const pivot = new Group();\n    pivot.name = 'lid';\n    pivot.position.set(0, spec.height, 0);\n    group.add(pivot);\n    const disc = new Mesh(new CylinderGeometry(spec.radius * 0.98, spec.radius * 0.98, 0.008, 18), metal);\n    pivot.add(disc);\n    const knob = new Mesh(new SphereGeometry(0.014, 7, 5), dark);\n    knob.position.y = 0.014;\n    pivot.add(knob);\n\n    let target = 1; // starts ON\n    let state = 1;\n    lid = {\n      object: pivot,\n      get state() {\n        return state;\n      },\n      // `open` reads as \"the lid is ON\", because that is the state that\n      // matters to the cooking: closed is the fast one.\n      get open() {\n        return target > 0.5;\n      },\n      toggle() {\n        const next = !(target > 0.5);\n        lid!.set(next);\n        return next;\n      },\n      set(value: number | boolean) {\n        const was = target > 0.5;\n        target = typeof value === 'boolean' ? (value ? 1 : 0) : clamp01(value);\n        if (was !== target > 0.5) lid!.onChange?.(target > 0.5);\n      },\n      update(dt: number) {\n        state += (target - state) * Math.min(1, dt * 5);\n        // Off means tipped up and set aside, not vanished.\n        pivot.position.set((1 - state) * spec.radius * 1.5, spec.height + (1 - state) * 0.02, 0);\n        pivot.rotation.z = (1 - state) * -1.1;\n      },\n    };\n  }\n\n  // ---- state -----------------------------------------------------------\n  let temperature = 0;\n  let level = clamp01(options.level ?? 0);\n  let progress = 0;\n  let cookFor = options.cookFor ?? 30;\n  let state: CookState = level > 0 ? 'raw' : 'raw';\n  let whistling = false;\n  const world = new Vector3();\n  const tint = new Vector3();\n  void rng;\n\n  const api: Cookware = {\n    object: group,\n    obstacleRadius: 0,\n    kind,\n    carry: spec.carry,\n    grip: { y: spec.height * 0.5 },\n    fill,\n    steam,\n    lid,\n    get temperature() {\n      return temperature;\n    },\n    get state() {\n      return state;\n    },\n    get progress() {\n      return progress;\n    },\n    get level() {\n      return level;\n    },\n    get boiling() {\n      return level > 0 && temperature > 0.55;\n    },\n    get whistling() {\n      return whistling;\n    },\n    add(amount = 1, opts = {}) {\n      level = clamp01(level + amount);\n      if (opts.cookFor !== undefined) cookFor = opts.cookFor;\n      progress = 0;\n      state = 'raw';\n      fill.setLevel(level);\n    },\n    empty() {\n      level = 0;\n      progress = 0;\n      state = 'raw';\n      whistling = false;\n      fill.setLevel(0);\n    },\n    update(dt: number, heat?: HeatField | number) {\n      if (dt <= 0) return;\n      lid?.update(dt);\n\n      let under = 0;\n      if (typeof heat === 'number') under = clamp01(heat);\n      else if (heat) {\n        group.updateWorldMatrix(true, false);\n        group.getWorldPosition(world);\n        under = clamp01(heat.heatAt(world.x, world.z));\n      }\n\n      // The vessel's own temperature, lagging by its mass. A lid keeps the\n      // heat in, so it comes up faster and holds better.\n      const lidOn = lid ? lid.state : 0;\n      // `mass` IS the time constant in seconds, so it goes in unscaled. A\n      // stray multiplier here quietly divides every number in the table:\n      // the first version had a cauldron coming up in four seconds and a\n      // frying pan in a third of one, which makes the whole column\n      // decorative.\n      const rate = (dt / spec.mass) * (1 + lidOn * 0.6);\n      temperature += (under - temperature) * Math.min(1, rate);\n      temperature = clamp01(temperature);\n\n      const was = state;\n      if (level > 0) {\n        // Boiling off. A pot left on goes dry, and a dry pot burns — which\n        // is the rule that makes any of this worth watching.\n        if (api.boiling) {\n          const off = spec.boilOff * (temperature - 0.5) * 2 * (1 - lidOn * 0.55) * dt;\n          level = Math.max(0, level - off);\n          fill.setLevel(level);\n        }\n        // Cooking only happens in a band. Barely warm does nothing.\n        if (temperature > 0.28) {\n          progress += (dt / cookFor) * (0.4 + temperature * 1.2) * (1 + lidOn * 0.35);\n        }\n        if (progress >= 1.9 || (level <= 0 && temperature > 0.5)) state = 'burnt';\n        else if (progress >= 1) state = 'done';\n        else if (progress > 0.02) state = 'cooking';\n        else state = 'raw';\n      }\n\n      // Steam while it is boiling, and no steam once it has burnt dry.\n      // Steam follows the WATER, not the verdict on the food. Keying it off\n      // `burnt` alone silences a pot that has caught but is still half full\n      // of stock, which is exactly when it steams hardest.\n      const steaming = api.boiling ? 0.55 + temperature * 0.45 : 0;\n      steam.setTarget(level <= 0 && state === 'burnt' ? 0.15 : steaming);\n      steam.update(dt);\n      if (api.boiling) fill.disturb(dt * 1.6);\n      fill.update(dt);\n\n      // The contents darken as they go. Raw is pale, done is brown, burnt\n      // is nearly black — and the fill's colour is the only thing anybody\n      // actually reads from across a kitchen.\n      if (surfaceMesh) {\n        // Driven by the STATE, not by progress alone. A pot that catches\n        // because it boiled dry never got past `done` on the timer, so a\n        // purely progress-based ramp leaves it looking half-cooked while it\n        // is reporting itself burnt — the label and the colour disagreeing\n        // about the same pan.\n        const char = clamp01((progress - 1) / 0.9);\n        if (state === 'burnt') tint.copy(DONE).lerp(BURNT, Math.max(0.8, char));\n        else if (progress <= 1) tint.copy(RAW).lerp(DONE, clamp01(progress));\n        else tint.copy(DONE).lerp(BURNT, char);\n        surfaceMesh.material.color.setRGB(tint.x, tint.y, tint.z);\n      }\n\n      // A kettle whistles when it boils, once, until it is taken off.\n      if (kind === 'kettle') {\n        const should = api.boiling && temperature > 0.7;\n        if (should && !whistling) {\n          whistling = true;\n          api.onWhistle?.();\n        } else if (!should) {\n          whistling = false;\n        }\n      }\n\n      if (state !== was) api.onState?.(state);\n    },\n  };\n  void palette;\n  return api;\n}\n\nexport const COOKWARE_KINDS: CookwareKind[] = ['pot', 'pan', 'kettle', 'cauldron', 'tray'];\n","import {\n  BoxGeometry,\n  CylinderGeometry,\n  Group,\n  Mesh,\n  MeshStandardMaterial,\n  Object3D,\n  SphereGeometry,\n  TorusGeometry,\n  Vector3,\n} from 'three';\nimport { Rng } from '../core/random';\nimport { DEFAULT_PALETTE, type Palette } from '../core/palette';\nimport { createSurface } from '../materials/surface';\nimport { drive, finish, makeBurst, workSlot, type WorkStation } from './workstations';\n\n/**\n * Preparation: the two-handed half of a kitchen.\n *\n * Every work loop the trilogy has so far is **one-handed or symmetric** — an\n * axe, a pick, a saw, a spoon. Preparing food is neither. One hand does the\n * work and the other **steadies it and gets out of the way**, and that\n * asymmetry is the entire read: a cook chopping an onion with two identical\n * hands is a cook hammering an onion.\n *\n * So a prep station publishes two anchors rather than one:\n *\n * ```ts\n * station.work   // where the knife, pestle or handle is\n * station.guide  // where the other hand holds the thing steady\n * ```\n *\n * ANIMA's `Prepping` poses to that pair. It is the same division of labour\n * as `heatAt` and `depthAt`: SCENA says where things are, ANIMA decides what\n * a body does about it.\n *\n * ```ts\n * const board = createPrepStation({ kind: 'board' });\n * board.onYield = (n) => console.log('chopped', n);\n * game.onUpdate((t) => board.update(t.delta, cook.working));\n * ```\n */\n\nexport type PrepKind =\n  /** A chopping board with a knife and something to cut. */\n  | 'board'\n  /** A mortar and pestle: one hand braces the bowl, the other grinds. */\n  | 'mortar'\n  /** A hand quern — two stones and a crank. Turning it must be visible. */\n  | 'quern'\n  /** A dough trough: both hands push, out of phase. */\n  | 'trough'\n  /** A mixing bowl held at an angle while the other hand whisks. */\n  | 'bowl';\n\n/**\n * A station a cook works at with **both hands doing different things**.\n *\n * `work` and `guide` are the pair. Everything else is the `WorkStation`\n * contract from the rhythmic-work track, so these drop into the same\n * machinery, the same slots and the same yield loop.\n */\nexport interface PrepStation extends WorkStation {\n  kind: PrepKind;\n  /** Where the working hand is — knife, pestle, crank handle. */\n  work: Object3D;\n  /** Where the steadying hand is — on the food, the rim, the bowl. */\n  guide: Object3D;\n  /** How much is left to prepare, 1 → 0. Refill with `load`. */\n  readonly remaining: number;\n  /** Put more on the board. */\n  load(amount?: number): void;\n}\n\nexport interface PrepOptions {\n  kind?: PrepKind;\n  /** How many cycles a full load takes. Default 8. */\n  batch?: number;\n  seed?: number;\n  palette?: Palette;\n}\n\ninterface KindSpec {\n  /** The ANIMA loop name a worker plays here. */\n  action: string;\n  /** Seconds per cycle. */\n  cycle: number;\n  /** Where in the cycle the thing actually happens. */\n  impact: number;\n  /** Working surface height. */\n  bench: number;\n}\n\nconst KINDS: Record<PrepKind, KindSpec> = {\n  board: { action: 'chopBoard', cycle: 0.55, impact: 0.55, bench: 0.92 },\n  mortar: { action: 'grind', cycle: 1.1, impact: 0.5, bench: 0.92 },\n  quern: { action: 'crank', cycle: 1.6, impact: 0.9, bench: 0.78 },\n  trough: { action: 'knead', cycle: 1.5, impact: 0.6, bench: 0.86 },\n  bowl: { action: 'whisk', cycle: 0.8, impact: 0.9, bench: 0.92 },\n};\n\n/** A bench, board, mortar, quern or trough — somewhere to prepare food. */\nexport function createPrepStation(options: PrepOptions = {}): PrepStation {\n  const kind = options.kind ?? 'board';\n  const spec = KINDS[kind];\n  const seed = options.seed ?? 1;\n  const rng = new Rng(seed);\n  const palette = options.palette ?? DEFAULT_PALETTE;\n  const batch = options.batch ?? 8;\n\n  const group = new Group();\n  group.name = `prep-${kind}`;\n  const wood = createSurface('wood', { color: palette.wood, seed });\n  const dark = createSurface('wood', { color: palette.woodDark, seed: seed + 1 });\n  const stone = createSurface('granite', { color: 0x8d8b86, seed: seed + 2 });\n  const steel = new MeshStandardMaterial({ color: 0xc6ccd2, roughness: 0.25, metalness: 0.8 });\n\n  // A bench for everything except the quern, which stands on its own legs.\n  if (kind !== 'quern') {\n    const top = new Mesh(new BoxGeometry(1.1, 0.06, 0.62), wood);\n    top.position.y = spec.bench - 0.03;\n    group.add(top);\n    for (const sx of [-1, 1]) {\n      for (const sz of [-1, 1]) {\n        const leg = new Mesh(new BoxGeometry(0.07, spec.bench - 0.06, 0.07), dark);\n        leg.position.set(sx * 0.48, (spec.bench - 0.06) / 2, sz * 0.24);\n        group.add(leg);\n      }\n    }\n  }\n\n  const work = new Object3D();\n  work.name = 'prep:work';\n  const guide = new Object3D();\n  guide.name = 'prep:guide';\n  group.add(work, guide);\n\n  /** Whatever moves once per cycle — the knife, the pestle, the crank. */\n  let mover: Object3D | null = null;\n  let tool: Object3D = new Group();\n  const bursts = [];\n\n  if (kind === 'board') {\n    const board = new Mesh(new BoxGeometry(0.42, 0.022, 0.3), dark);\n    board.position.set(0.05, spec.bench + 0.011, 0.02);\n    group.add(board);\n    // Something to cut, in a row, so the guide hand has a reason to retreat.\n    for (let i = 0; i < 5; i++) {\n      const piece = new Mesh(\n        new CylinderGeometry(0.028, 0.028, 0.02, 8),\n        new MeshStandardMaterial({ color: 0xe4d9a8, roughness: 0.75, flatShading: true })\n      );\n      piece.rotation.x = Math.PI / 2;\n      piece.position.set(-0.09 + i * 0.035, spec.bench + 0.032, 0.02);\n      group.add(piece);\n    }\n    const knife = new Group();\n    const blade = new Mesh(new BoxGeometry(0.18, 0.005, 0.045), steel);\n    blade.position.set(0.09, 0, 0);\n    const grip = new Mesh(new CylinderGeometry(0.012, 0.014, 0.09, 6), dark);\n    grip.rotation.z = Math.PI / 2;\n    knife.add(blade, grip);\n    knife.position.set(0.06, spec.bench + 0.05, 0.02);\n    group.add(knife);\n    mover = knife;\n    tool = knife;\n    work.position.set(0.06, spec.bench + 0.06, 0.02);\n    guide.position.set(-0.13, spec.bench + 0.05, 0.02);\n  } else if (kind === 'mortar') {\n    const bowl = new Mesh(new CylinderGeometry(0.11, 0.075, 0.1, 14), stone);\n    bowl.position.set(0, spec.bench + 0.05, 0);\n    group.add(bowl);\n    const hollow = new Mesh(\n      new CylinderGeometry(0.085, 0.05, 0.07, 14, 1, true),\n      stone\n    );\n    hollow.material.side = 2; // seen from inside\n    hollow.position.set(0, spec.bench + 0.07, 0);\n    group.add(hollow);\n    const pestle = new Group();\n    const shaft = new Mesh(new CylinderGeometry(0.017, 0.026, 0.13, 8), stone);\n    const head = new Mesh(new SphereGeometry(0.028, 8, 6), stone);\n    head.position.y = -0.065;\n    pestle.add(shaft, head);\n    pestle.position.set(0.01, spec.bench + 0.14, 0);\n    group.add(pestle);\n    mover = pestle;\n    tool = pestle;\n    work.position.set(0.01, spec.bench + 0.18, 0);\n    // The bracing hand is on the RIM, and it barely moves. That stillness is\n    // the read: a mortar that is not being held down slides across the bench.\n    guide.position.set(-0.11, spec.bench + 0.09, 0.01);\n  } else if (kind === 'quern') {\n    const base = new Mesh(new CylinderGeometry(0.24, 0.28, spec.bench - 0.14, 12), dark);\n    base.position.y = (spec.bench - 0.14) / 2;\n    group.add(base);\n    const bed = new Mesh(new CylinderGeometry(0.26, 0.26, 0.06, 16), stone);\n    bed.position.y = spec.bench - 0.11;\n    group.add(bed);\n    const runner = new Group();\n    const upper = new Mesh(new CylinderGeometry(0.25, 0.25, 0.07, 16), stone);\n    runner.add(upper);\n    // The handle IS the tell. A smooth stone turning about its own axis is\n    // pixel-identical to a stationary one — the knurled-knob trap, third\n    // time — so the crank stands proud and sweeps a visible circle.\n    const peg = new Mesh(new CylinderGeometry(0.016, 0.016, 0.16, 6), dark);\n    peg.position.set(0.17, 0.11, 0);\n    runner.add(peg);\n    const knob = new Mesh(new SphereGeometry(0.026, 8, 6), dark);\n    knob.position.set(0.17, 0.2, 0);\n    runner.add(knob);\n    runner.position.y = spec.bench - 0.04;\n    group.add(runner);\n    mover = runner;\n    tool = knob;\n    work.position.set(0.17, spec.bench + 0.16, 0);\n    // Both hands are on a quern, but only one turns: the other steadies the\n    // bed stone.\n    guide.position.set(-0.2, spec.bench - 0.05, 0.05);\n  } else if (kind === 'trough') {\n    const trough = new Mesh(new BoxGeometry(0.5, 0.1, 0.34), wood);\n    trough.position.set(0, spec.bench + 0.05, 0);\n    group.add(trough);\n    const dough = new Mesh(\n      new SphereGeometry(0.11, 10, 7),\n      new MeshStandardMaterial({ color: 0xe8dcc0, roughness: 0.9, flatShading: true })\n    );\n    dough.scale.set(1, 0.55, 0.85);\n    dough.position.set(0, spec.bench + 0.11, 0);\n    group.add(dough);\n    mover = dough;\n    tool = dough;\n    // Both hands work, half a cycle apart, which is its own kind of\n    // asymmetry: at any instant one is pushing and the other is drawing back.\n    work.position.set(0.07, spec.bench + 0.17, 0.04);\n    guide.position.set(-0.08, spec.bench + 0.17, -0.02);\n  } else {\n    const bowl = new Mesh(new CylinderGeometry(0.15, 0.09, 0.12, 16, 1, true), wood);\n    bowl.material.side = 2;\n    const bowlGroup = new Group();\n    bowlGroup.add(bowl);\n    const base = new Mesh(new CylinderGeometry(0.09, 0.09, 0.008, 16), wood);\n    base.position.y = -0.06;\n    bowlGroup.add(base);\n    // Tilted, because a bowl you are whisking in is always tipped toward you.\n    bowlGroup.rotation.x = -0.32;\n    bowlGroup.position.set(-0.02, spec.bench + 0.09, 0.02);\n    group.add(bowlGroup);\n    const whisk = new Group();\n    const handle = new Mesh(new CylinderGeometry(0.011, 0.013, 0.11, 6), dark);\n    handle.position.y = 0.06;\n    whisk.add(handle);\n    for (let i = 0; i < 4; i++) {\n      const a = (i / 4) * Math.PI;\n      const loop = new Mesh(new TorusGeometry(0.026, 0.0025, 3, 10, Math.PI), steel);\n      loop.rotation.set(0, a, 0);\n      loop.position.y = -0.02;\n      whisk.add(loop);\n    }\n    whisk.position.set(0.02, spec.bench + 0.15, 0.05);\n    group.add(whisk);\n    mover = whisk;\n    tool = whisk;\n    work.position.set(0.02, spec.bench + 0.22, 0.05);\n    guide.position.set(-0.15, spec.bench + 0.1, 0.04);\n  }\n\n  // Something flies off each cycle: chips, flour, dust.\n  const spray = makeBurst(rng, {\n    origin: new Vector3(0, spec.bench + 0.06, 0.02),\n    color: kind === 'quern' || kind === 'trough' ? 0xe8dcc0 : 0xd8cfa8,\n    count: 14,\n    size: 0.016,\n    speed: kind === 'board' ? 1.0 : 0.6,\n    up: 0.9,\n    life: 0.5,\n  });\n  group.add(spray.mesh);\n  bursts.push(spray);\n\n  let remaining = 1;\n  const core = drive(\n    spec.action,\n    spec.cycle,\n    spec.impact,\n    () => {\n      spray.emit(kind === 'board' ? 10 : 6);\n      remaining = Math.max(0, remaining - 1 / batch);\n    },\n    bursts\n  );\n\n  // The station's own motion, layered on top of the shared driver.\n  const baseUpdate = core.update.bind(core);\n  let clock = 0;\n  core.update = (dt: number, working = true) => {\n    // Nothing left to prepare means nothing happens, however hard the cook\n    // works. An empty board that still throws chips is a board with a hole\n    // in the loop.\n    baseUpdate(dt, working && remaining > 0);\n    if (dt <= 0) return;\n    if (working && remaining > 0) clock += dt;\n    const p = (clock / spec.cycle) % 1;\n    if (!mover) return;\n    if (kind === 'board') {\n      // Slow lift, fast fall — a knife does not float down.\n      const lift = p < 0.6 ? Math.sin((Math.PI / 2) * (p / 0.6)) : Math.max(0, 1 - (p - 0.6) / 0.14);\n      mover.position.y = spec.bench + 0.03 + lift * 0.11;\n      mover.rotation.z = lift * 0.22;\n    } else if (kind === 'mortar') {\n      mover.position.y = spec.bench + 0.13 + Math.abs(Math.sin(Math.PI * p)) * 0.03;\n      mover.position.x = 0.01 + Math.cos(Math.PI * 2 * p) * 0.018;\n      mover.position.z = Math.sin(Math.PI * 2 * p) * 0.018;\n    } else if (kind === 'quern') {\n      mover.rotation.y = clock * (Math.PI * 2) / spec.cycle;\n    } else if (kind === 'trough') {\n      mover.position.z = Math.sin(Math.PI * 2 * p) * 0.03;\n      mover.scale.set(1 + Math.sin(Math.PI * 2 * p) * 0.06, 0.55, 0.85);\n    } else {\n      mover.rotation.z = Math.sin(Math.PI * 2 * p) * 0.3;\n      mover.position.x = 0.02 + Math.cos(Math.PI * 2 * p) * 0.02;\n      mover.position.z = 0.05 + Math.sin(Math.PI * 2 * p) * 0.02;\n    }\n  };\n\n  const slot = workSlot(spec.action, group, 0, spec.bench * 0 + 0.55, Math.PI);\n  const station = finish(group, 0.55, slot, tool, core) as PrepStation;\n  station.kind = kind;\n  station.work = work;\n  station.guide = guide;\n  Object.defineProperty(station, 'remaining', { get: () => remaining });\n  station.load = (amount = 1) => {\n    remaining = Math.min(1, remaining + amount);\n  };\n  return station;\n}\n\nexport const PREP_KINDS: PrepKind[] = ['board', 'mortar', 'quern', 'trough', 'bowl'];\n","import {\n  CylinderGeometry,\n  DoubleSide,\n  Group,\n  Mesh,\n  MeshStandardMaterial,\n  PlaneGeometry,\n  Quaternion,\n  Vector2,\n  Vector3,\n} from 'three';\nimport { Rng } from '../core/random';\nimport { DEFAULT_PALETTE, type Palette } from '../core/palette';\nimport { createSurface } from '../materials/surface';\nimport type { Prop } from '../core/types';\n\n/**\n * Sail — and why you cannot go where you are pointing.\n *\n * `createWindField` has been in the library since the flora track, and its\n * `sample(x, z)` has never once been read by anything that moves. This is\n * the thing that reads it, and it produces the deepest movement constraint\n * in the whole trilogy from one function.\n *\n * A sail's drive is not a throttle. It is a **curve against the angle to\n * the wind**, and the interesting part of that curve is where it goes to\n * zero:\n *\n * ```ts\n * driveAt(angleOffWind): number   // 0 inside the no-go, peak on a reach\n * ```\n *\n * Inside roughly forty-five degrees of the wind — more for a square rig,\n * much more — a sailing vessel makes **no ground at all**. She stops, the\n * sails flog, and she is in irons. So the shortest path from here to there\n * stops being a straight line: to go upwind you sail across it, twice, and\n * every steering system in GAMA has only ever known how to point at a\n * target and drive.\n *\n * ```ts\n * const rig = createSailRig({ kind: 'lateen' });\n * ship.object.add(rig.object);\n * rig.setWind(wind);\n * game.onUpdate((t) => {\n *   rig.update(t.delta);\n *   ship.update(t.delta, { speed: rig.drive * 9, turn: helm });\n * });\n * rig.layline(bearingToPort);   // …and which way to point to get there\n * ```\n */\n\nexport type RigKind =\n  /** A square sail: magnificent downwind, hopeless anywhere near the wind. */\n  | 'square'\n  /** A lateen yard — the Mediterranean answer, and it points far better. */\n  | 'lateen'\n  /** Gaff: four-sided fore-and-aft, the working rig of the age of steam. */\n  | 'gaff'\n  /** Bermudan: the modern triangle, and the closest-winded of the four. */\n  | 'bermudan';\n\n/** Anything that can tell you the wind. Structurally SCENA's `WindField`. */\nexport interface WindSource {\n  sample(x: number, z: number, time?: number): Vector2;\n}\n\nexport interface SailRig extends Prop {\n  kind: RigKind;\n  /**\n   * Radians off the wind inside which she will not sail — the **no-go**.\n   *\n   * Published rather than inferred, because a helmsman needs it to plan\n   * and an AI needs it to avoid steering into a stall it cannot recover\n   * from by pointing harder.\n   */\n  readonly noGo: number;\n  /** How much canvas is set, 0 (furled) to 1 (everything). */\n  readonly set: number;\n  /** Set or shorten sail. */\n  setSail(amount: number): void;\n  /** Shorten by this much — `reef(0.3)` takes a third of it in. */\n  reef(amount?: number): void;\n  /** Angle of the apparent wind off the bow, 0 (dead ahead) to π (astern). */\n  readonly windAngle: number;\n  /** Drive along the hull's heading, 0–1. Multiply by your hull speed. */\n  readonly drive: number;\n  /**\n   * Sideways force, 0–1 — what heels her over.\n   *\n   * **Not a fixed fraction of `drive`.** The rig's force is roughly square\n   * to the canvas and the canvas is trimmed at about half the angle to the\n   * wind, so drive is that force's forward component and this is its\n   * sideways one: the RATIO between them is `cot(windAngle / 2)` times how\n   * tender she is. Dead downwind that is zero and she does not heel at all\n   * however hard she is driving; hard on the wind a tender rig is over one\n   * and she lies down further than she goes.\n   *\n   * Where the force itself peaks falls out of the two curves together, and\n   * it is not where intuition puts it: on a **close reach**, not\n   * close-hauled — and further aft the older the rig, because a square sail\n   * makes nothing at all up near the wind to be pressed by.\n   */\n  readonly heelForce: number;\n  /** Are the sails flogging? True in irons, and while sheets are let fly. */\n  readonly luffing: boolean;\n  /** Bind the wind. */\n  setWind(wind: WindSource | null): void;\n  /**\n   * The polar curve itself, for anybody planning a course.\n   *\n   * `angleOffWind` in radians, 0 = straight into it. Returns 0 inside the\n   * no-go, and peaks on a reach for everything except a square rig — whose\n   * best point of sailing is dead astern.\n   */\n  driveAt(angleOffWind: number): number;\n  /**\n   * What heading to steer to make ground toward `bearing`.\n   *\n   * **The function the track exists for.** If the bearing is sailable it\n   * hands it straight back. If it is inside the no-go it returns the closer\n   * of the two close-hauled headings instead — which is to say it tells you\n   * to tack, and the straight line was never available. The course it gives\n   * back is always one she will actually sail: laid a couple of degrees\n   * outside the no-go, never on the boundary itself.\n   */\n  layline(bearing: number, currentHeading?: number): number;\n  update(dt: number): void;\n}\n\ninterface KindSpec {\n  /** Radians off the wind she will not sail inside. */\n  noGo: number;\n  /**\n   * The polar: drive at 0°, 30°, 60°, 90°, 120°, 150°, 180° off the wind.\n   *\n   * This table IS the era axis, and it is not a reskin — the shapes are\n   * genuinely different curves. A square rig's best point of sailing is\n   * dead downwind and it cannot work to windward at all, which is why\n   * getting anywhere upwind took the age of sail centuries and a lateen\n   * yard. A Bermudan sloop's peak is on a reach and it is still making\n   * five-sixths of it at fifty degrees.\n   */\n  polar: [number, number, number, number, number, number, number];\n  /** Height of the mast, metres. */\n  mast: number;\n  /**\n   * How tender she is — the whole rig-and-hull's willingness to lie over.\n   *\n   * A scale on the side force, not its shape: the shape comes from the\n   * angle to the wind and is the same trigonometry for everybody. A square\n   * rigger is a deep beamy box that stands up to it; a Bermudan sloop is a\n   * tall lever on a light hull and lies down.\n   */\n  heel: number;\n}\n\nconst KINDS: Record<RigKind, KindSpec> = {\n  square: {\n    noGo: 1.22, // ~70°\n    polar: [0, 0, 0, 0.30, 0.72, 0.94, 1.0],\n    mast: 11, heel: 0.38,\n  },\n  lateen: {\n    noGo: 0.96, // ~55°\n    polar: [0, 0, 0.52, 0.86, 1.0, 0.88, 0.62],\n    mast: 10, heel: 0.62,\n  },\n  gaff: {\n    noGo: 0.87, // ~50°\n    polar: [0, 0, 0.66, 0.95, 1.0, 0.82, 0.52],\n    mast: 12, heel: 0.66,\n  },\n  bermudan: {\n    noGo: 0.70, // ~40°\n    polar: [0, 0, 0.84, 1.0, 0.96, 0.74, 0.44],\n    mast: 13, heel: 0.68,\n  },\n};\n\nexport interface SailOptions {\n  kind?: RigKind;\n  /** Overall scale of the rig. Default 1. */\n  scale?: number;\n  /** Start with sail set. Default 1. */\n  set?: number;\n  seed?: number;\n  palette?: Palette;\n}\n\nconst clamp01 = (t: number): number => (t < 0 ? 0 : t > 1 ? 1 : t);\nconst TAU = Math.PI * 2;\n/** How far outside the no-go a layline is laid — ~2°, i.e. do not pinch. */\nconst PINCH = 0.035;\n\n/** Shortest signed difference between two bearings, in (-π, π]. */\nfunction wrap(a: number): number {\n  let x = (a + Math.PI) % TAU;\n  if (x < 0) x += TAU;\n  return x - Math.PI;\n}\n\n/**\n * A mast and its canvas.\n *\n * Parent it to a hull: it reads its own world heading and position, so it\n * needs telling nothing about the ship it is on.\n */\nexport function createSailRig(options: SailOptions = {}): SailRig {\n  const kind = options.kind ?? 'gaff';\n  const spec = KINDS[kind];\n  const seed = options.seed ?? 1;\n  const rng = new Rng(seed);\n  const palette = options.palette ?? DEFAULT_PALETTE;\n  const scale = options.scale ?? 1;\n\n  const group = new Group();\n  group.name = `rig-${kind}`;\n\n  const timber = createSurface('wood', { seed, color: palette.woodDark });\n  const canvasMat = new MeshStandardMaterial({\n    color: 0xe6e0d0,\n    roughness: 0.92,\n    side: DoubleSide,\n    flatShading: true,\n  });\n\n  const H = spec.mast * scale;\n  const mast = new Mesh(new CylinderGeometry(0.13 * scale, 0.19 * scale, H, 8), timber);\n  mast.position.y = H / 2;\n  group.add(mast);\n\n  /**\n   * The boom or yard swings; the canvas hangs off it.\n   *\n   * A rig whose sails do not move when you change course is a rig with a\n   * picture of a sail on it — the whole visible read here is the boom\n   * crossing the deck as she comes about.\n   */\n  const spar = new Group();\n  spar.name = 'spar';\n  group.add(spar);\n\n  /**\n   * A piece of canvas, and the edge of it that is nailed down.\n   *\n   * Two things hang off getting this right.\n   *\n   * Furling: a sail that is half set is not a half-size sail hanging in\n   * mid-air, it is a sail that has come DOWN. So each one records the edge\n   * bent to its spar — the head for a square sail under its yard, the foot\n   * for anything standing up off a boom — and shrinks toward it.\n   *\n   * And that edge has to be the ORIGIN of the thing that rotates, not a\n   * number added afterwards. A rake applied to the mesh and an offset\n   * applied to its position do not compose: the offset comes out tilted,\n   * and a reefed lateen lifts off its own yard by however much the rake\n   * was. Hence the pivot — rake and flog live on it, the canvas inside only\n   * ever slides along its own luff.\n   */\n  interface Canvas {\n    mesh: Mesh;\n    /** Carries the bent edge: swung athwart, raked, and shaken. */\n    pivot: Group;\n    height: number;\n    /** 'head' = hangs down from a yard; 'foot' = stands up off a boom. */\n    anchor: 'head' | 'foot';\n    /** Rake within the sail's own plane, before any flogging. */\n    rake: number;\n  }\n  const sails: Canvas[] = [];\n\n  /** Bend a sail to a spar at `at`, and remember which edge that was. */\n  const bend = (\n    geometry: PlaneGeometry,\n    height: number,\n    anchor: 'head' | 'foot',\n    at: Vector3,\n    { swing = 0, rake = 0 } = {}\n  ): void => {\n    const pivot = new Group();\n    pivot.position.copy(at);\n    pivot.rotation.set(0, swing, rake);\n    const mesh = new Mesh(geometry, canvasMat);\n    pivot.add(mesh);\n    spar.add(pivot);\n    sails.push({ mesh, pivot, height, anchor, rake });\n  };\n\n  if (kind === 'square') {\n    spar.position.y = H * 0.72;\n    const yard = new Mesh(new CylinderGeometry(0.09 * scale, 0.09 * scale, H * 0.82, 6), timber);\n    yard.rotation.z = Math.PI / 2;\n    spar.add(yard);\n    // A square sail lies ACROSS the ship — the plane's own xy is already\n    // athwartships-and-vertical, so it needs no swinging at all.\n    bend(new PlaneGeometry(H * 0.78, H * 0.46, 6, 4), H * 0.46, 'head', new Vector3(0, 0, 0));\n    // A topsail, because a square rig is never one sail.\n    const topYard = new Mesh(new CylinderGeometry(0.07 * scale, 0.07 * scale, H * 0.5, 6), timber);\n    topYard.rotation.z = Math.PI / 2;\n    topYard.position.y = H * 0.28;\n    spar.add(topYard);\n    bend(new PlaneGeometry(H * 0.48, H * 0.22, 4, 3), H * 0.22, 'head', new Vector3(0, H * 0.28, 0));\n  } else if (kind === 'lateen') {\n    // FORE-AND-AFT, which is the entire point of a lateen — it is the rig\n    // that let the Mediterranean sail closer to the wind than a square sail\n    // ever could, and one hung athwartships is just a square sail on the\n    // skew. The yard rakes steeply: tack low and forward, peak high and\n    // aft, so the lean is about x (into z) and NOT about z (into x).\n    spar.position.y = H * 0.22;\n    const yard = new Mesh(new CylinderGeometry(0.07 * scale, 0.1 * scale, H * 1.05, 6), timber);\n    yard.rotation.x = -0.95;\n    yard.position.set(0, H * 0.34, -H * 0.16);\n    spar.add(yard);\n    bend(new PlaneGeometry(H * 0.85, H * 0.58, 6, 4), H * 0.58, 'foot', new Vector3(0, 0, -H * 0.06), {\n      swing: Math.PI / 2,\n      rake: 0.3,\n    });\n  } else {\n    // Gaff and Bermudan: a boom at the foot, canvas up the mast.\n    spar.position.y = H * 0.16;\n    const boom = new Mesh(new CylinderGeometry(0.07 * scale, 0.08 * scale, H * 0.62, 6), timber);\n    boom.rotation.x = Math.PI / 2;\n    boom.position.z = -H * 0.31;\n    spar.add(boom);\n    const luff = H * (kind === 'gaff' ? 0.62 : 0.76);\n    bend(new PlaneGeometry(H * 0.6, luff, 5, 6), luff, 'foot', new Vector3(0, 0, -H * 0.3), {\n      swing: Math.PI / 2,\n    });\n    if (kind === 'gaff') {\n      const gaff = new Mesh(new CylinderGeometry(0.055 * scale, 0.06 * scale, H * 0.42, 6), timber);\n      gaff.rotation.x = Math.PI / 2 - 0.4;\n      gaff.position.set(0, luff, -H * 0.2);\n      spar.add(gaff);\n    }\n  }\n  void rng;\n\n  // ---- state -----------------------------------------------------------\n  let wind: WindSource | null = null;\n  let sailSet = clamp01(options.set ?? 1);\n  let windAngle = Math.PI;\n  let drive = 0;\n  let heelForce = 0;\n  let luffing = false;\n  let clock = 0;\n  let flog = 0;\n  const here = new Vector3();\n  const fwd = new Vector3();\n  const spin = new Quaternion();\n\n  /**\n   * The polar, interpolated.\n   *\n   * Linear between the seven samples, and hard-zeroed inside the no-go\n   * rather than merely small — \"she will not go\" has to be a wall, not a\n   * gentle slope, or a helmsman pinching up gets away with it and the whole\n   * constraint evaporates.\n   */\n  const polarAt = (angle: number): number => {\n    const a = Math.abs(wrap(angle));\n    if (a < spec.noGo) return 0;\n    const t = (a / Math.PI) * 6;\n    const i = Math.min(5, Math.floor(t));\n    const f = t - i;\n    return spec.polar[i] * (1 - f) + spec.polar[i + 1] * f;\n  };\n\n  const api: SailRig = {\n    object: group,\n    obstacleRadius: 0,\n    kind,\n    noGo: spec.noGo,\n    get set() {\n      return sailSet;\n    },\n    get windAngle() {\n      return windAngle;\n    },\n    get drive() {\n      return drive;\n    },\n    get heelForce() {\n      return heelForce;\n    },\n    get luffing() {\n      return luffing;\n    },\n    setSail(amount: number) {\n      sailSet = clamp01(amount);\n    },\n    reef(amount = 0.3) {\n      sailSet = clamp01(sailSet - amount);\n    },\n    setWind(w: WindSource | null) {\n      wind = w;\n    },\n    driveAt(angleOffWind: number) {\n      return polarAt(angleOffWind);\n    },\n    layline(bearing: number, currentHeading?: number) {\n      // Where is the wind coming FROM, in world bearing terms?\n      group.updateWorldMatrix(true, false);\n      group.getWorldPosition(here);\n      const w = wind ? wind.sample(here.x, here.z, clock) : new Vector2(0, 0);\n      if (w.lengthSq() < 1e-8) return bearing;\n      // The wind blows toward `w`; it comes from the opposite bearing.\n      const from = Math.atan2(-w.x, -w.y);\n      const off = Math.abs(wrap(bearing - from));\n      // Sailable? Then the straight line is the answer after all.\n      if (off >= spec.noGo) return bearing;\n      // Otherwise the two close-hauled headings either side of the wind,\n      // and we take whichever is the smaller change from where she is\n      // already pointing — that is what makes a tack a decision rather\n      // than a coin toss.\n      //\n      // A hair outside the no-go, never exactly on it. A course laid on the\n      // boundary itself is one rounding error from making no ground at all,\n      // and a helmsman handed it sails there and stops — pinching. Sailors\n      // call the fix footing off, and it is worth two degrees.\n      const lay = spec.noGo + PINCH;\n      const a = from + lay;\n      const b = from - lay;\n      const ref = currentHeading ?? bearing;\n      return Math.abs(wrap(a - ref)) <= Math.abs(wrap(b - ref)) ? wrap(a) : wrap(b);\n    },\n    update(dt: number) {\n      if (dt <= 0) return;\n      clock += dt;\n      group.updateWorldMatrix(true, false);\n      group.getWorldPosition(here);\n      // The hull's heading: +z forward, matching every other craft.\n      fwd.set(0, 0, 1).applyQuaternion(group.getWorldQuaternion(spin));\n\n      if (!wind) {\n        drive = 0;\n        heelForce = 0;\n        luffing = false;\n        return;\n      }\n      const w = wind.sample(here.x, here.z, clock);\n      const speed = w.length();\n      if (speed < 1e-5) {\n        drive = 0;\n        heelForce = 0;\n        luffing = true;\n      } else {\n        // Angle between where she is pointing and where the wind is coming\n        // FROM. Dead ahead into it is 0; dead downwind is π.\n        const heading = Math.atan2(fwd.x, fwd.z);\n        const from = Math.atan2(-w.x, -w.y);\n        windAngle = Math.abs(wrap(heading - from));\n        const shape = polarAt(windAngle);\n        drive = shape * sailSet * Math.min(1, speed);\n        // The rig's force is roughly square to the canvas, and the canvas is\n        // trimmed at about half the angle to the wind. So drive is that\n        // force's forward component — sin(half) — and heel is its sideways\n        // one, cos(half). What matters is the RATIO, cot(half): zero dead\n        // downwind, so a ship running before it does not heel however hard\n        // she is driving, and greater than one hard on the wind, so she\n        // lies over further than she goes. A single fraction of `drive`\n        // cannot say either of those things.\n        const half = Math.max(0.05, windAngle / 2);\n        heelForce = clamp01(drive * (Math.cos(half) / Math.sin(half)) * spec.heel);\n        luffing = shape <= 0.001 || sailSet <= 0.02;\n      }\n\n      // ---- reads --------------------------------------------------------\n      // The spar swings. A rig whose sails do not move when you change\n      // course has a picture of a sail on it.\n      if (kind === 'square') {\n        // Square yards are braced round to meet the wind, up to a limit.\n        const brace = wrap(windAngle - Math.PI) * 0.5;\n        spar.rotation.y += (brace - spar.rotation.y) * Math.min(1, dt * 1.4);\n      } else {\n        // Fore-and-aft: the boom goes out on the side away from the wind,\n        // further the further off the wind she is.\n        const w2 = wind.sample(here.x, here.z, clock);\n        const side = wrap(Math.atan2(fwd.x, fwd.z) - Math.atan2(-w2.x, -w2.y));\n        const out = (windAngle / Math.PI) * 1.35 * Math.sign(side || 1);\n        spar.rotation.y += (out - spar.rotation.y) * Math.min(1, dt * 1.2);\n      }\n\n      // Luffing: the canvas flogs. THIS is the feedback loop — a helmsman\n      // who has pinched up into the wind sees the sail shaking before the\n      // speed has finished bleeding off, and that is the whole reason the\n      // no-go zone is learnable rather than merely punishing.\n      flog += ((luffing ? 1 : 0) - flog) * Math.min(1, dt * (luffing ? 7 : 3));\n      flog = clamp01(flog);\n      const hoist = 0.25 + sailSet * 0.75;\n      for (let i = 0; i < sails.length; i++) {\n        const { mesh, pivot, height, anchor, rake } = sails[i];\n        // A sail flogs about the edge it is bent to, not about its middle —\n        // so the shake goes on the pivot with the rake, and the canvas\n        // itself only ever slides along its own luff.\n        pivot.rotation.z = rake + Math.sin(clock * 19 + i * 2.1) * 0.13 * flog;\n        // …and it goes SLACK, not just shaky. A flat sail that wobbles is a\n        // flag; a sail with no wind in it loses its belly.\n        const belly = (1 - flog) * 0.85 + 0.15;\n        // Furled canvas is not half-size canvas hanging in mid-air: it comes\n        // DOWN. Scale toward the bent edge, never about the middle, or a\n        // reefed mainsail floats clear of its own boom.\n        mesh.scale.set(belly, hoist, 1);\n        mesh.position.y = ((anchor === 'head' ? -1 : 1) * height * hoist) / 2;\n        mesh.visible = sailSet > 0.02;\n      }\n    },\n  };\n  return api;\n}\n\nexport const RIG_KINDS: RigKind[] = ['square', 'lateen', 'gaff', 'bermudan'];\n\n/** Degrees, for the tables and the tests, because radians read badly there. */\nexport const noGoDegrees = (kind: RigKind): number => (KINDS[kind].noGo * 180) / Math.PI;\n","import {\n  BoxGeometry,\n  CylinderGeometry,\n  Group,\n  Mesh,\n  MeshStandardMaterial,\n  Object3D,\n  Quaternion,\n  Vector3,\n} from 'three';\nimport { Rng } from '../core/random';\nimport { DEFAULT_PALETTE, type Palette } from '../core/palette';\nimport { createSurface } from '../materials/surface';\nimport type { Prop, PropSlot } from '../core/types';\n\n/**\n * Alongside — mooring lines, fenders and the gangway.\n *\n * The decked-ship track made a vessel a **frame**: `ride` carries whatever\n * is standing on her, and a sailor who never takes a step still travels at\n * six knots. This is what happens when that frame meets one that does not\n * move, and there are exactly two ideas in it.\n *\n * **A rope is a one-way constraint.** It can pull and it can never push. A\n * fender is the same thing backwards: it pushes and can never pull. Neither\n * one alone holds a ship — a line by itself lets her grind along the wall, a\n * fender by itself lets her drift away — and neither is a spring, because a\n * spring would haul her *back* when she came in and shove her *out* when she\n * went away, which is not what either object does. She is held in the gap\n * between two constraints that each only act in one direction, and the whole\n * reason a ship alongside is never quite still is that inside that gap\n * nothing is acting on her at all.\n *\n * ```ts\n * const berth = createBerth({ era: 'harbour' });\n * const lines = moor(ship, berth);\n * game.onUpdate((t) => ship.update(t.delta, lines.hold(t.delta)));\n * ```\n *\n * **A gangway is where two frames blend.** It is walkable ground with a\n * `DeckField` on it exactly like a deck — but somebody halfway up it is\n * carried half as much by the ship as somebody standing on her deck, and\n * not at all at the shore end. Get that wrong in either direction and they\n * are either dragged off the quay or left behind by the ship.\n *\n * ```ts\n * const brow = createGangway({ berth, ship });\n * legs.update(t.delta, aboard ? ship : onBrow ? brow : berth);\n * ```\n *\n * All three — quay, gangway, deck — publish the same three functions, and\n * only one of them moves. Fixed ground is a moving frame whose delta is the\n * identity, which is why walking ashore needs no special case anywhere.\n */\n\n/** Anything that can carry what is standing on it — SCENA's `DeckField`. */\nexport interface Carrier {\n  deckAt(x: number, z: number, near?: number): number | null;\n  normalAt(x: number, z: number): Vector3;\n  ride(position: Vector3): Vector3;\n}\n\nexport type BerthEra =\n  /** Timber piles and a plank deck — a river wharf. */\n  | 'wharf'\n  /** Dressed stone with iron rings — a harbour wall. */\n  | 'harbour'\n  /** Concrete, steel bollards and rubber fenders — a container quay. */\n  | 'quay';\n\nexport const BERTH_ERAS: BerthEra[] = ['wharf', 'harbour', 'quay'];\n\n/** Something to make fast to. */\nexport interface Bollard {\n  anchor: Object3D;\n  kind: 'ring' | 'bollard' | 'bitt';\n  /** Distance along the quay from its centre, metres. */\n  along: number;\n}\n\nexport interface Berth extends Prop, Carrier {\n  era: BerthEra;\n  /** Along the quay face, metres. */\n  length: number;\n  /** Coping height above the water. */\n  height: number;\n  bollards: Bollard[];\n  /** Fenders hung on the face — where the hull is allowed to touch. */\n  fenders: Object3D[];\n  /**\n   * How far clear of the quay face a world point is.\n   *\n   * Positive is out in the harbour, negative is inside the wall. Everything\n   * a fender does is a reaction to this going negative.\n   */\n  clearance(x: number, z: number): number;\n  /** Outward normal of the face, in world space. */\n  faceNormal(out?: Vector3): Vector3;\n  /** Where a gangway would land on the shore side. */\n  brow: PropSlot;\n  slots: PropSlot[];\n}\n\nexport interface BerthOptions {\n  era?: BerthEra;\n  /** Along the face. Default 34. */\n  length?: number;\n  /** Coping above the water. Default per era. */\n  height?: number;\n  /** How many bollards. Default 4. */\n  bollards?: number;\n  seed?: number;\n  palette?: Palette;\n}\n\ninterface BerthSpec {\n  height: number;\n  /** How far the fenders stand off the face. */\n  fender: number;\n  bollard: Bollard['kind'];\n  deep: number;\n}\n\nconst BERTHS: Record<BerthEra, BerthSpec> = {\n  // `deep` is how far the thing reaches back from the water, and it is not a\n  // detail. A quay is the EDGE OF THE LAND: give it seven metres and it\n  // floats in the middle of the harbour with open water behind it, which\n  // reads as a pier and makes the whole scene a raft. Every test about\n  // clearance and mooring passed at seven.\n  wharf: { height: 1.4, fender: 0.45, bollard: 'bitt', deep: 14 },\n  harbour: { height: 2.6, fender: 0.75, bollard: 'ring', deep: 26 },\n  quay: { height: 3.4, fender: 1.15, bollard: 'bollard', deep: 38 },\n};\n\nconst clamp01 = (t: number): number => (t < 0 ? 0 : t > 1 ? 1 : t);\nconst UP = new Vector3(0, 1, 0);\n\n/**\n * A wall to lie alongside.\n *\n * The face is the quay's local **+x** plane at `x = 0`, running along z, and\n * the harbour is out toward +x. Everything about clearance is measured from\n * that plane in world space, so the berth can be placed and turned like any\n * other prop.\n */\nexport function createBerth(options: BerthOptions = {}): Berth {\n  const era = options.era ?? 'harbour';\n  const spec = BERTHS[era];\n  const seed = options.seed ?? 1;\n  const rng = new Rng(seed);\n  const palette = options.palette ?? DEFAULT_PALETTE;\n  const length = options.length ?? 34;\n  const height = options.height ?? spec.height;\n  const count = Math.max(2, options.bollards ?? 4);\n\n  const group = new Group();\n  group.name = `berth-${era}`;\n\n  const stone =\n    era === 'quay'\n      ? createSurface('concrete', { seed, color: 0x9a9c99 })\n      : era === 'harbour'\n        ? createSurface('ashlar', { seed, color: palette.cliff })\n        : createSurface('plank', { seed, color: palette.woodDark });\n  const iron = createSurface('steel', { seed: seed + 1, color: 0x4a4f55, metalness: 0.5, roughness: 0.5 });\n\n  // ---- the wall --------------------------------------------------------\n  // It goes DOWN into the water, not just up from it. A quay whose face\n  // stops at the waterline is a shelf, and a hull moored against a shelf\n  // has daylight under the one surface it is supposed to be leaning on.\n  const wall = new Mesh(new BoxGeometry(spec.deep, height + 8, length), stone);\n  wall.position.set(-spec.deep / 2, height / 2 - 4, 0);\n  group.add(wall);\n  // …and it runs off the ends too, or the berth is an island with a ship\n  // tied to it. Cheap: the same block, wider than the quay is long.\n  const shore = new Mesh(\n    new BoxGeometry(spec.deep * 0.8, height + 8, length * 2.4),\n    stone\n  );\n  shore.position.set(-spec.deep * 0.62, height / 2 - 4.2, 0);\n  group.add(shore);\n\n  if (era === 'wharf') {\n    // Timber piles, because a wharf is a deck on legs and reads as one.\n    for (let i = 0; i < Math.round(length / 3.2); i++) {\n      const pile = new Mesh(\n        new CylinderGeometry(0.16, 0.19, height + 3.4, 6),\n        createSurface('wood', { seed: seed + i, color: palette.woodDark })\n      );\n      pile.position.set(-0.28, height / 2 - 1.7, -length / 2 + 1.6 + i * 3.2);\n      group.add(pile);\n    }\n  }\n\n  // ---- bollards --------------------------------------------------------\n  const bollards: Bollard[] = [];\n  for (let i = 0; i < count; i++) {\n    const along = count === 1 ? 0 : -length / 2 + 2 + (i * (length - 4)) / (count - 1);\n    const post = new Group();\n    post.position.set(-1.35, height, along);\n    if (spec.bollard === 'ring') {\n      const ring = new Mesh(new CylinderGeometry(0.3, 0.3, 0.11, 10), iron);\n      ring.rotation.x = Math.PI / 2;\n      ring.position.set(0, 0.34, 0);\n      post.add(ring);\n      const plate = new Mesh(new BoxGeometry(0.22, 0.42, 0.22), iron);\n      plate.position.set(0, 0.21, 0);\n      post.add(plate);\n    } else if (spec.bollard === 'bitt') {\n      for (const s of [-0.22, 0.22]) {\n        const bitt = new Mesh(new CylinderGeometry(0.11, 0.13, 0.62, 7), iron);\n        bitt.position.set(0, 0.31, s);\n        post.add(bitt);\n      }\n    } else {\n      const body = new Mesh(new CylinderGeometry(0.28, 0.36, 0.78, 10), iron);\n      body.position.y = 0.39;\n      post.add(body);\n      const cap = new Mesh(new CylinderGeometry(0.4, 0.3, 0.16, 10), iron);\n      cap.position.y = 0.82;\n      post.add(cap);\n    }\n    group.add(post);\n    bollards.push({ anchor: post, kind: spec.bollard, along });\n  }\n\n  // ---- fenders ---------------------------------------------------------\n  // Hung ON the face, standing proud of it. They are the only thing a hull\n  // is ever allowed to touch, and their standoff IS the gap she lives in.\n  const fenders: Object3D[] = [];\n  const rubber = new MeshStandardMaterial({ color: 0x23262a, roughness: 0.95, flatShading: true });\n  const fenderCount = Math.max(2, Math.round(length / 5));\n  for (let i = 0; i < fenderCount; i++) {\n    const at = -length / 2 + 3 + (i * (length - 6)) / Math.max(1, fenderCount - 1);\n    const f = new Group();\n    f.position.set(0, height - 0.9 - rng.range(0, 0.3), at);\n    // The OUTER face of a fender is the plane `clearance` measures from —\n    // its centre is half a diameter inboard of that. Hung by their centres\n    // instead, every fender stood proud of the line the hull is stopped at\n    // and she lay through the middle of them: a ship resting on fenders\n    // that are inside her own plating, and not one number said so.\n    const radius = spec.fender * 0.5;\n    if (era === 'wharf') {\n      // A bundle of old rope, which is what a wharf actually used.\n      for (let r = 0; r < 3; r++) {\n        const coil = new Mesh(\n          new CylinderGeometry(radius, radius, 0.22, 8),\n          createSurface('canvas', { seed: seed + r, color: 0x9c8c68 })\n        );\n        coil.rotation.z = Math.PI / 2;\n        coil.position.set(radius, r * 0.26 - 0.26, 0);\n        f.add(coil);\n      }\n    } else {\n      const drum = new Mesh(\n        new CylinderGeometry(radius, radius, era === 'quay' ? 1.6 : 1.1, 10),\n        rubber\n      );\n      drum.rotation.x = Math.PI / 2;\n      drum.position.x = radius;\n      f.add(drum);\n    }\n    group.add(f);\n    fenders.push(f);\n  }\n\n  // ---- the coping, which is somewhere to stand -------------------------\n  const brow = new Object3D();\n  brow.position.set(-1.9, height, 0);\n  group.add(brow);\n\n  const here = new Vector3();\n  const normal = new Vector3();\n  const local = new Vector3();\n  const spin = new Quaternion();\n\n  /** Signed distance out from the face plane, in world units. */\n  const clearance = (x: number, z: number): number => {\n    group.updateWorldMatrix(true, false);\n    local.set(x, 0, z);\n    group.worldToLocal(local);\n    // The face is the plane x = fender standoff: a hull is \"touching\" when\n    // it reaches the fenders, not when it reaches the masonry.\n    return local.x - spec.fender;\n  };\n\n  const api: Berth = {\n    object: group,\n    obstacleRadius: 0,\n    era,\n    length,\n    height,\n    bollards,\n    fenders,\n    clearance,\n    faceNormal(out = new Vector3()) {\n      group.updateWorldMatrix(true, false);\n      return out.set(1, 0, 0).applyQuaternion(group.getWorldQuaternion(spin)).normalize();\n    },\n    brow: { kind: 'brow', anchor: brow, pose: 'run', approach: brow },\n    slots: [{ kind: 'brow', anchor: brow, pose: 'run', approach: brow }],\n\n    // ---- Carrier: fixed ground ----------------------------------------\n    deckAt(x: number, z: number) {\n      group.updateWorldMatrix(true, false);\n      local.set(x, 0, z);\n      group.worldToLocal(local);\n      if (local.x > 0 || local.x < -spec.deep) return null;\n      if (Math.abs(local.z) > length / 2) return null;\n      here.set(local.x, height, local.z);\n      return group.localToWorld(here).y;\n    },\n    normalAt() {\n      group.updateWorldMatrix(true, false);\n      return normal.set(0, 1, 0).applyQuaternion(group.getWorldQuaternion(spin)).normalize().clone();\n    },\n    /**\n     * Fixed ground is a moving frame whose delta is the identity.\n     *\n     * Not a stub — it is the reason walking ashore needs no special case.\n     * A controller that rides whatever it is standing on can be handed a\n     * quay, a gangway or a deck and never has to ask which it got.\n     */\n    ride(position: Vector3) {\n      return position;\n    },\n  };\n  return api;\n}\n\n// =====================================================================\n//  Mooring\n// =====================================================================\n\nexport interface MooringLine {\n  /** Where it leaves the ship. */\n  from: Object3D;\n  /** What it is made fast to. */\n  to: Object3D;\n  /**\n   * How much line is out, metres.\n   *\n   * Shorter than the gap and she is hauled in; longer and it does nothing\n   * whatever. There is no setting at which it pushes.\n   */\n  scope: number;\n  /** 0 while there is slack, rising as it comes bar-taut. */\n  readonly tension: number;\n  readonly taut: boolean;\n  /** Pay out or heave in to a given scope. */\n  set(scope: number): void;\n  /** Take in this much — `heave(0.5)` shortens by half a metre. */\n  heave(by?: number): void;\n  /** Let it go. */\n  cast(): void;\n  /** Take a turn again. */\n  makeFast(): void;\n  readonly fast: boolean;\n}\n\nexport interface Mooring {\n  /** The ropes themselves. Parent this to your scene, not to the ship. */\n  object: Object3D;\n  lines: MooringLine[];\n  /** Alongside and held — every fast line taut or nearly so, and touching. */\n  readonly alongside: boolean;\n  /**\n   * How much she is working, 0 (dead still) to 1 (ranging about).\n   *\n   * This is the number the gangway and the crew care about, and it is a\n   * SPEED, not a distance — a ship two metres off the wall and steady is a\n   * fine place to work, and one an inch off it and surging is not.\n   */\n  readonly surge: number;\n  /** Distance from the hull's inboard side to the fenders, metres. */\n  readonly gap: number;\n  /** Make another line fast. */\n  add(from: Object3D, to: Object3D, scope?: number): MooringLine;\n  /** Let go — everything, or one line. */\n  cast(line?: MooringLine): void;\n  /**\n   * Work out what the lines are doing to her, and give it back as helm.\n   *\n   * Returns a `ShipInput` to hand straight to `ship.update` — merged with\n   * anything you were already asking for. It goes through `update` rather\n   * than writing her position afterwards because `ride` depends on the\n   * frame delta covering every bit of a frame's movement.\n   */\n  hold(dt: number, input?: { speed?: number; turn?: number }): {\n    speed?: number;\n    turn?: number;\n    drift: { x: number; z: number };\n  };\n  /** Redraw the ropes. `hold` does this too; this is for when you don't. */\n  update(dt: number): void;\n}\n\n/** The vessel a mooring can hold: structurally a `DeckedShip`. */\nexport interface Moorable {\n  object: Object3D;\n  length: number;\n  beam: number;\n  /**\n   * Height of her rail above the waterline, if she knows it.\n   *\n   * Lines are led from the DECK, over the bulwark, and down to the bollard.\n   * Led from the waterline instead they run up the inside of the gap where\n   * nothing can see them, and a ship apparently moored by nothing at all is\n   * the sort of thing no test notices.\n   */\n  freeboard?: number;\n}\n\nexport interface MooringOptions {\n  /**\n   * Where she wants to lie: distance from the fenders, metres.\n   *\n   * Not zero. A ship resting hard against her fenders all watch is a ship\n   * with no lines on her — she is pinned there by whatever is pushing her,\n   * and if nothing is, she lies off.\n   */\n  standoff?: number;\n  /** How many lines, if none are given. Default 4 — head, stern and springs. */\n  lines?: number;\n  /** How hard the lines pull, per metre of stretch. Default 0.9. */\n  stiffness?: number;\n  /** How much the water damps her. Default 1.4. */\n  damping?: number;\n  seed?: number;\n  palette?: Palette;\n}\n\n/**\n * Make a vessel fast to a berth.\n *\n * Lines are run from fairleads at her bow and stern to the nearest bollards,\n * plus springs crossed the other way — which is what actually stops a ship\n * ranging fore and aft, and the reason four lines is the smallest number\n * that holds anything.\n */\nexport function moor(ship: Moorable, berth: Berth, options: MooringOptions = {}): Mooring {\n  const standoff = options.standoff ?? 0.5;\n  const stiffness = options.stiffness ?? 0.9;\n  const damping = options.damping ?? 1.4;\n  const palette = options.palette ?? DEFAULT_PALETTE;\n  const seed = options.seed ?? 1;\n  const wanted = options.lines ?? 4;\n\n  const group = new Group();\n  group.name = 'mooring';\n  const ropeMat = createSurface('canvas', { seed, color: palette.sand });\n\n  const lines: MooringLine[] = [];\n  const ropes = new Map<MooringLine, Mesh>();\n\n  const a = new Vector3();\n  const b = new Vector3();\n  const dir = new Vector3();\n  const mid = new Vector3();\n  const pull = new Vector3();\n  const arm = new Vector3();\n  const last = new Vector3();\n  const velocity = new Vector3();\n  const face = new Vector3();\n  /**\n   * What the lines and fenders are doing to her, as an acceleration, and the\n   * velocity it integrates into.\n   *\n   * It has to be integrated rather than applied straight. The first cut set\n   * the drift velocity directly from the stretch and then subtracted a\n   * fraction of the MEASURED velocity as damping — but the measured velocity\n   * is last frame's drift, so the whole thing collapsed to\n   * `v(n) = stretch − d·v(n−1)`, which for any `d` over one is a recurrence\n   * that alternates sign and doubles. She was at 1e54 metres inside a\n   * second, and every test that only looked at forces still passed.\n   */\n  const accel = new Vector3();\n  const held = new Vector3();\n  let yaw = 0;\n  let surge = 0;\n  let gap = 0;\n  let started = false;\n\n  const makeLine = (from: Object3D, to: Object3D, scope?: number): MooringLine => {\n    from.updateWorldMatrix(true, false);\n    to.updateWorldMatrix(true, false);\n    const span = from.getWorldPosition(a).distanceTo(to.getWorldPosition(b));\n    let out = scope ?? span;\n    let tension = 0;\n    let fast = true;\n    const line: MooringLine = {\n      from,\n      to,\n      get scope() {\n        return out;\n      },\n      set scope(v: number) {\n        out = Math.max(0.2, v);\n      },\n      get tension() {\n        return tension;\n      },\n      get taut() {\n        return tension > 0.02;\n      },\n      get fast() {\n        return fast;\n      },\n      set(v: number) {\n        out = Math.max(0.2, v);\n      },\n      heave(by = 0.5) {\n        out = Math.max(0.2, out - by);\n      },\n      cast() {\n        fast = false;\n        tension = 0;\n      },\n      makeFast() {\n        fast = true;\n      },\n    };\n    // A private setter the solver uses; kept off the public shape.\n    (line as unknown as { __set(t: number): void }).__set = (t: number) => {\n      tension = fast ? t : 0;\n    };\n    const rope = new Mesh(new CylinderGeometry(0.05, 0.05, 1, 6), ropeMat);\n    group.add(rope);\n    ropes.set(line, rope);\n    lines.push(line);\n    return line;\n  };\n\n  /** Draw a rope between its two ends, sagging when there is slack in it. */\n  const drawRope = (line: MooringLine): void => {\n    const rope = ropes.get(line);\n    if (!rope) return;\n    rope.visible = line.fast;\n    if (!line.fast) return;\n    line.from.updateWorldMatrix(true, false);\n    line.to.updateWorldMatrix(true, false);\n    line.from.getWorldPosition(a);\n    line.to.getWorldPosition(b);\n    dir.subVectors(b, a);\n    const span = dir.length();\n    if (span < 1e-4) return;\n    mid.addVectors(a, b).multiplyScalar(0.5);\n    // Slack goes somewhere: a rope with a metre spare hangs in a bight, and\n    // a rope drawn straight when it is slack is a steel bar.\n    const slack = Math.max(0, line.scope - span);\n    mid.y -= Math.min(1.4, slack * 0.45);\n    rope.position.copy(mid);\n    rope.scale.y = a.distanceTo(mid) + mid.distanceTo(b);\n    rope.quaternion.setFromUnitVectors(UP, dir.normalize());\n  };\n\n  // ---- default set of lines -------------------------------------------\n  if (wanted > 0) {\n    ship.object.updateWorldMatrix(true, false);\n    const fairleads: Object3D[] = [];\n    // Bow and stern, on the inboard side. Fore-and-aft position is what\n    // makes a line a head rope or a spring.\n    const railY = (ship.freeboard ?? 1.6) + 0.35;\n    for (const z of [ship.length * 0.42, -ship.length * 0.42]) {\n      const lead = new Object3D();\n      lead.position.set(-ship.beam * 0.45, railY, z);\n      ship.object.add(lead);\n      fairleads.push(lead);\n    }\n    const sorted = [...berth.bollards].sort((p, q) => p.along - q.along);\n    const nearest = (lead: Object3D): Object3D => {\n      lead.updateWorldMatrix(true, false);\n      lead.getWorldPosition(a);\n      let best = sorted[0].anchor;\n      let bestD = Infinity;\n      for (const bol of sorted) {\n        bol.anchor.updateWorldMatrix(true, false);\n        const d = bol.anchor.getWorldPosition(b).distanceTo(a);\n        if (d < bestD) {\n          bestD = d;\n          best = bol.anchor;\n        }\n      }\n      return best;\n    };\n    const furthest = (lead: Object3D): Object3D => {\n      lead.updateWorldMatrix(true, false);\n      lead.getWorldPosition(a);\n      let best = sorted[0].anchor;\n      let bestD = -1;\n      for (const bol of sorted) {\n        bol.anchor.updateWorldMatrix(true, false);\n        const d = bol.anchor.getWorldPosition(b).distanceTo(a);\n        if (d > bestD) {\n          bestD = d;\n          best = bol.anchor;\n        }\n      }\n      return best;\n    };\n    // Head and stern ropes.\n    makeLine(fairleads[0], nearest(fairleads[0]));\n    if (wanted > 1) makeLine(fairleads[1], nearest(fairleads[1]));\n    // …and SPRINGS, led the other way along the quay. Without them she is\n    // held off the wall and free to range fore and aft the whole length of\n    // her lines, which is the failure everybody has watched happen and\n    // nobody models.\n    if (wanted > 2) makeLine(fairleads[0], furthest(fairleads[0]));\n    if (wanted > 3) makeLine(fairleads[1], furthest(fairleads[1]));\n\n    // Then heave them in until she lies where she is wanted. Made up to\n    // exactly the distance she happens to be at, four lines hold a ship\n    // wherever she was left — including out in the fairway. Warping her\n    // alongside IS shortening the scope, so that is what this does.\n    ship.object.updateWorldMatrix(true, false);\n    a.set(-ship.beam * 0.5, 0, 0);\n    ship.object.localToWorld(a);\n    const haul = berth.clearance(a.x, a.z) - standoff;\n    if (haul > 0) {\n      berth.faceNormal(face);\n      for (const line of lines) {\n        line.from.updateWorldMatrix(true, false);\n        line.to.updateWorldMatrix(true, false);\n        pull.subVectors(line.to.getWorldPosition(b), line.from.getWorldPosition(a));\n        if (pull.lengthSq() < 1e-8) continue;\n        // Only the part of each line that actually pulls her TOWARD the\n        // wall. Take the whole haul out of every rope and the springs —\n        // which lie almost along the quay and barely move her sideways at\n        // all — come up hard and drag her onto her own fenders. She lay\n        // there pinned, with tension in every line, looking exactly like a\n        // ship properly moored.\n        const across = Math.abs(pull.normalize().dot(face));\n        line.set(Math.max(0.4, line.scope - haul * across));\n      }\n    }\n  }\n\n  /** Where the hull's inboard side is, at bow, midships and stern. */\n  const touchPoints = (out: Vector3[]): Vector3[] => {\n    ship.object.updateWorldMatrix(true, false);\n    const zs = [ship.length * 0.35, 0, -ship.length * 0.35];\n    for (let i = 0; i < 3; i++) {\n      out[i] = out[i] ?? new Vector3();\n      out[i].set(-ship.beam * 0.5, 0, zs[i]);\n      ship.object.localToWorld(out[i]);\n    }\n    return out;\n  };\n  const touches: Vector3[] = [];\n\n  const api: Mooring = {\n    object: group,\n    lines,\n    get alongside() {\n      // NOT \"some line is taut\". A ship properly moored and left alone has\n      // slack in every rope and is touching nothing — that is what lying in\n      // the gap between two one-way constraints looks like. Alongside is\n      // about being close and being STILL.\n      if (!lines.some((l) => l.fast)) return false;\n      return gap < 2.5 && surge < 0.25;\n    },\n    get surge() {\n      return surge;\n    },\n    get gap() {\n      return gap;\n    },\n    add(from: Object3D, to: Object3D, scope?: number) {\n      return makeLine(from, to, scope);\n    },\n    cast(line?: MooringLine) {\n      if (line) line.cast();\n      else for (const l of lines) l.cast();\n    },\n\n    hold(dt: number, input = {}) {\n      if (dt <= 0) return { ...input, drift: { x: 0, z: 0 } };\n      accel.set(0, 0, 0);\n      let torque = 0;\n\n      ship.object.updateWorldMatrix(true, false);\n      ship.object.getWorldPosition(mid);\n      if (!started) {\n        last.copy(mid);\n        started = true;\n      }\n      velocity.subVectors(mid, last).divideScalar(dt);\n      last.copy(mid);\n      surge += (clamp01(velocity.length() * 0.9) - surge) * Math.min(1, dt * 2.5);\n\n      // ---- the ropes ---------------------------------------------------\n      for (const line of lines) {\n        if (!line.fast) continue;\n        line.from.updateWorldMatrix(true, false);\n        line.to.updateWorldMatrix(true, false);\n        line.from.getWorldPosition(a);\n        line.to.getWorldPosition(b);\n        pull.subVectors(b, a);\n        const span = pull.length();\n        const over = span - line.scope;\n        // ONE WAY. Slack line, no force — not a small force, none at all.\n        // A spring here would haul her back in whenever she came closer\n        // than her scope, and a rope has never done that.\n        if (over <= 0 || span < 1e-5) {\n          (line as unknown as { __set(t: number): void }).__set(0);\n          continue;\n        }\n        (line as unknown as { __set(t: number): void }).__set(clamp01(over / Math.max(1, line.scope)));\n        pull.divideScalar(span).multiplyScalar(over * stiffness);\n        accel.x += pull.x;\n        accel.z += pull.z;\n        // …and it swings her, because it is made fast somewhere that is not\n        // her centre. A bow line pulls the bow, not the ship.\n        arm.subVectors(a, mid);\n        torque += (arm.z * pull.x - arm.x * pull.z) * 0.006;\n      }\n\n      // ---- the fenders -------------------------------------------------\n      berth.faceNormal(face);\n      touchPoints(touches);\n      let nearest = Infinity;\n      for (const point of touches) {\n        const clear = berth.clearance(point.x, point.z);\n        nearest = Math.min(nearest, clear);\n        // ONE WAY, the other way. A fender pushes a hull off and has never\n        // once pulled one in, which is why this is `< 0` and not a spring\n        // about the standoff.\n        if (clear >= 0) continue;\n        const push = -clear * stiffness * 5;\n        accel.x += face.x * push;\n        accel.z += face.z * push;\n        arm.subVectors(point, mid);\n        torque += (arm.z * face.x * push - arm.x * face.z * push) * 0.006;\n      }\n      gap = Number.isFinite(nearest) ? nearest : 0;\n\n      // ---- and the water, which is what stops it ringing ----------------\n      // Two one-way constraints with nothing between them would hammer the\n      // wall for ever. A hull in water does not. Integrate, then decay by a\n      // true exponential so the result does not depend on the frame rate\n      // and cannot overshoot however large `damping` gets.\n      const decay = Math.exp(-damping * dt);\n      held.addScaledVector(accel, dt).multiplyScalar(decay);\n      yaw = (yaw + torque * dt) * decay;\n\n      for (const line of lines) drawRope(line);\n      return { ...input, turn: (input.turn ?? 0) + yaw, drift: { x: held.x, z: held.z } };\n    },\n\n    update() {\n      for (const line of lines) drawRope(line);\n    },\n  };\n  return api;\n}\n\n// =====================================================================\n//  Gangway\n// =====================================================================\n\nexport interface Gangway extends Prop, Carrier {\n  /** Slope, radians. Positive is uphill from the shore. */\n  readonly angle: number;\n  /** Span between its two ends, metres. */\n  readonly span: number;\n  /** Down and usable. False when raised, or when she has ranged too far. */\n  readonly rigged: boolean;\n  /** Put it over, or take it in. */\n  lower(): void;\n  raise(): void;\n  /** Follow the ship. Call it after hers. */\n  update(dt: number): void;\n}\n\nexport interface GangwayOptions {\n  /** The shore end. Usually `berth.brow.anchor`. */\n  shore: Object3D;\n  /** The moving end, and the frame it belongs to. */\n  ship: Carrier & { object: Object3D };\n  /** Where it lands aboard. Defaults to a point on her inboard side. */\n  landing?: Object3D;\n  /** Widest span it will still bridge, metres. Default 1.6× its own length. */\n  reach?: number;\n  width?: number;\n  seed?: number;\n  palette?: Palette;\n}\n\n/**\n * A plank between two frames.\n *\n * The shore end is fixed and the ship end is not, so it re-solves every\n * frame — but the part that matters is `ride`. A gangway carries somebody\n * standing on it in **proportion to how far along it they are**: not at all\n * at the shore end, entirely at the ship end. Carry them all the way and\n * they get dragged off the quay; carry them not at all and the ship leaves\n * without them halfway across.\n */\nexport function createGangway(options: GangwayOptions): Gangway {\n  const { shore, ship } = options;\n  const seed = options.seed ?? 1;\n  const palette = options.palette ?? DEFAULT_PALETTE;\n  const width = options.width ?? 0.9;\n  void palette;\n\n  const group = new Group();\n  group.name = 'gangway';\n\n  const plankMat = createSurface('plank', { seed, color: palette.wood });\n  const iron = createSurface('steel', { seed: seed + 1, color: 0x59606a, metalness: 0.5, roughness: 0.5 });\n\n  // Unit-length along +z, so scaling z is scaling the span.\n  const deck = new Mesh(new BoxGeometry(width, 0.09, 1), plankMat);\n  deck.position.y = 0.045;\n  group.add(deck);\n  // Treads, so it reads as something you walk up rather than a ramp.\n  const treads: Mesh[] = [];\n  for (let i = 0; i < 9; i++) {\n    const t = new Mesh(new BoxGeometry(width * 0.92, 0.035, 0.09), plankMat);\n    treads.push(t);\n    group.add(t);\n  }\n  // Handrails, which is most of why a gangway is recognisable at all.\n  const rails: Mesh[] = [];\n  for (const s of [-1, 1]) {\n    const rail = new Mesh(new CylinderGeometry(0.035, 0.035, 1, 6), iron);\n    rail.position.set((s * width) / 2, 0.95, 0);\n    rail.rotation.x = Math.PI / 2;\n    group.add(rail);\n    rails.push(rail);\n    for (let i = 0; i < 5; i++) {\n      const stanchion = new Mesh(new CylinderGeometry(0.026, 0.026, 0.95, 5), iron);\n      stanchion.position.set((s * width) / 2, 0.475, 0);\n      group.add(stanchion);\n      rails.push(stanchion);\n    }\n  }\n\n  const landing = options.landing ?? null;\n  let solved = false;\n  const from = new Vector3();\n  const to = new Vector3();\n  /** Where the ship end was last time it was solved. */\n  const wasAt = new Vector3();\n  const shift = new Vector3();\n  const axis = new Vector3();\n  const flat = new Vector3();\n  const probe = new Vector3();\n  const normal = new Vector3();\n  const spin = new Quaternion();\n  let span = 1;\n  let angle = 0;\n  let rigged = true;\n  let down = true;\n  let reach = options.reach ?? 0;\n\n  /** Both ends, in world space. */\n  const ends = (): void => {\n    shore.updateWorldMatrix(true, false);\n    shore.getWorldPosition(from);\n    if (landing) {\n      landing.updateWorldMatrix(true, false);\n      landing.getWorldPosition(to);\n    } else {\n      ship.object.updateWorldMatrix(true, false);\n      ship.object.getWorldPosition(to);\n      // The deck nearest the COPING, not the highest one aboard. `near` is\n      // already the stacked-deck rule everywhere else in the library, and\n      // without it a gangway to a liner lands on her bridge twenty metres\n      // up and reads as a ladder to the sky.\n      const y = ship.deckAt(to.x, to.z, from.y + 2.5);\n      if (y !== null) to.y = y;\n    }\n  };\n\n  const solve = (): void => {\n    wasAt.copy(to);\n    ends();\n    axis.subVectors(to, from);\n    span = axis.length();\n    if (reach <= 0) reach = Math.max(3, span * 1.6);\n    // Too far and it comes off the quay. A gangway that stretches to any\n    // distance is a bridge, and the whole hazard of working a ship\n    // alongside is that this one does not.\n    rigged = down && span <= reach && span > 0.4;\n    if (!solved) {\n      wasAt.copy(to);\n      solved = true;\n    }\n    if (span < 1e-4) return;\n    angle = Math.asin(Math.max(-1, Math.min(1, (to.y - from.y) / span)));\n\n    group.position.copy(from);\n    group.quaternion.setFromUnitVectors(new Vector3(0, 0, 1), axis.clone().normalize());\n    deck.scale.z = span;\n    deck.position.set(0, 0.045, span / 2);\n    for (let i = 0; i < treads.length; i++) {\n      const t = (i + 0.5) / treads.length;\n      treads[i].position.set(0, 0.11, span * t);\n      treads[i].visible = rigged;\n    }\n    let r = 0;\n    for (const s of [-1, 1]) {\n      const rail = rails[r++];\n      rail.scale.y = span;\n      rail.position.set((s * width) / 2, 0.95, span / 2);\n      for (let i = 0; i < 5; i++) {\n        const st = rails[r++];\n        st.position.set((s * width) / 2, 0.475, span * ((i + 0.5) / 5));\n      }\n    }\n    group.visible = rigged;\n  };\n  solve();\n\n  /**\n   * How far along the plank a world point is, 0 at the shore, 1 aboard —\n   * or null if it is not on the plank at all.\n   */\n  const along = (x: number, z: number): number | null => {\n    if (!rigged) return null;\n    flat.set(to.x - from.x, 0, to.z - from.z);\n    const flatLen = flat.length();\n    if (flatLen < 1e-5) return null;\n    probe.set(x - from.x, 0, z - from.z);\n    const t = probe.dot(flat) / (flatLen * flatLen);\n    if (t < -0.02 || t > 1.02) return null;\n    // …and within its width, or you are standing beside it in the water.\n    const off = Math.abs(probe.x * (-flat.z / flatLen) + probe.z * (flat.x / flatLen));\n    if (off > width * 0.75) return null;\n    return Math.max(0, Math.min(1, t));\n  };\n\n  const api: Gangway = {\n    object: group,\n    obstacleRadius: 0,\n    get angle() {\n      return angle;\n    },\n    get span() {\n      return span;\n    },\n    get rigged() {\n      return rigged;\n    },\n    lower() {\n      down = true;\n      solve();\n    },\n    raise() {\n      down = false;\n      rigged = false;\n      group.visible = false;\n    },\n    update() {\n      solve();\n    },\n\n    deckAt(x: number, z: number, near?: number) {\n      const t = along(x, z);\n      if (t === null) return null;\n      const y = from.y + (to.y - from.y) * t + 0.11;\n      // `near` is how the stacked-deck rule works everywhere else: answer\n      // with what is under you, not what is over your head.\n      if (near !== undefined && y > near + 1.2) return null;\n      return y;\n    },\n    normalAt(x: number, z: number) {\n      const t = along(x, z);\n      if (t === null) return normal.set(0, 1, 0).clone();\n      // Square to the plank, which is what makes a body lean going up it.\n      //\n      // Just the plank's own up vector: the group is ALREADY turned to lay\n      // its +z along the span, so its local y is tilted by exactly the\n      // slope. Tilting it again by `angle` on top — which is what the first\n      // cut did — counts the rise twice and hands back a normal pointing\n      // into the water.\n      group.updateWorldMatrix(true, false);\n      return normal\n        .set(0, 1, 0)\n        .applyQuaternion(group.getWorldQuaternion(spin))\n        .normalize()\n        .clone();\n    },\n    /**\n     * Carried in proportion to how far aboard you are.\n     *\n     * The one idea in the whole prop. The plank's ship end moved by some\n     * amount since it was last solved; a point a fraction `t` along it moved\n     * by exactly `t` of that, because a straight line between a fixed point\n     * and a moving one is what a gangway is. At the ship end that is the\n     * deck; at the shore end it is nothing at all; in between it is neither,\n     * and no amount of choosing one of the two is right.\n     *\n     * It is the PLANK'S end that is lerped, not the ship's `ride` of the\n     * point itself. Those agree while she is only translating and part\n     * company the moment she swings: `ship.ride` applied to a point out on\n     * the quay rotates it about her centre from several metres outside her,\n     * which throws somebody at the shore end further than the plank they\n     * are standing on ever went.\n     */\n    ride(position: Vector3) {\n      const t = along(position.x, position.z);\n      if (t === null || t <= 0) return position;\n      shift.subVectors(to, wasAt);\n      return position.addScaledVector(shift, t);\n    },\n  };\n  return api;\n}\n","import {\n  BoxGeometry,\n  CylinderGeometry,\n  Group,\n  Mesh,\n  Object3D,\n  Vector3,\n} from 'three';\nimport { Rng } from '../core/random';\nimport { DEFAULT_PALETTE, type Palette } from '../core/palette';\nimport { createSurface } from '../materials/surface';\nimport type { Prop, PropSlot } from '../core/types';\n\n/**\n * Oars — and why a rowed boat does not travel at a steady speed.\n *\n * A sail is a curve against the angle to the wind. An engine is a throttle.\n * An oar is neither: it is a **duty cycle**. The blade is in the water for\n * something under half of every stroke and out of it for the rest, so the\n * thrust is a pulse and everything downstream of it inherits that.\n *\n * ```ts\n * bank.thrust   // ZERO for most of every stroke\n * bank.way      // …so her speed SURGES: drive, coast, drive, coast\n * ```\n *\n * That is the first idea and it is not a detail — a galley under oars\n * lurches, and the lurch is at the stroke rate, and you can feel the rate\n * from the deck without seeing an oar. Publish thrust as an average and the\n * whole thing becomes an engine with a wooden skin on it.\n *\n * The second idea is that it takes **several bodies agreeing**. Nothing\n * else in the trilogy needs that. Every rower drives off one shared number:\n *\n * ```ts\n * bank.phaseAt(seat)   // 0 at the catch, ~0.4 at the finish, 1 back again\n * ```\n *\n * and ANIMA's rowing controller takes that same number and writes a body\n * with it. Neither library imports the other; the handshake is a **scalar**\n * — a shared clock rather than a shared field or a shared frame, which is a\n * third kind and the only one that can say \"together\".\n *\n * And they are not quite together, ever. A rower does not watch the\n * coxswain, he watches the blade in front of him, so the stroke propagates\n * down the boat with a delay and `phaseAt` is a different number per seat.\n * Close it up and she runs; let it spread and the blades go in at different\n * moments, the thrusts no longer add, and she slows down — which falls out\n * of averaging the oars rather than being a penalty anybody wrote.\n *\n * ```ts\n * const bank = createOarBank({ kind: 'longship', seats: 8, beam: 4 });\n * ship.object.add(bank.object);\n * game.onUpdate((t) => {\n *   bank.update(t.delta);\n *   ship.update(t.delta, { speed: bank.way, turn: bank.yaw * 0.35 });\n * });\n * ```\n */\n\nexport type OarKind =\n  /** A pair of oars in a small boat — one person, both hands. */\n  | 'skiff'\n  /** A longship's benches: heavy oars, slow deep strokes. */\n  | 'longship'\n  /** A war galley — many oars, driven hard, and a rate you can hear. */\n  | 'galley'\n  /** A racing eight: light, long, and rowed at forty to the minute. */\n  | 'racing';\n\nexport const OAR_KINDS: OarKind[] = ['skiff', 'longship', 'galley', 'racing'];\n\n/** One oar in the bank. */\nexport interface Oar {\n  seat: number;\n  /** −1 port, +1 starboard. */\n  side: -1 | 1;\n  /** The whole oar, pivoting at its rowlock. */\n  object: Object3D;\n  /**\n   * The handle, in world space, wherever it is this instant.\n   *\n   * ANIMA's props conform to the pose rather than the pose reaching for the\n   * prop, so this is published for anything that wants to know rather than\n   * driven at — but it is the honest answer to \"where are his hands\".\n   */\n  grip: Object3D;\n  /** Somewhere to sit. */\n  seatSlot: PropSlot;\n  /** This oar's own phase, which is not the bank's. */\n  readonly phase: number;\n  /** Is the blade in the water right now? */\n  readonly buried: boolean;\n  /** What this one is contributing, −1 to 1. */\n  readonly thrust: number;\n  /** Fouled: the blade did not come clear and she is dragging it. */\n  readonly crabbing: boolean;\n}\n\nexport interface OarBank extends Prop {\n  kind: OarKind;\n  oars: Oar[];\n  seats: PropSlot[];\n  slots: PropSlot[];\n  /** The stroke's own phase: 0 at the catch, ~0.4 at the finish. */\n  readonly phase: number;\n  /** Strokes per minute. */\n  readonly rate: number;\n  setRate(spm: number): void;\n  /**\n   * How hard they are pulling, −1 (backing water) to 1.\n   *\n   * Give it two numbers to pull harder on one side than the other, which is\n   * how a boat with no rudder turns and how one with a rudder turns quickly.\n   */\n  setEffort(port: number, starboard?: number): void;\n  /**\n   * How together they are, 0 (a shambles) to 1 (as one blade).\n   *\n   * Not a multiplier on the output. It sets how far the stroke smears down\n   * the boat, and the loss of thrust comes out of the oars disagreeing.\n   */\n  together: number;\n  /**\n   * Thrust this instant, −1 to 1, and **zero through every recovery**.\n   *\n   * The mean over the bank, so a ragged crew makes less of it without\n   * anybody applying a penalty.\n   */\n  readonly thrust: number;\n  /**\n   * Her speed through the water, m/s.\n   *\n   * Integrated from `thrust` against drag, which is the only place the\n   * surge can live: hand a hull the instantaneous thrust and she jerks to a\n   * stop twice a second.\n   */\n  readonly way: number;\n  /** Turning effect from one side out-pulling the other, −1 to 1. */\n  readonly yaw: number;\n  /** Fraction of the bank currently fouled. */\n  readonly crabbing: number;\n  /** Where a given seat is in the stroke. */\n  phaseAt(seat: number): number;\n  /** Catch a crab: the blade fails to come clear and she drags it. */\n  crab(seat: number): void;\n  /** Ship oars — everybody stops, blades in. */\n  ship(): void;\n  /** Out oars again. */\n  out(): void;\n  readonly rowing: boolean;\n  update(dt: number): void;\n}\n\ninterface KindSpec {\n  /** Oar length, metres. */\n  loom: number;\n  blade: number;\n  /** Spacing between benches, metres. */\n  pitch: number;\n  /** Fastest they can go, strokes per minute. */\n  maxRate: number;\n  /** Comfortable cruising rate. */\n  rate: number;\n  /**\n   * Fraction of the cycle the blade is in the water.\n   *\n   * Always well under half. The recovery is the longer part of a stroke —\n   * that is what makes rowing a duty cycle rather than a crank.\n   */\n  drive: number;\n  /** How much way a full stroke puts on her. */\n  power: number;\n  /** How fast she loses it again. */\n  drag: number;\n  /** Half the angle the loom sweeps through, radians. */\n  reach: number;\n}\n\nconst KINDS: Record<OarKind, KindSpec> = {\n  skiff: { loom: 2.6, blade: 0.7, pitch: 0.9, maxRate: 34, rate: 22, drive: 0.42, power: 7.0, drag: 0.9, reach: 0.60 },\n  longship: { loom: 4.2, blade: 0.9, pitch: 1.0, maxRate: 30, rate: 20, drive: 0.40, power: 9.0, drag: 0.55, reach: 0.62 },\n  galley: { loom: 5.6, blade: 1.1, pitch: 1.15, maxRate: 36, rate: 26, drive: 0.38, power: 11.0, drag: 0.5, reach: 0.58 },\n  racing: { loom: 3.8, blade: 0.9, pitch: 1.25, maxRate: 44, rate: 32, drive: 0.36, power: 9.5, drag: 1.1, reach: 0.66 },\n};\n\nexport interface OarBankOptions {\n  kind?: OarKind;\n  /** Benches a side. Default per kind. */\n  seats?: number;\n  /** Beam of the hull it is bolted to — where the rowlocks go. */\n  beam?: number;\n  /** Height of the gunwale above the vessel's origin. */\n  gunwale?: number;\n  /** Rowers only down one side, for a sculling boat. Default both. */\n  sides?: 1 | 2;\n  together?: number;\n  seed?: number;\n  palette?: Palette;\n}\n\nconst clamp01 = (t: number): number => (t < 0 ? 0 : t > 1 ? 1 : t);\nconst wrap01 = (t: number): number => t - Math.floor(t);\n\n/**\n * Where the handle of an oar sits relative to the thwart a rower is on.\n *\n * Published in the same spirit as ANIMA's `GRIPS`, and identical to that\n * library's `ROW_GRIP`: the prop is built to the body's expectations rather\n * than the body reaching for the prop, so an oar and a rowing pose meet\n * without any runtime IK between them.\n *\n * `height` is what puts the thwart below the gunwale. An oar pivots at the\n * rowlock, so cocking the blade down to reach the water swings the inboard\n * end UP by half a metre — and if the handle is assumed to be low, the seat\n * derived from it ends up above the sheerstrake with the rower perched on\n * the rail.\n */\nexport const OAR_GRIP = {\n  /** Height of the handle above the thwart at the catch. */\n  height: 0.4,\n  /** How far in front of the chest the hands go at the catch. */\n  reach: 0.58,\n  /** …and how far past the body they come at the finish. */\n  finish: -0.16,\n} as const;\n\n/**\n * Smooth 0→1→0 over [0,1], for the shape of a pull.\n *\n * A rower does not apply full force the instant the blade touches, and the\n * pressure comes off before it leaves. A square pulse reads as a piston.\n */\nconst bump = (t: number): number => Math.sin(Math.PI * clamp01(t)) ** 1.4;\n\n/**\n * Smooth 0→1 — the shape of a swing, not of a ramp.\n *\n * An oar accelerates away from the catch and comes off the pressure before\n * the finish; it does not jump to full speed the instant the blade touches.\n * That matters past the look of it, because ANIMA's rower is solved onto\n * this same path: a handle moving at full speed from the first instant\n * leaves nothing for his legs to do and forces his elbows to bend at the\n * catch, which is the one thing a rower's arms must not do.\n */\nconst ease = (t: number): number => {\n  const u = clamp01(t);\n  return u * u * (3 - 2 * u);\n};\n\n/**\n * A bank of oars.\n *\n * Parent it to a hull. The origin is the hull's origin, +z forward, so the\n * rowlocks land on the gunwale and the blades reach out over the water.\n */\nexport function createOarBank(options: OarBankOptions = {}): OarBank {\n  const kind = options.kind ?? 'longship';\n  const spec = KINDS[kind];\n  const seed = options.seed ?? 1;\n  const rng = new Rng(seed);\n  const palette = options.palette ?? DEFAULT_PALETTE;\n  const beam = options.beam ?? (kind === 'skiff' ? 1.5 : kind === 'galley' ? 5 : 4);\n  const gunwale = options.gunwale ?? (kind === 'skiff' ? 0.45 : 1.1);\n  const sides: 1 | 2 = options.sides ?? 2;\n  const count = Math.max(1, options.seats ?? (kind === 'skiff' ? 1 : kind === 'racing' ? 4 : 6));\n\n  const group = new Group();\n  group.name = `oars-${kind}`;\n\n  const timber = createSurface('wood', { seed, color: palette.woodDark });\n  const bladeMat = createSurface('plank', { seed: seed + 1, color: palette.wood });\n\n  // ---- state -----------------------------------------------------------\n  let phase = 0;\n  let rate = spec.rate;\n  let effortPort = 1;\n  let effortStar = 1;\n  let together = clamp01(options.together ?? 0.85);\n  let way = 0;\n  let thrust = 0;\n  let yaw = 0;\n  let rowing = true;\n  const crabs = new Map<number, number>();\n  /** Per-rower slop, so a ragged crew is ragged in its own way. */\n  const wobble: number[] = [];\n  for (let i = 0; i < count * 2; i++) wobble.push(rng.range(-1, 1));\n\n  interface Built {\n    oar: Oar;\n    pivot: Group;\n    loom: Group;\n    seat: number;\n    side: -1 | 1;\n    thrust: number;\n    phase: number;\n    buried: boolean;\n  }\n  const built: Built[] = [];\n  const seats: PropSlot[] = [];\n\n  /**\n   * How much of the oar is inboard of the rowlock — and it is NOT a choice.\n   *\n   * The handle has to travel exactly as far as a rower's hands do, and that\n   * distance is published: `OAR_GRIP.reach` to `OAR_GRIP.finish`. Given the\n   * sweep, the inboard length falls out of it. Pick a nice-looking fraction\n   * instead — a third, a quarter — and the handle swings half a metre\n   * further than any pair of arms goes, so a whole crew rows a whole bank\n   * of oars from a foot away and both libraries insist they agree.\n   */\n  const inboard = (OAR_GRIP.reach - OAR_GRIP.finish) / (2 * Math.sin(spec.reach));\n  const outboard = spec.loom - inboard;\n  const bury = Math.atan2(gunwale + 0.18, outboard);\n\n  /**\n   * How far the loom is cocked down so the blade reaches the water.\n   *\n   * An oar runs DOWN and out from its rowlock — the thole is on the gunwale\n   * and the blade is under the surface, and the angle between them is set by\n   * how high she floats. The first cut left every loom horizontal, so three\n   * boats' worth of blades swept about in mid-air a metre above the sea and\n   * she made way on nothing at all. Every number in the model was right.\n   */\n\n  const sideList: Array<-1 | 1> = sides === 1 ? [-1] : [-1, 1];\n  for (let i = 0; i < count; i++) {\n    const z = ((count - 1) / 2 - i) * spec.pitch;\n    for (const side of sideList) {\n      // The rowlock: the oar turns about a point ON the gunwale, and both\n      // of its motions are rotations about that point.\n      const pivot = new Group();\n      pivot.position.set((side * beam) / 2, gunwale, z);\n      group.add(pivot);\n\n      const thole = new Mesh(new CylinderGeometry(0.05, 0.06, 0.26, 6), timber);\n      thole.position.y = 0.1;\n      pivot.add(thole);\n\n      // The oar itself lies along the pivot's +x, handle inboard.\n      const loom = new Group();\n      pivot.add(loom);\n      const shaft = new Mesh(\n        new CylinderGeometry(0.062, 0.078, spec.loom, 6),\n        timber\n      );\n      shaft.rotation.z = Math.PI / 2;\n      // A QUARTER of it inboard of the rowlock, three quarters out — what\n      // makes an oar a lever rather than a paddle, and the ratio also sets\n      // how far the inboard end swings UP when the blade is cocked down to\n      // the water. At a third, that rise put the thwart derived from it\n      // above the gunwale and the handle above the rower's own shoulders.\n      shaft.position.x = side * (spec.loom / 2 - inboard);\n      loom.add(shaft);\n\n      // A blade is a VERTICAL paddle — it pushes water sternward, so it\n      // stands on edge in the water. Laid flat it is a spoon, and a bank of\n      // spoons skims the surface without gripping anything.\n      const blade = new Mesh(new BoxGeometry(spec.blade, 0.3, 0.045), bladeMat);\n      blade.position.x = side * (outboard + spec.blade * 0.4);\n      loom.add(blade);\n\n      const grip = new Object3D();\n      grip.position.x = -side * inboard;\n      loom.add(grip);\n\n      // WHERE HE SITS is not a free choice — it is wherever his hands can\n      // be on that handle. Derived from the handle's own mid-stroke\n      // position and `OAR_GRIP`, rather than picked to look reasonable:\n      // the first cut put every rower a third of the beam to the far side\n      // of the boat from his own oar, so fourteen men rowed two metres\n      // clear of fourteen handles while every phase, thrust and stroke\n      // number in the model agreed with itself.\n      const thwart = new Object3D();\n      thwart.position.set(\n        side * (beam / 2 - inboard + 0.07),\n        gunwale + inboard * Math.sin(bury) - OAR_GRIP.height - 0.04,\n        z + 0.21\n      );\n      group.add(thwart);\n      const slot: PropSlot = {\n        kind: 'row',\n        anchor: thwart,\n        pose: 'sit',\n        approach: thwart,\n      };\n      seats.push(slot);\n\n      const record: Built = {\n        seat: i,\n        side,\n        pivot,\n        loom,\n        thrust: 0,\n        phase: 0,\n        buried: false,\n        oar: null as unknown as Oar,\n      };\n      record.oar = {\n        seat: i,\n        side,\n        object: loom,\n        grip,\n        seatSlot: slot,\n        get phase() {\n          return record.phase;\n        },\n        get buried() {\n          return record.buried;\n        },\n        get thrust() {\n          return record.thrust;\n        },\n        get crabbing() {\n          return (crabs.get(i * 2 + (side > 0 ? 1 : 0)) ?? 0) > 0;\n        },\n      };\n      built.push(record);\n    }\n  }\n\n  const key = (b: Built): number => b.seat * 2 + (b.side > 0 ? 1 : 0);\n\n  /**\n   * Where a given seat is in the stroke.\n   *\n   * Behind the stroke oar by a lag that grows as the crew comes apart,\n   * because nobody is watching the coxswain — they are watching the blade\n   * in front, and every one of them is a little late.\n   */\n  const phaseAt = (seat: number): number => {\n    const slop = 1 - together;\n    const lag = slop * 0.09 * seat;\n    return wrap01(phase - lag);\n  };\n\n  const api: OarBank = {\n    object: group,\n    obstacleRadius: 0,\n    kind,\n    oars: built.map((b) => b.oar),\n    seats,\n    slots: seats,\n    get phase() {\n      return phase;\n    },\n    get rate() {\n      return rate;\n    },\n    setRate(spm: number) {\n      rate = Math.max(0, Math.min(spec.maxRate, spm));\n    },\n    setEffort(port: number, starboard = port) {\n      effortPort = Math.max(-1, Math.min(1, port));\n      effortStar = Math.max(-1, Math.min(1, starboard));\n    },\n    get together() {\n      return together;\n    },\n    set together(t: number) {\n      together = clamp01(t);\n    },\n    get thrust() {\n      return thrust;\n    },\n    get way() {\n      return way;\n    },\n    get yaw() {\n      return yaw;\n    },\n    get crabbing() {\n      let n = 0;\n      for (const v of crabs.values()) if (v > 0) n++;\n      return built.length ? n / built.length : 0;\n    },\n    get rowing() {\n      return rowing;\n    },\n    phaseAt,\n    crab(seat: number) {\n      for (const b of built) {\n        if (b.seat !== seat) continue;\n        // One oar of the pair, not both — a crab is one blade, and the\n        // whole point of it is that she slews.\n        crabs.set(key(b), 1);\n        break;\n      }\n    },\n    ship() {\n      rowing = false;\n    },\n    out() {\n      rowing = true;\n    },\n\n    update(dt: number) {\n      if (dt <= 0) return;\n      if (rowing && rate > 0) phase = wrap01(phase + (rate / 60) * dt);\n\n      // How fast a blade is travelling sternward through the water. Arc\n      // length over the time the drive takes — so it rises with the rate,\n      // which is the whole reason rating up makes a boat go faster.\n      const arc = 2 * spec.reach * outboard;\n      const bladeSpeed = rate > 0 ? (arc * rate) / (60 * spec.drive) : 0;\n\n      let sum = 0;\n      let port = 0;\n      let star = 0;\n      let portN = 0;\n      let starN = 0;\n\n      for (const b of built) {\n        const k = key(b);\n        const foul = crabs.get(k) ?? 0;\n        if (foul > 0) crabs.set(k, Math.max(0, foul - dt * 0.55));\n\n        const effort = b.side < 0 ? effortPort : effortStar;\n        const slop = 1 - together;\n        // His own phase: the seat's lag, plus his own slop, which is what\n        // makes a ragged crew ragged rather than merely late.\n        const own = rowing\n          ? wrap01(phaseAt(b.seat) + wobble[k % wobble.length] * slop * 0.05)\n          : 0;\n        b.phase = own;\n\n        // Backing water runs the whole cycle the other way round.\n        const p = effort < 0 ? wrap01(1 - own) : own;\n        const inWater = p < spec.drive;\n        b.buried = rowing && inWater && foul <= 0;\n\n        // ---- what it is doing to her --------------------------------\n        let mine = 0;\n        if (rowing) {\n          if (foul > 0) {\n            // A crab is not \"no thrust\". The blade is caught flat in the\n            // water and being dragged through it, which is worse than not\n            // rowing at all — she slews toward the fouled side.\n            mine = -0.45 * foul;\n          } else if (inWater) {\n            // SLIP. A blade only pushes while it is going sternward faster\n            // than the water it is in; once she is already travelling at\n            // the speed the blade sweeps, it stops biting and starts being\n            // dragged along. It is the same fact as propeller slip, and it\n            // does three jobs at once:\n            //\n            //  * she has a terminal speed under oars, and it goes UP with\n            //    the rate rather than the model being indifferent to it;\n            //  * a crew out of time is slower, because the late blades\n            //    catch while she is already running from the early ones'\n            //    drive and get much less bite — which is a real mechanism\n            //    rather than a penalty applied to raggedness;\n            //  * and pulling one side only does not spin her up for ever.\n            const bite = bladeSpeed > 1e-4 ? clamp01(1 - way / bladeSpeed) : 0;\n            // And being out of time costs him. This one is a term I wrote\n            // rather than one that fell out, and it has to be: spreading\n            // the same total pull over more of the cycle makes a hull\n            // FASTER, because a steady push beats a pulsed one against\n            // drag — so left to itself the model says a shambles is quick,\n            // which is the opposite of every crew that ever rowed.\n            //\n            // What is missing from it is the rower. A man out of time is\n            // not applying the same force a moment late; he is washing out\n            // at the catch and checking her at the finish, fighting the\n            // boat through his own stretcher while the rest of them fight\n            // him back. That is a property of the body, not of the water,\n            // so it does not emerge from the water and it is written here.\n            const offBeat = Math.abs(wrap01(own - phase + 0.5) - 0.5);\n            const inTime = clamp01(1 - offBeat * 3.6);\n            mine = bump(p / spec.drive) * effort * (effort < 0 ? 1 : bite) * inTime;\n          }\n        }\n        b.thrust = mine;\n        sum += mine;\n        if (b.side < 0) {\n          port += mine;\n          portN++;\n        } else {\n          star += mine;\n          starN++;\n        }\n\n        // ---- and what it looks like ----------------------------------\n        // Sweep: aft through the drive, forward again through the recovery.\n        // The recovery is the longer half, so it comes back slower than it\n        // went — the tell that separates rowing from a windscreen wiper.\n        const swing = inWater\n          ? ease(p / spec.drive)\n          : 1 - ease((p - spec.drive) / (1 - spec.drive));\n        const reach = 0.62 + 0.12 * Math.abs(effort);\n        // The blade starts FORWARD at the catch and goes aft through the\n        // drive — it pushes water sternward, which is what drives her\n        // ahead. This was the other way round for the whole of the first\n        // version: an entire fleet rowing itself backwards while the\n        // thrust, the rate and the way were all computed from the phase and\n        // all agreed. Nothing found it until a body was put on the handle\n        // and its hands came out a whole stroke-length adrift.\n        b.pivot.rotation.y = b.side * (reach * (swing - 0.5) * 2);\n        // Lift: buried through the drive, clear of the water on the way\n        // forward. Without this the blades scythe through the sea in both\n        // directions and she should be going nowhere.\n        const clear = inWater ? 0 : Math.sin(Math.PI * ((p - spec.drive) / (1 - spec.drive)));\n        b.pivot.rotation.z = b.side * -(bury - clear * (bury + 0.22));\n        if (foul > 0) {\n          // Fouled: the loom kicks up and stops sweeping. It is the one\n          // thing in a boat that everybody sees at once.\n          b.pivot.rotation.z = b.side * -(bury - 0.9 * foul);\n          b.pivot.rotation.y *= 1 - foul * 0.8;\n        }\n      }\n\n      thrust = built.length ? sum / built.length : 0;\n      yaw = (starN ? star / starN : 0) - (portN ? port / portN : 0);\n\n      // ---- her way through the water ---------------------------------\n      // The pulse becomes a surge here and nowhere else. Handed straight to\n      // a hull, `thrust` stops her dead twice a second.\n      way += (thrust * spec.power - way * spec.drag) * dt;\n      if (way < 0 && thrust >= 0) way = Math.max(way, -0.5);\n    },\n  };\n  return api;\n}\n\n/** Where the handle should be, for a given phase, in the rower's own frame. */\nexport function oarGripAt(phase: number, out = new Vector3()): Vector3 {\n  const p = wrap01(phase);\n  const drive = 0.4;\n  const swing = p < drive ? ease(p / drive) : 1 - ease((p - drive) / (1 - drive));\n  return out.set(\n    0,\n    OAR_GRIP.height + (1 - swing) * 0.08,\n    OAR_GRIP.reach + (OAR_GRIP.finish - OAR_GRIP.reach) * swing\n  );\n}\n","import {\n  BoxGeometry,\n  CylinderGeometry,\n  Group,\n  Mesh,\n  MeshStandardMaterial,\n  Object3D,\n  PlaneGeometry,\n  Quaternion,\n  Raycaster,\n  TorusGeometry,\n  Vector3,\n} from 'three';\nimport { Rng } from '../core/random';\nimport { DEFAULT_PALETTE, type Palette } from '../core/palette';\nimport { createSurface } from '../materials/surface';\nimport { createSlot, addApproach, type Prop, type PropSlot } from '../core/types';\nimport { createSmoke, type SmokeSource, type SmokeLayer } from './smoke';\nimport { createSteam, type Steam } from './waterworks';\nimport { createPressureGauge, type PressureGauge } from './gauge';\n\n/**\n * A steam plant — and the one propulsion in this trilogy whose output is\n * **not monotonic in its own control.**\n *\n * A sail gives you more the better you trim it. Oars give you more the harder\n * you pull. Open a steam engine right up and she goes **slower**, and that is\n * not a penalty anybody wrote:\n *\n * ```ts\n * plant.setLink(1.0);                   // full gear, longest cut-off\n * plant.setLink(plant.linkFor(3600));   // …and this one beats it, by a third\n * ```\n *\n * The reason is that the regulator spends a store the fire fills a hundred\n * times more slowly than the engine empties it. Full gear admits steam for\n * most of the stroke, which is enormous torque and enormous consumption; the\n * boiler cannot keep up, the pressure sags, and half an hour later she is\n * making less power at 4 bar than she would have made all day at 9. Notch her\n * up — admit steam for a fifth of the stroke and let it *expand* — and she\n * settles at a speed she can hold. The whole nineteenth century is in that.\n *\n * So the store is the model. One integrated number, the boiler temperature,\n * with a **signed balance** across it:\n *\n * ```\n * balance = raised − lost − engine − auxiliaries − vent − dumped\n * ```\n *\n * and everything else is a read of that number. The pressure is not stored,\n * it is `pressureFor(temperature)` every time you ask — which is why the\n * needle sits flat on its stop for the first stretch of a cold light-up while\n * the funnel is already black. Below 100 °C there is no steam to have.\n *\n * ```ts\n * const ship  = createDeckedShip({ era: 'steamer' });\n * const plant = createSteamPlant({ kind: 'triple' });\n * ship.object.add(plant.object);\n *\n * plant.setDraught(1);\n * plant.setRegulator(1);\n * plant.setLink(plant.linkFor(3600));   // a setting she will actually keep\n *\n * game.onUpdate((t) => {\n *   plant.update(t.delta);                                    // FIRST\n *   ship.update(t.delta, { speed: plant.way, drift: plant.walk });\n * });\n * ```\n *\n * `way` goes straight into `ShipInput.speed` — it is already in hull units,\n * like `OarBank.way` and unlike `SailRig.drive`.\n */\nexport type SteamKind = 'sidelever' | 'compound' | 'triple' | 'launch';\n\n/**\n * Era order — and the axis is **what she asks of you to give you power.**\n *\n * A sidelever wants a man with a shovel and gives you 20 rpm at one and a bit\n * bar. A triple wants a stokehold watch and gives you a fortnight at sea. And\n * `launch` is the inversion at the end of it: she asks nothing — no bed, no\n * bunker, no black smoke, steam in eleven minutes — and then refuses to start\n * at all, because she has one cylinder and can stop on dead centre. Same\n * table, opposite gameplay.\n */\nexport const STEAM_KINDS: SteamKind[] = ['sidelever', 'compound', 'triple', 'launch'];\n\n/**\n * rest / transitioning-toward / at-target / drifting-back, classified from\n * `balance` at the end of every update — never a transition table.\n *\n * `blowing` and `turning` are booleans *beside* it rather than states of their\n * own: a boiler blowing off is still `'up'`, and four states have no room for\n * over-range.\n */\nexport type SteamState = 'cold' | 'raising' | 'up' | 'falling';\n\n/**\n * The control duck-type again — deliberately not imported from `mechanisms`,\n * so a caller can hand any object with this shape to anything that wants one.\n */\nexport interface SteamControl {\n  readonly state: number;\n  readonly open: boolean;\n  toggle(): boolean;\n  set(target: number | boolean): void;\n  update(dt: number): void;\n  onChange?: (open: boolean) => void;\n  object: Object3D;\n}\n\nexport interface SteamPlant extends Prop {\n  kind: SteamKind;\n\n  // ── the store ────────────────────────────────────────────────────────\n  /** Boiler contents, °C. THE ONE INTEGRATED NUMBER. */\n  readonly temperature: number;\n  /** Gauge pressure, bar. NOT STORED — derived from `temperature` every read. */\n  readonly pressure: number;\n  /** °C/s, SIGNED. The value that was integrated this step, so the needle's\n   *  velocity and a planner's number cannot drift apart. */\n  readonly balance: number;\n  readonly working: number;\n  readonly blowOff: number;\n  /** The red mark at the bottom of the dial. Read by the gauge, by `state`\n   *  and by `endurance` — and by NOTHING in the physics. Back pressure\n   *  already brings her smoothly to a stand. */\n  readonly low: number;\n  /** How much of her power she can give you now, 0–1. */\n  readonly readiness: number;\n  /** The pressure the fire NOW ON THE GRATE would settle at, capped at\n   *  `blowOff` because that is where the valve puts her. A getter, never a\n   *  table row — a written-down banked-hold figure is the single easiest\n   *  number in this family to get wrong. */\n  readonly reach: number;\n  /** Seconds to `bar` at the firing order she has now. `Infinity` if that\n   *  fire will never get her there.\n   *\n   *  Assumes you are NOT steaming while you wait, which is what notice means\n   *  — the same honest omission as `SailRig.layline` ignoring the tide. It\n   *  also ignores the fire's own catch time and the scale she lays down on\n   *  the way, so it runs a few per cent optimistic on a long light-up: under\n   *  2% on a hand-fired boiler, more like 7% on a compound. */\n  noticeFor(bar: number): number;\n  /** Seconds she will still have `bar` if nobody touches anything else. A\n   *  projection under held settings, not a promise. `Infinity` if she holds. */\n  holdsFor(bar: number): number;\n  /** === `holdsFor(low)`. One integrator, so the two cannot disagree. */\n  readonly endurance: number;\n  readonly state: SteamState;\n  onState?: (state: SteamState) => void;\n\n  // ── the fire ─────────────────────────────────────────────────────────\n  /** What it is DOING, 0–1, eased. */\n  readonly firing: number;\n  /** What it was TOLD. */\n  readonly draught: number;\n  setDraught(level: number): void;\n  /** Bank her: sugar for `setDraught(this era's banked level)`. Vocabulary,\n   *  not model. */\n  bank(): void;\n  /** Coal on. Raises the bed and sets `green`, which is the black puff. A\n   *  SILENT NO-OP on `launch` — and that no-op is the era axis. */\n  stoke(amount?: number): void;\n  /** Fire bed 0–1; caps `firing`. Always 1 on `launch`. */\n  readonly bed: number;\n  readonly fuel: number;\n  bunker(amount?: number): void;\n  /** Scale on the tubes, 0–1. A MULTIPLIER on the fire, not a state: a\n   *  fouled boiler still gets there, it just never stops working for it. */\n  readonly scale: number;\n  blowDown(): void;\n  fireDoor: SteamControl;\n\n  // ── the engine ───────────────────────────────────────────────────────\n  readonly regulator: number;\n  setRegulator(open: number): void;\n  /** Where the link IS: −1 (full astern gear) … 0 (mid-gear) … +1. NOT where\n   *  it was ordered — it travels, and it travels heavier under steam.\n   *  Cut-off AND direction in one number, because on a real engine they are\n   *  one lever. */\n  readonly link: number;\n  readonly linkOrder: number;\n  setLink(target: number): void;\n  ahead(gear?: number): void;\n  astern(gear?: number): void;\n  stopEngine(): void;\n  /** Fraction of the stroke steam is admitted for. */\n  readonly cutoff: number;\n  /** Revolutions per second, SIGNED. */\n  readonly rev: number;\n  /** Crank angle, rad, wrapping. The visible clock. */\n  readonly crank: number;\n  readonly mep: number;\n  /** Includes the ripple: it dips twice a rev on one cylinder. */\n  readonly torque: number;\n  /** Stopped on dead centre with steam on and nothing happening. Only ever\n   *  true where `cyls === 1`, and that is not a special case — it is the\n   *  crank effort sum reaching zero. */\n  readonly onCentre: boolean;\n  /** Bar her over by hand: a quarter turn, so she can start. */\n  barOver(): void;\n  /** The longest cut-off she can hold for `seconds`, as a reverser position\n   *  you hand straight back to `setLink`, signed to her current direction.\n   *  0 if she cannot hold anything that long.\n   *\n   *  THE FUNCTION THE WHOLE THING EXISTS FOR, and the exact analogue of\n   *  `SailRig.layline`: ask for a passage, get a setting she will keep. */\n  linkFor(seconds: number): number;\n\n  // ── what the hull takes ──────────────────────────────────────────────\n  /** Her way through the water, m/s. Straight into `ShipInput.speed`. */\n  readonly way: number;\n  /** Instantaneous. TELEMETRY — do not hand this to the hull. */\n  readonly thrust: number;\n  /** Transverse thrust in WORLD m/s, ready for `ShipInput.drift`. MUTATED IN\n   *  PLACE each frame: a live view, not a snapshot. */\n  readonly walk: { x: number; z: number };\n  /** How deep the screw is, 0 (racing in air) to 1. Feed it from the sea and\n   *  she races over the crests with nothing written for it. */\n  setImmersion(fraction: number): void;\n  readonly immersion: number;\n\n  // ── what you can see ─────────────────────────────────────────────────\n  readonly blowing: boolean;\n  readonly turning: boolean;\n  /** [soot, grease], parented at the funnel top and cross-faded. */\n  plumes: SmokeSource[];\n  /** The safety valve's white feather. ADDITIVE, driven with `setTarget`. */\n  feather: Steam;\n  /** TRUE until you call `plumesInto`. */\n  readonly stepsPlumes: boolean;\n  /** Hand the plumes to a room AND STOP STEPPING THEM. `SmokeLayer.update`\n   *  already calls `source.update` on everything add()ed; step them twice and\n   *  the rate easing and the shader clock both run at 2× with nothing\n   *  anywhere reporting it. Do NOT parent that layer to a moving hull —\n   *  the layer samples parent space. */\n  plumesInto(layer: SmokeLayer): void;\n  /** Top of the funnel. Call `updateMatrixWorld` before reading its world\n   *  position, like every other mouth in SCENA. */\n  funnelTop: Object3D;\n  gauge: PressureGauge;\n\n  stokehold: PropSlot;\n  platform: PropSlot;\n  slots: PropSlot[];\n\n  update(dt: number): void;\n  /** Explicit fast-forward for authoring. Places the shaft and hull at their\n   *  closed-form fixed points each coarse step and emits endpoints only. */\n  settle(seconds: number): void;\n}\n\nexport interface SteamPlantOptions {\n  kind?: SteamKind;\n  /** Where the crank starts, rad. Random by seed otherwise — and on a\n   *  single-cylinder engine, 0 is dead centre. */\n  crank?: number;\n  /** Where she starts, in bar. DEFAULTS TO THE ERA'S WORKING PRESSURE — a\n   *  ship in a scene has steam up, the way a fridge in a kitchen is cold.\n   *  Pass 0 for a cold ship and be prepared to wait, or to call `settle`. */\n  pressure?: number;\n  fuel?: number;\n  /** Funnel top above the plant's origin, m. Default 16 — far enough up that\n   *  a deck-level camera is not standing inside the plume. */\n  funnelHeight?: number;\n  /** Suppress the casing, keep the plumes. */\n  funnel?: boolean;\n  push?: number;\n  drag?: number;\n  /** Exposed so a test can wire the valve shut and prove the cap is an\n   *  OBJECT and not a `Math.min`. */\n  reliefArea?: number;\n  seed?: number;\n  palette?: Palette;\n}\n\nconst AMBIENT = 15;\nconst TAU = Math.PI * 2;\n/** Below this she is not turning, for the purpose of breaking away. */\nconst CREEP = 0.02;\n/** Half the travel of the die block in the expansion link, m. */\nconst ARC_HALF = 0.16;\n\nconst clamp01 = (t: number): number => (t < 0 ? 0 : t > 1 ? 1 : t);\n\n/**\n * Saturated-steam pressure, bar GAUGE, from water temperature. Antoine, and\n * the `max(0, …)` is the whole reason the needle sits on its stop: below\n * 100 °C the absolute pressure is under one atmosphere and the gauge — which\n * measures the difference — reads nothing at all.\n */\nexport function pressureFor(celsius: number): number {\n  return Math.max(0, Math.exp(11.784 - 3885 / (celsius + 230.2)) - 1.013);\n}\n\n/** The inverse. Gauge bar in, °C out. */\nexport function tempFor(bar: number): number {\n  return 3885 / (11.784 - Math.log(Math.max(0, bar) + 1.013)) - 230.2;\n}\n\n/**\n * Mean effective pressure as a fraction of boiler pressure, for a cut-off.\n *\n * `c·(1 + ln(1/c))` — admit for a fifth of the stroke and the steam still\n * does 0.52 of the work it would do admitted all the way, on a fifth of the\n * steam. That logarithm IS the argument for expansion, and it is also why\n * mid-gear produces no torque: the limit at c → 0 is zero, reached smoothly,\n * with nothing written to stop her.\n */\nexport function expansionRatio(cutoff: number): number {\n  return cutoff <= 1e-4 ? 0 : cutoff * (1 + Math.log(1 / cutoff));\n}\n\n/** Steam spent per unit of work: the reciprocal of the expansion gain. */\nexport function steamPerWork(cutoff: number): number {\n  return cutoff <= 1e-4 ? Infinity : 1 / (1 + Math.log(1 / cutoff));\n}\n\ninterface KindSpec {\n  /** Cylinders. DECIDES WHETHER SHE CAN STOP ON DEAD CENTRE — a behaviour,\n   *  not a mesh count. */\n  cyls: number;\n  phase: number[];\n  stroke: number;\n  rodRatio: number;\n  working: number;\n  blowOff: number;\n  reseat: number;\n  back: number;\n  /** °C/s at full fire. */\n  fire: number;\n  /** Fixed loss coefficient — the LAGGING. The only loss that does not scale\n   *  with the fire, and therefore the only thing that makes a banked fire\n   *  hold lower than a full one. */\n  lag: number;\n  /** Loss coefficient proportional to the firing rate — up the FLUE. */\n  flue: number;\n  appetite: number;\n  auxiliary: number;\n  reliefArea: number;\n  /** The draught that holds her at a simmer. DERIVED from the hold pressure\n   *  wanted, not chosen. */\n  banked: number;\n  dump: number;\n  catch: number;\n  die: number;\n  bedBurn: number;\n  green: number;\n  burnFor: number;\n  scaleRate: number;\n  maxCut: number;\n  /** How the cut-off maps onto reverser travel. DECIDES WHETHER THE PLAYER'S\n   *  REAL CONTROL IS THE GEAR OR THE THROTTLE — harmonise this toward 1.0\n   *  across the kinds \"for tidiness\" and the sidelever quietly becomes a slow\n   *  triple. */\n  gearShape: number;\n  linkRate: number;\n  pull: number;\n  absorb: number;\n  friction: number;\n  inertia: number;\n  pitch: number;\n  push: number;\n  drag: number;\n  astern: number;\n  walk: number;\n  paddle: boolean;\n}\n\n/**\n * The era table.\n *\n * The four thermal columns — `fire`, `lag`, `flue`, `auxiliary` — and\n * `banked` are **derived, not chosen.** Each was solved against one measured\n * behaviour, in an order where nothing has to be re-solved:\n *\n * - `lag` ← how long she takes to go cold with the fires drawn. Exact: with\n *   the fire out the auxiliaries are dead too, so it is a pure exponential.\n * - `fire` ← how often the safety valve lifts with the regulator shut.\n * - `flue` ← the light-up time, bisected, with `fire` following it.\n * - `banked` ← the draught that holds her at ~60% of working. Closed form.\n *\n * Solved the other way round — picking a banked draught and hoping — the\n * ceiling locks onto the banked hold and the safety valve can never lift at\n * all, because the flue loss and the heat are both proportional to the firing\n * rate and cancel.\n */\nconst KINDS: Record<SteamKind, KindSpec> = {\n  sidelever: {\n    cyls: 2, phase: [0, Math.PI / 2], stroke: 1.68, rodRatio: 4.2,\n    working: 1.2, blowOff: 1.45, reseat: 1.25, back: 0.1,\n    fire: 1.9987e-2, lag: 3.6954e-6, flue: 1.3337e-4,\n    appetite: 0.0264, auxiliary: 5.0472e-2, reliefArea: 6.55, banked: 0.0677,\n    dump: 1.69, catch: 420, die: 900, bedBurn: 1800, green: 110,\n    burnFor: 28800, scaleRate: 4.0e-7,\n    maxCut: 0.95, gearShape: 0.1, linkRate: 0.35,\n    pull: 5.46, absorb: 46.0, friction: 1.03, inertia: 446,\n    pitch: 22.0, push: 0.101, drag: 0.0146, astern: 0.85, walk: 0, paddle: true,\n  },\n  compound: {\n    cyls: 2, phase: [0, Math.PI / 2], stroke: 0.6, rodRatio: 4.0,\n    working: 7.0, blowOff: 7.6, reseat: 6.95, back: 0.35,\n    fire: 9.1224e-3, lag: 4.3299e-6, flue: 2.5807e-5,\n    appetite: 0.0112, auxiliary: 9.3086e-3, reliefArea: 3.74, banked: 0.1205,\n    dump: 4.43, catch: 240, die: 600, bedBurn: 1800, green: 90,\n    burnFor: 108000, scaleRate: 7.0e-7,\n    maxCut: 0.8, gearShape: 1.15, linkRate: 0.7,\n    pull: 0.922, absorb: 3.71, friction: 0.292, inertia: 63.2,\n    pitch: 5.24, push: 0.204, drag: 0.0114, astern: 0.72, walk: 0.22, paddle: false,\n  },\n  triple: {\n    cyls: 3, phase: [0, (TAU * 1) / 3, (TAU * 2) / 3], stroke: 0.99, rodRatio: 4.2,\n    working: 12.5, blowOff: 13.2, reseat: 12.35, back: 0.45,\n    fire: 6.9624e-3, lag: 3.9644e-6, flue: 1.3951e-5,\n    appetite: 0.00625, auxiliary: 7.1294e-3, reliefArea: 3.69, banked: 0.1471,\n    dump: 5.06, catch: 240, die: 600, bedBurn: 1800, green: 90,\n    burnFor: 216000, scaleRate: 6.0e-7,\n    maxCut: 0.85, gearShape: 1.3, linkRate: 0.55,\n    pull: 0.504, absorb: 2.75, friction: 0.251, inertia: 67.0,\n    pitch: 4.67, push: 0.173, drag: 0.00808, astern: 0.7, walk: 0.18, paddle: false,\n  },\n  launch: {\n    cyls: 1, phase: [0], stroke: 0.2, rodRatio: 3.8,\n    working: 11.0, blowOff: 12.0, reseat: 10.8, back: 0.3,\n    fire: 8.8854e-1, lag: 4.9101e-5, flue: 4.5336e-3,\n    appetite: 0.172, auxiliary: 3.757e-2, reliefArea: 0.453, banked: 0.0495,\n    dump: 8.7, catch: 8, die: 14, bedBurn: Infinity, green: 0,\n    burnFor: 21600, scaleRate: 1.2e-6,\n    maxCut: 0.75, gearShape: 0.9, linkRate: 1.6,\n    pull: 0.581, absorb: 0.127, friction: 0.054, inertia: 2.34,\n    pitch: 0.864, push: 0.919, drag: 0.0709, astern: 0.75, walk: 0.3, paddle: false,\n  },\n};\n\n/** Everything the model integrates, and nothing it draws. Copyable, so a\n *  projection can run forward without touching the plant. */\ninterface Sim {\n  temperature: number;\n  crank: number;\n  rev: number;\n  way: number;\n  link: number;\n  linkOrder: number;\n  firing: number;\n  draught: number;\n  bed: number;\n  green: number;\n  fuel: number;\n  scale: number;\n  blowing: boolean;\n  regulator: number;\n  immersion: number;\n  balance: number;\n  torque: number;\n  thrust: number;\n  doorShut: number;\n}\n\nconst copy = (s: Sim): Sim => ({ ...s });\n\n/** Mean |crank effort| over a revolution — the normaliser, so `torque` means\n *  the same thing whatever the cylinder count. */\nfunction effortNormOf(spec: KindSpec): number {\n  const lambda = 1 / spec.rodRatio;\n  let sum = 0;\n  const N = 720;\n  for (let i = 0; i < N; i++) {\n    const crank = (i / N) * TAU;\n    let e = 0;\n    for (const phi of spec.phase) {\n      const th = crank + phi;\n      e += Math.abs(Math.sin(th) + (lambda / 2) * Math.sin(2 * th));\n    }\n    sum += e / spec.cyls;\n  }\n  return sum / N;\n}\n\nexport function createSteamPlant(options: SteamPlantOptions = {}): SteamPlant {\n  const kind: SteamKind = options.kind ?? 'triple';\n  const base = KINDS[kind];\n  const spec: KindSpec = {\n    ...base,\n    push: options.push ?? base.push,\n    drag: options.drag ?? base.drag,\n    reliefArea: options.reliefArea ?? base.reliefArea,\n  };\n  const seed = options.seed ?? 1;\n  const rng = new Rng(seed);\n  const palette = options.palette ?? DEFAULT_PALETTE;\n  const funnelHeight = options.funnelHeight ?? 16;\n  const lambda = 1 / spec.rodRatio;\n  const effortNorm = effortNormOf(spec);\n  const low = 0.4 * spec.working;\n\n  // Free-running speed at working pressure in full gear — the normaliser the\n  // engine's steam draw is measured against.\n  const mepFull = Math.max(0, spec.working - spec.back) * expansionRatio(spec.maxCut);\n  const tqFull = spec.pull * mepFull;\n  const maxRev =\n    (-spec.friction + Math.sqrt(spec.friction ** 2 + 4 * spec.absorb * tqFull)) /\n    (2 * spec.absorb);\n\n  const sim: Sim = {\n    temperature: tempFor(options.pressure ?? spec.working),\n    crank: options.crank ?? rng.range(0.4, TAU - 0.4),\n    rev: 0,\n    way: 0,\n    link: 0,\n    linkOrder: 0,\n    firing: 0,\n    draught: 0,\n    bed: spec.bedBurn === Infinity ? 1 : 1,\n    green: 0,\n    fuel: clamp01(options.fuel ?? 1),\n    scale: 0,\n    blowing: false,\n    regulator: 0,\n    immersion: 1,\n    balance: 0,\n    torque: 0,\n    thrust: 0,\n    doorShut: 1,\n  };\n  // A COLD SHIP IS AT AMBIENT, NOT AT ZERO BAR. `tempFor(0)` is 100 °C — the\n  // temperature at which the gauge reads nothing because she is boiling, not\n  // because she is cold.\n  if ((options.pressure ?? spec.working) <= 0) sim.temperature = AMBIENT;\n\n  // ── the model ────────────────────────────────────────────────────────\n\n  /** Crank effort at an angle, normalised so 1 is the average. */\n  const effortAt = (crank: number): number => {\n    let e = 0;\n    for (const phi of spec.phase) {\n      const th = crank + phi;\n      e += Math.abs(Math.sin(th) + (lambda / 2) * Math.sin(2 * th));\n    }\n    return e / spec.cyls / effortNorm;\n  };\n\n  /** The fire, shared by the fine and the coarse step. */\n  const burn = (s: Sim, h: number): void => {\n    // A BANKED FIRE IS CHEAP — that is the one thing banking exists for. Burn\n    // the bed and the bunker at a flat rate regardless of the draught and a\n    // boiler banked overnight is found dead in the morning.\n    const eats = 0.01 + 0.99 * s.firing;\n    if (spec.bedBurn !== Infinity) s.bed = Math.max(0, s.bed - (h / spec.bedBurn) * eats);\n    // The fire door: open it and the draught falls away while you shovel.\n    // One multiplier, and it is why the needle sags every time you stoke.\n    const doorFactor = 0.35 + 0.65 * s.doorShut;\n    const want =\n      Math.min(s.draught * doorFactor, spec.bedBurn === Infinity ? 1 : s.bed) *\n      (s.fuel > 0 ? 1 : 0);\n    // A fire catches faster than it dies. Two time constants, and the\n    // asymmetry is why a banked boiler is worth having.\n    const lagT = want > s.firing ? spec.catch : spec.die;\n    s.firing += Math.sign(want - s.firing) * Math.min(Math.abs(want - s.firing), h / lagT);\n    s.fuel = Math.max(0, s.fuel - (h / spec.burnFor) * eats);\n    if (spec.green > 0) s.green = Math.max(0, s.green - h / spec.green);\n    s.scale = Math.min(1, s.scale + spec.scaleRate * s.firing * h);\n  };\n\n  /** The signed balance, and the integration of it. */\n  const thermal = (s: Sim, h: number, engineDraw: number, dumped: number): void => {\n    const P = pressureFor(s.temperature);\n    if (!s.blowing && P >= spec.blowOff) s.blowing = true;\n    else if (s.blowing && P <= spec.reseat) s.blowing = false;\n\n    const raised = spec.fire * s.firing * (1 - s.scale * 0.5);\n    const lost = (s.temperature - AMBIENT) * (spec.lag + spec.flue * s.firing);\n    // Auxiliary steam is REDUCED and it is only alive while there is a fire in\n    // her or the engine is turning. With the fires drawn they stop, which is\n    // what makes a cold-down a property of the lagging and nothing else.\n    const aux =\n      spec.appetite *\n      Math.min(P, spec.working) *\n      spec.auxiliary *\n      Math.max(s.firing, s.regulator);\n    const vent = s.blowing ? spec.appetite * P * spec.reliefArea : 0;\n    s.balance = raised - lost - engineDraw - aux - vent - dumped;\n    s.temperature += s.balance * h;\n  };\n\n  const INNER = 0.02;\n\n  /** One fine step: everything moves, nothing is at a fixed point. */\n  const fine = (s: Sim, h: number): void => {\n    const P = pressureFor(s.temperature);\n    const chest = P * s.regulator;\n\n    burn(s, h);\n\n    // The reverser is a VELOCITY, not a knob: it travels, and it travels\n    // heavier with steam on the valves.\n    const effort = 1 - 0.7 * s.regulator * clamp01(P / spec.working);\n    const maxStep = spec.linkRate * effort * h;\n    const err = s.linkOrder - s.link;\n    const moved = Math.abs(err) <= maxStep ? err : Math.sign(err) * maxStep;\n    s.link += moved;\n    const linkVel = h > 0 ? moved / h : 0;\n\n    const cutoff = spec.maxCut * Math.abs(s.link) ** spec.gearShape;\n    const mep = Math.max(0, chest - spec.back) * expansionRatio(cutoff);\n    const dir = Math.sign(s.link);\n    s.torque = spec.pull * mep * effortAt(s.crank) * dir * (dir < 0 ? spec.astern : 1);\n\n    const net =\n      s.torque - spec.absorb * s.rev * Math.abs(s.rev) * s.immersion - spec.friction * s.rev;\n    // DEAD CENTRE. Not a special case: the crank effort sum has simply\n    // reached zero, which one cylinder can do and two at 90° never can.\n    if (Math.abs(s.rev) < CREEP && Math.abs(net) < spec.friction * 0.5) s.rev = 0;\n    else s.rev += (net / spec.inertia) * h;\n    s.crank = (s.crank + s.rev * TAU * h) % TAU;\n    if (s.crank < 0) s.crank += TAU;\n\n    // Both terms carry `immersion`, but not to the same power: a screw half\n    // out of the water turns much faster AND pushes very little, because\n    // what is left is churning air down onto the blades. Linear in both and\n    // she races and goes FASTER, which is the opposite of the read.\n    s.thrust = spec.push * (s.rev * spec.pitch - s.way) * s.immersion * s.immersion;\n    s.way += (s.thrust - spec.drag * s.way * Math.abs(s.way)) * h;\n    if (s.way < 0 && s.thrust >= 0) s.way = Math.max(s.way, -0.5);\n\n    const engine = spec.appetite * chest * cutoff * (Math.abs(s.rev) / maxRev);\n    // Swinging the reverser under steam DUMPS a chestful. Notching up costs\n    // you something, which is why you do not fiddle with it.\n    const dumped = spec.dump * Math.abs(linkVel) * s.regulator * clamp01(P / spec.working);\n    thermal(s, h, engine, dumped);\n  };\n\n  /**\n   * One coarse step: the shaft and the hull RELAX toward their closed-form\n   * fixed points rather than being integrated.\n   *\n   * `tended` is the one thing a projection assumes that a watched plant does\n   * not. Skipping four hours with nobody on the plate finds the fire out and\n   * the boiler cold, which is true and useless — \"how long will she hold\n   * this\" means \"how long will she hold this while somebody keeps the fire\n   * in\". In real time, stoking is the player's job and this is false.\n   */\n  const coarse = (s: Sim, h: number, tended = true): void => {\n    if (tended && spec.bedBurn !== Infinity && s.fuel > 0) s.bed = 1;\n    const P = pressureFor(s.temperature);\n    const chest = P * s.regulator;\n    burn(s, h);\n    s.link = s.linkOrder;\n\n    const cutoff = spec.maxCut * Math.abs(s.link) ** spec.gearShape;\n    const mep = Math.max(0, chest - spec.back) * expansionRatio(cutoff);\n    const dir = Math.sign(s.link);\n    const tq = spec.pull * mep * dir * (dir < 0 ? spec.astern : 1);\n    const a = spec.absorb * s.immersion;\n    const revTo =\n      Math.sign(tq) *\n      ((-spec.friction + Math.sqrt(spec.friction ** 2 + 4 * a * Math.abs(tq))) / (2 * a));\n    // A SINGLE CYLINDER STOPPED ON DEAD CENTRE STAYS THERE. The fixed point\n    // knows nothing about crank angle, so skipping time would quietly start an\n    // engine a watched plant could never start.\n    const stalled =\n      Math.abs(s.rev) < CREEP && Math.abs(tq * effortAt(s.crank)) < spec.friction * 0.5;\n    if (stalled) s.rev = 0;\n    else {\n      // RELAX, do not SNAP. Snapping puts the shaft at full revolutions on the\n      // first coarse step, so the engine draws its whole appetite from an\n      // instant when a watched plant would still be turning over — a launch\n      // fast-forwarded arrives at half the pressure of the same launch watched.\n      const revTau = spec.inertia / (spec.friction + 2 * a * Math.abs(revTo) + 1e-9);\n      s.rev = revTo + (s.rev - revTo) * Math.exp(-h / revTau);\n    }\n    s.crank = (s.crank + s.rev * TAU * h) % TAU;\n    if (s.crank < 0) s.crank += TAU;\n\n    const k = spec.push * s.rev * spec.pitch * s.immersion;\n    const p = spec.push * s.immersion;\n    const mag = (drive: number): number =>\n      (-p + Math.sqrt(p * p + 4 * spec.drag * Math.abs(drive))) / (2 * spec.drag);\n    const wayTo = k >= 0 ? mag(k) : Math.max(-0.5, -mag(k));\n    const wayTau = 1 / (p + 2 * spec.drag * Math.abs(wayTo) + 1e-9);\n    s.way = wayTo + (s.way - wayTo) * Math.exp(-h / wayTau);\n    s.thrust = spec.push * (s.rev * spec.pitch - s.way) * s.immersion * s.immersion;\n\n    const engine = spec.appetite * chest * cutoff * (Math.abs(s.rev) / maxRev);\n    thermal(s, h, engine, 0);\n  };\n\n  const COARSE = Math.min(5, spec.catch / 5, spec.die / 5);\n  const advance = (s: Sim, seconds: number): void => {\n    let left = seconds;\n    while (left > 0) {\n      const h = Math.min(COARSE, left);\n      left -= h;\n      coarse(s, h);\n    }\n  };\n\n  /**\n   * The temperature a steady firing rate `f` would settle at, with the engine\n   * as it is now. Bisected rather than written down: the equilibrium moves\n   * with the scale on the tubes and with what the engine is taking, and a\n   * banked-hold figure in a table is the easiest number here to get wrong.\n   */\n  const settleTemp = (f: number): number => {\n    const cutoff = spec.maxCut * Math.abs(sim.link) ** spec.gearShape;\n    const at = (T: number): number => {\n      const P = pressureFor(T);\n      const chest = P * sim.regulator;\n      const raised = spec.fire * f * (1 - sim.scale * 0.5);\n      const lost = (T - AMBIENT) * (spec.lag + spec.flue * f);\n      const aux =\n        spec.appetite * Math.min(P, spec.working) * spec.auxiliary * Math.max(f, sim.regulator);\n      const engine = spec.appetite * chest * cutoff * (Math.abs(sim.rev) / maxRev);\n      return raised - lost - aux - engine;\n    };\n    let lo = AMBIENT;\n    let hi = AMBIENT + spec.fire / spec.lag;\n    if (at(lo) <= 0) return AMBIENT;\n    for (let i = 0; i < 60; i++) {\n      const m = (lo + hi) / 2;\n      if (at(m) > 0) lo = m;\n      else hi = m;\n    }\n    return (lo + hi) / 2;\n  };\n\n  // ── geometry ─────────────────────────────────────────────────────────\n\n  const group = new Group();\n  group.name = `steamPlant:${kind}`;\n\n  const iron = createSurface('steel', { color: 0x4d4f52, seed });\n  const lagged = createSurface('plaster', { color: 0xb9b2a4, seed: seed + 1 });\n  const brass = createSurface('brass', { seed: seed + 2 });\n  const dark = new MeshStandardMaterial({ color: 0x2b2d30, roughness: 0.75 });\n  // Iron, not whatever the palette calls metal — a white firebox face reads\n  // as a domestic appliance parked on the deck.\n  const plate = createSurface('steel', { color: 0x4a4d51, seed: seed + 3 });\n\n  // Scale everything off the stroke, so a launch is a launch and a sidelever\n  // fills an engine room.\n  const r = spec.stroke / 2;\n  const rod = spec.rodRatio * r;\n  const bore = spec.stroke * 0.62;\n  // The BOILER is not sized by the engine. Scale everything off the stroke and\n  // a triple gets a 2.7 m drum and a 1.1 m funnel — correct arithmetic, and it\n  // renders as a fridge with a flagpole on it. A Scotch boiler is four metres\n  // across and a liner's funnel is three, because the fire is the big thing.\n  const boilerR = Math.max(0.8, spec.stroke * 2.0);\n  const boilerLen = boilerR * 2.5;\n\n  // THE BOILER IS A HOLE. Shell as an open-ended cylinder with a back plate\n  // only — the front is the firebox face, and the door opens into a recess\n  // you can see into. A solid drum with the doors parented inside renders as\n  // a closed can and every test still passes, because no test looks through.\n  const shell = new Mesh(\n    new CylinderGeometry(boilerR, boilerR, boilerLen, 20, 1, true),\n    lagged\n  );\n  shell.rotation.x = Math.PI / 2;\n  shell.position.set(0, boilerR + 0.25, -boilerLen / 2 - 0.05);\n  group.add(shell);\n  const backPlate = new Mesh(new CylinderGeometry(boilerR, boilerR, 0.06, 20), plate);\n  backPlate.rotation.x = Math.PI / 2;\n  backPlate.position.set(0, boilerR + 0.25, -boilerLen - 0.05);\n  group.add(backPlate);\n  for (let i = 0; i < 3; i++) {\n    const hoop = new Mesh(new TorusGeometry(boilerR * 1.01, 0.035, 6, 20), iron);\n    hoop.position.set(0, boilerR + 0.25, -0.35 - (i * (boilerLen - 0.7)) / 2);\n    group.add(hoop);\n  }\n\n  // The firebox face, with a door-sized hole in it made of four plates.\n  const doorCount = spec.cyls === 1 ? 1 : 2;\n  const doorW = boilerR * 0.52;\n  const doorH = boilerR * 0.46;\n  const faceY = boilerR * 0.72;\n  const faceZ = -0.06;\n  const facePanel = (w: number, hgt: number, x: number, y: number): void => {\n    const m = new Mesh(new BoxGeometry(w, hgt, 0.05), plate);\n    m.position.set(x, y, faceZ);\n    group.add(m);\n  };\n  {\n    const span = doorCount * doorW + (doorCount - 1) * 0.1;\n    const sideW = (boilerR * 2 - span) / 2;\n    facePanel(sideW, boilerR * 2, -(span / 2 + sideW / 2), boilerR + 0.25);\n    facePanel(sideW, boilerR * 2, span / 2 + sideW / 2, boilerR + 0.25);\n    facePanel(span, boilerR * 2 - (faceY + doorH / 2) - 0.25 + boilerR, 0,\n      boilerR + 0.25 + (faceY + doorH / 2 + 0.25 + boilerR) / 2);\n    facePanel(span, faceY - doorH / 2 + 0.25, 0, (faceY - doorH / 2 + 0.25) / 2 - 0.25 + 0.25);\n    if (doorCount === 2) facePanel(0.1, doorH, 0, faceY);\n  }\n\n  // The void behind it: a box open toward +z, with the fire on the back of it.\n  const recess = new Group();\n  recess.position.set(0, faceY, faceZ - 0.03);\n  group.add(recess);\n  const rw = doorCount * doorW + (doorCount - 1) * 0.1;\n  const rd = boilerR * 0.9;\n  const wall = (w: number, hgt: number, d: number, x: number, y: number, z: number): void => {\n    const m = new Mesh(new BoxGeometry(w, hgt, d), dark);\n    m.position.set(x, y, z);\n    recess.add(m);\n  };\n  wall(rw, 0.04, rd, 0, doorH / 2, -rd / 2);\n  wall(rw, 0.04, rd, 0, -doorH / 2, -rd / 2);\n  wall(0.04, doorH, rd, -rw / 2, 0, -rd / 2);\n  wall(0.04, doorH, rd, rw / 2, 0, -rd / 2);\n  const fireMat = new MeshStandardMaterial({\n    color: 0x2a1408,\n    emissive: 0xff7326,\n    emissiveIntensity: 0,\n    roughness: 1,\n  });\n  const fireGlow = new Mesh(new PlaneGeometry(rw * 0.94, doorH * 0.92), fireMat);\n  fireGlow.name = 'firebox:fire';\n  fireGlow.position.z = -rd + 0.03;\n  recess.add(fireGlow);\n\n  // Fire doors — a fifth hand-rolled copy of the control duck-type, and\n  // called a copy. `> 0.5` throughout, matching every other clone in the tree\n  // rather than mechanisms.ts's `>= 0.5`.\n  const flaps: Object3D[] = [];\n  for (let i = 0; i < doorCount; i++) {\n    const hinge = new Object3D();\n    const x = doorCount === 1 ? 0 : (i === 0 ? -1 : 1) * (doorW / 2 + 0.05);\n    hinge.position.set(x + (doorCount === 1 ? -doorW / 2 : i === 0 ? -doorW / 2 : doorW / 2),\n      faceY, faceZ + 0.03);\n    const leaf = new Mesh(new BoxGeometry(doorW, doorH, 0.04), iron);\n    leaf.position.x = (i === 0 && doorCount === 2) || doorCount === 1 ? doorW / 2 : -doorW / 2;\n    hinge.add(leaf);\n    const handle = new Mesh(new CylinderGeometry(0.018, 0.018, doorH * 0.5, 8), brass);\n    handle.position.set(leaf.position.x + (doorCount === 1 ? doorW * 0.36 : 0), 0, 0.035);\n    hinge.add(handle);\n    group.add(hinge);\n    flaps.push(hinge);\n  }\n\n  // Funnel — a casing, hollow, so smoke comes out of a pipe and not a post.\n  const funnelR = Math.max(0.55, boilerR * 0.62);\n  const funnelTop = new Object3D();\n  funnelTop.position.set(0, funnelHeight, -boilerLen * 0.55);\n  group.add(funnelTop);\n  if (options.funnel !== false) {\n    const casing = new Mesh(\n      new CylinderGeometry(funnelR, funnelR * 1.08, funnelHeight - boilerR * 2 - 0.25, 16, 1, true),\n      createSurface('paint', { color: 0x2f3134, seed: seed + 4 })\n    );\n    casing.position.set(\n      0,\n      boilerR * 2 + 0.25 + (funnelHeight - boilerR * 2 - 0.25) / 2,\n      -boilerLen * 0.55\n    );\n    group.add(casing);\n    const cap = new Mesh(new TorusGeometry(funnelR * 1.04, 0.05, 6, 16), iron);\n    cap.rotation.x = Math.PI / 2;\n    cap.position.copy(funnelTop.position);\n    group.add(cap);\n  }\n\n  // Safety valve, on top of the boiler where everybody can hear it.\n  const valveMount = new Object3D();\n  valveMount.position.set(boilerR * 0.45, boilerR * 2 + 0.25, -boilerLen * 0.28);\n  group.add(valveMount);\n  const valveSeat = new Mesh(new CylinderGeometry(0.09, 0.11, 0.1, 12), brass);\n  valveMount.add(valveSeat);\n  const poppet = new Object3D();\n  poppet.position.y = 0.08;\n  valveMount.add(poppet);\n  const poppetHead = new Mesh(new CylinderGeometry(0.07, 0.07, 0.05, 12), brass);\n  poppet.add(poppetHead);\n  const spring = new Mesh(new CylinderGeometry(0.045, 0.045, 0.16, 8), iron);\n  spring.position.y = 0.13;\n  valveMount.add(spring);\n\n  // The engine. Built in a frame where the shaft runs along +x; a screw ship's\n  // engine is then turned a quarter so her shaft runs aft, and a paddler's is\n  // left athwartships with the wheels on the ends of it.\n  const engine = new Group();\n  engine.position.set(0, 0, boilerR * 1.35);\n  engine.rotation.y = spec.paddle ? 0 : Math.PI / 2;\n  group.add(engine);\n\n  const shaftY = 0.35 + r;\n  const spanX = Math.max(1.2, spec.cyls * bore * 1.9);\n  const bed = new Mesh(new BoxGeometry(spanX + 0.5, 0.3, bore * 2.4), plate);\n  bed.position.y = 0.15;\n  engine.add(bed);\n\n  const shaft = new Object3D();\n  shaft.position.y = shaftY;\n  engine.add(shaft);\n  const shaftBar = new Mesh(new CylinderGeometry(r * 0.22, r * 0.22, spanX + 0.4, 10), iron);\n  shaftBar.rotation.z = Math.PI / 2;\n  shaft.add(shaftBar);\n\n  interface Unit {\n    pin: Object3D;\n    crosshead: Object3D;\n    conrod: Object3D;\n    pistonRod: Mesh;\n    phase: number;\n    x: number;\n  }\n  const units: Unit[] = [];\n  for (let i = 0; i < spec.cyls; i++) {\n    const x = spec.cyls === 1 ? 0 : (i / (spec.cyls - 1) - 0.5) * spanX;\n    const phi = spec.phase[i];\n\n    // The throw is a CHILD OF THE SHAFT set at this cylinder's phase, so the\n    // pin follows the crank for free and a three-crank engine looks like one\n    // rather than like three of the same.\n    const throwArm = new Object3D();\n    throwArm.rotation.x = phi;\n    shaft.add(throwArm);\n    const web = new Mesh(new BoxGeometry(r * 0.3, r * 1.3, r * 0.34), iron);\n    web.position.set(x, r / 2, 0);\n    throwArm.add(web);\n    const pin = new Object3D();\n    pin.name = 'crankpin';\n    pin.position.set(x, r, 0);\n    throwArm.add(pin);\n    const pinBar = new Mesh(new CylinderGeometry(r * 0.16, r * 0.16, r * 0.4, 8), iron);\n    pinBar.rotation.z = Math.PI / 2;\n    pin.add(pinBar);\n\n    const crosshead = new Object3D();\n    crosshead.name = 'crosshead';\n    crosshead.position.x = x;\n    engine.add(crosshead);\n    const block = new Mesh(new BoxGeometry(bore * 0.5, r * 0.34, bore * 0.44), iron);\n    crosshead.add(block);\n\n    const conrod = new Object3D();\n    engine.add(conrod);\n    const rodBar = new Mesh(new BoxGeometry(r * 0.16, rod, r * 0.16), iron);\n    rodBar.position.y = rod / 2;\n    conrod.add(rodBar);\n\n    const pistonRod = new Mesh(new CylinderGeometry(r * 0.1, r * 0.1, spec.stroke * 1.4, 8), brass);\n    engine.add(pistonRod);\n\n    // Cylinder above, with a cover, and the guide bars the crosshead runs in.\n    const cylY = shaftY + r + rod + spec.stroke * 0.5 + 0.12;\n    const cyl = new Mesh(\n      new CylinderGeometry(bore / 2, bore / 2, spec.stroke * 1.25, 14, 1, true),\n      lagged\n    );\n    cyl.position.set(x, cylY, 0);\n    engine.add(cyl);\n    const cover = new Mesh(new CylinderGeometry(bore * 0.56, bore * 0.56, 0.06, 14), iron);\n    cover.position.set(x, cylY + spec.stroke * 0.625, 0);\n    engine.add(cover);\n    const bottom = new Mesh(new CylinderGeometry(bore * 0.56, bore * 0.56, 0.06, 14), iron);\n    bottom.position.set(x, cylY - spec.stroke * 0.625, 0);\n    engine.add(bottom);\n    for (let g = 0; g < 4; g++) {\n      const gx = x + (g < 2 ? -1 : 1) * bore * 0.4;\n      const gz = (g % 2 === 0 ? -1 : 1) * bore * 0.32;\n      const col = new Mesh(\n        new CylinderGeometry(0.035, 0.035, cylY - spec.stroke * 0.625 - 0.3, 6),\n        iron\n      );\n      col.position.set(gx, 0.3 + (cylY - spec.stroke * 0.625 - 0.3) / 2, gz);\n      engine.add(col);\n    }\n\n    units.push({ pin, crosshead, conrod, pistonRod, phase: phi, x });\n  }\n\n  // The expansion link: a curved slotted plate, STATIC, with a die block that\n  // slides in it. The die block sliding to the middle of the link is the exact\n  // instant the torque goes to zero — so the geometry and the physics are the\n  // same claim, seen twice.\n  const linkStand = new Object3D();\n  linkStand.position.set(spanX / 2 + 0.42, shaftY + r * 0.4, 0);\n  engine.add(linkStand);\n  const arc = new Mesh(new TorusGeometry(ARC_HALF * 1.9, 0.028, 6, 14, 1.05), iron);\n  arc.rotation.y = Math.PI / 2;\n  arc.rotation.z = Math.PI / 2 - 0.525;\n  linkStand.add(arc);\n  const dieBlock = new Mesh(new BoxGeometry(0.09, 0.075, 0.075), brass);\n  dieBlock.name = 'dieBlock';\n  linkStand.add(dieBlock);\n\n  const quadrant = new Object3D();\n  quadrant.position.set(spanX / 2 + 0.75, 0.32, bore * 0.8);\n  engine.add(quadrant);\n  const quadPlate = new Mesh(new TorusGeometry(0.55, 0.03, 5, 12, 1.3), iron);\n  quadPlate.rotation.y = Math.PI / 2;\n  quadPlate.rotation.z = Math.PI / 2 - 0.65;\n  quadrant.add(quadPlate);\n  const reverserLever = new Object3D();\n  quadrant.add(reverserLever);\n  const leverBar = new Mesh(new BoxGeometry(0.05, 0.9, 0.05), iron);\n  leverBar.position.y = 0.45;\n  reverserLever.add(leverBar);\n  const leverGrip = new Mesh(new CylinderGeometry(0.035, 0.035, 0.14, 8), brass);\n  leverGrip.position.y = 0.9;\n  leverGrip.rotation.z = Math.PI / 2;\n  reverserLever.add(leverGrip);\n\n  // Regulator: a wheel-topped lever on the starting platform. Its position is\n  // POLLED every frame — a notch change from 0.2 to 0.45 fires no onChange.\n  const regStand = new Object3D();\n  regStand.position.set(-spanX / 2 - 0.6, 0.9, bore * 0.8);\n  engine.add(regStand);\n  const regPost = new Mesh(new CylinderGeometry(0.05, 0.06, 0.9, 8), iron);\n  regPost.position.y = -0.45;\n  regStand.add(regPost);\n  const regLever = new Object3D();\n  regStand.add(regLever);\n  const regBar = new Mesh(new BoxGeometry(0.04, 0.62, 0.04), iron);\n  regBar.position.y = 0.31;\n  regLever.add(regBar);\n  const regKnob = new Mesh(new CylinderGeometry(0.05, 0.05, 0.05, 10), brass);\n  regKnob.position.y = 0.62;\n  regLever.add(regKnob);\n\n  // Starting platform and its rails.\n  const grating = new Mesh(new BoxGeometry(spanX + 1.6, 0.05, 0.7), plate);\n  grating.position.set(0, 0.3, bore * 1.25);\n  engine.add(grating);\n  for (let i = 0; i < 2; i++) {\n    const rail = new Mesh(\n      new CylinderGeometry(0.025, 0.025, spanX + 1.6, 6),\n      iron\n    );\n    rail.rotation.z = Math.PI / 2;\n    rail.position.set(0, 0.3 + 0.55 + i * 0.35, bore * 1.6);\n    engine.add(rail);\n  }\n\n  // Paddle wheels, on the ends of an athwartships shaft, where she has one.\n  interface Float {\n    pivot: Object3D;\n    ang: number;\n  }\n  const floats: Float[] = [];\n  if (spec.paddle) {\n    const wheelR = 3.2;\n    for (const side of [-1, 1]) {\n      const hub = new Object3D();\n      hub.position.x = side * (spanX / 2 + 1.9);\n      shaft.add(hub);\n      const rim = new Mesh(new TorusGeometry(wheelR, 0.07, 6, 24), iron);\n      rim.rotation.y = Math.PI / 2;\n      hub.add(rim);\n      for (let i = 0; i < 8; i++) {\n        const a = (i / 8) * TAU;\n        const spoke = new Mesh(new BoxGeometry(0.05, wheelR, 0.05), iron);\n        spoke.position.set(0, (Math.cos(a) * wheelR) / 2, (Math.sin(a) * wheelR) / 2);\n        spoke.rotation.x = -a;\n        hub.add(spoke);\n        // The float hangs off the rim on its own pivot and is counter-rotated\n        // so it stays near vertical — which is what feathering IS.\n        const pivot = new Object3D();\n        pivot.position.set(0, Math.cos(a) * wheelR, Math.sin(a) * wheelR);\n        hub.add(pivot);\n        const board = new Mesh(new BoxGeometry(0.9, 0.7, 0.06), createSurface('plank', {\n          color: palette.wood,\n          seed: seed + i,\n        }));\n        pivot.add(board);\n        floats.push({ pivot, ang: a });\n      }\n    }\n  }\n\n  // The gauge, on a stand where the engineer can see it from the platform.\n  const gauge = createPressureGauge({\n    max: Math.ceil(spec.blowOff * 1.25),\n    redline: spec.blowOff,\n    lowMark: low,\n    value: pressureFor(sim.temperature),\n    seed: seed + 5,\n    palette,\n  });\n  const gaugeStand = new Object3D();\n  gaugeStand.position.set(boilerR * 0.62, 1.55, boilerR * 0.7);\n  gaugeStand.rotation.y = -0.5;\n  group.add(gaugeStand);\n  const gaugePipe = new Mesh(new CylinderGeometry(0.03, 0.03, 1.55, 8), brass);\n  gaugePipe.position.y = -0.775;\n  gaugeStand.add(gaugePipe);\n  gaugeStand.add(gauge.object);\n\n  // Plumes at the funnel top. TWO, cross-faded: soot is what she makes all\n  // the time and grease is the black puff of a fresh shovelful. NORMAL\n  // blending, always — near-black smoke under AdditiveBlending is invisible\n  // while `rate` reads perfectly.\n  // A FUNNEL PLUME IS AN ORDER OF MAGNITUDE BIGGER than anything smoke.ts has\n  // drawn before — its styles are sized for a 52 m³ kitchen. At kitchen scale\n  // a ship's funnel makes three faint dots over a fifty-metre hull while\n  // `rate` reads 0.79.\n  const soot = createSmoke({\n    style: 'soot',\n    height: 26,\n    radius: funnelR * 2.4,\n    count: 34,\n    output: 14,\n    seed: seed + 6,\n  });\n  const grease = createSmoke({\n    style: 'grease',\n    height: 21,\n    radius: funnelR * 2.6,\n    count: 28,\n    output: 22,\n    seed: seed + 7,\n  });\n  funnelTop.add(soot.object);\n  funnelTop.add(grease.object);\n\n  // The safety valve's feather. Steam, so ADDITIVE — and driven with\n  // setTarget, not setRate. The two are not interchangeable.\n  const feather = createSteam({ radius: 0.3, height: 7.5, count: 18, seed: seed + 8 });\n  valveMount.add(feather.object);\n  feather.object.position.y = 0.24;\n\n  const stokehold = addApproach(\n    createSlot('stokehold', 'work', group, 0, 0, boilerR * 1.1, Math.PI),\n    group,\n    0.8,\n    'front'\n  );\n  const platform = addApproach(\n    createSlot('platform', 'work', group, -boilerR * 0.5, 0.35, boilerR * 2.4, Math.PI),\n    group,\n    0.8,\n    'front'\n  );\n\n  // ── the visible parts, each driven from exactly one piece of state ────\n\n  let valveLift = 0;\n  const walk = { x: 0, z: 0 };\n  const worldQ = new Quaternion();\n  const starboard = new Vector3();\n\n  const place = (): void => {\n    shaft.rotation.x = sim.crank;\n    for (const u of units) {\n      const th = sim.crank + u.phase;\n      // Exact slider-crank. Travel is exactly one stroke, and that is a test.\n      const root = Math.sqrt(Math.max(0, rod * rod - (r * Math.sin(th)) ** 2));\n      const y = r * Math.cos(th) + root;\n      u.crosshead.position.y = shaftY + y;\n      // The rod runs from the crankpin up to the crosshead and DOES NOT\n      // STRETCH: if the two ends do not meet, the linkage is wrong.\n      u.conrod.position.set(u.x, shaftY + r * Math.cos(th), r * Math.sin(th));\n      u.conrod.rotation.x = -Math.asin(clamp01(Math.abs(r * Math.sin(th)) / rod) *\n        Math.sign(Math.sin(th)));\n      u.pistonRod.position.set(u.x, shaftY + y + spec.stroke * 0.7, 0);\n    }\n    // The die block slides to the middle of the link at exactly the moment\n    // the torque goes to zero.\n    dieBlock.position.y = sim.link * ARC_HALF;\n    reverserLever.rotation.x = sim.link * 0.62;\n    regLever.rotation.x = -sim.regulator * 0.7;\n    for (const f of floats) {\n      // Counter-rotate against the wheel, with a little lag — a feathering\n      // float is never quite upright and that is what you see.\n      f.pivot.rotation.x = -sim.crank - f.ang + Math.sin(sim.crank + f.ang) * 0.22;\n    }\n    for (let i = 0; i < flaps.length; i++) {\n      const swing = (1 - sim.doorShut) * 1.9;\n      flaps[i].rotation.y = (i === 0 ? -1 : 1) * swing;\n    }\n    poppet.position.y = 0.08 + valveLift * 0.06;\n    spring.scale.y = 1 - valveLift * 0.35;\n    fireMat.emissiveIntensity = sim.firing * 2.6 * (0.35 + 0.65 * (1 - sim.doorShut));\n  };\n  place();\n\n  // ── state ────────────────────────────────────────────────────────────\n\n  let state: SteamState = 'cold';\n  const classify = (): SteamState => {\n    const P = pressureFor(sim.temperature);\n    // A two-sided band, so a plant sitting at its equilibrium does not\n    // chatter between raising and falling on the noise of its own integrator.\n    const enter = spec.fire * 0.12;\n    const leave = spec.fire * 0.3;\n    const band = state === 'up' || state === 'cold' ? leave : enter;\n    // Raising steam is an OPERATION and not only a rate. One frame after the\n    // damper opens the fire has not caught, the balance is still nothing, and\n    // reporting 'cold' for the next four minutes is a lie about intent.\n    //\n    // Against the fire she can actually GET, though — not against the damper.\n    // A thin bed caps the firing rate for as long as nobody shovels, and a\n    // plant collapsing under full gear then reads 'raising' for ever because\n    // the damper is still wide open.\n    const doorFactor = 0.35 + 0.65 * sim.doorShut;\n    const want = Math.min(\n      sim.draught * doorFactor,\n      spec.bedBurn === Infinity ? 1 : sim.bed\n    );\n    if (want > sim.firing + 0.02 && P < spec.working) return 'raising';\n    if (sim.balance > band) return 'raising';\n    if (sim.balance < -band) return 'falling';\n    return P >= low ? 'up' : 'cold';\n  };\n  state = classify();\n\n  const plant: SteamPlant = {\n    object: group,\n    // A fitting inside a hull is not something you steer around, and a\n    // nonzero radius would put a world-space circle in a walkable deck.\n    obstacleRadius: 0,\n    kind,\n    plumes: [soot, grease],\n    feather,\n    funnelTop,\n    gauge,\n    stokehold,\n    platform,\n    slots: [stokehold, platform],\n\n    get temperature() {\n      return sim.temperature;\n    },\n    get pressure() {\n      return pressureFor(sim.temperature);\n    },\n    get balance() {\n      return sim.balance;\n    },\n    working: spec.working,\n    blowOff: spec.blowOff,\n    low,\n    get readiness() {\n      return clamp01((pressureFor(sim.temperature) - low) / (spec.working - low));\n    },\n    get reach() {\n      return Math.min(spec.blowOff, pressureFor(settleTemp(sim.firing)));\n    },\n    noticeFor(bar: number) {\n      const target = tempFor(bar);\n      if (sim.temperature >= target) return 0;\n      // The fire she has been ORDERED, because notice is about what is coming.\n      const f = clamp01(sim.draught * (0.35 + 0.65 * sim.doorShut));\n      const eq = settleTemp(f);\n      if (eq <= target) return Infinity;\n      const k = spec.lag + spec.flue * f;\n      if (k <= 0) return Infinity;\n      return -Math.log((eq - target) / (eq - sim.temperature)) / k;\n    },\n    holdsFor(bar: number) {\n      if (pressureFor(sim.temperature) < bar) return 0;\n      const s = copy(sim);\n      const STEP = 30;\n      for (let t = 0; t < 24 * 3600; t += STEP) {\n        coarse(s, STEP);\n        if (pressureFor(s.temperature) < bar) return t + STEP;\n      }\n      return Infinity;\n    },\n    get endurance() {\n      return plant.holdsFor(low);\n    },\n    get state() {\n      return state;\n    },\n\n    get firing() {\n      return sim.firing;\n    },\n    get draught() {\n      return sim.draught;\n    },\n    setDraught(level: number) {\n      sim.draught = clamp01(level);\n    },\n    bank() {\n      sim.draught = spec.banked;\n    },\n    stoke(amount = 1) {\n      // A SILENT NO-OP on a launch, and that no-op is the era axis: the same\n      // call keeps a Scotch alive and does nothing at all to a burner.\n      if (spec.bedBurn === Infinity) return;\n      sim.bed = clamp01(sim.bed + amount);\n      if (spec.green > 0) sim.green = 1;\n    },\n    get bed() {\n      return spec.bedBurn === Infinity ? 1 : sim.bed;\n    },\n    get fuel() {\n      return sim.fuel;\n    },\n    bunker(amount = 1) {\n      sim.fuel = clamp01(sim.fuel + amount);\n    },\n    get scale() {\n      return sim.scale;\n    },\n    blowDown() {\n      sim.scale = 0;\n      // Blowing down dumps hot water over the side, so it costs her.\n      sim.temperature -= (sim.temperature - AMBIENT) * 0.06;\n    },\n    fireDoor: {\n      get state() {\n        return 1 - sim.doorShut;\n      },\n      get open() {\n        // `> 0.5`, matching every hand-rolled clone in the tree rather than\n        // mechanisms.ts's `>= 0.5`. A control parked at exactly 0.5 differs\n        // by which file you copied from.\n        return 1 - sim.doorShut > 0.5;\n      },\n      toggle() {\n        const next = !(1 - sim.doorShut > 0.5);\n        doorOrder = next ? 1 : 0;\n        return next;\n      },\n      set(target: number | boolean) {\n        doorOrder = typeof target === 'boolean' ? (target ? 1 : 0) : clamp01(target);\n      },\n      update() {\n        // Stepped by the plant; here so the duck-type is complete.\n      },\n      object: flaps[0],\n    },\n\n    get regulator() {\n      return sim.regulator;\n    },\n    setRegulator(open: number) {\n      sim.regulator = clamp01(open);\n    },\n    get link() {\n      return sim.link;\n    },\n    get linkOrder() {\n      return sim.linkOrder;\n    },\n    setLink(target: number) {\n      sim.linkOrder = Math.max(-1, Math.min(1, target));\n    },\n    ahead(gear = 1) {\n      sim.linkOrder = Math.abs(Math.max(-1, Math.min(1, gear)));\n    },\n    astern(gear = 1) {\n      sim.linkOrder = -Math.abs(Math.max(-1, Math.min(1, gear)));\n    },\n    stopEngine() {\n      sim.linkOrder = 0;\n      sim.regulator = 0;\n    },\n    get cutoff() {\n      return spec.maxCut * Math.abs(sim.link) ** spec.gearShape;\n    },\n    get rev() {\n      return sim.rev;\n    },\n    get crank() {\n      return sim.crank;\n    },\n    get mep() {\n      const chest = pressureFor(sim.temperature) * sim.regulator;\n      return Math.max(0, chest - spec.back) * expansionRatio(plant.cutoff);\n    },\n    get torque() {\n      return sim.torque;\n    },\n    get onCentre() {\n      return (\n        Math.abs(sim.rev) < CREEP &&\n        sim.regulator > 0.05 &&\n        Math.abs(sim.link) > 0.05 &&\n        pressureFor(sim.temperature) > spec.back &&\n        Math.abs(sim.torque) < spec.friction * 0.5\n      );\n    },\n    barOver() {\n      sim.crank = (sim.crank + Math.PI / 2) % TAU;\n      sim.rev += CREEP * 2 * Math.sign(sim.link || 1);\n    },\n    linkFor(seconds: number) {\n      const dir = sim.link < 0 ? -1 : 1;\n      // Monotone: a longer cut-off always empties her sooner, so bisect.\n      let lo = 0;\n      let hi = 1;\n      const holds = (g: number): boolean => {\n        const s = copy(sim);\n        s.linkOrder = dir * g;\n        s.link = dir * g;\n        const STEP = 30;\n        for (let t = 0; t < seconds; t += STEP) {\n          coarse(s, STEP);\n          if (pressureFor(s.temperature) < low) return false;\n        }\n        return true;\n      };\n      if (!holds(lo)) return 0;\n      for (let i = 0; i < 16; i++) {\n        const m = (lo + hi) / 2;\n        if (holds(m)) lo = m;\n        else hi = m;\n      }\n      return dir * lo;\n    },\n\n    get way() {\n      return sim.way;\n    },\n    get thrust() {\n      return sim.thrust;\n    },\n    walk,\n    setImmersion(fraction: number) {\n      sim.immersion = clamp01(fraction);\n    },\n    get immersion() {\n      return sim.immersion;\n    },\n\n    get blowing() {\n      return sim.blowing;\n    },\n    get turning() {\n      return Math.abs(sim.rev) >= CREEP;\n    },\n    get stepsPlumes() {\n      return stepsPlumes;\n    },\n    plumesInto(layer: SmokeLayer) {\n      layer.add(soot);\n      layer.add(grease);\n      // AND STOP STEPPING THEM. SmokeLayer.update already calls source.update\n      // on everything added; step them twice and the rate easing and the\n      // shader clock both run at 2× with nothing anywhere reporting it.\n      stepsPlumes = false;\n    },\n\n    update(dt: number) {\n      if (!(dt > 0)) return;\n      stepDoor(dt);\n      const n = Math.max(1, Math.min(64, Math.ceil(dt / INNER)));\n      const h = dt / n;\n      for (let i = 0; i < n; i++) fine(sim, h);\n      after(dt);\n    },\n    settle(seconds: number) {\n      if (!(seconds > 0)) return;\n      sim.doorShut = doorOrder > 0.5 ? 0 : 1;\n      advance(sim, seconds);\n      // Endpoints only — a fast-forward emits no intermediate states, and\n      // that is documented rather than pretended away.\n      after(Math.min(1, seconds));\n    },\n  };\n\n  let stepsPlumes = true;\n  let doorOrder = 0;\n\n  const stepDoor = (dt: number): void => {\n    const want = 1 - doorOrder;\n    sim.doorShut += (want - sim.doorShut) * Math.min(1, dt * 3.2);\n  };\n\n  /** Everything downstream of the integration: the visible parts, the plumes,\n   *  the gauge, the walk, and the state. */\n  const after = (dt: number): void => {\n    valveLift += ((sim.blowing ? 1 : 0) - valveLift) * Math.min(1, dt * 8);\n    place();\n\n    // THE FUNNEL READS THE FIRE AND NEVER THE BOILER. She makes her dirtiest\n    // smoke barely moving, because the damper is wide and no engine is taking\n    // anything from it — and nobody wrote that.\n    if (stepsPlumes) {\n      soot.setRate(clamp01(sim.firing * 0.85));\n      grease.setRate(clamp01(sim.green * sim.firing));\n      soot.update(dt);\n      grease.update(dt);\n    } else {\n      soot.setRate(clamp01(sim.firing * 0.85));\n      grease.setRate(clamp01(sim.green * sim.firing));\n    }\n    feather.setTarget(sim.blowing ? 1 : 0);\n    feather.update(dt);\n\n    gauge.setValue(pressureFor(sim.temperature));\n    gauge.update(dt);\n\n    // A right-handed single screw throws her stern to PORT going astern and\n    // barely at all going ahead — the asymmetry is the whole of it.\n    group.getWorldQuaternion(worldQ);\n    starboard.set(1, 0, 0).applyQuaternion(worldQ);\n    const astern = sim.rev < 0;\n    const amount =\n      spec.walk *\n      (astern ? -1 : 0.15) *\n      (Math.abs(sim.rev) / maxRev) *\n      sim.immersion *\n      Math.abs(sim.way > 0.2 ? 1 : 1.6);\n    walk.x = starboard.x * amount;\n    walk.z = starboard.z * amount;\n\n    const next = classify();\n    if (next !== state) {\n      state = next;\n      plant.onState?.(state);\n    }\n  };\n\n  return plant;\n}\n\n/**\n * Can the fireman see the fire?\n *\n * A ray from where he stands to the grate. It has to arrive without meeting\n * boiler plating on the way, which it only does if the firebox was built as\n * WALLS AROUND A VOID rather than as a solid drum with a door painted on it —\n * the failure that has already bitten half the containers in this library,\n * and that no test looking at numbers can catch.\n */\nexport function firesVisibleFrom(plant: SteamPlant): boolean {\n  plant.object.updateMatrixWorld(true);\n  const from = new Vector3();\n  plant.stokehold.anchor.getWorldPosition(from);\n  // From a standing fireman's eye, not from his boots — the door is a metre\n  // and a half up the firebox face.\n  from.y += 1.55;\n  const fire = plant.object.getObjectByName('firebox:fire');\n  if (!fire) return false;\n  const target = fire.getWorldPosition(new Vector3());\n  const dir = target.clone().sub(from);\n  if (dir.lengthSq() < 1e-8) return false;\n  dir.normalize();\n  const ray = new Raycaster(from, dir, 0.01, 40);\n  const hits = ray.intersectObject(plant.object, true);\n  for (const hit of hits) {\n    const mat = (hit.object as Mesh).material as MeshStandardMaterial;\n    if (mat && mat.emissive && mat.emissive.getHex() !== 0) return true;\n  }\n  return false;\n}\n","import {\n  BufferAttribute,\n  BufferGeometry,\n  BoxGeometry,\n  Color,\n  CylinderGeometry,\n  DoubleSide,\n  Group,\n  Mesh,\n  MeshStandardMaterial,\n  NormalBlending,\n  Object3D,\n  Points,\n  ShaderMaterial,\n  Vector3,\n} from 'three';\nimport { Rng } from '../core/random';\nimport { DEFAULT_PALETTE, type Palette } from '../core/palette';\nimport { createSurface } from '../materials/surface';\nimport type { HeatField } from './heat';\nimport { addApproach, createSlot, type Prop, type PropSlot } from '../core/types';\n\n/**\n * Smoke, and getting rid of it.\n *\n * This track exists because of one fact about the steam in `waterworks`:\n * it is drawn with **additive blending**, and its fragment shader writes\n * white. Additive can only ever *add* light. It is not that the steam is\n * the wrong colour for smoke — it is that no choice of colour or opacity in\n * an additive pass can produce something that makes the wall behind it\n * darker, and a plume that brightens what it covers is steam whatever you\n * call it. Smoke needs its own material, and that is the whole reason this\n * is a file rather than a parameter.\n *\n * The second thing smoke does that nothing else in the library does is\n * **stratify**. Heat is a field over a surface, cold is a field inside a\n * box, water is a depth — smoke is a **layer that fills a room from the\n * ceiling down**, so the reading depends on how high up you ask:\n *\n * ```ts\n * smokeAt(x, y, z): number   // 0–1, and y is the interesting argument\n * ```\n *\n * Thick at the ceiling long before it is anything at head height, which is\n * why extractors are mounted high, why you crawl, and why an alarm on the\n * ceiling goes off before anybody in the room notices.\n *\n * ```ts\n * const room = createSmokeLayer({ width: 5, depth: 4, height: 2.6 });\n * room.add(createSmoke({ style: 'grease' }));\n * room.vent(createExtractor({ era: 'hood' }));\n * game.onUpdate((t) => room.update(t.delta));\n * room.smokeAt(cook.x, 1.6, cook.z);   // can he still see?\n * ```\n */\n\nexport type SmokeStyle =\n  /** Pale wood smoke, from a hearth. */\n  | 'wood'\n  /** Grey soot — a stove that needs its damper opening. */\n  | 'soot'\n  /** Near-black grease smoke. A pan that has caught. */\n  | 'grease'\n  /** Thin blue haze — something scorching, not yet burning. */\n  | 'scorch';\n\n/**\n * How thick the smoke is at a point, in **world** coordinates.\n *\n * The fourth spatial handshake, after `depthAt`, `heatAt` and `chillAt`, and\n * the first one where **y is the interesting argument**. The others are\n * about where you are standing; this one is about how tall you are.\n */\nexport interface SmokeField {\n  /** 0 (clear) to 1 (solid) at a world point. 0 anywhere outside the room. */\n  smokeAt(x: number, y: number, z: number): number;\n}\n\nexport interface SmokeOptions {\n  style?: SmokeStyle;\n  /** How high the plume climbs before it joins the layer. Default 1.4. */\n  height?: number;\n  /** Radius at the base. Default 0.16. */\n  radius?: number;\n  /** Puffs. Default 18. */\n  count?: number;\n  /** m³ of smoke a second at full rate. Default per style. */\n  output?: number;\n  seed?: number;\n}\n\nexport interface SmokeSource extends Prop {\n  style: SmokeStyle;\n  /** How hard it is smoking, 0–1. Eases toward the target. */\n  readonly rate: number;\n  setRate(rate: number): void;\n  /** What it is putting into the room right now, m³/s. */\n  readonly output: number;\n  update(dt: number): void;\n}\n\ninterface StyleSpec {\n  colour: number;\n  /** Peak opacity of a single puff. */\n  opacity: number;\n  output: number;\n  /** How fast it climbs. */\n  lift: number;\n}\n\nconst STYLES: Record<SmokeStyle, StyleSpec> = {\n  wood: { colour: 0x9a948c, opacity: 0.26, output: 0.35, lift: 1.0 },\n  soot: { colour: 0x5c5854, opacity: 0.36, output: 0.6, lift: 0.85 },\n  grease: { colour: 0x24211e, opacity: 0.5, output: 1.1, lift: 0.7 },\n  scorch: { colour: 0x8f96a4, opacity: 0.17, output: 0.18, lift: 1.25 },\n};\n\nconst SMOKE_VERT = /* glsl */ `\nattribute float aPhase;\nattribute float aSpeed;\nattribute float aRad;\nattribute float aAng;\nuniform float uTime;\nuniform float uHeight;\nuniform float uRadius;\nuniform float uSize;\nvarying float vLife;\nvoid main() {\n  float life = fract(uTime * aSpeed + aPhase);\n  vLife = life;\n  // Smoke accelerates AWAY from the source and then slows, unlike steam,\n  // which drifts. The curl term is bigger too — it churns.\n  float rise = pow(life, 0.72);\n  // Grows, but not into a fog bank. The first version spread to nearly half\n  // a metre and every plume read as a smudge on the wall rather than as\n  // something rising off a pan.\n  float rad = aRad * uRadius * (0.3 + rise * 1.45);\n  float curl = life * 2.6 + aPhase * 6.283;\n  vec3 p = vec3(cos(aAng + curl) * rad, rise * uHeight, sin(aAng + curl) * rad);\n  vec4 mv = modelViewMatrix * vec4(p, 1.0);\n  gl_PointSize = uSize * (1.0 + life * 2.6) * (240.0 / -mv.z);\n  gl_Position = projectionMatrix * mv;\n}`;\n\n/**\n * The fragment stage, and the point of the whole file.\n *\n * It writes the smoke's **own colour**, not white, and the material is\n * `NormalBlending` — so the puff composites toward that colour and the wall\n * behind it gets darker. Under `AdditiveBlending` this exact shader would\n * still brighten the wall, because additive adds; a black puff would simply\n * be invisible and a grey one would be a grey glow.\n */\nconst SMOKE_FRAG = /* glsl */ `\nuniform float uDensity;\nuniform vec3 uColour;\nuniform float uOpacity;\nvarying float vLife;\nvoid main() {\n  float d = length(gl_PointCoord - 0.5);\n  if (d > 0.5) discard;\n  // Fades in fast and out slowly: smoke thins as it spreads rather than\n  // stopping.\n  float fade = min(1.0, vLife * 6.0) * (1.0 - vLife) * (1.0 - vLife);\n  gl_FragColor = vec4(uColour, (1.0 - d * 2.0) * fade * uOpacity * uDensity);\n}`;\n\n/** A plume. */\nexport function createSmoke(options: SmokeOptions = {}): SmokeSource {\n  const style = options.style ?? 'soot';\n  const spec = STYLES[style];\n  const rng = new Rng(options.seed ?? 1);\n  const count = options.count ?? 18;\n  const radius = options.radius ?? 0.16;\n  const height = options.height ?? 1.4;\n  const full = options.output ?? spec.output;\n\n  const pos = new Float32Array(count * 3);\n  const aPhase = new Float32Array(count);\n  const aSpeed = new Float32Array(count);\n  const aRad = new Float32Array(count);\n  const aAng = new Float32Array(count);\n  for (let i = 0; i < count; i++) {\n    aPhase[i] = rng.next();\n    aSpeed[i] = rng.range(0.14, 0.3) * spec.lift;\n    aRad[i] = rng.range(0.15, 1);\n    aAng[i] = rng.range(0, Math.PI * 2);\n  }\n  const geometry = new BufferGeometry();\n  geometry.setAttribute('position', new BufferAttribute(pos, 3));\n  geometry.setAttribute('aPhase', new BufferAttribute(aPhase, 1));\n  geometry.setAttribute('aSpeed', new BufferAttribute(aSpeed, 1));\n  geometry.setAttribute('aRad', new BufferAttribute(aRad, 1));\n  geometry.setAttribute('aAng', new BufferAttribute(aAng, 1));\n\n  const uniforms = {\n    uTime: { value: 0 },\n    uHeight: { value: height },\n    uRadius: { value: radius },\n    uSize: { value: 1.5 },\n    uDensity: { value: 0 },\n    uColour: { value: new Color(spec.colour) },\n    uOpacity: { value: spec.opacity },\n  };\n  const material = new ShaderMaterial({\n    uniforms,\n    vertexShader: SMOKE_VERT,\n    fragmentShader: SMOKE_FRAG,\n    transparent: true,\n    depthWrite: false,\n    // NOT AdditiveBlending. See the note on the fragment shader — this one\n    // line is the difference between smoke and steam.\n    blending: NormalBlending,\n  });\n  const mesh = new Points(geometry, material);\n  mesh.frustumCulled = false;\n\n  const group = new Group();\n  group.name = `smoke-${style}`;\n  group.add(mesh);\n\n  let rate = 0;\n  let target = 0;\n\n  const api: SmokeSource = {\n    object: group,\n    obstacleRadius: 0,\n    style,\n    get rate() {\n      return rate;\n    },\n    get output() {\n      return full * rate;\n    },\n    setRate(v: number) {\n      target = Math.max(0, Math.min(1, v));\n    },\n    update(dt: number) {\n      if (dt <= 0) return;\n      // Builds fast and dies slowly. A fire that stops smoking the instant\n      // you close the damper is a switch.\n      const speed = target > rate ? 1.4 : 0.35;\n      rate += (target - rate) * Math.min(1, dt * speed);\n      uniforms.uTime.value += dt;\n      uniforms.uDensity.value = rate;\n      group.visible = rate > 0.004;\n    },\n  };\n  return api;\n}\n\n// ------------------------------------------------------------- extraction\n\nexport type ExtractorEra =\n  /** A hole in the roof with a louvre over it. Only helps what is under it. */\n  | 'hole'\n  /** A masonry flue. Its draw depends on how hot the fire below it is. */\n  | 'chimney'\n  /** A canopy hood with a fan, over a hob. Its filter clogs. */\n  | 'hood'\n  /** A slot that rises out of the worktop and pulls sideways. */\n  | 'downdraft';\n\n/** The fan — structurally a `Manipulable`, like every switch in the library. */\nexport interface ExtractorFan {\n  readonly state: number;\n  readonly open: boolean;\n  toggle(): boolean;\n  set(target: number | boolean): void;\n  update(dt: number): void;\n  onChange?: (open: boolean) => void;\n  object: Object3D;\n}\n\nexport interface Extractor extends Prop {\n  era: ExtractorEra;\n  /**\n   * The opening — where it actually catches, and what you stand the pan\n   * under.\n   *\n   * Published for the same reason the stove publishes `zones` and the prep\n   * bench publishes `work`: the prop's origin is on its front face, and a\n   * caller measuring from there is measuring from the one point beneath a\n   * canopy that a fire never is. Nobody should have to guess.\n   */\n  mouth: Object3D;\n  /**\n   * How much of a plume at a world point it intercepts **before the smoke\n   * ever reaches the room**, 0–1.\n   *\n   * The half of extraction that matters. A hood over the hob catches the pan\n   * that has caught fire; the same hood does nothing at all about a pan on\n   * the other side of the kitchen, however hard the fan runs.\n   */\n  catches(x: number, z: number): number;\n  /** What it clears from the room's standing layer, m³/s, right now. */\n  readonly draw: number;\n  /** Demand, 0–1. Fixed at 1 on the eras with no controls. */\n  readonly power: number;\n  setPower(level: number | boolean): void;\n  fan: ExtractorFan | null;\n  /** Grease in the filter, 0 (clean) to 1 (blocked). It chokes the draw. */\n  readonly clogged: number;\n  clean(): void;\n  slot: PropSlot;\n  /**\n   * Advance it. Pass the heat below it: a **cold flue does not draw**, which\n   * is why a fire smokes into the room when you first light it.\n   */\n  update(dt: number, heat?: HeatField | number): void;\n}\n\ninterface EraSpec {\n  /** Peak share of a plume caught, directly underneath. */\n  capture: number;\n  /** How far that reaches, in metres. */\n  reach: number;\n  /** m³/s cleared from the standing layer at full power. */\n  draw: number;\n  /** Does its performance depend on the fire being hot? */\n  thermal: boolean;\n  hasFan: boolean;\n  /** Filter blocking per second while running. */\n  clogRate: number;\n  width: number;\n  depth: number;\n  /** Height of the mouth above the floor. */\n  mouth: number;\n}\n\n/**\n * The era table.\n *\n * `reach` is the column that decides everything. A smoke hole has a huge\n * capture directly beneath it and a reach of half a metre, so a medieval\n * hall is smoky **everywhere except under the hole** — you do not move the\n * hole, you move the fire. A hood has a smaller peak and four times the\n * reach, which is what a kitchen you can stand in actually needs.\n */\nconst ERAS: Record<ExtractorEra, EraSpec> = {\n  hole: {\n    capture: 0.55, reach: 0.55, draw: 0.015, thermal: true, hasFan: false,\n    clogRate: 0, width: 0.9, depth: 0.9, mouth: 2.6,\n  },\n  chimney: {\n    capture: 0.88, reach: 0.75, draw: 0.05, thermal: true, hasFan: false,\n    clogRate: 0, width: 1.3, depth: 0.8, mouth: 1.55,\n  },\n  hood: {\n    capture: 0.82, reach: 1.05, draw: 0.18, thermal: false, hasFan: true,\n    clogRate: 0.004, width: 0.9, depth: 0.52, mouth: 1.5,\n  },\n  downdraft: {\n    capture: 0.9, reach: 0.42, draw: 0.12, thermal: false, hasFan: true,\n    clogRate: 0.006, width: 0.78, depth: 0.1, mouth: 1.05,\n  },\n};\n\n/**\n * A note on the `draw` column, which was wrong by a factor of five.\n *\n * The first table gave a hood 0.9 m³/s of room-scavenging — more than a\n * smoking pan produces — so the extractor cleared the room no matter where\n * the pan was standing, and the entire distinction the track is built on\n * quietly stopped existing. Every test about capture still passed, because\n * they tested `catches` directly.\n *\n * Scavenging a standing layer through one small opening is SLOW. Catching a\n * plume that is rising straight into that opening is fast. Keeping the\n * second number much larger than the first is the only reason it matters\n * that the hood is over the hob.\n */\n\nexport interface ExtractorOptions {\n  era?: ExtractorEra;\n  seed?: number;\n  palette?: Palette;\n}\n\nconst clamp01 = (t: number): number => (t < 0 ? 0 : t > 1 ? 1 : t);\nconst smooth = (t: number): number => t * t * (3 - 2 * t);\n\nfunction makeFan(blades: Group, speed = 2.5): ExtractorFan {\n  let target = 0;\n  let state = 0;\n  const api: ExtractorFan = {\n    object: blades,\n    get state() {\n      return state;\n    },\n    get open() {\n      return target > 0.5;\n    },\n    toggle() {\n      const next = !(target > 0.5);\n      api.set(next);\n      return next;\n    },\n    set(value: number | boolean) {\n      const was = target > 0.5;\n      target = typeof value === 'boolean' ? (value ? 1 : 0) : clamp01(value);\n      if (was !== target > 0.5) api.onChange?.(target > 0.5);\n    },\n    update(dt: number) {\n      state += (target - state) * Math.min(1, dt * speed);\n      // A fan you cannot see turning is a fan that is off. Blades that\n      // spin about their own axis are invisible on a symmetric disc, so\n      // there is an odd number of them and one is marked.\n      blades.rotation.y += dt * state * 22;\n    },\n  };\n  return api;\n}\n\n/** A smoke hole, flue, hood or downdraft vent. */\nexport function createExtractor(options: ExtractorOptions = {}): Extractor {\n  const era = options.era ?? 'hood';\n  const spec = ERAS[era];\n  const seed = options.seed ?? 1;\n  const rng = new Rng(seed);\n  void rng;\n  const palette = options.palette ?? DEFAULT_PALETTE;\n\n  const group = new Group();\n  group.name = `extract-${era}`;\n\n  const W = spec.width;\n  const D = spec.depth;\n  const M = spec.mouth;\n\n  const shell =\n    era === 'hole'\n      ? createSurface('plank', { seed, color: palette.woodDark })\n      : era === 'chimney'\n        ? createSurface('plaster', { seed, color: 0xd8d0c0 })\n        : createSurface('steel', { seed, metalness: 0.42, roughness: 0.34 });\n  const dark = new MeshStandardMaterial({ color: 0x33383c, roughness: 0.6, metalness: 0.4 });\n\n  let fan: ExtractorFan | null = null;\n  let filterMat: MeshStandardMaterial | null = null;\n\n  if (era === 'hole') {\n    // A louvred lantern over an opening: four posts and a little cap, with\n    // the opening left OPEN. A solid cap over a solid ceiling is a box.\n    for (const [sx, sz] of [[-1, -1], [1, -1], [-1, 1], [1, 1]] as Array<[number, number]>) {\n      const post = new Mesh(new BoxGeometry(0.06, 0.42, 0.06), shell);\n      post.position.set((sx * W) / 2, M + 0.21, -D / 2 + (sz * D) / 2);\n      group.add(post);\n    }\n    for (const s of [-1, 1]) {\n      const slope = new Mesh(new BoxGeometry(W + 0.24, 0.05, D * 0.72), shell);\n      slope.position.set(0, M + 0.5, -D / 2 + s * D * 0.3);\n      slope.rotation.x = s * 0.42;\n      group.add(slope);\n    }\n    const kerb = new Mesh(new BoxGeometry(W + 0.1, 0.05, D + 0.1), shell);\n    kerb.position.set(0, M, -D / 2);\n    group.add(kerb);\n  } else if (era === 'chimney') {\n    // A tapering canopy over a hearth. Walls, not a wedge — you stand under\n    // it and look up the flue.\n    for (const s of [-1, 1]) {\n      const cheek = new Mesh(new BoxGeometry(0.06, 0.65, D), shell);\n      cheek.position.set((s * W) / 2, M + 0.32, -D / 2);\n      cheek.rotation.z = -s * 0.34;\n      group.add(cheek);\n    }\n    const hoodBack = new Mesh(new BoxGeometry(W, 0.7, 0.06), shell);\n    hoodBack.position.set(0, M + 0.35, -D + 0.03);\n    group.add(hoodBack);\n    const front = new Mesh(new BoxGeometry(W * 0.98, 0.68, 0.05), shell);\n    front.position.set(0, M + 0.34, 0);\n    front.rotation.x = -0.3;\n    group.add(front);\n    const flue = new Mesh(new CylinderGeometry(0.22, 0.3, 1.0, 8, 1, true), shell);\n    flue.material.side = DoubleSide;\n    flue.position.set(0, M + 1.15, -D / 2);\n    group.add(flue);\n    const lintel = new Mesh(new BoxGeometry(W + 0.14, 0.12, D + 0.08), shell);\n    lintel.position.set(0, M - 0.05, -D / 2);\n    group.add(lintel);\n  } else if (era === 'hood') {\n    const canopy = new Mesh(new BoxGeometry(W, 0.12, D), shell);\n    canopy.position.set(0, M + 0.06, -D / 2);\n    group.add(canopy);\n    for (const s of [-1, 1]) {\n      const skirt = new Mesh(new BoxGeometry(0.03, 0.16, D), shell);\n      skirt.position.set((s * W) / 2, M - 0.05, -D / 2);\n      skirt.rotation.z = s * 0.22;\n      group.add(skirt);\n    }\n    const chase = new Mesh(new BoxGeometry(W * 0.32, 0.65, D * 0.5), shell);\n    chase.position.set(0, M + 0.45, -D * 0.7);\n    group.add(chase);\n    // The filter, and its colour IS the clog reading — nothing else about a\n    // blocked extractor is visible at all.\n    filterMat = new MeshStandardMaterial({ color: 0xc4cad0, roughness: 0.5, metalness: 0.5 });\n    const filter = new Mesh(new BoxGeometry(W * 0.82, 0.014, D * 0.72), filterMat);\n    filter.position.set(0, M - 0.005, -D / 2);\n    group.add(filter);\n    const blades = new Group();\n    blades.position.set(0, M + 0.09, -D / 2);\n    group.add(blades);\n    for (let i = 0; i < 5; i++) {\n      const blade = new Mesh(new BoxGeometry(0.16, 0.006, 0.05), dark);\n      blade.position.set(Math.cos((i / 5) * Math.PI * 2) * 0.09, 0, Math.sin((i / 5) * Math.PI * 2) * 0.09);\n      blade.rotation.y = (i / 5) * Math.PI * 2;\n      blade.rotation.z = 0.35;\n      if (i === 0) blade.material = new MeshStandardMaterial({ color: 0x8a5a2a, roughness: 0.6 });\n      blades.add(blade);\n    }\n    fan = makeFan(blades);\n  } else {\n    // A slot that RISES out of the worktop. It is a Manipulable and its\n    // whole read is that it is up.\n    const riser = new Group();\n    riser.position.set(0, M - 0.06, -D / 2);\n    group.add(riser);\n    const panel = new Mesh(new BoxGeometry(W, 0.42, 0.05), shell);\n    panel.position.y = 0.21;\n    riser.add(panel);\n    filterMat = new MeshStandardMaterial({ color: 0xb8bfc6, roughness: 0.5, metalness: 0.55 });\n    const grille = new Mesh(new BoxGeometry(W * 0.86, 0.3, 0.012), filterMat);\n    grille.position.set(0, 0.21, 0.032);\n    riser.add(grille);\n    const slot = new Mesh(new BoxGeometry(W + 0.05, 0.05, D + 0.06), dark);\n    slot.position.set(0, M - 0.06, -D / 2);\n    group.add(slot);\n    let state = 0;\n    let target = 0;\n    const api: ExtractorFan = {\n      object: riser,\n      get state() {\n        return state;\n      },\n      get open() {\n        return target > 0.5;\n      },\n      toggle() {\n        const next = !(target > 0.5);\n        api.set(next);\n        return next;\n      },\n      set(value: number | boolean) {\n        const was = target > 0.5;\n        target = typeof value === 'boolean' ? (value ? 1 : 0) : clamp01(value);\n        if (was !== target > 0.5) api.onChange?.(target > 0.5);\n      },\n      update(dt: number) {\n        state += (target - state) * Math.min(1, dt * 2.2);\n        riser.position.y = M - 0.06 + smooth(state) * 0.4;\n        riser.visible = state > 0.01;\n      },\n    };\n    fan = api;\n  }\n\n  const mouth = new Object3D();\n  mouth.name = 'mouth';\n  mouth.position.set(0, M, -D / 2);\n  group.add(mouth);\n\n  const standAt = createSlot('vent', 'work', group, 0, 0, 0.6, Math.PI);\n  addApproach(standAt, group, 0.5, 'behind');\n\n  // ---- state -------------------------------------------------------------\n  let power = spec.hasFan ? 0 : 1;\n  let clogged = 0;\n  let heatNow = 1;\n  const probe = new Vector3();\n  const world = new Vector3();\n\n  /**\n   * How well it is working right now, 0–1.\n   *\n   * Three multiplied terms, and each one is a different way for an\n   * extractor to be useless: switched off, blocked, or — on the eras with\n   * no fan — attached to a fire that has not got going yet.\n   */\n  const efficiency = (): number => {\n    const running = spec.hasFan ? (fan ? Math.max(power, fan.state) : power) : 1;\n    const flow = 1 - clogged * 0.85;\n    const lift = spec.thermal ? 0.22 + heatNow * 0.78 : 1;\n    return clamp01(running * flow * lift);\n  };\n\n  const api: Extractor = {\n    object: group,\n    // You stand under a hood and a smoke hole; a chimney breast is masonry.\n    obstacleRadius: era === 'chimney' ? W * 0.4 : 0,\n    era,\n    fan,\n    mouth,\n    slot: standAt,\n    slots: [standAt],\n    get power() {\n      return spec.hasFan ? power : 1;\n    },\n    get clogged() {\n      return clogged;\n    },\n    get draw() {\n      return spec.draw * efficiency();\n    },\n    setPower(level: number | boolean) {\n      const v = typeof level === 'boolean' ? (level ? 1 : 0) : clamp01(level);\n      // A no-op where there is nothing to switch, and that IS the era axis:\n      // the same call runs a hood and does nothing to a hole in the roof.\n      if (!spec.hasFan) return;\n      power = v;\n      fan?.set(v);\n    },\n    clean() {\n      clogged = 0;\n    },\n    catches(x: number, z: number) {\n      group.updateWorldMatrix(true, false);\n      world.set(0, 0, -D / 2);\n      group.localToWorld(world);\n      const d = Math.hypot(world.x - x, world.z - z);\n      if (d > spec.reach) return 0;\n      // Falls off toward the edge rather than stopping at it, so moving the\n      // pan under the hood actually does something.\n      return spec.capture * (1 - (d / spec.reach) ** 2) * efficiency();\n    },\n    update(dt: number, heat?: HeatField | number) {\n      if (dt <= 0) return;\n      fan?.update(dt);\n      if (typeof heat === 'number') heatNow = clamp01(heat);\n      else if (heat) {\n        // Under the MOUTH, not at the origin. The origin is on the front\n        // face, which is the one place beneath a canopy that a fire never\n        // is — sampling there reads 0 for a hearth roaring half a metre\n        // behind it, and the flue never learns the fire is lit.\n        group.updateWorldMatrix(true, false);\n        probe.set(0, 0, -D / 2);\n        group.localToWorld(probe);\n        heatNow = clamp01(heat.heatAt(probe.x, probe.z));\n      } else if (spec.thermal) {\n        // Nothing told us about the fire. Assume there is one — a flue with\n        // no `heat` argument should work, not silently stop drawing.\n        heatNow = 1;\n      }\n      if (spec.clogRate > 0) {\n        clogged = clamp01(clogged + dt * spec.clogRate * (spec.hasFan ? Math.max(power, 0.1) : 1));\n      }\n      if (filterMat) {\n        // Clean steel through to black grease.\n        const t = clogged;\n        filterMat.color.setRGB(0.77 - t * 0.62, 0.79 - t * 0.66, 0.82 - t * 0.7);\n        filterMat.roughness = 0.5 + t * 0.45;\n        filterMat.metalness = 0.5 - t * 0.42;\n      }\n    },\n  };\n  return api;\n}\n\n// ------------------------------------------------------------- the layer\n\nexport interface SmokeLayerOptions {\n  /** Room footprint, metres. */\n  width?: number;\n  depth?: number;\n  /** Floor to ceiling. Default 2.6. */\n  height?: number;\n  /**\n   * How thick the layer has to get at `alarmY` before the alarm sounds.\n   * Default 0.35. 0 disables it.\n   */\n  alarmAt?: number;\n  /** Where the alarm is listening, metres above the floor. Default 2.3. */\n  alarmY?: number;\n  /** How fast it leaks out through doors and gaps, per second. Default 0.02. */\n  leak?: number;\n  seed?: number;\n  palette?: Palette;\n}\n\nexport interface SmokeLayer extends Prop, SmokeField {\n  /** How much is in the room, 0 (clear) to 1 (solid). */\n  readonly level: number;\n  /** How far the layer has come DOWN from the ceiling, in metres. */\n  readonly descent: number;\n  /** World Y of the underside of the layer. Everything above it is in it. */\n  readonly baseY: number;\n  /** Sources feeding it. */\n  add(source: SmokeSource): void;\n  /** Extractors fighting it. */\n  vent(extractor: Extractor): void;\n  /** Clear the room — throw the windows open. */\n  clear(): void;\n  smokeAt(x: number, y: number, z: number): number;\n  /** Fires once when it gets thick at `alarmY`; re-arms once it clears. */\n  onAlarm?: (sounding: boolean) => void;\n  update(dt: number): void;\n}\n\n/**\n * The room's standing smoke.\n *\n * A source puts smoke in, an extractor takes it out, and this is the thing\n * they argue over. The origin is on the floor at the centre of the\n * footprint — a room, not a prop, so it is placed like a rug.\n */\nexport function createSmokeLayer(options: SmokeLayerOptions = {}): SmokeLayer {\n  const W = options.width ?? 5;\n  const D = options.depth ?? 4;\n  const H = options.height ?? 2.6;\n  const alarmAt = options.alarmAt ?? 0.35;\n  const alarmY = options.alarmY ?? 2.3;\n  const leak = options.leak ?? 0.02;\n\n  const group = new Group();\n  group.name = 'smoke-layer';\n\n  /**\n   * The visible layer: ONE box with a vertical alpha gradient, scaled to\n   * span from the ceiling down to the underside.\n   *\n   * The first version was a stack of seven thin sheets, on the theory that\n   * lower ones fading in later would give the underside a soft edge. Viewed\n   * from across the room it was seven hard edges instead of one — a set of\n   * horizontal stripes, which is the shelf problem seven times over rather\n   * than a fix for it. A gradient in the shader is one draw call and has no\n   * edges to be hard.\n   */\n  const layerMat = new MeshStandardMaterial({\n    color: 0x3c3a37,\n    roughness: 1,\n    transparent: true,\n    opacity: 0,\n    depthWrite: false,\n    side: DoubleSide,\n  });\n  layerMat.onBeforeCompile = (shader) => {\n    shader.vertexShader = shader.vertexShader\n      .replace('#include <common>', '#include <common>\\nvarying float vSmokeY;')\n      .replace(\n        '#include <begin_vertex>',\n        '#include <begin_vertex>\\n  vSmokeY = position.y + 0.5;'\n      );\n    shader.fragmentShader = shader.fragmentShader\n      .replace('#include <common>', '#include <common>\\nvarying float vSmokeY;')\n      .replace(\n        '#include <dithering_fragment>',\n        // Solid at the ceiling, gone at the underside. Squared, so the last\n        // stretch fades out rather than stopping.\n        '#include <dithering_fragment>\\n  float sm = smoothstep(0.0, 0.5, vSmokeY);\\n  gl_FragColor.a *= sm * sm;'\n      );\n  };\n  layerMat.customProgramCacheKey = () => 'scenaSmokeLayer';\n  const slab = new Mesh(new BoxGeometry(W * 0.995, 1, D * 0.995), layerMat);\n  slab.renderOrder = 3;\n  slab.visible = false;\n  group.add(slab);\n\n  const sources: SmokeSource[] = [];\n  const vents: Extractor[] = [];\n  let smoke = 0;\n  let sounding = false;\n  const local = new Vector3();\n\n  const volume = W * D * H;\n\n  const api: SmokeLayer = {\n    object: group,\n    obstacleRadius: 0,\n    add(source: SmokeSource) {\n      sources.push(source);\n    },\n    vent(extractor: Extractor) {\n      vents.push(extractor);\n    },\n    clear() {\n      smoke = 0;\n    },\n    get level() {\n      return clamp01(smoke / volume);\n    },\n    get descent() {\n      // Descends FIRST and thickens after. A layer whose thickness and\n      // density are the same number can only ever be one reading, and the\n      // whole point of smoke is that it reaches your head before it fills\n      // the room.\n      return Math.min(H, clamp01((smoke / volume) * 1.6) * H);\n    },\n    get baseY() {\n      return group.position.y + H - api.descent;\n    },\n    smokeAt(x: number, y: number, z: number) {\n      if (smoke <= 0) return 0;\n      group.updateWorldMatrix(true, false);\n      local.set(x, y, z);\n      group.worldToLocal(local);\n      if (Math.abs(local.x) > W / 2 || Math.abs(local.z) > D / 2) return 0;\n      if (local.y > H + 0.2 || local.y < -0.1) return 0;\n      const base = H - api.descent;\n      const strength = clamp01(smoke / volume);\n      if (local.y >= base) {\n        // Inside the layer: densest at the ceiling, softening toward the\n        // underside so there is no hard line to walk through.\n        const up = api.descent <= 1e-4 ? 1 : clamp01((local.y - base) / Math.max(0.25, api.descent));\n        return strength * (0.35 + 0.65 * up);\n      }\n      // Below it. Real smoke is not perfectly stratified — a little hangs\n      // about, and more of it the fuller the room is.\n      return strength * strength * 0.18;\n    },\n    update(dt: number) {\n      if (dt <= 0) return;\n\n      for (const source of sources) {\n        source.update(dt);\n        if (source.output <= 0) continue;\n        source.object.updateWorldMatrix(true, false);\n        const at = source.object.getWorldPosition(new Vector3());\n        // How much of THIS plume is caught before it ever reaches the room.\n        // Several extractors do not stack past 1 — two hoods over one pan\n        // cannot catch 160% of it.\n        let caught = 0;\n        for (const vent of vents) caught = Math.max(caught, vent.catches(at.x, at.z));\n        smoke += source.output * (1 - clamp01(caught)) * dt;\n      }\n\n      // …and what the extractors scavenge from the standing layer, which is\n      // a different job from catching a plume and is why they are two\n      // numbers. A hood clears a smoky room slowly; it catches the pan\n      // under it almost completely.\n      let pulled = 0;\n      for (const vent of vents) pulled += vent.draw;\n      smoke = Math.max(0, smoke - pulled * dt - smoke * leak * dt);\n\n      // ---- reads --------------------------------------------------------\n      const descent = api.descent;\n      const strength = clamp01(smoke / volume);\n      const thickness = Math.max(0.02, descent);\n      slab.scale.set(1, thickness, 1);\n      slab.position.set(0, H - thickness / 2, 0);\n      layerMat.opacity = Math.min(0.72, strength * 1.15);\n      slab.visible = layerMat.opacity > 0.005;\n\n      if (alarmAt > 0) {\n        const head = api.smokeAt(group.position.x, group.position.y + alarmY, group.position.z);\n        if (!sounding && head > alarmAt) {\n          sounding = true;\n          api.onAlarm?.(true);\n        } else if (sounding && head < alarmAt * 0.6) {\n          sounding = false;\n          api.onAlarm?.(false);\n        }\n      }\n    },\n  };\n  return api;\n}\n\nexport const SMOKE_STYLES: SmokeStyle[] = ['wood', 'soot', 'grease', 'scorch'];\nexport const EXTRACTOR_ERAS: ExtractorEra[] = ['hole', 'chimney', 'hood', 'downdraft'];\n","import {\n  BoxGeometry,\n  CylinderGeometry,\n  Group,\n  Mesh,\n  MeshStandardMaterial,\n  Object3D,\n  TorusGeometry,\n} from 'three';\nimport { DEFAULT_PALETTE, type Palette } from '../core/palette';\nimport { createSurface } from '../materials/surface';\nimport type { Prop } from '../core/types';\n\n/**\n * A pressure gauge — the first instrument in SCENA.\n *\n * Everything else in this library is a thing. This is a thing that *tells you\n * about* another thing, and the difference shows up in two places.\n *\n * The first is that a gauge is a **readout, not a Manipulable**. It has no\n * `open` and no `toggle`, because you cannot operate a gauge — you can only\n * read it. Its one input is a number and its one output is where the needle\n * happens to be, which lags behind because a real Bourdon tube has a spring\n * and a linkage in it.\n *\n * The second is subtler and it is the whole reason this is its own file. A\n * dial with a full ring of marks on it is a **clock**, and no amount of\n * captioning it \"boiler pressure\" will stop a viewer reading it as one. What\n * makes a disc read as an instrument is the **270° sweep with a dead zone at\n * the bottom** — the needle goes round most of the way and then stops, which\n * a clock never does — plus a red band at each end for the two numbers that\n * matter, and a needle that is off-centre, asymmetric and the wrong colour\n * for a clock hand.\n *\n * ```ts\n * const gauge = createPressureGauge({ max: 16, redline: 13.2, lowMark: 5 });\n * pipe.add(gauge.object);\n * game.onUpdate((t) => {\n *   gauge.setValue(plant.pressure);\n *   gauge.update(t.delta);\n * });\n * ```\n *\n * It faces **+z with its origin at the mounting face**, the fixtures/wallArt\n * convention, so the caller rotates it onto whatever it is standing on.\n */\nexport interface PressureGauge extends Prop {\n  /** Where the needle IS, in bar. Eases toward `target`. */\n  readonly value: number;\n  /** Where it has been told to go. */\n  readonly target: number;\n  setValue(bar: number): void;\n  /** Past the upper red band. Lights the pip beside the dial. */\n  readonly overRange: boolean;\n  /** Below the lower red arc — she has not enough to work with. */\n  readonly low: boolean;\n  update(dt: number): void;\n}\n\nexport interface PressureGaugeOptions {\n  /** Dial radius. Default 0.16. */\n  radius?: number;\n  /** Full scale, bar. Default 16. */\n  max?: number;\n  /** Where the upper red band starts. Default 0.82 × max. */\n  redline?: number;\n  /** Where the lower red arc ends. Default 0.25 × max. */\n  lowMark?: number;\n  /** Numbered marks around the sweep. Default 11. */\n  ticks?: number;\n  /** Starting reading. Default 0. */\n  value?: number;\n  seed?: number;\n  palette?: Palette;\n}\n\n/** Where the needle starts and how far round it goes: 270°, gap at the bottom. */\nconst SWEEP_FROM = -0.75 * Math.PI;\nconst SWEEP = 1.5 * Math.PI;\n\nconst clamp01 = (t: number): number => (t < 0 ? 0 : t > 1 ? 1 : t);\n\nexport function createPressureGauge(options: PressureGaugeOptions = {}): PressureGauge {\n  const r = options.radius ?? 0.16;\n  const max = Math.max(0.1, options.max ?? 16);\n  const redline = options.redline ?? max * 0.82;\n  const lowMark = options.lowMark ?? max * 0.25;\n  const ticks = Math.max(2, Math.round(options.ticks ?? 11));\n  const seed = options.seed ?? 1;\n  const palette = options.palette ?? DEFAULT_PALETTE;\n  void palette;\n\n  const group = new Group();\n  group.name = 'gauge';\n\n  const brass = createSurface('brass', { seed });\n  const dark = new MeshStandardMaterial({ color: 0x24272b, roughness: 0.7 });\n  const red = new MeshStandardMaterial({ color: 0xc0392b, roughness: 0.6 });\n\n  // Case: a ring standing off the mounting face, so the dial is a recess and\n  // not a sticker. Depth first, everything else stacked forward of it.\n  const bezel = new Mesh(new CylinderGeometry(r, r * 1.04, 0.042, 24, 1, true), brass);\n  bezel.rotation.x = Math.PI / 2;\n  bezel.position.z = 0.021;\n  group.add(bezel);\n  const back = new Mesh(new CylinderGeometry(r * 1.04, r * 1.04, 0.008, 24), brass);\n  back.rotation.x = Math.PI / 2;\n  group.add(back);\n\n  const face = new Mesh(\n    new CylinderGeometry(r * 0.96, r * 0.96, 0.004, 24),\n    new MeshStandardMaterial({ color: 0xe8e3d6, roughness: 0.85 })\n  );\n  face.rotation.x = Math.PI / 2;\n  face.position.z = 0.034;\n  group.add(face);\n\n  // The marks. A clock's hour loop with the full circle swapped for the\n  // 270° sweep — the arc IS the instrument, and closing it makes a clock.\n  for (let i = 0; i < ticks; i++) {\n    const major = i % 2 === 0;\n    const len = major ? r * 0.17 : r * 0.09;\n    const mark = new Mesh(new BoxGeometry(major ? 0.005 : 0.003, len, 0.002), dark);\n    const a = SWEEP_FROM + (i / (ticks - 1)) * SWEEP;\n    const at = r * 0.8 - len / 2;\n    mark.position.set(Math.sin(a) * at, Math.cos(a) * at, 0.0365);\n    mark.rotation.z = -a;\n    group.add(mark);\n  }\n\n  // Two red bands: one from the bottom of the scale up to `lowMark`, one from\n  // `redline` to full. TorusGeometry's arc runs anticlockwise from +x, so a\n  // band is placed by rotating its start onto the sweep.\n  const band = (from: number, to: number): void => {\n    const a0 = SWEEP_FROM + clamp01(from / max) * SWEEP;\n    const a1 = SWEEP_FROM + clamp01(to / max) * SWEEP;\n    const arc = Math.abs(a1 - a0);\n    if (arc < 1e-3) return;\n    const ring = new Mesh(new TorusGeometry(r * 0.86, 0.004, 4, 16, arc), red);\n    // The dial's zero is +y and it runs clockwise; the torus starts at +x and\n    // runs anticlockwise. Mirror in x, then bring the start onto a0.\n    ring.scale.x = -1;\n    ring.rotation.z = Math.PI / 2 + a0;\n    ring.position.z = 0.0365;\n    group.add(ring);\n  };\n  band(0, lowMark);\n  band(redline, max);\n\n  // The needle. Pivoted near its tail so the counterweight end shows, built\n  // pointing +y so a negative rotation.z sweeps clockwise, and red — the\n  // clock's *second* hand colour, which is the one nobody uses for the time.\n  const pivot = new Object3D();\n  pivot.position.z = 0.038;\n  const needleLen = r * 0.84;\n  const needle = new Mesh(new BoxGeometry(0.006, needleLen, 0.003), red);\n  // Named, so a test can find the needle by identity rather than by colour —\n  // the red bands on the rim are the same red and they never move.\n  needle.name = 'gauge:needle';\n  needle.position.y = needleLen / 2 - needleLen * 0.14;\n  pivot.add(needle);\n  group.add(pivot);\n  const boss = new Mesh(new CylinderGeometry(0.009, 0.009, 0.005, 12), dark);\n  boss.rotation.x = Math.PI / 2;\n  boss.position.z = 0.0405;\n  group.add(boss);\n\n  // The over-range pip, beside the dial rather than on it: an instrument that\n  // changes colour is a warning light, and a warning light is a separate lamp.\n  const pipMat = new MeshStandardMaterial({\n    color: 0x5a2018,\n    emissive: 0xc0392b,\n    emissiveIntensity: 0,\n    roughness: 0.5,\n  });\n  const pip = new Mesh(new CylinderGeometry(0.018, 0.018, 0.012, 12), pipMat);\n  pip.rotation.x = Math.PI / 2;\n  pip.position.set(0, -r * 1.22, 0.012);\n  group.add(pip);\n\n  let value = clamp01((options.value ?? 0) / max) * max;\n  let target = value;\n\n  const place = (): void => {\n    pivot.rotation.z = -(SWEEP_FROM + clamp01(value / max) * SWEEP);\n    pipMat.emissiveIntensity = value >= redline ? 1.4 : 0;\n  };\n  place();\n\n  return {\n    object: group,\n    // A dial on a bulkhead is not something you steer around.\n    obstacleRadius: 0,\n    get value() {\n      return value;\n    },\n    get target() {\n      return target;\n    },\n    setValue(bar: number) {\n      target = Number.isFinite(bar) ? bar : 0;\n    },\n    get overRange() {\n      return value >= redline;\n    },\n    get low() {\n      return value <= lowMark;\n    },\n    update(dt: number) {\n      if (dt <= 0) return;\n      // A Bourdon tube has a spring and a linkage in it, so the needle\n      // asymptotes rather than arriving. Exponential, and never tested for\n      // equality anywhere.\n      value += (target - value) * Math.min(1, dt * 6);\n      place();\n    },\n  };\n}\n","import {\n  BoxGeometry,\n  Group,\n  Mesh,\n  MeshStandardMaterial,\n  Object3D,\n  PlaneGeometry,\n  Vector3,\n} from 'three';\nimport { Rng } from '../core/random';\nimport { DEFAULT_PALETTE, type Palette } from '../core/palette';\nimport { createSurface } from '../materials/surface';\nimport { createSlot, addApproach, type Prop, type PropSlot } from '../core/types';\n\n/**\n * Below decks — and the first thing in this library where **where** you put\n * something changes what the whole object does.\n *\n * Everything else here that has a mass has it at its origin. A hold does not.\n * Put fifty tonnes in the fore hold and she goes down by the head; put it to\n * starboard and she lists; put it aboard at all and she sits deeper and her\n * propeller bites harder. The load is a position, not a number.\n *\n * ```ts\n * const hold = createHold({ kind: 'steamer' });\n * ship.object.add(hold.object);\n *\n * hold.load('fore', 300);\n * game.onUpdate((t) => {\n *   hold.update(t.delta);\n *   ship.update(t.delta, { speed: plant.way, loading: hold.loading });\n *   plant.setImmersion(hold.immersion);\n * });\n * ```\n *\n * ## The weight is not the problem. The fact that it can move is.\n *\n * A hold **full** of water is safer than a hold **half full** of it, and the\n * reason has nothing whatever to do with how much water there is. A liquid\n * with a free surface runs to the low side as she leans, and the weight goes\n * with it — so her centre of gravity effectively rises, and she leans further.\n * The size of that virtual rise depends on the **width of the surface cubed**\n * and not at all on the depth of the liquid:\n *\n * ```ts\n * hold.pump('ballast', 1.0);   // pressed full — no surface, no problem\n * hold.pump('ballast', 0.5);   // slack — and this is the dangerous one\n * hold.pump('ballast', 0.0);   // empty — safe again, and now she is light\n * ```\n *\n * So `pump` is a verb that can kill her in either direction, and the right\n * answer is almost never \"some\". It is why tankers are loaded full or in\n * ballast and rarely between, and why a slack tank is a thing officers count.\n *\n * ## And an empty ship is not a safe ship\n *\n * Light, she floats high, her metacentric height is enormous, and she snaps\n * back from every roll hard enough to throw people off their feet and start\n * cargo moving. That is what ballast is *for* — you take weight aboard on\n * purpose, low down, to make her worse at standing up. `'light'` is a state\n * this module warns about, not a state it treats as empty and fine.\n */\nexport type HoldKind = 'carrack' | 'steamer' | 'liner' | 'tanker';\n\n/**\n * The era axis is **what you can do about it.**\n *\n * A carrack has one open hold and no pumps: your only lever is to move the\n * cargo, by hand, and a cargo that shifts on its own in a seaway is how ships\n * were lost. A steamer has separate holds and a double bottom you can pump —\n * one wide tank, so slack it is a menace. A liner subdivides everything,\n * which makes each free surface small and is the whole reason she is a place\n * people are willing to sleep. A tanker's cargo **is** the free surface, and\n * she is only ever safe pressed up or empty.\n */\nexport const HOLD_KINDS: HoldKind[] = ['carrack', 'steamer', 'liner', 'tanker'];\n\n/** rest / transitioning-toward / at-target / drifting-back, on the GM axis. */\nexport type TrimState = 'light' | 'laden' | 'tender' | 'lost';\n\n/**\n * One space below decks.\n *\n * `slack` is the whole module in one boolean: a liquid compartment that is\n * neither empty nor pressed up.\n */\nexport interface Compartment {\n  name: string;\n  /** Centre, fore-and-aft, in vessel metres. Positive is forward. */\n  z: number;\n  /** Centre athwartships. Positive is to starboard. */\n  x: number;\n  length: number;\n  width: number;\n  depth: number;\n  /** Height of its floor below the waterline, m. */\n  floor: number;\n  /** Does it hold liquid? Only liquids have a free surface. */\n  liquid: boolean;\n  /** Tonnes it will take. */\n  capacity: number;\n  /** Tonnes in it now. */\n  readonly load: number;\n  /** How full, 0–1. */\n  readonly level: number;\n  /** Liquid, and neither empty nor pressed up. */\n  readonly slack: boolean;\n  /** Its own free-surface moment, tonne·m⁴ — `width³ × length / 12`, and it\n   *  does not depend on how much is in it. */\n  readonly surfaceMoment: number;\n  /** Where its contents actually sit across it, in metres from its own\n   *  centreline. Cargo stowed to one side is the commonest way a ship gets\n   *  a list, and it is nobody's decision — it is a mistake. */\n  readonly offset: number;\n}\n\n/**\n * What the hull takes from a load.\n *\n * The same shape as `ShipInput.drift` and passed the same way — but it is the\n * first thing in that channel that is a **state of the vessel** rather than a\n * force on her. A drift stops when the tide slackens. A list does not stop.\n */\nexport interface Loading {\n  /** Radians of bow-down pitch. Positive is down by the head. */\n  trim: number;\n  /** Radians of list. Positive is to starboard. */\n  list: number;\n  /** Extra metres she is sitting down in the water. */\n  sink: number;\n  /** Multiplier on how fast she answers the sea. A stiff ship SNAPS. */\n  stiffness: number;\n}\n\nexport interface Hold extends Prop {\n  kind: HoldKind;\n  compartments: Compartment[];\n  /** By name, because `compartments[2]` is not a thing anybody says. */\n  at(name: string): Compartment | undefined;\n\n  /**\n   * Put weight in. Returns the tonnes that would not fit.\n   *\n   * `side` is where it goes ACROSS the compartment, −1 hard to port through 0\n   * on the centreline to +1 hard to starboard. It is the whole reason a ship\n   * with her cargo correctly distributed fore and aft can still be lying over\n   * at ten degrees, and there is no total tonnage that says so.\n   */\n  load(name: string, tonnes: number, side?: number): number;\n  /** Take it out. Returns the tonnes that actually came. */\n  unload(name: string, tonnes: number): number;\n  /** Move it — the only lever a carrack has, and the slow one. */\n  shift(from: string, to: string, tonnes: number): number;\n  /**\n   * Pump a liquid compartment toward a fraction of its depth.\n   *\n   * DANGEROUS IN BOTH DIRECTIONS. Emptying a pressed-up tank takes her\n   * through slack on the way, and slack is where the free surface is.\n   */\n  pump(name: string, to: number): void;\n  /** Water where it should not be — and it has the widest surface aboard. */\n  readonly bilge: number;\n  /** Start her making water, tonnes/s. */\n  holed(rate: number): void;\n  /** Suction on the bilge. Slower than the sea, which is the point. */\n  pumpBilge(on: boolean): void;\n  readonly pumping: boolean;\n\n  // ── what it does to her ──────────────────────────────────────────────\n  /** Tonnes aboard, cargo and ballast and bilge. */\n  readonly deadweight: number;\n  /** Tonnes of hull and everything in her. */\n  readonly displacement: number;\n  /** How deep she floats, m. */\n  readonly draught: number;\n  /** Metres of side left above the sea. */\n  readonly freeboard: number;\n  /** How much of the screw is in the water, 0–1. Straight into\n   *  `SteamPlant.setImmersion`. */\n  readonly immersion: number;\n  /** Metacentric height WITH the free-surface correction applied, m. THE\n   *  number: it is what decides everything else here. */\n  readonly gm: number;\n  /** What she would have if nothing aboard could move. `gm` is this minus\n   *  `freeSurface`, and the difference is the module. */\n  readonly solidGm: number;\n  /** Virtual rise in her centre of gravity from every slack surface, m. */\n  readonly freeSurface: number;\n  /** Seconds for one complete roll. Short is STIFF and violent; long is\n   *  tender and she hangs at the end of each one. */\n  readonly rollPeriod: number;\n  /** Loaded to her marks: 0 light, 1 down to the load line, >1 overloaded. */\n  readonly toMarks: number;\n  readonly state: TrimState;\n  onState?: (state: TrimState) => void;\n  /** She has taken an angle of loll and is lying there. A boolean BESIDE the\n   *  state, because a ship lolling is still `'lost'` by the same measure. */\n  readonly lolling: boolean;\n  /**\n   * Hang an EXTERNAL heeling moment on her, tonne·metres, positive to\n   * starboard. Named, so several can be live at once and each updated on its\n   * own; pass 0 to take one off.\n   *\n   * A working boat is heeled by her gear rather than by her cargo, and the\n   * wire is not aboard her — but the arithmetic is identical the moment it\n   * reaches her deck, and so is the angle past which she does not come back.\n   * Everything that capsizes a badly stowed ship capsizes a tug girted by her\n   * own tow, through this.\n   */\n  heel(name: string, tonneMetres: number): void;\n  /** Past the angle of vanishing stability — over, and not coming back. */\n  readonly capsized: boolean;\n  /** Her angle of vanishing stability, radians. Published so a caller can\n   *  say how close she is rather than only that she has gone. */\n  readonly vanishing: number;\n\n  /** Hand this straight to `ShipInput.loading`. Mutated in place. */\n  readonly loading: Loading;\n  hatch: PropSlot;\n  slots: PropSlot[];\n  update(dt: number): void;\n}\n\nexport interface HoldOptions {\n  kind?: HoldKind;\n  /** Override the vessel's dimensions, if the hold is going into something\n   *  other than the hull its kind is sized for. */\n  length?: number;\n  beam?: number;\n  /** Tonnes of hull, engines and everything that is not cargo. */\n  lightship?: number;\n  /**\n   * How deep the HULL she is going into is drawn, m — `DeckedShip.draft`.\n   *\n   * `sink` is measured from this, because it is the datum the hull mesh was\n   * built to. Leave it out and the hold measures from its own load line\n   * instead: a ship loaded exactly to her marks is then lifted clear of the\n   * water by the difference between the two, a light one is lifted almost\n   * out of it altogether, and there is no number anywhere that says so.\n   *\n   * ```ts\n   * createHold({ kind: 'steamer', draft: ship.draft });\n   * ```\n   */\n  draft?: number;\n  /** Start her loaded. Names not in the kind are ignored. */\n  cargo?: Record<string, number>;\n  seed?: number;\n  palette?: Palette;\n}\n\n/** Sea water. Everything here is in tonnes and metres. */\nconst RHO = 1.025;\nconst G = 9.81;\n\nconst clamp01 = (t: number): number => (t < 0 ? 0 : t > 1 ? 1 : t);\n\ninterface Space {\n  name: string;\n  z: number;\n  x: number;\n  length: number;\n  width: number;\n  depth: number;\n  floor: number;\n  liquid: boolean;\n  capacity: number;\n}\n\ninterface KindSpec {\n  length: number;\n  beam: number;\n  depth: number;\n  /** Tonnes of her, empty. */\n  lightship: number;\n  /** Height of her light centre of gravity above the keel, m. */\n  lightKg: number;\n  /** Waterplane coefficient — how boxy her waterline is. */\n  cw: number;\n  /** Block coefficient — how boxy she is underwater. */\n  cb: number;\n  /** Radius of gyration as a fraction of the beam. Sets the roll period. */\n  gyration: number;\n  /** Draught she is designed to float at, loaded to her marks. */\n  marks: number;\n  /** How much GM she wants. Below `tender` she lolls about; above `stiff` she\n   *  snaps back hard enough to hurt people. NEITHER END IS SAFE. */\n  tender: number;\n  stiff: number;\n  /** Depth of the screw below the waterline at her marks. */\n  screw: number;\n  /**\n   * Angle of vanishing stability, radians — past which she has no righting\n   * arm left and does not come back. It is not a clamp for tidiness: it is\n   * the end of the curve, and a ship taken past it is over.\n   */\n  vanishing: number;\n  /** Tonnes a minute the cargo gang can move by hand. */\n  shiftRate: number;\n  /** Tonnes a second the ballast pumps will do. */\n  pumpRate: number;\n  /** Tonnes a second the bilge pump will do. */\n  bilgeRate: number;\n  spaces: Space[];\n}\n\nconst KINDS: Record<HoldKind, KindSpec> = {\n  carrack: {\n    length: 26, beam: 8, depth: 3.6, lightship: 120, lightKg: 2.2,\n    cw: 0.78, cb: 0.55, gyration: 0.38, marks: 2.4,\n    tender: 0.5, stiff: 3.4, vanishing: 0.78, screw: 0, shiftRate: 0.9, pumpRate: 0, bilgeRate: 0.008,\n    // ONE SPACE, AND NO PUMPS. Your only lever is to move it, by hand, at\n    // under a tonne a minute — which is why a cargo that shifted on its own\n    // in a seaway was usually the end of the argument.\n    spaces: [{ name: 'hold', z: 0, x: 0, length: 15, width: 6, depth: 2.6, floor: 1.6, liquid: false, capacity: 170 }],\n  },\n  steamer: {\n    length: 58, beam: 9.5, depth: 6.0, lightship: 480, lightKg: 2.9,\n    cw: 0.84, cb: 0.68, gyration: 0.37, marks: 3.6,\n    tender: 0.4, stiff: 2.6, vanishing: 0.72, screw: 2.2, shiftRate: 2.5, pumpRate: 0.32, bilgeRate: 0.05,\n    // Three holds and ONE wide double-bottom tank. The tank is the invention\n    // — you can change how she floats without touching the cargo — and it is\n    // also the widest free surface she has, so half of it is a menace.\n    spaces: [\n      { name: 'fore', z: 16, x: 0, length: 14, width: 8, depth: 4.5, floor: 2.5, liquid: false, capacity: 300 },\n      { name: 'main', z: 0, x: 0, length: 16, width: 8.6, depth: 4.5, floor: 2.5, liquid: false, capacity: 380 },\n      { name: 'aft', z: -17, x: 0, length: 12, width: 7.4, depth: 4.5, floor: 2.5, liquid: false, capacity: 220 },\n      { name: 'ballast', z: 0, x: 0, length: 30, width: 8.8, depth: 0.9, floor: 3.4, liquid: true, capacity: 260 },\n    ],\n  },\n  liner: {\n    length: 180, beam: 24, depth: 18, lightship: 15600, lightKg: 11.2,\n    cw: 0.8, cb: 0.62, gyration: 0.36, marks: 9.0,\n    tender: 0.5, stiff: 2.2, vanishing: 0.66, screw: 6.0, shiftRate: 6, pumpRate: 2.2, bilgeRate: 0.4,\n    // SUBDIVIDED, and that is the whole point of her. Six narrow tanks in\n    // place of one wide one cut the free surface by the square of the number\n    // — because the moment goes as the WIDTH CUBED — which is why a liner is\n    // somewhere people are willing to go to sleep.\n    spaces: [\n      { name: 'fore', z: 56, x: 0, length: 30, width: 18, depth: 11, floor: 6.0, liquid: false, capacity: 2600 },\n      { name: 'main', z: 10, x: 0, length: 52, width: 22, depth: 11, floor: 6.0, liquid: false, capacity: 4600 },\n      { name: 'aft', z: -50, x: 0, length: 30, width: 18, depth: 11, floor: 6.0, liquid: false, capacity: 2400 },\n      { name: 'ballastP1', z: 34, x: -8, length: 40, width: 5.4, depth: 2.6, floor: 8.6, liquid: true, capacity: 700 },\n      { name: 'ballastS1', z: 34, x: 8, length: 40, width: 5.4, depth: 2.6, floor: 8.6, liquid: true, capacity: 700 },\n      { name: 'ballastP2', z: -34, x: -8, length: 40, width: 5.4, depth: 2.6, floor: 8.6, liquid: true, capacity: 700 },\n      { name: 'ballastS2', z: -34, x: 8, length: 40, width: 5.4, depth: 2.6, floor: 8.6, liquid: true, capacity: 700 },\n    ],\n  },\n  tanker: {\n    length: 150, beam: 22, depth: 14, lightship: 5200, lightKg: 7.0,\n    cw: 0.9, cb: 0.82, gyration: 0.38, marks: 8.4,\n    tender: 0.7, stiff: 3.4, vanishing: 0.6, screw: 5.5, shiftRate: 0, pumpRate: 3.4, bilgeRate: 0.3,\n    // THE CARGO IS THE FREE SURFACE. Three tanks the full width of her, and\n    // she is only ever safe pressed up or empty — anywhere between and the\n    // whole cargo runs to leeward with her.\n    spaces: [\n      { name: 'no1', z: 42, x: 0, length: 34, width: 20, depth: 12, floor: 6.4, liquid: true, capacity: 6200 },\n      { name: 'no2', z: 0, x: 0, length: 38, width: 21, depth: 12, floor: 6.4, liquid: true, capacity: 7300 },\n      { name: 'no3', z: -42, x: 0, length: 34, width: 20, depth: 12, floor: 6.4, liquid: true, capacity: 6200 },\n    ],\n  },\n};\n\ninterface Cell extends Space {\n  load: number;\n  /** Where the pumps are taking it, for liquids. */\n  order: number;\n  /** Mean position of the contents across the compartment, metres. */\n  offset: number;\n}\n\nexport function createHold(options: HoldOptions = {}): Hold {\n  const kind = options.kind ?? 'steamer';\n  const base = KINDS[kind];\n  const spec: KindSpec = {\n    ...base,\n    length: options.length ?? base.length,\n    beam: options.beam ?? base.beam,\n    lightship: options.lightship ?? base.lightship,\n  };\n  // The datum her sinkage is measured from. Defaults to her own marks so a\n  // hold on its own is self-consistent; pass the hull's if she is going into\n  // one, because that is the depth the mesh was drawn to.\n  const drawnDraft = options.draft ?? base.marks;\n  const seed = options.seed ?? 1;\n  const rng = new Rng(seed);\n  const palette = options.palette ?? DEFAULT_PALETTE;\n\n  const L = spec.length;\n  const B = spec.beam;\n\n  const cells: Cell[] = spec.spaces.map((s) => ({\n    ...s,\n    load: clamp01((options.cargo?.[s.name] ?? 0) / Math.max(1, s.capacity)) * s.capacity,\n    order: s.liquid ? clamp01((options.cargo?.[s.name] ?? 0) / Math.max(1, s.capacity)) : 0,\n    offset: 0,\n  }));\n  // The bilge is a compartment too, and it is the WORST one she has: the full\n  // width of her, no subdivision, and it fills itself.\n  const bilgeCell: Cell = {\n    name: 'bilge',\n    z: 0, x: 0,\n    length: L * 0.62,\n    width: B * 0.9,\n    depth: 0.9,\n    floor: spec.marks - 0.1,\n    liquid: true,\n    capacity: RHO * L * 0.62 * B * 0.9 * 0.9,\n    load: 0,\n    order: 0,\n    offset: 0,\n  };\n\n  let leak = 0;\n  let pumping = false;\n  const loading: Loading = { trim: 0, list: 0, sink: 0, stiffness: 1 };\n\n  // ── geometry ─────────────────────────────────────────────────────────\n\n  const group = new Group();\n  group.name = `hold:${kind}`;\n\n  const steel = createSurface('steel', { color: 0x53585e, seed });\n  const timber = createSurface('plank', { color: palette.woodDark, seed: seed + 1 });\n  const structure = kind === 'carrack' ? timber : steel;\n  const cargoMats = [\n    createSurface('plank', { color: palette.wood, seed: seed + 2 }),\n    createSurface('canvas', { color: 0xa89a7c, seed: seed + 3 }),\n    createSurface('leather', { color: 0x6d5843, seed: seed + 4 }),\n  ];\n  const waterMat = new MeshStandardMaterial({\n    color: 0x2f5f74,\n    transparent: true,\n    opacity: 0.72,\n    roughness: 0.25,\n    metalness: 0.1,\n  });\n  const oilMat = new MeshStandardMaterial({\n    color: 0x14100c,\n    transparent: true,\n    opacity: 0.9,\n    roughness: 0.45,\n  });\n\n  interface Built {\n    cell: Cell;\n    /** The liquid's own surface — a pivot the plane hangs under. */\n    surface: Object3D | null;\n    /** Stacks of cargo whose visible count follows the load. */\n    stacks: Object3D[];\n  }\n  const built: Built[] = [];\n\n  /**\n   * A COMPARTMENT IS A HOLE. Four walls and a floor, built as slabs around a\n   * void — never a solid box with cargo parented inside it, which renders as\n   * a filled crate whether it is loaded or empty and passes every test in\n   * this file because no test looks into it.\n   */\n  const boxOut = (c: Cell, parent: Group): void => {\n    const t = Math.min(0.16, c.width * 0.03);\n    const y0 = -c.floor;\n    const wall = (w: number, h: number, d: number, x: number, y: number, z: number): void => {\n      const m = new Mesh(new BoxGeometry(w, h, d), structure);\n      m.position.set(x, y, z);\n      parent.add(m);\n    };\n    wall(c.width, t, c.length, c.x, y0, c.z);\n    wall(t, c.depth, c.length, c.x - c.width / 2, y0 + c.depth / 2, c.z);\n    wall(t, c.depth, c.length, c.x + c.width / 2, y0 + c.depth / 2, c.z);\n    wall(c.width, c.depth, t, c.x, y0 + c.depth / 2, c.z - c.length / 2);\n    wall(c.width, c.depth, t, c.x, y0 + c.depth / 2, c.z + c.length / 2);\n  };\n\n  for (const c of cells) {\n    const sub = new Group();\n    sub.name = `compartment:${c.name}`;\n    group.add(sub);\n    boxOut(c, sub);\n\n    let surface: Object3D | null = null;\n    const stacks: Object3D[] = [];\n    if (c.liquid) {\n      // THE READ, and it needs its own pivot. Laying a plane flat costs a\n      // rotation.x of -90°, and stacking the vessel's attitude on top of that\n      // in the same Euler composes in an order nobody can reason about — the\n      // surface ends up tilting about the wrong axis by a plausible amount.\n      // Pivot rotates; plane inside it only ever lies flat.\n      const pivot = new Object3D();\n      pivot.name = `surface:${c.name}`;\n      pivot.position.set(c.x, -c.floor, c.z);\n      const sheet = new Mesh(\n        new PlaneGeometry(c.width * 0.97, c.length * 0.98),\n        kind === 'tanker' ? oilMat : waterMat\n      );\n      sheet.rotation.x = -Math.PI / 2;\n      pivot.add(sheet);\n      sub.add(pivot);\n      surface = pivot;\n    } else {\n      // Cargo in courses in a group of its own, so a hold stowed to one side\n      // can be MOVED to one side — a list nobody can see is a list somebody\n      // will decide is a bug in the model.\n      const stackGroup = new Group();\n      stackGroup.name = `stow:${c.name}`;\n      sub.add(stackGroup);\n      // Cargo in courses, so a half-loaded hold is visibly half loaded.\n      const across = Math.max(2, Math.round(c.width / 1.7));\n      const along = Math.max(3, Math.round(c.length / 1.9));\n      const tiers = Math.max(2, Math.round(c.depth / 1.3));\n      const bw = (c.width * 0.88) / across;\n      const bl = (c.length * 0.92) / along;\n      const bh = (c.depth * 0.86) / tiers;\n      for (let ti = 0; ti < tiers; ti++) {\n        for (let ai = 0; ai < along; ai++) {\n          for (let xi = 0; xi < across; xi++) {\n            const m = new Mesh(\n              new BoxGeometry(bw * 0.92, bh * 0.9, bl * 0.92),\n              cargoMats[Math.floor(rng.next() * cargoMats.length)]\n            );\n            m.position.set(\n              c.x + (xi - (across - 1) / 2) * bw,\n              -c.floor + bh / 2 + ti * bh,\n              c.z + (ai - (along - 1) / 2) * bl\n            );\n            m.rotation.y = (rng.next() - 0.5) * 0.09;\n            m.visible = false;\n            stackGroup.add(m);\n            stacks.push(m);\n          }\n        }\n      }\n      // Bottom tier first, so she loads from the floor up rather than a\n      // random scatter appearing in mid-air.\n      stacks.sort((a, b) => a.position.y - b.position.y);\n    }\n    built.push({ cell: c, surface, stacks });\n  }\n\n  // The bilge: one plane, the full width of her, under everything.\n  const bilgeSurface = new Object3D();\n  bilgeSurface.name = 'surface:bilge';\n  bilgeSurface.position.set(0, -bilgeCell.floor, 0);\n  bilgeSurface.visible = false;\n  const bilgeSheet = new Mesh(\n    new PlaneGeometry(bilgeCell.width, bilgeCell.length),\n    new MeshStandardMaterial({\n      color: 0x1d2a2b,\n      transparent: true,\n      opacity: 0.8,\n      roughness: 0.2,\n    })\n  );\n  bilgeSheet.rotation.x = -Math.PI / 2;\n  bilgeSurface.add(bilgeSheet);\n  group.add(bilgeSurface);\n\n  /**\n   * The load line, painted on her side.\n   *\n   * An instrument with no moving parts: the marks stay where they are and the\n   * SEA comes up them. Nothing else in SCENA reads out by not moving.\n   */\n  const marks = new Group();\n  marks.name = 'loadline';\n  const markMat = new MeshStandardMaterial({ color: 0xf2f2ee, roughness: 0.8 });\n  const disc = new Mesh(new BoxGeometry(0.06, 0.5, 0.5), markMat);\n  disc.position.set(B / 2 + 0.03, 0, 0);\n  marks.add(disc);\n  const bar = new Mesh(new BoxGeometry(0.06, 0.09, 1.5), markMat);\n  bar.position.set(B / 2 + 0.03, 0, 0);\n  marks.add(bar);\n  for (let i = 0; i < 5; i++) {\n    const step = new Mesh(new BoxGeometry(0.06, 0.07, 0.42), markMat);\n    step.position.set(B / 2 + 0.03, (i - 2) * 0.26, 1.1);\n    marks.add(step);\n  }\n  group.add(marks);\n\n  const hatch = addApproach(\n    createSlot('hatch', 'work', group, 0, 0.1, cells[0].z + cells[0].length / 2 + 1.1, Math.PI),\n    group,\n    0.9,\n    'front'\n  );\n\n  // ── the model ────────────────────────────────────────────────────────\n\n  const at = (name: string): Cell | undefined =>\n    name === 'bilge' ? bilgeCell : cells.find((c) => c.name === name);\n\n  const allCells = (): Cell[] => [...cells, bilgeCell];\n\n  /** Tonnes aboard that are not the ship herself. */\n  const deadweightOf = (): number => allCells().reduce((s, c) => s + c.load, 0);\n\n  /**\n   * Height of the whole vessel's centre of gravity above the keel.\n   *\n   * A compartment's `floor` is measured DOWN FROM THE WATERLINE, and the\n   * waterline at her marks is `spec.marks` above the keel — not `spec.depth`,\n   * which is the keel to the main deck. Using the depth puts every tonne\n   * aboard a whole freeboard higher than it is, and every ship in the table\n   * comes out tender for a reason that is arithmetic rather than loading.\n   */\n  const kgOf = (): number => {\n    let moment = spec.lightship * spec.lightKg;\n    let mass = spec.lightship;\n    for (const c of allCells()) {\n      if (c.load <= 0) continue;\n      const fill = clamp01(c.load / Math.max(1e-6, c.capacity));\n      const h = Math.max(0, spec.marks - c.floor) + (c.depth * fill) / 2;\n      moment += c.load * h;\n      mass += c.load;\n    }\n    return moment / Math.max(1e-6, mass);\n  };\n\n  /**\n   * THE FREE SURFACE. Sum of `width³ × length / 12` over every SLACK liquid\n   * compartment, divided by the displacement — a virtual rise in G that does\n   * not care how much liquid there is, only how wide it is free to slop.\n   *\n   * A pressed-up tank contributes nothing at all, and neither does an empty\n   * one. Half of it contributes exactly as much as nine tenths of it.\n   */\n  const freeSurfaceOf = (disp: number): number => {\n    let i = 0;\n    for (const c of allCells()) {\n      if (!c.liquid) continue;\n      const fill = c.load / Math.max(1e-6, c.capacity);\n      if (fill <= 0.005 || fill >= 0.995) continue;\n      i += (c.width ** 3 * c.length) / 12;\n    }\n    return (RHO * i) / Math.max(1e-6, disp);\n  };\n\n  let state: TrimState = 'laden';\n  let read = {\n    displacement: spec.lightship,\n    draught: 0,\n    gm: 0,\n    solidGm: 0,\n    freeSurface: 0,\n    rollPeriod: 0,\n  };\n\n  /** External heeling moments, t·m, by name — gear, a shifted deck cargo,\n   *  anything that pulls on her from outside the cargo model. */\n  const outside = new Map<string, number>();\n\n  const solve = (): void => {\n    const dw = deadweightOf();\n    const disp = spec.lightship + dw;\n\n    // How deep she floats. Volume over the waterplane, and the waterplane is\n    // what a change in load moves her through.\n    const draught = disp / (RHO * spec.cb * L * B);\n\n    // KB is roughly the centroid of the immersed body; BM is the waterplane's\n    // own moment of inertia over the volume, which is why a WIDE ship is a\n    // stable one and it goes as the beam SQUARED.\n    const kb = draught * 0.53;\n    const volume = disp / RHO;\n    const bm = (spec.cw * L * B ** 3) / 12 / Math.max(1e-6, volume);\n    const km = kb + bm;\n    const kg = kgOf();\n    const solidGm = km - kg;\n    const fs = freeSurfaceOf(disp);\n    const gm = solidGm - fs;\n\n    // Trim and list are moments about the centre, divided by how hard she\n    // resists being turned that way. Longitudinally that is enormous — a ship\n    // is long — which is why the same tonne moved athwartships does far more.\n    let mz = 0;\n    let mx = 0;\n    for (const c of allCells()) {\n      mz += c.load * c.z;\n      mx += c.load * (c.x + c.offset);\n    }\n    for (const m of outside.values()) mx += m;\n    const gml = L * 1.1;\n    loading.trim = Math.atan(mz / Math.max(1e-6, disp * gml));\n    // A negative GM does not give a negative list, it gives an ANGLE OF LOLL:\n    // she falls to one side and sits there, and the side she picks is\n    // whichever way she happened to be leaning.\n    if (gm > 0.02) {\n      // GZ = GM·sin θ, NOT GM·θ — and `atan` obligingly returns an answer all\n      // the way to ninety degrees, so a badly stowed ship comes out lying at\n      // forty-four degrees and steaming along quite happily. There is no\n      // equilibrium past the angle of vanishing stability: she is over.\n      const arg = mx / Math.max(1e-6, disp * gm);\n      const limit = Math.sin(spec.vanishing);\n      loading.list =\n        Math.abs(arg) >= limit\n          ? Math.sign(arg) * spec.vanishing\n          : Math.asin(arg);\n    } else {\n      const loll = Math.min(0.45, Math.sqrt(Math.max(0, -gm) / Math.max(0.2, bm)) * 1.6);\n      loading.list = (mx >= 0 ? 1 : -1) * loll;\n    }\n    loading.sink = draught - drawnDraft;\n    // A stiff ship snaps back. The hull's own easing is how fast she answers\n    // the sea, and this is the same claim from the other side.\n    // A ship with no positive stability does not roll about upright at all —\n    // she lies at her angle of loll. Clamping the square root gives a number\n    // like 118 seconds, which reads as \"very slow\" when the truth is \"never\".\n    const period = gm > 0.02 ? (2 * Math.PI * spec.gyration * B) / Math.sqrt(gm * G) : Infinity;\n    // Rises WITH the metacentric height. A stiff ship snaps back and a tender\n    // one wallows, so the multiplier that decides how fast she answers the sea\n    // has to go the same way GM does — written as `tender/gm` it goes the\n    // other way, and a light ship becomes the ponderous one.\n    loading.stiffness = 0.6 + clamp01(gm / spec.stiff) * 0.9;\n\n    read = {\n      displacement: disp,\n      draught,\n      gm,\n      solidGm,\n      freeSurface: fs,\n      rollPeriod: period,\n    };\n  };\n\n  const classify = (): TrimState => {\n    if (read.gm <= 0 || spec.depth - read.draught <= 0) return 'lost';\n    // Past the end of her righting-arm curve, with plenty of metacentric\n    // height and nothing whatever to use it on.\n    if (Math.abs(loading.list) >= spec.vanishing - 1e-6) return 'lost';\n    // Two-sided bands, so a ship sitting at the edge of tender does not\n    // chatter across it on the noise of her own pumps.\n    const enterTender = state === 'tender' ? spec.tender * 1.12 : spec.tender;\n    const enterLight = state === 'light' ? spec.stiff * 0.9 : spec.stiff;\n    if (read.gm < enterTender) return 'tender';\n    if (read.gm > enterLight) return 'light';\n    return 'laden';\n  };\n\n  const place = (): void => {\n    for (const b of built) {\n      const fill = clamp01(b.cell.load / Math.max(1e-6, b.cell.capacity));\n      if (b.surface) {\n        b.surface.visible = fill > 0.004;\n        b.surface.position.y = -b.cell.floor + b.cell.depth * fill;\n        // A LIQUID STAYS LEVEL AND THE SHIP DOES NOT. The hull is rotated by\n        // (−trim, −list); the surface takes (+trim, +list) inside it and comes\n        // out horizontal, sitting deeper against the low side of a tilted\n        // compartment — which is the whole module, visible.\n        //\n        // A tank pressed up against its deckhead CANNOT do that, so it does\n        // not, and a still frame tells you which tanks are the dangerous ones.\n        const free = fill > 0.005 && fill < 0.995;\n        b.surface.rotation.set(free ? -loading.trim : 0, 0, free ? loading.list : 0);\n      }\n      if (b.stacks.length) {\n        const want = Math.round(fill * b.stacks.length);\n        for (let i = 0; i < b.stacks.length; i++) b.stacks[i].visible = i < want;\n        const stow = b.stacks[0].parent;\n        if (stow) stow.position.x = b.cell.offset;\n      }\n    }\n    const bFill = clamp01(bilgeCell.load / bilgeCell.capacity);\n    bilgeSurface.visible = bFill > 0.004;\n    bilgeSurface.position.y = -bilgeCell.floor + bilgeCell.depth * bFill;\n    bilgeSurface.rotation.set(-loading.trim, 0, loading.list);\n    // The marks stay put and the sea comes up them: the group tracks the\n    // waterline, which in the hull's frame is y = 0 minus how far she sank.\n    marks.position.y = -loading.sink;\n  };\n\n  /**\n   * Re-derive, re-draw, and RE-CLASSIFY.\n   *\n   * The classifier lived only in `update` at first, so a ship loaded until\n   * her metacentric height went negative went on reporting `'light'` until\n   * somebody happened to step the frame. Loading her IS the event.\n   */\n  const settle = (): void => {\n    solve();\n    place();\n    const next = classify();\n    if (next !== state) {\n      state = next;\n      hold.onState?.(state);\n    }\n  };\n\n  solve();\n  state = classify();\n  place();\n\n  const view = (c: Cell): Compartment => ({\n    name: c.name,\n    z: c.z,\n    x: c.x,\n    length: c.length,\n    width: c.width,\n    depth: c.depth,\n    floor: c.floor,\n    liquid: c.liquid,\n    capacity: c.capacity,\n    get load() {\n      return c.load;\n    },\n    get level() {\n      return clamp01(c.load / Math.max(1e-6, c.capacity));\n    },\n    get slack() {\n      const f = c.load / Math.max(1e-6, c.capacity);\n      return c.liquid && f > 0.005 && f < 0.995;\n    },\n    get surfaceMoment() {\n      return (c.width ** 3 * c.length) / 12;\n    },\n    get offset() {\n      return c.offset;\n    },\n  });\n  const views = [...cells, bilgeCell].map(view);\n\n  /** Tonnes still being walked from one hold to another. */\n  let moving: { from: Cell; to: Cell; left: number } | null = null;\n  const hold: Hold = {\n    object: group,\n    // Below decks is not something you steer around from outside.\n    obstacleRadius: 0,\n    kind,\n    compartments: views,\n    at(name: string) {\n      return views.find((c) => c.name === name);\n    },\n    hatch,\n    slots: [hatch],\n    loading,\n\n    load(name: string, tonnes: number, side = 0) {\n      const c = at(name);\n      if (!c || !(tonnes > 0)) return tonnes > 0 ? tonnes : 0;\n      const room = Math.max(0, c.capacity - c.load);\n      const took = Math.min(room, tonnes);\n      // A liquid finds its own level and cannot be stowed to one side; solid\n      // cargo can, and stays where it was put.\n      if (!c.liquid && took > 0) {\n        const where = Math.max(-1, Math.min(1, side)) * (c.width / 2) * 0.8;\n        c.offset = (c.offset * c.load + where * took) / (c.load + took);\n      }\n      c.load += took;\n      if (c.liquid) c.order = c.load / c.capacity;\n      settle();\n      return tonnes - took;\n    },\n    unload(name: string, tonnes: number) {\n      const c = at(name);\n      if (!c || !(tonnes > 0)) return 0;\n      const came = Math.min(c.load, tonnes);\n      c.load -= came;\n      if (c.liquid) c.order = c.load / c.capacity;\n      settle();\n      return came;\n    },\n    shift(from: string, to: string, tonnes: number) {\n      const a = at(from);\n      const b = at(to);\n      if (!a || !b || a === b || !(tonnes > 0)) return 0;\n      // A carrack has no pumps, so this is her only lever — and it takes\n      // hours, which is the whole difference between her and a steamer.\n      const can = Math.min(a.load, Math.max(0, b.capacity - b.load), tonnes);\n      if (can <= 0) return 0;\n      moving = { from: a, to: b, left: can };\n      return can;\n    },\n    pump(name: string, to: number) {\n      const c = at(name);\n      if (!c || !c.liquid) return;\n      c.order = clamp01(to);\n    },\n    get bilge() {\n      return bilgeCell.load;\n    },\n    holed(rate: number) {\n      leak = Math.max(0, rate);\n    },\n    pumpBilge(on: boolean) {\n      pumping = on;\n    },\n    get pumping() {\n      return pumping;\n    },\n\n    get deadweight() {\n      return deadweightOf();\n    },\n    get displacement() {\n      return read.displacement;\n    },\n    get draught() {\n      return read.draught;\n    },\n    get freeboard() {\n      return Math.max(0, spec.depth - read.draught);\n    },\n    get immersion() {\n      // The screw is a fixed depth below her marks; as she rises out of the\n      // water it comes with her, and a light ship races.\n      if (spec.screw <= 0) return 1;\n      const under = read.draught - (spec.marks - spec.screw);\n      return clamp01(under / Math.max(0.1, spec.screw));\n    },\n    get gm() {\n      return read.gm;\n    },\n    get solidGm() {\n      return read.solidGm;\n    },\n    get freeSurface() {\n      return read.freeSurface;\n    },\n    get rollPeriod() {\n      return read.rollPeriod;\n    },\n    get toMarks() {\n      return read.draught / spec.marks;\n    },\n    get state() {\n      return state;\n    },\n    get lolling() {\n      return read.gm <= 0.02 && Math.abs(loading.list) > 0.02;\n    },\n    heel(name: string, tonneMetres: number) {\n      if (!Number.isFinite(tonneMetres) || tonneMetres === 0) outside.delete(name);\n      else outside.set(name, tonneMetres);\n      settle();\n    },\n    get capsized() {\n      return Math.abs(loading.list) >= spec.vanishing - 1e-6;\n    },\n    vanishing: spec.vanishing,\n\n    update(dt: number) {\n      if (!(dt > 0)) return;\n\n      // The pumps: liquid compartments walk toward their order.\n      if (spec.pumpRate > 0) {\n        for (const c of cells) {\n          if (!c.liquid) continue;\n          const want = c.order * c.capacity;\n          const step = spec.pumpRate * dt;\n          const err = want - c.load;\n          c.load += Math.abs(err) <= step ? err : Math.sign(err) * step;\n        }\n      }\n\n      // The cargo gang, at under a tonne a minute on a carrack.\n      if (moving) {\n        const step = (spec.shiftRate / 60) * dt;\n        const took = Math.min(moving.left, step, moving.from.load);\n        const room = Math.max(0, moving.to.capacity - moving.to.load);\n        const put = Math.min(took, room);\n        moving.from.load -= put;\n        moving.to.load += put;\n        moving.left -= put;\n        if (moving.left <= 1e-6 || put <= 0) moving = null;\n      }\n\n      // The sea comes in faster than the pump takes it out. That is not a\n      // balance anybody tuned — it is why you go for the hole and not the\n      // handle.\n      if (leak > 0) bilgeCell.load = Math.min(bilgeCell.capacity, bilgeCell.load + leak * dt);\n      if (pumping && bilgeCell.load > 0) {\n        bilgeCell.load = Math.max(0, bilgeCell.load - spec.bilgeRate * dt);\n      }\n\n      settle();\n    },\n  };\n\n  return hold;\n}\n\n/**\n * What one slack tank costs her, in metres of metacentric height.\n *\n * Published on its own because it is the number the whole module turns on and\n * because it is worth being able to ask before you pump: a surface **eight\n * metres** wide costs eight times what a **four metre** one does, at any\n * depth of liquid whatever. Subdivide a tank in two and you have divided its\n * penalty by four.\n */\nexport function freeSurfaceCost(\n  width: number,\n  length: number,\n  displacement: number\n): number {\n  return (RHO * (width ** 3 * length)) / 12 / Math.max(1e-6, displacement);\n}\n\n/** Where a point in the hold is, in the vessel's frame. Handy for placing\n *  lights, ladders and people down there. */\nexport function holdPoint(hold: Hold, name: string, out = new Vector3()): Vector3 {\n  const c = hold.at(name);\n  if (!c) return out.set(0, 0, 0);\n  return out.set(c.x, -c.floor + c.depth * c.level, c.z);\n}\n","import {\n  BoxGeometry,\n  CylinderGeometry,\n  Group,\n  Mesh,\n  MeshStandardMaterial,\n  Object3D,\n} from 'three';\nimport { Rng } from '../core/random';\nimport { DEFAULT_PALETTE, type Palette } from '../core/palette';\nimport { createSurface } from '../materials/surface';\nimport type { Prop } from '../core/types';\n\n/**\n * Stabilisers — and the only thing in this library that **stops working when\n * you stop.**\n *\n * A fin stabiliser is a wing. It makes its righting moment out of lift, and\n * lift comes out of water going past it, so a ship lying stopped has none at\n * all — she rolls exactly as badly as she would with no fins fitted, and the\n * fins are still there costing her the drag. Get her moving and they come\n * alive; the faster she goes the better they work, because lift goes as the\n * **square** of the speed.\n *\n * ```ts\n * const fins = createStabilisers({ kind: 'activeFin' });\n * ship.object.add(fins.object);\n *\n * fins.deploy(true);\n * game.onUpdate((t) => {\n *   fins.setWay(plant.way);                 // …and this is what they run on\n *   fins.update(t.delta);\n *   ship.update(t.delta, {\n *     speed: plant.way - fins.drag,         // they are not free\n *     damping: fins.damping,\n *   });\n * });\n * ```\n *\n * That is backwards from every other comfort in a ship. A wider hull is calm\n * at anchor. Deep loading is calm at anchor. Fins are the one thing that is\n * worst exactly when she is least able to do anything about it — riding out a\n * gale hove to, which is the moment you want them most.\n *\n * ## They take the roll out and leave the pitch\n *\n * `damping` touches `ShipInput.damping`, which touches the roll and nothing\n * else. A stabilised ship in a head sea pitches exactly as hard as an\n * unstabilised one, and that is the commonest complaint about them rather\n * than a simplification here.\n */\nexport type StabiliserKind = 'bilgeKeel' | 'fin' | 'activeFin' | 'gyro';\n\n/**\n * The era axis is **what it needs from you.**\n *\n * A bilge keel needs nothing whatever — welded on, never moves, works at any\n * speed including none — and takes about a quarter of the roll out. A fin\n * needs way. An active fin needs way *and* power and gives you nearly all of\n * it back. And the gyro is the inversion at the end: it asks for no speed, no\n * water, no drag and no thought, and then simply cannot lift a big ship —\n * which is why it is on yachts and not on liners.\n */\nexport const STABILISER_KINDS: StabiliserKind[] = ['bilgeKeel', 'fin', 'activeFin', 'gyro'];\n\nexport interface Stabilisers extends Prop {\n  kind: StabiliserKind;\n  /** Run them out, or house them. A no-op on a bilge keel, which is welded on\n   *  — and that no-op is the era axis. */\n  deploy(out: boolean): void;\n  /** Where the fins ARE, 0 housed to 1 fully out. They travel. */\n  readonly out: number;\n  readonly ordered: boolean;\n  /** Her way through the water, m/s. What they run on. */\n  setWay(speed: number): void;\n  readonly way: number;\n  /**\n   * How much of her roll they are ACTUALLY taking out, 0–1 — straight into\n   * `ShipInput.damping`.\n   *\n   * Not what they are rated at: what they are managing, at this speed, at\n   * this much deployment. Zero when she is stopped, for everything but a\n   * gyro.\n   */\n  readonly damping: number;\n  /** What they are rated at, with all the way in the world. */\n  readonly rated: number;\n  /** Speed they are costing her, m/s. Subtract it from what you hand the\n   *  hull — comfort is not free and this is the bill. */\n  readonly drag: number;\n  /** Working, and not merely deployed. */\n  readonly biting: boolean;\n  /** The speed below which they do essentially nothing, m/s. Published so a\n   *  bridge can say \"we need eight knots to steady her\" rather than a\n   *  caller having to know it. */\n  readonly bites: number;\n  update(dt: number): void;\n}\n\nexport interface StabiliserOptions {\n  kind?: StabiliserKind;\n  /** Her beam, m — the fins are sized off it. Default per kind. */\n  beam?: number;\n  /** How far below the waterline they come out. Default per kind. */\n  depth?: number;\n  /** Start them out. Default false, because a fin housed is a fin that has\n   *  not yet been bent on somebody's quay. */\n  deployed?: boolean;\n  seed?: number;\n  palette?: Palette;\n}\n\nconst clamp01 = (t: number): number => (t < 0 ? 0 : t > 1 ? 1 : t);\n\ninterface KindSpec {\n  beam: number;\n  depth: number;\n  /** Roll reduction with all the way in the world, 0–1. */\n  rated: number;\n  /**\n   * Speed at which they make HALF their rated damping, m/s.\n   *\n   * Lift goes as the square of the speed, so this is not a threshold with a\n   * cliff at it — it is the knee of a curve, and below it she is on her own\n   * by degrees rather than all at once.\n   */\n  bites: number;\n  /** m/s of way they cost when fully out and she is doing 10 m/s. */\n  cost: number;\n  /** m/s of way they cost when HOUSED. A bilge keel never houses. */\n  parked: number;\n  /** Seconds to run them out. */\n  travel: number;\n  /** Does it need water going past it? */\n  needsWay: boolean;\n  /** Fins a side. */\n  fins: number;\n}\n\nconst KINDS: Record<StabiliserKind, KindSpec> = {\n  bilgeKeel: {\n    beam: 24, depth: 3.2, rated: 0.26, bites: 0.6, cost: 0.05, parked: 0.05,\n    travel: 0, needsWay: false, fins: 1,\n    // Welded to the turn of the bilge and never moves. It works by dragging,\n    // not by lifting, so it does not care whether she is going anywhere —\n    // and it is dragging all the time, including in harbour.\n  },\n  fin: {\n    beam: 24, depth: 4.0, rated: 0.62, bites: 4.6, cost: 0.22, parked: 0.02,\n    travel: 40, needsWay: true, fins: 1,\n  },\n  activeFin: {\n    beam: 24, depth: 4.6, rated: 0.9, bites: 3.8, cost: 0.34, parked: 0.02,\n    travel: 55, needsWay: true, fins: 2,\n    // The real thing: fins driven off a gyro, actively working against the\n    // roll rather than merely resisting it. Nearly all of the roll, for a\n    // third of a metre a second and a very long time running them out.\n  },\n  gyro: {\n    beam: 12, depth: 0, rated: 0.55, bites: 0, cost: 0.0, parked: 0.0,\n    travel: 180, needsWay: false, fins: 0,\n    // ASKS NOTHING. No water, no speed, no drag — and it is a flywheel, so\n    // what it can do is bounded by how heavy it is, which is why the beam it\n    // is sized for here is half a liner's and it is on yachts instead.\n  },\n};\n\nexport function createStabilisers(options: StabiliserOptions = {}): Stabilisers {\n  const kind = options.kind ?? 'activeFin';\n  const base = KINDS[kind];\n  const spec: KindSpec = {\n    ...base,\n    beam: options.beam ?? base.beam,\n    depth: options.depth ?? base.depth,\n  };\n  const seed = options.seed ?? 1;\n  const rng = new Rng(seed);\n  const palette = options.palette ?? DEFAULT_PALETTE;\n  void palette;\n  void rng;\n\n  const group = new Group();\n  group.name = `stabilisers:${kind}`;\n\n  const steel = createSurface('steel', { color: 0x3b4046, seed });\n  const antifoul = new MeshStandardMaterial({ color: 0x7d2f28, roughness: 0.85 });\n\n  interface Blade {\n    pivot: Object3D;\n    side: number;\n  }\n  const blades: Blade[] = [];\n\n  if (kind === 'gyro') {\n    // A flywheel in a housing, on her centreline and as low as it will go.\n    const housing = new Mesh(new CylinderGeometry(spec.beam * 0.16, spec.beam * 0.16, spec.beam * 0.2, 16), steel);\n    housing.position.y = -0.4;\n    group.add(housing);\n    const wheel = new Object3D();\n    wheel.name = 'flywheel';\n    group.add(wheel);\n    const rim = new Mesh(\n      new CylinderGeometry(spec.beam * 0.13, spec.beam * 0.13, spec.beam * 0.06, 20),\n      createSurface('steel', { color: 0x8a9099, seed: seed + 1 })\n    );\n    rim.position.y = -0.4;\n    wheel.add(rim);\n    blades.push({ pivot: wheel, side: 0 });\n  } else {\n    for (const side of [-1, 1]) {\n      for (let i = 0; i < spec.fins; i++) {\n        const pivot = new Object3D();\n        pivot.name = `fin:${side < 0 ? 'port' : 'stbd'}${i}`;\n        // On the turn of the bilge, low and about a third aft of amidships.\n        pivot.position.set(side * spec.beam * 0.46, -spec.depth * 0.55, -i * spec.beam * 0.7);\n        group.add(pivot);\n\n        if (kind === 'bilgeKeel') {\n          // A STRAKE, not a wing: a long thin plate running most of her\n          // length, and it never moves because there is nothing to move it.\n          const strake = new Mesh(\n            new BoxGeometry(0.14, spec.depth * 0.35, spec.beam * 3.6),\n            antifoul\n          );\n          strake.position.x = side * 0.1;\n          pivot.add(strake);\n        } else {\n          const root = new Mesh(new CylinderGeometry(0.34, 0.34, 0.9, 10), steel);\n          root.rotation.z = Math.PI / 2;\n          pivot.add(root);\n          const fin = new Mesh(new BoxGeometry(spec.beam * 0.34, 0.34, spec.beam * 0.16), steel);\n          fin.position.x = side * spec.beam * 0.19;\n          pivot.add(fin);\n          const tip = new Mesh(new BoxGeometry(spec.beam * 0.06, 0.22, spec.beam * 0.12), antifoul);\n          tip.position.x = side * spec.beam * 0.36;\n          pivot.add(tip);\n        }\n        blades.push({ pivot, side });\n      }\n    }\n  }\n\n  // A bilge keel is always out and has no travel; everything else starts\n  // housed unless the caller says otherwise.\n  let out = spec.travel <= 0 ? 1 : options.deployed ? 1 : 0;\n  let ordered = out > 0.5;\n  let way = 0;\n  let angle = 0;\n  let spin = 0;\n\n  const place = (): void => {\n    for (const b of blades) {\n      if (kind === 'gyro') {\n        // A flywheel does not stop when the ship does. It is the one moving\n        // part here whose speed has nothing to do with hers.\n        b.pivot.rotation.y = spin;\n      } else if (kind === 'bilgeKeel') {\n        b.pivot.rotation.z = 0;\n      } else {\n        // Housed, they lie fore-and-aft in their boxes; out, they stand\n        // athwartships and the ACTIVE ones work — the visible angle is the\n        // angle of attack, and it goes to nothing when she has no way on.\n        b.pivot.rotation.y = (1 - out) * (Math.PI / 2) * b.side;\n        b.pivot.rotation.z = out * angle * b.side;\n      }\n    }\n  };\n  place();\n\n  const api: Stabilisers = {\n    object: group,\n    // Below the waterline. Nobody walks round it.\n    obstacleRadius: 0,\n    kind,\n    deploy(want: boolean) {\n      // A SILENT NO-OP on a bilge keel, and that no-op is the era axis: it is\n      // welded to her, and there was never a lever.\n      if (spec.travel <= 0) return;\n      ordered = want;\n    },\n    get out() {\n      return out;\n    },\n    get ordered() {\n      return ordered;\n    },\n    setWay(speed: number) {\n      way = Math.abs(Number.isFinite(speed) ? speed : 0);\n    },\n    get way() {\n      return way;\n    },\n    rated: spec.rated,\n    bites: spec.bites,\n    get damping() {\n      if (!spec.needsWay) return spec.rated * out;\n      // LIFT GOES AS THE SQUARE OF THE SPEED, so this is a knee and not a\n      // cliff: she loses them by degrees as she slows, and at rest she has\n      // nothing. Written as a threshold it would switch off at a stroke and\n      // a ship would go from steady to rolling between two frames.\n      const v = way / Math.max(1e-6, spec.bites);\n      return spec.rated * out * (v * v) / (1 + v * v);\n    },\n    get drag() {\n      // They cost her whether they are working or not, and a housed fin still\n      // costs a little because the box it lives in is a hole in her bottom.\n      const share = spec.parked + (spec.cost - spec.parked) * out;\n      return share * (way / 10) * (way / 10) * 10 * 0.1 + share * 0.08;\n    },\n    get biting() {\n      return api.damping > spec.rated * 0.25;\n    },\n    update(dt: number) {\n      if (!(dt > 0)) return;\n      if (spec.travel > 0) {\n        const step = dt / spec.travel;\n        const want = ordered ? 1 : 0;\n        const err = want - out;\n        out += Math.abs(err) <= step ? err : Math.sign(err) * step;\n      }\n      // The angle of attack an active fin is holding. It is a READ, not a\n      // control: it goes to nothing as she loses way, which is what makes a\n      // stopped ship's fins visibly idle rather than invisibly useless.\n      const bite = spec.needsWay ? clamp01(way / Math.max(1e-6, spec.bites * 2)) : 1;\n      angle = (kind === 'activeFin' ? 0.42 : 0.16) * bite;\n      spin += dt * (kind === 'gyro' ? 26 : 0);\n      place();\n    },\n  };\n  return api;\n}\n\n/**\n * How much roll a set of fins would take out at a given speed — without\n * building any.\n *\n * Published for the same reason `freeSurfaceCost` is: it is the question you\n * want to ask *before* you commit, and the answer is a curve rather than a\n * yes. At half their biting speed they are managing a fifth of what they are\n * rated at; at twice it, four fifths.\n */\nexport function dampingAt(kind: StabiliserKind, speed: number): number {\n  const spec = KINDS[kind];\n  if (!spec.needsWay) return spec.rated;\n  const v = Math.abs(speed) / Math.max(1e-6, spec.bites);\n  return (spec.rated * (v * v)) / (1 + v * v);\n}\n","import {\n  CylinderGeometry,\n  Group,\n  Mesh,\n  MeshStandardMaterial,\n  Vector3,\n} from 'three';\nimport { Rng } from '../core/random';\nimport { DEFAULT_PALETTE, type Palette } from '../core/palette';\nimport { createSurface } from '../materials/surface';\nimport { createSlot, type Prop, type PropSlot } from '../core/types';\n\n/**\n * Plumbing — the first thing in this library where **what you get depends on\n * what somebody else is doing.**\n *\n * Everything up to here is local. A boiler makes steam out of its own fire; a\n * hull floats on its own displacement; a light is a fact about one observer.\n * None of them has any opinion about what else is happening in the world. A\n * water supply is a *network*, and a network's defining property is that it is\n * shared — so this is the first module in the trilogy where two objects\n * interfere with each other without either one knowing the other exists.\n *\n * ## The shower goes scalding when the lavatory is flushed\n *\n * Everybody has had this happen and almost nobody has the mechanism right. It\n * is not a temperature failure. **It is a pressure failure that arrives as a\n * temperature.**\n *\n * A mixer set to 40 °C from 60 °C hot and 10 °C cold is running 60 % hot. A WC\n * cistern draws from the COLD branch only. The cold manifold's pressure drops,\n * so the cold flow through the mixer drops — and the hot does not, because\n * nothing happened to the hot branch. Same hot, less cold, and the mixture\n * climbs:\n *\n * ```ts\n *   cold at 100%  ->  40.0 °C\n *   cold at  72%  ->  43.8 °C     a basin tap opens\n *   cold at  55%  ->  46.6 °C     a WC fills                    SCALD\n *   cold at  25%  ->  52.9 °C     the cold branch nearly dies   burns in seconds\n *   cold at   0%  ->  60.0 °C     you are standing under the cylinder\n * ```\n *\n * Nothing in the shower changed. Nothing in the mixer changed. Somebody in\n * another room pressed a lever.\n *\n * ## What happens to the person in the shower\n *\n * The era axis, and it is not about how much water you get:\n *\n * | kind | what a flush does to the shower |\n * | --- | --- |\n * | `bucket` | nothing. There is no network, so there is nothing to share. |\n * | `gravity` | takes the flow away. A cistern in the loft has a third of a bar and nothing to spare. |\n * | `mains` | takes the TEMPERATURE away. There is flow to spare and the scald arrives instead. |\n * | `thermostatic` | takes a little flow, and holds the temperature. |\n *\n * A bucket has no contention because it has no network — which is not\n * primitive, it is *uncoupled*, and it is the only supply here that cannot\n * scald anybody.\n *\n * And `thermostatic` is the inversion at the end, the same shape as a gyro\n * stabiliser that needs no way from you and a sectored light that navigates\n * instead of you: **it does not stop the contention. It stops the contention\n * from reaching you.** The pressure still collapses; the mixer gives up flow\n * to hold the temperature, and if the cold fails altogether it shuts off\n * rather than deliver sixty degrees.\n *\n * ## The store empties seven times faster than it fills\n *\n * A 120-litre cylinder at 60 °C, and a shower drawing six and a half litres a\n * minute of hot:\n *\n * ```ts\n * plumbing.hotLastsFor() / 60;   // 20 minutes\n * plumbing.reheatTakes() / 60;   // 140 minutes, on a 3 kW immersion\n * ```\n *\n * Which is the steam plant again in a different trade: a store the heater\n * fills far slower than the outlet empties it. There is no way to have a long\n * shower and a hot bath afterwards, and no setting anywhere that changes it.\n *\n * And it does not cool — it **runs out**. The cylinder is stratified: hot\n * floats on the cold feed coming in underneath and is drawn off the top at\n * very nearly full temperature until it is gone. So the shower stays perfect,\n * and stays perfect, and then falls off a cliff — which is what everybody has\n * actually stood in, and is nothing like the gentle fade a stirred-tank model\n * produces.\n *\n * ## Height is pressure, and that is the whole argument for a pump\n *\n * On gravity the pressure at an outlet is the head above it and nothing else —\n * so the same house gives a different shower on each floor:\n *\n * ```ts\n * // a cistern at 8 m\n * ground floor  (0.0 m):  0.79 bar  ->  7.5 L/min\n * first  floor  (2.7 m):  0.52 bar  ->  6.1 L/min\n * second floor  (5.4 m):  0.26 bar  ->  4.3 L/min\n * ```\n *\n * Pass an outlet's `height` and it is worked out for you. It is the one number\n * in this module that a fitter cannot argue with.\n */\nexport type SupplyKind = 'bucket' | 'gravity' | 'mains' | 'thermostatic';\n\nexport const SUPPLY_KINDS: SupplyKind[] = ['bucket', 'gravity', 'mains', 'thermostatic'];\n\n/** idle / comfortable / noticeably down / not enough to use. */\nexport type SupplyState = 'idle' | 'easy' | 'strained' | 'starved';\n\n/** What kind of thing is on the end of the pipe. */\nexport type OutletKind = 'shower' | 'tap' | 'bath' | 'wc';\n\nexport interface Draw {\n  name: string;\n  kind: OutletKind;\n  /** How far open, 0–1. */\n  open: number;\n  /** Litres a minute, both branches together. */\n  flow: number;\n  /** …of which this much is coming out of the cylinder. */\n  hot: number;\n  /** Degrees C at the outlet. */\n  temp: number;\n  /**\n   * Over 44 °C, which is the limit for water a person stands under.\n   *\n   * Fifty and above scalds a child in well under a minute; sixty does it in\n   * about a second, and sixty is simply the cylinder temperature — the number\n   * you get when the cold gives up entirely.\n   */\n  scalding: boolean;\n  /** Enough flow to be worth having. A shower under five litres a minute is a\n   *  drip you stand in. */\n  usable: boolean;\n  /**\n   * Bar AT THE OUTLET — the manifold pressure less the lift to get up there.\n   *\n   * Reporting the manifold instead reads backwards: raise an outlet and it\n   * draws less, so the manifold pressure goes UP while the shower gets worse.\n   */\n  pressure: number;\n}\n\nexport interface OutletOptions {\n  kind?: OutletKind;\n  /** Where it is, for the pipework to be drawn to. */\n  at?: Vector3;\n  /**\n   * Metres above the supply datum.\n   *\n   * On gravity this is subtracted from the head, so it decides everything. An\n   * outlet above the cistern gets nothing at all, which is why the cistern is\n   * in the loft and why a shower in a loft conversion does not work.\n   */\n  height?: number;\n  /** Fraction of the flow taken from the hot branch, 0–1. A WC ignores it. */\n  mix?: number;\n}\n\nexport interface Plumbing extends Prop {\n  kind: SupplyKind;\n  /** Add something on the end of a pipe. */\n  outlet(name: string, options?: OutletOptions): void;\n  open(name: string, fraction?: number): void;\n  close(name: string): void;\n  /** Move the mixer. 0 is all cold, 1 is all cylinder. */\n  setMix(name: string, hotFraction: number): void;\n  /**\n   * Set it to a TEMPERATURE, which is what a person actually does.\n   *\n   * Nobody turns a shower to 'sixty per cent hot'. They turn it until it feels\n   * right, with whatever else in the house happens to be running at that\n   * moment — and the setting is then fixed, so when the conditions change the\n   * temperature does. Calibrating by mix fraction quietly assumes the tap\n   * knows something it cannot know, and hides the entire failure.\n   */\n  setTarget(name: string, celsius: number): void;\n  /** What that outlet is getting, right now, given everything else. */\n  drawAt(name: string): Draw | null;\n  readonly draws: Draw[];\n  readonly outlets: string[];\n\n  /** Bar at the cold manifold. */\n  readonly pressure: number;\n  /** Bar at the hot manifold — a different number, and that is the module. */\n  readonly hotPressure: number;\n  /** Litres a minute leaving the system. */\n  readonly demand: number;\n  readonly state: SupplyState;\n  onState?: (state: SupplyState) => void;\n\n  /** Litres of usable hot water left in the cylinder. */\n  readonly hot: number;\n  /** What is in the cylinder now, °C. It falls as it is drawn. */\n  readonly hotTemp: number;\n  readonly cylinder: number;\n  /**\n   * Seconds until the water stops being warm enough to stand under, at the\n   * present draw — or `Infinity` if nothing is drawing hot.\n   *\n   * A cylinder does not run out, it cools: a tank model falls exponentially\n   * and never reaches the cold feed, so 'litres of hot left divided by the\n   * rate' overstates it badly. This integrates the thing forward until the\n   * delivered temperature drops below `warm`, which is the number a person\n   * standing in it would recognise.\n   */\n  hotLastsFor(warm?: number): number;\n  /** Seconds to bring a cold cylinder back up. */\n  reheatTakes(): number;\n  /** Switch the immersion on and off. */\n  setHeater(on: boolean): void;\n  readonly heating: boolean;\n\n  /**\n   * Tip water in by hand, litres.\n   *\n   * The bucket loop, and it works on every kind — because it is the one way of\n   * getting water that no supply failure can take away from you.\n   */\n  pour(name: string, litres: number): void;\n  readonly poured: number;\n\n  station: PropSlot;\n  slots: PropSlot[];\n  update(dt: number): void;\n}\n\nexport interface PlumbingOptions {\n  kind?: SupplyKind;\n  /** Metres of head, for `gravity`. The loft, usually. */\n  head?: number;\n  /** Bar at the stopcock, for the pressurised kinds. */\n  mains?: number;\n  /** Cylinder size, litres. */\n  cylinder?: number;\n  /** Immersion rating, kW. */\n  heater?: number;\n  /** What the cylinder is held at, °C. */\n  stored?: number;\n  /** What comes out of the ground, °C. */\n  cold?: number;\n  seed?: number;\n  palette?: Palette;\n}\n\nconst RHO = 1000;\nconst G = 9.81;\n/** Specific heat of water, kJ per kg per K. */\nconst CP = 4.186;\n/** Above this, water is not something a person can stand under. */\nexport const SCALD = 44;\nconst clamp01 = (t: number): number => (t < 0 ? 0 : t > 1 ? 1 : t);\n\n/** Bar from metres of head. A loft cistern is a third of a bar and no more. */\nexport function headPressure(metres: number): number {\n  return (Math.max(0, metres) * RHO * G) / 1e5;\n}\n\n/**\n * Litres a minute through an orifice at a given pressure.\n *\n * `Q = k√p`, calibrated so a shower head at two bar gives twelve litres a\n * minute — which is what a decent mains shower actually does.\n */\nexport function orificeFlow(k: number, bar: number): number {\n  return bar <= 0 ? 0 : k * Math.sqrt(bar);\n}\n\ninterface OutletSpec {\n  /** Orifice coefficient. */\n  k: number;\n  /** Litres a minute below which it is not worth having. */\n  usable: number;\n  /** Can its mixer be moved, or does it only ever take cold? */\n  mixes: boolean;\n}\n\nconst OUTLETS: Record<OutletKind, OutletSpec> = {\n  shower: { k: 12 / Math.SQRT2, usable: 5, mixes: true },\n  tap: { k: 10 / Math.SQRT2, usable: 2, mixes: true },\n  bath: { k: 18 / Math.SQRT2, usable: 8, mixes: true },\n  // A WC takes COLD AND ONLY COLD, and that single fact is what makes the\n  // shower scald rather than merely weaken.\n  //\n  // It is also the one outlet here that does not mind being starved, because\n  // a cistern is a BUFFER: starve it and it simply takes longer to fill, and\n  // nobody is standing in it while it does. Given a shower's expectations it\n  // drags the whole house to `starved` over a fixture that is perfectly happy.\n  wc: { k: 6 / Math.SQRT2, usable: 1.5, mixes: false },\n};\n\ninterface KindSpec {\n  /** Metres of head on the cold side. `0` where it is not a head system. */\n  head: number;\n  /** Bar at the stopcock. `0` on gravity. */\n  mains: number;\n  /** How much lower the hot side sits than the cold, m or bar as appropriate. */\n  hotDrop: number;\n  /**\n   * Resistance of each branch, bar per (L/min)².\n   *\n   * NOT the main — the branch. What kills a shower is the fifteen-millimetre\n   * run that the bathroom shares, and the cold one is always the worse of the\n   * two because it feeds the WC, the basin and everything outside as well.\n   * Sized off the main instead, a flush moves the shower six tenths of a\n   * degree and the module has nothing to say.\n   */\n  coldResistance: number;\n  hotResistance: number;\n  /** Does a mixer hold its temperature when a branch fails? */\n  thermostatic: boolean;\n  /** Is there any network at all? */\n  piped: boolean;\n}\n\nconst KINDS: Record<SupplyKind, KindSpec> = {\n  // No network. There is nothing to share, nothing to lose pressure, and\n  // nothing that can scald anybody — which is not primitive, it is UNCOUPLED.\n  bucket: { head: 0, mains: 0, hotDrop: 0, coldResistance: 0, hotResistance: 0, thermostatic: false, piped: false },\n  // A cistern in the loft, and a hot cylinder a little below it. A third of a\n  // bar, old narrow pipe, and nothing whatever to spare.\n  gravity: { head: 8, mains: 0, hotDrop: 1.2, coldResistance: 0.0042, hotResistance: 0.0022, thermostatic: false, piped: true },\n  // Pressurised, and now there IS flow to spare — so contention stops taking\n  // the flow away and starts taking the temperature away instead.\n  mains: { head: 0, mains: 2.4, hotDrop: 0.2, coldResistance: 0.055, hotResistance: 0.012, thermostatic: false, piped: true },\n  // The same supply, and a mixer that gives up flow rather than temperature.\n  thermostatic: {\n    head: 0, mains: 2.4, hotDrop: 0.2, coldResistance: 0.055, hotResistance: 0.012,\n    thermostatic: true, piped: true,\n  },\n};\n\ninterface Live {\n  name: string;\n  kind: OutletKind;\n  spec: OutletSpec;\n  open: number;\n  mix: number;\n  height: number;\n  at: Vector3 | null;\n  pipe: Mesh | null;\n  flow: number;\n  hotFlow: number;\n  temp: number;\n}\n\nexport function createPlumbing(options: PlumbingOptions = {}): Plumbing {\n  const kind = options.kind ?? 'mains';\n  const base = KINDS[kind];\n  const head = options.head ?? base.head;\n  const mains = options.mains ?? base.mains;\n  const capacity = options.cylinder ?? 120;\n  const heaterKw = options.heater ?? 3;\n  const stored = options.stored ?? 60;\n  const coldTemp = options.cold ?? 10;\n  const seed = options.seed ?? 1;\n  const rng = new Rng(seed);\n  const palette = options.palette ?? DEFAULT_PALETTE;\n\n  const group = new Group();\n  group.name = `plumbing:${kind}`;\n\n  const copper = createSurface('paintedMetal', { color: 0xb2703a, seed });\n  void palette;\n  const lagging = createSurface('plaster', { color: 0xd8d2c2, seed: seed + 1 });\n  const steel = createSurface('steel', { color: 0x6d7378, seed: seed + 2 });\n  /** Each run gets its own material, because each run is painted by what is\n   *  going down it. */\n  const pipeMat = (): MeshStandardMaterial =>\n    new MeshStandardMaterial({ color: 0x5f7f9a, roughness: 0.5, flatShading: true });\n\n  // ── geometry ─────────────────────────────────────────────────────────\n\n  const MANIFOLD = new Vector3(0, 0.55, 0);\n\n  if (kind === 'bucket') {\n    // A pail and a stand. The entire installation.\n    const pail = new Mesh(new CylinderGeometry(0.17, 0.13, 0.3, 12, 1, true), steel);\n    pail.position.set(0, 0.15, 0);\n    group.add(pail);\n    const handle = new Mesh(new CylinderGeometry(0.012, 0.012, 0.34, 6), steel);\n    handle.rotation.z = Math.PI / 2;\n    handle.position.set(0, 0.32, 0);\n    group.add(handle);\n  } else {\n    // The cylinder — lagged, because the whole point of it is that it holds\n    // heat, and an unlagged one is a radiator in a cupboard.\n    const tank = new Mesh(new CylinderGeometry(0.23, 0.23, 1.1, 14), lagging);\n    tank.position.set(0.42, 0.62, 0);\n    group.add(tank);\n    const dome = new Mesh(new CylinderGeometry(0.05, 0.23, 0.16, 14), lagging);\n    dome.position.set(0.42, 1.24, 0);\n    group.add(dome);\n\n    if (head > 0) {\n      // THE CISTERN IN THE LOFT, and it is drawn where the head says it is —\n      // this is the one prop whose pressure IS its geometry.\n      const cistern = new Mesh(\n        new CylinderGeometry(0.44, 0.44, 0.4, 4),\n        createSurface('plaster', { color: 0x8d9aa4, seed: seed + 3 })\n      );\n      cistern.rotation.y = Math.PI / 4;\n      cistern.position.set(-0.5, head - 0.2, 0);\n      group.add(cistern);\n      const riser = new Mesh(new CylinderGeometry(0.028, 0.028, head - 0.4, 8), copper);\n      riser.position.set(-0.5, (head - 0.4) / 2, 0);\n      group.add(riser);\n    } else {\n      // A stopcock where it comes in under the floor.\n      const stop = new Mesh(new CylinderGeometry(0.05, 0.05, 0.12, 10), copper);\n      stop.position.set(-0.5, 0.16, 0);\n      group.add(stop);\n      const wheel = new Mesh(new CylinderGeometry(0.09, 0.09, 0.02, 12), steel);\n      wheel.position.set(-0.5, 0.26, 0);\n      group.add(wheel);\n    }\n\n    const manifold = new Mesh(new CylinderGeometry(0.035, 0.035, 1.1, 8), copper);\n    manifold.rotation.z = Math.PI / 2;\n    manifold.position.copy(MANIFOLD);\n    group.add(manifold);\n    for (let i = 0; i < 3; i++) {\n      const clip = new Mesh(new CylinderGeometry(0.045, 0.045, 0.03, 8), steel);\n      clip.rotation.z = Math.PI / 2;\n      clip.position.set(-0.4 + i * 0.4, MANIFOLD.y, rng.next() * 0.01);\n      group.add(clip);\n    }\n  }\n\n  const pipes = new Group();\n  pipes.name = 'plumbing:pipes';\n  group.add(pipes);\n\n  const station = createSlot('plumbing', 'stopcock', group, -0.5, 0, 0.6, 0);\n\n  // ── the model ────────────────────────────────────────────────────────\n\n  const live = new Map<string, Live>();\n  /**\n   * Litres of water in the cylinder still at storage temperature.\n   *\n   * STRATIFIED, not stirred. Hot water floats: it sits on top of the cold feed\n   * coming in underneath and is drawn off the top at very nearly full\n   * temperature until it is gone. Modelled as a stirred tank instead, the\n   * shower starts cooling in the first second and is tepid in three minutes —\n   * where what actually happens is that it stays perfect, and stays perfect,\n   * and then falls off a cliff. Everybody has stood in that cliff.\n   */\n  let hotLitres = capacity;\n  let heating = true;\n  let poured = 0;\n  let coldBar = 0;\n  let hotBar = 0;\n  let state: SupplyState = 'idle';\n\n  /**\n   * What is coming out of the cylinder this instant.\n   *\n   * Full temperature while there is a layer of it, then down through the\n   * thermocline — the mixed band between the hot above and the cold feed\n   * below, which on a real cylinder is a few inches and here is the last tenth.\n   */\n  const THERMOCLINE = 0.1;\n  /** kJ to lift one litre from the cold feed to storage temperature. */\n  const perLitre = CP * Math.max(1e-6, stored - coldTemp);\n  const deliveredHot = (): number => {\n    const f = clamp01(hotLitres / Math.max(1e-6, capacity * THERMOCLINE));\n    return coldTemp + (stored - coldTemp) * f;\n  };\n\n  const sourceCold = base.piped ? (head > 0 ? headPressure(head) : mains) : 0;\n  const sourceHot = base.piped\n    ? head > 0\n      ? headPressure(Math.max(0, head - base.hotDrop))\n      : Math.max(0, mains - base.hotDrop)\n    : 0;\n\n  /**\n   * Solve the two manifolds.\n   *\n   * They are SEPARATE, and that is the whole module: a WC pulls the cold\n   * branch down and leaves the hot exactly where it was, so every mixer in the\n   * building is suddenly running a hotter mixture than it was set to. Solved\n   * as one supply, the two branches fall together, the mixture stays at 40 °C\n   * and there is no scald anywhere — which is a plumbing system nobody has\n   * ever lived in.\n   */\n  const solve = (): void => {\n    if (!base.piped) {\n      coldBar = 0;\n      hotBar = 0;\n      for (const o of live.values()) {\n        o.flow = 0;\n        o.hotFlow = 0;\n        o.temp = coldTemp;\n      }\n      return;\n    }\n    let pc = sourceCold;\n    let ph = sourceHot;\n    for (let i = 0; i < 40; i++) {\n      let qc = 0;\n      let qh = 0;\n      for (const o of live.values()) {\n        if (o.open <= 0) continue;\n        const lift = headPressure(o.height);\n        const mix = o.spec.mixes ? o.mix : 0;\n        qc += orificeFlow(o.spec.k * (1 - mix), Math.max(0, pc - lift)) * o.open;\n        qh += orificeFlow(o.spec.k * mix, Math.max(0, ph - lift)) * o.open;\n      }\n      const nc = Math.max(0, sourceCold - base.coldResistance * qc * qc);\n      const nh = Math.max(0, sourceHot - base.hotResistance * qh * qh);\n      pc = pc * 0.55 + nc * 0.45;\n      ph = ph * 0.55 + nh * 0.45;\n    }\n    coldBar = pc;\n    hotBar = ph;\n\n    for (const o of live.values()) {\n      if (o.open <= 0) {\n        o.flow = 0;\n        o.hotFlow = 0;\n        o.temp = coldTemp;\n        continue;\n      }\n      const lift = headPressure(o.height);\n      const mix = o.spec.mixes ? o.mix : 0;\n      let c = orificeFlow(o.spec.k * (1 - mix), Math.max(0, pc - lift)) * o.open;\n      let h = orificeFlow(o.spec.k * mix, Math.max(0, ph - lift)) * o.open;\n\n      if (base.thermostatic && o.spec.mixes && mix > 0) {\n        // A THERMOSTATIC MIXER GIVES UP FLOW, NOT TEMPERATURE. It cannot make\n        // more cold appear, so it throttles the hot to match whatever cold it\n        // is actually getting — and if there is no cold at all it shuts,\n        // rather than hand somebody the cylinder temperature.\n        const th = deliveredHot();\n        const want = coldTemp + (th - coldTemp) * mix;\n        const denom = Math.max(1e-6, th - want);\n        const allowed = (c * (want - coldTemp)) / denom;\n        h = Math.min(h, Math.max(0, allowed));\n        if (c <= 0.01) h = 0;\n      }\n\n      o.flow = c + h;\n      o.hotFlow = h;\n      o.temp = o.flow <= 1e-6 ? coldTemp : (h * deliveredHot() + c * coldTemp) / o.flow;\n    }\n  };\n\n  /**\n   * How hard the supply is being asked to work — measured in CONSEQUENCES.\n   *\n   * Not in the fraction of the source pressure still standing, which was the\n   * first attempt: that is a number about the pipe, it has to be tuned against\n   * whatever resistance the pipe happens to have, and with a realistic branch\n   * it called one shower on a mains supply 'strained'. What matters is whether\n   * anybody is getting something they can use, at a temperature they can stand.\n   */\n  const classify = (): SupplyState => {\n    let anyOpen = false;\n    let starved = false;\n    let strained = false;\n    for (const o of live.values()) {\n      if (o.open <= 0) continue;\n      anyOpen = true;\n      if (o.flow < o.spec.usable) starved = true;\n      else if (o.flow < o.spec.usable * 1.3) strained = true;\n      if (o.flow > 0.1 && o.temp >= SCALD) strained = true;\n    }\n    if (!anyOpen) return 'idle';\n    if (starved) return 'starved';\n    return strained ? 'strained' : 'easy';\n  };\n\n  const layPipe = (o: Live): void => {\n    if (!o.at || !base.piped) return;\n    const from = MANIFOLD.clone();\n    const span = o.at.clone().sub(from);\n    const len = Math.max(0.02, span.length());\n    // Built one metre long and SCALED, so the run's length is readable from\n    // the object rather than buried in a geometry parameter.\n    const pipe = new Mesh(new CylinderGeometry(0.022, 0.022, 1, 7), pipeMat());\n    pipe.name = `plumbing:pipe:${o.name}`;\n    pipe.scale.set(1, len, 1);\n    pipe.position.copy(from).addScaledVector(span, 0.5);\n    pipe.quaternion.setFromUnitVectors(new Vector3(0, 1, 0), span.normalize());\n    pipes.add(pipe);\n    o.pipe = pipe;\n  };\n\n  const paint = (): void => {\n    for (const o of live.values()) {\n      if (!o.pipe) continue;\n      // Hot where the hot is going, and brighter the more is moving — a still\n      // frame of a plumbing system is nothing at all unless the pipes say\n      // which of them is working.\n      const hotShare = o.flow <= 1e-6 ? 0 : o.hotFlow / o.flow;\n      const busy = clamp01(o.flow / Math.max(1, o.spec.k * 1.4));\n      const mat = o.pipe.material as MeshStandardMaterial;\n      mat.color.setRGB(\n        0.28 + hotShare * 0.5 + busy * 0.12,\n        0.36 - hotShare * 0.12 + busy * 0.2,\n        0.5 - hotShare * 0.24 + busy * 0.12\n      );\n      mat.emissive.setRGB(busy * 0.14 + hotShare * busy * 0.16, busy * 0.09, busy * 0.05);\n    }\n  };\n\n  const api: Plumbing = {\n    object: group,\n    obstacleRadius: 0.5,\n    kind,\n    station,\n    slots: [station],\n    cylinder: capacity,\n\n    outlet(name: string, opts: OutletOptions = {}) {\n      const k = opts.kind ?? 'tap';\n      const spec = OUTLETS[k];\n      const o: Live = {\n        name,\n        kind: k,\n        spec,\n        open: 0,\n        mix: spec.mixes ? clamp01(opts.mix ?? 0.6) : 0,\n        height: Math.max(0, opts.height ?? 0),\n        at: opts.at ? opts.at.clone() : null,\n        pipe: null,\n        flow: 0,\n        hotFlow: 0,\n        temp: coldTemp,\n      };\n      live.set(name, o);\n      layPipe(o);\n      solve();\n      paint();\n    },\n    open(name: string, fraction = 1) {\n      const o = live.get(name);\n      if (!o) return;\n      o.open = clamp01(Number.isFinite(fraction) ? fraction : 0);\n      solve();\n      paint();\n    },\n    close(name: string) {\n      api.open(name, 0);\n    },\n    setTarget(name: string, celsius: number) {\n      const o = live.get(name);\n      if (!o || !o.spec.mixes) return;\n      const want = Number.isFinite(celsius) ? celsius : coldTemp;\n      // Solved against the pressures AS THEY ARE. That is the whole point: the\n      // setting is right for the house at this instant and for no other.\n      solve();\n      const lift = headPressure(o.height);\n      const pc = Math.max(0, coldBar - lift);\n      const ph = Math.max(0, hotBar - lift);\n      let lo = 0;\n      let hi = 1;\n      for (let i = 0; i < 40; i++) {\n        const m = (lo + hi) / 2;\n        const c = orificeFlow(o.spec.k * (1 - m), pc);\n        const h = orificeFlow(o.spec.k * m, ph);\n        const t = c + h <= 1e-9 ? coldTemp : (h * deliveredHot() + c * coldTemp) / (c + h);\n        if (t < want) lo = m;\n        else hi = m;\n      }\n      o.mix = clamp01((lo + hi) / 2);\n      solve();\n      paint();\n    },\n    setMix(name: string, hotFraction: number) {\n      const o = live.get(name);\n      if (!o || !o.spec.mixes) return;\n      o.mix = clamp01(Number.isFinite(hotFraction) ? hotFraction : 0);\n      solve();\n      paint();\n    },\n    drawAt(name: string) {\n      const o = live.get(name);\n      if (!o) return null;\n      return {\n        name: o.name,\n        kind: o.kind,\n        open: o.open,\n        flow: o.flow,\n        hot: o.hotFlow,\n        temp: o.temp,\n        scalding: o.open > 0 && o.flow > 0.1 && o.temp >= SCALD,\n        usable: o.flow >= o.spec.usable,\n        pressure: Math.max(0, coldBar - headPressure(o.height)),\n      };\n    },\n    get draws() {\n      return [...live.keys()].map((n) => api.drawAt(n)!).filter(Boolean);\n    },\n    get outlets() {\n      return [...live.keys()];\n    },\n\n    get pressure() {\n      return coldBar;\n    },\n    get hotPressure() {\n      return hotBar;\n    },\n    get demand() {\n      let q = 0;\n      for (const o of live.values()) q += o.flow;\n      return q;\n    },\n    get state() {\n      // Worked out on demand, so a system asked what it is doing before\n      // anybody has stepped it answers about the taps that are open rather\n      // than about last frame.\n      return classify();\n    },\n\n    get hot() {\n      return hotLitres;\n    },\n    get hotTemp() {\n      return deliveredHot();\n    },\n    hotLastsFor(warm = 35) {\n      let draw = 0;\n      for (const o of live.values()) draw += o.hotFlow;\n      if (draw <= 1e-6) return Infinity;\n      // Run the tank forward coarsely. There is no closed form once the\n      // mixture matters, and the whole point is what the PERSON gets.\n      const held = hotLitres;\n      let t = 0;\n      const dt = 5;\n      try {\n        for (; t < 6 * 3600; t += dt) {\n          let hottest = -Infinity;\n          for (const o of live.values()) {\n            if (o.open > 0 && o.hotFlow > 0.01) hottest = Math.max(hottest, o.temp);\n          }\n          if (hottest < warm) return t;\n          let q = 0;\n          for (const o of live.values()) q += o.hotFlow;\n          if (q <= 1e-6) return Infinity;\n          hotLitres = Math.max(0, hotLitres - (q * dt) / 60);\n          if (heating && hotLitres < capacity) {\n            hotLitres = Math.min(capacity, hotLitres + (heaterKw * dt) / perLitre);\n          }\n          solve();\n        }\n        return Infinity;\n      } finally {\n        hotLitres = held;\n        solve();\n      }\n    },\n    reheatTakes() {\n      return heaterKw <= 0 ? Infinity : (capacity * perLitre) / heaterKw;\n    },\n    setHeater(on: boolean) {\n      heating = on;\n    },\n    get heating() {\n      return heating;\n    },\n\n    pour(name: string, litres: number) {\n      const l = Math.max(0, Number.isFinite(litres) ? litres : 0);\n      poured += l;\n      void name;\n    },\n    get poured() {\n      return poured;\n    },\n\n    update(dt: number) {\n      if (!(dt > 0)) return;\n      solve();\n\n      // The cylinder: hot out, cold in to replace it, mixed. A tank model\n      // rather than a stratified one — real cylinders stratify and give you a\n      // little longer, and the difference is not the point.\n      let drawn = 0;\n      for (const o of live.values()) drawn += o.hotFlow;\n      if (drawn > 0) hotLitres = Math.max(0, hotLitres - (drawn * dt) / 60);\n      if (heating && hotLitres < capacity) {\n        // Litres a second the immersion can bring up from the cold feed:\n        // kW divided by the energy it takes to lift one litre the whole way.\n        hotLitres = Math.min(capacity, hotLitres + (heaterKw * dt) / perLitre);\n      }\n      solve();\n      paint();\n\n      const next = classify();\n      if (next !== state) {\n        state = next;\n        api.onState?.(state);\n      }\n    },\n  };\n\n  solve();\n  paint();\n  return api;\n}\n\n/**\n * The temperature a mixer actually delivers when the cold has been taken away.\n *\n * Published on its own because it is the one sum in this module worth knowing\n * without a plumbing system attached: `mix` is what the tap was set to, and\n * `coldLeft` is the fraction of the cold flow that survived somebody else\n * opening something.\n */\nexport function mixedAt(\n  mix: number,\n  hotTemp: number,\n  coldTemp: number,\n  coldLeft = 1\n): number {\n  const h = clamp01(mix);\n  const c = (1 - h) * clamp01(coldLeft);\n  if (h + c <= 1e-9) return coldTemp;\n  return (h * hotTemp + c * coldTemp) / (h + c);\n}\n\n/** The mixer setting that gives a wanted temperature. */\nexport function mixFor(want: number, hotTemp: number, coldTemp: number): number {\n  const span = hotTemp - coldTemp;\n  if (Math.abs(span) < 1e-6) return 0;\n  return clamp01((want - coldTemp) / span);\n}\n","import {\n  BoxGeometry,\n  BufferAttribute,\n  BufferGeometry,\n  Color,\n  ConeGeometry,\n  CylinderGeometry,\n  DoubleSide,\n  Group,\n  Mesh,\n  MeshBasicMaterial,\n} from 'three';\nimport { createSurface } from '../materials/surface';\nimport type { Prop } from '../core/types';\n\n/**\n * A public address — the first prop in this library that reaches the ear.\n *\n * Everything until now has been seen. A hull, a light, a derrick, a boiler:\n * all of them are things you look at, and the ones that answer questions\n * about a point in space — `heatAt`, `smokeAt`, `depthAt` — answer them about\n * where a *body* is. Sound is the first field where the interesting number is\n * about what a **person** can do there: whether they can talk, whether they\n * can stay, how long before it costs them something.\n *\n * ```ts\n * const pa = createPA({ era: 'array', power: 118 });\n * pa.levelAt(0, 100);      // 93 dB(A), a hundred metres back\n * pa.stateAt(0, 100);      // 'harmful'\n * pa.earshotAt(0, 100);    // 0.18 m — you shout into an ear or you don't talk\n * pa.exposureAt(0, 100);   // 4 500 s before the day's dose is gone\n * ```\n *\n * ## Distance is a filter, not a volume knob\n *\n * The one fact everybody has met and almost nobody models: from far enough\n * away, a band is **all bass**. That is not an artistic choice about mixing,\n * it is air. Absorption is strongly frequency-dependent — about 0.004 dB/m at\n * 125 Hz and 0.15 dB/m at 4 kHz — so over 800 m the bass loses 3 dB and the\n * top loses a hundred and twenty:\n *\n * ```ts\n *      3 m   bass 110   mid 111   treble 110     a band\n *    100 m   bass  85   mid  92   treble  83     a band, further off\n *    300 m   bass  74   mid  77   treble  47     a PA, over there\n *    800 m   bass  64   mid  55   treble  33     a thud, two streets away\n * ```\n *\n * Model sound as one number that falls off with range and you get a quiet\n * band. It is not a quiet band. It is a **different band**, and that is why\n * `bandsAt` exists next to `levelAt`.\n *\n * ## What it costs the person standing there\n *\n * The states are not `'off' | 'low' | 'high'` — that is a fact about the\n * amplifier. They are what a person has to do:\n *\n * | state | |\n * | --- | --- |\n * | `quiet` | you can talk |\n * | `raised` | you are raising your voice and have not noticed |\n * | `shouting` | you shout into an ear, or you do not talk |\n * | `harmful` | the day's safe dose runs out in under four hours |\n *\n * ## The era axis: what the front row pays for the back row\n *\n * A PA has exactly one hard problem, and it is not power. It is that the\n * front row and the back row are the same system. Cover 200 m to a usable\n * 75 dB(A) at the back and ask what that does to the people at the barrier:\n *\n * | era | front row | safe for |\n * | --- | --- | --- |\n * | `horn` | 113 dB(A) | 49 seconds |\n * | `hifi` | 114 dB(A) | 35 seconds |\n * | `array` | 105 dB(A) | 5 minutes |\n * | `delayed` | 91 dB(A) | 2 hours |\n *\n * `delayed` is the inversion at the end of the axis, in the same shape as the\n * gyro stabiliser and the thermostatic mixer: **it does not make the PA\n * louder, it stops the loudness having to reach that far** — and the bill is\n * paid in a completely different currency, which is *time*. Get a delay wrong\n * and every one of those people hears an echo.\n */\n\n/** How the sound is thrown. */\nexport type PAEra =\n  /** Horns on a pole. Efficient, directional, and no bass at all. */\n  | 'horn'\n  /** A pair of full-range stacks. A point source: 6 dB per doubling. */\n  | 'hifi'\n  /** A line array. Cylindrical near field: 3 dB per doubling, while it lasts. */\n  | 'array'\n  /** An array plus delay towers downfield. The front row stops paying. */\n  | 'delayed';\n\n/**\n * Three bands, because one number cannot say what distance does to sound.\n *\n * Centred at 125 Hz, 1 kHz and 4 kHz — low enough to diffract round a wall,\n * the region speech lives in, and the region air eats.\n */\nexport type Band = 'bass' | 'mid' | 'treble';\n\n/** What it costs to stand there. Measured in the person, not the amplifier. */\nexport type LoudnessState = 'quiet' | 'raised' | 'shouting' | 'harmful';\n\n/**\n * What two arrivals of the same sound do to each other.\n *\n * `clean` — one source, nothing to interfere with.\n * `comb` — under 5 ms apart: not an echo, a *filter*. Hollow and phasey.\n * `fused` — the precedence effect. Two arrivals, one apparent source.\n * `echo` — over 40 ms: you hear the sound twice, and you cannot unhear it.\n */\nexport type EchoState = 'clean' | 'comb' | 'fused' | 'echo';\n\n/** Unweighted sound pressure level in each band, dB re 20 µPa. */\nexport interface BandLevels {\n  bass: number;\n  mid: number;\n  treble: number;\n}\n\n/**\n * How loud it is at a world point.\n *\n * The fifth spatial handshake, after `depthAt`, `heatAt`, `chillAt` and\n * `smokeAt`, and deliberately the same shape. SCENA says how loud it is\n * there; ANIMA decides whether a character has to shout and GAMA decides\n * whether an agent wants to be there.\n */\nexport interface SoundField {\n  /** A-weighted sound pressure level at a world point, dB(A). */\n  levelAt(x: number, z: number): number;\n}\n\n/** A hang, a stack, or a delay tower. */\nexport interface SourceSpec {\n  /** World position. Defaults to the PA's own origin. */\n  x?: number;\n  z?: number;\n  /** Height of the acoustic centre above ground, metres. */\n  height?: number;\n  /** Facing, radians, 0 = +z. Defaults to the PA's facing. */\n  facing?: number;\n  /** On-axis sound pressure level at 1 m, dB. */\n  power?: number;\n  /**\n   * Vertical extent of the radiating source, metres. 0 for a point source.\n   * A line array's near field — where it loses 3 dB per doubling instead of\n   * 6 — extends to about `length² · f / 2c`, so a longer hang keeps its level\n   * further out, and keeps it further out *for the top than for the bottom*.\n   */\n  length?: number;\n  /** Electronic delay, seconds. See `alignDelays`. */\n  delay?: number;\n}\n\n/**\n * A wall between a source and an ear.\n *\n * A line in plan with a height — which is all a barrier is acoustically. It\n * is not drawn: this is a fact about the sound, in the same way `heightAt` is\n * a fact about the ground, and whatever put the wall there draws it.\n */\nexport interface BarrierSpec {\n  /** One end, in world coordinates. */\n  x1: number;\n  z1: number;\n  /** The other end. */\n  x2: number;\n  z2: number;\n  /** Height of the top edge above ground, metres. */\n  height: number;\n}\n\nexport interface PAOptions {\n  era?: PAEra;\n  /** On-axis SPL at 1 m of the main hang, dB. Defaults per era. */\n  power?: number;\n  /** World position of the main hang. */\n  x?: number;\n  z?: number;\n  /** Height of the main hang's acoustic centre, metres. */\n  height?: number;\n  /** Facing, radians. 0 = +z, which is the direction the crowd is in. */\n  facing?: number;\n  /** Ear height for every query, metres. */\n  earHeight?: number;\n  /** Background level with the PA silent, dB(A). */\n  ambient?: number;\n  /** How much of full output the programme is asking for, 0–1. */\n  program?: number;\n  /** For `delayed`: how many towers, and how far downfield the field runs. */\n  towers?: number;\n  fieldLength?: number;\n}\n\n/** What one source contributes at a point. */\nexport interface SoundArrival {\n  name: string;\n  /** A-weighted contribution, dB(A). */\n  level: number;\n  /** When it gets there: flight time plus electronic delay, seconds. */\n  arrival: number;\n}\n\nexport interface EchoReading {\n  /** Milliseconds between the first and last audible arrival. */\n  spread: number;\n  state: EchoState;\n  /** How many arrivals are within 15 dB of the loudest. */\n  arrivals: number;\n}\n\nexport interface PublicAddress extends Prop, SoundField {\n  readonly era: PAEra;\n  /** Every source, mains first. */\n  readonly names: string[];\n\n  /** A-weighted level at a world point, dB(A). */\n  levelAt(x: number, z: number): number;\n  /** Unweighted level in each band at a world point, dB. */\n  bandsAt(x: number, z: number): BandLevels;\n  /** What it costs to stand there. */\n  stateAt(x: number, z: number): LoudnessState;\n  /** Seconds of the daily noise dose that point spends per second. */\n  exposureAt(x: number, z: number): number;\n  /** Metres at which a shout is still intelligible there. */\n  earshotAt(x: number, z: number): number;\n  /** What the arrivals do to each other there. */\n  echoAt(x: number, z: number): EchoReading;\n  /** Every source's contribution at a point, loudest first. */\n  arrivalsAt(x: number, z: number): SoundArrival[];\n\n  /** How far down the axis the level stays at or above `target` dB(A). */\n  reach(target?: number): number;\n  /** The level at the barrier — `distance` metres down the axis. */\n  frontRow(distance?: number): number;\n\n  /** Add a source. Returns its name. */\n  tower(name: string, spec?: SourceSpec): string;\n  /** Register a wall. Barriers shadow every source. */\n  barrier(name: string, spec: BarrierSpec): void;\n  /** Forget a wall. */\n  clearBarrier(name: string): void;\n\n  setPower(name: string, dB: number): void;\n  setDelay(name: string, seconds: number): void;\n  /** How hard the programme is driving it, 0–1. 0 is silence. */\n  setProgram(level: number): void;\n\n  /**\n   * Set every tower's delay from its distance to the mains, plus `haas`.\n   *\n   * The extra offset is the whole trick: aligned to the arithmetic and no\n   * more, the two arrivals land within a millisecond of each other and comb.\n   * Ten or fifteen milliseconds late and the mains arrive first, so the sound\n   * still comes from the stage.\n   */\n  alignDelays(haas?: number): void;\n\n  /**\n   * Turn every source down as far as it will go and still cover the field.\n   *\n   * Each source is sized for the end of its own zone, in order — which is\n   * what a system tech does, and what makes the era axis a fair comparison\n   * rather than four different volume settings.\n   */\n  cover(length: number, target?: number): void;\n\n  /** Paint the field. Grey-blue → green → amber → red, by state. */\n  showCoverage(on: boolean, opts?: { width?: number; depth?: number; cell?: number }): void;\n\n  update(dt: number): void;\n}\n\n// ---------------------------------------------------------------------------\n// The physics\n// ---------------------------------------------------------------------------\n\n/** Speed of sound, m/s, at 20 °C. */\nexport const SPEED_OF_SOUND = 343;\n\nconst BANDS: Band[] = ['bass', 'mid', 'treble'];\n\n/** Band centre frequencies, Hz. */\nexport const BAND_HZ: Record<Band, number> = { bass: 125, mid: 1000, treble: 4000 };\n\n/**\n * Air absorption, dB per metre, at 20 °C and 50 % relative humidity.\n *\n * Nearly forty times worse at 4 kHz than at 125 Hz, and that ratio is the\n * whole reason a distant PA is a thud.\n */\nexport const AIR_ABSORPTION: Record<Band, number> = { bass: 0.004, mid: 0.028, treble: 0.15 };\n\n/**\n * A-weighting at the band centres, dB.\n *\n * The ear is nearly deaf to bass at low levels, and the weighting says so:\n * −16 dB at 125 Hz. Which is also why a festival can measure legal on a\n * dB(A) meter at the site boundary while the people two streets away lie\n * awake — everything they can hear is in the band the meter discounts.\n */\nexport const A_WEIGHTING: Record<Band, number> = { bass: -16.1, mid: 0, treble: 1.0 };\n\n/**\n * Most a thin barrier can take off, per band.\n *\n * Diffraction over the top is not the only path: some of it comes straight\n * through the panel, and transmission loss follows the mass law — 6 dB per\n * doubling of frequency. So a wall has a floor, and the floor is lowest\n * exactly where the diffraction is weakest.\n */\nexport const BARRIER_CAP: Record<Band, number> = { bass: 18, mid: 24, treble: 28 };\n\n/** Below this a person can hold a conversation. */\nexport const QUIET = 62;\n/** Above this they must shout to be heard at all. */\nexport const SHOUTING = 78;\n/** Above this the day's dose runs out in under four hours. */\nexport const HARMFUL = 88;\n/** A shout, at one metre, dB(A). */\nexport const SHOUT_AT_1M = 78;\n\n/** Energy sum of decibel values. */\nexport function sumDecibels(values: number[]): number {\n  let total = 0;\n  for (const v of values) total += Math.pow(10, v / 10);\n  return total <= 0 ? -Infinity : 10 * Math.log10(total);\n}\n\n/**\n * Spreading loss at range `r`, dB.\n *\n * A point source loses 6 dB per doubling — the surface of the sphere the\n * energy is spread over goes as r². A line source loses **3**, because near\n * enough to it the wavefront is a cylinder, not a sphere. That is the entire\n * argument for a line array, and it holds only out to the array's near-field\n * limit, which is proportional to frequency: a 6 m hang holds the top up to\n * 210 m and the bass to 6 m. Which is why the back of a festival gets a thin,\n * mid-heavy sound and the subs are a separate problem.\n */\nexport function spreadingLoss(r: number, length: number, band: Band): number {\n  const d = Math.max(1, r);\n  if (length <= 0) return 20 * Math.log10(d);\n  const critical = (length * length * BAND_HZ[band]) / (2 * SPEED_OF_SOUND);\n  if (critical <= 1) return 20 * Math.log10(d);\n  if (d <= critical) return 10 * Math.log10(d);\n  return 10 * Math.log10(critical) + 20 * Math.log10(d / critical);\n}\n\n/**\n * Maekawa's barrier attenuation, dB, from the path-length difference.\n *\n * The number that matters is the **Fresnel number** `N = 2δ/λ`: how many\n * half-wavelengths of extra path the sound has to take to get over the top.\n * A 3 m wall against a 4 kHz wavelength of 86 mm is an obstacle; against a\n * 125 Hz wavelength of 2.7 m it is barely there. `blocked` is false when the\n * ear can see the source over the wall — attenuation then falls away over the\n * transition zone rather than stopping dead, because being in line of sight\n * is not the same as being clear of the first Fresnel zone.\n */\nexport function barrierLoss(delta: number, band: Band, blocked: boolean): number {\n  const N = ((blocked ? 2 : -2) * Math.max(0, delta) * BAND_HZ[band]) / SPEED_OF_SOUND;\n  if (N < -0.2) return 0;\n  if (N < 0) return 5 * (1 + N / 0.2);\n  return Math.min(BARRIER_CAP[band], 10 * Math.log10(3 + 20 * N));\n}\n\n/**\n * Seconds at `dBA` before the day's noise dose is used up.\n *\n * 85 dB(A) for eight hours, and a 3 dB exchange rate — every 3 dB halves the\n * time, because 3 dB is twice the energy. Which makes 100 dB(A) a quarter of\n * an hour and the front row of a badly designed PA a matter of seconds.\n */\nexport function exposureLimit(dBA: number): number {\n  return 8 * 3600 * Math.pow(2, (85 - dBA) / 3);\n}\n\n/** Metres at which a shout is still intelligible against `dBA` of noise. */\nexport function earshot(dBA: number): number {\n  return Math.pow(10, (SHOUT_AT_1M - dBA) / 20);\n}\n\n/** Classify a level in what it costs the person standing there. */\nexport function loudnessState(dBA: number): LoudnessState {\n  if (dBA >= HARMFUL) return 'harmful';\n  if (dBA >= SHOUTING) return 'shouting';\n  if (dBA >= QUIET) return 'raised';\n  return 'quiet';\n}\n\n// ---------------------------------------------------------------------------\n\ninterface EraSpec {\n  power: number;\n  length: number;\n  band: Record<Band, number>;\n  /** Half-angle at which the source is 6 dB down, degrees. */\n  half: number;\n  towers: number;\n  towerLength: number;\n}\n\nconst ERAS: Record<PAEra, EraSpec> = {\n  // A horn is the most efficient loudspeaker there is and cannot do bass:\n  // the mouth would have to be metres across. Speech carries; music does not.\n  horn: {\n    power: 105, length: 0, half: 30, towers: 0, towerLength: 0,\n    band: { bass: -25, mid: 0, treble: -8 },\n  },\n  hifi: {\n    power: 112, length: 0, half: 50, towers: 0, towerLength: 0,\n    band: { bass: -2, mid: 0, treble: -2 },\n  },\n  array: {\n    power: 118, length: 6, half: 55, towers: 0, towerLength: 3,\n    band: { bass: -1, mid: 0, treble: 0 },\n  },\n  delayed: {\n    power: 118, length: 6, half: 55, towers: 2, towerLength: 3,\n    band: { bass: -1, mid: 0, treble: 0 },\n  },\n};\n\ninterface Source {\n  name: string;\n  x: number;\n  z: number;\n  height: number;\n  facing: number;\n  power: number;\n  length: number;\n  delay: number;\n  band: Record<Band, number>;\n  half: number;\n  object: Group;\n  meter: Mesh | null;\n}\n\ninterface Barrier extends BarrierSpec {\n  name: string;\n}\n\nconst STATE_COLOUR: Record<LoudnessState, number> = {\n  quiet: 0x3a4a5e,\n  raised: 0x3f7a4a,\n  shouting: 0xc08a2a,\n  harmful: 0xb03428,\n};\n\nfunction angleDiff(a: number, b: number): number {\n  let d = a - b;\n  while (d > Math.PI) d -= Math.PI * 2;\n  while (d < -Math.PI) d += Math.PI * 2;\n  return d;\n}\n\n/** Where two plan segments cross, or null. */\nfunction segmentCross(\n  px: number, pz: number, qx: number, qz: number,\n  ax: number, az: number, bx: number, bz: number,\n): { x: number; z: number } | null {\n  const rx = qx - px, rz = qz - pz;\n  const sx = bx - ax, sz = bz - az;\n  const den = rx * sz - rz * sx;\n  if (Math.abs(den) < 1e-9) return null;\n  const t = ((ax - px) * sz - (az - pz) * sx) / den;\n  const u = ((ax - px) * rz - (az - pz) * rx) / den;\n  if (t < 0 || t > 1 || u < 0 || u > 1) return null;\n  return { x: px + t * rx, z: pz + t * rz };\n}\n\nexport function createPA(options: PAOptions = {}): PublicAddress {\n  const era = options.era ?? 'array';\n  const spec = ERAS[era];\n  const originX = options.x ?? 0;\n  const originZ = options.z ?? 0;\n  const facing = options.facing ?? 0;\n  const earHeight = options.earHeight ?? 1.6;\n  const ambient = options.ambient ?? 45;\n  const fieldLength = options.fieldLength ?? 200;\n  const towerCount = options.towers ?? spec.towers;\n\n  const group = new Group();\n  group.position.set(originX, 0, originZ);\n  group.rotation.y = facing;\n\n  const sources: Source[] = [];\n  const barriers = new Map<string, Barrier>();\n  let program = options.program ?? 1;\n  let elapsed = 0;\n\n  const boxMat = createSurface('paintedMetal', { baseColor: 0x1b1c20 });\n  const grilleMat = createSurface('metal', { baseColor: 0x2c2e34 });\n  const steelMat = createSurface('steel', { baseColor: 0x6a6d74 });\n  const hornMat = createSurface('brass', {});\n  const meterMat = new MeshBasicMaterial({ color: 0x7fe08a });\n\n  // -- visuals -------------------------------------------------------------\n\n  /** A speaker box: a black trapezoid with a grille face. */\n  function makeBox(w: number, h: number, d: number): Group {\n    const g = new Group();\n    const body = new Mesh(new BoxGeometry(w, h, d), boxMat);\n    g.add(body);\n    const grille = new Mesh(new BoxGeometry(w * 0.86, h * 0.78, 0.02), grilleMat);\n    grille.position.z = d / 2 + 0.011;\n    g.add(grille);\n    return g;\n  }\n\n  function makeMeter(): Mesh {\n    const m = new Mesh(new BoxGeometry(0.5, 0.06, 0.03), meterMat);\n    return m;\n  }\n\n  /** Four legs and cross-braces — a scaffold tower. */\n  function makeScaffold(height: number, width = 1.6): Group {\n    const g = new Group();\n    const leg = new CylinderGeometry(0.05, 0.05, height, 6);\n    for (const [sx, sz] of [[-1, -1], [1, -1], [-1, 1], [1, 1]] as const) {\n      const l = new Mesh(leg, steelMat);\n      l.position.set((sx * width) / 2, height / 2, (sz * width) / 2);\n      g.add(l);\n    }\n    const rungs = Math.max(2, Math.round(height / 1.8));\n    for (let i = 1; i <= rungs; i++) {\n      const y = (height * i) / (rungs + 1);\n      for (const axis of [0, 1]) {\n        const r = new Mesh(new BoxGeometry(axis ? 0.05 : width, 0.05, axis ? width : 0.05), steelMat);\n        r.position.set(0, y, axis ? 0 : 0);\n        g.add(r);\n      }\n    }\n    return g;\n  }\n\n  /** Era-specific geometry for the main hang. */\n  function buildMains(height: number, length: number): Group {\n    const g = new Group();\n    if (era === 'horn') {\n      g.add(makeScaffold(height));\n      for (let i = 0; i < 4; i++) {\n        const cone = new Mesh(new ConeGeometry(0.42, 0.9, 10), hornMat);\n        cone.rotation.x = -Math.PI / 2;\n        cone.position.set(0, height, 0.5);\n        cone.rotation.z = (i / 4) * Math.PI * 2;\n        const arm = new Group();\n        arm.rotation.y = ((i - 1.5) / 4) * 1.4;\n        arm.add(cone);\n        g.add(arm);\n      }\n      return g;\n    }\n    if (era === 'hifi') {\n      for (const side of [-1, 1]) {\n        const stack = new Group();\n        stack.position.set(side * 3.2, 0, 0);\n        stack.rotation.y = -side * 0.28;\n        const sub = makeBox(1.3, 0.8, 1.0);\n        sub.position.y = 0.4;\n        stack.add(sub);\n        for (let i = 0; i < 3; i++) {\n          const b = makeBox(1.0, 0.7, 0.8);\n          b.position.y = 0.8 + 0.7 * i + 0.35;\n          stack.add(b);\n        }\n        g.add(stack);\n      }\n      return g;\n    }\n    // array / delayed: a hang either side, subs on the deck between them\n    for (const side of [-1, 1]) {\n      const hang = new Group();\n      hang.position.set(side * 4.2, 0, 0);\n      const top = height + length / 2;\n      const boxes = Math.max(4, Math.round(length / 0.42));\n      for (let i = 0; i < boxes; i++) {\n        const t = i / (boxes - 1);\n        const b = makeBox(1.15, length / boxes - 0.02, 0.62);\n        b.position.y = top - (length * (i + 0.5)) / boxes;\n        // A hang is curved: the lower boxes are tilted down at the near field.\n        b.rotation.x = -0.05 - t * t * 0.55;\n        b.position.z = t * t * 0.35;\n        hang.add(b);\n      }\n      const bumper = new Mesh(new BoxGeometry(1.5, 0.12, 0.7), steelMat);\n      bumper.position.y = top + 0.1;\n      hang.add(bumper);\n      hang.add(makeScaffold(top + 0.2, 1.2));\n      for (let i = 0; i < 3; i++) {\n        const sub = makeBox(1.25, 0.75, 1.05);\n        sub.position.set(-side * 1.6 - side * i * 1.3, 0.38, -0.4);\n        hang.add(sub);\n      }\n      g.add(hang);\n    }\n    return g;\n  }\n\n  function buildTower(height: number, length: number): Group {\n    const g = new Group();\n    g.add(makeScaffold(height, 1.3));\n    const boxes = Math.max(3, Math.round(length / 0.4));\n    for (let i = 0; i < boxes; i++) {\n      const b = makeBox(0.85, length / boxes - 0.02, 0.5);\n      b.position.y = height + length / 2 - (length * (i + 0.5)) / boxes;\n      b.rotation.x = -0.08 - (i / boxes) * 0.5;\n      g.add(b);\n    }\n    return g;\n  }\n\n  // -- sources -------------------------------------------------------------\n\n  function addSource(name: string, s: SourceSpec, mains: boolean): Source {\n    const height = s.height ?? (mains ? (options.height ?? 6) : 5);\n    const length = s.length ?? (mains ? spec.length : spec.towerLength);\n    const object = mains ? buildMains(height, length) : buildTower(height, length);\n    const x = s.x ?? originX;\n    const z = s.z ?? originZ;\n    // Sources live in world coordinates but hang under the PA's group, which\n    // is itself rotated — so undo the rotation to place them.\n    const dx = x - originX;\n    const dz = z - originZ;\n    const c = Math.cos(-facing);\n    const sn = Math.sin(-facing);\n    object.position.set(dx * c + dz * sn, 0, -dx * sn + dz * c);\n    object.rotation.y = (s.facing ?? facing) - facing;\n    const meter = makeMeter();\n    meter.position.set(0, height + length + 0.35, 0);\n    object.add(meter);\n    group.add(object);\n    const src: Source = {\n      name, x, z, height,\n      facing: s.facing ?? facing,\n      power: s.power ?? (mains ? (options.power ?? spec.power) : spec.power - 12),\n      length,\n      delay: s.delay ?? 0,\n      band: spec.band,\n      half: spec.half,\n      object,\n      meter,\n    };\n    sources.push(src);\n    return src;\n  }\n\n  addSource('mains', {}, true);\n\n  // -- the field -----------------------------------------------------------\n\n  /** Worst loss any registered barrier imposes on this path, per band. */\n  function barrierAttenuation(s: Source, rx: number, rz: number): Record<Band, number> | null {\n    let worst: Record<Band, number> | null = null;\n    for (const b of barriers.values()) {\n      const cross = segmentCross(s.x, s.z, rx, rz, b.x1, b.z1, b.x2, b.z2);\n      if (!cross) continue;\n      const ds = Math.hypot(cross.x - s.x, cross.z - s.z);\n      const dr = Math.hypot(cross.x - rx, cross.z - rz);\n      const t = ds / Math.max(1e-6, ds + dr);\n      // Where the direct ray passes the wall line. Above the top edge and the\n      // ear can see the source; the barrier still shades the bass, because\n      // line of sight is not the same as clear of the first Fresnel zone.\n      const rayY = s.height + (earHeight - s.height) * t;\n      const A = Math.hypot(ds, b.height - s.height);\n      const B = Math.hypot(dr, b.height - earHeight);\n      const D = Math.hypot(ds + dr, earHeight - s.height);\n      const delta = Math.max(0, A + B - D);\n      const blocked = b.height > rayY;\n      const loss: Record<Band, number> = { bass: 0, mid: 0, treble: 0 };\n      for (const band of BANDS) loss[band] = barrierLoss(delta, band, blocked);\n      if (!worst) worst = loss;\n      else for (const band of BANDS) worst[band] = Math.max(worst[band], loss[band]);\n    }\n    return worst;\n  }\n\n  interface Contribution {\n    name: string;\n    band: Record<Band, number>;\n    dba: number;\n    arrival: number;\n  }\n\n  function contribute(s: Source, x: number, z: number): Contribution {\n    const dx = x - s.x;\n    const dz = z - s.z;\n    const plan = Math.hypot(dx, dz);\n    const dy = s.height - earHeight;\n    const slant = Math.max(1, Math.hypot(plan, dy));\n    const theta = plan < 1e-6 ? 0 : Math.abs(angleDiff(Math.atan2(dx, dz), s.facing)) * (180 / Math.PI);\n    const off = Math.min(30, 6 * Math.pow(theta / s.half, 2));\n    const att = barrierAttenuation(s, x, z);\n    const drive = program <= 0 ? -Infinity : 20 * Math.log10(program);\n    const band: Record<Band, number> = { bass: 0, mid: 0, treble: 0 };\n    for (const b of BANDS) {\n      band[b] = s.power + drive + s.band[b]\n        - spreadingLoss(slant, s.length, b)\n        - AIR_ABSORPTION[b] * slant\n        - off\n        - (att ? att[b] : 0);\n    }\n    return {\n      name: s.name,\n      band,\n      dba: sumDecibels(BANDS.map((b) => band[b] + A_WEIGHTING[b])),\n      arrival: slant / SPEED_OF_SOUND + s.delay,\n    };\n  }\n\n  const contributions = (x: number, z: number): Contribution[] =>\n    sources.map((s) => contribute(s, x, z));\n\n  const levelAt = (x: number, z: number): number =>\n    sumDecibels([...contributions(x, z).map((c) => c.dba), ambient]);\n\n  function bandsAt(x: number, z: number): BandLevels {\n    const cs = contributions(x, z);\n    const floor = ambient - 12;\n    return {\n      bass: Math.max(floor, sumDecibels(cs.map((c) => c.band.bass))),\n      mid: Math.max(floor, sumDecibels(cs.map((c) => c.band.mid))),\n      treble: Math.max(floor, sumDecibels(cs.map((c) => c.band.treble))),\n    };\n  }\n\n  function echoAt(x: number, z: number): EchoReading {\n    const cs = contributions(x, z);\n    if (cs.length < 2) return { spread: 0, state: 'clean', arrivals: cs.length };\n    const loudest = Math.max(...cs.map((c) => c.dba));\n    // A second arrival 15 dB down is still perfectly audible as an echo — it\n    // is the *delay* that makes it audible, not the level.\n    const heard = cs.filter((c) => c.dba > loudest - 15).map((c) => c.arrival);\n    if (heard.length < 2) return { spread: 0, state: 'clean', arrivals: heard.length };\n    const spread = (Math.max(...heard) - Math.min(...heard)) * 1000;\n    const state: EchoState = spread < 5 ? 'comb' : spread < 40 ? 'fused' : 'echo';\n    return { spread, state, arrivals: heard.length };\n  }\n\n  /** Unit vector down the PA's axis. */\n  const axis = () => ({ x: Math.sin(facing), z: Math.cos(facing) });\n\n  function onAxis(distance: number): { x: number; z: number } {\n    const a = axis();\n    return { x: originX + a.x * distance, z: originZ + a.z * distance };\n  }\n\n  function reach(target = QUIET): number {\n    let lo = 0.5;\n    let hi = 4000;\n    const at = (d: number) => {\n      const p = onAxis(d);\n      return levelAt(p.x, p.z);\n    };\n    if (at(lo) < target) return 0;\n    for (let i = 0; i < 70; i++) {\n      const m = (lo + hi) / 2;\n      if (at(m) >= target) lo = m;\n      else hi = m;\n    }\n    return lo;\n  }\n\n  // -- tuning --------------------------------------------------------------\n\n  function alignDelays(haas = 0.012): void {\n    const mains = sources[0];\n    for (const s of sources) {\n      if (s === mains) continue;\n      const d = Math.hypot(s.x - mains.x, s.z - mains.z);\n      s.delay = d / SPEED_OF_SOUND + haas;\n    }\n    dirty = true;\n  }\n\n  function cover(length: number, target = 75): void {\n    const a = axis();\n    // Order the sources by how far down the axis they sit; each one is then\n    // responsible for the stretch between it and the next.\n    const along = (s: Source) => (s.x - originX) * a.x + (s.z - originZ) * a.z;\n    const order = [...sources].sort((p, q) => along(p) - along(q));\n    for (let i = 0; i < order.length; i++) {\n      const s = order[i];\n      const end = i + 1 < order.length ? along(order[i + 1]) : length;\n      const p = onAxis(end);\n      // Everything past this source is not helping yet; mute it while we size\n      // this one, or a loud tower downfield hides the hole in front of it.\n      const held = order.slice(i + 1).map((o) => o.power);\n      for (const o of order.slice(i + 1)) o.power = -200;\n      let lo = 40;\n      let hi = 150;\n      for (let k = 0; k < 60; k++) {\n        const m = (lo + hi) / 2;\n        s.power = m;\n        if (levelAt(p.x, p.z) < target) lo = m;\n        else hi = m;\n      }\n      s.power = lo;\n      order.slice(i + 1).forEach((o, k) => { o.power = held[k]; });\n    }\n    dirty = true;\n  }\n\n  // -- coverage grid -------------------------------------------------------\n\n  let coverage: Mesh | null = null;\n  let coverageOpts = { width: 120, depth: 220, cell: 8 };\n  let dirty = false;\n\n  function buildCoverage(): void {\n    if (coverage) {\n      group.remove(coverage);\n      coverage.geometry.dispose();\n      coverage = null;\n    }\n    const { width, depth, cell } = coverageOpts;\n    const nx = Math.max(1, Math.round(width / cell));\n    const nz = Math.max(1, Math.round(depth / cell));\n    const pos = new Float32Array(nx * nz * 18);\n    const col = new Float32Array(nx * nz * 18);\n    const a = axis();\n    const c = new Color();\n    let p = 0;\n    let q = 0;\n    for (let iz = 0; iz < nz; iz++) {\n      for (let ix = 0; ix < nx; ix++) {\n        const lx = -width / 2 + (ix + 0.5) * cell;\n        const lz = (iz + 0.5) * cell;\n        // Local (PA) space to world, to ask the field the right question.\n        const wx = originX + lx * a.z + lz * a.x;\n        const wz = originZ - lx * a.x + lz * a.z;\n        c.setHex(STATE_COLOUR[loudnessState(levelAt(wx, wz))]);\n        const h = cell / 2 - 0.35;\n        const corners: Array<[number, number]> = [\n          [lx - h, lz - h], [lx + h, lz - h], [lx + h, lz + h],\n          [lx - h, lz - h], [lx + h, lz + h], [lx - h, lz + h],\n        ];\n        for (const [cx, cz] of corners) {\n          pos[p++] = cx; pos[p++] = 0.06; pos[p++] = cz;\n          col[q++] = c.r; col[q++] = c.g; col[q++] = c.b;\n        }\n      }\n    }\n    const geo = new BufferGeometry();\n    geo.setAttribute('position', new BufferAttribute(pos, 3));\n    geo.setAttribute('color', new BufferAttribute(col, 3));\n    geo.computeVertexNormals();\n    coverage = new Mesh(geo, new MeshBasicMaterial({ vertexColors: true, side: DoubleSide }));\n    coverage.renderOrder = -1;\n    group.add(coverage);\n  }\n\n  // -- the prop ------------------------------------------------------------\n\n  const find = (name: string): Source | undefined => sources.find((s) => s.name === name);\n\n  const pa: PublicAddress = {\n    object: group,\n    obstacleRadius: era === 'horn' ? 1.2 : 5.5,\n    era,\n    get names() { return sources.map((s) => s.name); },\n\n    levelAt,\n    bandsAt,\n    stateAt: (x, z) => loudnessState(levelAt(x, z)),\n    exposureAt: (x, z) => exposureLimit(levelAt(x, z)),\n    earshotAt: (x, z) => earshot(levelAt(x, z)),\n    echoAt,\n    arrivalsAt: (x, z) =>\n      contributions(x, z)\n        .map((c) => ({ name: c.name, level: c.dba, arrival: c.arrival }))\n        .sort((p, q) => q.level - p.level),\n\n    reach,\n    frontRow(distance = 3) {\n      const p = onAxis(distance);\n      return levelAt(p.x, p.z);\n    },\n\n    tower(name, s = {}) {\n      addSource(name, s, false);\n      dirty = true;\n      return name;\n    },\n    barrier(name, s) {\n      barriers.set(name, { ...s, name });\n      dirty = true;\n    },\n    clearBarrier(name) {\n      barriers.delete(name);\n      dirty = true;\n    },\n\n    setPower(name, dB) {\n      const s = find(name);\n      if (s) s.power = dB;\n      dirty = true;\n    },\n    setDelay(name, seconds) {\n      const s = find(name);\n      if (s) s.delay = Math.max(0, seconds);\n      dirty = true;\n    },\n    setProgram(level) {\n      program = Math.max(0, Math.min(1, level));\n      dirty = true;\n    },\n\n    alignDelays,\n    cover,\n\n    showCoverage(on, opts) {\n      if (opts) coverageOpts = { ...coverageOpts, ...opts };\n      if (!on) {\n        if (coverage) {\n          group.remove(coverage);\n          coverage.geometry.dispose();\n          coverage = null;\n        }\n        return;\n      }\n      buildCoverage();\n    },\n\n    update(dt) {\n      elapsed += dt;\n      if (dirty && coverage) {\n        buildCoverage();\n        dirty = false;\n      }\n      // A meter that only says \"there is programme\": the level is a fact about\n      // the source, not about the frame, so it must not integrate `dt`.\n      for (const s of sources) {\n        if (!s.meter) continue;\n        const drive = program * (0.55 + 0.45 * Math.sin(elapsed * 6.1 + s.x * 0.7));\n        s.meter.scale.x = Math.max(0.001, drive);\n        (s.meter.material as MeshBasicMaterial).color.setHex(\n          drive > 0.85 ? 0xe05a3c : drive > 0.6 ? 0xe0c04a : 0x7fe08a,\n        );\n        s.meter.visible = program > 0.01;\n      }\n    },\n  };\n\n  if (towerCount > 0) {\n    const a = axis();\n    for (let i = 1; i <= towerCount; i++) {\n      const d = (fieldLength * i) / (towerCount + 1);\n      pa.tower(`tower${i}`, { x: originX + a.x * d, z: originZ + a.z * d });\n    }\n    alignDelays();\n  }\n\n  return pa;\n}\n","import {\n  BoxGeometry,\n  CircleGeometry,\n  ConeGeometry,\n  CylinderGeometry,\n  Group,\n  Mesh,\n  MeshBasicMaterial,\n  MeshStandardMaterial,\n  SphereGeometry,\n  TorusGeometry,\n} from 'three';\nimport { Rng } from '../core/random';\nimport { createSurface } from '../materials/surface';\nimport { createSlot, type Prop } from '../core/types';\nimport { AIR_ABSORPTION, A_WEIGHTING, spreadingLoss, sumDecibels, type SoundField } from './sound';\n\n/**\n * The woofer — the first prop in this library that is not all here.\n *\n * Everything else in the trilogy is simulated: a boiler makes steam out of\n * numbers this library owns, a hull floats on arithmetic, and even the PA is\n * a field computed from a power figure. Operate this and it plays **web\n * radio** — a stream from outside the process and outside the frame clock,\n * that keeps playing whether or not anybody is looking, that buffers, drops\n * and dies, and that no amount of correct local code can make reliable.\n *\n * ```ts\n * const rig = createWoofer({ seed: 7 });\n * const floor = createDanceTiles({ cols: 10, rows: 8 });\n * scene.add(rig.object, floor.object);\n *\n * // THE interaction. First touch starts the radio; the next touches tune.\n * canvas.addEventListener('pointerdown', () => rig.operate());\n *\n * game.onUpdate((t) => {\n *   rig.update(t.delta);\n *   floor.feed(rig.pulse());   // and the DJ tiles come alive\n *   floor.update(t.delta);\n * });\n * ```\n *\n * ## The dropout is the design problem\n *\n * A stream fails four ways — it takes a moment to start, it rebuffers, the\n * station dies, the CORS handshake refuses — and a dance floor that freezes\n * whenever the network hiccups is a network monitor wearing a glitter ball.\n * So the rig has a **bed**: a seeded, deterministic beat that runs under\n * everything, takes the floor whenever the stream cannot, and hands back the\n * moment it can. The states say who is driving:\n *\n * | state | who has the floor |\n * | --- | --- |\n * | `off` | nobody. The cones are still. |\n * | `demo` | the bed, by choice — no radio was asked for. |\n * | `tuning` | the bed, while the stream buffers its first seconds. |\n * | `live` | **the radio.** The one state this module cannot fake. |\n * | `holding` | the bed, because the stream stalled — and the tiles never knew. |\n *\n * `holding` is the inversion at the end of this axis, in the same shape as\n * the thermostatic mixer and the delay tower: it does not stop the dropout,\n * it stops the dropout **reaching the floor**, and the bill is paid in\n * honesty — what you are hearing is not the radio, and `state` says so.\n *\n * ## Where the pulse comes from\n *\n * Live, the pulse is measured off the actual audio with an analyser: bass /\n * mid / treble energy plus a beat detector watching for the kick. In every\n * other state it comes from the bed. Either way `pulse()` has the same shape,\n * which is the whole point — the tiles do not know, and must not know, where\n * the music is coming from.\n *\n * ## What runs where\n *\n * - **A browser, after a user gesture** — the real thing. Autoplay policy\n *   means nothing sounds until somebody interacts, which is not a bug to\n *   fight: the rig is off until somebody turns it on.\n * - **A browser, no gesture yet / headless** — `demo`. The bed drives the\n *   tiles, deterministically, so the picture is alive and verifiable with no\n *   network and no audio device.\n * - **Node (the tests)** — there is no `Audio` here at all. The bed is pure\n *   arithmetic and the whole state machine is testable through an injected\n *   fake stream.\n *\n * The default stations are SomaFM channels, which send the CORS header that\n * lets a `MediaElementAudioSourceNode` actually read the samples. Point\n * `tune()` at a station without that header and the element itself refuses\n * to load — which arrives as an error, which is a `holding`, which the floor\n * survives. That failure path is the module.\n */\n\n/** Who currently has the floor. */\nexport type WooferState = 'off' | 'demo' | 'tuning' | 'live' | 'holding';\n\n/** A web radio channel. */\nexport interface RadioStation {\n  name: string;\n  /** Stream URL. Must send CORS headers for the analyser to read anything. */\n  url: string;\n  /** Rough words for what plays there. */\n  genre: string;\n}\n\n/**\n * SomaFM, because they are listener-supported, run for decades, and — the\n * property that matters here — send `Access-Control-Allow-Origin` on their\n * streams, so the analyser can actually see the music it is playing.\n */\nexport const RADIO_STATIONS: RadioStation[] = [\n  { name: 'Groove Salad', url: 'https://ice1.somafm.com/groovesalad-128-mp3', genre: 'ambient beats' },\n  { name: 'Beat Blender', url: 'https://ice1.somafm.com/beatblender-128-mp3', genre: 'deep house' },\n  { name: 'DEF CON Radio', url: 'https://ice1.somafm.com/defcon-128-mp3', genre: 'hacker electronica' },\n  { name: 'The Trip', url: 'https://ice1.somafm.com/thetrip-128-mp3', genre: 'progressive house' },\n  { name: 'Drone Zone', url: 'https://ice1.somafm.com/dronezone-128-mp3', genre: 'atmospheres' },\n];\n\n/** One reading of the music, wherever it is coming from. */\nexport interface AudioPulse {\n  /** Band energies, 0–1. */\n  bass: number;\n  mid: number;\n  treble: number;\n  /** True on the frame a kick landed. */\n  beat: boolean;\n  /** Estimated tempo, beats per minute. 0 until there is one. */\n  bpm: number;\n}\n\n/**\n * The seam a live stream plugs in through — and the seam a test fakes.\n *\n * Everything above this line is deterministic and runs anywhere; only an\n * implementation of this interface ever touches the network or an audio\n * device. If the module needed a real stream to be exercised, the module\n * would be designed wrong.\n */\nexport interface RadioMedia {\n  /** Point at a stream and start loading. */\n  tune(url: string): void;\n  /** Try to start. Rejects when autoplay policy or the network says no. */\n  play(): Promise<void>;\n  pause(): void;\n  /** 'playing' | 'waiting' | 'error' — the three transitions that matter. */\n  on(event: 'playing' | 'waiting' | 'error', cb: () => void): void;\n  /** Measured band energies, or null while there is nothing to measure. */\n  bands(): { bass: number; mid: number; treble: number } | null;\n}\n\nexport interface WooferOptions {\n  seed?: number;\n  /** Stations `operate()` cycles through. Default: `RADIO_STATIONS`. */\n  stations?: RadioStation[];\n  /** Bed tempo, BPM. Default seeded 118–128. */\n  bpm?: number;\n  /** On-axis dB at 1 m when flat out, for `levelAt`. Default 106. */\n  power?: number;\n  /** Inject a stream implementation (tests). Default: Web Audio, if present. */\n  media?: RadioMedia;\n}\n\nexport interface Woofer extends Prop, SoundField {\n  readonly state: WooferState;\n  readonly stations: RadioStation[];\n  /** The station tuned, or null before the first `play`. */\n  readonly station: RadioStation | null;\n  /** Bed tempo (and the reported bpm while the bed drives). */\n  readonly bpm: number;\n\n  /**\n   * THE interaction. Off → start the radio; playing → tune the next station.\n   * Wire this to the click/use — it is what a person does to a sound system.\n   */\n  operate(): void;\n  /** Start the radio (or the bed, where there is no radio to be had). */\n  play(station?: RadioStation | number): void;\n  /** Silence, and the cones stop. */\n  stop(): void;\n  /** Next station round the dial. */\n  tune(): void;\n  /** The dial, both ways. `next()` is `tune()` with its partner. */\n  next(): void;\n  prev(): void;\n  /** Fired whenever the tuned station changes. Returns the unsubscribe. */\n  onStation(cb: (station: RadioStation) => void): () => void;\n\n  /** The music, now. Same shape whoever has the floor. */\n  pulse(): AudioPulse;\n  /** Overall drive 0–1 — feed it to a PA's `setProgram`. */\n  level(): number;\n  /** dB(A) at a world point, while she plays. The AQ handshake, kept. */\n  levelAt(x: number, z: number): number;\n  /** Fired on every kick. Returns the unsubscribe. */\n  onBeat(cb: () => void): () => void;\n\n  update(dt: number): void;\n}\n\n// ---------------------------------------------------------------------------\n// The bed: a deterministic groove\n// ---------------------------------------------------------------------------\n\n/**\n * Four to the floor, hats on the off-beat, a mid line that moves — all a pure\n * function of accumulated time, so the same seed is the same night out and a\n * headless verifier sees the same frames a browser does.\n */\nexport function bedPulse(t: number, bpm: number): { bass: number; mid: number; treble: number } {\n  const beats = (t * bpm) / 60;\n  const inBeat = beats % 1;\n  const bar = Math.floor(beats / 4);\n  // The kick: a sharp attack that has mostly died by the off-beat.\n  const kick = Math.exp(-inBeat * 6.5);\n  // Every fourth bar the kick drops out for the last beat — a fill, and a\n  // test that the beat detector recovers rather than free-wheeling.\n  const drop = bar % 4 === 3 && beats % 4 >= 3;\n  const bass = drop ? 0.12 : 0.2 + 0.8 * kick;\n  const hat = Math.exp(-((beats + 0.5) % 1) * 9);\n  const treble = 0.08 + 0.55 * hat + (drop ? 0.3 : 0);\n  const mid = clamp01(\n    0.34 + 0.2 * Math.sin(t * 0.9) + 0.14 * Math.sin(beats * Math.PI * 0.5) + 0.08 * Math.sin(t * 2.63)\n  );\n  return { bass: clamp01(bass), mid, treble: clamp01(treble) };\n}\n\nconst clamp01 = (v: number): number => (v < 0 ? 0 : v > 1 ? 1 : v);\n\n// ---------------------------------------------------------------------------\n// The beat detector\n// ---------------------------------------------------------------------------\n\n/**\n * A kick is bass energy standing clear of its own recent average. The\n * detector is shared by every source — the bed does not get to *announce*\n * its beats, it has to be heard, or `live` and `demo` would disagree about\n * what a beat is.\n */\nfunction makeBeatDetector() {\n  const window: number[] = [];\n  let sinceBeat = Infinity;\n  const gaps: number[] = [];\n  let lastAt = -1;\n  let clock = 0;\n  return {\n    step(bass: number, dt: number): boolean {\n      clock += dt;\n      sinceBeat += dt;\n      window.push(bass);\n      if (window.length > 45) window.shift();\n      const mean = window.reduce((a, b) => a + b, 0) / window.length;\n      // Clear of the average, loud in its own right, and not an echo of the\n      // kick we just counted: a refractory quarter-second, or 240 BPM would\n      // read as 480.\n      const isBeat = bass > mean * 1.3 && bass > 0.45 && sinceBeat > 0.25;\n      if (isBeat) {\n        if (lastAt >= 0) {\n          gaps.push(clock - lastAt);\n          if (gaps.length > 8) gaps.shift();\n        }\n        lastAt = clock;\n        sinceBeat = 0;\n      }\n      return isBeat;\n    },\n    bpm(): number {\n      if (gaps.length < 3) return 0;\n      const sorted = [...gaps].sort((a, b) => a - b);\n      return 60 / sorted[Math.floor(sorted.length / 2)];\n    },\n  };\n}\n\n// ---------------------------------------------------------------------------\n// The default RadioMedia: Web Audio, when the world has it\n// ---------------------------------------------------------------------------\n\n/** Build the real thing, or null where there is no audio to be had. */\nfunction makeWebRadio(): RadioMedia | null {\n  const g = globalThis as {\n    Audio?: new () => HTMLAudioElement;\n    AudioContext?: new () => AudioContext;\n  };\n  if (!g.Audio || !g.AudioContext) return null;\n  const el = new g.Audio();\n  el.crossOrigin = 'anonymous';\n  el.preload = 'auto';\n  let ctx: AudioContext | null = null;\n  let analyser: AnalyserNode | null = null;\n  let data: Uint8Array | null = null;\n\n  const ensureGraph = () => {\n    if (ctx) return;\n    // The graph is built lazily, inside the first play() — which is inside a\n    // user gesture, which is the only place an AudioContext may start.\n    ctx = new g.AudioContext!();\n    const src = ctx.createMediaElementSource(el);\n    analyser = ctx.createAnalyser();\n    analyser.fftSize = 1024;\n    analyser.smoothingTimeConstant = 0.55;\n    src.connect(analyser);\n    analyser.connect(ctx.destination);\n    data = new Uint8Array(analyser.frequencyBinCount);\n  };\n\n  const bandOf = (lo: number, hi: number): number => {\n    if (!ctx || !analyser || !data) return 0;\n    const hz = ctx.sampleRate / 2 / data.length;\n    const a = Math.max(0, Math.floor(lo / hz));\n    const b = Math.min(data.length - 1, Math.ceil(hi / hz));\n    let sum = 0;\n    for (let i = a; i <= b; i++) sum += data[i];\n    return clamp01(sum / ((b - a + 1) * 255) * 1.6);\n  };\n\n  return {\n    tune(url) {\n      el.src = url;\n      el.load();\n    },\n    async play() {\n      ensureGraph();\n      await ctx!.resume();\n      await el.play();\n    },\n    pause() {\n      el.pause();\n    },\n    on(event, cb) {\n      // 'stalled' and 'waiting' are the same fact at different layers.\n      el.addEventListener(event, cb);\n      if (event === 'waiting') el.addEventListener('stalled', cb);\n    },\n    bands() {\n      if (!analyser || !data || el.paused) return null;\n      analyser.getByteFrequencyData(data as Uint8Array<ArrayBuffer>);\n      return { bass: bandOf(35, 180), mid: bandOf(180, 2000), treble: bandOf(2000, 9000) };\n    },\n  };\n}\n\n// ---------------------------------------------------------------------------\n// The prop\n// ---------------------------------------------------------------------------\n\nexport function createWoofer(options: WooferOptions = {}): Woofer {\n  const rng = new Rng(options.seed ?? 1);\n  const stations = options.stations ?? RADIO_STATIONS;\n  const bpm = options.bpm ?? rng.int(118, 128);\n  const power = options.power ?? 106;\n  // `media` may be injected (tests), found (browser), or absent (Node) — and\n  // everything below has to be indifferent to which.\n  const media = options.media ?? makeWebRadio() ?? undefined;\n\n  let state: WooferState = 'off';\n  let stationIdx = -1;\n  let elapsed = 0;\n  let last: AudioPulse = { bass: 0, mid: 0, treble: 0, beat: false, bpm: 0 };\n  const detector = makeBeatDetector();\n  const beatCbs = new Set<() => void>();\n  const stationCbs = new Set<(s: RadioStation) => void>();\n\n  if (media) {\n    media.on('playing', () => {\n      if (state === 'tuning' || state === 'holding') state = 'live';\n    });\n    // Both of these mean the same thing to the floor: the bed takes over.\n    // A stall hands back on 'playing'; an error waits for the next tune.\n    media.on('waiting', () => {\n      if (state === 'live') state = 'holding';\n    });\n    media.on('error', () => {\n      if (state !== 'off' && state !== 'demo') state = 'holding';\n    });\n  }\n\n  // -- visuals -------------------------------------------------------------\n\n  const group = new Group();\n  const cabinetMat = createSurface('paintedMetal', { baseColor: 0x181a1e });\n  const grilleMat = createSurface('metal', { baseColor: 0x24262c });\n  const coneMat = new MeshStandardMaterial({ color: 0x2e3138, roughness: 0.65, flatShading: true });\n  const capMat = new MeshStandardMaterial({ color: 0x101114, roughness: 0.4, metalness: 0.35 });\n  const trimMat = new MeshStandardMaterial({ color: 0x8a8f98, roughness: 0.5, metalness: 0.6 });\n  const lampMat = new MeshBasicMaterial({ color: 0x22252a });\n\n  // The cabinet: fridge-sized, because the user asked for a BIG woofer and a\n  // hi-fi bookshelf box reads as furniture.\n  const W = 1.7;\n  const H = 1.9;\n  const D = 0.95;\n  const cabinet = new Mesh(new BoxGeometry(W, H, D), cabinetMat);\n  cabinet.position.y = H / 2;\n  group.add(cabinet);\n  const face = new Mesh(new BoxGeometry(W * 0.92, H * 0.92, 0.03), grilleMat);\n  face.position.set(0, H / 2, D / 2 + 0.016);\n  group.add(face);\n\n  // Two drivers, and the cones PUMP — scale is cheap and reads at any range.\n  const cones: Mesh[] = [];\n  for (const [cy, r] of [\n    [H * 0.66, 0.52],\n    [H * 0.27, 0.34],\n  ] as const) {\n    const ring = new Mesh(new TorusGeometry(r, 0.045, 8, 28), trimMat);\n    ring.position.set(0, cy, D / 2 + 0.04);\n    group.add(ring);\n    const cone = new Mesh(new ConeGeometry(r * 0.96, 0.26, 28, 1, true), coneMat);\n    cone.rotation.x = Math.PI / 2;\n    cone.position.set(0, cy, D / 2 + 0.04);\n    group.add(cone);\n    const cap = new Mesh(new SphereGeometry(r * 0.24, 12, 8), capMat);\n    cap.position.set(0, cy, D / 2 + 0.1);\n    group.add(cap);\n    cones.push(cone, cap);\n  }\n\n  // A bass port either side of the big driver, and an ON-AIR lamp.\n  for (const side of [-1, 1]) {\n    const port = new Mesh(new CircleGeometry(0.09, 16), capMat);\n    port.position.set(side * W * 0.36, H * 0.9, D / 2 + 0.035);\n    group.add(port);\n  }\n  const lamp = new Mesh(new BoxGeometry(0.3, 0.07, 0.03), lampMat);\n  lamp.position.set(0, H + 0.001 - 0.06, D / 2 + 0.02);\n  group.add(lamp);\n\n  // THE CHANNEL SELECTOR: one LED per station across the top of the cabinet,\n  // the tuned one lit. A dial you can read from across the room — because a\n  // toggle whose current position is invisible is a coin, not a control.\n  const ledGeo = new BoxGeometry(0.09, 0.05, 0.02);\n  const leds: MeshBasicMaterial[] = [];\n  {\n    const n = stations.length;\n    for (let i = 0; i < n; i++) {\n      const mat = new MeshBasicMaterial({ color: 0x2a2d33 });\n      const led = new Mesh(ledGeo, mat);\n      led.position.set((i - (n - 1) / 2) * 0.16, H - 0.18, D / 2 + 0.02);\n      group.add(led);\n      leds.push(mat);\n    }\n  }\n  const feet = new Mesh(new CylinderGeometry(0.05, 0.06, 0.06, 8), capMat);\n  feet.position.set(0, 0.03, 0);\n  group.add(feet);\n\n  const slot = createSlot('operate', 'operate', group, 0, 0, D / 2 + 0.8, Math.PI);\n\n  // -- behaviour -----------------------------------------------------------\n\n  const play = (which?: RadioStation | number): void => {\n    const before = stationIdx;\n    if (typeof which === 'number') stationIdx = ((which % stations.length) + stations.length) % stations.length;\n    else if (which) stationIdx = Math.max(0, stations.indexOf(which));\n    else if (stationIdx < 0) stationIdx = 0;\n    if (stationIdx !== before && stationIdx >= 0)\n      for (const cb of stationCbs) cb(stations[stationIdx]);\n    if (!media || stations.length === 0) {\n      // Nowhere for a stream to come from: the bed IS the show, and says so.\n      state = 'demo';\n      return;\n    }\n    state = 'tuning';\n    media.tune(stations[stationIdx].url);\n    // A rejected play() is autoplay policy or a dead stream — same answer:\n    // the bed holds the floor and the state does not lie about it.\n    media.play().catch(() => {\n      if (state === 'tuning') state = 'holding';\n    });\n  };\n\n  const woofer: Woofer = {\n    object: group,\n    obstacleRadius: Math.hypot(W, D) / 2 + 0.1,\n    slots: [slot],\n    get state() {\n      return state;\n    },\n    stations,\n    get station() {\n      return stationIdx >= 0 ? stations[stationIdx] : null;\n    },\n    bpm,\n\n    operate() {\n      if (state === 'off') play();\n      else woofer.tune();\n    },\n    play,\n    stop() {\n      media?.pause();\n      state = 'off';\n      last = { bass: 0, mid: 0, treble: 0, beat: false, bpm: 0 };\n    },\n    tune() {\n      if (stations.length === 0) return;\n      play((stationIdx < 0 ? 0 : stationIdx + 1) % stations.length);\n    },\n    next() {\n      woofer.tune();\n    },\n    prev() {\n      if (stations.length === 0) return;\n      play(stationIdx < 0 ? stations.length - 1 : stationIdx - 1 + stations.length);\n    },\n    onStation(cb) {\n      stationCbs.add(cb);\n      return () => stationCbs.delete(cb);\n    },\n\n    pulse: () => last,\n    level: () => clamp01(last.bass * 0.55 + last.mid * 0.3 + last.treble * 0.15),\n    levelAt(x, z) {\n      const drive = woofer.level();\n      if (drive <= 0.001) return 0;\n      const dx = x - group.position.x;\n      const dz = z - group.position.z;\n      const r = Math.max(1, Math.hypot(dx, dz));\n      // A single cabinet is the simplest case AQ models: a point source, with\n      // the woofer's own balance for a spectrum. Same physics, same units, so\n      // a GAMA agent can treat a party and a festival as one kind of fact.\n      const dB = (band: 'bass' | 'mid' | 'treble', at: number) =>\n        power + 20 * Math.log10(Math.max(0.02, at * drive)) - spreadingLoss(r, 0, band) - AIR_ABSORPTION[band] * r;\n      return sumDecibels([\n        dB('bass', last.bass) + A_WEIGHTING.bass,\n        dB('mid', last.mid) + A_WEIGHTING.mid,\n        dB('treble', last.treble) + A_WEIGHTING.treble,\n      ]);\n    },\n    onBeat(cb) {\n      beatCbs.add(cb);\n      return () => beatCbs.delete(cb);\n    },\n\n    update(dt) {\n      if (state === 'off') {\n        for (const c of cones) c.scale.setScalar(1);\n        lampMat.color.setHex(0x22252a);\n        leds.forEach((m) => m.color.setHex(0x2a2d33));\n        return;\n      }\n      leds.forEach((m, i) => m.color.setHex(i === stationIdx ? 0x4ad0ff : 0x2a2d33));\n      elapsed += dt;\n      // WHO HAS THE FLOOR. Live asks the stream; if the analyser has nothing\n      // yet (first buffers), the bed covers the gap without a state change.\n      const liveBands = state === 'live' ? media?.bands() ?? null : null;\n      const bands = liveBands ?? bedPulse(elapsed, bpm);\n      const beat = detector.step(bands.bass, dt);\n      last = {\n        ...bands,\n        beat,\n        bpm: state === 'live' ? detector.bpm() : bpm,\n      };\n      if (beat) for (const cb of beatCbs) cb();\n\n      // The cones pump with the bass, the lamp says who is driving.\n      const pump = 1 + last.bass * 0.16;\n      for (const c of cones) c.scale.setScalar(pump);\n      lampMat.color.setHex(\n        state === 'live' ? 0xe0483a : state === 'holding' ? 0xe0a83a : 0x3ac06a\n      );\n    },\n  };\n\n  return woofer;\n}\n\n// ---------------------------------------------------------------------------\n// The DJ tiles\n// ---------------------------------------------------------------------------\n\nexport interface DanceTilesOptions {\n  seed?: number;\n  cols?: number;\n  rows?: number;\n  /** Tile pitch, metres. Default 0.9. */\n  size?: number;\n}\n\nexport interface DanceTiles {\n  object: Group;\n  /** True once something has fed it a live pulse. */\n  readonly activated: boolean;\n  /** Hand the floor this frame's music. */\n  feed(pulse: AudioPulse): void;\n  /** Fade the lit pattern along. Call every frame. */\n  update(dt: number): void;\n  /** How many tiles are lit past half right now. */\n  litCount(): number;\n}\n\n/**\n * The floor the woofer is for. A grid of emissive tiles: the kick throws a\n * ring out from the centre, the treble sparkles the corners, the mid sets\n * how warm the floor idles. It knows nothing about radios, networks or\n * states — it eats `AudioPulse` and that is the entire coupling, which is\n * why a dropout upstream never reaches it.\n */\nexport function createDanceTiles(options: DanceTilesOptions = {}): DanceTiles {\n  const rng = new Rng(options.seed ?? 1);\n  const cols = options.cols ?? 8;\n  const rows = options.rows ?? 8;\n  const size = options.size ?? 0.9;\n\n  const group = new Group();\n  const geo = new BoxGeometry(size * 0.92, 0.06, size * 0.92);\n  interface Tile {\n    mesh: Mesh;\n    mat: MeshStandardMaterial;\n    /** 0–1 light level, decaying. */\n    lit: number;\n    hue: number;\n    ring: number;\n  }\n  const tiles: Tile[] = [];\n  const cx = (cols - 1) / 2;\n  const cz = (rows - 1) / 2;\n  const maxRing = Math.hypot(cx, cz);\n  for (let r = 0; r < rows; r++) {\n    for (let c = 0; c < cols; c++) {\n      const mat = new MeshStandardMaterial({\n        color: 0x15171b,\n        emissive: 0x000000,\n        roughness: 0.35,\n        metalness: 0.1,\n        flatShading: true,\n      });\n      const mesh = new Mesh(geo, mat);\n      mesh.position.set((c - cx) * size, 0.03, (r - cz) * size);\n      group.add(mesh);\n      tiles.push({ mesh, mat, lit: 0, hue: rng.next(), ring: Math.hypot(c - cx, r - cz) });\n    }\n  }\n\n  let activated = false;\n  let ringFront = -1; // beat rings travel outward; negative = no ring running\n  let warmth = 0;\n  let hueBase = rng.next();\n\n  const paint = (t: Tile) => {\n    // Hue drifts with the night; brightness is the tile's own decay.\n    const h = (hueBase + t.hue * 0.14 + t.ring * 0.04) % 1;\n    const v = t.lit;\n    // Cheap HSV→RGB, saturated: a dance floor is not tasteful.\n    const i = Math.floor(h * 6);\n    const f = h * 6 - i;\n    const q = 1 - f;\n    const [r, g, b] = [\n      [1, f, 0], [q, 1, 0], [0, 1, f], [0, q, 1], [f, 0, 1], [1, 0, q],\n    ][i % 6];\n    t.mat.emissive.setRGB(r * v, g * v, b * v);\n    t.mat.color.setRGB(0.08 + r * v * 0.25, 0.08 + g * v * 0.25, 0.09 + b * v * 0.25);\n  };\n\n  return {\n    object: group,\n    get activated() {\n      return activated;\n    },\n    feed(pulse) {\n      const energy = pulse.bass + pulse.mid + pulse.treble;\n      if (energy <= 0.02) return;\n      activated = true;\n      warmth = pulse.mid;\n      if (pulse.beat) {\n        ringFront = 0;\n        hueBase = (hueBase + 0.07) % 1;\n      }\n      // Treble sparkles: a few random tiles flare, more when the hats are hot.\n      const sparks = Math.floor(pulse.treble * 4);\n      for (let i = 0; i < sparks; i++) {\n        const t = tiles[rng.int(0, tiles.length - 1)];\n        t.lit = Math.max(t.lit, 0.65 + pulse.treble * 0.35);\n      }\n    },\n    update(dt) {\n      if (ringFront >= 0) {\n        // The kick's ring sweeps outward at eight tiles a second.\n        ringFront += dt * 8;\n        for (const t of tiles) {\n          if (Math.abs(t.ring - ringFront) < 0.75) t.lit = Math.max(t.lit, 1);\n        }\n        if (ringFront > maxRing + 1) ringFront = -1;\n      }\n      const floorGlow = activated ? 0.05 + warmth * 0.1 : 0;\n      for (const t of tiles) {\n        t.lit = Math.max(floorGlow, t.lit - dt * 2.4);\n        paint(t);\n      }\n    },\n    litCount: () => tiles.reduce((n, t) => n + (t.lit > 0.5 ? 1 : 0), 0),\n  };\n}\n","import {\n  BoxGeometry,\n  CylinderGeometry,\n  Group,\n  Mesh,\n  MeshStandardMaterial,\n  Object3D,\n  Quaternion,\n  SphereGeometry,\n  Vector3,\n} from 'three';\nimport { Rng } from '../core/random';\nimport { createSurface } from '../materials/surface';\nimport type { Prop } from '../core/types';\n\n/**\n * The shala — a place to practice.\n *\n * A yoga centre is the quietest gathering this library has: no seats, no\n * table, no fire — a deck, a grid of mats, and an orientation. The\n * orientation is the point. Surya namaskar faces the sun, so the shala\n * takes a **sunrise bearing** and lays every student mat facing it, with\n * the instructor's mat out front facing back at the class — the same\n * geometry a class controller (ANIMA's `YogaClass`) produces on its own,\n * offered here as a *place* instead of a formula.\n *\n * ```ts\n * const shala = createShala({ era: 'retreat', students: 8, sunrise: 0.4 });\n * shala.object.position.set(10, 0, -4);\n * scene.add(shala.object);\n *\n * // The handshake: one spot per mat, in WORLD space, instructor first.\n * for (const [i, spot] of shala.matSpots().entries()) {\n *   rigs[i].object.position.set(spot.x, deckTop, spot.z);\n *   rigs[i].object.rotation.y = spot.facing;\n * }\n * ```\n *\n * ## Eras\n *\n * Like the PA stacks, the shala has eras — the same practice, four rooms:\n *\n * - **ashram** — sandstone deck between carved columns, a low ashlar wall\n *   at the back, bronze finials. The oldest room.\n * - **studio** — parquet floor, a mirror wall with a barre. The room that\n *   rents by the hour.\n * - **rooftop** — concrete pad, perimeter railing, string lights sagging\n *   between the posts. The room with a skyline.\n * - **retreat** — teak planks under a bamboo pergola, planters at the\n *   corners, open on every side. The room that is barely a room.\n *\n * ## The spots are world-space, on purpose\n *\n * `matSpots()` converts through the prop's current transform at call time:\n * move or rotate the shala and the spots move with it, facing included.\n * Index 0 is always the instructor's mat. The deck is walk-through\n * (`obstacleRadius` 0) — a platform is a floor, not an obstacle.\n */\n\nexport type ShalaEra = 'ashram' | 'studio' | 'rooftop' | 'retreat';\n\nexport const SHALA_ERAS: ShalaEra[] = ['ashram', 'studio', 'rooftop', 'retreat'];\n\nexport interface ShalaOptions {\n  seed?: number;\n  /** Which room. Default: a seeded pick. */\n  era?: ShalaEra;\n  /** Student mats. Default 8. */\n  students?: number;\n  /** Mats per row. Default 4. */\n  perRow?: number;\n  /** Bearing of the sunrise about +Y, radians — the class faces it. Default 0 (+Z). */\n  sunrise?: number;\n}\n\n/** One mat's stand-here, in world space. Index 0 is the instructor. */\nexport interface MatSpot {\n  x: number;\n  z: number;\n  /** World yaw to stand at. Students face the sunrise; the instructor faces them. */\n  facing: number;\n}\n\nexport interface Shala extends Prop {\n  era: ShalaEra;\n  /** One spot per mat, world-space, converted at call time. Instructor first. */\n  matSpots(): MatSpot[];\n  /** A point above the instructor's mat — aim the class's gaze here. */\n  focus: Object3D;\n  /** Height of the deck surface above the prop's origin. */\n  deckTop: number;\n}\n\nconst MAT_COLORS = [0x7a4f9e, 0x3e7d78, 0x8a6d3b, 0x9e5540, 0x4f5d9e, 0x6b8747];\n\nexport function createShala(options: ShalaOptions = {}): Shala {\n  const rng = new Rng(options.seed ?? 1);\n  const era = options.era ?? SHALA_ERAS[Math.floor(rng.next() * SHALA_ERAS.length)];\n  const students = Math.max(1, options.students ?? 8);\n  const perRow = Math.max(1, options.perRow ?? 4);\n  const sunrise = options.sunrise ?? 0;\n  const rows = Math.ceil(students / perRow);\n  const spacing = 1.7;\n  const rowGap = 2.3;\n\n  const group = new Group();\n  group.name = 'shala';\n  // Everything practice-shaped lives in an inner group rotated to the\n  // sunrise, so the deck, the dressing and the mats all agree with it.\n  const room = new Group();\n  room.rotation.y = sunrise;\n  group.add(room);\n\n  // --- The floor plan, in practice space (+Z = the sun).\n  const width = Math.max(Math.min(students, perRow) * spacing + 2.4, 6.2);\n  const instructorZ = (rows * rowGap) / 2 + 0.6;\n  const backZ = instructorZ - 1.9 - (rows - 1) * rowGap - 1.6;\n  const depth = instructorZ - backZ + 2.6;\n  const midZ = (instructorZ + backZ) / 2;\n  const deckH = 0.14;\n\n  const deckKind =\n    era === 'ashram' ? 'sandstone' : era === 'studio' ? 'parquet' : era === 'rooftop' ? 'concrete' : 'teak';\n  const deck = new Mesh(\n    new BoxGeometry(width, deckH, depth),\n    createSurface(deckKind, { seed: options.seed ?? 1 })\n  );\n  deck.name = 'deck';\n  deck.position.set(0, deckH / 2, midZ);\n  room.add(deck);\n\n  // --- Mats: laid neatly, which for humans means ALMOST neatly. The\n  // visual jitter stays out of the anchors — a class aligns to the spots,\n  // not to the millimetre a mat was dropped.\n  const matGeo = new BoxGeometry(0.66, 0.022, 1.95);\n  const anchors: Object3D[] = [];\n  const layMat = (x: number, z: number, facing: number, color: number): void => {\n    const mat = new Mesh(\n      matGeo,\n      new MeshStandardMaterial({ color, roughness: 0.96, flatShading: true })\n    );\n    mat.name = 'mat';\n    mat.position.set(x + rng.range(-0.04, 0.04), deckH + 0.011, z + rng.range(-0.04, 0.04));\n    mat.rotation.y = facing + rng.range(-0.035, 0.035);\n    room.add(mat);\n    const anchor = new Object3D();\n    anchor.name = 'matSpot';\n    anchor.position.set(x, deckH, z);\n    anchor.rotation.y = facing;\n    room.add(anchor);\n    anchors.push(anchor);\n  };\n\n  // Instructor first: out front, facing the class (back to the sun).\n  layMat(0, instructorZ, Math.PI, 0xb5623a);\n  for (let i = 0; i < students; i++) {\n    const row = Math.floor(i / perRow);\n    const inRow = Math.min(perRow, students - row * perRow);\n    const lat = ((i % perRow) - (inRow - 1) / 2) * spacing;\n    layMat(lat, instructorZ - 1.9 - row * rowGap, 0, MAT_COLORS[Math.floor(rng.next() * MAT_COLORS.length)]);\n  }\n\n  const focus = new Object3D();\n  focus.name = 'focus';\n  focus.position.set(0, 1.2, instructorZ);\n  room.add(focus);\n\n  // --- Era dressing.\n  const halfW = width / 2;\n  if (era === 'ashram') {\n    const columns = new Group();\n    columns.name = 'columns';\n    const colGeo = new CylinderGeometry(0.14, 0.17, 2.5, 8);\n    const capGeo = new SphereGeometry(0.14, 8, 6);\n    const stone = createSurface('sandstone', { seed: 2 });\n    const bronze = createSurface('bronze', { seed: 3 });\n    for (let side = -1; side <= 1; side += 2) {\n      for (let i = 0; i < 3; i++) {\n        const z = backZ + 1.0 + (i * (depth - 2.0)) / 2;\n        const col = new Mesh(colGeo, stone);\n        col.position.set(side * (halfW - 0.35), deckH + 1.25, z);\n        columns.add(col);\n        const cap = new Mesh(capGeo, bronze);\n        cap.position.set(side * (halfW - 0.35), deckH + 2.6, z);\n        columns.add(cap);\n      }\n    }\n    const wall = new Mesh(new BoxGeometry(width, 0.9, 0.3), createSurface('ashlar', { seed: 4 }));\n    wall.position.set(0, deckH + 0.45, backZ + 0.15);\n    columns.add(wall);\n    room.add(columns);\n  } else if (era === 'studio') {\n    const wallGroup = new Group();\n    wallGroup.name = 'mirror';\n    const wall = new Mesh(new BoxGeometry(width, 2.5, 0.16), createSurface('plaster', { seed: 2 }));\n    wall.position.set(0, deckH + 1.25, backZ + 0.08);\n    wallGroup.add(wall);\n    // The mirror: no reflections in a low-poly world, and FULL metalness\n    // with nothing to reflect renders black — so this stays a cold bright\n    // half-metal, which reads as glass from every angle that matters.\n    const mirror = new Mesh(\n      new BoxGeometry(width - 0.8, 1.9, 0.03),\n      new MeshStandardMaterial({ color: 0xdde9f4, roughness: 0.1, metalness: 0.45 })\n    );\n    mirror.position.set(0, deckH + 1.35, backZ + 0.18);\n    wallGroup.add(mirror);\n    const barre = new Mesh(\n      new CylinderGeometry(0.03, 0.03, width - 1.2, 8),\n      createSurface('teak', { seed: 5 })\n    );\n    barre.rotation.z = Math.PI / 2;\n    barre.position.set(0, deckH + 1.0, backZ + 0.34);\n    wallGroup.add(barre);\n    room.add(wallGroup);\n  } else if (era === 'rooftop') {\n    const railing = new Group();\n    railing.name = 'railing';\n    const steel = createSurface('steel', { seed: 2 });\n    const postGeo = new BoxGeometry(0.05, 1.05, 0.05);\n    const railGeo = new BoxGeometry(1, 0.05, 0.05);\n    const run = (x0: number, z0: number, x1: number, z1: number): void => {\n      const len = Math.hypot(x1 - x0, z1 - z0);\n      const posts = Math.max(2, Math.round(len / 1.4) + 1);\n      for (let i = 0; i < posts; i++) {\n        const t = i / (posts - 1);\n        const post = new Mesh(postGeo, steel);\n        post.position.set(x0 + (x1 - x0) * t, deckH + 0.52, z0 + (z1 - z0) * t);\n        railing.add(post);\n      }\n      const rail = new Mesh(railGeo, steel);\n      rail.scale.x = len;\n      rail.position.set((x0 + x1) / 2, deckH + 1.05, (z0 + z1) / 2);\n      rail.rotation.y = Math.atan2(-(z1 - z0), x1 - x0);\n      railing.add(rail);\n      // String lights: small warm bulbs on a sagging line under the rail.\n      const bulbs = Math.max(3, Math.round(len / 0.8));\n      const bulbGeo = new SphereGeometry(0.035, 6, 5);\n      for (let i = 1; i < bulbs; i++) {\n        const t = i / bulbs;\n        const sag = Math.sin(t * Math.PI) * 0.16;\n        const bulb = new Mesh(\n          bulbGeo,\n          new MeshStandardMaterial({ color: 0xffe6b8, emissive: 0xffb35a, emissiveIntensity: 1.6 })\n        );\n        bulb.position.set(x0 + (x1 - x0) * t, deckH + 0.98 - sag, z0 + (z1 - z0) * t);\n        railing.add(bulb);\n      }\n    };\n    // Three sides — the sunrise side stays open. That is what the roof is for.\n    run(-halfW + 0.1, backZ + 0.1, halfW - 0.1, backZ + 0.1);\n    run(-halfW + 0.1, backZ + 0.1, -halfW + 0.1, midZ + depth / 2 - 0.1);\n    run(halfW - 0.1, backZ + 0.1, halfW - 0.1, midZ + depth / 2 - 0.1);\n    room.add(railing);\n  } else {\n    const pergola = new Group();\n    pergola.name = 'pergola';\n    const bamboo = createSurface('bark', { seed: 2, color: 0xa88d54 });\n    const postGeo = new CylinderGeometry(0.07, 0.08, 2.6, 7);\n    const frontZ = midZ + depth / 2 - 0.5;\n    const rearZ = backZ + 0.5;\n    for (const [px, pz] of [\n      [-halfW + 0.5, rearZ], [halfW - 0.5, rearZ],\n      [-halfW + 0.5, frontZ], [halfW - 0.5, frontZ],\n    ]) {\n      const post = new Mesh(postGeo, bamboo);\n      post.position.set(px, deckH + 1.3, pz);\n      pergola.add(post);\n    }\n    const beamGeo = new CylinderGeometry(0.055, 0.055, width - 0.6, 7);\n    for (const bz of [rearZ, frontZ]) {\n      const beam = new Mesh(beamGeo, bamboo);\n      beam.rotation.z = Math.PI / 2;\n      beam.position.set(0, deckH + 2.62, bz);\n      pergola.add(beam);\n    }\n    const slatGeo = new CylinderGeometry(0.03, 0.03, frontZ - rearZ + 0.7, 6);\n    const slats = Math.max(4, Math.round(width / 0.9));\n    for (let i = 0; i < slats; i++) {\n      const t = i / (slats - 1);\n      const slat = new Mesh(slatGeo, bamboo);\n      slat.rotation.x = Math.PI / 2;\n      slat.position.set(-halfW + 0.6 + t * (width - 1.2), deckH + 2.72, (rearZ + frontZ) / 2);\n      pergola.add(slat);\n    }\n    // Planters at the rear corners: a box of green where a wall would be.\n    for (const side of [-1, 1]) {\n      const planter = new Mesh(new BoxGeometry(0.6, 0.4, 0.6), createSurface('terracotta', { seed: 6 }));\n      planter.position.set(side * (halfW - 0.7), deckH + 0.2, rearZ + 0.4);\n      pergola.add(planter);\n      const shrub = new Mesh(\n        new BoxGeometry(0.55, 0.5, 0.55),\n        new MeshStandardMaterial({ color: 0x5d7a3a, roughness: 1, flatShading: true })\n      );\n      shrub.position.set(side * (halfW - 0.7), deckH + 0.62, rearZ + 0.4);\n      pergola.add(shrub);\n    }\n    room.add(pergola);\n  }\n\n  const pos = new Vector3();\n  const quat = new Quaternion();\n  const fwd = new Vector3();\n\n  return {\n    object: group,\n    obstacleRadius: 0,\n    era,\n    deckTop: deckH,\n    focus,\n    matSpots(): MatSpot[] {\n      group.updateWorldMatrix(true, true);\n      return anchors.map((anchor) => {\n        anchor.getWorldPosition(pos);\n        anchor.getWorldQuaternion(quat);\n        fwd.set(0, 0, 1).applyQuaternion(quat);\n        return { x: pos.x, z: pos.z, facing: Math.atan2(fwd.x, fwd.z) };\n      });\n    },\n  };\n}\n","import {\n  CylinderGeometry,\n  Group,\n  LatheGeometry,\n  Mesh,\n  MeshStandardMaterial,\n  SphereGeometry,\n  Vector2,\n} from 'three';\nimport { Rng } from '../core/random';\nimport { createSurface } from '../materials/surface';\nimport type { Prop } from '../core/types';\n\n/**\n * The singing bowl — the woofer's calm opposite.\n *\n * The woofer publishes the music as an `AudioPulse` and a floor full of\n * dancers answers it. The bowl publishes **breath**: a `BreathPulse` at a\n * tenth the frequency, with no beat edge at all — breath has turning\n * points, not kicks. Strike the bowl and the chime is the cue to breathe\n * in: the breath clock restarts at the inhale, the ring blooms and then\n * takes its long time dying away, and anything listening — a class, the\n * incense, the lanterns — settles onto the bowl's time.\n *\n * ```ts\n * const bowl = createSingingBowl({ seed: 4 });\n * scene.add(bowl.object);\n * window.addEventListener('pointerdown', () => bowl.strike());\n *\n * game.onUpdate((t) => {\n *   bowl.update(t.delta);\n *   const breath = bowl.pulse();          // { phase, inhale, rate, ring }\n *   cls.instructor.slaveTo(breath.phase); // ANIMA: the class keeps bowl time\n *   incense.setRate(0.25 + 0.6 * (breath.inhale ? 0.2 : 1)); // SCENA: ambience\n * });\n * ```\n *\n * ## The ring is long on purpose\n *\n * A struck bowl sings for tens of seconds — the decay IS the instrument.\n * `ringing` falls exponentially (about twelve seconds to a third), the rim\n * shivers visibly while it lasts, and the bowl's bronze warms with a faint\n * emissive glow that cools as the note dies. In a browser the strike also\n * *sounds*: two detuned partials synthesized on a lazily-created\n * AudioContext (created inside the strike, which is a user gesture, so\n * autoplay policy is satisfied by construction). Headless and in tests\n * there is no AudioContext and the bowl simply rings silently — the same\n * honest degradation as the woofer's bed.\n *\n * The pulse's `ring` field carries the envelope, so ambience can answer\n * the chime as well as the breath — a lantern that flares softly at the\n * strike and settles as the note does.\n */\n\n/** What the breath says this frame. ANIMA-compatible by shape, as ever. */\nexport interface BreathPulse {\n  /** 0..1 — inhale over the first half, exhale the second. */\n  phase: number;\n  inhale: boolean;\n  /** Breaths per minute the clock is pacing. */\n  rate: number;\n  /** The chime's envelope, 1 at the strike, 0 at silence. */\n  ring: number;\n}\n\nexport interface SingingBowlOptions {\n  seed?: number;\n  /** The pace the bowl keeps. Default 6 breaths a minute. */\n  breathsPerMinute?: number;\n  /** Fundamental pitch, Hz. Default seeded 200–320 (a mid-size bowl). */\n  frequency?: number;\n  /** Never synthesize audio, even in a browser. */\n  mute?: boolean;\n}\n\nexport interface SingingBowl extends Prop {\n  /** Ring the bowl. The breath restarts at the inhale — the chime is the cue. */\n  strike(velocity?: number): void;\n  update(dt: number): void;\n  /** The whole coupling: read it once a frame and hand it to anything. */\n  pulse(): BreathPulse;\n  /** The chime envelope, 0..1. */\n  readonly ringing: number;\n  /** This bowl's fundamental, Hz. */\n  readonly frequency: number;\n  onStrike(cb: () => void): () => void;\n  /** The paced breath's turning points: 'inhale' | 'exhale'. */\n  onBreath(cb: (side: 'inhale' | 'exhale') => void): () => void;\n}\n\n/** The note takes ~12 s to fall to 1/e — the decay IS the instrument. */\nconst DECAY = 12;\n\nexport function createSingingBowl(options: SingingBowlOptions = {}): SingingBowl {\n  const rng = new Rng(options.seed ?? 1);\n  const rate = options.breathsPerMinute ?? 6;\n  const frequency = options.frequency ?? 200 + rng.next() * 120;\n\n  const group = new Group();\n  group.name = 'singing-bowl';\n\n  // --- The bowl: a lathe of a few honest points, in old bronze.\n  const profile: Vector2[] = [\n    new Vector2(0.02, 0),\n    new Vector2(0.14, 0.005),\n    new Vector2(0.185, 0.05),\n    new Vector2(0.21, 0.13),\n    new Vector2(0.205, 0.2),\n  ];\n  const bronze = createSurface('bronze', { seed: options.seed ?? 1 });\n  const bowlMat = bronze.clone() as MeshStandardMaterial;\n  bowlMat.emissive.setHex(0xff9a3c);\n  bowlMat.emissiveIntensity = 0;\n  const bowl = new Mesh(new LatheGeometry(profile, 10), bowlMat);\n  bowl.name = 'bowl';\n  bowl.position.y = 0.09;\n  group.add(bowl);\n\n  // --- The cushion it sits on…\n  const cushion = new Mesh(\n    new CylinderGeometry(0.19, 0.23, 0.09, 9),\n    new MeshStandardMaterial({ color: 0x8a3d3d, roughness: 0.98, flatShading: true })\n  );\n  cushion.name = 'cushion';\n  cushion.position.y = 0.045;\n  group.add(cushion);\n\n  // --- …and the mallet resting beside it, leather head outward.\n  const mallet = new Group();\n  mallet.name = 'mallet';\n  const handle = new Mesh(new CylinderGeometry(0.012, 0.012, 0.24, 6), createSurface('wood', { seed: 2 }));\n  handle.rotation.z = Math.PI / 2 - 0.18;\n  handle.position.set(0.3, 0.03, 0.12);\n  mallet.add(handle);\n  const head = new Mesh(new SphereGeometry(0.035, 7, 6), createSurface('leather', { seed: 3 }));\n  head.position.set(0.42, 0.05, 0.12);\n  mallet.add(head);\n  group.add(mallet);\n\n  let phase = rng.next() * 0.3;\n  let ring = 0;\n  let time = 0;\n  const strikeCbs = new Set<() => void>();\n  const breathCbs = new Set<(side: 'inhale' | 'exhale') => void>();\n\n  // Lazily-created audio, inside the strike gesture. `null` = tried and\n  // unavailable (node, or mute) — never try again, never throw.\n  let audio: AudioContext | null | undefined;\n  const chime = (velocity: number): void => {\n    if (options.mute || audio === null) return;\n    if (audio === undefined) {\n      const Ctx = (globalThis as { AudioContext?: typeof AudioContext }).AudioContext;\n      audio = Ctx ? new Ctx() : null;\n      if (!audio) return;\n    }\n    const now = audio.currentTime;\n    const out = audio.createGain();\n    out.gain.setValueAtTime(0.24 * velocity, now);\n    out.gain.exponentialRampToValueAtTime(0.0004, now + DECAY * 1.6);\n    out.connect(audio.destination);\n    // A bowl is its partials: the fundamental, a shimmer-mate a few hertz\n    // off (their beating is the \"singing\"), and one bright inharmonic.\n    for (const [f, g] of [\n      [frequency, 1],\n      [frequency + 2.3, 0.7],\n      [frequency * 2.71, 0.22],\n    ] as const) {\n      const osc = audio.createOscillator();\n      osc.type = 'sine';\n      osc.frequency.value = f;\n      const mix = audio.createGain();\n      mix.gain.value = g;\n      osc.connect(mix).connect(out);\n      osc.start(now);\n      osc.stop(now + DECAY * 1.6);\n    }\n  };\n\n  return {\n    object: group,\n    obstacleRadius: 0.3,\n    get ringing() {\n      return ring;\n    },\n    frequency,\n    strike(velocity = 1): void {\n      const v = Math.min(1, Math.max(0.05, velocity));\n      ring = Math.min(1, Math.max(ring, v));\n      // The chime is the cue to breathe IN: the clock restarts at the inhale.\n      phase = 0;\n      chime(v);\n      for (const cb of strikeCbs) cb();\n      for (const cb of breathCbs) cb('inhale');\n    },\n    update(dt: number): void {\n      time += dt;\n      const before = phase;\n      phase = (phase + (dt * rate) / 60) % 1;\n      if (phase < before) for (const cb of breathCbs) cb('inhale');\n      else if (before < 0.5 && phase >= 0.5) for (const cb of breathCbs) cb('exhale');\n      ring *= Math.exp(-dt / DECAY);\n      if (ring < 0.001) ring = 0;\n      // The rim shivers while the note lasts, and the bronze holds a\n      // little of the strike's warmth.\n      const shiver = Math.sin(time * 34) * 0.007 * ring;\n      bowl.scale.set(1 + shiver, 1, 1 - shiver);\n      bowlMat.emissiveIntensity = ring * 0.35;\n    },\n    pulse(): BreathPulse {\n      return { phase, inhale: phase < 0.5, rate, ring };\n    },\n    onStrike(cb: () => void): () => void {\n      strikeCbs.add(cb);\n      return () => strikeCbs.delete(cb);\n    },\n    onBreath(cb: (side: 'inhale' | 'exhale') => void): () => void {\n      breathCbs.add(cb);\n      return () => breathCbs.delete(cb);\n    },\n  };\n}\n","import {\n  BufferAttribute,\n  BufferGeometry,\n  CircleGeometry,\n  DataTexture,\n  FloatType,\n  Group,\n  InstancedMesh,\n  Matrix4,\n  Mesh,\n  MeshStandardMaterial,\n  NearestFilter,\n  PlaneGeometry,\n  RedFormat,\n  Vector3,\n} from 'three';\nimport { Rng } from '../core/random';\nimport type { Prop } from '../core/types';\n\n/**\n * The beach — the line where the water was a moment ago.\n *\n * Dry sand is terrain and the sea already ships; what makes a beach READ\n * is the strip between them. This prop owns that strip: the **swash** —\n * the tongue of water that runs up the sand and drains back — and the\n * memory it leaves. Sand where the water has just been is mirror-wet; it\n * dries through dark, damp and dry over half a minute; each retreat\n * strands a lace of foam at its high point; and the whole record is\n * queryable as **`wetAt(x, z)`** — the fifth spatial field, after\n * `depthAt`, `heatAt`, `chillAt` and `smokeAt`.\n *\n * ```ts\n * const beach = createBeach({ seed: 7, width: 46 });\n * scene.add(beach.object);\n * const ocean = createOcean({ shore: beach.heightAt, wind });   // compose\n * game.onUpdate((t) => beach.update(t.delta));\n * ```\n *\n * ## One water, two directions\n *\n * The beach does not own the sea — it *asks* it. Pass any\n * `water(x, z, time)` (structurally `Ocean.heightAt`) and the swash runs\n * on the real swell; pass nothing and a seeded built-in swell drives it —\n * progressive along the shore (tongues run diagonally, as they do) and\n * modulated into **sets**, because waves arrive in families. Either way\n * the beach hands its `heightAt` back to the ocean's `shore` option, so\n * the two agree about where the land is. Neither imports the other.\n *\n * ## The sand remembers\n *\n * `stamp(x, z)` presses a mark into the sand — a footprint, a paw, a\n * dropped coconut. **Only wet sand takes a print** (try stamping dry dune\n * and it simply doesn't), and the next tongue that crosses a print wipes\n * it. Wire ANIMA's `loco.onFootstep` to `stamp` and characters write\n * their path along the beach while the sea edits it — that one coupling\n * is worth more than any ten props.\n *\n * `wrackLine()` reports the session's high-water mark per shore segment —\n * where the tide leaves its shells and kelp, and where 0.82's scatter\n * will put them.\n *\n * Local frame: X runs along the shore, +Z is seaward, the still-water\n * line sits at `z0` (about a sixth of the depth seaward of centre). All\n * public queries are **world-space** and ride the prop's transform.\n */\n\nexport interface BeachOptions {\n  seed?: number;\n  /** Metres of shoreline (local X). Default 40. */\n  width?: number;\n  /** Cross-shore extent (local Z). Default 24. */\n  depth?: number;\n  /** Still-water level, world Y. Default 0. */\n  level?: number;\n  /** Height of the back dune above sea level. Default 1.6. */\n  duneHeight?: number;\n  /** Seconds fully-wet sand takes to dry. Default 30. */\n  dryTime?: number;\n  /**\n   * Water height at a world point and time — structurally `Ocean.heightAt`.\n   * Default: a seeded built-in swell with along-shore progression and sets.\n   */\n  water?: (x: number, z: number, time: number) => number;\n}\n\nexport interface Beach extends Prop {\n  /** Sand height at a world point — hand this to `createOcean({ shore })`. */\n  heightAt(x: number, z: number): number;\n  /** How wet the sand is at a world point, 0..1. The fifth field. */\n  wetAt(x: number, z: number): number;\n  /** The water edge's current position at shore coordinate x, as a world point. */\n  reachAt(x: number): { x: number; z: number };\n  /**\n   * Press a mark into the sand. Only wet sand (wetAt > 0.15) takes a\n   * print; returns whether it took. The next tongue over it wipes it.\n   */\n  stamp(x: number, z: number, r?: number): boolean;\n  /** Prints currently in the sand. */\n  readonly stamps: number;\n  /** Foam scraps currently stranded. */\n  readonly foam: number;\n  /** The session's high-water mark, one world point per shore segment. */\n  wrackLine(): Array<{ x: number; z: number }>;\n  update(dt: number): void;\n}\n\nconst SEGS = 48; // along-shore swash segments\nconst CELLS = 48; // cross-shore wetness cells (full depth)\nconst MAX_FOAM = 96;\nconst MAX_STAMPS = 220;\n/** Foreshore slope: 1 in 12 — a walkable, dissipative beach. */\nconst SLOPE = 0.084;\n/** Swash momentum: the tongue runs further than the static intersection. */\nconst RUNUP = 1.6;\n\nexport function createBeach(options: BeachOptions = {}): Beach {\n  const rng = new Rng(options.seed ?? 1);\n  const width = options.width ?? 40;\n  const depth = options.depth ?? 24;\n  const level = options.level ?? 0;\n  const duneH = options.duneHeight ?? 1.6;\n  const dryTime = Math.max(1, options.dryTime ?? 30);\n  const z0 = depth / 6; // still-water line, local\n\n  // The built-in swell: two progressive components + a slow set envelope.\n  const a1 = 0.1 + rng.next() * 0.08;\n  const a2 = 0.05 + rng.next() * 0.05;\n  const p1 = rng.next() * Math.PI * 2;\n  const p2 = rng.next() * Math.PI * 2;\n  const defaultSwell = (x: number, _z: number, t: number): number => {\n    const set = 1 + 0.5 * Math.sin((t * Math.PI * 2) / 47 + p2);\n    return (\n      set *\n      (a1 * Math.sin((t * Math.PI * 2) / 6.1 - x * 0.35 + p1) +\n        a2 * Math.sin((t * Math.PI * 2) / 9.7 + x * 0.21 + p2))\n    );\n  };\n  const water = options.water ?? defaultSwell;\n\n  // --- The sand: a berm profile, dune at -Z, foreshore running under the sea.\n  const profile = (z: number): number => {\n    const fore = level + (z0 - z) * SLOPE;\n    const duneT = Math.min(1, Math.max(0, (z0 - 7 - z) / 8));\n    return fore + duneH * duneT * duneT * (3 - 2 * duneT);\n  };\n\n  const group = new Group();\n  group.name = 'beach';\n\n  const sandGeo = new PlaneGeometry(width, depth, 64, 48);\n  sandGeo.rotateX(-Math.PI / 2);\n  {\n    const pos = sandGeo.getAttribute('position');\n    for (let i = 0; i < pos.count; i++) {\n      pos.setY(i, profile(pos.getZ(i)));\n    }\n    sandGeo.computeVertexNormals();\n  }\n\n  // --- The wetness record: one scalar per cell, uploaded as a texture the\n  // sand shader reads. `lastCovered` is the whole simulation state.\n  const lastCovered = new Float32Array(SEGS * CELLS).fill(-1e9);\n  const wetData = new Float32Array(SEGS * CELLS);\n  const wetTex = new DataTexture(wetData, SEGS, CELLS, RedFormat, FloatType);\n  wetTex.magFilter = NearestFilter;\n  wetTex.minFilter = NearestFilter;\n\n  // Fully matte: at 0.95 a low sun still drags a glitter path up dry sand\n  // (found by probe screenshots, invariant to the sheen band). Dry sand\n  // scatters; only the WET record is allowed any shine.\n  const sandMat = new MeshStandardMaterial({\n    color: 0xdbc79d,\n    roughness: 1,\n    metalness: 0,\n  });\n  sandMat.defines = { USE_UV: '' };\n  sandMat.onBeforeCompile = (shader) => {\n    shader.uniforms.uWet = { value: wetTex };\n    shader.fragmentShader = shader.fragmentShader\n      .replace(\n        '#include <common>',\n        '#include <common>\\nuniform sampler2D uWet;'\n      )\n      .replace(\n        '#include <color_fragment>',\n        `#include <color_fragment>\n  // The plane is rotated flat, which flips v: dune is v=1, sea is v=0.\n  float scWet = texture2D(uWet, vec2(vUv.x, 1.0 - vUv.y)).r;\n  // Wet sand is darker and slightly warmer; the sheen band is near-mirror.\n  diffuseColor.rgb *= 1.0 - 0.42 * scWet;\n  diffuseColor.rgb += vec3(0.02, 0.012, 0.0) * scWet;`\n      )\n      .replace(\n        '#include <roughnessmap_fragment>',\n        `#include <roughnessmap_fragment>\n  // Sheen only where the water JUST was, and matte enough that the sun's\n  // reflection is a gleam, not a nova — found by screenshot, as ever.\n  float scSheen = smoothstep(0.82, 1.0, scWet);\n  roughnessFactor = mix(roughnessFactor, 0.22, scSheen);`\n      );\n  };\n  const sand = new Mesh(sandGeo, sandMat);\n  sand.name = 'sand';\n  group.add(sand);\n\n  // --- The tongue: a strip whose front edge IS the current reach.\n  const swashGeo = new BufferGeometry();\n  {\n    const verts = new Float32Array((SEGS + 1) * 2 * 3);\n    const cols = new Float32Array((SEGS + 1) * 2 * 3);\n    const idx: number[] = [];\n    for (let i = 0; i < SEGS; i++) {\n      const a = i * 2;\n      idx.push(a, a + 1, a + 2, a + 1, a + 3, a + 2);\n    }\n    swashGeo.setAttribute('position', new BufferAttribute(verts, 3));\n    swashGeo.setAttribute('color', new BufferAttribute(cols, 3));\n    swashGeo.setIndex(idx);\n  }\n  // Matte and modest: a specular white sheet under a low sun reads as a\n  // glare bomb, not water. The film keeps its shine in the SAND's sheen\n  // band; the sheet itself is just a soft milky wash.\n  const swashMat = new MeshStandardMaterial({\n    vertexColors: true,\n    transparent: true,\n    opacity: 0.32,\n    roughness: 0.6,\n    depthWrite: false,\n  });\n  const swash = new Mesh(swashGeo, swashMat);\n  swash.name = 'swash';\n  group.add(swash);\n\n  // --- Foam scraps: the lace the retreat strands, popping over seconds.\n  const foamMesh = new InstancedMesh(\n    new CircleGeometry(0.22, 8).rotateX(-Math.PI / 2),\n    new MeshStandardMaterial({ color: 0xffffff, roughness: 0.6, transparent: true, opacity: 0.85 }),\n    MAX_FOAM\n  );\n  foamMesh.name = 'foam';\n  foamMesh.count = 0;\n  group.add(foamMesh);\n  interface Scrap {\n    x: number;\n    z: number;\n    born: number;\n    size: number;\n  }\n  const scraps: Scrap[] = [];\n\n  // --- Prints: only wet sand takes them; the next tongue wipes them.\n  const stampMesh = new InstancedMesh(\n    new CircleGeometry(1, 9).rotateX(-Math.PI / 2),\n    // Darker than the WET sand around it, or a print reads as a bright dot.\n    new MeshStandardMaterial({ color: 0x63523c, roughness: 1 }),\n    MAX_STAMPS\n  );\n  stampMesh.name = 'stamps';\n  stampMesh.count = 0;\n  group.add(stampMesh);\n  interface Print {\n    x: number;\n    z: number;\n    r: number;\n    /** 1 while set; ramps to 0 while a tongue washes it. */\n    life: number;\n    washing: boolean;\n  }\n  const prints: Print[] = [];\n\n  // --- Swash state.\n  let time = 0;\n  const reach = new Float32Array(SEGS).fill(z0);\n  const minReachEver = new Float32Array(SEGS).fill(z0);\n  /** Per-segment retreat bookkeeping for foam. */\n  const excursion = new Float32Array(SEGS).fill(z0);\n  const lastFoamAt = new Float32Array(SEGS).fill(-1e9);\n  const retreating = new Uint8Array(SEGS);\n\n  const segX = (i: number): number => -width / 2 + ((i + 0.5) * width) / SEGS;\n  const segOf = (x: number): number =>\n    Math.max(0, Math.min(SEGS - 1, Math.floor(((x + width / 2) / width) * SEGS)));\n  const cellOf = (z: number): number =>\n    Math.max(0, Math.min(CELLS - 1, Math.floor(((z + depth / 2) / depth) * CELLS)));\n  const cellZ = (k: number): number => -depth / 2 + ((k + 0.5) * depth) / CELLS;\n\n  const world = new Vector3();\n  const inverse = new Matrix4();\n  const toLocal = (x: number, z: number): { x: number; z: number } => {\n    group.updateWorldMatrix(true, false);\n    inverse.copy(group.matrixWorld).invert();\n    world.set(x, 0, z).applyMatrix4(inverse);\n    return { x: world.x, z: world.z };\n  };\n  const toWorld = (x: number, z: number): { x: number; z: number } => {\n    group.updateWorldMatrix(true, false);\n    world.set(x, 0, z).applyMatrix4(group.matrixWorld);\n    return { x: world.x, z: world.z };\n  };\n\n  const wetOfCell = (i: number, k: number): number => {\n    if (cellZ(k) >= reach[i]) return 1; // under the water right now\n    const age = time - lastCovered[k * SEGS + i];\n    return Math.max(0, 1 - age / dryTime);\n  };\n\n  const dummy = new Matrix4();\n\n  const rebuildFoam = (): void => {\n    foamMesh.count = scraps.length;\n    for (let s = 0; s < scraps.length; s++) {\n      const scrap = scraps[s];\n      const age = time - scrap.born;\n      const k = Math.max(0.001, scrap.size * (1 - age / 4.5));\n      dummy.makeScale(k, 1, k * 0.55);\n      dummy.setPosition(scrap.x, profile(scrap.z) + 0.015, scrap.z);\n      foamMesh.setMatrixAt(s, dummy);\n    }\n    foamMesh.instanceMatrix.needsUpdate = true;\n  };\n\n  const rebuildStamps = (): void => {\n    stampMesh.count = prints.length;\n    for (let s = 0; s < prints.length; s++) {\n      const print = prints[s];\n      const k = print.r * print.life;\n      dummy.makeScale(Math.max(0.001, k), 1, Math.max(0.001, k * 0.7));\n      dummy.setPosition(print.x, profile(print.z) + 0.008, print.z);\n      stampMesh.setMatrixAt(s, dummy);\n    }\n    stampMesh.instanceMatrix.needsUpdate = true;\n  };\n\n  return {\n    object: group,\n    obstacleRadius: 0,\n\n    heightAt(x: number, z: number): number {\n      // The FIELD extends the coast forever; only the mesh is bounded.\n      // (An -Infinity here once reached the ocean's shore attribute and\n      // rendered as a glowing smeared sliver — fields must stay finite.)\n      const p = toLocal(x, z);\n      return profile(p.z);\n    },\n\n    wetAt(x: number, z: number): number {\n      const p = toLocal(x, z);\n      if (Math.abs(p.x) > width / 2 || Math.abs(p.z) > depth / 2) return 0;\n      return wetOfCell(segOf(p.x), cellOf(p.z));\n    },\n\n    reachAt(x: number): { x: number; z: number } {\n      const p = toLocal(x, 0);\n      const i = segOf(p.x);\n      return toWorld(segX(i), reach[i]);\n    },\n\n    stamp(x: number, z: number, r = 0.11): boolean {\n      const p = toLocal(x, z);\n      if (Math.abs(p.x) > width / 2 || Math.abs(p.z) > depth / 2) return false;\n      const i = segOf(p.x);\n      // Dry sand takes no print — and neither does open water.\n      if (wetOfCell(i, cellOf(p.z)) < 0.15) return false;\n      if (p.z >= reach[i]) return false;\n      if (prints.length >= MAX_STAMPS) prints.shift();\n      prints.push({ x: p.x, z: p.z, r, life: 1, washing: false });\n      rebuildStamps();\n      return true;\n    },\n\n    get stamps(): number {\n      return prints.length;\n    },\n\n    get foam(): number {\n      return scraps.length;\n    },\n\n    wrackLine(): Array<{ x: number; z: number }> {\n      const line: Array<{ x: number; z: number }> = [];\n      for (let i = 0; i < SEGS; i++) line.push(toWorld(segX(i), minReachEver[i]));\n      return line;\n    },\n\n    update(dt: number): void {\n      time += dt;\n      group.updateWorldMatrix(true, false);\n\n      const swashPos = swashGeo.getAttribute('position');\n      const swashCol = swashGeo.getAttribute('color');\n\n      for (let i = 0; i < SEGS; i++) {\n        const shorePoint = toWorld(segX(i), z0);\n        const wave = water(shorePoint.x, shorePoint.z, time) - level;\n        // Momentum carries the tongue past the static intersection; the\n        // backwash bares extra sand below the still-water line.\n        const excursionZ =\n          wave >= 0 ? z0 - (wave * RUNUP) / SLOPE : z0 + (-wave * 0.8) / SLOPE;\n        const target = Math.max(z0 - 6.4, Math.min(depth / 2 - 0.4, excursionZ));\n        const prev = reach[i];\n        // The edge chases its target — water has inertia even here.\n        reach[i] = prev + (target - prev) * Math.min(1, dt * 2.6);\n\n        if (reach[i] < minReachEver[i]) minReachEver[i] = reach[i];\n\n        // Foam: the moment a run-up turns, strand a scrap at its high point.\n        if (reach[i] < excursion[i]) {\n          excursion[i] = reach[i];\n          retreating[i] = 0;\n        } else if (\n          !retreating[i] &&\n          reach[i] > excursion[i] + 0.25 &&\n          z0 - excursion[i] > 0.7 &&\n          time - lastFoamAt[i] > 2.4\n        ) {\n          retreating[i] = 1;\n          lastFoamAt[i] = time;\n          excursion[i] = reach[i];\n          if (scraps.length >= MAX_FOAM) scraps.shift();\n          scraps.push({\n            x: segX(i) + (rng.next() - 0.5) * (width / SEGS),\n            z: excursion[i] - 0.1,\n            born: time,\n            size: 0.6 + rng.next() * 0.8,\n          });\n        } else if (retreating[i]) {\n          excursion[i] = reach[i];\n        }\n\n        // Everything seaward of the edge is covered NOW.\n        for (let k = cellOf(reach[i]); k < CELLS; k++) {\n          lastCovered[k * SEGS + i] = time;\n        }\n      }\n\n      // Write the strip in a second tidy pass (verts are shared per column).\n      for (let c = 0; c <= SEGS; c++) {\n        const i = Math.min(SEGS - 1, Math.max(0, c - 0));\n        const iL = Math.max(0, c - 1);\n        const r = c === 0 ? reach[0] : c === SEGS ? reach[SEGS - 1] : (reach[i] + reach[iL]) / 2;\n        const x = -width / 2 + (c * width) / SEGS;\n        const front = c * 2;\n        const back = c * 2 + 1;\n        swashPos.setXYZ(front, x, profile(r) + 0.02, r);\n        swashPos.setXYZ(back, x, profile(r + 2.6) + 0.012, r + 2.6);\n        swashCol.setXYZ(front, 0.9, 0.95, 0.95);\n        swashCol.setXYZ(back, 0.62, 0.72, 0.74);\n      }\n      swashPos.needsUpdate = true;\n      swashCol.needsUpdate = true;\n      swashGeo.computeVertexNormals();\n\n      // Dying foam.\n      for (let s = scraps.length - 1; s >= 0; s--) {\n        if (time - scraps[s].born > 4.5) scraps.splice(s, 1);\n      }\n      rebuildFoam();\n\n      // Prints: a tongue over a print washes it out.\n      let stampsDirty = false;\n      for (let s = prints.length - 1; s >= 0; s--) {\n        const print = prints[s];\n        if (!print.washing && print.z >= reach[segOf(print.x)] - 0.05) {\n          print.washing = true;\n        }\n        if (print.washing) {\n          print.life -= dt / 0.7;\n          stampsDirty = true;\n          if (print.life <= 0) prints.splice(s, 1);\n        }\n      }\n      if (stampsDirty) rebuildStamps();\n\n      // Refresh the wetness record the shader reads.\n      for (let i = 0; i < SEGS; i++) {\n        for (let k = 0; k < CELLS; k++) {\n          wetData[k * SEGS + i] = wetOfCell(i, k);\n        }\n      }\n      wetTex.needsUpdate = true;\n    },\n  };\n}\n","import {\n  BoxGeometry,\n  CylinderGeometry,\n  Group,\n  Mesh,\n  MeshStandardMaterial,\n  Object3D,\n  RingGeometry,\n  SphereGeometry,\n  Vector3,\n} from 'three';\nimport { Rng } from '../core/random';\nimport { createSurface } from '../materials/surface';\nimport type { Prop } from '../core/types';\n\n/**\n * The cricket ground, and the gear.\n *\n * A cricket field is mostly EMPTY, and the emptiness is measured: a\n * 22-yard strip, creases painted at fixed distances from the stumps, and\n * a boundary a long way further out than anyone expects. Getting those\n * numbers right is what makes a ground read as a cricket ground rather\n * than a green circle with sticks in it, so this file works in the\n * game's own units — yards and inches, converted once — and every\n * distance below is the real one.\n *\n * ```ts\n * const ground = createCricketGround({ seed: 3 });\n * scene.add(ground.object);\n * ground.strikerEnd;    // where the batter stands\n * ground.bowlerEnd;     // where the run-up starts\n * ground.stumpsAt(-1);  // the stumps a delivery is aimed at\n * ```\n */\n\nconst YARD = 0.9144;\nconst INCH = 0.0254;\n/** The pitch: 22 yards stump to stump, 10 feet wide. */\nexport const PITCH_LENGTH = 22 * YARD;\nexport const PITCH_WIDTH = 3.05;\n/** Stumps: 28 inches tall, 9 inches across all three. */\nexport const STUMP_HEIGHT = 28 * INCH;\nexport const STUMP_SPREAD = 9 * INCH;\n/** The popping crease is 4 feet in front of the stumps. */\nexport const CREASE_FRONT = 4 * 0.3048;\n\nexport interface CricketGroundOptions {\n  seed?: number;\n  /** Boundary radius in metres. Default 62 — a real, big field. */\n  boundary?: number;\n  /** Grass colour. Default a mown green. */\n  grass?: number;\n  /** Width of the mower's stripes, metres. Default 7. */\n  stripe?: number;\n}\n\nexport interface CricketGround extends Prop {\n  /** Where the batter on strike stands (world space, on the crease). */\n  readonly strikerEnd: Vector3;\n  /** Where the non-striker / bowler's end is. */\n  readonly bowlerEnd: Vector3;\n  /** Boundary radius, metres. */\n  readonly boundary: number;\n  /**\n   * The base of the stumps at one end: `-1` is the striker's (the end\n   * being bowled AT), `+1` the bowler's.\n   */\n  stumpsAt(end: -1 | 1): Vector3;\n  /** True when a point has crossed the rope. */\n  isBoundary(x: number, z: number): boolean;\n  /** Knock the bails off the striker's stumps — a wicket, visibly. */\n  breakWicket(end?: -1 | 1): void;\n  /** Put them back for the next batter. */\n  resetWicket(): void;\n  update(dt: number): void;\n}\n\ninterface Bail {\n  mesh: Mesh;\n  home: Vector3;\n  vel: Vector3;\n  spin: number;\n  flying: boolean;\n}\n\nexport function createCricketGround(options: CricketGroundOptions = {}): CricketGround {\n  const rng = new Rng(options.seed ?? 1);\n  const boundary = options.boundary ?? 62;\n  const group = new Group();\n  group.name = 'cricket-ground';\n\n  // --- The outfield. THE STRIPES ARE THE GROUND: a cricket field without\n  // the mower's alternating bands reads as a green disc, and no amount of\n  // correct geometry fixes that.\n  const turf = createSurface('dirt', {\n    seed: options.seed ?? 1,\n    color: options.grass ?? 0x4f8a3c,\n  });\n  const cut = options.stripe ?? 7;\n  const inner = turf.onBeforeCompile;\n  const innerKey = turf.customProgramCacheKey;\n  turf.onBeforeCompile = (shader, renderer) => {\n    inner?.call(turf, shader, renderer);\n    shader.uniforms.uCut = { value: cut };\n    shader.vertexShader = shader.vertexShader\n      .replace('#include <common>', '#include <common>\\nvarying vec3 vTurf;')\n      .replace(\n        '#include <begin_vertex>',\n        '#include <begin_vertex>\\nvTurf = (modelMatrix * vec4(transformed, 1.0)).xyz;'\n      );\n    shader.fragmentShader = shader.fragmentShader\n      .replace(\n        '#include <common>',\n        '#include <common>\\nvarying vec3 vTurf;\\nuniform float uCut;'\n      )\n      .replace(\n        '#include <color_fragment>',\n        `#include <color_fragment>\n        // Mown bands, and the roller's sheen: a stripe is light because the\n        // grass is lying away from you, so it brightens and it flattens.\n        float band = floor(vTurf.z / uCut);\n        float away = mod(band, 2.0) < 1.0 ? 1.0 : 0.0;\n        diffuseColor.rgb *= mix(0.88, 1.12, away);`\n      );\n  };\n  turf.customProgramCacheKey = () => `${innerKey ? innerKey.call(turf) : ''}|stripe`;\n\n  const outfield = new Mesh(\n    new CylinderGeometry(boundary + 6, boundary + 6, 0.1, 64),\n    turf\n  );\n  outfield.name = 'outfield';\n  outfield.position.y = -0.05;\n  group.add(outfield);\n\n  // The thirty-yard circle, painted the way a limited-overs ground paints it.\n  const circle = new Mesh(\n    new RingGeometry(27.2, 27.4, 72).rotateX(-Math.PI / 2),\n    new MeshStandardMaterial({ color: 0xf2f0e8, roughness: 0.95 })\n  );\n  circle.name = 'infield-circle';\n  circle.position.y = 0.012;\n  group.add(circle);\n\n  // --- The rope: the line everything is measured against.\n  const rope = new Mesh(\n    new RingGeometry(boundary - 0.35, boundary, 64).rotateX(-Math.PI / 2),\n    new MeshStandardMaterial({ color: 0xf2f0e8, roughness: 0.9 })\n  );\n  rope.name = 'boundary';\n  rope.position.y = 0.02;\n  group.add(rope);\n\n  // --- The strip. Worn, pale, and the only bare earth on the field.\n  const pitch = new Mesh(\n    new BoxGeometry(PITCH_WIDTH, 0.04, PITCH_LENGTH + 3),\n    createSurface('sand', { seed: 7, color: 0xb9a179 })\n  );\n  pitch.name = 'pitch';\n  pitch.position.y = 0.02;\n  group.add(pitch);\n  // The worn middle: where a season of bowlers has taken the grass off.\n  const worn = new Mesh(\n    new BoxGeometry(1.15, 0.005, PITCH_LENGTH - 3),\n    new MeshStandardMaterial({ color: 0xa78f68, roughness: 1 })\n  );\n  worn.position.y = 0.041;\n  group.add(worn);\n\n  const paint = new MeshStandardMaterial({ color: 0xf6f4ec, roughness: 0.95 });\n  const line = (w: number, l: number, x: number, z: number): void => {\n    const m = new Mesh(new BoxGeometry(w, 0.01, l), paint);\n    m.position.set(x, 0.045, z);\n    group.add(m);\n  };\n\n  // --- Stumps, bails and creases at both ends.\n  const bails: Bail[] = [];\n  const stumpsBase: Record<number, Vector3> = {};\n  const wood = createSurface('wood', { seed: 3, color: 0xe8dcc0 });\n  for (const end of [-1, 1] as const) {\n    const z = (end * PITCH_LENGTH) / 2;\n    stumpsBase[end] = new Vector3(0, 0, z);\n    const set = new Group();\n    set.name = end === -1 ? 'stumps-striker' : 'stumps-bowler';\n    for (let i = -1; i <= 1; i++) {\n      const stump = new Mesh(\n        new CylinderGeometry(0.018, 0.018, STUMP_HEIGHT, 7),\n        wood\n      );\n      stump.position.set((i * STUMP_SPREAD) / 2, STUMP_HEIGHT / 2, z);\n      set.add(stump);\n    }\n    for (const side of [-1, 1]) {\n      const bail = new Mesh(new CylinderGeometry(0.011, 0.011, STUMP_SPREAD / 2 + 0.02, 6), wood);\n      bail.rotation.z = Math.PI / 2;\n      const home = new Vector3((side * STUMP_SPREAD) / 4, STUMP_HEIGHT + 0.012, z);\n      bail.position.copy(home);\n      set.add(bail);\n      bails.push({\n        mesh: bail,\n        home,\n        vel: new Vector3(),\n        spin: 0,\n        flying: false,\n      });\n    }\n    group.add(set);\n    // The popping crease in front, the bowling crease through the stumps,\n    // and the return creases running back from both.\n    line(PITCH_WIDTH, 0.05, 0, z - end * CREASE_FRONT);\n    line(PITCH_WIDTH, 0.05, 0, z);\n    for (const side of [-1, 1]) {\n      line(0.05, 1.32, (side * 4 * 0.3048), z - end * 0.66);\n    }\n  }\n\n  // A couple of seeded worn patches where bowlers land.\n  for (const end of [-1, 1]) {\n    const scuff = new Mesh(\n      new BoxGeometry(0.5 + rng.next() * 0.3, 0.005, 0.7),\n      new MeshStandardMaterial({ color: 0xb59a6d, roughness: 1 })\n    );\n    scuff.position.set(rng.range(-0.4, 0.4), 0.043, end * (PITCH_LENGTH / 2 - 2.6));\n    group.add(scuff);\n  }\n\n  const striker = new Vector3(0, 0, -PITCH_LENGTH / 2 + CREASE_FRONT);\n  const bowler = new Vector3(0, 0, PITCH_LENGTH / 2 - CREASE_FRONT);\n  const world = new Vector3();\n\n  return {\n    object: group,\n    obstacleRadius: 0,\n    boundary,\n    get strikerEnd() {\n      return striker.clone().applyMatrix4(group.matrixWorld);\n    },\n    get bowlerEnd() {\n      return bowler.clone().applyMatrix4(group.matrixWorld);\n    },\n    stumpsAt(end: -1 | 1): Vector3 {\n      group.updateWorldMatrix(true, false);\n      return world.copy(stumpsBase[end]).applyMatrix4(group.matrixWorld).clone();\n    },\n    isBoundary(x: number, z: number): boolean {\n      group.updateWorldMatrix(true, false);\n      const c = new Vector3(0, 0, 0).applyMatrix4(group.matrixWorld);\n      return Math.hypot(x - c.x, z - c.z) >= boundary;\n    },\n    breakWicket(end: -1 | 1 = -1): void {\n      // The bails fly. It is the only moment in cricket that announces\n      // itself, and a wicket without it is a scoreboard update.\n      const z = (end * PITCH_LENGTH) / 2;\n      for (const bail of bails) {\n        if (Math.abs(bail.home.z - z) > 0.01 || bail.flying) continue;\n        bail.flying = true;\n        bail.vel.set(rng.range(-1.4, 1.4), rng.range(2.2, 3.4), -end * rng.range(1.5, 3));\n        bail.spin = rng.range(-12, 12);\n      }\n    },\n    resetWicket(): void {\n      for (const bail of bails) {\n        bail.flying = false;\n        bail.vel.set(0, 0, 0);\n        bail.mesh.position.copy(bail.home);\n        bail.mesh.rotation.set(0, 0, Math.PI / 2);\n      }\n    },\n    update(dt: number): void {\n      for (const bail of bails) {\n        if (!bail.flying) continue;\n        bail.vel.y -= 9.8 * dt;\n        bail.mesh.position.addScaledVector(bail.vel, dt);\n        bail.mesh.rotation.x += bail.spin * dt;\n        if (bail.mesh.position.y <= 0.012) {\n          bail.mesh.position.y = 0.012;\n          bail.vel.multiplyScalar(0);\n          bail.spin = 0;\n          bail.flying = false;\n        }\n      }\n    },\n  };\n}\n\nexport interface BatOptions {\n  seed?: number;\n  /** Blade length, metres. Default 0.58 (a full-size bat is ~0.85 overall). */\n  blade?: number;\n}\n\n/** A bat: willow blade, shoulders, splice and a bound handle. */\nexport function createBat(options: BatOptions = {}): Prop {\n  const blade = options.blade ?? 0.58;\n  const group = new Group();\n  group.name = 'bat';\n  const willow = createSurface('wood', { seed: options.seed ?? 1, color: 0xe6d8b4 });\n  const face = new Mesh(new BoxGeometry(0.108, blade, 0.042), willow);\n  face.position.y = blade / 2;\n  group.add(face);\n  // The swell: a bat is thicker at the bottom, and it is why it drives.\n  const swell = new Mesh(new BoxGeometry(0.104, blade * 0.42, 0.026), willow);\n  swell.position.set(0, blade * 0.26, -0.03);\n  group.add(swell);\n  const handle = new Mesh(\n    new CylinderGeometry(0.017, 0.019, 0.3, 8),\n    new MeshStandardMaterial({ color: 0x2c2c30, roughness: 0.95 })\n  );\n  handle.position.y = blade + 0.14;\n  group.add(handle);\n  for (let i = 0; i < 5; i++) {\n    const grip = new Mesh(\n      new CylinderGeometry(0.0192, 0.0192, 0.012, 8),\n      new MeshStandardMaterial({ color: 0xc0392b, roughness: 0.9 })\n    );\n    grip.position.y = blade + 0.04 + i * 0.055;\n    group.add(grip);\n  }\n  return { object: group, obstacleRadius: 0.12 };\n}\n\nexport interface CricketBallProp extends Prop {\n  /** The ball's own marker so a game can parent effects to it. */\n  readonly marker: Object3D;\n}\n\n/** A cricket ball: 72 mm, red, with a proud stitched seam. */\nexport function createCricketBall(options: { seed?: number; color?: number } = {}): CricketBallProp {\n  const group = new Group();\n  group.name = 'cricket-ball';\n  const r = 0.036;\n  const leather = new MeshStandardMaterial({\n    color: options.color ?? 0xa02020,\n    roughness: 0.45,\n    flatShading: true,\n  });\n  const body = new Mesh(new SphereGeometry(r, 12, 10), leather);\n  group.add(body);\n  // The seam: six stitches proud of the leather, on one great circle.\n  const seam = new Mesh(\n    new CylinderGeometry(r * 1.02, r * 1.02, 0.006, 16, 1, true),\n    new MeshStandardMaterial({ color: 0xf0ece0, roughness: 0.9 })\n  );\n  seam.rotation.x = Math.PI / 2;\n  group.add(seam);\n  const marker = new Object3D();\n  group.add(marker);\n  return { object: group, obstacleRadius: r, marker };\n}\n","import {\n  CylinderGeometry,\n  Group,\n  Mesh,\n  MeshStandardMaterial,\n  PlaneGeometry,\n  SphereGeometry,\n} from 'three';\nimport { Rng } from '../core/random';\nimport { createSurface } from '../materials/surface';\nimport { wavingClothMaterial } from '../materials/clothWave';\nimport type { Prop } from '../core/types';\n\n/**\n * Tropical trees whose leaves are CLOTH.\n *\n * A palm frond is, mechanically, a flag pinned at the stem: fixed at one\n * edge, free at the fly, rippled by the air, drooping under its own\n * weight. So these trees borrow the banner machinery wholesale — every\n * leaf is a tapered plane driven by the shared cloth-wave shader, with a\n * seeded phase of its own so no two leaves flutter in step. Rigid-leaf\n * palms read as plastic; fabric reads as alive, which is the whole trick.\n *\n * ```ts\n * const palm = createPalm({ seed: 7, height: 6 });\n * scene.add(palm.object);\n * game.onUpdate((t) => palm.update(t.delta));\n * ```\n *\n * Two species:\n * - **`createPalm`** — a coconut palm: curved trunk (the lean toward the\n *   water is the whole silhouette), a crown of long serrated-feel fronds,\n *   coconuts at the throat.\n * - **`createBananaTree`** — a banana plant: green pseudostem, huge\n *   paddle leaves that arch up and over — each leaf built as THREE cloth\n *   strips side by side, because banana leaves split along their veins\n *   and the strips fluttering out of phase with each other IS that split.\n */\n\nexport interface TropicalTree extends Prop {\n  /** Advance the leaves' cloth. */\n  update(dt: number): void;\n  /** World-ish height of the crown/stem top, for dressing. */\n  crownY: number;\n}\n\nexport interface PalmOptions {\n  seed?: number;\n  /** Trunk height to the crown. Default seeded 4.5–6.5. */\n  height?: number;\n  /** Sideways lean of the whole trunk, radians. Default seeded 0.1–0.3. */\n  lean?: number;\n  /** Fronds in the crown. Default 9. */\n  fronds?: number;\n  /** Coconuts. Default seeded 2–4. */\n  coconuts?: number;\n}\n\nexport interface BananaOptions {\n  seed?: number;\n  /** Pseudostem height. Default seeded 1.6–2.4. */\n  height?: number;\n  /** Leaves. Default 6. */\n  leaves?: number;\n  /** Hang a bunch of bananas. Default seeded (about half of them). */\n  fruiting?: boolean;\n}\n\n/** A tapered leaf strip: fixed edge at x=0, fly at x=len, width in Y. */\nfunction leafGeometry(len: number, width: number, tipWidth: number): PlaneGeometry {\n  const geo = new PlaneGeometry(len, width, 10, 2);\n  geo.translate(len / 2, 0, 0);\n  const pos = geo.getAttribute('position');\n  for (let i = 0; i < pos.count; i++) {\n    // Clamped: float32 storage can leave the fixed edge a few nanometres\n    // NEGATIVE after the translate, and pow(-2e-8, 1.4) is NaN.\n    const t = Math.max(0, pos.getX(i) / len);\n    const taper = 1 - (1 - tipWidth / width) * Math.pow(t, 1.4);\n    pos.setY(i, pos.getY(i) * taper);\n  }\n  return geo;\n}\n\n/**\n * Mount one cloth leaf on a crown: azimuth around the trunk, drooped by\n * `pitch`, fluttering with its own phase. Returns its wave uniforms.\n */\nfunction mountLeaf(\n  crown: Group,\n  geo: PlaneGeometry,\n  color: number,\n  len: number,\n  width: number,\n  pitch: number,\n  azimuth: number,\n  phase: number,\n  sag: number,\n  amp: number,\n  cacheKey: string\n): { value: number } {\n  const material = wavingClothMaterial({\n    freeLen: len,\n    crossLen: width,\n    amp,\n    waves: 1.6,\n    speed: 1.7,\n    sag,\n    phase,\n    cacheKey,\n    color,\n    roughness: 0.85,\n  });\n  const az = new Group();\n  az.rotation.y = azimuth;\n  const tilt = new Group();\n  tilt.rotation.z = -pitch;\n  const leaf = new Mesh(geo, material);\n  leaf.rotation.x = -Math.PI / 2; // leaf lies flat; the cloth ripple turns vertical\n  tilt.add(leaf);\n  az.add(tilt);\n  crown.add(az);\n  return (material.userData.waveUniforms as { uTime: { value: number } }).uTime;\n}\n\nexport function createPalm(options: PalmOptions = {}): TropicalTree {\n  const rng = new Rng(options.seed ?? 1);\n  const height = options.height ?? rng.range(4.5, 6.5);\n  const lean = options.lean ?? rng.range(0.1, 0.3);\n  const fronds = Math.max(4, options.fronds ?? 9);\n  const coconuts = options.coconuts ?? Math.floor(rng.range(2, 5));\n\n  const group = new Group();\n  group.name = 'palm';\n  const bark = createSurface('bark', { seed: options.seed ?? 1, color: 0x9b7d55 });\n\n  // The trunk: stacked segments curving into the lean — a straight palm\n  // reads as a lamp post.\n  const segs = 7;\n  let x = 0;\n  let y = 0;\n  let angle = 0;\n  const trunk = new Group();\n  trunk.name = 'trunk';\n  for (let i = 0; i < segs; i++) {\n    const t = i / (segs - 1);\n    const segLen = height / segs;\n    const r0 = 0.16 * (1 - t * 0.5);\n    const seg = new Mesh(new CylinderGeometry(r0 * 0.92, r0, segLen * 1.08, 7), bark);\n    angle = lean * Math.pow(t, 1.4);\n    seg.rotation.z = -angle;\n    seg.position.set(x + Math.sin(angle) * segLen * 0.5, y + Math.cos(angle) * segLen * 0.5, 0);\n    x += Math.sin(angle) * segLen;\n    y += Math.cos(angle) * segLen;\n    trunk.add(seg);\n  }\n  group.add(trunk);\n\n  const crown = new Group();\n  crown.name = 'crown';\n  crown.position.set(x, y, 0);\n  crown.rotation.z = -angle * 0.6;\n  group.add(crown);\n\n  const times: Array<{ value: number }> = [];\n  const frondGeo = leafGeometry(2.3, 0.5, 0.06);\n  for (let i = 0; i < fronds; i++) {\n    const shade = 0x2f7d3a + Math.floor(rng.next() * 3) * 0x000a04;\n    // Upper fronds reach out; lower ones hang — the fountain silhouette.\n    const pitch = 0.15 + (i / fronds) * 1.15 + rng.range(-0.08, 0.08);\n    times.push(\n      mountLeaf(\n        crown,\n        frondGeo,\n        shade,\n        2.3,\n        0.5,\n        pitch,\n        (i / fronds) * Math.PI * 2 + rng.range(-0.2, 0.2),\n        rng.next() * Math.PI * 2,\n        0.55,\n        0.09,\n        'scena-palm-frond'\n      )\n    );\n  }\n\n  const nutMat = new MeshStandardMaterial({ color: 0x6d5a30, roughness: 0.9, flatShading: true });\n  for (let i = 0; i < coconuts; i++) {\n    const nut = new Mesh(new SphereGeometry(0.11, 7, 6), nutMat);\n    const a = rng.next() * Math.PI * 2;\n    nut.position.set(Math.cos(a) * 0.16, -0.12, Math.sin(a) * 0.16);\n    nut.name = 'coconut';\n    crown.add(nut);\n  }\n\n  let time = rng.next() * 10;\n  return {\n    object: group,\n    obstacleRadius: 0.3,\n    crownY: y,\n    update(dt: number): void {\n      time += dt;\n      for (const t of times) t.value = time;\n      // The whole crown breathes a little on top of the flutter.\n      crown.rotation.x = Math.sin(time * 0.4) * 0.02;\n    },\n  };\n}\n\nexport function createBananaTree(options: BananaOptions = {}): TropicalTree {\n  const rng = new Rng(options.seed ?? 1);\n  const height = options.height ?? rng.range(1.6, 2.4);\n  const leaves = Math.max(3, options.leaves ?? 6);\n  const fruiting = options.fruiting ?? rng.next() < 0.5;\n\n  const group = new Group();\n  group.name = 'banana';\n\n  const stem = new Mesh(\n    new CylinderGeometry(0.07, 0.13, height, 7),\n    new MeshStandardMaterial({ color: 0x7fa04a, roughness: 0.8, flatShading: true })\n  );\n  stem.name = 'stem';\n  stem.position.y = height / 2;\n  group.add(stem);\n\n  const crown = new Group();\n  crown.name = 'crown';\n  crown.position.y = height;\n  group.add(crown);\n\n  const times: Array<{ value: number }> = [];\n  const len = 1.7;\n  const stripW = 0.24;\n  for (let i = 0; i < leaves; i++) {\n    const azimuth = (i / leaves) * Math.PI * 2 + rng.range(-0.25, 0.25);\n    // Arch up and over: pitched UP at the stem, sagged down at the tip.\n    const pitch = -0.55 + rng.range(-0.1, 0.1) + (i % 2) * 0.25;\n    const shade = 0x3a8a3f + (i % 3) * 0x000c05;\n    // THREE strips per leaf, fluttering out of phase: the split of a\n    // banana leaf along its veins, done with fabric instead of cuts.\n    for (const off of [-1, 0, 1]) {\n      const geo = leafGeometry(len, stripW, 0.09);\n      geo.translate(0, off * (stripW + 0.015), 0);\n      times.push(\n        mountLeaf(\n          crown,\n          geo,\n          shade,\n          len,\n          stripW * 3.2,\n          pitch,\n          azimuth,\n          rng.next() * Math.PI * 2,\n          0.75,\n          0.07,\n          'scena-banana-leaf'\n        )\n      );\n    }\n  }\n\n  if (fruiting) {\n    const bunch = new Group();\n    bunch.name = 'bunch';\n    const skin = new MeshStandardMaterial({ color: 0xd9c353, roughness: 0.75, flatShading: true });\n    for (let tier = 0; tier < 3; tier++) {\n      for (let i = 0; i < 5; i++) {\n        const a = (i / 5) * Math.PI * 2;\n        const banana = new Mesh(new CylinderGeometry(0.022, 0.03, 0.16, 5), skin);\n        banana.position.set(Math.cos(a) * 0.07, -tier * 0.12, Math.sin(a) * 0.07);\n        banana.rotation.z = 0.35;\n        banana.rotation.y = -a;\n        bunch.add(banana);\n      }\n    }\n    bunch.position.set(0.16, -0.2, 0);\n    crown.add(bunch);\n  }\n\n  let time = rng.next() * 10;\n  return {\n    object: group,\n    obstacleRadius: 0.25,\n    crownY: height,\n    update(dt: number): void {\n      time += dt;\n      for (const t of times) t.value = time;\n      crown.rotation.y = Math.sin(time * 0.3) * 0.015;\n    },\n  };\n}\n","import {\n  BoxGeometry,\n  BufferAttribute,\n  BufferGeometry,\n  Color,\n  DoubleSide,\n  Group,\n  Matrix4,\n  Mesh,\n  MeshStandardMaterial,\n  Vector3,\n} from 'three';\nimport { Rng } from '../core/random';\nimport type { Prop } from '../core/types';\n\n/**\n * The lagoon — the turquoise pool the postcard is actually of.\n *\n * Not surf: a big, calm, SWIMMABLE basin of clear water — the sheltered\n * pool behind the reef, with the open ocean out on the horizon where it\n * belongs. The build is three honest layers: a sandy **bowl** (visible\n * through the water, because clear water IS its bottom), a **surface**\n * whose colour runs pale at the rim to deep turquoise over the middle,\n * gently rippling, and **fish** — small, colourful, and busy, each on a\n * seeded circuit of its own, wiggling as it goes.\n *\n * ```ts\n * const lagoon = createLagoon({ seed: 7, radius: 9 });\n * scene.add(lagoon.object);\n * game.onUpdate((t) => lagoon.update(t.delta));\n * ```\n *\n * ## Swimmers drop straight in\n *\n * The lagoon is structurally ANIMA's `WaterBody` — `surfaceY`,\n * `depthAt(x, z)`, `disturb()` — so a `Swimming` character needs no\n * adapter at all: hand them the lagoon and they swim in it. `depthAt` is\n * world-space and rides the prop's transform, like every SCENA field.\n *\n * The outline is organic — a seeded radial wobble, never a circle — and\n * the bowl is deepest a little off-centre, the way real lagoons are.\n */\n\nexport interface LagoonOptions {\n  seed?: number;\n  /** Mean radius of the pool, metres. Default 9. */\n  radius?: number;\n  /** Depth at the deep point, metres. Default 1.8. */\n  depth?: number;\n  /** Water level, local Y. Default 0. */\n  level?: number;\n  /** Fish in the water. Default 14. */\n  fish?: number;\n}\n\nexport interface Lagoon extends Prop {\n  /** ANIMA `WaterBody`, structurally: the water's local surface height. */\n  surfaceY: number;\n  /** Water depth at a world point, metres; 0 outside the pool. */\n  depthAt(x: number, z: number): number;\n  /** A ripple hook (a swimmer's kick). Accepted, gently ignored for now. */\n  disturb(x: number, z: number, strength?: number): void;\n  update(dt: number): void;\n}\n\nconst FISH_COLORS = [0xe8722c, 0x2f7fd4, 0xe8c832, 0xd44a6a, 0x35c0b0, 0xf0f0e8];\n\nexport function createLagoon(options: LagoonOptions = {}): Lagoon {\n  const rng = new Rng(options.seed ?? 1);\n  const R = options.radius ?? 9;\n  const maxDepth = options.depth ?? 1.8;\n  const level = options.level ?? 0;\n  const fishCount = Math.max(0, options.fish ?? 14);\n\n  // The outline: a seeded wobble, so no two lagoons are the same pool.\n  const p3 = rng.next() * Math.PI * 2;\n  const p5 = rng.next() * Math.PI * 2;\n  const w3 = rng.range(0.1, 0.18);\n  const w5 = rng.range(0.05, 0.1);\n  const rim = (theta: number): number =>\n    R * (1 + w3 * Math.sin(3 * theta + p3) + w5 * Math.sin(5 * theta + p5));\n  // Deepest a little off-centre, the way real pools are.\n  const deepX = rng.range(-0.25, 0.25) * R;\n  const deepZ = rng.range(-0.25, 0.25) * R;\n  const depthLocal = (x: number, z: number): number => {\n    const theta = Math.atan2(z, x);\n    const edge = rim(theta);\n    const d = Math.hypot(x, z);\n    if (d >= edge) return 0;\n    const toDeep = Math.hypot(x - deepX, z - deepZ) / (edge * 1.05);\n    const bowl = Math.pow(Math.max(0, 1 - toDeep), 0.9);\n    // Shallow shelf at the rim, bowl toward the deep point.\n    const shelf = Math.pow(1 - d / edge, 0.55);\n    return maxDepth * Math.min(1, bowl * 0.75 + shelf * 0.45);\n  };\n\n  const group = new Group();\n  group.name = 'lagoon';\n\n  // --- Fan discs for the bowl and the surface, on the same outline.\n  const RINGS = 9;\n  const SPOKES = 40;\n  const SPOKES_APRON = 40;\n  const buildDisc = (\n    yAt: (x: number, z: number, edgeT: number) => number,\n    colorAt: (x: number, z: number, edgeT: number) => [number, number, number]\n  ): BufferGeometry => {\n    const verts: number[] = [0, yAt(0, 0, 0), 0];\n    const cols: number[] = [...colorAt(0, 0, 0)];\n    const idx: number[] = [];\n    for (let ring = 1; ring <= RINGS; ring++) {\n      const t = ring / RINGS;\n      for (let s = 0; s < SPOKES; s++) {\n        const theta = (s / SPOKES) * Math.PI * 2;\n        const x = Math.cos(theta) * rim(theta) * t;\n        const z = Math.sin(theta) * rim(theta) * t;\n        verts.push(x, yAt(x, z, t), z);\n        cols.push(...colorAt(x, z, t));\n      }\n    }\n    const at = (ring: number, s: number): number =>\n      ring === 0 ? 0 : 1 + (ring - 1) * SPOKES + (s % SPOKES);\n    for (let s = 0; s < SPOKES; s++) idx.push(0, at(1, s + 1), at(1, s));\n    for (let ring = 1; ring < RINGS; ring++) {\n      for (let s = 0; s < SPOKES; s++) {\n        const a = at(ring, s);\n        const b = at(ring, s + 1);\n        const c = at(ring + 1, s);\n        const d = at(ring + 1, s + 1);\n        idx.push(a, b, c, b, d, c);\n      }\n    }\n    const geo = new BufferGeometry();\n    geo.setAttribute('position', new BufferAttribute(new Float32Array(verts), 3));\n    geo.setAttribute('color', new BufferAttribute(new Float32Array(cols), 3));\n    geo.setIndex(idx);\n    geo.computeVertexNormals();\n    return geo;\n  };\n\n  // The bowl: pale wet sand, darkening slightly with depth.\n  const sandShallow = new Color(0xd8c398);\n  const sandDeep = new Color(0xb09a72);\n  const bottom = new Mesh(\n    buildDisc(\n      (x, z) => level - depthLocal(x, z) - 0.02,\n      (x, z) => {\n        const t = depthLocal(x, z) / maxDepth;\n        const c = sandShallow.clone().lerp(sandDeep, t);\n        return [c.r, c.g, c.b];\n      }\n    ),\n    new MeshStandardMaterial({ vertexColors: true, roughness: 1 })\n  );\n  bottom.name = 'bottom';\n  group.add(bottom);\n\n  // The water: rim-pale to mid-deep turquoise, translucent so the bowl\n  // and the fish show through — clear water IS its bottom.\n  // A sand APRON around the pool: a low berm rising just past the rim and\n  // falling away outside, so the lagoon seats into ANY ground plane with\n  // no coplanar seam to z-fight (the mottled-water bug, by screenshot).\n  {\n    const verts: number[] = [];\n    const cols: number[] = [];\n    const idx: number[] = [];\n    const RADII = [1.0, 1.12, 1.45];\n    const YS = [-0.02, 0.06, -0.12];\n    const apronIn = new Color(0xdcc79b);\n    const apronOut = new Color(0xe2cf9f);\n    for (let ring = 0; ring < RADII.length; ring++) {\n      for (let s = 0; s < SPOKES_APRON; s++) {\n        const theta = (s / SPOKES_APRON) * Math.PI * 2;\n        const r = rim(theta) * RADII[ring];\n        verts.push(Math.cos(theta) * r, level + YS[ring], Math.sin(theta) * r);\n        const c = ring === 0 ? apronIn : apronOut;\n        cols.push(c.r, c.g, c.b);\n      }\n    }\n    for (let ring = 0; ring < RADII.length - 1; ring++) {\n      for (let s = 0; s < SPOKES_APRON; s++) {\n        const a = ring * SPOKES_APRON + s;\n        const b = ring * SPOKES_APRON + ((s + 1) % SPOKES_APRON);\n        const c = (ring + 1) * SPOKES_APRON + s;\n        const d = (ring + 1) * SPOKES_APRON + ((s + 1) % SPOKES_APRON);\n        idx.push(a, b, c, b, d, c);\n      }\n    }\n    const geo = new BufferGeometry();\n    geo.setAttribute('position', new BufferAttribute(new Float32Array(verts), 3));\n    geo.setAttribute('color', new BufferAttribute(new Float32Array(cols), 3));\n    geo.setIndex(idx);\n    geo.computeVertexNormals();\n    const apron = new Mesh(geo, new MeshStandardMaterial({ vertexColors: true, roughness: 1 }));\n    apron.name = 'apron';\n    group.add(apron);\n  }\n\n  const rimColor = new Color(0xaef2e4);\n  const deepColor = new Color(0x1fa8b0);\n  const water = new Mesh(\n    buildDisc(\n      () => level,\n      (x, z) => {\n        const t = Math.min(1, (depthLocal(x, z) / maxDepth) * 1.25);\n        const c = rimColor.clone().lerp(deepColor, Math.pow(t, 0.8));\n        return [c.r, c.g, c.b];\n      }\n    ),\n    new MeshStandardMaterial({\n      vertexColors: true,\n      transparent: true,\n      opacity: 0.62,\n      roughness: 0.12,\n      metalness: 0,\n      side: DoubleSide,\n      depthWrite: false,\n    })\n  );\n  water.name = 'water';\n  group.add(water);\n  const waterPos = water.geometry.getAttribute('position');\n  const waterRest = (waterPos.array as Float32Array).slice();\n\n  // --- The fish: each on a seeded circuit, wiggling as it goes.\n  interface Fish {\n    node: Group;\n    cx: number;\n    cz: number;\n    orbit: number;\n    swimY: number;\n    speed: number;\n    phase: number;\n    wiggle: number;\n  }\n  const fishGroup = new Group();\n  fishGroup.name = 'fish';\n  group.add(fishGroup);\n  const fishes: Fish[] = [];\n  for (let i = 0; i < fishCount; i++) {\n    const color = FISH_COLORS[Math.floor(rng.next() * FISH_COLORS.length)];\n    const mat = new MeshStandardMaterial({ color, roughness: 0.5, flatShading: true });\n    const node = new Group();\n    // A fish in four boxes: body, nose, tail fin, top fin.\n    const bodyMesh = new Mesh(new BoxGeometry(0.2, 0.08, 0.035), mat);\n    const nose = new Mesh(new BoxGeometry(0.06, 0.05, 0.028), mat);\n    nose.position.x = 0.12;\n    const tailMat = new MeshStandardMaterial({\n      color: new Color(color).offsetHSL(0.04, 0, -0.08).getHex(),\n      roughness: 0.5,\n      flatShading: true,\n    });\n    const tail = new Mesh(new BoxGeometry(0.07, 0.06, 0.012), tailMat);\n    tail.position.x = -0.13;\n    const fin = new Mesh(new BoxGeometry(0.07, 0.04, 0.012), tailMat);\n    fin.position.y = 0.055;\n    node.add(bodyMesh, nose, tail, fin);\n    fishGroup.add(node);\n    // The circuit: an ellipse of its own, safely inside the rim shelf.\n    const a = rng.next() * Math.PI * 2;\n    const cd = rng.next() * 0.35 * R;\n    const d = depthLocal(Math.cos(a) * cd, Math.sin(a) * cd);\n    fishes.push({\n      node,\n      cx: Math.cos(a) * cd,\n      cz: Math.sin(a) * cd,\n      // Never an orbit that grazes the rim: home is the middle of the pool.\n      orbit: Math.min(rng.range(0.18, 0.42) * R, 0.66 * R - cd),\n      swimY: level - Math.min(d * 0.7, rng.range(0.35, 1.1)),\n      speed: rng.range(0.25, 0.6) * (rng.next() < 0.5 ? 1 : -1),\n      phase: rng.next() * Math.PI * 2,\n      wiggle: rng.range(5, 8),\n    });\n  }\n\n  let time = rng.next() * 20;\n  const world = new Vector3();\n  const inverse = new Matrix4();\n\n  return {\n    object: group,\n    obstacleRadius: 0,\n    surfaceY: level,\n\n    depthAt(x: number, z: number): number {\n      group.updateWorldMatrix(true, false);\n      inverse.copy(group.matrixWorld).invert();\n      world.set(x, 0, z).applyMatrix4(inverse);\n      return depthLocal(world.x, world.z);\n    },\n\n    disturb(): void {\n      // A swimmer's kick. The surface is already alive; accepted quietly.\n    },\n\n    update(dt: number): void {\n      time += dt;\n      // The surface breathes: two slow crossing ripples, centimetres tall.\n      for (let i = 0; i < waterPos.count; i++) {\n        const x = waterRest[i * 3];\n        const z = waterRest[i * 3 + 2];\n        waterPos.setY(\n          i,\n          level +\n            0.02 * Math.sin(x * 0.9 + time * 1.1) +\n            0.015 * Math.sin(z * 1.3 - time * 0.8 + 1.7)\n        );\n      }\n      waterPos.needsUpdate = true;\n\n      for (const fish of fishes) {\n        const t = time * fish.speed + fish.phase;\n        const x = fish.cx + Math.cos(t) * fish.orbit;\n        const z = fish.cz + Math.sin(t) * fish.orbit * 0.75;\n        // A fish follows the sand up over the shelf and never beaches:\n        // preferred depth, clamped inside [just under the surface, just\n        // above the bottom] wherever the circuit has taken it.\n        const d = depthLocal(x, z);\n        const y = Math.max(fish.swimY + Math.sin(t * 2.3) * 0.05, -(Math.max(0.12, d) - 0.07));\n        fish.node.position.set(x, Math.min(-0.06, y), z);\n        // Face travel, wiggle the tail-end via a little yaw shimmy.\n        const heading = Math.atan2(\n          Math.cos(t) * fish.orbit * 0.75 * Math.sign(fish.speed),\n          -Math.sin(t) * fish.orbit * Math.sign(fish.speed)\n        );\n        fish.node.rotation.y = heading + Math.sin(time * fish.wiggle) * 0.18;\n      }\n    },\n  };\n}\n","import {\n  BoxGeometry,\n  BufferAttribute,\n  BufferGeometry,\n  Color,\n  CylinderGeometry,\n  DoubleSide,\n  Group,\n  Mesh,\n  MeshStandardMaterial,\n} from 'three';\nimport { Rng } from '../core/random';\nimport { createSurface } from '../materials/surface';\nimport { wavingClothMaterial } from '../materials/clothWave';\nimport { createSlot, addApproach } from '../core/types';\nimport type { Prop, PropSlot } from '../core/types';\n\n/**\n * The beach kit — Miami.\n *\n * The props that turn sand into a BEACH: the art-deco lifeguard stand,\n * the striped umbrella, the lounger. Miami Beach's lifeguard towers are\n * the reason this file has a palette: they are pastel geometric huts on\n * stilts, no two the same colour, and a beach with a row of them is\n * unmistakably that beach.\n *\n * ```ts\n * const tower = createLifeguardTower({ seed: 3 });\n * const shade = createBeachUmbrella({ seed: 4 });\n * const chair = createLounger({ seed: 5, recline: 'reading' });\n * ```\n *\n * Cloth wherever cloth belongs: the tower's pennant and the umbrella's\n * valance are driven by the shared cloth-wave shader (the same one\n * behind the flags and the palm fronds), so the beach moves even when\n * nothing is happening.\n */\n\n/** The Ocean Drive palette: pastels that only look right in that light. */\nexport const MIAMI_COLORS = [\n  0x35cfc9, // aqua\n  0xff6f91, // flamingo\n  0xffd166, // lemon\n  0x8ce99a, // mint\n  0xff9f6b, // coral\n  0x7ac6ff, // sky\n  0xf5f0e6, // shell white\n];\n\nexport interface LifeguardTowerOptions {\n  seed?: number;\n  /** Deck height above the sand. Default seeded 1.5–2.2. */\n  height?: number;\n  /** Body colour. Default: a seeded Miami pastel. */\n  color?: number;\n  /** Trim/roof colour. Default: a contrasting seeded pastel. */\n  trim?: number;\n  /** Fly a surf pennant. Default true. */\n  pennant?: boolean;\n}\n\nexport interface BeachUmbrellaOptions {\n  seed?: number;\n  /** Canopy radius. Default seeded 1.1–1.5. */\n  radius?: number;\n  /** Pole height to the hub. Default seeded 2.0–2.4. */\n  height?: number;\n  /** The two stripe colours. Default: seeded Miami pair. */\n  colors?: [number, number];\n  /** Lean off vertical, radians. Default seeded ±0.14. */\n  tilt?: number;\n}\n\nexport type LoungerRecline = 'flat' | 'reading' | 'upright';\n\nexport interface LoungerOptions {\n  seed?: number;\n  /** Back angle preset. Default 'reading'. */\n  recline?: LoungerRecline;\n  /** Frame colour. Default seeded pastel. */\n  color?: number;\n  /** Towel over the bed. Default seeded (about half). */\n  towel?: boolean;\n}\n\nexport interface BeachProp extends Prop {\n  update(dt: number): void;\n}\n\nconst RECLINE: Record<LoungerRecline, number> = {\n  flat: 0.06,\n  reading: 0.62,\n  upright: 1.15,\n};\n\nexport function createLifeguardTower(options: LifeguardTowerOptions = {}): BeachProp {\n  const rng = new Rng(options.seed ?? 1);\n  const H = options.height ?? rng.range(1.5, 2.2);\n  const body = options.color ?? MIAMI_COLORS[Math.floor(rng.next() * MIAMI_COLORS.length)];\n  const trim =\n    options.trim ??\n    (() => {\n      // A contrasting pastel: never the body colour back again.\n      const others = MIAMI_COLORS.filter((c) => c !== body);\n      return others[Math.floor(rng.next() * others.length)];\n    })();\n\n  const group = new Group();\n  group.name = 'lifeguard-tower';\n  const paint = (color: number, rough = 0.65): MeshStandardMaterial =>\n    new MeshStandardMaterial({ color, roughness: rough, flatShading: true });\n  const bodyMat = paint(body);\n  const trimMat = paint(trim);\n  const wood = createSurface('plank', { seed: options.seed ?? 1, color: 0xd8c9a8 });\n\n  const W = 2.0;\n  const D = 1.8;\n\n  // Stilts, raked outward — a tower on plumb legs looks like a table.\n  const legGeo = new BoxGeometry(0.12, H + 0.3, 0.12);\n  for (const sx of [-1, 1]) {\n    for (const sz of [-1, 1]) {\n      const leg = new Mesh(legGeo, trimMat);\n      leg.position.set(sx * (W / 2 - 0.16), (H + 0.3) / 2 - 0.2, sz * (D / 2 - 0.16));\n      leg.rotation.z = -sx * 0.06;\n      leg.rotation.x = sz * 0.05;\n      group.add(leg);\n    }\n  }\n\n  const deck = new Mesh(new BoxGeometry(W + 0.3, 0.12, D + 0.3), wood);\n  deck.name = 'deck';\n  deck.position.y = H;\n  group.add(deck);\n\n  // The cabin: three walls and a wide open front, the way a lifeguard\n  // stand actually is — you have to be able to see the water.\n  const wallH = 1.15;\n  const back = new Mesh(new BoxGeometry(W, wallH, 0.1), bodyMat);\n  back.position.set(0, H + wallH / 2, -D / 2);\n  group.add(back);\n  for (const sx of [-1, 1]) {\n    const side = new Mesh(new BoxGeometry(0.1, wallH, D), bodyMat);\n    side.position.set(sx * (W / 2), H + wallH / 2, 0);\n    group.add(side);\n    // The deco eyebrow: a bold horizontal band, the giveaway detail.\n    const band = new Mesh(new BoxGeometry(0.12, 0.13, D + 0.06), trimMat);\n    band.position.set(sx * (W / 2), H + wallH * 0.72, 0);\n    group.add(band);\n  }\n  const rail = new Mesh(new BoxGeometry(W, 0.1, 0.1), trimMat);\n  rail.position.set(0, H + 0.42, D / 2);\n  group.add(rail);\n\n  // The roof: a jaunty overhanging wedge, tilted to the sea.\n  const roof = new Mesh(new BoxGeometry(W + 0.7, 0.12, D + 0.7), trimMat);\n  roof.name = 'roof';\n  roof.position.set(0, H + wallH + 0.22, 0.05);\n  roof.rotation.x = -0.16;\n  group.add(roof);\n  const crest = new Mesh(new BoxGeometry(W * 0.5, 0.26, 0.12), bodyMat);\n  crest.position.set(0, H + wallH + 0.4, -D / 2 + 0.15);\n  group.add(crest);\n\n  // The ramp up the back — every stand has one, and it reads instantly.\n  const ramp = new Mesh(new BoxGeometry(0.7, 0.08, H * 1.5), wood);\n  ramp.position.set(0, H / 2 - 0.05, -D / 2 - H * 0.62);\n  ramp.rotation.x = Math.atan2(H, H * 1.45);\n  group.add(ramp);\n\n  const times: Array<{ value: number }> = [];\n  if (options.pennant ?? true) {\n    const mast = new Mesh(new CylinderGeometry(0.03, 0.03, 1.5, 6), trimMat);\n    mast.position.set(W / 2 - 0.1, H + wallH + 0.85, -D / 2 + 0.2);\n    group.add(mast);\n    const flagLen = 0.6;\n    const flagH = 0.34;\n    const geo = new BufferGeometry();\n    {\n      // A simple two-triangle pennant, fixed edge at x = 0.\n      const verts = new Float32Array([0, 0, 0, flagLen, -0.06, 0, 0, flagH, 0, flagLen, flagH - 0.1, 0]);\n      geo.setAttribute('position', new BufferAttribute(verts, 3));\n      geo.setIndex([0, 1, 2, 1, 3, 2]);\n      geo.computeVertexNormals();\n    }\n    const cloth = wavingClothMaterial({\n      freeLen: flagLen,\n      crossLen: flagH,\n      amp: 0.09,\n      waves: 2.2,\n      speed: 3.4,\n      sag: 0.03,\n      phase: rng.next() * Math.PI * 2,\n      cacheKey: 'scena-lifeguard-pennant',\n      color: 0xff3b30, // the red flag: the one everybody knows\n      roughness: 0.9,\n    });\n    const flag = new Mesh(geo, cloth);\n    flag.name = 'pennant';\n    flag.position.set(W / 2 - 0.08, H + wallH + 1.25, -D / 2 + 0.2);\n    group.add(flag);\n    times.push((cloth.userData.waveUniforms as { uTime: { value: number } }).uTime);\n  }\n\n  const slot = createSlot('watch', 'sit', group, 0, H + 0.12, -0.2);\n  const slots: PropSlot[] = [addApproach(slot, group, 1.4)];\n\n  let time = rng.next() * 10;\n  return {\n    object: group,\n    obstacleRadius: 1.3,\n    slots,\n    update(dt: number): void {\n      time += dt;\n      for (const t of times) t.value = time;\n    },\n  };\n}\n\nexport function createBeachUmbrella(options: BeachUmbrellaOptions = {}): BeachProp {\n  const rng = new Rng(options.seed ?? 1);\n  const R = options.radius ?? rng.range(1.1, 1.5);\n  const H = options.height ?? rng.range(2.0, 2.4);\n  const pair =\n    options.colors ??\n    (() => {\n      const a = MIAMI_COLORS[Math.floor(rng.next() * MIAMI_COLORS.length)];\n      const rest = MIAMI_COLORS.filter((c) => c !== a);\n      return [a, rest[Math.floor(rng.next() * rest.length)]] as [number, number];\n    })();\n  const tilt = options.tilt ?? rng.range(-0.14, 0.14);\n\n  const group = new Group();\n  group.name = 'beach-umbrella';\n  const lean = new Group();\n  lean.rotation.z = tilt;\n  lean.rotation.x = rng.range(-0.1, 0.1);\n  group.add(lean);\n\n  const pole = new Mesh(\n    new CylinderGeometry(0.035, 0.045, H, 7),\n    new MeshStandardMaterial({ color: 0xf2ede2, roughness: 0.5, flatShading: true })\n  );\n  pole.position.y = H / 2 - 0.25; // a foot of it is buried in the sand\n  lean.add(pole);\n\n  // The canopy: alternating vertex-coloured gores, drooping at the rim —\n  // an umbrella is a cone that has given up a little at the edges.\n  const GORES = 12;\n  const verts: number[] = [];\n  const cols: number[] = [];\n  const idx: number[] = [];\n  const hub = 0.14;\n  const c0 = new Color(pair[0]);\n  const c1 = new Color(pair[1]);\n  verts.push(0, hub, 0);\n  cols.push(c0.r, c0.g, c0.b);\n  for (let i = 0; i < GORES; i++) {\n    const a = (i / GORES) * Math.PI * 2;\n    const dip = rng.range(0, 0.03);\n    verts.push(Math.cos(a) * R, -0.22 - dip, Math.sin(a) * R);\n    const c = i % 2 === 0 ? c0 : c1;\n    cols.push(c.r, c.g, c.b);\n  }\n  for (let i = 0; i < GORES; i++) {\n    idx.push(0, 1 + ((i + 1) % GORES), 1 + i);\n  }\n  const canopyGeo = new BufferGeometry();\n  canopyGeo.setAttribute('position', new BufferAttribute(new Float32Array(verts), 3));\n  canopyGeo.setAttribute('color', new BufferAttribute(new Float32Array(cols), 3));\n  canopyGeo.setIndex(idx);\n  canopyGeo.computeVertexNormals();\n  const canopy = new Mesh(\n    canopyGeo,\n    new MeshStandardMaterial({\n      vertexColors: true,\n      roughness: 0.88,\n      side: DoubleSide,\n      flatShading: true,\n    })\n  );\n  canopy.name = 'canopy';\n  canopy.position.y = H - 0.25;\n  lean.add(canopy);\n\n  const finial = new Mesh(\n    new CylinderGeometry(0.02, 0.02, 0.16, 5),\n    new MeshStandardMaterial({ color: 0xf2ede2, roughness: 0.5 })\n  );\n  finial.position.y = H - 0.05;\n  lean.add(finial);\n\n  let time = rng.next() * 10;\n  const sway = rng.range(0.55, 0.9);\n  return {\n    object: group,\n    obstacleRadius: 0.2,\n    update(dt: number): void {\n      time += dt;\n      // A parasol in a sea breeze never stops moving, and never much.\n      lean.rotation.z = tilt + Math.sin(time * sway) * 0.022;\n      canopy.rotation.y = Math.sin(time * sway * 0.7) * 0.03;\n    },\n  };\n}\n\nexport function createLounger(options: LoungerOptions = {}): BeachProp {\n  const rng = new Rng(options.seed ?? 1);\n  const recline = options.recline ?? 'reading';\n  const color = options.color ?? MIAMI_COLORS[Math.floor(rng.next() * MIAMI_COLORS.length)];\n  const towel = options.towel ?? rng.next() < 0.5;\n\n  const group = new Group();\n  group.name = 'lounger';\n  const frameMat = new MeshStandardMaterial({ color: 0xf5f2ea, roughness: 0.45, flatShading: true });\n  const slatMat = new MeshStandardMaterial({ color, roughness: 0.8, flatShading: true });\n\n  const L = 1.75;\n  const W = 0.62;\n  const seatY = 0.34;\n\n  // Frame rails and stubby legs — the sand takes the rest.\n  for (const sx of [-1, 1]) {\n    const rail = new Mesh(new BoxGeometry(0.05, 0.05, L), frameMat);\n    rail.position.set(sx * (W / 2), seatY, 0);\n    group.add(rail);\n    for (const sz of [-1, 1]) {\n      const leg = new Mesh(new BoxGeometry(0.05, seatY, 0.05), frameMat);\n      leg.position.set(sx * (W / 2), seatY / 2, sz * (L / 2 - 0.18));\n      group.add(leg);\n    }\n  }\n\n  // The bed: slats, because a solid slab reads as a table.\n  const bed = new Group();\n  bed.name = 'bed';\n  for (let i = 0; i < 7; i++) {\n    const slat = new Mesh(new BoxGeometry(W, 0.035, 0.11), slatMat);\n    slat.position.set(0, seatY + 0.04, -L / 2 + 0.22 + i * 0.14);\n    bed.add(slat);\n  }\n  group.add(bed);\n\n  // The back, hinged at the head end and set to its recline.\n  const backPivot = new Group();\n  backPivot.name = 'back';\n  backPivot.position.set(0, seatY + 0.04, -L / 2 + 0.18);\n  backPivot.rotation.x = RECLINE[recline];\n  for (let i = 0; i < 5; i++) {\n    const slat = new Mesh(new BoxGeometry(W, 0.035, 0.11), slatMat);\n    slat.position.set(0, 0, -0.06 - i * 0.14);\n    backPivot.add(slat);\n  }\n  group.add(backPivot);\n\n  if (towel) {\n    const towelColor = MIAMI_COLORS[Math.floor(rng.next() * MIAMI_COLORS.length)];\n    const cloth = new Mesh(\n      new BoxGeometry(W * 0.8, 0.02, L * 0.5),\n      new MeshStandardMaterial({ color: towelColor, roughness: 0.95, flatShading: true })\n    );\n    cloth.name = 'towel';\n    cloth.position.set(rng.range(-0.04, 0.04), seatY + 0.075, rng.range(0.05, 0.3));\n    cloth.rotation.y = rng.range(-0.08, 0.08);\n    group.add(cloth);\n  }\n\n  const slot = createSlot('lie', recline === 'flat' ? 'sleep' : 'sit', group, 0, seatY + 0.1, 0.1);\n  const slots: PropSlot[] = [addApproach(slot, group, 0.85)];\n\n  return {\n    object: group,\n    obstacleRadius: 0.75,\n    slots,\n    update(): void {\n      // A lounger is furniture. It has the decency to stay still.\n    },\n  };\n}\n","import {\n  CylinderGeometry,\n  DoubleSide,\n  Group,\n  Mesh,\n  MeshBasicMaterial,\n  MeshStandardMaterial,\n  RingGeometry,\n  SphereGeometry,\n  Vector3,\n} from 'three';\nimport { Rng } from '../core/random';\nimport { DEFAULT_PALETTE, type Palette } from '../core/palette';\nimport { createSurface } from '../materials/surface';\nimport { createSlot, type Prop, type PropSlot } from '../core/types';\n\n/**\n * Seamarks — the first thing in this library whose entire purpose is **to be\n * seen from somewhere else.**\n *\n * Everything up to here has been a thing that *is*: a hull that floats, a\n * boiler that makes steam, a net that comes fast. A light is none of those. It\n * does nothing where it stands. Its whole function happens fifteen miles away\n * in somebody else's eye, and every number on it is really a number about the\n * observer.\n *\n * ## The curvature of the earth decides it, and the lamp does not\n *\n * This is the truth the module exists for, and it is the least intuitive one\n * in the whole trilogy. A light has two ranges and you get the SMALLER:\n *\n * - the **geographic** range, where it drops below the horizon — a function of\n *   how high the light is and how high your eye is, and of nothing else at all;\n * - the **luminous** range, where it gets too faint to see — a function of the\n *   lamp and the visibility.\n *\n * ```ts\n * const light = createSeamark({ kind: 'flashing' });     // 40 m, 200 000 cd\n * light.sightedFrom(x, z, 12).range;      // 18.5 nm — the lamp is the limit\n * ```\n *\n * …so make the lamp bigger. Double it, and again, and again:\n *\n * ```ts\n *    200 000 cd  ->  seen at 18.5 nm\n *    400 000 cd  ->  seen at 20.2 nm\n *    800 000 cd  ->  seen at 20.4 nm\n *  1 600 000 cd  ->  seen at 20.4 nm\n * 20 000 000 cd  ->  seen at 20.4 nm     ← a hundredfold lamp. Under two miles.\n * ```\n *\n * The horizon does not negotiate. Past that point the only thing that buys\n * range is **height** — of the tower, or of the eye looking for it, and that is\n * why lighthouses are on cliffs and why the answer to \"we cannot see it\" was\n * never a bigger lamp.\n *\n * ## The same light, the same night, and two boats that see differently\n *\n * `heightOfEye` is not a detail. A man standing in an open boat has his eye\n * about 1.5 m up; the officer on a ship's bridge has his at 12 m. They are\n * looking at the same lamp:\n *\n * ```ts\n * light.sightedFrom(x, z, 1.5).range;   // 15.7 nm, and HORIZON-limited\n * light.sightedFrom(x, z, 12).range;    // 18.5 nm, and LAMP-limited\n * ```\n *\n * Not only a different range — a different *reason*. And it inverts: with a\n * feeble light, raising your eye buys nothing whatever, because you were never\n * near the horizon to begin with.\n *\n * ## What tells you it is that light and not another one\n *\n * The era axis, and it is about **identity** rather than power:\n *\n * | kind | how you know which light it is |\n * | --- | --- |\n * | `bonfire` | you do not. It is a fire on a headland, and so is a burning house. |\n * | `harbour` | by where it is. A fixed light is a fixed light, and ships were lost mistaking one for another. |\n * | `flashing` | by its **character** — `Fl(3) 15s` is a name you can look up. |\n * | `sectored` | it tells you where **you** are: white in the fairway, red over the rocks. |\n *\n * The last one is the inversion at the end of the axis, the same shape as a\n * gyro stabiliser that needs no way from you and a self-righting boat that\n * needs no crew: a sectored light does the navigating instead of you. You do\n * not take a bearing off it. You look at its colour.\n *\n * ```ts\n * const s = light.sightedFrom(x, z, 4);\n * s.sector;   // 'red'\n * s.safe;     // false — and there is nothing else to work out\n * ```\n */\nexport type MarkKind = 'bonfire' | 'harbour' | 'flashing' | 'sectored';\n\nexport const MARK_KINDS: MarkKind[] = ['bonfire', 'harbour', 'flashing', 'sectored'];\n\n/**\n * What she has of it, as she comes up on it.\n *\n * This is the real sequence, and it is four-stated like everything else here —\n * `'loom'` is the one people forget. A light is seen in the sky for miles\n * before it is seen at all: the beam lights the haze above the horizon while\n * the lamp itself is still under it.\n *\n * `'raising'` is the narrow band where the lamp sits ON the horizon, and it is\n * not a curiosity — standing up brings it in sight and crouching puts it out,\n * and that gives a distance. It is the one navigational fix in this library\n * that costs nothing but knowing how tall you are.\n */\nexport type SightState = 'dark' | 'loom' | 'raising' | 'showing';\n\nexport interface Sector {\n  name: string;\n  /**\n   * Bearings **outward from the light** — the direction you are, seen from\n   * the tower.\n   *\n   * Charts quote sector limits the other way round, as bearings *from\n   * seaward*, and the two differ by 180°. Take one for the other and the red\n   * sector lands squarely over the fairway, which is a way of putting a ship\n   * on the rocks with entirely correct arithmetic.\n   */\n  from: number;\n  to: number;\n  colour: 'white' | 'red' | 'green';\n  /** Fraction of the lamp that gets through the glass. */\n  transmission: number;\n  /** True where this is the water you want to be in. */\n  safe: boolean;\n}\n\n/** Coloured glass eats light, and this is how much of it. */\nexport const SECTOR_TRANSMISSION: Record<'white' | 'red' | 'green', number> = {\n  white: 1,\n  red: 0.25,\n  green: 0.18,\n};\n\nexport interface Sighting {\n  /**\n   * Close enough to see it — whether or not it happens to be lit this instant.\n   *\n   * This is the question charts and passage plans ask. `visible` is the other\n   * one, and for a flashing light the two disagree most of the time: `Fl(3)\n   * 15s` is DARK for eleven and a half seconds out of every fifteen, so a\n   * caller testing `visible` once a frame sees a light that is mostly not\n   * there. Both are true statements about the same lamp.\n   */\n  inRange: boolean;\n  /** In range AND lit at this instant. */\n  visible: boolean;\n  state: SightState;\n  /** Metres from the observer to the tower. */\n  distance: number;\n  /** Radians, from the observer to the light, clockwise from north (−z). */\n  bearing: number;\n  /** How far she could see it from there, m — the SMALLER of the two. */\n  range: number;\n  /** Where it drops below the horizon, m. The lamp has no say in this. */\n  geographic: number;\n  /** Where it gets too faint, m. The horizon has no say in this. */\n  luminous: number;\n  /** Which of the two is doing the limiting — and it changes with her eye. */\n  limitedBy: 'horizon' | 'lamp';\n  /** Which sector she is in, or `null` on a light that has none. */\n  sector: Sector | null;\n  /** In the water the light says is good. `null` where it does not say. */\n  safe: boolean | null;\n  /** Is the lamp lit this instant? A flashing light is dark most of the time. */\n  showing: boolean;\n}\n\nexport interface Seamark extends Prop {\n  kind: MarkKind;\n  /** Focal plane above sea level, m. THE number for geographic range. */\n  readonly height: number;\n  /** Candela on the white bearing. */\n  readonly intensity: number;\n  /** `'Fl(3) 15s'`, `'Oc 8s'`, `'F'` — the name of its rhythm. */\n  readonly character: string;\n  /** Seconds for one complete character. `Infinity` for a fixed light. */\n  readonly period: number;\n  /** Lit this instant. */\n  readonly showing: boolean;\n  /** 0–1 through the character. */\n  readonly phase: number;\n  /**\n   * Can she tell it from another light?\n   *\n   * False for a bonfire, which is a fire like any other fire, and false for a\n   * plain fixed light, which is why characters were invented at all.\n   */\n  readonly identifiable: boolean;\n  /** On a chart at all, with a name and a daymark. A bonfire is not. */\n  readonly charted: boolean;\n\n  /** What she has of it from there. THE method. */\n  sightedFrom(x: number, z: number, heightOfEye?: number): Sighting;\n  /**\n   * The range at which a given eye raises it, m.\n   *\n   * Also a position line: see the lamp sitting on the horizon and you know how\n   * far off you are, to within the accuracy of knowing your own height.\n   */\n  dips(heightOfEye: number): number;\n  /** Where it becomes too faint, m, in the visibility she is in. */\n  luminousRange(intensity?: number): number;\n\n  /** Meteorological visibility, nautical miles. Straight out of the weather. */\n  setVisibility(nauticalMiles: number): void;\n  readonly visibility: number;\n\n  /** Add a sector, in bearings OUTWARD from the light. */\n  sector(name: string, from: number, to: number, colour: 'white' | 'red' | 'green'): void;\n  sectorAt(bearing: number): Sector | null;\n  readonly sectors: Sector[];\n  /**\n   * Draw the sectors on the water.\n   *\n   * Off by default, and it is a **chart made visible**: nothing at sea looks\n   * remotely like this. The point of the picture is that the boat can see one\n   * colour at a time and the chart can see all of them.\n   *\n   * `scale` is there because a sector arc is thirteen nautical miles long and\n   * the tower it comes out of is twenty-five metres tall. No frame holds both,\n   * and that is not a limitation of the renderer — it is the subject. Drawn to\n   * a fraction the RATIOS survive, which is what carries the one claim the\n   * picture is for: the red arc is shorter than the white one.\n   */\n  showSectors(on: boolean, scale?: number): void;\n\n  /** When you cannot see it at all. */\n  readonly fogSignal: number;\n  readonly sounding: boolean;\n  /**\n   * Audible out to here, m — and it is the least trustworthy number on the\n   * object. Sound goes over the top of you, round headlands, and into silent\n   * sectors close under the station itself.\n   */\n  readonly audibleRange: number;\n\n  station: PropSlot;\n  slots: PropSlot[];\n  update(dt: number): void;\n}\n\nexport interface SeamarkOptions {\n  kind?: MarkKind;\n  /** Focal plane above the sea, m. */\n  height?: number;\n  /** Candela. */\n  intensity?: number;\n  /** Starting meteorological visibility, nautical miles. */\n  visibility?: number;\n  seed?: number;\n  palette?: Palette;\n}\n\n/** Metres in a nautical mile. */\nexport const NM = 1852;\n/** The eye at night, lux — the threshold everything luminous is solved against. */\nconst THRESHOLD = 0.67e-6;\n\nconst TAU = Math.PI * 2;\n\n/**\n * Geographic range in METRES: how far a light of height `H` is visible to an\n * eye of height `h`, both in metres.\n *\n * `2.08(√H + √h)` nautical miles. The 2.08 rather than a bare geometric 1.93 is\n * terrestrial refraction — the atmosphere bends light down around the curve and\n * hands you about eight per cent more range than the geometry alone allows.\n */\nexport function geographicRange(height: number, heightOfEye: number): number {\n  return 2.08 * (Math.sqrt(Math.max(0, height)) + Math.sqrt(Math.max(0, heightOfEye))) * NM;\n}\n\n/**\n * Luminous range in METRES, by Allard's law, solved for the distance at which\n * a light of `intensity` candela falls to the night threshold in `visibility`\n * nautical miles of air.\n *\n * `E = I·e^(−σd) / d²`. There is no closed form for `d`, so it is bisected —\n * eighty halvings, which is exact to the width of an atom and costs nothing.\n */\nexport function luminousRange(intensity: number, visibility: number): number {\n  const I = Math.max(0, intensity);\n  if (I <= 0) return 0;\n  const sigma = 3 / Math.max(0.05, visibility);\n  const at = (nm: number): number => (I * Math.exp(-sigma * nm)) / Math.pow(nm * NM, 2);\n  let lo = 0.0005;\n  let hi = 300;\n  if (at(lo) < THRESHOLD) return 0;\n  for (let i = 0; i < 80; i++) {\n    const mid = (lo + hi) / 2;\n    if (at(mid) > THRESHOLD) lo = mid;\n    else hi = mid;\n  }\n  return lo * NM;\n}\n\ninterface CharSpec {\n  label: string;\n  /** Flashes in a group. */\n  flashes: number;\n  /** Seconds each flash is lit. */\n  on: number;\n  /** Seconds between flashes within the group. */\n  gap: number;\n  /** Seconds for the whole thing. `Infinity` is a fixed light. */\n  period: number;\n}\n\ninterface KindSpec {\n  height: number;\n  intensity: number;\n  char: CharSpec;\n  charted: boolean;\n  /** Can you tell it from the next one along the coast? */\n  identifiable: boolean;\n  /** Painted bands, which is how you know it by DAY — a light is a mark\n   *  around the clock and is unlit for half of it. */\n  bands: number;\n  /** Seconds between blasts. `Infinity` for a station with no signal. */\n  fog: number;\n  /** How loud, as a range in metres. */\n  audible: number;\n}\n\nconst FIXED: CharSpec = { label: 'F', flashes: 1, on: Infinity, gap: 0, period: Infinity };\n\nconst KINDS: Record<MarkKind, KindSpec> = {\n  // A fire on a headland. It is bright by the standards of a candle and feeble\n  // by the standards of a lighthouse, it has no rhythm whatever, and there is\n  // nothing about it that says it is not a burning barn.\n  bonfire: {\n    height: 18, intensity: 1200, char: FIXED,\n    charted: false, identifiable: false, bands: 0, fog: Infinity, audible: 0,\n  },\n  // Charted, in a known place, with a daymark — and still a FIXED light, so a\n  // stranger cannot tell it from the next fixed light along the coast. Ships\n  // were lost doing exactly that, and that is why the next row exists.\n  harbour: {\n    height: 12, intensity: 6000, char: FIXED,\n    charted: true, identifiable: false, bands: 0, fog: 30, audible: 2 * NM,\n  },\n  // A CHARACTER. Three flashes every fifteen seconds is a name, and a name can\n  // be looked up in a book, and a light with a name cannot be mistaken for a\n  // light with a different one.\n  flashing: {\n    height: 40, intensity: 200000,\n    char: { label: 'Fl(3) 15s', flashes: 3, on: 0.4, gap: 1.0, period: 15 },\n    charted: true, identifiable: true, bands: 3, fog: 20, audible: 3 * NM,\n  },\n  // …and this one tells you where YOU are.\n  sectored: {\n    height: 25, intensity: 100000,\n    char: { label: 'Oc 8s', flashes: 1, on: 6, gap: 0, period: 8 },\n    charted: true, identifiable: true, bands: 2, fog: 15, audible: 2.5 * NM,\n  },\n};\n\nexport function createSeamark(options: SeamarkOptions = {}): Seamark {\n  const kind = options.kind ?? 'flashing';\n  const base = KINDS[kind];\n  const H = options.height ?? base.height;\n  const I = options.intensity ?? base.intensity;\n  const seed = options.seed ?? 1;\n  const rng = new Rng(seed);\n  const palette = options.palette ?? DEFAULT_PALETTE;\n  let visibility = options.visibility ?? 10;\n\n  const group = new Group();\n  group.name = `seamark:${kind}`;\n\n  const stone = createSurface('ashlar', { color: 0xd9d4c8, seed });\n  const dark = createSurface('paintedMetal', { color: 0x2e3338, seed: seed + 1 });\n  const lampMat = new MeshStandardMaterial({\n    color: 0xfff3d0,\n    emissive: palette.lampGlow,\n    emissiveIntensity: 2.4,\n    roughness: 0.3,\n  });\n  /**\n   * The halo, and it is NOT additive.\n   *\n   * Additive blending can only add light, so a halo drawn that way is invisible\n   * against anything already bright — and a light is a thing you look at\n   * against a sky. Plain transparency reads at dusk and at night both.\n   */\n  const haloMat = new MeshBasicMaterial({\n    color: palette.lampGlow,\n    transparent: true,\n    opacity: 0.4,\n    depthWrite: false,\n  });\n\n  // ── geometry ─────────────────────────────────────────────────────────\n\n  const lantern = new Group();\n  lantern.name = 'seamark:lantern';\n\n  if (kind === 'bonfire') {\n    // No tower. A stone platform on the head, and a fire on top of it, which\n    // is the entire technology and most of the history.\n    const plinth = new Mesh(new CylinderGeometry(2.6, 3.2, H * 0.9, 10), stone);\n    plinth.position.y = (H * 0.9) / 2;\n    group.add(plinth);\n    const basket = new Mesh(new CylinderGeometry(1.5, 1.1, H * 0.16, 10, 1, true), dark);\n    basket.position.y = H * 0.95;\n    group.add(basket);\n  } else {\n    const shaft = new Mesh(new CylinderGeometry(2.1, 3.4, H * 0.92, 14), stone);\n    shaft.position.y = (H * 0.92) / 2;\n    group.add(shaft);\n    // THE DAYMARK. A lighthouse is a mark around the clock and is unlit for\n    // half of it, so the bands are not decoration — they are how she is\n    // identified in daylight, when the whole rest of this module is asleep.\n    for (let i = 0; i < base.bands; i++) {\n      const t = (i + 0.5) / (base.bands + 0.4);\n      const r = 3.4 - (3.4 - 2.1) * t;\n      const band = new Mesh(\n        new CylinderGeometry(r + 0.03, r + 0.03, (H * 0.92) / (base.bands * 2.2), 14),\n        dark\n      );\n      band.position.y = t * H * 0.92;\n      group.add(band);\n    }\n    const gallery = new Mesh(new CylinderGeometry(2.9, 2.9, 0.22, 14), dark);\n    gallery.position.y = H * 0.92;\n    group.add(gallery);\n    const room = new Mesh(new CylinderGeometry(1.8, 2.0, H * 0.13, 12, 1, true), dark);\n    room.position.y = H;\n    group.add(room);\n    const cap = new Mesh(new CylinderGeometry(0.35, 1.9, H * 0.06, 12), dark);\n    cap.position.y = H * 1.09;\n    group.add(cap);\n  }\n  /**\n   * THE FOCAL PLANE, and it is exactly `height`.\n   *\n   * Every range on this object is worked out from that number, so the lamp had\n   * better be at it. Hung off a fraction of the tower instead, the arithmetic\n   * says eighteen metres and the picture shows fourteen — numbers agreeing\n   * while the geometry is four metres out, which is the commonest defect in\n   * this library and the one no amount of correct maths catches.\n   */\n  lantern.position.y = H;\n  group.add(lantern);\n\n  const lamp = new Mesh(new SphereGeometry(kind === 'bonfire' ? 1.2 : 1.05, 12, 10), lampMat);\n  lamp.name = 'seamark:lamp';\n  lantern.add(lamp);\n  // A light looks far bigger than its lamp, and at any range that shows what a\n  // light is FOR, the lamp itself is a fraction of a pixel. The halo is not the\n  // glass; it is how a light reads.\n  const halo = new Mesh(new SphereGeometry(Math.max(2.4, H * 0.28), 12, 10), haloMat);\n  halo.name = 'seamark:halo';\n  lantern.add(halo);\n\n  /** The sectors, painted on the water — off unless somebody asks. */\n  const chart = new Group();\n  chart.name = 'seamark:sectors';\n  chart.visible = false;\n  chart.position.y = 1.2;\n  group.add(chart);\n\n  const station = createSlot('seamark', 'watch', group, 4.2, 0, 0, -Math.PI / 2);\n\n  // ── the model ────────────────────────────────────────────────────────\n\n  const sectors: Sector[] = [];\n  let chartScale = 1;\n  let clock = rng.next() * (base.char.period === Infinity ? 1 : base.char.period);\n  let showing = true;\n  let phase = 0;\n\n  const groupLength =\n    base.char.period === Infinity\n      ? Infinity\n      : base.char.flashes * base.char.on + (base.char.flashes - 1) * base.char.gap;\n\n  const litAt = (t: number): boolean => {\n    if (base.char.period === Infinity) return true;\n    const p = t % base.char.period;\n    if (p >= groupLength) return false;\n    if (base.char.gap <= 0) return true;\n    return p % (base.char.on + base.char.gap) < base.char.on;\n  };\n\n  const rebuildChart = (): void => {\n    for (const c of [...chart.children]) chart.remove(c);\n    if (!sectors.length) return;\n    for (const s of sectors) {\n      // The wedge is drawn out to the range THIS colour actually reaches, not\n      // to some common radius — a red sector is always shorter than the white\n      // one beside it, because the glass eats three quarters of the lamp.\n      const reach = luminousRange(I * s.transmission, visibility) * chartScale;\n      const span = ((s.to - s.from + TAU) % TAU) || TAU;\n      const ring = new Mesh(\n        new RingGeometry(\n          Math.min(6, reach * 0.02),\n          Math.max(8, reach),\n          Math.max(6, Math.round(span * 12)),\n          1,\n          0,\n          span\n        ),\n        new MeshBasicMaterial({\n          color: s.colour === 'red' ? 0xd1443a : s.colour === 'green' ? 0x2f9d5b : 0xf2ecd8,\n          transparent: true,\n          opacity: 0.17,\n          side: DoubleSide,\n          depthWrite: false,\n        })\n      );\n      // A RingGeometry lies in xy and sweeps from +x. The water is xz, and a\n      // bearing is clockwise from −z, so it wants laying down AND turning.\n      ring.rotation.x = -Math.PI / 2;\n      ring.rotation.z = Math.PI / 2 - s.from;\n      chart.add(ring);\n    }\n  };\n\n  const sectorAt = (bearing: number): Sector | null => {\n    if (!sectors.length) return null;\n    const b = ((bearing % TAU) + TAU) % TAU;\n    for (const s of sectors) {\n      const span = ((s.to - s.from + TAU) % TAU) || TAU;\n      const off = ((b - s.from + TAU) % TAU);\n      if (off < span) return s;\n    }\n    return null;\n  };\n\n  const api: Seamark = {\n    object: group,\n    obstacleRadius: kind === 'bonfire' ? 3.4 : 3.6,\n    kind,\n    height: H,\n    intensity: I,\n    character: base.char.label,\n    period: base.char.period,\n    charted: base.charted,\n    identifiable: base.identifiable,\n    station,\n    slots: [station],\n    fogSignal: base.fog,\n\n    get showing() {\n      return showing;\n    },\n    get phase() {\n      return phase;\n    },\n    get sounding() {\n      // Worked out on demand rather than only inside `update`. Set the\n      // visibility and ask, and a station that answered with whatever it\n      // happened to think last frame would be wrong on the frame that matters\n      // — the same defect the trim track had, three modules along.\n      return base.fog !== Infinity && visibility < 2 && clock % base.fog < 2.5;\n    },\n    get audibleRange() {\n      return base.audible;\n    },\n    get visibility() {\n      return visibility;\n    },\n    setVisibility(nauticalMiles: number) {\n      visibility = Math.max(0.01, Number.isFinite(nauticalMiles) ? nauticalMiles : 10);\n      rebuildChart();\n    },\n    get sectors() {\n      return sectors;\n    },\n\n    dips(heightOfEye: number) {\n      return geographicRange(H, heightOfEye);\n    },\n    luminousRange(intensity = I) {\n      return luminousRange(intensity, visibility);\n    },\n\n    sector(name, from, to, colour) {\n      sectors.push({\n        name,\n        from: ((from % TAU) + TAU) % TAU,\n        to: ((to % TAU) + TAU) % TAU,\n        colour,\n        transmission: SECTOR_TRANSMISSION[colour],\n        // White is the water you want. That is the whole convention and it is\n        // the reason the system works on a dark night with a frightened crew.\n        safe: colour === 'white',\n      });\n      rebuildChart();\n    },\n    sectorAt,\n    showSectors(on: boolean, scale = 1) {\n      chartScale = Math.max(1e-4, Number.isFinite(scale) ? scale : 1);\n      rebuildChart();\n      chart.visible = on && sectors.length > 0;\n    },\n\n    sightedFrom(x: number, z: number, heightOfEye = 1.5) {\n      const here = group.getWorldPosition(new Vector3());\n      const dx = x - here.x;\n      const dz = z - here.z;\n      const distance = Math.hypot(dx, dz);\n      // Bearing OUTWARD from the light: which way she is, seen from the tower.\n      // Clockwise from north, and north is −z.\n      const bearing = ((Math.atan2(dx, -dz) % TAU) + TAU) % TAU;\n\n      const sector = sectorAt(bearing);\n      const lampHere = I * (sector ? sector.transmission : 1);\n      const geographic = geographicRange(H, heightOfEye);\n      const lum = luminousRange(lampHere, visibility);\n      const range = Math.min(geographic, lum);\n\n      // The loom: the beam lights the haze ABOVE the horizon, so the glow is\n      // there for miles before the lamp is. It is the first thing anybody\n      // actually sees, and it is beyond the range any table gives.\n      //\n      // It only exists where the horizon is what is hiding the lamp. A light\n      // that has simply got too faint has no loom — there is nothing over the\n      // hill, because there is no hill.\n      const horizonLimited = geographic <= lum;\n      const loomOut = horizonLimited ? geographic * 1.25 : range;\n      let state: SightState;\n      if (distance > loomOut) state = 'dark';\n      else if (distance > range) state = 'loom';\n      else if (horizonLimited && distance > geographic * 0.94) state = 'raising';\n      else state = 'showing';\n\n      const inRange = distance <= range;\n      return {\n        inRange,\n        visible: inRange && showing,\n        state,\n        distance,\n        bearing,\n        range,\n        geographic,\n        luminous: lum,\n        limitedBy: geographic <= lum ? 'horizon' : 'lamp',\n        sector,\n        safe: sector ? sector.safe : null,\n        showing,\n      };\n    },\n\n    update(dt: number) {\n      if (!(dt > 0)) return;\n      clock += dt;\n      const lit = litAt(clock);\n      phase = base.char.period === Infinity ? 0 : (clock % base.char.period) / base.char.period;\n      if (lit !== showing) {\n        showing = lit;\n        lampMat.emissiveIntensity = lit ? 2.4 : 0.02;\n        haloMat.opacity = lit ? 0.4 : 0;\n        halo.visible = lit;\n      }\n    },\n  };\n\n  // Start consistent with the clock rather than blindly lit: a light created\n  // mid-character and reported as `showing` before anybody has stepped it is\n  // the same defect the trim track had, one object along.\n  showing = litAt(clock);\n  lampMat.emissiveIntensity = showing ? 2.4 : 0.02;\n  haloMat.opacity = showing ? 0.4 : 0;\n  halo.visible = showing;\n\n  if (kind === 'sectored') {\n    // A fairway between two dangers: white down the channel, red over the rocks\n    // to one side and green over the shoal to the other. The white sector is\n    // narrow on purpose — it is a line, not a region.\n    api.sector('rocks', (188 * Math.PI) / 180, (352 * Math.PI) / 180, 'red');\n    api.sector('fairway', (172 * Math.PI) / 180, (188 * Math.PI) / 180, 'white');\n    api.sector('shoal', (352 * Math.PI) / 180, (172 * Math.PI) / 180, 'green');\n  }\n\n  return api;\n}\n","import {\n  BoxGeometry,\n  CylinderGeometry,\n  Group,\n  Mesh,\n  MeshStandardMaterial,\n  Quaternion,\n  Vector3,\n} from 'three';\nimport { Rng } from '../core/random';\nimport { DEFAULT_PALETTE, type Palette } from '../core/palette';\nimport { createSurface } from '../materials/surface';\nimport { createSlot, type Prop, type PropSlot } from '../core/types';\nimport type { Loading } from './hold';\n\n/**\n * Small craft — the only vessel in this library whose stability walks around,\n * and the only one that can be lost and come back.\n *\n * Everything else in the boat arc is a machine that survives things. A liner\n * takes a gale because she is a hundred and eighty metres long; a steamer\n * takes it because she has a thousand tonnes of cargo holding her down. A\n * small boat has neither, and what happens to her in the next thirty seconds\n * is decided by half a metre of freeboard and by where four people are\n * sitting.\n *\n * ## She is not lost to stability. She is lost to freeboard.\n *\n * This is the finding, and it is not what anybody expects — including the\n * first draft of this module, which took the free-surface sum straight out of\n * `createHold` and got a negative metacentric height out of **two buckets of\n * water**. That formula is a full-beam slab, derived for a ballast tank six\n * metres wide with a metre of water standing in it. Water in the bottom of a\n * boat lies in the *narrow* part of her section, and the width that matters is\n * the width at that depth. Taken seriously, she keeps a positive GM all the\n * way to the gunwale.\n *\n * What actually happens is a **runaway**:\n *\n * ```text\n *   water aboard  →  less freeboard  →  more water aboard\n * ```\n *\n * Nothing else in this library does that. Every other model here settles: a\n * boiler finds a pressure, a sea finds a height, a hull finds a list. This one\n * has a tipping point, and on the wrong side of it there is nothing to find.\n *\n * ```ts\n * boat.meet(0.8);  boat.swampsIn();   // Infinity — she is dry all day\n * boat.meet(1.0);  boat.swampsIn();   // 79 s\n * boat.meet(1.5);  boat.swampsIn();   // 23 s\n * boat.bail(2);    boat.swampsIn();   // 23 s. A man with a bucket is not in it.\n * ```\n *\n * ## What happens after she fills\n *\n * The era axis is **where in that loop you intervene**, and every one of the\n * four intervenes somewhere different:\n *\n * | fit | what it does about the runaway |\n * | --- | --- |\n * | `open` | nothing. You bail, and you lose, and then she goes under. |\n * | `buoyant` | cannot stop it — puts a FLOOR under it. She floods to awash and stays there. |\n * | `selfDraining` | breaks it. Water out faster than water in, so the freeboard never falls. |\n * | `selfRighting` | lets it finish and comes back anyway, with nobody doing anything. |\n *\n * `buoyant` is the interesting one, and the numbers say something sharper than\n * the usual claim for it: **it buys no seconds at all.** She fills marginally\n * SOONER than an open boat, because the tanks take up room the water would\n * have had. What changes is what is still floating when she is full — and\n * turning drowning into swimming is the biggest single step on this list even\n * though it does not buy one second of it.\n *\n * And `selfRighting` is the inversion at the end of the axis, the same shape as\n * a gyro stabiliser that needs no way and a derrick that cannot let go: it\n * makes the crew's position **stop mattering**. Every other fit here is a boat\n * you have to be good in.\n *\n * ## A breaker does not care what her GM is\n *\n * A sea steeper than one in seven is breaking, and a breaking sea taller than\n * about six tenths of her beam rolls her over regardless of stability, because\n * it is not a heeling moment — it is a wall of water with momentum in it. It\n * is the only failure in this library that no number on the vessel answers.\n *\n * ```ts\n * boat.meet(1.4, 9);   // 1.4 m at 9 m long: steepness 1 in 6.4, and breaking\n * boat.breaking;       // true\n * boat.capsized;       // true, and her GM was 3.6\n * ```\n */\nexport type CraftFit = 'open' | 'buoyant' | 'selfDraining' | 'selfRighting';\n\nexport const CRAFT_FITS: CraftFit[] = ['open', 'buoyant', 'selfDraining', 'selfRighting'];\n\n/** dry / taking it / full / foundered, on the same four-state shape as the rest. */\nexport type CraftState = 'dry' | 'wet' | 'awash' | 'gone';\n\n/** Somebody aboard, and on a boat this size they are a third of her. */\nexport interface Hand {\n  name: string;\n  /** Kilograms. */\n  kg: number;\n  /** Where along her, −1 hard aft to +1 hard forward. */\n  along: number;\n  /** Where across her, −1 on the port gunwale to +1 on the starboard one. */\n  side: number;\n  /** On their feet — which puts their weight most of a metre higher up. */\n  standing: boolean;\n  /** Out over the side, 0–1. It multiplies whichever arm they already have,\n   *  and which side that is decides whether it saves her. */\n  out: number;\n}\n\nexport interface SmallCraft extends Prop {\n  fit: CraftFit;\n  readonly length: number;\n  readonly beam: number;\n  /** Keel to gunwale, m. Freeboard is this minus her draught. */\n  readonly depth: number;\n\n  // ── the ballast that walks ───────────────────────────────────────────\n  /**\n   * Put somebody aboard. `along` is −1 aft to +1 forward, `side` is −1 to +1\n   * across her.\n   *\n   * Their weight is a third of her displacement, so this moves her draught,\n   * her trim, her list and her metacentric height all at once — and they can\n   * do it again next second, which is what makes a small boat a boat you have\n   * to be good in.\n   */\n  seat(name: string, kg: number, along?: number, side?: number): void;\n  /** Move somebody who is already aboard. */\n  move(name: string, along: number, side: number): void;\n  /** On their feet. Their centre of mass goes up most of a metre. */\n  stand(name: string, up: boolean): void;\n  /**\n   * Out over the gunwale, 0–1.\n   *\n   * It multiplies the arm they already have, and it does not care which way\n   * that arm points: hiking out on the high side is the only time the crew is\n   * stability rather than a problem, and hiking out on the low side puts her\n   * over twice as fast. The sign is the skill.\n   */\n  hike(name: string, out: number): void;\n  leave(name: string): void;\n  readonly hands: Hand[];\n  readonly crew: number;\n  readonly crewMass: number;\n\n  // ── the water ────────────────────────────────────────────────────────\n  /**\n   * The sea she is in: height in metres, and the wavelength if you have it.\n   *\n   * `SeaState`'s trains go straight in — `boat.meet(sea.windSea.height,\n   * sea.windSea.length)` — with nothing imported either way. Given a length\n   * she works out for herself whether it is **breaking**, which is the one\n   * thing that can roll her whatever her stability is.\n   */\n  meet(height: number, length?: number): void;\n  readonly sea: number;\n  /** Steeper than one in seven, and it is a wall rather than a slope. */\n  readonly breaking: boolean;\n  /** Kilograms of water in her. */\n  readonly water: number;\n  /** Kilograms she would hold to the gunwale. */\n  readonly capacity: number;\n  /** Coming aboard right now, kg/s. It GROWS as her freeboard falls. */\n  readonly boarding: number;\n  /** Bail at this many kg/s — a bucket is about 2, a hand pump about 1.5. */\n  bail(kgPerSecond: number): void;\n  readonly bailing: number;\n  /** Going out again by itself, kg/s. Zero unless she is self-draining. */\n  readonly draining: number;\n  /** More coming in than everything she has can put out. The runaway has\n   *  started, and on the wrong side of this it does not stop. */\n  readonly swamping: boolean;\n  /**\n   * Seconds until she is FULL, in the sea she is in now — or `Infinity` if she\n   * can live in it.\n   *\n   * Full is not the same as lost, and the difference is the whole era axis:\n   * read `state` when this expires. A buoyant boat fills marginally SOONER\n   * than an open one, because her tanks take up room the water would have\n   * had — buoyancy buys no seconds whatever. What it changes is what is\n   * floating there at the end of them.\n   *\n   * The same idiom as `SeaState.fallsTo` and `SteamPlant.reach`: run the model\n   * forward coarsely and say when, rather than making the caller integrate it\n   * themselves to find out.\n   */\n  swampsIn(): number;\n  /** Empty her. */\n  dry(): void;\n\n  // ── what she is doing about it ───────────────────────────────────────\n  readonly displacement: number;\n  readonly draught: number;\n  /**\n   * Metres of side above the sea AT HER LOWEST RAIL — which is not the same\n   * as amidships on the centreline once she is trimmed or listed. Four people\n   * sitting in the stern cost her half of it, and that is how a boat is\n   * swamped from astern.\n   */\n  readonly freeboard: number;\n  readonly gm: number;\n  readonly solidGm: number;\n  readonly freeSurface: number;\n  readonly rollPeriod: number;\n  readonly state: CraftState;\n  onState?: (state: CraftState) => void;\n  readonly capsized: boolean;\n  capsize(): void;\n  /**\n   * Get her back up.\n   *\n   * On an `open` boat that leaves you with a boat full of water. On a\n   * `buoyant` one, a boat floating awash. On a `selfDraining` one she empties\n   * herself afterwards. And on a `selfRighting` one you never call this at\n   * all, because she has already done it.\n   */\n  right(): void;\n\n  /** The AK handshake, unchanged: trim, list, sink, stiffness. Hand it to\n   *  anything that takes a `ShipInput`. */\n  readonly loading: Loading;\n\n  // ── the frames handshake, so people can stand in her ─────────────────\n  deckAt(x: number, z: number): number | null;\n  normalAt(x: number, z: number): Vector3;\n  ride(position: Vector3): Vector3;\n\n  /** Bind the water: `ocean.heightAt`. */\n  float(heightAt: (x: number, z: number) => number): void;\n  helm: PropSlot;\n  slots: PropSlot[];\n  update(dt: number): void;\n}\n\nexport interface SmallCraftOptions {\n  fit?: CraftFit;\n  /** Overall length, m. */\n  length?: number;\n  beam?: number;\n  /** Keel to gunwale, m. */\n  depth?: number;\n  /** Hull mass with nothing in her, kg. */\n  light?: number;\n  seed?: number;\n  palette?: Palette;\n}\n\nconst G = 9.81;\n/** Kilograms per cubic metre, so every mass in this file is a kilogram. */\nconst RHO = 1000;\n/** Steeper than this and a wave is breaking rather than passing. */\nconst BREAKS_AT = 1 / 7;\nconst clamp01 = (t: number): number => (t < 0 ? 0 : t > 1 ? 1 : t);\nconst clamp = (v: number, lo: number, hi: number): number => (v < lo ? lo : v > hi ? hi : v);\n\n/**\n * The four fits, on ONE hull.\n *\n * Sized differently they would not be comparable and the axis would be a\n * catalogue instead of an argument — the same reason `?view=trim` is four\n * identical steamers rather than four different ships. The only thing that\n * changes down this table is what happens to the water.\n */\ninterface FitSpec {\n  /**\n   * Kilograms of buoyancy that do not depend on her being dry: sealed tanks,\n   * foam, airbags. This is the difference between a boat that goes under and\n   * a boat that floats awash with everybody hanging onto it.\n   */\n  reserve: number;\n  /** Seconds to shed the water she has. `Infinity` where there is no way out. */\n  freeing: number;\n  /** Metres of her section taken up by a tank each side, which narrows the\n   *  free surface — and the free surface goes as the width CUBED. */\n  tank: number;\n  /** Ballast, kg, and how far above her keel it sits. Low and heavy is what\n   *  brings her back from beyond ninety degrees. */\n  ballast: number;\n  ballastAt: number;\n  /** Seconds to come back up on her own. `Infinity` if she stays where she\n   *  is until somebody does something. */\n  rights: number;\n}\n\nconst FITS: Record<CraftFit, FitSpec> = {\n  // An open boat. There is nothing here at all: no tanks, no ports, no\n  // ballast, and nothing keeping her up once she is full. This is most of the\n  // small craft that have ever existed and most of the people they drowned.\n  open: { reserve: 0, freeing: Infinity, tank: 0, ballast: 0, ballastAt: 0, rights: Infinity },\n  // Tanks under the side benches. They cannot stop her filling — the ports\n  // are the only thing that does — but they hold her up when she has, and\n  // they narrow the water that is loose in her.\n  buoyant: {\n    reserve: 900, freeing: Infinity, tank: 0.3, ballast: 0, ballastAt: 0, rights: Infinity,\n  },\n  // A sole ABOVE the waterline and holes in the transom. Water that comes\n  // aboard goes out again by itself, faster than it comes in, so her\n  // freeboard never falls and the loop never starts. It is the only fit here\n  // that fixes the problem rather than surviving it.\n  selfDraining: {\n    reserve: 900, freeing: 6, tank: 0.3, ballast: 0, ballastAt: 0, rights: Infinity,\n  },\n  // Ballast on the keel and buoyancy high up. She will go over — and then she\n  // will come back, with nobody aboard doing anything, which is the end of\n  // the axis and the point at which the crew stops being her stability.\n  selfRighting: {\n    reserve: 1100, freeing: 6, tank: 0.3, ballast: 260, ballastAt: 0.06, rights: 4,\n  },\n};\n\nexport function createSmallCraft(options: SmallCraftOptions = {}): SmallCraft {\n  const fit = options.fit ?? 'open';\n  const spec = FITS[fit];\n  const L = options.length ?? 5.5;\n  const B = options.beam ?? 1.9;\n  const D = options.depth ?? 0.62;\n  const light = options.light ?? 320;\n  const seed = options.seed ?? 1;\n  const rng = new Rng(seed);\n  const palette = options.palette ?? DEFAULT_PALETTE;\n\n  /** Block and waterplane coefficients for a small boat's sections. */\n  const CB = 0.42;\n  const CW = 0.72;\n  const lightAt = 0.25;\n\n  const group = new Group();\n  group.name = `craft:${fit}`;\n\n  const plank = createSurface('plank', { color: palette.wood, seed });\n  const paint = createSurface('paintedMetal', { color: 0xd8d2c4, seed: seed + 1 });\n  // Water standing IN her has to read against the sea outside her, and a\n  // realistic dark green-grey does not: at any range that fits the boat in\n  // frame the one thing the whole module is about is a slightly different\n  // shade of the same blue.\n  const bilge = new MeshStandardMaterial({\n    color: 0x1d6f86,\n    emissive: 0x07242c,\n    transparent: true,\n    opacity: 0.9,\n    roughness: 0.18,\n    flatShading: true,\n  });\n\n  // ── geometry ─────────────────────────────────────────────────────────\n\n  const hull = new Group();\n  group.add(hull);\n\n  const bottom = new Mesh(new BoxGeometry(B * 0.62, 0.07, L * 0.94), plank);\n  bottom.position.y = 0.035;\n  hull.add(bottom);\n  for (const side of [-1, 1]) {\n    // Flared, so her section really is narrow at the bottom and wide at the\n    // gunwale — which is the whole reason the free surface down there is not\n    // the free surface of a tank.\n    const strake = new Mesh(new BoxGeometry(0.06, D, L * 0.96), plank);\n    strake.position.set(side * B * 0.42, D / 2, 0);\n    strake.rotation.z = side * 0.2;\n    hull.add(strake);\n    const gunwale = new Mesh(new BoxGeometry(0.1, 0.06, L * 0.96), plank);\n    gunwale.position.set(side * B * 0.5, D, 0);\n    hull.add(gunwale);\n  }\n  for (const z of [-L * 0.46, L * 0.46]) {\n    const end = new Mesh(new BoxGeometry(B * 0.66, D, 0.07), plank);\n    end.position.set(0, D / 2, z);\n    hull.add(end);\n  }\n  /** Thwarts — and they are where the crew sits, which is why they are here. */\n  const thwarts: number[] = [-L * 0.24, 0, L * 0.24];\n  for (const z of thwarts) {\n    const t = new Mesh(new BoxGeometry(B * 0.9, 0.05, 0.26), plank);\n    t.position.set(0, D * 0.56, z);\n    hull.add(t);\n  }\n\n  if (spec.tank > 0) {\n    // Side benches with the tanks in them. On a self-draining boat they are\n    // also the sole, and the difference is where the top of them is relative\n    // to the sea.\n    for (const side of [-1, 1]) {\n      const bench = new Mesh(new BoxGeometry(spec.tank, D * 0.5, L * 0.8), paint);\n      bench.position.set(side * (B * 0.5 - spec.tank / 2), D * 0.42, 0);\n      hull.add(bench);\n    }\n  }\n  if (spec.freeing < Infinity) {\n    // FREEING PORTS. Four holes in the transom, and they are the whole module.\n    for (let i = 0; i < 4; i++) {\n      const port = new Mesh(new CylinderGeometry(0.055, 0.055, 0.1, 8), paint);\n      port.rotation.x = Math.PI / 2;\n      port.position.set(-B * 0.24 + i * (B * 0.16), D * 0.7, -L * 0.46);\n      hull.add(port);\n    }\n  }\n  if (spec.ballast > 0) {\n    const keel = new Mesh(new BoxGeometry(0.16, 0.2, L * 0.6), paint);\n    keel.position.set(0, -0.09, 0);\n    hull.add(keel);\n  }\n  for (let i = 0; i < 6; i++) {\n    const frame = new Mesh(new BoxGeometry(B * 0.66, 0.05, 0.05), plank);\n    frame.position.set(0, 0.07 + rng.next() * 0.02, -L * 0.36 + i * (L * 0.144));\n    hull.add(frame);\n  }\n\n  /**\n   * The water in her, and it has to be a SLAB THAT MOVES rather than a level.\n   *\n   * A boat filling up is the one thing in this whole arc that a still frame\n   * can show on its own, and the reason it can is that you see the water\n   * standing inside her against the sea outside.\n   */\n  const pond = new Mesh(new BoxGeometry(1, 1, 1), bilge);\n  pond.name = 'craft:water';\n  pond.visible = false;\n  hull.add(pond);\n\n  const helm = createSlot('craft', 'helm', group, 0, D * 0.56, -L * 0.3, 0);\n\n  // ── the model ────────────────────────────────────────────────────────\n\n  const hands = new Map<string, Hand>();\n  let water = 0;\n  let bailing = 0;\n  let seaH = 0;\n  let seaL = 0;\n  let capsized = false;\n  let righting = 0;\n  let state: CraftState = 'dry';\n  let sampler: ((x: number, z: number) => number) | null = null;\n  const loading: Loading = { trim: 0, list: 0, sink: 0, stiffness: 1 };\n  /** Her own attitude on the waves, before the crew and the water get a say. */\n  let wavePitch = 0;\n  let waveRoll = 0;\n  let lastY = 0;\n  let riseRate = 0;\n\n  /** Her whole internal volume, to the gunwale, in kg of water. */\n  const capacity = ((L * B * D) / 2) * RHO * (1 - (spec.tank * 2) / B);\n\n  /**\n   * How deep the water in her is standing.\n   *\n   * Her section is a wedge, not a box: the volume up to depth `d` goes as\n   * `d²`, so a little water is deep and narrow and a lot of it is shallow and\n   * wide. Taken as a box, `d` comes out four times too small and the free\n   * surface with it.\n   */\n  const pondDepth = (): number =>\n    water <= 0 ? 0 : Math.min(D, Math.sqrt((2 * D * water) / (RHO * L * B)));\n\n  /** The width the loose water actually reaches, at the depth it is at. */\n  const pondWidth = (): number =>\n    Math.max(0, B * Math.min(1, pondDepth() / D) - spec.tank * 2);\n\n  const massAt = (): { mass: number; kg: number } => {\n    let moment = light * lightAt + spec.ballast * spec.ballastAt;\n    let mass = light + spec.ballast;\n    for (const h of hands.values()) {\n      // Sitting on a thwart their centre of mass is a bit over half a metre\n      // up; standing it is most of a metre and a half. On a boat this size\n      // that is a real change in her centre of gravity.\n      const y = h.standing ? D * 0.56 + 0.62 : D * 0.56 + 0.28;\n      moment += h.kg * y;\n      mass += h.kg;\n    }\n    const d = pondDepth();\n    if (water > 0) {\n      moment += water * d * 0.45;\n      mass += water;\n    }\n    return { mass, kg: moment / mass };\n  };\n\n  /** Where the crew and the water put her, athwartships and fore-and-aft. */\n  const moments = (): { mx: number; mz: number } => {\n    let mx = 0;\n    let mz = 0;\n    for (const h of hands.values()) {\n      // Hiking puts them beyond the gunwale — which extends whichever arm they\n      // already have. On the high side it is the only stability she has; on\n      // the low side it is how a dinghy is capsized to windward.\n      const across = (h.side + Math.sign(h.side || 1) * h.out * 0.7) * (B / 2);\n      mx += h.kg * across;\n      mz += h.kg * h.along * (L / 2);\n    }\n    return { mx, mz };\n  };\n\n  const solve = (): void => {\n    const { mass, kg } = massAt();\n    const disp = mass;\n    const vol = disp / RHO;\n    const draught = vol / (L * B * CB);\n    const bm = (CW * L * B ** 3) / 12 / Math.max(1e-6, vol);\n    const solidGm = draught * 0.53 + bm - kg;\n    const w = pondWidth();\n    const fs = water > 1 ? (RHO * ((w ** 3 * L) / 12)) / disp : 0;\n    const gm = solidGm - fs;\n\n    const { mx, mz } = moments();\n    loading.list = gm > 0.02 ? Math.asin(clamp(mx / (disp * gm), -1, 1)) : Math.sign(mx) * 1.4;\n    // Longitudinal stability is enormous compared with transverse — she trims\n    // long before she lists — but on a boat this short the crew's fore-and-aft\n    // arm is metres, and four people in the stern is how she is swamped from\n    // astern.\n    const gml = L * 1.1;\n    loading.trim = Math.atan(mz / Math.max(1e-6, disp * gml));\n    loading.sink = draught - (light + spec.ballast) / RHO / (L * B * CB);\n    loading.stiffness = gm > 0.02 ? clamp(gm / 3.6, 0.3, 2.4) : 0.3;\n\n    solved = { disp, draught, kg, bm, solidGm, fs, gm };\n  };\n  let solved = { disp: light, draught: 0, kg: 0, bm: 0, solidGm: 0, fs: 0, gm: 0 };\n\n  /**\n   * Metres of side above the sea AT HER LOWEST RAIL.\n   *\n   * Not amidships on the centreline. Trim her by the stern and the low corner\n   * is the quarter; list her and it is a gunwale. That distinction is what\n   * makes where the crew sits feed straight into how fast she fills, and\n   * without it a boat with four people in the stern is as safe as an empty\n   * one.\n   */\n  const freeboardOf = (): number =>\n    D -\n    solved.draught -\n    Math.abs(Math.sin(loading.trim)) * (L / 2) -\n    Math.abs(Math.sin(loading.list)) * (B / 2);\n\n  /**\n   * What the sea would be putting aboard if she had this much water in her.\n   *\n   * The same sum as `boarding` with the freeboard evaluated at a hypothetical\n   * load, which is what lets the runaway be settled with arithmetic instead of\n   * integrated for an hour every frame.\n   */\n  const boardingAt = (w: number): number => {\n    let held = light + spec.ballast;\n    for (const h of hands.values()) held += h.kg;\n    const draught = (held + w) / RHO / (L * B * CB);\n    const fb =\n      D -\n      draught -\n      Math.abs(Math.sin(loading.trim)) * (L / 2) -\n      Math.abs(Math.sin(loading.list)) * (B / 2);\n    const reach = seaH * (breakingOf() ? 0.85 : 0.5);\n    return L * Math.max(0, reach - fb) * 40;\n  };\n\n  /**\n   * Water over the rail, kg/s.\n   *\n   * The whole module is in the sign of this derivative: it is a function of\n   * the freeboard she has LEFT, and taking water reduces that, so taking water\n   * makes her take water faster. Everything else in this library settles.\n   */\n  const boardingOf = (): number => {\n    if (capsized) return 0;\n    const fb = freeboardOf();\n    const reach = seaH * (breakingOf() ? 0.85 : 0.5);\n    return L * Math.max(0, reach - fb) * 40;\n  };\n\n  const breakingOf = (): boolean => seaL > 0.1 && seaH / seaL > BREAKS_AT;\n\n  const drainingOf = (): number =>\n    // …and not while she is upside down. A hole in the transom is a hole in\n    // the transom: it lets water out when the transom is above the sea and it\n    // is a hole in the bottom of a bowl when it is not.\n    spec.freeing === Infinity || water <= 0 || capsized ? 0 : water / spec.freeing;\n\n  /**\n   * She is full, and there is not enough buoyancy in her to hold up what is\n   * left.\n   *\n   * And what is left is the hull, her ballast and her crew — NOT the water.\n   * Water inside a swamped boat weighs nothing at all: it is sea water sitting\n   * in a hole in the sea, and it is already being held up by the sea it came\n   * from. Counted against the tanks it sinks every boat here however much\n   * buoyancy she has, which is how the first draft foundered a lifeboat.\n   */\n  const foundered = (): boolean => {\n    if (water < capacity - 1) return false;\n    let held = light + spec.ballast;\n    for (const h of hands.values()) held += h.kg;\n    return spec.reserve < held;\n  };\n\n  const classify = (): CraftState => {\n    if (foundered()) return 'gone';\n    // A boat on her side is not 'dry' however little water is in her, and a\n    // self-draining one WILL empty herself while inverted if nobody says so.\n    if (capsized) return 'awash';\n    if (water >= capacity * 0.82 || solved.gm <= 0.02) return 'awash';\n    if (water > capacity * 0.03) return 'wet';\n    return 'dry';\n  };\n\n  const place = (): void => {\n    const d = pondDepth();\n    pond.visible = d > 0.005 && !capsized;\n    if (pond.visible) {\n      const w = Math.max(0.05, B * Math.min(1, d / D) - spec.tank * 2);\n      pond.scale.set(w, Math.max(0.01, d), L * 0.9);\n      // It lies where the low corner is, not in the middle of her — the same\n      // reason the freeboard is measured at a corner.\n      pond.position.set(\n        clamp(-Math.sin(loading.list) * 6, -1, 1) * ((B - w) / 2),\n        d / 2,\n        clamp(-Math.sin(loading.trim) * 6, -1, 1) * (L * 0.05)\n      );\n      // THE SURFACE OF WATER IS LEVEL. It is a child of the hull, so left\n      // alone it heels with her — a slab of sea tilted inside a tilted boat,\n      // which is the one thing water never does.\n      pond.rotation.set(-group.rotation.x, 0, -group.rotation.z);\n    }\n  };\n\n  solve();\n  place();\n\n  const requireHand = (name: string): Hand | undefined => hands.get(name);\n\n  const api: SmallCraft = {\n    object: group,\n    obstacleRadius: B * 0.6,\n    fit,\n    length: L,\n    beam: B,\n    depth: D,\n    helm,\n    slots: [helm],\n    capacity,\n\n    seat(name: string, kg: number, along = 0, side = 0) {\n      hands.set(name, {\n        name,\n        kg: Math.max(0, Number.isFinite(kg) ? kg : 0),\n        along: clamp(Number.isFinite(along) ? along : 0, -1, 1),\n        side: clamp(Number.isFinite(side) ? side : 0, -1, 1),\n        standing: false,\n        out: 0,\n      });\n      solve();\n      place();\n    },\n    move(name: string, along: number, side: number) {\n      const h = requireHand(name);\n      if (!h) return;\n      h.along = clamp(Number.isFinite(along) ? along : 0, -1, 1);\n      h.side = clamp(Number.isFinite(side) ? side : 0, -1, 1);\n      solve();\n      place();\n    },\n    stand(name: string, up: boolean) {\n      const h = requireHand(name);\n      if (!h) return;\n      h.standing = up;\n      solve();\n      place();\n    },\n    hike(name: string, out: number) {\n      const h = requireHand(name);\n      if (!h) return;\n      h.out = clamp01(Number.isFinite(out) ? out : 0);\n      solve();\n      place();\n    },\n    leave(name: string) {\n      if (hands.delete(name)) {\n        solve();\n        place();\n      }\n    },\n    get hands() {\n      return [...hands.values()];\n    },\n    get crew() {\n      return hands.size;\n    },\n    get crewMass() {\n      let m = 0;\n      for (const h of hands.values()) m += h.kg;\n      return m;\n    },\n\n    meet(height: number, length = 0) {\n      seaH = Math.max(0, Number.isFinite(height) ? height : 0);\n      seaL = Math.max(0, Number.isFinite(length) ? length : 0);\n      // A breaking sea over about six tenths of her beam rolls her, and no\n      // number on the vessel has anything to say about it. It is momentum,\n      // not a moment.\n      if (breakingOf() && seaH > B * 0.6) api.capsize();\n    },\n    get sea() {\n      return seaH;\n    },\n    get breaking() {\n      return breakingOf();\n    },\n    get water() {\n      return water;\n    },\n    get boarding() {\n      return boardingOf();\n    },\n    bail(kgPerSecond: number) {\n      bailing = Math.max(0, Number.isFinite(kgPerSecond) ? kgPerSecond : 0);\n    },\n    get bailing() {\n      return bailing;\n    },\n    get draining() {\n      return drainingOf();\n    },\n    get swamping() {\n      const out = drainingOf() + bailing;\n      if (boardingOf() <= out) return false;\n      // A CONSTANT outflow cannot beat a growing inflow. Bailing takes the same\n      // two kilos a second however low she is, and the sea takes more of them\n      // the lower she gets, so above the point where the sea wins there is no\n      // level she can settle at — and this is why bailing does not save her.\n      if (spec.freeing === Infinity) return true;\n      // Freeing ports are different in kind, not in degree: their outflow goes\n      // as the water she has, so it grows too, and faster. She settles if they\n      // can beat the sea at the very worst level there is.\n      return capacity / spec.freeing < boardingAt(capacity);\n    },\n    swampsIn() {\n      // Run her forward coarsely. Integrating a runaway is the only honest way\n      // to answer this: there is no closed form, and the whole point is that\n      // the rate is a function of the state.\n      if (capsized) return 0;\n      let w = water;\n      const held = water;\n      let t = 0;\n      const dt = 0.25;\n      for (; t < 3600; t += dt) {\n        water = w;\n        solve();\n        const inflow = boardingOf();\n        const out = drainingOf() + bailing;\n        const next = Math.max(0, w + (inflow - out) * dt);\n        if (next >= capacity - 1) {\n          water = held;\n          solve();\n          place();\n          return t;\n        }\n        // She has found a level she can live with, and will sit there all day.\n        if (Math.abs(next - w) < 1e-4 && inflow <= out) break;\n        w = next;\n      }\n      water = held;\n      solve();\n      place();\n      return Infinity;\n    },\n    dry() {\n      water = 0;\n      solve();\n      place();\n    },\n\n    get displacement() {\n      return solved.disp;\n    },\n    get draught() {\n      return solved.draught;\n    },\n    get freeboard() {\n      return freeboardOf();\n    },\n    get gm() {\n      return solved.gm;\n    },\n    get solidGm() {\n      return solved.solidGm;\n    },\n    get freeSurface() {\n      return solved.fs;\n    },\n    get rollPeriod() {\n      // NOT clamped. A boat with no stability left does not have a long roll\n      // period, she has no roll period, and saying '118 seconds' where the\n      // truth is 'never' is the kind of number somebody builds on.\n      return solved.gm > 0.02 ? (2 * Math.PI * 0.35 * B) / Math.sqrt(G * solved.gm) : Infinity;\n    },\n    get state() {\n      // Classified on demand and not only in `update`, so a boat handed four\n      // people and half a tonne of water reports what she is before anybody\n      // has stepped a frame.\n      return classify();\n    },\n    get capsized() {\n      return capsized;\n    },\n    capsize() {\n      if (capsized) return;\n      capsized = true;\n      righting = spec.rights;\n      // Over she goes, and she fills as she does it — except where there is\n      // something holding her up.\n      water = Math.min(capacity, water + (capacity - water) * (spec.reserve > 0 ? 0.55 : 1));\n      solve();\n      place();\n    },\n    right() {\n      if (!capsized) return;\n      capsized = false;\n      righting = 0;\n      // …and she comes up with everything that came in still in her, unless\n      // there is a way for it to get out. THAT is the axis: coming back up is\n      // not the same as being all right.\n      if (spec.freeing === Infinity) water = Math.min(capacity, Math.max(water, capacity * 0.9));\n      solve();\n      place();\n    },\n    get loading() {\n      return loading;\n    },\n\n    deckAt(x: number, z: number) {\n      // World point → her frame. The sole she can be stood on is the thwarts,\n      // and outside her sheer there is no deck at all — which is how you find\n      // out somebody has gone over the side, with no separate test.\n      const local = group.worldToLocal(new Vector3(x, 0, z));\n      if (Math.abs(local.x) > B * 0.5 || Math.abs(local.z) > L * 0.5) return null;\n      const p = new Vector3(local.x, D * 0.56, local.z);\n      return group.localToWorld(p).y;\n    },\n    normalAt(x: number, z: number) {\n      void x;\n      void z;\n      return new Vector3(0, 1, 0).applyQuaternion(group.getWorldQuaternion(new Quaternion())).normalize();\n    },\n    ride(position: Vector3) {\n      position.y += riseRate;\n      return position;\n    },\n\n    float(heightAt: (x: number, z: number) => number) {\n      sampler = heightAt;\n    },\n\n    update(dt: number) {\n      if (!(dt > 0)) return;\n\n      // She comes back up on her own, or she does not, and that is the fit.\n      if (capsized && righting !== Infinity) {\n        righting -= dt;\n        if (righting <= 0) api.right();\n      }\n\n      const inflow = boardingOf();\n      const out = drainingOf() + bailing;\n      water = clamp(water + (inflow - out) * dt, 0, capacity);\n      solve();\n\n      // …and once she is full, whether she is still there depends entirely on\n      // whether anything aboard floats without her.\n      if (foundered()) water = capacity;\n\n      if (sampler) {\n        const { x, z } = group.position;\n        const sin = Math.sin(group.rotation.y);\n        const cos = Math.cos(group.rotation.y);\n        const bow = sampler(x + sin * L * 0.4, z + cos * L * 0.4);\n        const stern = sampler(x - sin * L * 0.4, z - cos * L * 0.4);\n        const port = sampler(x - cos * B * 0.5, z + sin * B * 0.5);\n        const stbd = sampler(x + cos * B * 0.5, z - sin * B * 0.5);\n        const want = (bow + stern + port + stbd) / 4 - solved.draught;\n        riseRate = want - lastY;\n        lastY = want;\n        group.position.y = want;\n        // A small boat takes the slope of the wave she is on — she does not\n        // average it out, because she is shorter than it is.\n        wavePitch = Math.atan2(stern - bow, L * 0.8);\n        waveRoll = Math.atan2(port - stbd, B);\n      }\n\n      group.rotation.x = wavePitch + loading.trim;\n      // Trim and list take OPPOSITE signs at the hull, and not by accident.\n      group.rotation.z = capsized\n        ? Math.sign(loading.list || 1) * 1.75\n        : waveRoll - loading.list;\n      place();\n\n      const next = classify();\n      if (next !== state) {\n        state = next;\n        api.onState?.(state);\n      }\n    },\n  };\n  return api;\n}\n\n/**\n * The sea a boat of this freeboard can live in, metres.\n *\n * Half her freeboard is the whole criterion, and it is worth having on its own\n * because it is the number that decides whether a passage is a passage or a\n * drowning — and because it does not mention her length, her engine, her crew\n * or her stability, none of which come into it.\n */\nexport function livesIn(freeboard: number): number {\n  return Math.max(0, freeboard) * 2;\n}\n\n/** Is a sea of this height and length breaking? Steeper than one in seven. */\nexport function isBreaking(height: number, length: number): boolean {\n  return length > 0.1 && height / length > BREAKS_AT;\n}\n","import {\n  BoxGeometry,\n  CylinderGeometry,\n  Group,\n  Mesh,\n  MeshStandardMaterial,\n  Object3D,\n  Quaternion,\n  Vector3,\n} from 'three';\nimport { Rng } from '../core/random';\nimport { DEFAULT_PALETTE, type Palette } from '../core/palette';\nimport { createSurface } from '../materials/surface';\nimport { createSlot, addApproach, type Prop, type PropSlot } from '../core/types';\n\n/**\n * Working gear — and the first load in this library that **pulls back.**\n *\n * Every other force in the boat arc acts through her centreline. A sail's\n * drive, an oar's thrust, a screw's push: all of them push her along the way\n * she is pointing, and none of them can put her on her beam ends. A working\n * load does not. It acts at a point on her deck, at the end of a wire, and the\n * further outboard and the higher that point is, the more of your own engine\n * goes into laying her over instead of moving her.\n *\n * `object` stands on her WORKING DECK: y = 0 is the planking, not the\n * waterline. Hang it off the deck it belongs to —\n * `gear.object.position.y = deck.y` — the same way a funnel is hung. Left at\n * the hull's own origin every gallows, hook and boom is a freeboard too low,\n * which is to say inside her, and the load and the wire are under the sea.\n *\n * ```ts\n * const gear = createGear({ kind: 'tow', beam: ship.beam, length: ship.length });\n * const deck = ship.decks.find((d) => d.name === 'waist')!;\n * gear.object.position.y = deck.y;\n * ship.object.add(gear.object);\n *\n * gear.shoot();\n * game.onUpdate((t) => {\n *   gear.setWay(plant.way);\n *   gear.setAngle(towAngle);         // …and this is the one that kills you\n *   gear.update(t.delta);\n *   hold.heel('gear', gear.moment);  // straight into the same arithmetic\n *   ship.update(t.delta, { speed: plant.way - gear.drag, loading: hold.loading });\n * });\n * ```\n *\n * ## The wire comes abeam and the boat is gone\n *\n * A tug tows from a hook near her own centre of turning, as low as she can get\n * it, and she is still lost if the line comes across her. It is called\n * **girting**: the tow's weight comes on the quarter, the pull is behind her\n * pivot so her rudder cannot bring her back, and she goes over. Every tug ever\n * built has a way of letting the wire go *instantly*, and that is the only\n * reason there is a `slip()` on this object.\n *\n * ```ts\n * gear.girting;   // true, and you have seconds\n * gear.slip();    // a tow hook lets go NOW. A derrick cannot let go at all.\n * ```\n *\n * ## How fast you can get rid of it is not a modern invention\n *\n * | kind | the load | how it kills you | letting go |\n * | --- | --- | --- | --- |\n * | `pots` | a string of pots on the rail | weight outboard, hauled by hand | drop it |\n * | `trawl` | a net towed astern | it comes fast on the bottom | knock out the block |\n * | `tow` | another vessel | it comes abeam — girting | INSTANT, by design |\n * | `derrick` | a weight in the air | it acts at the boom head the instant it lifts | you cannot |\n *\n * The axis is **how fast you can be rid of it**, and it is not monotone with\n * era: the most capable gear here is the one with no way out. A derrick's load\n * has to be put down somewhere, and putting it down takes as long as it takes.\n */\nexport type GearKind = 'pots' | 'trawl' | 'tow' | 'derrick';\n\nexport const GEAR_KINDS: GearKind[] = ['pots', 'trawl', 'tow', 'derrick'];\n\n/** rest / transitioning-toward / at-target / drifting-back, on the gear. */\nexport type GearState = 'stowed' | 'shooting' | 'working' | 'fast';\n\nexport interface Gear extends Prop {\n  kind: GearKind;\n  /** Put it over the side. */\n  shoot(): void;\n  /** Get it back aboard. */\n  haul(): void;\n  /**\n   * LET GO.\n   *\n   * The one verb on this object that exists because of a way of dying. A tow\n   * hook does it in an instant; a trawl takes a few seconds to knock the block\n   * out; a derrick cannot do it at all and `slip` is a no-op — the load has to\n   * be **lowered**, and that no-op is the era axis.\n   */\n  slip(): void;\n  /** 0 all inboard, 1 all the way out. It travels. */\n  readonly out: number;\n  readonly state: GearState;\n  onState?: (state: GearState) => void;\n\n  /** Her way through the water, m/s. The load pulls back harder the harder\n   *  you drive her. */\n  setWay(speed: number): void;\n  readonly way: number;\n  /** Where the wire lies, radians from dead astern. Positive to starboard. */\n  setAngle(radians: number): void;\n  readonly angle: number;\n  /** For a derrick: how far outboard the boom head is swung, m. */\n  setOutreach(metres: number): void;\n  readonly outreach: number;\n  /** For a derrick: the weight on the hook, tonnes. */\n  setLoad(tonnes: number): void;\n\n  /** Tension in the wire, tonnes. */\n  readonly strain: number;\n  /** What she can pull before the wire is simply dragging her backwards. */\n  readonly bollardPull: number;\n  /** HEELING MOMENT, tonne·metres, positive to starboard. Hand it straight to\n   *  `Hold.heel`. */\n  readonly moment: number;\n  /** Speed the gear is costing her, m/s. */\n  readonly drag: number;\n  /** Where the wire leaves her, in vessel metres. THE lever arm, and the\n   *  whole design of a tug is about getting it low and near her middle. */\n  readonly lead: Object3D;\n\n  /**\n   * THE OTHER END PULLS. A tow sheers, a net snags a wreck, a load swings off\n   * a barge in a swell — and for a few seconds the wire carries several times\n   * anything she could put on it herself.\n   *\n   * Nothing else in this module can capsize a properly built boat. This can,\n   * and it is the reason a tow hook opens.\n   */\n  snatch(tonnes: number): void;\n  /** What the other end is adding, tonnes. Decays over a few seconds. */\n  readonly surge: number;\n\n  /** She is being pulled over by her own gear. */\n  readonly girting: boolean;\n  /** The load has come fast — foul of the bottom, or a tow that will not\n   *  come. Strain goes to everything she has and stays there. */\n  readonly fast: boolean;\n  comeFast(): void;\n  clear(): void;\n\n  station: PropSlot;\n  slots: PropSlot[];\n  update(dt: number): void;\n}\n\nexport interface GearOptions {\n  kind?: GearKind;\n  /** Her beam, m — the lead points are placed off it. */\n  beam?: number;\n  /** Her length, m. */\n  length?: number;\n  /** Height of her working deck above the water, m. */\n  freeboard?: number;\n  /** What she can pull, tonnes. Sizes everything else. */\n  bollardPull?: number;\n  /** Start with it over the side. */\n  shot?: boolean;\n  seed?: number;\n  palette?: Palette;\n}\n\nconst clamp01 = (t: number): number => (t < 0 ? 0 : t > 1 ? 1 : t);\n\n/** Scratch, so placing a wire every frame allocates nothing. */\nconst worldQ = new Quaternion();\nconst tmpUp = new Vector3();\nconst tmpDir = new Vector3();\nconst tmpA = new Vector3();\nconst tmpB = new Vector3();\n\ninterface KindSpec {\n  beam: number;\n  length: number;\n  freeboard: number;\n  bollardPull: number;\n  /** Seconds to get it over the side. */\n  shootFor: number;\n  /** Seconds to get it back. */\n  haulFor: number;\n  /** Seconds to let go. `Infinity` where there is no way to. */\n  slipFor: number;\n  /**\n   * Does the load hang, or does it tow?\n   *\n   * A hanging load heels her through how far OUTBOARD it is; a towed one\n   * heels her through how far ABOVE the water the lead is and how far round\n   * the wire has come. They are different sums and getting them the same way\n   * round is the difference between a boat that capsizes when you swing the\n   * derrick and one that capsizes when you open the throttle.\n   */\n  hangs: boolean;\n  /** Working load at rest, tonnes — a string of pots, or a tow's own drag. */\n  base: number;\n  /** How much the strain grows with the square of her way, t per (m/s)². */\n  byWay: number;\n  /** How far astern the gear streams, m, as a multiple of her length. */\n  scope: number;\n  /**\n   * Lead point, as fractions of beam / length / freeboard.\n   *\n   * `leadY` is measured from the WORKING DECK, because that is where the\n   * ironwork is bolted. Its height above the SEA — which is what the heeling\n   * arm wants — is that plus her freeboard.\n   */\n  leadX: number;\n  leadZ: number;\n  leadY: number;\n  /**\n   * How deep her grip on the water is, m.\n   *\n   * A towed load does not heel her about the deck. The wire pulls one way at\n   * the lead and the water holds the hull the other way, low down — and the\n   * couple is between those two, not between the wire and the planking. Left\n   * out, a tug girted right abeam heels about half as far as she really does.\n   */\n  resist: number;\n}\n\nconst KINDS: Record<GearKind, KindSpec> = {\n  pots: {\n    beam: 4.2, length: 11, freeboard: 1.1, bollardPull: 1.2,\n    shootFor: 30, haulFor: 90, slipFor: 1, hangs: true,\n    base: 0.35, byWay: 0.02, scope: 0.4,\n    // OVER THE RAIL, because that is where a man can reach. It is also the\n    // worst place on the boat to put a weight, and there is nowhere else.\n    leadX: 0.5, leadZ: 0.05, leadY: 1.0, resist: 0.45,\n  },\n  trawl: {\n    beam: 7.4, length: 24, freeboard: 2.2, bollardPull: 9,\n    shootFor: 120, haulFor: 300, slipFor: 8, hangs: false,\n    base: 0.8, byWay: 0.9, scope: 3.5,\n    // The gallows on the quarter: outboard, aft, and high enough to shoot the\n    // net over. Every one of those is a lever arm.\n    leadX: 0.44, leadZ: -0.36, leadY: 1.0, resist: 1.5,\n  },\n  tow: {\n    beam: 9, length: 26, freeboard: 2.6, bollardPull: 40,\n    shootFor: 60, haulFor: 180, slipFor: 0.4, hangs: false,\n    base: 2.0, byWay: 1.6, scope: 6,\n    // AS LOW AND AS NEAR HER MIDDLE AS IT WILL GO. A towing hook is placed\n    // where it is entirely to make this number small, and she can still be\n    // girted, which tells you how big the number would otherwise be.\n    leadX: 0, leadZ: -0.12, leadY: 0.55, resist: 1.7,\n  },\n  derrick: {\n    beam: 11, length: 34, freeboard: 3.0, bollardPull: 6,\n    shootFor: 45, haulFor: 45, slipFor: Infinity, hangs: true,\n    base: 0, byWay: 0.05, scope: 0,\n    // The boom HEAD, which is high and can be swung right outboard — and a\n    // weight on it acts there the instant it leaves the deck.\n    leadX: 0.55, leadZ: 0.2, leadY: 2.6, resist: 2.2,\n  },\n};\n\nexport function createGear(options: GearOptions = {}): Gear {\n  const kind = options.kind ?? 'trawl';\n  const base = KINDS[kind];\n  const spec: KindSpec = {\n    ...base,\n    beam: options.beam ?? base.beam,\n    length: options.length ?? base.length,\n    freeboard: options.freeboard ?? base.freeboard,\n    bollardPull: options.bollardPull ?? base.bollardPull,\n  };\n  const seed = options.seed ?? 1;\n  const rng = new Rng(seed);\n  const palette = options.palette ?? DEFAULT_PALETTE;\n\n  const group = new Group();\n  group.name = `gear:${kind}`;\n\n  const steel = createSurface('steel', { color: 0x4e5359, seed });\n  const timber = createSurface('plank', { color: palette.wood, seed: seed + 1 });\n  const rope = new MeshStandardMaterial({ color: 0x2b2b28, roughness: 0.95 });\n  const buoyMat = new MeshStandardMaterial({\n    color: 0xe0561f,\n    emissive: 0x2a0c03,\n    roughness: 0.6,\n    flatShading: true,\n  });\n\n  const leadX = spec.leadX * spec.beam;\n  const leadY = spec.leadY * spec.freeboard;\n  const leadZ = spec.leadZ * spec.length;\n\n  const lead = new Object3D();\n  lead.name = 'gear:lead';\n  lead.position.set(leadX, leadY, leadZ);\n  group.add(lead);\n\n  // ── geometry ─────────────────────────────────────────────────────────\n\n  if (kind === 'trawl') {\n    for (const side of [-1, 1]) {\n      const gallows = new Group();\n      gallows.position.set(side * leadX, 0, leadZ);\n      group.add(gallows);\n      for (const dz of [-0.5, 0.5]) {\n        const leg = new Mesh(new CylinderGeometry(0.09, 0.11, leadY, 8), steel);\n        leg.position.set(0, leadY / 2, dz);\n        gallows.add(leg);\n      }\n      const head = new Mesh(new BoxGeometry(0.2, 0.16, 1.3), steel);\n      head.position.y = leadY;\n      gallows.add(head);\n      const block = new Mesh(new CylinderGeometry(0.2, 0.2, 0.14, 10), steel);\n      block.rotation.x = Math.PI / 2;\n      block.position.y = leadY - 0.2;\n      gallows.add(block);\n    }\n    const drum = new Mesh(new CylinderGeometry(0.7, 0.7, spec.beam * 0.6, 14), steel);\n    drum.rotation.z = Math.PI / 2;\n    drum.position.set(0, spec.freeboard * 0.5, leadZ + spec.length * 0.22);\n    group.add(drum);\n  } else if (kind === 'tow') {\n    const post = new Mesh(new CylinderGeometry(0.34, 0.4, leadY, 12), steel);\n    post.position.set(0, leadY / 2, leadZ);\n    group.add(post);\n    const hook = new Mesh(new BoxGeometry(0.5, 0.34, 0.34), steel);\n    hook.position.set(0, leadY, leadZ);\n    group.add(hook);\n    // The BOW of the winch drum, forward of the hook.\n    const drum = new Mesh(new CylinderGeometry(0.6, 0.6, spec.beam * 0.5, 14), steel);\n    drum.rotation.z = Math.PI / 2;\n    drum.position.set(0, spec.freeboard * 0.5, leadZ + spec.length * 0.2);\n    group.add(drum);\n    // …and the hoop that keeps the wire from sweeping the deck. It is what\n    // makes girting a thing that takes a while rather than a thing that\n    // happens the first time she sheers.\n    const horns = new Mesh(new BoxGeometry(spec.beam * 0.8, 0.14, 0.14), steel);\n    horns.position.set(0, leadY * 0.85, leadZ - 1.2);\n    group.add(horns);\n  } else if (kind === 'pots') {\n    const davit = new Mesh(new CylinderGeometry(0.07, 0.08, leadY * 1.5, 8), steel);\n    davit.position.set(leadX * 0.9, leadY * 0.75, leadZ);\n    davit.rotation.z = -0.28;\n    group.add(davit);\n    const hauler = new Mesh(new CylinderGeometry(0.22, 0.22, 0.2, 12), steel);\n    hauler.rotation.x = Math.PI / 2;\n    hauler.position.set(leadX * 0.72, leadY * 0.55, leadZ);\n    group.add(hauler);\n    for (let i = 0; i < 5; i++) {\n      const pot = new Mesh(new BoxGeometry(0.66, 0.42, 0.9), timber);\n      pot.position.set(\n        -spec.beam * 0.16 + (i % 2) * 0.75,\n        0.22 + Math.floor(i / 2) * 0.44,\n        leadZ - 1.6 - Math.floor(i / 2) * 0.2\n      );\n      pot.rotation.y = (rng.next() - 0.5) * 0.2;\n      group.add(pot);\n    }\n  } else {\n    // A derrick: a mast, a boom that swings, and a runner down to the hook.\n    const mast = new Mesh(new CylinderGeometry(0.24, 0.3, leadY * 1.35, 10), steel);\n    mast.position.set(0, (leadY * 1.35) / 2, leadZ);\n    group.add(mast);\n  }\n\n  /** The boom, for a derrick — it swings, and where its head is IS the sum. */\n  const boomY = leadY * 0.55;\n  const boom = new Object3D();\n  boom.name = 'gear:boom';\n  boom.position.set(0, boomY, leadZ);\n  if (kind === 'derrick') {\n    const spar = new Mesh(new BoxGeometry(spec.beam * 0.9, 0.22, 0.22), steel);\n    spar.position.x = spec.beam * 0.45;\n    boom.add(spar);\n    group.add(boom);\n  }\n\n  /**\n   * THE WIRE. One segment, from the lead to wherever the load is.\n   *\n   * It is the whole read: a still frame of a working boat tells you nothing\n   * unless you can see where her gear is pulling from, and the angle of that\n   * wire against her heel is the entire module in one picture.\n   */\n  // Thick enough to EXIST. A five-centimetre wire is the honest diameter and\n  // it is a sub-pixel line at any range that fits the boat in the frame, so\n  // the one thing the whole module is about is invisible in every picture of\n  // it. Scaled off her beam, so it stays a wire rather than a hawser.\n  const wireR = Math.max(0.06, spec.beam * 0.02);\n  const wire = new Mesh(new CylinderGeometry(wireR, wireR, 1, 6), rope);\n  wire.name = 'gear:wire';\n  group.add(wire);\n\n  const buoyR = Math.max(0.3, spec.beam * 0.075);\n  const buoy = new Mesh(new CylinderGeometry(buoyR, buoyR, buoyR * 1.8, 10), buoyMat);\n  buoy.name = 'gear:load';\n  group.add(buoy);\n\n  const station = addApproach(\n    createSlot('gear', 'work', group, leadX * 0.55, 0, leadZ + 1.2, Math.PI),\n    group,\n    0.8,\n    'front'\n  );\n\n  // ── the model ────────────────────────────────────────────────────────\n\n  let out = options.shot ? 1 : 0;\n  let ordered = out > 0.5;\n  let way = 0;\n  let angle = 0;\n  let outreach = kind === 'derrick' ? spec.beam * 0.3 : 0;\n  let load = kind === 'derrick' ? 2 : 0;\n  let fast = false;\n  let slipping = 0;\n  let surge = 0;\n  let state: GearState = out > 0.5 ? 'working' : 'stowed';\n\n  const ownStrain = (): number => {\n    if (out <= 0.01) return 0;\n    if (kind === 'derrick') return load;\n    if (fast) {\n      // COME FAST. Everything she has goes into the wire and stays there, and\n      // it does not care how fast she is going, because she is not going.\n      return spec.bollardPull * out;\n    }\n    // Towing, the strain grows with the square of her way — which is why it is\n    // a thing you control with the throttle and not with the winch. But it\n    // SATURATES at her bollard pull, because a boat cannot pull harder than\n    // she can pull. Written as a bare square she out-pulls herself at working\n    // speed, and then coming fast — which gives all of it — makes the strain\n    // go DOWN, and the one event this module exists to be about becomes a\n    // relief.\n    const want = spec.base + spec.byWay * way * way;\n    return spec.bollardPull * (1 - Math.exp(-want / spec.bollardPull)) * out;\n  };\n\n  /**\n   * What is on the wire. Her own pull, plus whatever the OTHER end is doing.\n   *\n   * The distinction matters more than anything else here. Her own gear at its\n   * absolute worst gives her a heel she can live with — that is what her beam\n   * is for. What kills a tug is the tow: twenty thousand tonnes with way on it\n   * sheers, and the wire takes several times her bollard pull for four\n   * seconds. She has no stability answer to that and was never given one. She\n   * was given a hook that opens.\n   */\n  const strainOf = (): number => (out <= 0.01 ? 0 : ownStrain() + surge);\n\n  const momentOf = (): number => {\n    const s = strainOf();\n    if (s <= 0) return 0;\n    if (spec.hangs) {\n      // A HANGING LOAD acts where it hangs from — and for a derrick that is\n      // the boom head, the instant the weight leaves the deck. The dangerous\n      // moment of a lift is the pick-up, not the swing.\n      const arm = kind === 'derrick' ? outreach : leadX;\n      return s * arm;\n    }\n    // A TOWED LOAD heels her through the athwartships part of the pull. Dead\n    // astern it does nothing whatever; abeam it does all of it — which is\n    // girting.\n    //\n    // The arm is the whole distance from the wire to the water's grip on her:\n    // the lead above the deck, the deck above the sea, and her hold on the\n    // water below it. The wire pulls one way up here and the hull is held the\n    // other way down there, and the couple is between those two — not between\n    // the wire and the planking it is bolted to.\n    return s * Math.sin(angle) * (leadY + spec.freeboard + spec.resist);\n  };\n\n  const place = (): void => {\n    // Where the load is, and where the wire leaves her, in her own frame. Deck\n    // is y = 0; the water is a freeboard below it.\n    const at = new Vector3();\n    const from = new Vector3(leadX, leadY, leadZ);\n\n    /**\n     * WHICH WAY IS UP, in her frame.\n     *\n     * Everything here is a child of the hull, so it rolls when she rolls — and\n     * a hundred and fifty metres of wire rolled forty-five degrees puts its far\n     * end a hundred metres under the sea. She carries her own net around the\n     * sky, and the picture of a girted tug has no wire in it at all.\n     *\n     * A towed load is in the water and stays in the water. A hanging one hangs\n     * plumb, which is precisely why a heeled ship's derrick load swings out\n     * over her side. Both of those are the WORLD vertical, not hers.\n     *\n     * The parent chain is a frame stale here — this runs inside `update`,\n     * before whatever carries her has set her attitude for the tick — and one\n     * frame of lag on a wire is not a thing anybody can see.\n     */\n    group.getWorldQuaternion(worldQ);\n    const up = tmpUp.set(0, 1, 0).applyQuaternion(worldQ.clone().invert());\n\n    /**\n     * How far the lead actually is above her flotation plane, right now.\n     *\n     * Not the height it would be if she were sitting up straight: a hook 3.3 m\n     * up on an upright tug is 2.3 m up on one lying at forty-five degrees, and\n     * dropping the load by the upright figure buries it a metre under. Her own\n     * origin IS her waterline, and it rides the wave with her, so the\n     * difference between the two in world y is the whole answer and it follows\n     * the sea for free.\n     */\n    let aboveWater = leadY + spec.freeboard;\n    if (group.parent) {\n      lead.getWorldPosition(tmpA);\n      group.parent.getWorldPosition(tmpB);\n      aboveWater = Math.max(0, tmpA.y - tmpB.y);\n    }\n    // Standing on its own with nothing to be mounted on, there is no hull to\n    // ask, so it falls back to the documented convention: the deck is a\n    // freeboard above the sea.\n\n    if (kind === 'derrick') {\n      // The boom SLEWS. It stows fore-and-aft and swings outboard, and\n      // `outreach` is how far outboard its head has got — so the angle comes\n      // out of a cosine, not a sine. Taken as `asin(outreach / L)` the head\n      // travels aft instead of over the side, and the arm the whole module\n      // turns on is the one distance the picture does not show.\n      const L = Math.max(0.1, spec.beam * 0.9);\n      const phi = Math.acos(clamp01(outreach / L));\n      boom.rotation.y = phi;\n      const headZ = leadZ - Math.sqrt(Math.max(0, L * L - outreach * outreach));\n      from.set(outreach, boomY, headZ);\n      // Straight down from the head, and DOWN is the world's down.\n      at.copy(from).addScaledVector(up, -Math.max(0.2, boomY - 0.9) * (1 - out) - 0.9);\n    } else {\n      const run = spec.scope * spec.length * out;\n      // The wire lies along the water, so its direction is squared off against\n      // the world horizon rather than against her deck.\n      const along = tmpDir\n        .set(Math.sin(angle), 0, -Math.cos(angle))\n        .projectOnPlane(up)\n        .normalize();\n      at.set(leadX, leadY, leadZ)\n        .addScaledVector(along, run)\n        // …and down to the surface, however she is lying.\n        .addScaledVector(up, -aboveWater * clamp01(out * 3));\n    }\n    buoy.position.copy(at);\n    buoy.visible = out > 0.02;\n\n    // …and the wire between them. A cylinder built along +y, so it is aimed by\n    // pointing its own axis at the far end rather than by three Eulers nobody\n    // can check.\n    const span = at.clone().sub(from);\n    const len = Math.max(0.01, span.length());\n    wire.visible = out > 0.02;\n    wire.scale.set(1, len, 1);\n    wire.position.copy(from).addScaledVector(span, 0.5);\n    wire.quaternion.setFromUnitVectors(new Vector3(0, 1, 0), span.normalize());\n    // Bar-taut when she is pulling and slack when she is not: the one thing\n    // everybody on a working deck watches.\n    const taut = clamp01(strainOf() / Math.max(0.01, spec.bollardPull));\n    (wire.material as MeshStandardMaterial).color.setRGB(\n      0.17 + taut * 0.5,\n      0.17 + taut * 0.06,\n      0.16\n    );\n  };\n  place();\n\n  const api: Gear = {\n    object: group,\n    obstacleRadius: 0,\n    kind,\n    lead,\n    station,\n    slots: [station],\n    bollardPull: spec.bollardPull,\n\n    shoot() {\n      ordered = true;\n    },\n    haul() {\n      ordered = false;\n    },\n    slip() {\n      // A DERRICK CANNOT LET GO. The load has to be put down somewhere and\n      // that takes as long as it takes — which is the era axis, and it is the\n      // most capable gear here that has no way out.\n      if (!Number.isFinite(spec.slipFor)) return;\n      slipping = spec.slipFor;\n      fast = false;\n    },\n    get out() {\n      return out;\n    },\n    get state() {\n      return state;\n    },\n    setWay(speed: number) {\n      way = Math.abs(Number.isFinite(speed) ? speed : 0);\n    },\n    get way() {\n      return way;\n    },\n    setAngle(radians: number) {\n      const r = Number.isFinite(radians) ? radians : 0;\n      angle = Math.max(-Math.PI / 2, Math.min(Math.PI / 2, r));\n    },\n    get angle() {\n      return angle;\n    },\n    setOutreach(metres: number) {\n      outreach = Math.max(0, Math.min(spec.beam * 0.9, Number.isFinite(metres) ? metres : 0));\n    },\n    get outreach() {\n      return outreach;\n    },\n    setLoad(tonnes: number) {\n      load = Math.max(0, Number.isFinite(tonnes) ? tonnes : 0);\n    },\n    get strain() {\n      return strainOf();\n    },\n    get moment() {\n      return momentOf();\n    },\n    get drag() {\n      // What the gear takes out of her. A towed net is most of her power; a\n      // string of pots is nothing much; a derrick is not in the water at all.\n      if (out <= 0.01 || spec.hangs) return 0;\n      return Math.min(way, (strainOf() / Math.max(0.01, spec.bollardPull)) * way * 0.55);\n    },\n    snatch(tonnes: number) {\n      const t = Number.isFinite(tonnes) ? Math.abs(tonnes) : 0;\n      // The worst of two snatches is a snatch, not the sum of two.\n      surge = Math.max(surge, t);\n    },\n    get surge() {\n      return out <= 0.01 ? 0 : surge;\n    },\n    get girting() {\n      // The wire is across her, there is real weight on it, and she cannot\n      // steer out of it because the pull is behind her pivot.\n      return (\n        !spec.hangs &&\n        out > 0.5 &&\n        Math.abs(Math.sin(angle)) > 0.62 &&\n        strainOf() > spec.bollardPull * 0.3\n      );\n    },\n    get fast() {\n      return fast;\n    },\n    comeFast() {\n      if (spec.hangs || out < 0.5) return;\n      fast = true;\n    },\n    clear() {\n      fast = false;\n    },\n\n    update(dt: number) {\n      if (!(dt > 0)) return;\n\n      // A snatch is over in seconds. That is the whole problem with it: by the\n      // time anybody has decided what to do, it has already either capsized\n      // her or not.\n      surge *= Math.exp(-dt / 2.5);\n      if (surge < 1e-3) surge = 0;\n\n      if (slipping > 0) {\n        slipping -= dt;\n        if (slipping <= 0) {\n          // Gone. All of it, at once, and the strain with it.\n          slipping = 0;\n          out = 0;\n          ordered = false;\n          fast = false;\n          surge = 0;\n        }\n      } else {\n        const per = ordered ? spec.shootFor : spec.haulFor;\n        const want = ordered ? 1 : 0;\n        const step = dt / Math.max(0.01, per);\n        const err = want - out;\n        out += Math.abs(err) <= step ? err : Math.sign(err) * step;\n        // Something foul of the bottom does not come up. Hauling against a\n        // fast net is how a boat is pulled down by her own winch.\n        if (fast && !ordered) out = Math.max(out, 0.55);\n      }\n      place();\n\n      const next: GearState = fast\n        ? 'fast'\n        : out <= 0.02\n          ? 'stowed'\n          : Math.abs(out - (ordered ? 1 : 0)) > 0.02\n            ? 'shooting'\n            : 'working';\n      if (next !== state) {\n        state = next;\n        api.onState?.(state);\n      }\n    },\n  };\n  return api;\n}\n\n/**\n * The list a heeling moment gives a vessel, radians — for a boat with no hold\n * to hand it to.\n *\n * `asin(M / (Δ · GM))`, and it returns the angle of vanishing stability if the\n * moment is more than she can answer, because past that there is no\n * equilibrium at all. The same sum `createHold` does, published for the small\n * craft that do not carry a cargo model around with them.\n */\nexport function listFor(\n  moment: number,\n  displacement: number,\n  gm: number,\n  vanishing = 0.7\n): number {\n  if (gm <= 0.02 || displacement <= 0) return Math.sign(moment) * vanishing;\n  const arg = moment / (displacement * gm);\n  const limit = Math.sin(vanishing);\n  return Math.abs(arg) >= limit ? Math.sign(arg) * vanishing : Math.asin(arg);\n}\n","import {\n  BoxGeometry,\n  CylinderGeometry,\n  Group,\n  Matrix4,\n  Mesh,\n  Quaternion,\n  Object3D,\n  Vector3,\n} from 'three';\nimport { Rng } from '../core/random';\nimport { DEFAULT_PALETTE, type Palette } from '../core/palette';\nimport { createSurface } from '../materials/surface';\nimport { addApproach, createSlot, type Prop, type PropSlot } from '../core/types';\n\n/**\n * Vessels you can stand on — the deck as ground that moves.\n *\n * `createBoat` and `createShip` already exist and are hulls that **bob**:\n * bind a water sampler, ride the waves, seat somebody at the helm. This is\n * the other half, and it is a different problem. Past about ten metres a\n * ship stops being a vehicle and becomes a **place** — somewhere with work\n * and rooms and other people, that happens to be moving.\n *\n * Every character controller in the trilogy assumes the floor is the world.\n * `terrain.heightAt` never moves. A deck pitches, rolls **and translates**,\n * so the fact that breaks everything is this:\n *\n * > A character standing perfectly still on a moving deck has to change\n * > world position anyway.\n *\n * Nothing in ANIMA or GAMA does that, and no amount of walking code fixes\n * it, because the character is not walking. So the handshake is a pair —\n * one query that mirrors `terrain.heightAt`, and one that has no equivalent\n * anywhere in the library:\n *\n * ```ts\n * deckAt(x, z): number | null    // walkable height in WORLD space\n * ride(position): Vector3        // and where that point goes next\n * ```\n *\n * `ride` is the whole track. It is one matrix multiply: the inverse of the\n * vessel's transform last frame, times its transform this frame. Feed a\n * standing character through it and they come along; do not, and they walk\n * out through the stern at whatever speed the ship is making.\n *\n * ```ts\n * const ship = createVessel({ era: 'carrack' });\n * ship.float((x, z) => ocean.heightAt(x, z));\n * game.onUpdate((t) => {\n *   ship.update(t.delta, { speed: 4 });\n *   ship.ride(sailor.position);              // carried by the deck\n *   sailor.position.y = ship.deckAt(sailor.position.x, sailor.position.z) ?? 0;\n * });\n * ```\n */\n\nexport type ShipEra =\n  /** An open oared galley: one low deck, no rail, and it moves like a leaf. */\n  | 'galley'\n  /** A carrack: a waist between a raised fo'c'sle and poop, ladders between. */\n  | 'carrack'\n  /** A steamer: flush deck, rails, a superstructure amidships. */\n  | 'steamer'\n  /** A liner: several decks, high freeboard, and a motion you barely feel. */\n  | 'liner';\n\n/**\n * Ground that moves, in **world** coordinates.\n *\n * The fifth spatial handshake, after `depthAt`, `heatAt`, `chillAt` and\n * `smokeAt` — and the first one that is not a *reading* but a *frame*. The\n * others answer \"what is it like here\". This one answers \"where is here\n * going\".\n */\nexport interface DeckField {\n  /**\n   * Walkable height at a world (x, z), or **null** if that point is not over\n   * a deck at all — which is how you test whether somebody is aboard, with\n   * no separate `contains`.\n   *\n   * `near` picks between stacked decks: the walkable surface nearest below\n   * it, so a sailor in the hold does not get teleported to the poop.\n   */\n  deckAt(x: number, z: number, near?: number): number | null;\n  /** The deck's up vector at a world point — it is not (0,1,0) at sea. */\n  normalAt(x: number, z: number): Vector3;\n  /**\n   * Carry a world point along with the vessel's own motion, in place.\n   *\n   * Call it every frame on anything standing on the deck, **after**\n   * `update`. Returns the same vector for chaining.\n   */\n  ride(position: Vector3): Vector3;\n}\n\n/** One walkable level. */\nexport interface DeckLevel {\n  /** Free label: 'waist', 'poop', 'promenade', 'hold'. */\n  name: string;\n  /** Height above the vessel's origin, in vessel space. */\n  y: number;\n  /** Extent along the vessel's z (fore–aft) and x (beam). */\n  length: number;\n  beam: number;\n  /** Centre along z, in vessel space. */\n  z: number;\n}\n\n/** A way up: structurally ANIMA's `Climbable`, like the pool ladder. */\nexport interface Companionway {\n  bottom: Object3D;\n  top: Object3D;\n  rungSpacing: number;\n}\n\nexport interface ShipInput {\n  /** Way through the water, m/s. */\n  speed?: number;\n  /** Rate of turn, radians/s. */\n  turn?: number;\n  /**\n   * Motion that is NOT along her own heading, m/s in world x and z.\n   *\n   * A vessel making way goes where she is pointing; a vessel being set by a\n   * tide, blown down onto a wall, or held off it by her own mooring lines\n   * does not, and there is no value of `speed` and `turn` that says so. It\n   * is applied inside `update` rather than by the caller writing `position`\n   * afterwards, because everything `ride` does depends on the frame delta\n   * being taken across ALL of a frame's movement — a ship warped sideways\n   * after her own update leaves her crew standing where she used to be.\n   */\n  drift?: { x: number; z: number };\n  /**\n   * How she is loaded — trim, list, sinkage, and how hard she snaps back.\n   *\n   * Structurally `Hold.loading`, and duck-typed rather than imported so the\n   * hull knows nothing about cargo. It is the first thing in this channel\n   * that is a **state of the vessel** rather than a force on her: a drift\n   * stops when the tide slackens, and a list does not stop.\n   *\n   * It is a BIAS on the sea-driven attitude and not a target for it. The\n   * hull eases toward the waves because she has mass; she does not ease\n   * toward her own trim, because her trim is not somewhere she is going.\n   */\n  /**\n   * How much of her ROLL something is taking out, 0 (nothing) to 1 (all of it).\n   *\n   * Structurally `Stabilisers.damping`, duck-typed like everything else in\n   * this channel. It touches the roll and NOTHING ELSE — fins are wings that\n   * work athwartships, and a stabilised ship in a head sea pitches exactly as\n   * hard as an unstabilised one. That is not a simplification; it is the\n   * commonest complaint about them.\n   */\n  damping?: number;\n  loading?: {\n    /** Positive is DOWN BY THE HEAD, the way it is said aboard. */\n    trim?: number;\n    /** Positive is a list to STARBOARD. */\n    list?: number;\n    sink?: number;\n    stiffness?: number;\n  };\n}\n\nexport interface DeckedShip extends Prop, DeckField {\n  era: ShipEra;\n  length: number;\n  beam: number;\n  /** Height of her main rail above the waterline — where lines are led. */\n  freeboard: number;\n  /**\n   * How deep she is DRAWN, m: keel to waterline, as her hull mesh was built.\n   *\n   * Published because anything that makes her float higher or lower has to\n   * measure from the same datum she was drawn to. A hold that measures its\n   * sinkage from its own load line instead lifts the whole ship clear of the\n   * sea by the difference, and every number about her stays correct.\n   */\n  draft: number;\n  decks: DeckLevel[];\n  ladders: Companionway[];\n  /** Where somebody steers. */\n  helm: PropSlot;\n  /** Bind the sea: `ocean.heightAt`, or a flat level. */\n  float(heightAt: (x: number, z: number) => number): void;\n  /** Live attitude, radians. */\n  readonly pitch: number;\n  readonly roll: number;\n  /**\n   * How hard it is to stand up right now, 0 (alongside) to 1 (hang on).\n   *\n   * Derived from the RATE of change of attitude and the heave, not from the\n   * attitude itself. A vessel heeled steadily at ten degrees under sail is\n   * easy to walk on; the same ten degrees arriving twice a second is not,\n   * and a number taken off the angle cannot tell those apart.\n   */\n  readonly motion: number;\n  /**\n   * How hard it is to stand up AT A POINT on her, 0–1. A FIELD — the fourth\n   * in the trilogy, after `heightAt`, `depthAt` and the rest.\n   *\n   * `motion` is one number for the whole ship. This one is not, and the\n   * difference is the entire layout of a liner. Her pitch throws the bow and\n   * the stern up and down and leaves amidships almost alone; her roll throws\n   * the high decks and the wings of the bridge about and leaves the\n   * centreline low down almost alone. So the quietest place aboard is\n   * **amidships and low**, and that falls out of two lever arms rather than\n   * out of a price list — which is nonetheless exactly what a price list for\n   * cabins looks like.\n   *\n   * In vessel-local metres: `x` athwartships, `z` fore-and-aft, `y` above\n   * the waterline.\n   */\n  motionAt(x: number, z: number, y?: number): number;\n  /** Vertical speed of the deck under a point, m/s. What `motionAt` is made\n   *  of, published because a number in m/s is a thing you can reason about\n   *  and a number in 0–1 is not. */\n  heaveAt(x: number, z: number, y?: number): number;\n  update(dt: number, input?: ShipInput): void;\n}\n\ninterface EraSpec {\n  length: number;\n  beam: number;\n  /** Deck height above the waterline. */\n  freeboard: number;\n  draft: number;\n  /**\n   * How much of the wave-induced attitude actually reaches the deck, and how\n   * fast. A galley follows every wave; a liner averages them out and takes\n   * its time about what is left.\n   */\n  gain: number;\n  /** Attitude smoothing (1/s). Low = slow, ponderous motion. */\n  ease: number;\n  levels: Array<{ name: string; y: number; length: number; beam: number; z: number }>;\n  rails: boolean;\n  superstructure: boolean;\n}\n\n/**\n * The era table.\n *\n * `gain` and `ease` are the whole of it, and they are not decoration: they\n * decide whether the deck is somewhere you can work. A galley at gain 1 and\n * ease 9 snaps to every crest — you brace, you do not carry things. A liner\n * at 0.12 and 0.7 has a motion you notice mainly as a slow lean, which is\n * exactly why one has a swimming pool on it and the other has oars.\n *\n * The beam does a lot of this for free and correctly: `deckAt` samples the\n * sea at port and starboard, and a 24 m beam spans more of a wavelength than\n * a 3.4 m one, so a wide hull averages the swell out before `gain` is even\n * applied. That fell out of the maths rather than being put in.\n */\nconst ERAS: Record<ShipEra, EraSpec> = {\n  galley: {\n    length: 22, beam: 3.6, freeboard: 0.75, draft: 0.5, gain: 1.0, ease: 9,\n    levels: [{ name: 'deck', y: 0.75, length: 20, beam: 3.2, z: 0 }],\n    rails: false, superstructure: false,\n  },\n  carrack: {\n    length: 26, beam: 8, freeboard: 2.1, draft: 1.6, gain: 0.72, ease: 4.5,\n    levels: [\n      { name: 'waist', y: 2.1, length: 12, beam: 7, z: 0 },\n      { name: 'forecastle', y: 3.5, length: 5.5, beam: 6, z: 9 },\n      { name: 'poop', y: 3.9, length: 6.5, beam: 6.4, z: -8.5 },\n      { name: 'hold', y: 0.5, length: 16, beam: 6, z: 0 },\n    ],\n    rails: true, superstructure: false,\n  },\n  steamer: {\n    length: 58, beam: 9.5, freeboard: 3.2, draft: 2.6, gain: 0.42, ease: 2.2,\n    levels: [\n      { name: 'main', y: 3.2, length: 52, beam: 9, z: 0 },\n      { name: 'boat', y: 6.0, length: 18, beam: 8, z: -4 },\n      { name: 'bridge', y: 8.2, length: 7, beam: 7.5, z: 4 },\n    ],\n    rails: true, superstructure: true,\n  },\n  liner: {\n    length: 180, beam: 24, freeboard: 11, draft: 7.5, gain: 0.12, ease: 0.7,\n    levels: [\n      { name: 'promenade', y: 11, length: 160, beam: 22, z: 0 },\n      { name: 'lido', y: 16, length: 90, beam: 20, z: -12 },\n      { name: 'sun', y: 20, length: 46, beam: 16, z: -20 },\n      { name: 'bridge', y: 23, length: 12, beam: 18, z: 55 },\n    ],\n    rails: true, superstructure: true,\n  },\n};\n\nexport interface DeckedShipOptions {\n  era?: ShipEra;\n  seed?: number;\n  palette?: Palette;\n  color?: number;\n}\n\nconst clamp01 = (t: number): number => (t < 0 ? 0 : t > 1 ? 1 : t);\n\n/**\n * A vessel with decks you can stand on.\n *\n * The origin is at the waterline, amidships, with **+z forward** — matching\n * the existing watercraft, so a hull and a vessel are interchangeable to\n * anything that only wants to float something.\n */\nexport function createDeckedShip(options: DeckedShipOptions = {}): DeckedShip {\n  const era = options.era ?? 'carrack';\n  const spec = ERAS[era];\n  const seed = options.seed ?? 1;\n  const rng = new Rng(seed);\n  const palette = options.palette ?? DEFAULT_PALETTE;\n\n  const group = new Group();\n  group.name = `ship-${era}`;\n\n  const L = spec.length;\n  const B = spec.beam;\n\n  const hullMat =\n    era === 'liner'\n      ? createSurface('paint', { seed, color: options.color ?? 0xf0f1f2 })\n      : era === 'steamer'\n        ? createSurface('paintedMetal', { seed, color: options.color ?? 0x2a3540 })\n        : createSurface('plank', { seed, color: options.color ?? palette.woodDark });\n  const deckMat =\n    era === 'liner'\n      ? createSurface('teak', { seed: seed + 1 })\n      : createSurface('plank', { seed: seed + 1, color: palette.wood });\n  const trim = createSurface(era === 'carrack' || era === 'galley' ? 'wood' : 'steel', {\n    seed: seed + 2,\n    metalness: 0.4,\n    roughness: 0.4,\n  });\n\n  // ---- hull ------------------------------------------------------------\n  /**\n   * Tapered at both ends rather than a box. Three sections is enough to read\n   * as a hull at any distance somebody will look at it from, and the point\n   * of this track is what happens ON the deck.\n   */\n  const hullTop = spec.freeboard;\n  const hullBottom = -spec.draft;\n  const hullH = hullTop - hullBottom;\n  const sections: Array<[number, number, number]> = [\n    [B, L * 0.6, 0],\n    [B * 0.62, L * 0.22, L * 0.41],\n    [B * 0.7, L * 0.2, -L * 0.4],\n  ];\n  for (const [w, len, z] of sections) {\n    const m = new Mesh(new BoxGeometry(w, hullH, len), hullMat);\n    m.position.set(0, hullBottom + hullH / 2, z);\n    group.add(m);\n  }\n  // A stem that actually cuts the water.\n  const stem = new Mesh(new BoxGeometry(B * 0.24, hullH, L * 0.12), hullMat);\n  stem.position.set(0, hullBottom + hullH / 2, L * 0.53);\n  stem.rotation.x = -0.22;\n  group.add(stem);\n\n  // ---- decks -----------------------------------------------------------\n  const decks: DeckLevel[] = [];\n  for (const level of spec.levels) {\n    decks.push({ ...level });\n    const board = new Mesh(new BoxGeometry(level.beam, 0.12, level.length), deckMat);\n    board.position.set(0, level.y - 0.06, level.z);\n    group.add(board);\n    // Bulwark or rail — all FOUR sides. Three of them left every raised deck\n    // open at the after end, which reads as a tray rather than a deck.\n    if (spec.rails && level.name !== 'hold') {\n      const railH = era === 'carrack' ? 0.9 : 1.05;\n      for (const s of [-1, 1]) {\n        const side = new Mesh(new BoxGeometry(0.09, railH, level.length), trim);\n        side.position.set((s * level.beam) / 2, level.y + railH / 2, level.z);\n        group.add(side);\n      }\n      for (const e of [-1, 1]) {\n        const end = new Mesh(new BoxGeometry(level.beam, railH, 0.09), trim);\n        end.position.set(0, level.y + railH / 2, level.z + (e * level.length) / 2);\n        group.add(end);\n      }\n    }\n    // …and the face it stands on. Without this a raised deck is a plank\n    // hovering above the hull with daylight under it — from three metres\n    // away the first render read as a stack of separate rafts rather than\n    // one ship.\n    if (level.y > spec.freeboard + 0.05) {\n      const drop = level.y - spec.freeboard;\n      for (const e of [-1, 1]) {\n        const face = new Mesh(new BoxGeometry(level.beam, drop, 0.14), hullMat);\n        face.position.set(0, level.y - drop / 2, level.z + (e * level.length) / 2);\n        group.add(face);\n      }\n      for (const sgn of [-1, 1]) {\n        const flank = new Mesh(new BoxGeometry(0.14, drop, level.length), hullMat);\n        flank.position.set((sgn * level.beam) / 2, level.y - drop / 2, level.z);\n        group.add(flank);\n      }\n    }\n  }\n  // Sort high to low: `deckAt` walks this and takes the first one at or\n  // below where you already are.\n  decks.sort((a, b) => b.y - a.y);\n\n  // ---- companionways ---------------------------------------------------\n  const ladders: Companionway[] = [];\n  const raised = decks.filter((d) => d.name !== 'hold');\n  for (let i = 0; i < raised.length - 1; i++) {\n    const upper = raised[i];\n    const lower = raised[i + 1];\n    if (upper.y - lower.y < 0.6) continue;\n    const at = new Group();\n    at.name = `companionway:${lower.name}-${upper.name}`;\n    // At the near edge of the upper deck, on the centreline-ish.\n    const z = upper.z + (upper.z > lower.z ? -upper.length / 2 - 0.3 : upper.length / 2 + 0.3);\n    at.position.set(B * 0.22, lower.y, z);\n    group.add(at);\n    const rise = upper.y - lower.y;\n    const spacing = 0.28;\n    for (let r = spacing; r < rise; r += spacing) {\n      const rung = new Mesh(new CylinderGeometry(0.03, 0.03, 0.7, 6), trim);\n      rung.rotation.z = Math.PI / 2;\n      rung.position.set(0, r, 0);\n      at.add(rung);\n    }\n    for (const s of [-1, 1]) {\n      const stringer = new Mesh(new BoxGeometry(0.06, rise, 0.06), trim);\n      stringer.position.set(s * 0.35, rise / 2, 0);\n      at.add(stringer);\n    }\n    const bottom = new Object3D();\n    bottom.name = 'ladder:bottom';\n    at.add(bottom);\n    const top = new Object3D();\n    top.name = 'ladder:top';\n    top.position.set(0, rise, upper.z > lower.z ? 0.5 : -0.5);\n    at.add(top);\n    ladders.push({ bottom, top, rungSpacing: spacing });\n  }\n\n  if (spec.superstructure) {\n    const house = new Mesh(\n      new BoxGeometry(B * 0.72, era === 'liner' ? 9 : 3.2, L * (era === 'liner' ? 0.42 : 0.22)),\n      era === 'liner' ? hullMat : createSurface('paint', { seed: seed + 3, color: 0xe8e6e0 })\n    );\n    house.position.set(0, spec.freeboard + (era === 'liner' ? 4.5 : 1.6), era === 'liner' ? -6 : 2);\n    group.add(house);\n  }\n  if (era === 'galley') {\n    // Thwarts. An open boat is benches, and the deck between them is the\n    // only walkable strip on it.\n    for (let i = -7; i <= 7; i++) {\n      const thwart = new Mesh(new BoxGeometry(B * 0.86, 0.1, 0.3), deckMat);\n      thwart.position.set(0, spec.freeboard + 0.35, i * 1.3);\n      group.add(thwart);\n    }\n  }\n  void rng;\n\n  const top = decks[0];\n  const helm = createSlot('helm', 'stand', group, 0, top.y, top.z - top.length / 2 + 0.8, 0);\n  addApproach(helm, group, 1.2, 'front');\n\n  // ---- state -----------------------------------------------------------\n  let sampler: ((x: number, z: number) => number) | null = null;\n  let pitch = 0;\n  let roll = 0;\n  let motion = 0;\n  // The three RATES, eased, kept apart. `motion` lumps them into one number\n  // for the whole ship; a point on her cares which is which, because they act\n  // through different lever arms.\n  let pitchRate = 0;\n  let rollRate = 0;\n  let heaveRate = 0;\n  /**\n   * The vessel's transform delta for this frame: current × inverse(previous).\n   *\n   * This one matrix IS the track. `ride` is a single `applyMatrix4` by it.\n   */\n  const delta = new Matrix4();\n  const prevInverse = new Matrix4();\n  const local = new Vector3();\n  const up = new Vector3();\n  const spin = new Quaternion();\n\n  const api: DeckedShip = {\n    object: group,\n    // A vessel is not an obstacle you steer around on land; it is the ground.\n    obstacleRadius: 0,\n    era,\n    length: L,\n    beam: B,\n    freeboard: spec.freeboard,\n    draft: spec.draft,\n    decks,\n    ladders,\n    helm,\n    slots: [helm],\n    get pitch() {\n      return pitch;\n    },\n    get roll() {\n      return roll;\n    },\n    get motion() {\n      return motion;\n    },\n    float(heightAt) {\n      sampler = heightAt;\n    },\n    deckAt(x: number, z: number, near?: number) {\n      group.updateWorldMatrix(true, false);\n      local.set(x, 0, z);\n      // Only x and z of the query mean anything: we are asking \"if I am over\n      // this spot, what is under me\", so the probe goes down the world Y.\n      group.worldToLocal(local);\n      for (const level of decks) {\n        if (Math.abs(local.x) > level.beam / 2) continue;\n        if (Math.abs(local.z - level.z) > level.length / 2) continue;\n        // Stacked decks: take the first at or below where the asker already\n        // is, so somebody in the hold is not teleported onto the poop.\n        if (near !== undefined) {\n          up.set(local.x, level.y, local.z);\n          group.localToWorld(up);\n          if (up.y > near + 1.2) continue;\n        }\n        up.set(local.x, level.y, local.z);\n        return group.localToWorld(up).y;\n      }\n      return null;\n    },\n    normalAt(x: number, z: number) {\n      // The deck's own up, turned into the world. It is not (0, 1, 0) at\n      // sea, which is the entire reason this is published rather than\n      // assumed. Flat within one vessel, so x and z do not enter — but they\n      // stay in the signature because a caller should not have to know that,\n      // and a hull with camber or a listing one will use them.\n      void x;\n      void z;\n      group.updateWorldMatrix(true, false);\n      group.getWorldQuaternion(spin);\n      return up.set(0, 1, 0).applyQuaternion(spin).normalize().clone();\n    },\n    ride(position: Vector3) {\n      return position.applyMatrix4(delta);\n    },\n    heaveAt(x: number, z: number, y = 0) {\n      // Honestly vertical: pitch through the distance from amidships, roll\n      // through the distance from her centreline, plus the heave — which is\n      // the same everywhere aboard and is why height does not enter here.\n      void y;\n      return pitchRate * Math.abs(z) + rollRate * Math.abs(x) + heaveRate;\n    },\n    motionAt(x: number, z: number, y = 0) {\n      // NOT the same weighting as `heaveAt`, and that is the point. Heave is\n      // the whole ship going up and down together — slow, gentle, and the\n      // thing you notice least; it is the LEVER ARMS that throw you, and being\n      // high up adds a sideways throw that does not appear in a vertical speed\n      // at all. Weighted equally, heave swamps both arms and the bow, the\n      // bridge wing and the middle of the dining saloon all read the same,\n      // which is the one distinction this field exists to make.\n      const felt =\n        pitchRate * Math.abs(z) +\n        rollRate * Math.abs(x) +\n        rollRate * Math.abs(y) * 0.8 +\n        heaveRate * 0.25;\n      // Saturating rather than clamped: an open boat in a gale is worse than\n      // an open boat in a swell, and a clamp says they are the same.\n      return 1 - Math.exp(-felt / 0.55);\n    },\n    update(dt: number, input: ShipInput = {}) {\n      if (dt <= 0) return;\n\n      // Capture where we were BEFORE moving. Everything about `ride` depends\n      // on this being taken first and exactly once.\n      group.updateWorldMatrix(true, false);\n      prevInverse.copy(group.matrixWorld).invert();\n\n      // Make way.\n      const speed = input.speed ?? 0;\n      if (input.turn) group.rotation.y += input.turn * dt;\n      if (speed) {\n        group.position.x += Math.sin(group.rotation.y) * speed * dt;\n        group.position.z += Math.cos(group.rotation.y) * speed * dt;\n      }\n      if (input.drift) {\n        group.position.x += input.drift.x * dt;\n        group.position.z += input.drift.z * dt;\n      }\n\n      // Ride the sea. Same four-point sample as the existing hulls, but the\n      // attitude is EASED toward it rather than snapped, because a ship has\n      // mass and a liner in particular takes half a minute to roll.\n      if (sampler) {\n        const { x, z } = group.position;\n        const sin = Math.sin(group.rotation.y);\n        const cos = Math.cos(group.rotation.y);\n        const bow = sampler(x + sin * L * 0.4, z + cos * L * 0.4);\n        const stern = sampler(x - sin * L * 0.4, z - cos * L * 0.4);\n        const port = sampler(x - cos * B * 0.5, z + sin * B * 0.5);\n        const starboard = sampler(x + cos * B * 0.5, z - sin * B * 0.5);\n\n        // SINKAGE IS PART OF WHERE SHE IS HEADING, not something done to her\n        // afterwards. Subtracted from `position.y` after the easing it is\n        // applied AGAIN every frame and never taken off, so it accumulates\n        // into a leaky integrator and settles at `sink / k` — a light steamer\n        // ends up twenty-two metres in the air, at 60 fps, with every number\n        // about her load perfectly correct.\n        const wantY = (bow + stern + port + starboard) / 4 - (input.loading?.sink ?? 0);\n        const wantPitch = Math.atan2(stern - bow, L * 0.8) * spec.gain;\n        // Damping takes the ROLL out and nothing else.\n        const wantRoll =\n          Math.atan2(port - starboard, B) * spec.gain * (1 - clamp01(input.damping ?? 0));\n        // A stiff ship answers the sea FASTER. That is the same claim as a\n        // short roll period, seen from the hull's side.\n        const k = Math.min(1, dt * spec.ease * (input.loading?.stiffness ?? 1));\n        const prevPitch = pitch;\n        const prevRoll = roll;\n        const prevY = group.position.y;\n        pitch += (wantPitch - pitch) * k;\n        roll += (wantRoll - roll) * k;\n        group.position.y += (wantY - group.position.y) * k;\n        // The load is a BIAS, added after the easing rather than eased toward.\n        // Ease her toward her own trim and a ship loaded down by the head\n        // spends thirty seconds getting there and then reads correctly for\n        // ever, which looks exactly like a ship that was always trimmed.\n        // OPPOSITE SIGNS, and not by accident. A positive rotation.x carries\n        // +z toward −y, so it puts the BOW DOWN; a positive rotation.z carries\n        // +x toward +y, so it lifts the STARBOARD side. \"Down by the head\" and\n        // \"list to starboard\" are both the sailor's positive, and they\n        // therefore need different signs here. Guessed either way round it\n        // reads back out of the model perfectly and puts her stem in the air.\n        group.rotation.x = pitch + (input.loading?.trim ?? 0);\n        group.rotation.z = roll - (input.loading?.list ?? 0);\n\n        // How hard it is to stand up: the RATE, not the angle. A vessel\n        // heeled steadily at ten degrees under sail is easy to walk on; the\n        // same ten degrees arriving twice a second is not, and a number\n        // taken off the angle cannot tell those two apart.\n        const rate =\n          (Math.abs(pitch - prevPitch) + Math.abs(roll - prevRoll)) / dt +\n          Math.abs(group.position.y - prevY) / dt * 0.25;\n        motion += (clamp01(rate * 1.6) - motion) * Math.min(1, dt * 3);\n\n        const k2 = Math.min(1, dt * 3);\n        pitchRate += (Math.abs(pitch - prevPitch) / dt - pitchRate) * k2;\n        rollRate += (Math.abs(roll - prevRoll) / dt - rollRate) * k2;\n        heaveRate += (Math.abs(group.position.y - prevY) / dt - heaveRate) * k2;\n      }\n\n      group.updateWorldMatrix(true, false);\n      delta.multiplyMatrices(group.matrixWorld, prevInverse);\n    },\n  };\n  return api;\n}\n\nexport const SHIP_ERAS: ShipEra[] = ['galley', 'carrack', 'steamer', 'liner'];\n","import {\n  Box3,\n  BoxGeometry,\n  Color,\n  CylinderGeometry,\n  Group,\n  Mesh,\n  MeshStandardMaterial,\n  SphereGeometry,\n  Vector3,\n} from 'three';\nimport { Rng } from '../core/random';\nimport { DEFAULT_PALETTE, type Palette } from '../core/palette';\nimport type { ChillField } from './cold';\nimport type { Carryable } from '../core/types';\n\n/**\n * Ingredients — the things the rest of the kitchen is for.\n *\n * This is the prop that closes the loop. The stove published a `HeatField`,\n * the cold store published a `ChillField`, the prep bench yields and the\n * sink consumes; none of it had anything to act *on*. An ingredient is the\n * subject, and it reads those fields itself, exactly the way `Cookware`\n * does:\n *\n * ```ts\n * onion.update(t.delta, fridge);   // samples keepAt at its own position\n * ```\n *\n * There are **two independent axes**, and keeping them apart is the whole\n * design:\n *\n * - **form** — `whole` → `prepped`. What you did to it. A one-way step, and\n *   it is the yield of a prep station.\n * - **freshness** — 1 down to 0. What time did to it, at a rate the cold\n *   store decides.\n *\n * They interact in exactly one place, and it is the rule worth having:\n * **prepping something makes it spoil far faster.** A whole onion keeps for\n * weeks and a chopped one keeps for a day, so `prep()` is a commitment\n * rather than a free upgrade — which is the only thing that makes a cook\n * plan the order of anything.\n *\n * ```ts\n * const onion = createIngredient({ kind: 'onion' });\n * onion.prep();                    // now on a clock\n * onion.update(t.delta, larder);   // …that the larder can slow down\n * onion.spoiled;                   // and eventually lose\n * ```\n */\n\nexport type IngredientKind =\n  | 'onion'\n  | 'carrot'\n  | 'potato'\n  | 'cabbage'\n  | 'meat'\n  | 'fish'\n  | 'bread'\n  | 'cheese'\n  | 'herbs'\n  | 'egg';\n\n/** What has been done to it. One way only — you cannot un-chop an onion. */\nexport type IngredientForm = 'whole' | 'prepped';\n\n/** How it is doing. `spoiled` is terminal. */\nexport type IngredientState = 'fresh' | 'tired' | 'spoiled';\n\ninterface KindSpec {\n  /** Seconds it keeps, whole, at bench temperature. */\n  keeps: number;\n  /**\n   * How much faster it goes off once it is cut.\n   *\n   * The number that makes the kitchen a planning problem rather than a\n   * sequence. Anything above about 4 and prepping ahead is simply wrong;\n   * at 1 it is free and nobody ever has to think.\n   */\n  cutFactor: number;\n  /** Radius of the whole thing, roughly. */\n  size: number;\n  colour: number;\n  /** What it looks like inside, once cut. */\n  inside: number;\n  /** How many pieces it falls into. */\n  pieces: number;\n  shape: 'round' | 'long' | 'slab' | 'leafy';\n}\n\n/**\n * The kind table.\n *\n * `keeps` spans two orders of magnitude on purpose. A potato and a fish are\n * not the same object with different meshes: one of them you can leave in a\n * corner for the whole game and the other is a **timer that started when you\n * picked it up**, and a kitchen with only one of those in it has no\n * decisions in it either.\n */\nconst KINDS: Record<IngredientKind, KindSpec> = {\n  onion:   { keeps: 900, cutFactor: 6,  size: 0.045, colour: 0xd8c9a4, inside: 0xf2ece0, pieces: 7, shape: 'round' },\n  carrot:  { keeps: 700, cutFactor: 5,  size: 0.028, colour: 0xd4732a, inside: 0xe89a4c, pieces: 8, shape: 'long' },\n  potato:  { keeps: 1400, cutFactor: 7, size: 0.05, colour: 0xa8834e, inside: 0xead9b0, pieces: 6, shape: 'round' },\n  cabbage: { keeps: 800, cutFactor: 4,  size: 0.075, colour: 0x8fae62, inside: 0xd6e2b4, pieces: 9, shape: 'round' },\n  meat:    { keeps: 180, cutFactor: 3,  size: 0.06, colour: 0xa84a48, inside: 0xc46a63, pieces: 5, shape: 'slab' },\n  fish:    { keeps: 120, cutFactor: 3,  size: 0.055, colour: 0xb8bec4, inside: 0xe4c9b4, pieces: 4, shape: 'long' },\n  bread:   { keeps: 420, cutFactor: 4,  size: 0.07, colour: 0xc09858, inside: 0xeadcb8, pieces: 6, shape: 'slab' },\n  cheese:  { keeps: 600, cutFactor: 3,  size: 0.05, colour: 0xe4c464, inside: 0xf0dc98, pieces: 5, shape: 'slab' },\n  herbs:   { keeps: 150, cutFactor: 8,  size: 0.05, colour: 0x4e8c3c, inside: 0x6ea84e, pieces: 10, shape: 'leafy' },\n  egg:     { keeps: 500, cutFactor: 9,  size: 0.026, colour: 0xf0e4cc, inside: 0xf6c93a, pieces: 3, shape: 'round' },\n};\n\nexport interface IngredientOptions {\n  kind?: IngredientKind;\n  /** Start already cut. Default false. */\n  form?: IngredientForm;\n  /** Start at less than perfect. 0–1, default 1. */\n  freshness?: number;\n  seed?: number;\n  palette?: Palette;\n}\n\nexport interface Ingredient extends Carryable {\n  kind: IngredientKind;\n  readonly form: IngredientForm;\n  readonly state: IngredientState;\n  /** 1 (just picked) down to 0 (gone). */\n  readonly freshness: number;\n  /** Nothing you can do about it. */\n  readonly spoiled: boolean;\n  /**\n   * Seconds of life left **at the rate it is currently going off**, or\n   * `Infinity` in a freezer. What a HUD wants and what a planner needs.\n   */\n  readonly shelfLife: number;\n  /** Cut it up. Returns false if it was already prepped, or already gone. */\n  prep(): boolean;\n  /** Advance the clock. Pass the cold store it is sitting in, or a rate. */\n  update(dt: number, chill?: ChillField | number): void;\n  /** Fired once, when it crosses into `tired` or `spoiled`. */\n  onState?: (state: IngredientState) => void;\n}\n\nconst clamp01 = (t: number): number => (t < 0 ? 0 : t > 1 ? 1 : t);\n\n/**\n * One ingredient.\n *\n * The origin is at its base, like every other carryable, so it sits on a\n * shelf or a board without arithmetic.\n */\nexport function createIngredient(options: IngredientOptions = {}): Ingredient {\n  const kind = options.kind ?? 'onion';\n  const spec = KINDS[kind];\n  const seed = options.seed ?? 1;\n  const rng = new Rng(seed);\n  const palette = options.palette ?? DEFAULT_PALETTE;\n  void palette;\n\n  const group = new Group();\n  group.name = `ingredient-${kind}`;\n\n  const skinBase = new Color(spec.colour);\n  const skin = new MeshStandardMaterial({\n    color: skinBase.clone(),\n    roughness: 0.72,\n    flatShading: true,\n  });\n  const flesh = new MeshStandardMaterial({\n    color: new Color(spec.inside),\n    roughness: 0.65,\n    flatShading: true,\n  });\n\n  /** The uncut thing. */\n  const whole = new Group();\n  group.add(whole);\n  const R = spec.size;\n  if (spec.shape === 'round') {\n    const body = new Mesh(new SphereGeometry(R, 9, 7), skin);\n    body.scale.set(1, kind === 'egg' ? 1.32 : rng.range(0.85, 1.0), 1);\n    body.position.y = R * (kind === 'egg' ? 1.32 : 0.92);\n    whole.add(body);\n    if (kind === 'onion') {\n      const wisp = new Mesh(new CylinderGeometry(0.002, 0.006, R * 0.9, 4), skin);\n      wisp.position.y = R * 2.2;\n      whole.add(wisp);\n    }\n  } else if (spec.shape === 'long') {\n    const body = new Mesh(new CylinderGeometry(R * 0.45, R, R * 5.5, 7), skin);\n    body.rotation.z = Math.PI / 2;\n    body.position.y = R;\n    whole.add(body);\n    if (kind === 'carrot') {\n      for (let i = 0; i < 3; i++) {\n        const frond = new Mesh(new BoxGeometry(0.004, R * 1.6, 0.012), flesh);\n        frond.material = new MeshStandardMaterial({ color: 0x4e8c3c, roughness: 0.8, flatShading: true });\n        frond.position.set(R * 2.9, R + R * 0.9, rng.range(-0.01, 0.01));\n        frond.rotation.z = rng.range(-0.5, 0.5);\n        whole.add(frond);\n      }\n    }\n  } else if (spec.shape === 'slab') {\n    const body = new Mesh(new BoxGeometry(R * 2.4, R * 1.1, R * 1.7), skin);\n    body.position.y = R * 0.55;\n    body.rotation.y = rng.range(-0.3, 0.3);\n    whole.add(body);\n  } else {\n    for (let i = 0; i < 6; i++) {\n      const leaf = new Mesh(new BoxGeometry(R * 0.5, 0.004, R * 1.1), skin);\n      leaf.position.set(rng.range(-R * 0.5, R * 0.5), 0.004 + i * 0.005, rng.range(-R * 0.4, R * 0.4));\n      leaf.rotation.set(rng.range(-0.2, 0.2), rng.range(0, 3), rng.range(-0.2, 0.2));\n      whole.add(leaf);\n    }\n  }\n\n  /**\n   * The cut-up version.\n   *\n   * Built up front and hidden, rather than rebuilt on `prep()`. A generator\n   * that swaps geometry mid-game is a generator that allocates during play,\n   * and the whole point of the pieces is that they are the same object.\n   */\n  const cut = new Group();\n  cut.visible = false;\n  group.add(cut);\n  for (let i = 0; i < spec.pieces; i++) {\n    const piece =\n      spec.shape === 'long'\n        ? new Mesh(new CylinderGeometry(R * 0.85, R * 0.85, R * 0.5, 8), flesh)\n        : spec.shape === 'leafy'\n          ? new Mesh(new BoxGeometry(R * 0.2, 0.003, R * 0.2), flesh)\n          : new Mesh(new BoxGeometry(R * 0.7, R * 0.35, R * 0.7), flesh);\n    // A heap, not a grid. Cut vegetables land where they land.\n    const a = rng.range(0, Math.PI * 2);\n    const r = rng.range(0, R * 1.5);\n    piece.position.set(Math.cos(a) * r, R * 0.2 + (i % 2) * R * 0.22, Math.sin(a) * r);\n    piece.rotation.set(rng.range(-0.4, 0.4), rng.range(0, 3), rng.range(-0.4, 0.4));\n    cut.add(piece);\n  }\n\n  /**\n   * Seat both versions on y = 0.\n   *\n   * Measured rather than hand-placed. A cylinder laid on its side has a\n   * seven-sided cross-section that is not symmetric about its axis, so\n   * \"put the centre at the radius\" leaves a carrot a centimetre into the\n   * worktop and a fish nearly three — and every one of those numbers would\n   * have had to be found and tuned by kind. Shifting the children (not the\n   * group) also keeps the wilting scale shrinking toward the surface rather\n   * than lifting the thing off it.\n   */\n  for (const part of [whole, cut]) {\n    part.updateMatrixWorld(true);\n    const drop = new Box3().setFromObject(part).min.y;\n    if (Number.isFinite(drop)) for (const child of part.children) child.position.y -= drop;\n  }\n\n  // ---- state -------------------------------------------------------------\n  let form: IngredientForm = options.form ?? 'whole';\n  let freshness = clamp01(options.freshness ?? 1);\n  let state: IngredientState = 'fresh';\n  const world = new Vector3();\n\n  const classify = (): IngredientState =>\n    freshness <= 0 ? 'spoiled' : freshness < 0.4 ? 'tired' : 'fresh';\n  state = classify();\n\n  /** Ageing per second, before whatever the cold store does about it. */\n  const wear = (): number => (1 / spec.keeps) * (form === 'prepped' ? spec.cutFactor : 1);\n\n  const paint = (): void => {\n    // Fresh → tired → spoiled, in the skin. A number nothing on screen\n    // reflects is a number, and a green cabbage that reports itself rotten\n    // is worse than no state at all.\n    const t = 1 - freshness;\n    skin.color.copy(skinBase);\n    // Desaturate and darken toward a grey-brown; the last stretch goes\n    // properly off rather than just dim.\n    const off = new Color(0x6b5f44);\n    skin.color.lerp(off, Math.min(1, t * 0.85));\n    flesh.color.set(spec.inside);\n    flesh.color.lerp(off, Math.min(1, t * 0.95));\n    // And it shrinks. Everything that goes off loses water.\n    const shrink = 1 - t * 0.22;\n    whole.scale.set(shrink, shrink, shrink);\n    cut.scale.set(shrink, shrink, shrink);\n  };\n  paint();\n  whole.visible = form === 'whole';\n  cut.visible = form === 'prepped';\n\n  /** The last sampled preservation rate, so `shelfLife` can answer honestly. */\n  let lastKeep = 1;\n\n  const api: Ingredient = {\n    object: group,\n    obstacleRadius: 0,\n    carry: 'side',\n    kind,\n    get form() {\n      return form;\n    },\n    get state() {\n      return state;\n    },\n    get freshness() {\n      return freshness;\n    },\n    get spoiled() {\n      return freshness <= 0;\n    },\n    get shelfLife() {\n      if (freshness <= 0) return 0;\n      const rate = wear() * lastKeep;\n      return rate <= 1e-9 ? Infinity : freshness / rate;\n    },\n    prep() {\n      // One way, and not on something that is already gone: chopping a\n      // rotten onion gives you rotten chopped onion, which no recipe wants\n      // and which no player meant to make.\n      if (form === 'prepped' || freshness <= 0) return false;\n      form = 'prepped';\n      whole.visible = false;\n      cut.visible = true;\n      return true;\n    },\n    update(dt: number, chill?: ChillField | number) {\n      if (dt <= 0 || freshness <= 0) return;\n\n      // The same shape as `Cookware.update(dt, heat)`: hand it the prop and\n      // it samples the field at its OWN position, so moving it into the\n      // fridge is all it takes and nothing has to be told about it.\n      let keep = 1;\n      if (typeof chill === 'number') keep = Math.max(0, chill);\n      else if (chill) {\n        group.updateWorldMatrix(true, false);\n        group.getWorldPosition(world);\n        keep = Math.max(0, chill.keepAt(world.x, world.y, world.z));\n      }\n      lastKeep = keep;\n\n      const was = state;\n      freshness = Math.max(0, freshness - wear() * keep * dt);\n      paint();\n      state = classify();\n      if (state !== was) api.onState?.(state);\n    },\n  };\n  return api;\n}\n\n/**\n * How long this kind keeps at bench temperature, in seconds — whole, and\n * once it is cut.\n *\n * Exported so a planner can decide what to prepare last without having to\n * build one and watch it rot.\n */\nexport function keepsFor(kind: IngredientKind, form: IngredientForm = 'whole'): number {\n  const spec = KINDS[kind];\n  return form === 'prepped' ? spec.keeps / spec.cutFactor : spec.keeps;\n}\n\nexport const INGREDIENT_KINDS: IngredientKind[] = [\n  'onion', 'carrot', 'potato', 'cabbage', 'meat',\n  'fish', 'bread', 'cheese', 'herbs', 'egg',\n];\n","import {\n  Box3,\n  BoxGeometry,\n  CylinderGeometry,\n  Group,\n  Mesh,\n  MeshStandardMaterial,\n  Object3D,\n  SphereGeometry,\n  TorusGeometry,\n  Vector3,\n} from 'three';\nimport { Rng } from '../core/random';\nimport { DEFAULT_PALETTE, type Palette } from '../core/palette';\nimport { createSurface } from '../materials/surface';\nimport {\n  createPropSurface,\n  createSlot,\n  addApproach,\n  type Carryable,\n  type Prop,\n  type PropSlot,\n  type PropSurface,\n} from '../core/types';\n\n/**\n * Dressers, racks and rails — storage that **shows what is in it**.\n *\n * Every storage prop the library has so far is a box that opens: a chest, a\n * drawer, a cupboard, a `Manipulable` whose whole job is to hide its\n * contents until somebody operates it. A kitchen is the opposite. The room\n * is arranged so that the things you use most are visible and within reach,\n * and a dresser with nothing on it is a bookcase.\n *\n * So this track's contribution is the vertical counterpart to `dress`:\n *\n * ```ts\n * dress(table.surfaces[0], things);   // puts things DOWN on a surface\n * stock(dresser, things);             // puts things AWAY — on shelves,\n *                                     // in grooves, on hooks\n * ```\n *\n * `dress` only knows about horizontal surfaces. Half of a kitchen's storage\n * is neither: plates stand **on edge** in the grooves of a rack, pans **hang**\n * from a rail, and a wall cupboard's shelves are **behind a door** and\n * therefore not on display at all until it is opened. A `StorageSpace`\n * carries all three of those distinctions, and `hidden` is live — shut the\n * cupboard and what is in it stops counting as shown.\n *\n * ```ts\n * const dresser = createDresser({ kind: 'welsh' });\n * stock(dresser, createKitchenware({ count: 14 }), { seed: 3 });\n * dresser.shown;   // how much of it a person can actually see\n * ```\n */\n\nexport type DresserKind =\n  /** A Welsh dresser: a cupboard base, and open plate shelves above. */\n  | 'welsh'\n  /** A wall-hung plate rack — grooves, and nothing else. */\n  | 'plateRack'\n  /** A hanging rail of S-hooks for pans and tools. */\n  | 'potRail'\n  /** A run of modern wall cabinets. Doors, so nothing is on show. */\n  | 'wallUnit'\n  /** A tall larder cupboard for dry goods. Deep shelves, behind doors. */\n  | 'pantry';\n\nexport type SpaceKind =\n  /** Sits on it, the way it was built. */\n  | 'shelf'\n  /** Stands ON EDGE in it — a plate rack, a tray slot. */\n  | 'groove'\n  /** Hangs from it, by its top. */\n  | 'hook'\n  /** Sits in it, and is hidden whether or not there is a door. */\n  | 'drawer';\n\n/** A cupboard door or a drawer front — structurally a `Manipulable`. */\nexport interface DresserDoor {\n  readonly state: number;\n  readonly open: boolean;\n  toggle(): boolean;\n  set(target: number | boolean): void;\n  update(dt: number): void;\n  onChange?: (open: boolean) => void;\n  object: Object3D;\n}\n\n/** Somewhere one thing goes. */\nexport interface StorageSpace {\n  kind: SpaceKind;\n  /** Where the thing sits, stands or hangs from. A child of the prop. */\n  anchor: Object3D;\n  /** Clear height above a shelf, or the drop below a hook, in metres. */\n  clear: number;\n  /** Clear width along the anchor's x, in metres. */\n  width: number;\n  /** What is in it, or null. */\n  held: Object3D | null;\n  /**\n   * Is it out of sight?\n   *\n   * **Live**, not a constant: shut the cupboard door and everything on its\n   * shelves stops being on display. This is the distinction the whole track\n   * turns on, because it is the difference between a dresser and a cupboard.\n   */\n  readonly hidden: boolean;\n}\n\nexport interface Storage extends Prop {\n  kind: DresserKind;\n  spaces: StorageSpace[];\n  /** Doors, where it has any. Operate them like any other `Manipulable`. */\n  doors: DresserDoor[];\n  /** Worktops and shelf tops you can also `dress`. */\n  surfaces: PropSurface[];\n  /** Where somebody stands to reach it. */\n  slot: PropSlot;\n  readonly used: number;\n  readonly free: number;\n  /** How many of the things in it are actually visible right now. */\n  readonly shown: number;\n  /**\n   * Put something away. Picks the first free space it fits, optionally of a\n   * given kind. Returns the space, or null if nothing would take it.\n   */\n  put(item: Prop | Object3D, kind?: SpaceKind): StorageSpace | null;\n  /** Take it back out. Returns what was there, unparented. */\n  take(space: StorageSpace): Object3D | null;\n  update(dt: number): void;\n}\n\ninterface KindSpec {\n  width: number;\n  depth: number;\n  height: number;\n  /** Height of the underside, for the wall-hung ones. */\n  base: number;\n  doors: number;\n  /** Shelves behind the doors. */\n  inner: number;\n  /** Open shelves. */\n  open: number;\n  grooves: number;\n  hooks: number;\n  drawers: number;\n  /** Is there a worktop you can put things down on? */\n  worktop: boolean;\n}\n\n/**\n * The kind table.\n *\n * The `doors` column is the one that matters, and it is not a styling\n * choice: a `welsh` dresser and a `wallUnit` hold about the same amount, and\n * one of them is furniture you look at while the other is a box on a wall.\n * Everything downstream — what `shown` reports, what a room reads as, what\n * `stock` is even worth doing to it — follows from that column.\n */\nconst KINDS: Record<DresserKind, KindSpec> = {\n  welsh: {\n    width: 1.2, depth: 0.46, height: 2.0, base: 0,\n    doors: 2, inner: 1, open: 3, grooves: 5, hooks: 4, drawers: 2, worktop: true,\n  },\n  plateRack: {\n    width: 0.72, depth: 0.2, height: 0.52, base: 1.28,\n    doors: 0, inner: 0, open: 0, grooves: 8, hooks: 0, drawers: 0, worktop: false,\n  },\n  potRail: {\n    width: 1.15, depth: 0.12, height: 0.1, base: 1.72,\n    doors: 0, inner: 0, open: 0, grooves: 0, hooks: 7, drawers: 0, worktop: false,\n  },\n  wallUnit: {\n    width: 1.0, depth: 0.34, height: 0.74, base: 1.38,\n    doors: 2, inner: 3, open: 0, grooves: 0, hooks: 0, drawers: 0, worktop: false,\n  },\n  pantry: {\n    width: 0.82, depth: 0.5, height: 2.05, base: 0,\n    doors: 2, inner: 5, open: 0, grooves: 0, hooks: 0, drawers: 0, worktop: false,\n  },\n};\n\nexport interface DresserOptions {\n  kind?: DresserKind;\n  seed?: number;\n  palette?: Palette;\n  /** Paint/timber colour. Defaults per kind. */\n  color?: number;\n}\n\nconst clamp01 = (t: number): number => (t < 0 ? 0 : t > 1 ? 1 : t);\nconst smooth = (t: number): number => t * t * (3 - 2 * t);\n\n/** A hinged leaf or a sliding drawer, shaped exactly like `Manipulable`. */\nfunction makeJoint(\n  pivot: Group,\n  apply: (t: number, pivot: Group) => void,\n  speed = 3\n): DresserDoor {\n  let target = 0;\n  let state = 0;\n  const api: DresserDoor = {\n    object: pivot,\n    get state() {\n      return state;\n    },\n    get open() {\n      return target > 0.5;\n    },\n    toggle() {\n      const next = !(target > 0.5);\n      api.set(next);\n      return next;\n    },\n    set(value: number | boolean) {\n      const was = target > 0.5;\n      target = typeof value === 'boolean' ? (value ? 1 : 0) : clamp01(value);\n      if (was !== target > 0.5) api.onChange?.(target > 0.5);\n    },\n    update(dt: number) {\n      state += (target - state) * Math.min(1, dt * speed);\n      apply(smooth(state), pivot);\n    },\n  };\n  return api;\n}\n\n/** Measure an object in its own space, with any previous placement undone. */\nfunction sizeOf(object: Object3D): { size: Vector3; min: Vector3 } {\n  object.position.set(0, 0, 0);\n  object.rotation.set(0, 0, 0);\n  object.updateMatrixWorld(true);\n  const box = new Box3().setFromObject(object);\n  return { size: box.getSize(new Vector3()), min: box.min.clone() };\n}\n\nconst objectOf = (item: Prop | Object3D): Object3D =>\n  (item as Prop).object instanceof Object3D ? (item as Prop).object : (item as Object3D);\n\n/**\n * A dresser, rack, rail or cupboard.\n *\n * The origin is on the floor at the centre of the front face, facing +z into\n * the room — the same as the stove, the cold store and the sink, **including\n * the wall-hung kinds**. A plate rack's origin is on the floor below it, not\n * at the bracket, so a kitchen wall is a row of these at the same y with no\n * arithmetic.\n */\nexport function createDresser(options: DresserOptions = {}): Storage {\n  const kind = options.kind ?? 'welsh';\n  const spec = KINDS[kind];\n  const seed = options.seed ?? 1;\n  const rng = new Rng(seed);\n  const palette = options.palette ?? DEFAULT_PALETTE;\n\n  const group = new Group();\n  group.name = `dresser-${kind}`;\n\n  const W = spec.width;\n  const D = spec.depth;\n  const H = spec.height;\n  const B = spec.base;\n  const T = 0.026;\n\n  const body =\n    kind === 'wallUnit'\n      ? createSurface('paint', { seed, color: options.color ?? 0xe6e3dc })\n      : createSurface('wood', { seed, color: options.color ?? palette.wood });\n  const dark = createSurface('wood', { seed: seed + 1, color: palette.woodDark });\n  const metal = createSurface('metal', { seed: seed + 2, color: 0x8d939a });\n\n  const spaces: StorageSpace[] = [];\n  const doors: DresserDoor[] = [];\n  const surfaces: PropSurface[] = [];\n\n  /**\n   * Build a space.\n   *\n   * `door` is captured rather than copied, so `hidden` follows the door for\n   * the life of the prop. A boolean snapshotted at build time would report a\n   * shut cupboard forever, however often the thing is opened.\n   */\n  const addSpace = (\n    spaceKind: SpaceKind,\n    x: number,\n    y: number,\n    z: number,\n    clear: number,\n    width: number,\n    door: DresserDoor | null\n  ): StorageSpace => {\n    const anchor = new Object3D();\n    anchor.name = `space:${spaceKind}`;\n    anchor.position.set(x, y, z);\n    group.add(anchor);\n    const space: StorageSpace = {\n      kind: spaceKind,\n      anchor,\n      clear,\n      width,\n      held: null,\n      get hidden() {\n        // A drawer is out of sight whether or not it has a front on it.\n        if (spaceKind === 'drawer') return !(door?.open ?? false);\n        return door !== null && !door.open;\n      },\n    };\n    spaces.push(space);\n    return space;\n  };\n\n  /** A carcass: five panels around a hole, never a solid box. */\n  const carcass = (y0: number, y1: number, depth: number, zBack: number): void => {\n    const h = y1 - y0;\n    for (const [w, hh, d, x, y, z] of [\n      [T, h, depth, -W / 2 + T / 2, (y0 + y1) / 2, zBack - depth / 2],\n      [T, h, depth, W / 2 - T / 2, (y0 + y1) / 2, zBack - depth / 2],\n      [W, h, T, 0, (y0 + y1) / 2, zBack - depth + T / 2],\n      [W, T, depth, 0, y1 - T / 2, zBack - depth / 2],\n      [W, T, depth, 0, y0 + T / 2, zBack - depth / 2],\n    ] as Array<[number, number, number, number, number, number]>) {\n      const m = new Mesh(new BoxGeometry(w, hh, d), body);\n      m.position.set(x, y, z);\n      group.add(m);\n    }\n  };\n\n  /** A pair of doors on the front of a carcass between y0 and y1. */\n  const hangDoors = (y0: number, y1: number, count: number, z: number): DresserDoor[] => {\n    const made: DresserDoor[] = [];\n    const leafW = (W - 0.02) / count;\n    for (let i = 0; i < count; i++) {\n      // Hinged on the OUTER edge of each leaf, so a pair opens outward like a\n      // pair rather than both swinging the same way like a saloon.\n      const side = count === 1 ? -1 : i === 0 ? -1 : 1;\n      const hx = -W / 2 + 0.01 + i * leafW + (side < 0 ? 0 : leafW);\n      const pivot = new Group();\n      pivot.position.set(hx, 0, z);\n      group.add(pivot);\n      const leaf = new Mesh(new BoxGeometry(leafW - 0.006, y1 - y0 - 0.01, 0.022), body);\n      leaf.position.set((-side * leafW) / 2, (y0 + y1) / 2, 0.012);\n      pivot.add(leaf);\n      const panel = new Mesh(\n        new BoxGeometry((leafW - 0.006) * 0.72, (y1 - y0 - 0.01) * 0.78, 0.008),\n        dark\n      );\n      panel.position.set((-side * leafW) / 2, (y0 + y1) / 2, 0.026);\n      pivot.add(panel);\n      const knob = new Mesh(new SphereGeometry(0.016, 8, 6), metal);\n      knob.position.set((-side * leafW) / 2 + side * (leafW / 2 - 0.05), (y0 + y1) / 2, 0.03);\n      pivot.add(knob);\n      made.push(makeJoint(pivot, (t, p) => (p.rotation.y = -side * t * 1.85)));\n    }\n    return made;\n  };\n\n  if (kind === 'welsh') {\n    const baseTop = 0.9;\n    carcass(0, baseTop, D, 0);\n    const cupboardDoors = hangDoors(0.24, baseTop - 0.16, spec.doors, 0);\n    doors.push(...cupboardDoors);\n    // Hidden shelf inside the base.\n    const midY = 0.24 + (baseTop - 0.4) / 2;\n    const shelfBoard = new Mesh(new BoxGeometry(W - T * 2, 0.02, D - T * 2), body);\n    shelfBoard.position.set(0, midY, -D / 2);\n    group.add(shelfBoard);\n    addSpace('shelf', 0, midY + 0.01, -D / 2, 0.3, W - 0.1, cupboardDoors[0] ?? null);\n\n    // The drawer row.\n    for (let i = 0; i < spec.drawers; i++) {\n      const dw = (W - 0.04) / spec.drawers;\n      const dx = -W / 2 + 0.02 + dw * (i + 0.5);\n      const pivot = new Group();\n      pivot.position.set(dx, baseTop - 0.08, 0);\n      group.add(pivot);\n      const front = new Mesh(new BoxGeometry(dw - 0.01, 0.11, 0.02), body);\n      front.position.z = 0.011;\n      pivot.add(front);\n      const pull = new Mesh(new CylinderGeometry(0.008, 0.008, dw * 0.4, 6), metal);\n      pull.rotation.z = Math.PI / 2;\n      pull.position.z = 0.03;\n      pivot.add(pull);\n      // A drawer box, so an open drawer is not a hole with a face floating\n      // in front of it.\n      for (const [w, h, dd, x, y, z] of [\n        [dw - 0.02, 0.012, D * 0.8, 0, -0.05, -D * 0.4],\n        [0.01, 0.09, D * 0.8, -(dw - 0.02) / 2, 0, -D * 0.4],\n        [0.01, 0.09, D * 0.8, (dw - 0.02) / 2, 0, -D * 0.4],\n      ] as Array<[number, number, number, number, number, number]>) {\n        const m = new Mesh(new BoxGeometry(w, h, dd), dark);\n        m.position.set(x, y, z);\n        pivot.add(m);\n      }\n      const drawer = makeJoint(pivot, (t, p) => (p.position.z = t * D * 0.62));\n      doors.push(drawer);\n      addSpace('drawer', dx, baseTop - 0.13, -D * 0.4, 0.085, dw - 0.05, drawer);\n    }\n\n    // The worktop, which is also a surface you can `dress`.\n    const top = new Mesh(new BoxGeometry(W + 0.04, 0.03, D + 0.03), dark);\n    top.position.set(0, baseTop + 0.015, -D / 2);\n    group.add(top);\n    surfaces.push(createPropSurface('worktop', group, 0, baseTop + 0.03, -D * 0.45, W * 0.86, D * 0.7));\n\n    // The open plate shelves above — the point of a dresser.\n    const upperD = D * 0.52;\n    const back = new Mesh(new BoxGeometry(W - 0.04, H - baseTop - 0.04, 0.014), body);\n    back.position.set(0, (baseTop + H) / 2, -upperD + 0.007);\n    group.add(back);\n    for (const s of [-1, 1]) {\n      const side = new Mesh(new BoxGeometry(0.02, H - baseTop - 0.04, upperD), body);\n      side.position.set((s * (W - 0.04)) / 2, (baseTop + H) / 2, -upperD / 2);\n      group.add(side);\n    }\n    const cornice = new Mesh(new BoxGeometry(W + 0.02, 0.04, upperD + 0.02), dark);\n    cornice.position.set(0, H - 0.02, -upperD / 2);\n    group.add(cornice);\n\n    const shelfGap = (H - 0.06 - (baseTop + 0.06)) / spec.open;\n    for (let i = 0; i < spec.open; i++) {\n      const y = baseTop + 0.06 + shelfGap * i;\n      const board = new Mesh(new BoxGeometry(W - 0.06, 0.018, upperD - 0.01), body);\n      board.position.set(0, y, -upperD / 2);\n      group.add(board);\n      // A groove strip at the back: the ledge plates lean against, and the\n      // reason a dresser displays crockery instead of storing it.\n      const lip = new Mesh(new BoxGeometry(W - 0.06, 0.014, 0.012), dark);\n      lip.position.set(0, y + 0.016, -upperD + 0.05);\n      group.add(lip);\n      surfaces.push(\n        createPropSurface(`shelf${i}`, group, 0, y + 0.01, -upperD * 0.42, W * 0.8, upperD * 0.6)\n      );\n      addSpace('shelf', 0, y + 0.01, -upperD * 0.36, shelfGap - 0.05, W - 0.12, null);\n      // …and grooves on the back half of the same shelf.\n      const per = Math.max(1, Math.round(spec.grooves / spec.open));\n      for (let g = 0; g < per && spaces.filter((sp) => sp.kind === 'groove').length < spec.grooves; g++) {\n        const gx = -W / 2 + 0.12 + ((W - 0.24) * (g + 0.5)) / per;\n        addSpace('groove', gx, y + 0.02, -upperD + 0.075, shelfGap - 0.06, (W - 0.24) / per, null);\n      }\n    }\n    // Cup hooks under the lowest open shelf.\n    for (let i = 0; i < spec.hooks; i++) {\n      const hx = -W / 2 + 0.14 + ((W - 0.28) * i) / Math.max(1, spec.hooks - 1);\n      const hy = baseTop + 0.06 + shelfGap - 0.03;\n      const hook = new Mesh(new TorusGeometry(0.016, 0.003, 4, 8, Math.PI * 1.4), metal);\n      hook.rotation.set(Math.PI / 2, 0, 0);\n      hook.position.set(hx, hy, -upperD * 0.45);\n      group.add(hook);\n      addSpace('hook', hx, hy - 0.02, -upperD * 0.45, shelfGap - 0.12, (W - 0.28) / spec.hooks, null);\n    }\n  } else if (kind === 'plateRack') {\n    // A frame of dowels on the wall. Every space is a groove and nothing is\n    // hidden — it is a rack, it has no secrets.\n    const frameY = B + H / 2;\n    for (const s of [-1, 1]) {\n      const side = new Mesh(new BoxGeometry(0.022, H, D), body);\n      side.position.set((s * (W - 0.02)) / 2, frameY, -D / 2);\n      group.add(side);\n    }\n    for (const y of [B + 0.03, B + H - 0.03]) {\n      const rail = new Mesh(new BoxGeometry(W, 0.022, D), body);\n      rail.position.set(0, y, -D / 2);\n      group.add(rail);\n    }\n    const per = spec.grooves;\n    for (let i = 0; i <= per; i++) {\n      const x = -W / 2 + 0.04 + ((W - 0.08) * i) / per;\n      for (const z of [-D + 0.05, -0.05]) {\n        const dowel = new Mesh(new CylinderGeometry(0.007, 0.007, H - 0.08, 6), dark);\n        dowel.position.set(x, frameY, z);\n        group.add(dowel);\n      }\n    }\n    for (let i = 0; i < per; i++) {\n      const x = -W / 2 + 0.04 + ((W - 0.08) * (i + 0.5)) / per;\n      addSpace('groove', x, B + 0.05, -D / 2, H - 0.1, (W - 0.08) / per, null);\n    }\n  } else if (kind === 'potRail') {\n    const railY = B;\n    const rail = new Mesh(new CylinderGeometry(0.013, 0.013, W, 10), metal);\n    rail.rotation.z = Math.PI / 2;\n    rail.position.set(0, railY, -D / 2);\n    group.add(rail);\n    for (const s of [-1, 1]) {\n      const bracket = new Mesh(new BoxGeometry(0.018, 0.1, 0.018), metal);\n      bracket.position.set((s * W) / 2 - s * 0.05, railY + 0.05, -D / 2);\n      group.add(bracket);\n      const arm = new Mesh(new BoxGeometry(0.018, 0.018, D), metal);\n      arm.position.set((s * W) / 2 - s * 0.05, railY + 0.1, -D / 2);\n      group.add(arm);\n    }\n    for (let i = 0; i < spec.hooks; i++) {\n      const x = -W / 2 + 0.1 + ((W - 0.2) * i) / Math.max(1, spec.hooks - 1);\n      // An S-hook, drawn as a hook rather than a peg, because a straight peg\n      // with a pan on it reads as a pan stuck to the wall.\n      const s1 = new Mesh(new TorusGeometry(0.019, 0.0035, 4, 9, Math.PI * 1.3), metal);\n      s1.rotation.set(Math.PI / 2, 0, Math.PI);\n      s1.position.set(x, railY - 0.016, -D / 2);\n      group.add(s1);\n      const s2 = new Mesh(new TorusGeometry(0.019, 0.0035, 4, 9, Math.PI * 1.3), metal);\n      s2.rotation.set(Math.PI / 2, 0, 0);\n      s2.position.set(x, railY - 0.05, -D / 2);\n      group.add(s2);\n      addSpace('hook', x, railY - 0.07, -D / 2, 0.42, (W - 0.2) / spec.hooks, null);\n    }\n  } else {\n    // wallUnit and pantry: a carcass with doors, and everything inside is\n    // hidden until they are open.\n    carcass(B, B + H, D, 0);\n    const leaves = hangDoors(B + 0.01, B + H - 0.01, spec.doors, 0);\n    doors.push(...leaves);\n    const gap = (H - 0.12) / spec.inner;\n    for (let i = 0; i < spec.inner; i++) {\n      const y = B + 0.08 + gap * i;\n      const board = new Mesh(new BoxGeometry(W - T * 2, 0.018, D - T * 2), body);\n      board.position.set(0, y, -D / 2);\n      group.add(board);\n      // Each shelf belongs to the door that covers it: a two-door pantry with\n      // one leaf open shows half its contents, which is the correct answer\n      // and not one a single boolean could give.\n      const owner = leaves[Math.min(leaves.length - 1, i % Math.max(1, leaves.length))] ?? null;\n      addSpace('shelf', 0, y + 0.009, -D / 2, gap - 0.04, W - 0.1, owner);\n    }\n    if (kind === 'pantry') {\n      const plinth = new Mesh(new BoxGeometry(W * 0.94, 0.06, D * 0.9), dark);\n      plinth.position.set(0, 0.03, -D / 2);\n      group.add(plinth);\n    }\n  }\n\n  const standAt = createSlot('reach', 'work', group, 0, 0, 0.6, Math.PI);\n  addApproach(standAt, group, 0.55, 'behind');\n\n  const held = new Map<StorageSpace, Object3D>();\n\n  const api: Storage = {\n    object: group,\n    obstacleRadius: B > 0.6 ? 0 : Math.max(W, D) * 0.55,\n    kind,\n    spaces,\n    doors,\n    surfaces,\n    slot: standAt,\n    slots: [standAt],\n    get used() {\n      return spaces.filter((s) => s.held !== null).length;\n    },\n    get free() {\n      return spaces.filter((s) => s.held === null).length;\n    },\n    get shown() {\n      return spaces.filter((s) => s.held !== null && !s.hidden).length;\n    },\n    put(item: Prop | Object3D, want?: SpaceKind) {\n      const object = objectOf(item);\n      const { size, min } = sizeOf(object);\n      for (const space of spaces) {\n        if (space.held) continue;\n        if (want && space.kind !== want) continue;\n\n        if (space.kind === 'groove') {\n          // ON EDGE. A plate laid flat in a plate rack is a plate on a shelf\n          // and the rack might as well not be there.\n          //\n          // The axis matters and it is not the obvious one. A rack's slots\n          // run front to back, and plates go in side by side ALONG the rack —\n          // so the plate turns about z, not x, and what has to fit the slot\n          // width is its THICKNESS while what has to fit the clear height is\n          // its diameter. Turning it about x instead lays each plate across\n          // the slots like a bridge, and the fit test then measures the wrong\n          // two numbers and rejects everything.\n          if (size.y > space.width || size.x > space.clear) continue;\n          object.rotation.set(rng.range(-0.07, 0.07), 0, Math.PI / 2);\n          object.updateMatrixWorld(true);\n          const box = new Box3().setFromObject(object);\n          object.position.set(\n            space.anchor.position.x,\n            space.anchor.position.y - box.min.y,\n            space.anchor.position.z\n          );\n        } else if (space.kind === 'hook') {\n          if (size.y > space.clear || size.x > space.width) continue;\n          // Hung by its TOP, and off-square. A row of pans all hanging plumb\n          // is a shop display.\n          object.rotation.set(0, rng.range(-0.35, 0.35), rng.range(-0.1, 0.1));\n          object.updateMatrixWorld(true);\n          const box = new Box3().setFromObject(object);\n          object.position.set(\n            space.anchor.position.x,\n            space.anchor.position.y - box.max.y,\n            space.anchor.position.z\n          );\n        } else {\n          if (size.y > space.clear || size.x > space.width) continue;\n          object.rotation.set(0, rng.range(-0.4, 0.4), 0);\n          object.position.set(\n            space.anchor.position.x + rng.range(-1, 1) * Math.max(0, (space.width - size.x) * 0.3),\n            space.anchor.position.y - min.y,\n            space.anchor.position.z\n          );\n        }\n        group.add(object);\n        space.held = object;\n        held.set(space, object);\n        return space;\n      }\n      return null;\n    },\n    take(space: StorageSpace) {\n      const object = held.get(space) ?? null;\n      if (!object) return null;\n      group.remove(object);\n      held.delete(space);\n      space.held = null;\n      return object;\n    },\n    update(dt: number) {\n      for (const d of doors) d.update(dt);\n    },\n  };\n  return api;\n}\n\nexport interface StockOptions {\n  /** Fill at most this share of the spaces, 0–1. Default 0.72. */\n  density?: number;\n  /** Restrict to these kinds of space. */\n  only?: SpaceKind[];\n  seed?: number;\n}\n\n/**\n * Put things away — the vertical counterpart to `dress`.\n *\n * `dress` arranges items on a horizontal surface. Half of what a kitchen\n * holds is not on one: plates stand on edge, pans hang, jars go behind a\n * door. `stock` walks the spaces instead, tries each item into the first one\n * that will take it, and **deliberately leaves gaps** — a dresser with\n * something in every single space is a shop, and the density default is\n * there for the same reason `dress` has one.\n *\n * Returns what it actually placed. Anything that would not fit is left\n * unparented and simply missing from the result.\n */\nexport function stock(\n  storage: Storage,\n  items: Array<Prop | Object3D>,\n  options: StockOptions = {}\n): Object3D[] {\n  const rng = new Rng(options.seed ?? 1);\n  const density = Math.min(1, Math.max(0, options.density ?? 0.72));\n  const only = options.only;\n\n  const usable = storage.spaces.filter((s) => s.held === null && (!only || only.includes(s.kind)));\n  const budget = Math.round(usable.length * density);\n  if (budget <= 0) return [];\n\n  // Shuffle which spaces get used, so the gaps are scattered rather than all\n  // at the end — a dresser filled front-to-back has one empty shelf, which\n  // reads as an unfinished dresser rather than a used one.\n  const order = usable.slice();\n  for (let i = order.length - 1; i > 0; i--) {\n    const j = Math.floor(rng.next() * (i + 1));\n    [order[i], order[j]] = [order[j], order[i]];\n  }\n  const open = new Set(order.slice(0, budget));\n\n  const placed: Object3D[] = [];\n  for (const item of items) {\n    if (placed.length >= budget) break;\n    let seated: StorageSpace | null = null;\n    for (const space of storage.spaces) {\n      if (!open.has(space) || space.held) continue;\n      seated = storage.put(item, space.kind);\n      // `put` scans from the start, so it may have landed somewhere other\n      // than the space we were offering. That is fine — it is still a space\n      // we meant to fill — but stop looking once it is in.\n      if (seated) break;\n    }\n    if (seated) placed.push(seated.held!);\n  }\n  return placed;\n}\n\n// --------------------------------------------------------------- the things\n\nexport type UtensilStyle = 'ladle' | 'skimmer' | 'spoon' | 'knife' | 'board' | 'sieve';\n\nexport interface UtensilOptions {\n  style?: UtensilStyle;\n  seed?: number;\n  palette?: Palette;\n}\n\n/**\n * A kitchen tool, built **handle up**.\n *\n * That is the one decision in here. A ladle hangs from its handle with the\n * bowl below, and it also stands in a jar the same way up — so a single\n * model works both hung and put down, and `stock` needs no per-prop hook\n * point to hang it by. It just uses the top of the bounding box.\n */\nexport function createUtensil(options: UtensilOptions = {}): Carryable {\n  const style = options.style ?? 'ladle';\n  const seed = options.seed ?? 1;\n  const rng = new Rng(seed);\n  const palette = options.palette ?? DEFAULT_PALETTE;\n\n  const group = new Group();\n  group.name = `utensil-${style}`;\n  const steel = new MeshStandardMaterial({\n    color: 0xb4bac0,\n    roughness: 0.34,\n    metalness: 0.6,\n    flatShading: true,\n  });\n  const wood = createSurface('wood', { seed, color: palette.woodDark });\n\n  const handleFor = (length: number, top: number): void => {\n    const h = new Mesh(new CylinderGeometry(0.008, 0.0095, length, 6), wood);\n    h.position.y = top - length / 2;\n    group.add(h);\n    // The hanging hole, and it is not decoration: without it a hung utensil\n    // reads as a stick balanced on a hook.\n    const eye = new Mesh(new TorusGeometry(0.009, 0.002, 4, 8), steel);\n    eye.rotation.x = Math.PI / 2;\n    eye.position.y = top - 0.004;\n    group.add(eye);\n  };\n\n  if (style === 'board') {\n    const slab = new Mesh(new BoxGeometry(0.2, 0.3, 0.016), wood);\n    slab.position.y = 0.15;\n    group.add(slab);\n    const hole = new Mesh(new TorusGeometry(0.016, 0.004, 4, 10), wood);\n    hole.rotation.x = Math.PI / 2;\n    hole.position.y = 0.295;\n    group.add(hole);\n  } else if (style === 'knife') {\n    handleFor(0.11, 0.3);\n    const blade = new Mesh(new BoxGeometry(0.035, 0.16, 0.003), steel);\n    blade.position.y = 0.11;\n    group.add(blade);\n  } else if (style === 'sieve') {\n    handleFor(0.1, 0.3);\n    const mesh = new Mesh(new SphereGeometry(0.06, 10, 6, 0, Math.PI * 2, Math.PI / 2, Math.PI / 2), steel);\n    mesh.material.side = 2;\n    mesh.position.y = 0.19;\n    group.add(mesh);\n    const rim = new Mesh(new TorusGeometry(0.06, 0.004, 4, 14), steel);\n    rim.position.y = 0.19;\n    group.add(rim);\n  } else {\n    const long = style === 'spoon' ? 0.19 : 0.16;\n    handleFor(long, 0.32);\n    const bowl =\n      style === 'ladle'\n        ? new Mesh(new SphereGeometry(0.042, 10, 6, 0, Math.PI * 2, Math.PI / 2, Math.PI / 2), steel)\n        : style === 'skimmer'\n          ? new Mesh(new CylinderGeometry(0.05, 0.05, 0.008, 12), steel)\n          : new Mesh(new SphereGeometry(0.036, 10, 6, 0, Math.PI * 2, Math.PI / 2, Math.PI / 2), steel);\n    if (style !== 'skimmer') bowl.material.side = 2;\n    bowl.position.y = 0.32 - long;\n    bowl.scale.set(1, style === 'spoon' ? 0.6 : 1, style === 'spoon' ? 1.35 : 1);\n    group.add(bowl);\n  }\n  group.rotation.y = rng.range(0, 0.4);\n\n  return { object: group, obstacleRadius: 0, carry: 'side', rest: 'upright' };\n}\n\nexport interface CrockeryOptions {\n  /** A single plate, a stack of them, or a stack of bowls. */\n  style?: 'plate' | 'stack' | 'bowls';\n  /** How many in a stack. Default 4. */\n  count?: number;\n  seed?: number;\n  palette?: Palette;\n}\n\n/**\n * Plates and bowls.\n *\n * A single `plate` is what goes in a rack groove; a `stack` is what goes on\n * a shelf. They are the same object at different counts, which is exactly\n * why a rack and a shelf are different kinds of space rather than the same\n * one with a flag.\n */\nexport function createCrockery(options: CrockeryOptions = {}): Carryable {\n  const style = options.style ?? 'stack';\n  const count = style === 'plate' ? 1 : Math.max(1, options.count ?? 4);\n  const seed = options.seed ?? 1;\n  const rng = new Rng(seed);\n\n  const group = new Group();\n  group.name = `crockery-${style}`;\n  const glaze = createSurface('glaze', {\n    seed,\n    color: rng.next() < 0.4 ? 0xe8e2d4 : rng.next() < 0.5 ? 0xdfe8ea : 0xf2efe8,\n  });\n\n  for (let i = 0; i < count; i++) {\n    const piece =\n      style === 'bowls'\n        ? new Mesh(new CylinderGeometry(0.072, 0.045, 0.05, 14), glaze)\n        : new Mesh(new CylinderGeometry(0.088, 0.07, 0.013, 16), glaze);\n    const step = style === 'bowls' ? 0.026 : 0.015;\n    piece.position.set(rng.range(-0.004, 0.004), 0.008 + i * step, rng.range(-0.004, 0.004));\n    piece.rotation.y = rng.range(0, 3);\n    group.add(piece);\n  }\n\n  return { object: group, obstacleRadius: 0, carry: 'crate', rest: 'upright' };\n}\n\nexport interface KitchenwareOptions {\n  /** How many pieces. Default 10. */\n  count?: number;\n  seed?: number;\n  palette?: Palette;\n}\n\n/**\n * The kitchen dress kit: a mixed set of things a kitchen actually holds.\n *\n * Weighted rather than uniform, because a real kitchen is mostly crockery\n * with a few tools in it, and an even draw across six utensil styles and\n * three crockery styles gives you a hardware display.\n */\nexport function createKitchenware(options: KitchenwareOptions = {}): Carryable[] {\n  const seed = options.seed ?? 1;\n  const rng = new Rng(seed);\n  const palette = options.palette ?? DEFAULT_PALETTE;\n  const count = options.count ?? 10;\n\n  const utensils: UtensilStyle[] = ['ladle', 'skimmer', 'spoon', 'knife', 'board', 'sieve'];\n  const out: Carryable[] = [];\n  for (let i = 0; i < count; i++) {\n    const roll = rng.next();\n    if (roll < 0.34) {\n      out.push(createCrockery({ style: 'plate', seed: seed * 17 + i, palette }));\n    } else if (roll < 0.52) {\n      out.push(createCrockery({ style: 'stack', count: 3 + Math.floor(rng.next() * 3), seed: seed * 17 + i, palette }));\n    } else if (roll < 0.64) {\n      out.push(createCrockery({ style: 'bowls', count: 2 + Math.floor(rng.next() * 3), seed: seed * 17 + i, palette }));\n    } else {\n      out.push(\n        createUtensil({ style: utensils[Math.floor(rng.next() * utensils.length)], seed: seed * 17 + i, palette })\n      );\n    }\n  }\n  return out;\n}\n\nexport const DRESSER_KINDS: DresserKind[] = ['welsh', 'plateRack', 'potRail', 'wallUnit', 'pantry'];\nexport const UTENSIL_STYLES: UtensilStyle[] = ['ladle', 'skimmer', 'spoon', 'knife', 'board', 'sieve'];\n","import {\n  BoxGeometry,\n  CylinderGeometry,\n  DoubleSide,\n  Group,\n  Mesh,\n  MeshStandardMaterial,\n  Object3D,\n  Vector3,\n} from 'three';\nimport { Rng } from '../core/random';\nimport { DEFAULT_PALETTE, type Palette } from '../core/palette';\nimport { createSurface } from '../materials/surface';\nimport { createFill, createSteam, type Fill, type Steam } from './waterworks';\nimport { createTap, type Tap } from './washing';\nimport { makeBurst, type Burst, type WorkStation } from './workstations';\nimport {\n  addApproach,\n  createPropSurface,\n  createSlot,\n  type Prop,\n  type PropSlot,\n  type PropSurface,\n} from '../core/types';\n\n/**\n * The sink, and the washing-up.\n *\n * `createBasin` already exists and this is deliberately not it. A basin is\n * about **water**: taps, a level, a plug. A sink is about the **pile of\n * dishes** — the water is only the thing that makes the pile go down, and\n * how good the water is decides how fast.\n *\n * So this is a `WorkStation` like the chopping block and the prep bench, but\n * with one difference that turns it into a track of its own: **the cycle\n * time is not a constant.** Every other work loop in the library grinds at a\n * fixed rate forever. Here the rate is a product of what is in the bowl:\n *\n * ```\n * rate = (water > 0) × (1 − soil × 0.75) × (0.5 + hot × 0.5)\n * ```\n *\n * No water and nothing happens at all. Fresh hot water is four times faster\n * than a cold grey bowlful, and every plate you wash makes the water a\n * little worse — so at some point you stop, pull the plug, and run another\n * lot. That decision is the game, and none of it is a re-skin of a basin.\n *\n * The era axis is the same shape as the stove's and the cold store's, and it\n * ends the same way: the modern one **takes the loop away**. A dishwasher is\n * not a faster sink, it is a door, a capacity and a wait.\n *\n * ```ts\n * const sink = createWashUp({ era: 'sink' });\n * sink.load(10);\n * sink.taps[0].set(true);\n * sink.onYield = (n) => console.log('washed', n);\n * game.onUpdate((t) => sink.update(t.delta, cook.atSink));\n * ```\n */\n\nexport type SinkEra =\n  /** A stone trough. No tap and no drain: water is carried in and baled out. */\n  | 'trough'\n  /** A deep butler sink with one cold tap. Hot water arrives in a kettle. */\n  | 'scullery'\n  /** A double bowl, a mixer, a draining board. Hot water on demand. */\n  | 'sink'\n  /** A machine. Load it, shut it, start it, walk away. */\n  | 'dishwasher';\n\n/**\n * A pile of things to wash and a pile of things that are washed.\n *\n * Deliberately a **count**, not a list of objects. What a game wants from\n * the sink is \"are the dishes done\", and making the caller hand over twelve\n * `Carryable`s to get twelve back is ceremony around a number.\n */\nexport interface WashQueue {\n  /** Waiting to be washed. */\n  readonly dirty: number;\n  /** Washed, and still sitting there until somebody puts them away. */\n  readonly clean: number;\n  /** How many it holds at once. */\n  readonly capacity: number;\n  /** Put dirty things in. Returns how many it actually took. */\n  load(count?: number): number;\n  /** Take the clean ones away. Returns how many it actually gave. */\n  collect(count?: number): number;\n}\n\n/** The machine door — structurally a `Manipulable`, like every other one. */\nexport interface SinkDoor {\n  readonly state: number;\n  readonly open: boolean;\n  toggle(): boolean;\n  set(target: number | boolean): void;\n  update(dt: number): void;\n  onChange?: (open: boolean) => void;\n  object: Object3D;\n}\n\nexport interface WashUp extends Prop, WorkStation, WashQueue {\n  era: SinkEra;\n  /** Water in the bowl, 0–1. */\n  readonly water: number;\n  /** How grey it is, 0 (fresh) to 1 (finished). Every plate adds to it. */\n  readonly soil: number;\n  /** Heat left in it, 0–1. It goes cold on its own, fast in a stone trough. */\n  readonly hot: number;\n  /**\n   * Run water in. `hot` is what came out of it — 1 from a plumbed hot tap or\n   * a kettle off the stove, 0 from a bucket. New water **dilutes** what is\n   * already there rather than replacing it, so topping up a filthy bowl\n   * helps a bit and never as much as emptying it.\n   */\n  fill(amount: number, hot?: number): void;\n  /** Pull the plug. Takes the heat and the dirt with it. */\n  empty(): void;\n  /** Taps to operate. **Empty on `trough`** — that is the point of it. */\n  taps: Tap[];\n  /** The draining board clean things stack on. Also published in `surfaces`. */\n  board: PropSurface | null;\n  /** The machine's door. Null on everything you wash by hand. */\n  door: SinkDoor | null;\n  /**\n   * Start a cycle. Returns false if it will not go: door open, nothing in\n   * it, or already running. A no-op on the eras you wash by hand.\n   */\n  start(): boolean;\n  readonly running: boolean;\n  /** Cycle progress, 0–1. Always 0 on the hand eras. */\n  readonly cycle: number;\n  /** Steam off hot water, or out of a machine that has just finished. */\n  steam: Steam;\n  /** Where somebody stands. */\n  slot: PropSlot;\n  /** Fired when a machine cycle finishes. */\n  onDone?: () => void;\n  /** Advance it. `working` gates the scrubbing, not the machine. */\n  update(dt: number, working?: boolean): void;\n}\n\ninterface EraSpec {\n  /** Seconds per item in perfect water. The rate scales this. */\n  scrub: number;\n  /** Items one bowlful will do before it is grey. */\n  perFill: number;\n  /** Water each item uses up. */\n  usePerItem: number;\n  /** Heat lost per second. A stone trough is a radiator. */\n  cool: number;\n  capacity: number;\n  taps: number;\n  /** Does the tap deliver hot? On a scullery it does not — that is a kettle. */\n  plumbedHot: boolean;\n  hasBoard: boolean;\n  machine: boolean;\n  /** Seconds for a machine cycle. */\n  cycleFor: number;\n  width: number;\n  depth: number;\n  height: number;\n  /** How deep the bowl is below the counter. */\n  bowl: number;\n}\n\n/**\n * The era table, and as always every number is a gameplay decision.\n *\n * `perFill` is the interesting column. A stone trough does six things before\n * the water is filthy and a modern sink does fourteen, not because the\n * porcelain is better but because a trough holds less and you were never\n * going to carry more. It is the same shape as the icebox's block of ice:\n * the medieval end of every one of these axes is a **resource you have to\n * keep going and fetch**.\n */\nconst ERAS: Record<SinkEra, EraSpec> = {\n  trough: {\n    scrub: 2.2, perFill: 6, usePerItem: 0.09, cool: 0.055, capacity: 8,\n    taps: 0, plumbedHot: false, hasBoard: false, machine: false, cycleFor: 0,\n    width: 1.0, depth: 0.52, height: 0.82, bowl: 0.2,\n  },\n  scullery: {\n    scrub: 1.8, perFill: 10, usePerItem: 0.06, cool: 0.03, capacity: 12,\n    taps: 1, plumbedHot: false, hasBoard: true, machine: false, cycleFor: 0,\n    width: 0.94, depth: 0.56, height: 0.9, bowl: 0.26,\n  },\n  sink: {\n    scrub: 1.4, perFill: 14, usePerItem: 0.045, cool: 0.02, capacity: 16,\n    taps: 1, plumbedHot: true, hasBoard: true, machine: false, cycleFor: 0,\n    width: 1.26, depth: 0.6, height: 0.9, bowl: 0.18,\n  },\n  dishwasher: {\n    scrub: 0, perFill: 0, usePerItem: 0, cool: 0, capacity: 12,\n    taps: 0, plumbedHot: true, hasBoard: false, machine: true, cycleFor: 45,\n    width: 0.6, depth: 0.6, height: 0.86, bowl: 0,\n  },\n};\n\nexport interface SinkOptions {\n  era?: SinkEra;\n  /** Start with dirty things in it. Default 0. */\n  dirty?: number;\n  /** Start with water in the bowl, 0–1. Default 0. */\n  water?: number;\n  /** How fast a fully open tap fills it, in levels per second. Default 0.3. */\n  rate?: number;\n  seed?: number;\n  palette?: Palette;\n}\n\nconst clamp01 = (t: number): number => (t < 0 ? 0 : t > 1 ? 1 : t);\nconst smooth = (t: number): number => t * t * (3 - 2 * t);\n\n/** The drop-front door of a machine, hinged along its bottom edge. */\nfunction makeFlap(pivot: Group, swing: number, speed = 2.4): SinkDoor {\n  let target = 0;\n  let state = 0;\n  const api: SinkDoor = {\n    object: pivot,\n    get state() {\n      return state;\n    },\n    get open() {\n      return target > 0.5;\n    },\n    toggle() {\n      const next = !(target > 0.5);\n      api.set(next);\n      return next;\n    },\n    set(value: number | boolean) {\n      const was = target > 0.5;\n      target = typeof value === 'boolean' ? (value ? 1 : 0) : clamp01(value);\n      if (was !== target > 0.5) api.onChange?.(target > 0.5);\n    },\n    update(dt: number) {\n      state += (target - state) * Math.min(1, dt * speed);\n      pivot.rotation.x = smooth(state) * swing;\n    },\n  };\n  return api;\n}\n\n/**\n * A sink, trough, scullery bowl or dishwasher.\n *\n * The origin is on the floor at the centre of the front face, facing +z out\n * into the room — the same convention as the stove and the cold store, so a\n * kitchen wall is a row of these with no arithmetic.\n */\nexport function createWashUp(options: SinkOptions = {}): WashUp {\n  const era = options.era ?? 'sink';\n  const spec = ERAS[era];\n  const seed = options.seed ?? 1;\n  const rng = new Rng(seed);\n  const palette = options.palette ?? DEFAULT_PALETTE;\n  const fillRate = options.rate ?? 0.3;\n\n  const group = new Group();\n  group.name = `washup-${era}`;\n\n  const W = spec.width;\n  const D = spec.depth;\n  const H = spec.height;\n\n  const carcass =\n    era === 'trough'\n      ? createSurface('stone', { seed, color: palette.rock[1] })\n      : era === 'scullery'\n        ? createSurface('wood', { seed, color: palette.wood })\n        : createSurface('paint', { seed, color: 0xe4e7ea });\n  const ware =\n    era === 'trough'\n      ? createSurface('stone', { seed: seed + 1, color: palette.rock[0] })\n      : era === 'scullery'\n        ? createSurface('glaze', { seed: seed + 1 })\n        : // NOT stock 'steel'. At metalness 0.92 with no environment map a\n          // stainless worktop renders near-black at any glancing angle — the\n          // same trap the range hit — and the first render of the double sink\n          // was a slab of tarmac with a tap on it.\n          createSurface('steel', { seed: seed + 1, metalness: 0.4, roughness: 0.36 });\n  const metal = createSurface('chrome', { seed: seed + 2 });\n  const timber = createSurface('teak', { seed: seed + 3 });\n\n  const bursts: Burst[] = [];\n  const dirtyStack: Object3D[] = [];\n  const cleanStack: Object3D[] = [];\n  const taps: Tap[] = [];\n  let fill: Fill | null = null;\n  let sudsMat: MeshStandardMaterial | null = null;\n  let suds: Mesh | null = null;\n  let waterMat: MeshStandardMaterial | null = null;\n  let board: PropSurface | null = null;\n  /** Where the washing bowl is, so the suds can sit on it. */\n  let bowlX = 0;\n  let door: SinkDoor | null = null;\n  let rack: Group | null = null;\n  let lampMat: MeshStandardMaterial | null = null;\n\n  const plateGeom = new CylinderGeometry(0.085, 0.07, 0.014, 14);\n  const plateMat = createSurface('glaze', { seed: seed + 4 });\n\n  if (spec.machine) {\n    // ---- the machine ---------------------------------------------------\n    // Five walls around a hole, as ever: a solid box with a door painted on\n    // it has nowhere for the rack to be, and the moment the door drops the\n    // render shows a slab.\n    const T = 0.05;\n    for (const [w, h, d, x, y, z] of [\n      [T, H, D, -W / 2 + T / 2, H / 2, -D / 2],\n      [T, H, D, W / 2 - T / 2, H / 2, -D / 2],\n      [W, H, T, 0, H / 2, -D + T / 2],\n      [W, T, D, 0, H - T / 2, -D / 2],\n      [W, T, D, 0, T / 2, -D / 2],\n    ] as Array<[number, number, number, number, number, number]>) {\n      const m = new Mesh(new BoxGeometry(w, h, d), carcass);\n      m.position.set(x, y, z);\n      group.add(m);\n    }\n    const cavity = new MeshStandardMaterial({\n      color: 0xb9c1c6,\n      roughness: 0.3,\n      metalness: 0.6,\n      side: DoubleSide,\n    });\n    const backLiner = new Mesh(new BoxGeometry(W - T * 2, H - T * 2, 0.004), cavity);\n    backLiner.position.set(0, H / 2, -D + T + 0.005);\n    group.add(backLiner);\n\n    // The rack rides OUT with the door. A machine whose door drops to reveal\n    // an empty black hole is a cupboard with a hinge.\n    const pivot = new Group();\n    pivot.position.set(0, T, 0);\n    group.add(pivot);\n    const leaf = new Mesh(new BoxGeometry(W - 0.01, H - T, 0.04), carcass);\n    leaf.position.set(0, (H - T) / 2, 0.02);\n    pivot.add(leaf);\n    const handle = new Mesh(new CylinderGeometry(0.013, 0.013, W * 0.7, 8), metal);\n    handle.rotation.z = Math.PI / 2;\n    handle.position.set(0, H - T - 0.08, 0.06);\n    pivot.add(handle);\n    // The indicator: the machine's only visible state, and it needs one,\n    // because a cycle you cannot see is a forty-five second nothing.\n    lampMat = new MeshStandardMaterial({\n      color: 0x2a3a30,\n      roughness: 0.4,\n      emissive: 0x33ff88,\n      emissiveIntensity: 0,\n    });\n    const lamp = new Mesh(new BoxGeometry(0.05, 0.014, 0.006), lampMat);\n    lamp.position.set(-W / 2 + 0.12, H - T - 0.16, 0.042);\n    pivot.add(lamp);\n\n    rack = new Group();\n    rack.position.set(0, 0.28, -D / 2);\n    group.add(rack);\n    for (let i = 0; i < 9; i++) {\n      const tine = new Mesh(new CylinderGeometry(0.004, 0.004, 0.3, 5), metal);\n      tine.rotation.x = Math.PI / 2;\n      tine.position.set(-W / 2 + 0.09 + i * ((W - 0.18) / 8), 0.02, 0);\n      rack.add(tine);\n    }\n    for (const z of [-0.14, 0.14]) {\n      const rail = new Mesh(new CylinderGeometry(0.005, 0.005, W - 0.14, 5), metal);\n      rail.rotation.z = Math.PI / 2;\n      rail.position.set(0, 0.04, z);\n      rack.add(rail);\n    }\n    // Plates stand ON EDGE in a rack. Lying flat they read as a stack of\n    // coins and the rack reads as a shelf.\n    for (let i = 0; i < spec.capacity; i++) {\n      const plate = new Mesh(plateGeom, plateMat);\n      plate.rotation.z = Math.PI / 2;\n      plate.position.set(-W / 2 + 0.1 + (i % 9) * ((W - 0.2) / 8), 0.12, i < 9 ? -0.07 : 0.07);\n      plate.visible = false;\n      rack.add(plate);\n      dirtyStack.push(plate);\n    }\n    door = makeFlap(pivot, Math.PI / 2);\n  } else {\n    // ---- a bowl you stand at --------------------------------------------\n    /**\n     * The worktop is a FRAME AROUND A HOLE, not a slab with a bowl parked on\n     * top of it.\n     *\n     * This is the defect the library keeps rediscovering — the pot, the\n     * pool, the oven, the sunken bath, the fridge — and it caught this prop\n     * too. The first version built a solid counter box and then placed the\n     * bowl at its centre, which put the bowl *inside* solid geometry: from\n     * above, four sinks that were four worktops. Everything below the bowl\n     * floor is solid; everything beside it is solid; the aperture itself has\n     * nothing in it at all.\n     */\n    const bowls =\n      era === 'sink'\n        ? [\n            { x: -0.254 * W, w: 0.397 * W },\n            { x: 0.127 * W, w: 0.27 * W },\n          ]\n        : era === 'scullery'\n          ? [{ x: -0.16 * W, w: 0.6 * W }]\n          : [{ x: 0, w: 0.68 * W }];\n    const bd = D * 0.66;\n    const bz = -D / 2;\n    const floorY = H - spec.bowl;\n    const wall = 0.018;\n    const ax0 = Math.min(...bowls.map((b) => b.x - b.w / 2));\n    const ax1 = Math.max(...bowls.map((b) => b.x + b.w / 2));\n    const az0 = bz - bd / 2;\n    const az1 = bz + bd / 2;\n\n    // Solid below the bowls.\n    const plinth = new Mesh(new BoxGeometry(W, floorY, D), carcass);\n    plinth.position.set(0, floorY / 2, -D / 2);\n    group.add(plinth);\n    // …and solid on all four sides of the aperture, full worktop height.\n    const rim = H - floorY;\n    for (const [w, d, cx, cz] of [\n      [ax0 + W / 2, D, (-W / 2 + ax0) / 2, -D / 2],\n      [W / 2 - ax1, D, (ax1 + W / 2) / 2, -D / 2],\n      [ax1 - ax0, az0 + D, (ax0 + ax1) / 2, (-D + az0) / 2],\n      [ax1 - ax0, -az1, (ax0 + ax1) / 2, az1 / 2],\n    ] as Array<[number, number, number, number]>) {\n      if (w <= 0.001 || d <= 0.001) continue;\n      const block = new Mesh(new BoxGeometry(w, rim, d), carcass);\n      block.position.set(cx, floorY + rim / 2, cz);\n      group.add(block);\n    }\n\n    // The bowls themselves: a ware floor, and a ware liner on the inside\n    // faces, because the frame's own faces point outward and are invisible\n    // from where you are standing.\n    const makeBowl = (cx: number, bw: number): void => {\n      const f = new Mesh(new BoxGeometry(bw, 0.01, bd), ware);\n      f.position.set(cx, floorY + 0.006, bz);\n      group.add(f);\n      for (const [w, d, ox, oz] of [\n        [bw, wall, 0, -bd / 2 + wall / 2],\n        [bw, wall, 0, bd / 2 - wall / 2],\n        [wall, bd, -bw / 2 + wall / 2, 0],\n        [wall, bd, bw / 2 - wall / 2, 0],\n      ] as Array<[number, number, number, number]>) {\n        const s = new Mesh(new BoxGeometry(w, rim, d), ware);\n        s.position.set(cx + ox, floorY + rim / 2, bz + oz);\n        group.add(s);\n      }\n    };\n    for (const b of bowls) makeBowl(b.x, b.w);\n    // The divider between a double sink's two bowls — the one piece the\n    // aperture frame cannot supply.\n    if (bowls.length > 1) {\n      const gapMid = (bowls[0].x + bowls[0].w / 2 + (bowls[1].x - bowls[1].w / 2)) / 2;\n      const gapW = bowls[1].x - bowls[1].w / 2 - (bowls[0].x + bowls[0].w / 2);\n      if (gapW > 0.005) {\n        const div = new Mesh(new BoxGeometry(gapW, rim, bd), ware);\n        div.position.set(gapMid, floorY + rim / 2, bz);\n        group.add(div);\n      }\n    }\n    const bw = bowls[0].w;\n    const bx = bowls[0].x;\n    bowlX = bx;\n\n    fill = createFill({\n      width: bw - wall * 2,\n      length: bd - wall * 2,\n      depth: spec.bowl - 0.02,\n      level: 0,\n      color: 0x5f8fa4,\n      seed,\n      palette,\n    });\n    fill.object.position.set(bx, floorY + 0.006, bz);\n    group.add(fill.object);\n    // Reach in for the water's material once, so `soil` can grey it. The\n    // level alone is not a reading of how filthy it is, and grey water is\n    // the only thing on screen that says \"change me\".\n    fill.object.traverse((c) => {\n      if (!waterMat && (c as Mesh).isMesh) waterMat = (c as Mesh).material as MeshStandardMaterial;\n    });\n\n    sudsMat = new MeshStandardMaterial({\n      color: 0xf6f8f7,\n      roughness: 0.95,\n      transparent: true,\n      opacity: 0,\n      flatShading: true,\n    });\n    // Foam clumps rather than one flat lid: a white slab lying on the water\n    // is indistinguishable from the water, which is how the first render of\n    // this came out.\n    suds = new Group() as unknown as Mesh;\n    for (let i = 0; i < 7; i++) {\n      const clump = new Mesh(\n        new BoxGeometry(rng.range(0.05, 0.13), rng.range(0.012, 0.026), rng.range(0.05, 0.12)),\n        sudsMat\n      );\n      clump.position.set(\n        rng.range(-1, 1) * (bw * 0.32),\n        rng.range(0, 0.012),\n        rng.range(-1, 1) * (bd * 0.3)\n      );\n      clump.rotation.y = rng.range(0, 3);\n      suds.add(clump);\n    }\n    suds.visible = false;\n    group.add(suds);\n\n    // Dirty things leaning in the bowl, one per item waiting.\n    for (let i = 0; i < spec.capacity; i++) {\n      const plate = new Mesh(plateGeom, plateMat);\n      plate.rotation.set(rng.range(-0.3, 0.3), rng.range(0, 3), Math.PI / 2 + rng.range(-0.5, 0.5));\n      plate.position.set(\n        bx + rng.range(-bw * 0.3, bw * 0.3),\n        floorY + 0.05 + (i % 3) * 0.02,\n        bz + rng.range(-bd * 0.28, bd * 0.28)\n      );\n      plate.visible = false;\n      group.add(plate);\n      dirtyStack.push(plate);\n    }\n\n    if (spec.hasBoard) {\n      // Beside the aperture, on the solid part of the worktop — which is\n      // exactly where the frame above left room for it.\n      const boardX = (ax1 + W / 2) / 2;\n      const bwid = (W / 2 - ax1) * 0.86;\n      if (era === 'sink') {\n        // A ribbed steel drainer, tilted so it runs back into the bowl.\n        const slab = new Mesh(new BoxGeometry(bwid, 0.012, bd), ware);\n        slab.position.set(boardX, H + 0.006, bz);\n        slab.rotation.z = 0.04;\n        group.add(slab);\n        for (let i = 0; i < 5; i++) {\n          const rib = new Mesh(new BoxGeometry(bwid * 0.88, 0.005, 0.009), ware);\n          rib.position.set(boardX, H + 0.014, bz - bd / 2 + 0.06 + i * (bd / 6));\n          group.add(rib);\n        }\n      } else {\n        // A scullery's board is a teak plank laid on the worktop.\n        const slab = new Mesh(new BoxGeometry(bwid, 0.018, bd * 0.85), timber);\n        slab.position.set(boardX, H + 0.009, bz);\n        group.add(slab);\n      }\n      board = createPropSurface('drainer', group, boardX, H + 0.02, bz, bwid * 0.9, bd * 0.8);\n      // Clean things stack up here — the strongest read in the prop, because\n      // it is the only one that shows the WORK rather than the water.\n      for (let i = 0; i < spec.capacity; i++) {\n        const plate = new Mesh(plateGeom, plateMat);\n        // A STACK, not a scatter. Spread across the board they overlap into\n        // one white smear and the count is unreadable; piled up, the height\n        // of the pile is the count.\n        plate.position.set(\n          boardX + rng.range(-0.006, 0.006),\n          H + 0.03 + i * 0.015,\n          bz + rng.range(-0.006, 0.006)\n        );\n        plate.rotation.y = rng.range(0, 3);\n        plate.visible = false;\n        group.add(plate);\n        cleanStack.push(plate);\n      }\n    }\n\n    for (let i = 0; i < spec.taps; i++) {\n      const tap = createTap({\n        style: era === 'sink' ? 'mixer' : 'crosshead',\n        seed: seed + 10 + i,\n        palette,\n      });\n      tap.object.position.set(bx, H, az0 - 0.05);\n      group.add(tap.object);\n      taps.push(tap);\n    }\n\n    const splash = makeBurst(rng, {\n      origin: new Vector3(bx, floorY + spec.bowl * 0.8, bz),\n      color: 0xbcd8e4,\n      count: 12,\n      size: 0.014,\n      speed: 0.7,\n      up: 1.1,\n      life: 0.45,\n    });\n    group.add(splash.mesh);\n    bursts.push(splash);\n  }\n\n  // Small and low. A bowl of hot water gives off a wisp; the stock size read\n  // as a bank of fog hanging behind every unit in the row.\n  const steam = createSteam({\n    radius: W * 0.16,\n    height: 0.34,\n    count: 8,\n    seed: seed + 6,\n  });\n  steam.object.position.set(0, H + 0.02, -D / 2);\n  group.add(steam.object);\n\n  const standAt = createSlot('wash', 'work', group, 0, 0, 0.56, Math.PI);\n  standAt.loop = spec.machine ? 'stack' : 'scrub';\n  addApproach(standAt, group, 0.55, 'behind');\n\n  // ---- state -------------------------------------------------------------\n  let dirty = Math.min(spec.capacity, Math.max(0, Math.round(options.dirty ?? 0)));\n  let clean = 0;\n  let water = clamp01(options.water ?? 0);\n  let soil = 0;\n  let heat = 0;\n  let phase = 0;\n  let total = 0;\n  let running = false;\n  let cycleAt = 0;\n  const tool = new Object3D();\n  tool.name = 'tool:cloth';\n  tool.position.set(0, H + 0.04, -D / 2 + 0.08);\n  group.add(tool);\n\n  /**\n   * How fast the scrubbing goes, as a multiple of the era's best.\n   *\n   * This function IS the track. Everything else is a container to hang it\n   * on: no water and there is no washing-up, cold grey water is a quarter\n   * the speed of fresh hot, and the way out of that is to stop and refill.\n   */\n  const rateNow = (): number => {\n    if (spec.machine || water <= 0.02) return 0;\n    return (1 - soil * 0.75) * (0.5 + heat * 0.5);\n  };\n\n  const api: WashUp = {\n    object: group,\n    obstacleRadius: Math.max(W, D) * 0.55,\n    era,\n    taps,\n    board,\n    surfaces: board ? [board] : [],\n    door,\n    steam,\n    slot: standAt,\n    slots: [standAt],\n    tool,\n    capacity: spec.capacity,\n    get action() {\n      return spec.machine ? 'stack' : 'scrub';\n    },\n    get progress() {\n      return phase;\n    },\n    get dirty() {\n      return dirty;\n    },\n    get clean() {\n      return clean;\n    },\n    get water() {\n      return water;\n    },\n    get soil() {\n      return soil;\n    },\n    get hot() {\n      return heat;\n    },\n    get running() {\n      return running;\n    },\n    get cycle() {\n      return spec.machine && spec.cycleFor > 0 ? clamp01(cycleAt / spec.cycleFor) : 0;\n    },\n    load(count = 1) {\n      const took = Math.max(0, Math.min(Math.round(count), spec.capacity - dirty - clean));\n      dirty += took;\n      return took;\n    },\n    collect(count = Infinity) {\n      const gave = Math.max(0, Math.min(Math.round(Math.min(count, clean)), clean));\n      clean -= gave;\n      return gave;\n    },\n    fill(amount: number, hotness = 0) {\n      if (amount <= 0) return;\n      const before = water;\n      water = clamp01(water + amount);\n      const added = water - before;\n      if (added <= 0) return;\n      // Mixing, not replacing. Adding half a bowl of clean hot water to a\n      // grey cold one gives you something in between, which is exactly why\n      // topping up is a worse move than emptying and starting again.\n      heat = (heat * before + hotness * added) / water;\n      soil = (soil * before) / water;\n      fill?.fillBy(added);\n    },\n    empty() {\n      water = 0;\n      soil = 0;\n      heat = 0;\n      fill?.setLevel(0);\n    },\n    start() {\n      if (!spec.machine || running || dirty <= 0) return false;\n      // It will not run with the door hanging open, which is the whole\n      // difference between a machine and a bowl.\n      if (door?.open) return false;\n      running = true;\n      cycleAt = 0;\n      return true;\n    },\n    update(dt: number, working = true) {\n      if (dt <= 0) return;\n      door?.update(dt);\n      for (const t of taps) t.update(dt);\n      for (const b of bursts) b.update(dt);\n\n      // Taps run water in. A scullery tap is COLD — hot water is a kettle,\n      // and that is the era, not a detail.\n      let tapping = 0;\n      for (const t of taps) tapping = Math.max(tapping, t.state);\n      if (tapping > 0.02 && water < 1) {\n        api.fill(tapping * fillRate * dt, spec.plumbedHot ? 0.9 : 0.05);\n      }\n\n      if (spec.machine) {\n        if (running) {\n          // Opening the door mid-cycle ABORTS it. They come out dirty,\n          // because half-washed is dirty.\n          if (door?.open) {\n            running = false;\n            cycleAt = 0;\n          } else {\n            cycleAt += dt;\n            if (cycleAt >= spec.cycleFor) {\n              total += dirty;\n              clean += dirty;\n              dirty = 0;\n              running = false;\n              cycleAt = 0;\n              api.onYield?.(total);\n              api.onDone?.();\n            }\n          }\n        }\n        phase = api.cycle;\n      } else {\n        // Hand washing. The rate is the whole point — see `rateNow`.\n        const rate = rateNow();\n        if (working && dirty > 0 && rate > 0) {\n          phase += (dt / spec.scrub) * rate;\n          while (phase >= 1 && dirty > 0) {\n            phase -= 1;\n            dirty -= 1;\n            // Only count it as clean if there is somewhere to put it. On a\n            // trough there is no board, so washed things simply leave.\n            if (board) clean += 1;\n            total += 1;\n            soil = clamp01(soil + 1 / spec.perFill);\n            water = Math.max(0, water - spec.usePerItem);\n            fill?.setLevel(water);\n            fill?.disturb(0.6);\n            for (const b of bursts) b.emit(5);\n            api.onYield?.(total);\n          }\n        } else {\n          phase = 0;\n        }\n        // Water goes cold whether or not anybody is using it.\n        heat = Math.max(0, heat - spec.cool * dt);\n        fill?.setLevel(water);\n        fill?.update(dt);\n      }\n\n      // ---- reads --------------------------------------------------------\n      if (waterMat) {\n        // Grey, and then frankly brown. The level says how much; the colour\n        // is the only thing that says how much longer it is any use.\n        waterMat.color.setRGB(\n          0.37 + soil * 0.22,\n          0.56 - soil * 0.16,\n          0.64 - soil * 0.3\n        );\n      }\n      if (suds && sudsMat) {\n        // Suds are the first thing to go. A bowl still frothing after twelve\n        // plates is a bowl that has not been used.\n        const froth = clamp01(water * 2) * (1 - clamp01(soil * 1.4));\n        suds.visible = froth > 0.02;\n        sudsMat.opacity = froth * 0.85;\n        suds.position.y = H - spec.bowl + 0.01 + water * (spec.bowl - 0.03);\n        suds.position.x = bowlX;\n        suds.position.z = -D / 2;\n      }\n      // In a machine, washed dishes do not leave the rack — they are still in\n      // there until somebody unloads them. Showing only `dirty` emptied the\n      // rack the instant the cycle finished, so the payoff for waiting\n      // forty-five seconds was the dishes disappearing.\n      const inBowl = spec.machine ? dirty + clean : dirty;\n      for (let i = 0; i < dirtyStack.length; i++) dirtyStack[i].visible = i < inBowl;\n      for (let i = 0; i < cleanStack.length; i++) cleanStack[i].visible = i < clean;\n      if (rack && door) {\n        // Out with the door, and only while it is genuinely open.\n        rack.position.z = -D / 2 + smooth(door.state) * (D * 0.75);\n      }\n      if (lampMat) lampMat.emissiveIntensity = running ? 0.9 : 0;\n      steam.setTarget(spec.machine ? (running && cycleAt > 2 ? 0.3 : 0) : water * heat * 0.45);\n      steam.update(dt);\n    },\n  };\n  return api;\n}\n\n/** A stone trough: no tap, no plug, and the water arrives in a bucket. */\nexport function createTrough(options: Omit<SinkOptions, 'era'> = {}): WashUp {\n  return createWashUp({ ...options, era: 'trough' });\n}\n\n/**\n * A kitchen sink — `scullery` for the butler sink, `sink` for the double bowl.\n *\n * Named in full because `createSink` is already taken by the bathroom\n * washstand in `stations.ts`, and the two really are different props: that\n * one is somewhere to wash your hands, this one is somewhere to work.\n */\nexport function createKitchenSink(\n  options: Omit<SinkOptions, 'era'> & { era?: 'scullery' | 'sink' } = {}\n): WashUp {\n  return createWashUp({ ...options, era: options.era ?? 'sink' });\n}\n\n/** The machine that takes the loop away. */\nexport function createDishwasher(options: Omit<SinkOptions, 'era'> = {}): WashUp {\n  return createWashUp({ ...options, era: 'dishwasher' });\n}\n\nexport const SINK_ERAS: SinkEra[] = ['trough', 'scullery', 'sink', 'dishwasher'];\n","import {\n  BoxGeometry,\n  CylinderGeometry,\n  DoubleSide,\n  Group,\n  Mesh,\n  MeshStandardMaterial,\n  Object3D,\n  PointLight,\n  Vector3,\n} from 'three';\nimport { Rng } from '../core/random';\nimport { DEFAULT_PALETTE, type Palette } from '../core/palette';\nimport { createSurface } from '../materials/surface';\nimport {\n  addApproach,\n  createPropSurface,\n  createSlot,\n  type Prop,\n  type PropSlot,\n  type PropSurface,\n} from '../core/types';\n\n/**\n * Cold storage: the larder-to-freezer axis.\n *\n * The mirror of the heat track, and the differences are the interesting\n * part. Heat is a **surface** you put a pot on top of; cold is a **volume**\n * you put food inside, and the whole of it leaks the moment you open the\n * door. So the handshake gains a y:\n *\n * ```ts\n * chillAt(x, y, z): number   // °C at a world point, ambient outside\n * ```\n *\n * alongside `heatAt(x, z)` and `depthAt(x, z)`. It reports **°C**, not a\n * 0–1 dial, because unlike a fire's output there is a real scale here and\n * the entire game is played against thresholds on it: four degrees keeps\n * milk, minus eighteen keeps it for a year, and the line between them is a\n * phase change rather than \"a bit colder\".\n *\n * The era is not a finish. It is *what you have to do to keep the cold in*:\n *\n * - a **larder** has no mechanism at all and simply sits a few degrees under\n *   the room, so on a hot day it does nothing and that is the point;\n * - an **icebox** spends a block of ice, faster the more heat it absorbs —\n *   the fuel loop from the hearth, running backwards;\n * - a **fridge** holds a setpoint, cycling a compressor you cannot see;\n * - a **freezer** holds one far below zero and slowly ices itself up until\n *   somebody defrosts it.\n *\n * ```ts\n * const fridge = createColdStore({ era: 'fridge' });\n * fridge.door.toggle();                       // it leaks while it is open\n * game.onUpdate((t) => fridge.update(t.delta));\n * fridge.keepAt(milk.x, milk.y, milk.z);      // how fast the milk is going off\n * ```\n */\n\nexport type ColdEra =\n  /** A cool stone cupboard with a marble slab and a mesh door. No mechanism. */\n  | 'larder'\n  /** An oak cabinet chilled by a block of ice that melts and must be replaced. */\n  | 'icebox'\n  /** A domestic refrigerator: a setpoint, a cycling compressor, a door light. */\n  | 'fridge'\n  /** A freezer, well below zero, that frosts up until it is defrosted. */\n  | 'freezer';\n\n/** The same four-state shape as the stove and the shower, running the other way. */\nexport type ColdState = 'warm' | 'chilling' | 'cold' | 'warming';\n\n/**\n * How cold it is somewhere, in **world** coordinates.\n *\n * The preserving mirror of `HeatField`. Note that the neutral value is\n * **ambient**, not zero: `depthAt` and `heatAt` can return 0 for \"nothing\n * here\" because no water and no fire are genuinely nothing, but there is no\n * such thing as a place with no temperature. Outside the cabinet you get\n * the room.\n */\nexport interface ChillField {\n  /** Temperature at a world point in °C. The ambient room anywhere outside. */\n  chillAt(x: number, y: number, z: number): number;\n  /**\n   * How fast food spoils at a world point, **relative to the open bench**.\n   *\n   * 1 is sitting out at 20 °C; a fridge is about 0.3; a freezer is under\n   * 0.01. Multiply a perishable's clock by it and the whole track becomes\n   * one line of gameplay code.\n   */\n  keepAt(x: number, y: number, z: number): number;\n}\n\n/** The door — structurally a `Manipulable`, like every other hinged thing. */\nexport interface ColdDoor {\n  readonly state: number;\n  readonly open: boolean;\n  toggle(): boolean;\n  set(target: number | boolean): void;\n  update(dt: number): void;\n  onChange?: (open: boolean) => void;\n  object: Object3D;\n}\n\nexport interface ColdStore extends Prop, ChillField {\n  era: ColdEra;\n  readonly state: ColdState;\n  /** Interior air temperature, °C. */\n  readonly temperature: number;\n  /** What it is trying to hold, °C. On a larder this floats with the room. */\n  readonly setpoint: number;\n  /** The room outside, °C. Writable: hand it your season or your weather. */\n  ambient: number;\n  door: ColdDoor;\n  /** How long the door has been open, in seconds. 0 while it is shut. */\n  readonly ajar: number;\n  /**\n   * Is the mechanism drawing power right now?\n   *\n   * A fridge does not run continuously — it cycles. This is the one reading\n   * with no visual to go with it, deliberately: you *hear* a fridge. Wire it\n   * to a hum and a power meter.\n   */\n  readonly running: boolean;\n  /** Ice left, 0–1. Always 1 on the eras that are wired or need none. */\n  readonly ice: number;\n  /** Put a fresh block in. A no-op on anything but an icebox. */\n  restock(amount?: number): void;\n  /** Frost on the coils, 0–1. It chokes the cooling as it builds. */\n  readonly frost: number;\n  /** Scrape it out. */\n  defrost(): void;\n  /** Interior shelves, also published as `surfaces` so `dress` can fill them. */\n  shelves: PropSurface[];\n  /** The bulb, on the eras that have one. Comes on with the door. */\n  light: PointLight | null;\n  /** Where somebody stands to open it. */\n  slot: PropSlot;\n  onState?: (state: ColdState) => void;\n  /** The door has been open too long. Fires once per opening. */\n  onAlarm?: () => void;\n  update(dt: number): void;\n}\n\ninterface EraSpec {\n  /** Target °C. On a larder this is read as \"degrees under the room\" instead. */\n  setpoint: number;\n  /** Passive: no mechanism, just sits this far below ambient. */\n  passive: boolean;\n  /** Heat leaking in through shut walls, as a fraction of the gap per second. */\n  leak: number;\n  /** …and with the door hanging open. */\n  openLeak: number;\n  /** °C per second the mechanism can pull, at full capacity. */\n  pull: number;\n  /** Does it spend ice? */\n  usesIce: boolean;\n  /** Kelvin-seconds of absorbed heat in a full block. */\n  iceCapacity: number;\n  /** Ice melts even doing nothing — it is cold and the world is not. K/s. */\n  iceStanding: number;\n  /** Frost per second while running. 0 where it is auto-defrosting or has no coil. */\n  frostRate: number;\n  /** Seconds the door may hang open before the alarm. 0 = it has no alarm. */\n  alarmAfter: number;\n  hasLight: boolean;\n  shelves: number;\n  width: number;\n  depth: number;\n  height: number;\n}\n\n/**\n * The era table. Every number here is a gameplay decision, not a datasheet.\n *\n * The `leak` column is the one that matters. A larder loses its whole gap to\n * the room in about twenty seconds, so it is never really cold; a freezer\n * holds for minutes. But `openLeak` is within a factor of three across all\n * four, because an open door is an open door — a £900 fridge standing open\n * is barely better than a stone cupboard, and that is the lesson the track\n * is built to teach.\n */\nconst ERAS: Record<ColdEra, EraSpec> = {\n  larder: {\n    setpoint: 6, passive: true, leak: 0.012, openLeak: 0.5, pull: 0,\n    usesIce: false, iceCapacity: 0, iceStanding: 0, frostRate: 0, alarmAfter: 0, hasLight: false,\n    shelves: 3, width: 0.92, depth: 0.46, height: 1.62,\n  },\n  icebox: {\n    setpoint: 7, passive: false, leak: 0.014, openLeak: 0.34, pull: 0.55,\n    usesIce: true, iceCapacity: 160, iceStanding: 0.06, frostRate: 0, alarmAfter: 0, hasLight: false,\n    shelves: 2, width: 0.7, depth: 0.54, height: 1.16,\n  },\n  fridge: {\n    setpoint: 4, passive: false, leak: 0.006, openLeak: 0.22, pull: 1.4,\n    usesIce: false, iceCapacity: 0, iceStanding: 0, frostRate: 0.00025, alarmAfter: 25, hasLight: true,\n    shelves: 4, width: 0.62, depth: 0.62, height: 1.76,\n  },\n  freezer: {\n    setpoint: -18, passive: false, leak: 0.004, openLeak: 0.18, pull: 1.1,\n    usesIce: false, iceCapacity: 0, iceStanding: 0, frostRate: 0.006, alarmAfter: 20, hasLight: true,\n    shelves: 3, width: 0.62, depth: 0.62, height: 1.58,\n  },\n};\n\n/**\n * The thermostat's dead band, in °C.\n *\n * It has to be a band on **both** sides of the setpoint. Switching off at\n * exactly the setpoint looks right and does not work: the leak adds a hair\n * every frame, so the interior never quite reaches the line and the\n * compressor runs forever. A real one overshoots below and coasts back up,\n * which is why you hear a fridge start and stop rather than hum steadily.\n */\nconst BAND_ON = 1.2;\nconst BAND_OFF = 0.5;\n\nexport interface ColdOptions {\n  era?: ColdEra;\n  /** The room, °C. Default 20. */\n  ambient?: number;\n  /** Start already down at temperature. Default true — a fridge in a kitchen is cold. */\n  cold?: boolean;\n  /** Start with a full block of ice. Default true. */\n  iced?: boolean;\n  /** Shelf count override. */\n  shelves?: number;\n  seed?: number;\n  palette?: Palette;\n}\n\nconst clamp01 = (t: number): number => (t < 0 ? 0 : t > 1 ? 1 : t);\nconst smooth = (t: number): number => t * t * (3 - 2 * t);\n\n/**\n * Spoilage rate at `t` °C, relative to a bench at 20 °C.\n *\n * Q10: bacteria and the chemistry roughly halve for every ten degrees you\n * take off. That alone would make a freezer only twelve times better than a\n * worktop, which is nonsense — so freezing is modelled as what it actually\n * is, a **phase change** rather than more of the same. Once the water in the\n * food is solid nothing moves through it and the rate falls off a cliff.\n */\nexport function spoilRate(t: number): number {\n  const q10 = Math.pow(2, (t - 20) / 10);\n  // Smoothly over the two degrees below zero, so a fridge hovering at 0.5\n  // does not flicker between two regimes.\n  const frozen = smooth(clamp01(-t / 2));\n  return q10 * (1 - frozen * 0.92);\n}\n\n/** A hinged door on a pivot at one edge, shaped exactly like `Manipulable`. */\nfunction makeDoor(pivot: Group, swing: number, speed = 2.6): ColdDoor {\n  let target = 0;\n  let state = 0;\n  const api: ColdDoor = {\n    object: pivot,\n    get state() {\n      return state;\n    },\n    get open() {\n      return target > 0.5;\n    },\n    toggle() {\n      const next = !(target > 0.5);\n      api.set(next);\n      return next;\n    },\n    set(value: number | boolean) {\n      const was = target > 0.5;\n      target = typeof value === 'boolean' ? (value ? 1 : 0) : clamp01(value);\n      if (was !== target > 0.5) api.onChange?.(target > 0.5);\n    },\n    update(dt: number) {\n      state += (target - state) * Math.min(1, dt * speed);\n      pivot.rotation.y = -smooth(state) * swing;\n    },\n  };\n  return api;\n}\n\n/**\n * A larder, icebox, fridge or freezer.\n *\n * The origin is on the floor at the centre of the front face, facing +z out\n * into the room — the same convention as the stove, so the two stand side by\n * side without anybody doing arithmetic.\n */\nexport function createColdStore(options: ColdOptions = {}): ColdStore {\n  const era = options.era ?? 'fridge';\n  const spec = ERAS[era];\n  const seed = options.seed ?? 1;\n  const rng = new Rng(seed);\n  const palette = options.palette ?? DEFAULT_PALETTE;\n  const shelfCount = options.shelves ?? spec.shelves;\n\n  const group = new Group();\n  group.name = `cold-${era}`;\n\n  const W = spec.width;\n  const D = spec.depth;\n  const H = spec.height;\n  /** Carcass thickness. The interior is this much smaller on every side. */\n  const T = era === 'larder' ? 0.06 : 0.05;\n  const base = era === 'larder' ? 0 : 0.08;\n\n  const shell =\n    era === 'larder'\n      ? createSurface('stone', { seed, color: palette.rock[0] })\n      : era === 'icebox'\n        ? createSurface('wood', { seed, color: palette.woodDark })\n        : createSurface('paint', { seed, color: era === 'freezer' ? 0xdfe3e6 : 0xeceff1 });\n  const liner = new MeshStandardMaterial({\n    // The icebox's zinc lining is DARK, and that is not period colour-matching\n    // — a pale-grey block of ice against a pale-grey liner is nothing at all,\n    // the same way white frost on a white freezer wall is nothing. The read\n    // has to have something to be read against.\n    color: era === 'larder' ? 0xb8b2a6 : era === 'icebox' ? 0x7c848b : 0xe8eef2,\n    roughness: era === 'larder' ? 0.85 : 0.35,\n    metalness: era === 'larder' ? 0 : 0.15,\n  });\n  const trim = createSurface(era === 'icebox' ? 'brass' : 'chrome', { seed: seed + 1 });\n  const wire = new MeshStandardMaterial({ color: 0xcdd3d8, roughness: 0.4, metalness: 0.7 });\n\n  /**\n   * The carcass is FIVE WALLS AROUND A HOLE, not a box.\n   *\n   * This is the same defect that has bitten every container in the library —\n   * the pot, the pool, the oven, the bath. A cabinet modelled as a solid box\n   * with a door on it has nowhere to put anything, and the moment the door\n   * swings the render shows a painted slab where the food should be.\n   */\n  const panel = (\n    w: number,\n    h: number,\n    d: number,\n    x: number,\n    y: number,\n    z: number,\n    material: MeshStandardMaterial\n  ): Mesh => {\n    const m = new Mesh(new BoxGeometry(w, h, d), material);\n    m.position.set(x, y, z);\n    group.add(m);\n    return m;\n  };\n\n  // Outer skin: two sides, a back, a top and a floor, leaving the front open.\n  panel(T, H, D, -W / 2 + T / 2, H / 2, -D / 2, shell);\n  panel(T, H, D, W / 2 - T / 2, H / 2, -D / 2, shell);\n  panel(W, H, T, 0, H / 2, -D + T / 2, shell);\n  panel(W, T, D, 0, H - T / 2, -D / 2, shell);\n  panel(W, T, D, 0, base + T / 2, -D / 2, shell);\n  if (base > 0) panel(W * 0.92, base, D * 0.9, 0, base / 2, -D / 2, trim);\n\n  // Interior liner, inset — what you actually see when the door opens. Its\n  // own surfaces face inward, so it is drawn DoubleSide rather than trusting\n  // a box's outward normals to be visible from inside.\n  const inner = { w: W - T * 2, h: H - base - T * 2, d: D - T * 1.5 };\n  const innerY = base + T + inner.h / 2;\n  const linerFaces = new MeshStandardMaterial().copy(liner);\n  linerFaces.side = DoubleSide;\n  const backPanel = new Mesh(new BoxGeometry(inner.w, inner.h, 0.004), linerFaces);\n  backPanel.position.set(0, innerY, -D + T + 0.004);\n  group.add(backPanel);\n  for (const s of [-1, 1]) {\n    const side = new Mesh(new BoxGeometry(0.004, inner.h, inner.d), linerFaces);\n    side.position.set((s * inner.w) / 2, innerY, -D / 2);\n    group.add(side);\n  }\n\n  // ---- shelves ---------------------------------------------------------\n  const shelves: PropSurface[] = [];\n  const shelfMat =\n    era === 'larder'\n      ? createSurface('marble', { seed: seed + 2 })\n      : era === 'icebox'\n        ? createSurface('wood', { seed: seed + 2, color: 0x8a6a44 })\n        : wire;\n  // The top of an icebox is the ice rack, so its shelves start lower.\n  // An icebox loses its whole top third to the ice compartment, so its\n  // shelves have to clear the rack — publishing a shelf with 16 cm of\n  // headroom under a solid board is publishing a surface nothing fits on.\n  const topRoom = era === 'icebox' ? 0.44 : 0.1;\n  const shelfFrom = base + T + 0.17;\n  const shelfSpan = Math.max(0.1, inner.h - topRoom - 0.32);\n  const shelfYs: number[] = [];\n  for (let i = 0; i < shelfCount; i++) {\n    // SPAN the cavity rather than marching up from the bottom. Dividing by\n    // the count instead of the gaps left a third of every cabinet empty above\n    // the top shelf, and squeezed the lower ones close enough together that a\n    // bottle stood on one went straight through the next.\n    const y = shelfFrom + shelfSpan * (shelfCount === 1 ? 0.5 : i / (shelfCount - 1));\n    shelfYs.push(y);\n    if (era === 'fridge' || era === 'freezer') {\n      // A wire grille, because a solid white slab in a white box reads as\n      // nothing at all — there is no shadow to separate them.\n      for (let b = 0; b < 7; b++) {\n        const bar = new Mesh(new CylinderGeometry(0.004, 0.004, inner.d * 0.94, 5), shelfMat);\n        bar.rotation.x = Math.PI / 2;\n        bar.position.set(-inner.w / 2 + 0.03 + (b * (inner.w - 0.06)) / 6, y, -D / 2);\n        group.add(bar);\n      }\n      for (const e of [-1, 1]) {\n        const rail = new Mesh(new CylinderGeometry(0.005, 0.005, inner.w * 0.98, 5), shelfMat);\n        rail.rotation.z = Math.PI / 2;\n        rail.position.set(0, y, -D / 2 + (e * inner.d) / 2.4);\n        group.add(rail);\n      }\n    } else {\n      const slab = new Mesh(new BoxGeometry(inner.w * 0.98, 0.026, inner.d * 0.92), shelfMat);\n      slab.position.set(0, y, -D / 2);\n      group.add(slab);\n    }\n    shelves.push(createPropSurface(`shelf${i}`, group, 0, y + 0.015, -D / 2, inner.w * 0.9, inner.d * 0.85));\n  }\n\n  // ---- the ice block ---------------------------------------------------\n  let iceMesh: Mesh | null = null;\n  if (spec.usesIce) {\n    const rack = new Mesh(new BoxGeometry(inner.w * 0.9, 0.012, inner.d * 0.8), trim);\n    rack.position.set(0, base + T + inner.h - 0.3, -D / 2);\n    group.add(rack);\n    // Translucent, and it SHRINKS — the reading is its size, which is the\n    // only honest way to show a resource that is literally consumed. Cut with\n    // segments so flat shading gives it faceted edges: a smooth pale box has\n    // no silhouette against a liner, and the first render of this was a blank\n    // rectangle nobody could tell was there.\n    iceMesh = new Mesh(\n      new BoxGeometry(inner.w * 0.7, 0.2, inner.d * 0.62, 2, 2, 2),\n      new MeshStandardMaterial({\n        color: 0x9fd2e8,\n        roughness: 0.18,\n        metalness: 0.05,\n        transparent: true,\n        opacity: 0.85,\n        flatShading: true,\n      })\n    );\n    iceMesh.position.set(0, base + T + inner.h - 0.18, -D / 2);\n    group.add(iceMesh);\n  }\n\n  // ---- frost -----------------------------------------------------------\n  /**\n   * Rime that grows on the interior. Scaled from nothing, so 0 really is 0.\n   *\n   * The first version was white cards on a white liner, which is to say it\n   * was nothing — `frost` read 1.0 in the debug dump and the render showed a\n   * clean freezer. Two things fix it: a **blue** white rather than a paper\n   * one, and putting most of it on the SHELVES, where pale chunks sit against\n   * dark wire instead of disappearing into the walls.\n   */\n  const frostBits: Mesh[] = [];\n  if (spec.frostRate > 0) {\n    const rime = new MeshStandardMaterial({\n      color: 0xbcdcef,\n      roughness: 1,\n      metalness: 0,\n      flatShading: true,\n    });\n    const addBit = (w: number, h: number, d: number, x: number, y: number, z: number, ry = 0): void => {\n      const bit = new Mesh(new BoxGeometry(w, h, d), rime);\n      bit.position.set(x, y, z);\n      // Jittered, because a wall of identically-square slabs reads as blue\n      // tiling rather than as something that grew there.\n      bit.rotation.set(rng.range(-0.25, 0.25), ry + rng.range(-0.4, 0.4), rng.range(-0.3, 0.3));\n      bit.scale.setScalar(0.001);\n      group.add(bit);\n      frostBits.push(bit);\n    };\n    for (const y of shelfYs) {\n      // Along the shelf: the high-contrast place, and where you would\n      // actually find it.\n      for (let i = 0; i < 4; i++) {\n        addBit(\n          rng.range(0.05, 0.11), rng.range(0.025, 0.06), rng.range(0.05, 0.12),\n          rng.range(-inner.w / 2, inner.w / 2) * 0.8,\n          y + 0.02,\n          -D / 2 + rng.range(-0.16, 0.16)\n        );\n      }\n    }\n    for (let i = 0; i < 10; i++) {\n      const wall = rng.next() < 0.5 ? 0 : rng.next() < 0.5 ? -1 : 1;\n      const y = base + T + rng.range(0.1, inner.h - 0.1);\n      if (wall === 0) {\n        addBit(rng.range(0.06, 0.16), rng.range(0.04, 0.12), rng.range(0.03, 0.06),\n          rng.range(-inner.w / 2, inner.w / 2) * 0.85, y, -D + T + 0.025);\n      } else {\n        addBit(rng.range(0.06, 0.14), rng.range(0.04, 0.12), rng.range(0.03, 0.06),\n          (wall * inner.w) / 2 - wall * 0.02, y, -D / 2 + rng.range(-0.2, 0.2), Math.PI / 2);\n      }\n    }\n  }\n\n  // ---- the door --------------------------------------------------------\n  /** Hinged at one edge — the pivot IS the hinge, and the leaf hangs off it. */\n  const hingeSide = rng.next() < 0.5 ? -1 : 1;\n  const pivot = new Group();\n  pivot.position.set((hingeSide * W) / 2, 0, 0);\n  group.add(pivot);\n  const leafW = W - 0.01;\n  const leafH = H - base;\n  const leaf = new Group();\n  leaf.position.set((-hingeSide * leafW) / 2, base + leafH / 2, 0.012);\n  pivot.add(leaf);\n\n  if (era === 'larder') {\n    // A meat safe: a frame with a punched-tin lattice, so the larder is\n    // ventilated — which is exactly why it can never get properly cold.\n    const stile = 0.06;\n    for (const [w, h, x, y] of [\n      [stile, leafH, -leafW / 2 + stile / 2, 0],\n      [stile, leafH, leafW / 2 - stile / 2, 0],\n      [leafW, stile, 0, leafH / 2 - stile / 2],\n      [leafW, stile, 0, -leafH / 2 + stile / 2],\n    ] as Array<[number, number, number, number]>) {\n      const bar = new Mesh(new BoxGeometry(w, h, 0.03), shell);\n      bar.position.set(x, y, 0);\n      leaf.add(bar);\n    }\n    const mesh = new MeshStandardMaterial({ color: 0x4a4438, roughness: 0.7, metalness: 0.4 });\n    for (let i = 0; i < 9; i++) {\n      const bar = new Mesh(new BoxGeometry(0.006, leafH - stile * 2, 0.006), mesh);\n      bar.position.set(-leafW / 2 + stile + ((leafW - stile * 2) * (i + 0.5)) / 9, 0, 0);\n      leaf.add(bar);\n    }\n  } else {\n    const slab = new Mesh(new BoxGeometry(leafW, leafH, 0.045), shell);\n    leaf.add(slab);\n    if (era === 'icebox') {\n      // A raised panel and brass hardware: the cabinetmaker's icebox.\n      const inset = new Mesh(\n        new BoxGeometry(leafW * 0.76, leafH * 0.84, 0.012),\n        createSurface('wood', { seed: seed + 5, color: 0x4e3720 })\n      );\n      inset.position.z = 0.028;\n      leaf.add(inset);\n      const latch = new Mesh(new CylinderGeometry(0.012, 0.012, 0.09, 8), trim);\n      latch.position.set((-hingeSide * leafW) / 2 + hingeSide * 0.07, 0, 0.048);\n      leaf.add(latch);\n      for (const y of [leafH / 2 - 0.12, -leafH / 2 + 0.12]) {\n        const hinge = new Mesh(new BoxGeometry(0.05, 0.05, 0.01), trim);\n        hinge.position.set((hingeSide * leafW) / 2 - hingeSide * 0.03, y, 0.03);\n        leaf.add(hinge);\n      }\n    } else {\n      // A full-height bar handle, on the swinging edge.\n      const handle = new Mesh(new CylinderGeometry(0.014, 0.014, leafH * 0.55, 8), trim);\n      handle.position.set((-hingeSide * leafW) / 2 + hingeSide * 0.06, 0, 0.07);\n      leaf.add(handle);\n      for (const y of [1, -1]) {\n        const stand = new Mesh(new BoxGeometry(0.02, 0.02, 0.05), trim);\n        stand.position.set((-hingeSide * leafW) / 2 + hingeSide * 0.06, (y * leafH * 0.55) / 2, 0.045);\n        leaf.add(stand);\n      }\n      const gasket = new Mesh(new BoxGeometry(leafW * 0.94, leafH * 0.95, 0.008), liner);\n      gasket.position.z = -0.026;\n      leaf.add(gasket);\n    }\n  }\n  // The door opens away from its hinge; the sign of the swing follows the side.\n  const door = makeDoor(pivot, hingeSide * -1.9);\n\n  // ---- the light -------------------------------------------------------\n  let light: PointLight | null = null;\n  let lens: Mesh | null = null;\n  if (spec.hasLight) {\n    // Short range on purpose: an interior bulb that lights the whole room is\n    // a fridge with the wall knocked out.\n    light = new PointLight(0xfff2d8, 0, 1.1, 2);\n    light.position.set(0, base + T + inner.h - 0.08, -D / 2 + 0.06);\n    group.add(light);\n    lens = new Mesh(\n      new BoxGeometry(0.09, 0.03, 0.05),\n      new MeshStandardMaterial({ color: 0xfff4e0, emissive: 0xffe9c0, emissiveIntensity: 0 })\n    );\n    lens.position.copy(light.position);\n    group.add(lens);\n  }\n\n  const openAt = createSlot('open', 'work', group, 0, 0, D * 0 + 0.62, Math.PI);\n  addApproach(openAt, group, 0.55, 'behind');\n\n  // ---- state -----------------------------------------------------------\n  let ambient = options.ambient ?? 20;\n  const floorFor = (): number => (spec.passive ? ambient - spec.setpoint : spec.setpoint);\n  let interior = options.cold === false ? ambient : floorFor();\n  let ice = spec.usesIce ? (options.iced === false ? 0 : 1) : 1;\n  let frost = 0;\n  let running = false;\n  let ajar = 0;\n  let alarmed = false;\n  /** Shared by the constructor and the loop, so a store never lies before its first step. */\n  const classify = (): ColdState => {\n    const floor = floorFor();\n    // A store that CANNOT cool is not chilling, whatever its thermometer\n    // reads on the way past. An icebox with an empty rack reported\n    // 'chilling' at 19 °C and climbing — the same lie the hearth would tell\n    // if a fire with no fuel in it still counted as heating.\n    const losing = door.open || (spec.usesIce && ice <= 0);\n    if (interior > ambient - 1.5) return 'warm';\n    if (interior > floor + 2.5) return losing ? 'warming' : 'chilling';\n    return losing ? 'warming' : 'cold';\n  };\n  let state: ColdState = classify();\n\n  const local = new Vector3();\n  /** Half-extents of the usable cavity, in the cabinet's own space. */\n  const cavity = {\n    minX: -inner.w / 2,\n    maxX: inner.w / 2,\n    minY: base + T,\n    maxY: base + T + inner.h,\n    minZ: -D + T,\n    maxZ: 0,\n  };\n  const insideLocal = (): boolean =>\n    local.x >= cavity.minX &&\n    local.x <= cavity.maxX &&\n    local.y >= cavity.minY &&\n    local.y <= cavity.maxY &&\n    local.z >= cavity.minZ &&\n    local.z <= cavity.maxZ;\n\n  const api: ColdStore = {\n    object: group,\n    obstacleRadius: Math.max(W, D) * 0.55,\n    era,\n    door,\n    shelves,\n    surfaces: shelves,\n    light,\n    slot: openAt,\n    slots: [openAt],\n    get ambient() {\n      return ambient;\n    },\n    set ambient(v: number) {\n      ambient = v;\n    },\n    get temperature() {\n      return interior;\n    },\n    get setpoint() {\n      return floorFor();\n    },\n    get state() {\n      return state;\n    },\n    get running() {\n      return running;\n    },\n    get ajar() {\n      return ajar;\n    },\n    get ice() {\n      return spec.usesIce ? ice : 1;\n    },\n    get frost() {\n      return frost;\n    },\n    restock(amount = 1) {\n      // A no-op where there is nothing to restock, and that IS the era axis:\n      // the same call keeps an icebox cold and does nothing to a fridge.\n      if (!spec.usesIce) return;\n      ice = clamp01(ice + amount);\n    },\n    defrost() {\n      frost = 0;\n    },\n    chillAt(x: number, y: number, z: number) {\n      group.updateWorldMatrix(true, false);\n      local.set(x, y, z);\n      group.worldToLocal(local);\n      return insideLocal() ? interior : ambient;\n    },\n    keepAt(x: number, y: number, z: number) {\n      return spoilRate(api.chillAt(x, y, z));\n    },\n    update(dt: number) {\n      if (dt <= 0) return;\n      const was = state;\n      door.update(dt);\n\n      // The door. Its own timer, and an alarm that fires once per opening\n      // rather than every frame it is still hanging there.\n      if (door.open) {\n        ajar += dt;\n        if (spec.alarmAfter > 0 && !alarmed && ajar > spec.alarmAfter) {\n          alarmed = true;\n          api.onAlarm?.();\n        }\n      } else {\n        ajar = 0;\n        alarmed = false;\n      }\n      // The leaf's easing, not the target: a door halfway through swinging\n      // shut is still most of the way open.\n      const gape = door.open ? Math.max(door.state, 0.25) : door.state;\n      const leakRate = spec.leak + (spec.openLeak - spec.leak) * gape;\n\n      // What the interior is leaking *toward*. Normally the room — but a\n      // larder has no mechanism at all, so its whole cooling story lives\n      // here: thick stone in the shade settles a few degrees under the\n      // room, and swinging the mesh door open puts the room right there.\n      // Modelling that as a second settling term on top of the leak was the\n      // first bug in this file: the two fought and met in the middle, so a\n      // larder in an 8 °C pantry sat at 5 instead of 2.\n      const outside = spec.passive ? ambient - spec.setpoint * (1 - gape) : ambient;\n      const gained = (outside - interior) * Math.min(1, leakRate * dt);\n\n      // Heat out, from whatever mechanism there is.\n      let pulled = 0;\n      if (!spec.passive) {\n        const target = spec.setpoint;\n        let capacity = 0;\n        if (spec.usesIce) {\n          // Ice does not cycle. It works whenever there is any left.\n          capacity = ice > 0 ? 1 : 0;\n        } else {\n          if (running && interior <= target - BAND_OFF) running = false;\n          else if (!running && interior > target + BAND_ON) running = true;\n          capacity = running ? 1 : 0;\n        }\n        // Frost is an insulator on the coil. It does not stop the cooling,\n        // it makes it *slower* — so a neglected freezer still gets down to\n        // temperature, it just never stops running to stay there. That is\n        // exactly why nobody notices until the bill arrives.\n        capacity *= 1 - frost * 0.8;\n        pulled = spec.pull * capacity * dt;\n        // A block of ice cannot make anything colder than the block of ice,\n        // so that one clamps where a compressor is free to overshoot.\n        if (spec.usesIce) pulled = Math.max(0, Math.min(interior - target, pulled));\n        if (spec.usesIce && ice > 0) {\n          // Charge the block for what it ACTUALLY absorbed, and nothing\n          // else. Charging it for the leak as well double-counted — heat\n          // entering the box only melts ice insofar as the ice takes it out\n          // again — and produced the backwards result that an icebox stood\n          // wide open melted *slower* than a shut one, because once it had\n          // warmed to room temperature nothing was leaking in any more.\n          ice = Math.max(0, ice - (pulled + spec.iceStanding * dt) / spec.iceCapacity);\n        }\n      }\n      interior += gained - pulled;\n\n      // Frost. It grows while the coil is working, and much faster with the\n      // door open, because what freezes onto it is the room's damp air.\n      if (spec.frostRate > 0) {\n        frost = clamp01(frost + dt * spec.frostRate * ((running ? 1 : 0.15) + gape * 4));\n      }\n\n      // ---- reads --------------------------------------------------------\n      if (iceMesh) {\n        const s = Math.max(0.001, ice);\n        iceMesh.scale.set(0.35 + s * 0.65, s, 0.4 + s * 0.6);\n        iceMesh.visible = ice > 0.002;\n      }\n      for (let i = 0; i < frostBits.length; i++) {\n        // Staggered, so frost creeps rather than appearing all at once.\n        const t = clamp01((frost - (i / frostBits.length) * 0.55) / 0.45);\n        frostBits[i].visible = t > 0.01;\n        frostBits[i].scale.setScalar(Math.max(0.001, t));\n      }\n      if (light && lens) {\n        const lit = smooth(door.state);\n        light.intensity = lit * 1.6;\n        (lens.material as MeshStandardMaterial).emissiveIntensity = lit * 1.4;\n      }\n\n      state = classify();\n      if (state !== was) api.onState?.(state);\n    },\n  };\n  return api;\n}\n\n/** A cool cupboard with a marble slab: no mechanism, and it shows. */\nexport function createLarder(options: Omit<ColdOptions, 'era'> = {}): ColdStore {\n  return createColdStore({ ...options, era: 'larder' });\n}\n\n/** An oak cabinet cooled by a block of ice you have to keep replacing. */\nexport function createIcebox(options: Omit<ColdOptions, 'era'> = {}): ColdStore {\n  return createColdStore({ ...options, era: 'icebox' });\n}\n\n/** A refrigerator — `fridge` holds 4 °C, `freezer` holds −18 °C and ices up. */\nexport function createFridge(\n  options: Omit<ColdOptions, 'era'> & { era?: 'fridge' | 'freezer' } = {}\n): ColdStore {\n  return createColdStore({ ...options, era: options.era ?? 'fridge' });\n}\n\nexport const COLD_ERAS: ColdEra[] = ['larder', 'icebox', 'fridge', 'freezer'];\n","import {\n  BoxGeometry,\n  Color,\n  CylinderGeometry,\n  Group,\n  IcosahedronGeometry,\n  Mesh,\n  MeshStandardMaterial,\n} from 'three';\nimport { Rng } from '../core/random';\nimport { DEFAULT_PALETTE, type Palette } from '../core/palette';\nimport { createSurface } from '../materials/surface';\nimport { createVessel } from './vessels';\nimport type { Prop } from '../core/types';\n\n/**\n * Houseplants.\n *\n * The trap here is worth stating before the code, because it is the only\n * thing that matters: **plants read by silhouette, not by colour.** Six\n * species that are all \"green ball on a stalk\" in six different greens is\n * one plant, six times, and no amount of leaf detail rescues it. So the\n * species below differ *structurally* — upright blades, drooping strands, a\n * dense low mound, a bare column with pads, a thin trunk under a canopy, a\n * flat rosette — and the colour is chosen afterwards.\n *\n * ```ts\n * const plant = createPlant({ species: 'trailing', seed: 3 });\n * placeOn(shelf.surfaces[0], plant, { along: 0.2 });\n * ```\n *\n * The pot is a `createVessel` lathe, which is the whole reason that track\n * came first: a houseplant in a box would undo it.\n */\nexport type PlantSpecies =\n  /** Tall stiff blades fanning up from the soil. */\n  | 'snake'\n  /** A low crown with strands hanging over the rim and down. */\n  | 'trailing'\n  /** A dense low mound of arcing fronds. */\n  | 'fern'\n  /** A bare column with a pad or two, and no leaves at all. */\n  | 'cactus'\n  /** A thin trunk under a loose canopy — the corner tree. */\n  | 'ficus'\n  /** A flat rosette of thick leaves, barely above the soil. */\n  | 'succulent';\n\nexport const PLANT_SPECIES: PlantSpecies[] = [\n  'snake',\n  'trailing',\n  'fern',\n  'cactus',\n  'ficus',\n  'succulent',\n];\n\n/** Rough natural height above the soil, in metres, before seeded variation. */\nconst FOLIAGE_HEIGHT: Record<PlantSpecies, number> = {\n  snake: 0.5,\n  trailing: 0.2,\n  fern: 0.26,\n  cactus: 0.34,\n  ficus: 0.75,\n  succulent: 0.09,\n};\n\n/**\n * Pot height as a fraction of the foliage height.\n *\n * A trailing plant gets a TALL pot, because that is what real ones are put\n * in: the whole species is defined by strands hanging down, and a plant with\n * nothing to hang down past is a small bush. This is the difference between\n * six silhouettes and five.\n */\nconst POT_RATIO: Record<PlantSpecies, number> = {\n  snake: 0.42,\n  trailing: 1.15,\n  fern: 0.5,\n  cactus: 0.5,\n  ficus: 0.38,\n  succulent: 0.9,\n};\n\nexport interface PlantOptions {\n  species?: PlantSpecies;\n  /** Overall height including the pot. Defaults to the species' own. */\n  height?: number;\n  /** Skip the pot — for planting into a trough or a window box. */\n  pot?: boolean;\n  /**\n   * How far foliage may hang below the soil, in metres.\n   *\n   * A potted plant on a shelf must stop at the base of its own pot, or the\n   * strands go through it and out under the shelf — and every placement\n   * helper then lifts the whole plant to clear them, floating the pot. But an\n   * UNPOTTED one has been planted into something with a rim of its own, and\n   * that host knows how deep it is. Defaults to the pot height when potted;\n   * pass it when planting into a trough or a basket.\n   */\n  drop?: number;\n  /** Foliage colour. Defaults to a seeded pick from the palette. */\n  color?: number;\n  seed?: number;\n  palette?: Palette;\n}\n\nexport interface Plant extends Prop {\n  species: PlantSpecies;\n  /** Total height in metres. */\n  height: number;\n  /** Where the soil surface is, for planting several in one trough. */\n  soil: number;\n}\n\nfunction leafMaterial(rng: Rng, palette: Palette, color: number | undefined): MeshStandardMaterial {\n  const base = new Color(color ?? rng.pick(palette.foliage));\n  return new MeshStandardMaterial({\n    color: base.offsetHSL(rng.range(-0.03, 0.03), rng.range(-0.1, 0.05), rng.range(-0.08, 0.06)).getHex(),\n    roughness: 0.82,\n    flatShading: true,\n  });\n}\n\n/** Build the greenery for a species into `group`, rising from y = 0. */\nfunction grow(\n  group: Group,\n  species: PlantSpecies,\n  rng: Rng,\n  palette: Palette,\n  color: number | undefined,\n  height: number,\n  spread: number,\n  /**\n   * How far below the soil anything may hang. A potted plant on a shelf must\n   * stop at the base of its own pot: strands that carry on past it go through\n   * the pot and out under the shelf, and every placement helper then lifts\n   * the whole plant to clear them, floating the pot in mid-air.\n   */\n  maxDrop: number\n): number {\n  let radius = spread;\n\n  if (species === 'snake') {\n    // Stiff blades, splayed slightly, each twisted so the fan is not flat.\n    const blades = 5 + Math.floor(rng.next() * 4);\n    for (let i = 0; i < blades; i++) {\n      const h = height * rng.range(0.6, 1);\n      const blade = new Mesh(new BoxGeometry(spread * 0.34, h, 0.008), leafMaterial(rng, palette, color));\n      const a = (i / blades) * Math.PI * 2 + rng.range(-0.3, 0.3);\n      const lean = rng.range(0.08, 0.26);\n      blade.position.set(Math.cos(a) * spread * 0.2, (h / 2) * Math.cos(lean), Math.sin(a) * spread * 0.2);\n      blade.rotation.set(Math.sin(a) * lean, a, -Math.cos(a) * lean);\n      group.add(blade);\n    }\n    radius = spread * 0.6;\n  } else if (species === 'trailing') {\n    // A small crown, then strands that go OVER the rim and hang. The hang is\n    // the species: a trailing plant that stays inside its pot is a fern.\n    const crown = new Mesh(new IcosahedronGeometry(spread * 0.42, 0), leafMaterial(rng, palette, color));\n    crown.scale.y = 0.5;\n    crown.position.y = height * 0.5;\n    group.add(crown);\n    const strands = 4 + Math.floor(rng.next() * 4);\n    for (let i = 0; i < strands; i++) {\n      const a = (i / strands) * Math.PI * 2 + rng.range(-0.4, 0.4);\n      // Reach all the way to whatever the strands are allowed to fall to,\n      // measured from where they leave the crown — not a fixed length that\n      // then gets clipped to nothing on a short pot.\n      const reach = height * 0.4 + maxDrop;\n      const drop = reach * rng.range(0.55, 1);\n      const segs = 4 + Math.floor(rng.next() * 3);\n      const mat = leafMaterial(rng, palette, color);\n      for (let s = 0; s < segs; s++) {\n        const t = (s + 1) / segs;\n        const leaf = new Mesh(new BoxGeometry(0.026, 0.012, 0.038), mat);\n        // Out over the rim first, then straight down — an arc, not a spike.\n        const out = spread * (0.5 + Math.sin(Math.min(1, t * 1.6) * Math.PI * 0.5) * 0.42);\n        leaf.position.set(Math.cos(a) * out, height * 0.4 - t * t * drop, Math.sin(a) * out);\n        leaf.rotation.set(rng.range(-0.4, 0.4), a, rng.range(-0.5, 0.5));\n        group.add(leaf);\n      }\n      radius = Math.max(radius, spread * 0.95);\n    }\n  } else if (species === 'fern') {\n    // Many short fronds arcing out and over — a mound with a soft edge.\n    const fronds = 9 + Math.floor(rng.next() * 6);\n    for (let i = 0; i < fronds; i++) {\n      const a = (i / fronds) * Math.PI * 2 + rng.range(-0.25, 0.25);\n      const len = height * rng.range(0.7, 1.15);\n      const arc = rng.range(0.7, 1.15);\n      const frond = new Mesh(new BoxGeometry(len, 0.01, 0.05), leafMaterial(rng, palette, color));\n      frond.position.set(\n        Math.cos(a) * len * 0.42,\n        height * rng.range(0.4, 0.7),\n        Math.sin(a) * len * 0.42\n      );\n      frond.rotation.set(0, -a, arc * 0.5);\n      group.add(frond);\n    }\n    radius = spread * 1.25;\n  } else if (species === 'cactus') {\n    // No leaves at all, which is exactly what makes it read.\n    const mat = leafMaterial(rng, palette, color);\n    const trunk = new Mesh(new CylinderGeometry(spread * 0.3, spread * 0.34, height, 8), mat);\n    trunk.position.y = height / 2;\n    group.add(trunk);\n    const arms = Math.floor(rng.next() * 3);\n    for (let i = 0; i < arms; i++) {\n      const s = i % 2 === 0 ? 1 : -1;\n      const at = height * rng.range(0.35, 0.6);\n      const len = height * rng.range(0.22, 0.38);\n      const elbow = new Mesh(new CylinderGeometry(spread * 0.17, spread * 0.19, len * 0.7, 7), mat);\n      elbow.rotation.z = -s * Math.PI * 0.5;\n      elbow.position.set(s * (spread * 0.3 + len * 0.35), at, rng.range(-0.02, 0.02));\n      group.add(elbow);\n      const up = new Mesh(new CylinderGeometry(spread * 0.15, spread * 0.17, len, 7), mat);\n      up.position.set(s * (spread * 0.3 + len * 0.7), at + len / 2, elbow.position.z);\n      group.add(up);\n      radius = Math.max(radius, spread * 0.3 + len * 0.85);\n    }\n  } else if (species === 'ficus') {\n    // A visible bare trunk under the canopy. Without the gap it is a bush.\n    const trunkH = height * rng.range(0.42, 0.55);\n    const trunk = new Mesh(\n      new CylinderGeometry(height * 0.018, height * 0.028, trunkH, 6),\n      createSurface('bark', { color: palette.trunk, seed: rng.int(1, 1e9) })\n    );\n    trunk.position.y = trunkH / 2;\n    trunk.rotation.z = rng.range(-0.06, 0.06);\n    group.add(trunk);\n    const clumps = 4 + Math.floor(rng.next() * 4);\n    for (let i = 0; i < clumps; i++) {\n      const r = spread * rng.range(0.42, 0.72);\n      const clump = new Mesh(new IcosahedronGeometry(r, 0), leafMaterial(rng, palette, color));\n      const a = (i / clumps) * Math.PI * 2 + rng.range(-0.5, 0.5);\n      clump.position.set(\n        Math.cos(a) * spread * rng.range(0.1, 0.5),\n        trunkH + rng.range(0, height - trunkH) * 0.8 + r * 0.4,\n        Math.sin(a) * spread * rng.range(0.1, 0.5)\n      );\n      clump.scale.y = rng.range(0.65, 0.9);\n      group.add(clump);\n      radius = Math.max(radius, spread * 0.5 + r);\n    }\n  } else {\n    // A rosette: flat leaves radiating out in two layers, barely proud of\n    // the soil. Height is what it does NOT have.\n    for (let ring = 0; ring < 2; ring++) {\n      const leaves = ring === 0 ? 7 : 5;\n      for (let i = 0; i < leaves; i++) {\n        const a = (i / leaves) * Math.PI * 2 + ring * 0.4;\n        const len = spread * (ring === 0 ? rng.range(0.8, 1.0) : rng.range(0.45, 0.62));\n        const leaf = new Mesh(\n          new BoxGeometry(len, height * rng.range(0.3, 0.45), len * 0.42),\n          leafMaterial(rng, palette, color)\n        );\n        const rise = ring === 0 ? rng.range(0.15, 0.3) : rng.range(0.5, 0.8);\n        leaf.position.set(\n          Math.cos(a) * len * 0.45,\n          height * (0.2 + ring * 0.3),\n          Math.sin(a) * len * 0.45\n        );\n        leaf.rotation.set(0, -a, rise);\n        group.add(leaf);\n      }\n    }\n    radius = spread * 1.1;\n  }\n  return radius;\n}\n\n/** A potted houseplant. */\nexport function createPlant(options: PlantOptions = {}): Plant {\n  const seed = options.seed ?? 1;\n  const rng = new Rng(seed);\n  const species = options.species ?? PLANT_SPECIES[Math.floor(rng.next() * PLANT_SPECIES.length)];\n  const palette = options.palette ?? DEFAULT_PALETTE;\n  const withPot = options.pot ?? true;\n\n  const group = new Group();\n  group.name = `plant-${species}`;\n\n  const natural = FOLIAGE_HEIGHT[species];\n  const scale = options.height ? options.height / (natural * 1.35) : rng.range(0.82, 1.2);\n  const foliageH = natural * scale;\n\n  let soil = 0;\n  let radius = foliageH * 0.34;\n\n  if (withPot) {\n    // The pot is a lathe. A houseplant standing in a box would undo the\n    // entire point of having built the vessel generator.\n    const pot = createVessel({\n      style: 'pot',\n      height: Math.max(0.07, foliageH * POT_RATIO[species]),\n      seed: seed + 11,\n      color: rng.pick([0xa9603f, 0xb8b0a4, 0x8d7a63, 0x5f6b63]),\n      palette,\n    });\n    group.add(pot.object);\n    soil = pot.height * 0.72;\n    radius = pot.radius;\n    const earth = new Mesh(\n      new CylinderGeometry(pot.radius * 0.82, pot.radius * 0.82, 0.012, 12),\n      createSurface('dirt', { seed })\n    );\n    earth.position.y = soil;\n    group.add(earth);\n  }\n\n  const foliage = new Group();\n  foliage.name = 'foliage';\n  foliage.position.y = soil;\n  group.add(foliage);\n  const spread = Math.max(radius, foliageH * 0.32);\n  const maxDrop = options.drop ?? (withPot ? soil : 0.12);\n  radius = Math.max(\n    radius,\n    grow(foliage, species, rng, palette, options.color, foliageH, spread, maxDrop)\n  );\n\n  return {\n    object: group,\n    obstacleRadius: 0,\n    species,\n    height: soil + foliageH,\n    soil,\n  };\n}\n\nexport interface HangingPlantOptions extends PlantOptions {\n  /** Length of the cords above the pot. Default 0.3. */\n  cord?: number;\n}\n\n/**\n * A plant in a hanging basket.\n *\n * The origin is at the **fixing point**, with everything below it, because a\n * hanging thing is positioned by where it is hung from — the same argument\n * as the tapestry's rod.\n */\nexport function createHangingPlant(options: HangingPlantOptions = {}): Plant {\n  const seed = options.seed ?? 1;\n  const rng = new Rng(seed);\n  const cord = options.cord ?? 0.3;\n  const plant = createPlant({\n    ...options,\n    species: options.species ?? (rng.next() < 0.65 ? 'trailing' : 'fern'),\n    // The whole point of a hanging basket is that things hang out of it.\n    drop: options.drop ?? 0.35,\n    seed,\n  });\n\n  const group = new Group();\n  group.name = 'hangingPlant';\n  plant.object.position.y = -cord - plant.height;\n  group.add(plant.object);\n\n  const cordMat = new MeshStandardMaterial({ color: 0x6b6153, roughness: 0.95, flatShading: true });\n  for (let i = 0; i < 3; i++) {\n    const a = (i / 3) * Math.PI * 2;\n    const line = new Mesh(new CylinderGeometry(0.0035, 0.0035, cord, 4), cordMat);\n    line.position.set((Math.cos(a) * plant.height) / 6, -cord / 2, (Math.sin(a) * plant.height) / 6);\n    line.rotation.set(Math.sin(a) * 0.14, 0, -Math.cos(a) * 0.14);\n    group.add(line);\n  }\n  const ring = new Mesh(new CylinderGeometry(0.012, 0.012, 0.006, 8), cordMat);\n  ring.position.y = -0.004;\n  group.add(ring);\n\n  return {\n    object: group,\n    obstacleRadius: 0,\n    species: plant.species,\n    height: cord + plant.height,\n    soil: plant.soil,\n  };\n}\n\nexport interface WindowBoxOptions {\n  /** Trough length in metres. Default 0.8. */\n  length?: number;\n  seed?: number;\n  palette?: Palette;\n}\n\n/** A window trough with several plants in it, sharing one bed of soil. */\nexport function createWindowBox(options: WindowBoxOptions = {}): Prop {\n  const seed = options.seed ?? 1;\n  const rng = new Rng(seed);\n  const palette = options.palette ?? DEFAULT_PALETTE;\n  const length = options.length ?? 0.8;\n  const depth = 0.16;\n  const wall = 0.14;\n\n  const group = new Group();\n  group.name = 'windowBox';\n  const box = new Mesh(\n    new BoxGeometry(length, wall, depth),\n    createSurface('wood', { color: palette.woodDark, seed })\n  );\n  box.position.y = wall / 2;\n  group.add(box);\n  const earth = new Mesh(\n    new BoxGeometry(length - 0.02, 0.02, depth - 0.02),\n    createSurface('dirt', { seed: seed + 1 })\n  );\n  earth.position.y = wall - 0.008;\n  group.add(earth);\n\n  // Mixed planting: something upright at the back, something trailing over\n  // the front. A trough of one species is a hedge.\n  const count = Math.max(2, Math.round(length / 0.22));\n  for (let i = 0; i < count; i++) {\n    const front = rng.next() < 0.45;\n    const plant = createPlant({\n      species: front ? 'trailing' : rng.pick(['fern', 'succulent', 'snake'] as PlantSpecies[]),\n      pot: false,\n      drop: wall - 0.02,\n      height: front ? 0.14 : rng.range(0.16, 0.26),\n      seed: seed * 7 + i * 13 + 1,\n      palette,\n    });\n    plant.object.position.set(\n      -length / 2 + ((i + 0.5) / count) * length + rng.range(-0.02, 0.02),\n      wall - 0.01,\n      front ? depth * rng.range(0.16, 0.28) : -depth * rng.range(0.1, 0.24)\n    );\n    plant.object.rotation.y = rng.next() * Math.PI * 2;\n    group.add(plant.object);\n  }\n  return { object: group, obstacleRadius: 0 };\n}\n","import {\n  BoxGeometry,\n  Group,\n  Mesh,\n  MeshStandardMaterial,\n  PlaneGeometry,\n} from 'three';\nimport { Rng } from '../core/random';\nimport { DEFAULT_PALETTE, type Palette } from '../core/palette';\nimport { createSurface } from '../materials/surface';\nimport { createPicture, type PictureStyle } from '../materials/picture';\nimport type { Prop } from '../core/types';\n\n/**\n * Paper on walls — posters, pinboards, whiteboards, sticky notes.\n *\n * The one hard rule: **no letterforms.** There is no font here, and fake\n * glyphs are the single most recognisable tell in a procedural scene — at\n * any distance where you could tell they were letters, you can tell they are\n * the wrong ones. What goes on these is *type at the density type has when\n * you see it across a room*: ruled bands with ragged right edges, heavy\n * blocks where a headline sits, nothing glyph-shaped. (`createSign` is the\n * exception and earns it, because a signpost is read deliberately and has a\n * real vector font behind it.)\n *\n * Everything here follows the wall-art convention: origin at the wall face,\n * facing +z, so `hangOn` places it.\n */\n\nexport interface PosterOptions {\n  /** Width in metres. Default 0.5. */\n  width?: number;\n  /** Height. Defaults to a poster proportion. */\n  height?: number;\n  /** `poster` (colour field) or `notice` (printed sheet). Default 'poster'. */\n  style?: Extract<PictureStyle, 'poster' | 'notice'>;\n  /** Fix it with tape at the corners rather than pins. Default false. */\n  taped?: boolean;\n  seed?: number;\n  palette?: Palette;\n}\n\n/** A sheet stuck straight to the wall — no frame, no glass. */\nexport function createPoster(options: PosterOptions = {}): Prop {\n  const seed = options.seed ?? 1;\n  const rng = new Rng(seed);\n  const w = options.width ?? rng.range(0.34, 0.6);\n  const h = options.height ?? w * rng.range(1.3, 1.5);\n  const style = options.style ?? 'poster';\n\n  const group = new Group();\n  group.name = `poster-${style}`;\n  const picture = createPicture(w, h, { style, seed, age: 0.05 });\n  const sheet = new Mesh(new PlaneGeometry(w, h), picture.material);\n  sheet.name = 'sheet';\n  sheet.position.z = 0.0015;\n  group.add(sheet);\n\n  const fixings = options.taped\n    ? new MeshStandardMaterial({ color: 0xd8d2c0, roughness: 0.9, transparent: true, opacity: 0.6 })\n    : new MeshStandardMaterial({ color: 0xc04a3a, roughness: 0.4 });\n  for (const sx of [-1, 1]) {\n    for (const sy of [-1, 1]) {\n      const pin = new Mesh(\n        options.taped ? new BoxGeometry(0.03, 0.014, 0.001) : new BoxGeometry(0.008, 0.008, 0.005),\n        fixings\n      );\n      pin.position.set(sx * (w / 2 - 0.022), sy * (h / 2 - 0.018), options.taped ? 0.002 : 0.004);\n      if (options.taped) pin.rotation.z = rng.range(-0.5, 0.5);\n      group.add(pin);\n    }\n  }\n  return { object: group, obstacleRadius: 0 };\n}\n\nexport interface PinboardOptions {\n  /** Board width in metres. Default 0.8. */\n  width?: number;\n  /** Board height. Default 0.6. */\n  height?: number;\n  /** How many things are pinned to it. Default 7. */\n  count?: number;\n  seed?: number;\n  palette?: Palette;\n}\n\n/**\n * A cork pinboard with things overlapping on it.\n *\n * The **overlap** is the prop. A board of neatly spaced non-touching notes is\n * a spreadsheet; a real one has a photo half over a flyer with a corner of a\n * receipt under both, and everything at a slightly different angle.\n */\nexport function createPinboard(options: PinboardOptions = {}): Prop {\n  const seed = options.seed ?? 1;\n  const rng = new Rng(seed);\n  const palette = options.palette ?? DEFAULT_PALETTE;\n  const w = options.width ?? 0.8;\n  const h = options.height ?? 0.6;\n  const count = options.count ?? 7;\n\n  const group = new Group();\n  group.name = 'pinboard';\n  const frame = createSurface('wood', { color: palette.woodDark, seed });\n  const cork = new Mesh(\n    new BoxGeometry(w, h, 0.016),\n    createSurface('canvas', { color: 0xb08a55, roughness: 0.95, seed: seed + 1 })\n  );\n  cork.position.z = 0.008;\n  group.add(cork);\n  for (const [bw, bh, x, y] of [\n    [w + 0.04, 0.028, 0, h / 2 + 0.006],\n    [w + 0.04, 0.028, 0, -h / 2 - 0.006],\n    [0.028, h + 0.04, -w / 2 - 0.006, 0],\n    [0.028, h + 0.04, w / 2 + 0.006, 0],\n  ]) {\n    const bar = new Mesh(new BoxGeometry(bw, bh, 0.024), frame);\n    bar.position.set(x, y, 0.012);\n    group.add(bar);\n  }\n\n  const pinMat = new MeshStandardMaterial({ color: 0xc04a3a, roughness: 0.35 });\n  const pinned: PictureStyle[] = ['notice', 'photo', 'poster', 'notice', 'photo'];\n  for (let i = 0; i < count; i++) {\n    const style = pinned[i % pinned.length];\n    const pw = w * rng.range(0.16, 0.3);\n    const ph = pw * rng.range(0.72, 1.45);\n    const picture = createPicture(pw, ph, { style, seed: seed * 13 + i, age: 0.04 });\n    const note = new Mesh(new PlaneGeometry(pw, ph), picture.material);\n    // Overlapping on purpose, and stacked in z so the ones on top really are.\n    note.position.set(\n      rng.range(-1, 1) * (w / 2 - pw / 2 - 0.02),\n      rng.range(-1, 1) * (h / 2 - ph / 2 - 0.02),\n      0.017 + i * 0.0012\n    );\n    note.rotation.z = rng.range(-0.16, 0.16);\n    group.add(note);\n    const pin = new Mesh(new BoxGeometry(0.009, 0.009, 0.006), pinMat);\n    pin.position.set(note.position.x, note.position.y + ph / 2 - 0.014, note.position.z + 0.004);\n    group.add(pin);\n  }\n  return { object: group, obstacleRadius: 0 };\n}\n\nexport interface WhiteboardOptions {\n  /** Board width in metres. Default 1.2. */\n  width?: number;\n  /** Board height. Default 0.8. */\n  height?: number;\n  /** How covered it is, 0–1. Default 0.6. */\n  fill?: number;\n  seed?: number;\n}\n\n/**\n * A whiteboard with something on it.\n *\n * Handwriting is drawn as strokes rather than as anything readable, for the\n * same reason as everything else in this file. What sells a whiteboard is\n * the **layout**: a boxed diagram somewhere, a couple of lines of scrawl, an\n * arrow — and a big blank patch, because nobody ever fills one.\n */\nexport function createWhiteboard(options: WhiteboardOptions = {}): Prop {\n  const seed = options.seed ?? 1;\n  const rng = new Rng(seed);\n  const w = options.width ?? 1.2;\n  const h = options.height ?? 0.8;\n  const fill = options.fill ?? 0.6;\n\n  const group = new Group();\n  group.name = 'whiteboard';\n  const tray = new MeshStandardMaterial({ color: 0x9aa2aa, roughness: 0.4, metalness: 0.5 });\n  const board = new Mesh(\n    new BoxGeometry(w, h, 0.018),\n    new MeshStandardMaterial({ color: 0xf2f4f5, roughness: 0.16 })\n  );\n  board.position.z = 0.009;\n  group.add(board);\n  for (const [bw, bh, x, y] of [\n    [w + 0.03, 0.024, 0, h / 2 + 0.004],\n    [w + 0.03, 0.024, 0, -h / 2 - 0.004],\n    [0.024, h + 0.03, -w / 2 - 0.004, 0],\n    [0.024, h + 0.03, w / 2 + 0.004, 0],\n  ]) {\n    const edge = new Mesh(new BoxGeometry(bw, bh, 0.026), tray);\n    edge.position.set(x, y, 0.013);\n    group.add(edge);\n  }\n  const shelf = new Mesh(new BoxGeometry(w * 0.5, 0.018, 0.05), tray);\n  shelf.position.set(0, -h / 2 - 0.024, 0.03);\n  group.add(shelf);\n  for (let i = 0; i < 3; i++) {\n    const pen = new Mesh(\n      new BoxGeometry(0.09, 0.012, 0.012),\n      new MeshStandardMaterial({ color: [0x2a2d33, 0xc0392b, 0x2a6fb0][i], roughness: 0.5 })\n    );\n    pen.position.set(-0.13 + i * 0.11 + rng.range(-0.02, 0.02), -h / 2 - 0.012, 0.045);\n    pen.rotation.y = rng.range(-0.12, 0.12);\n    group.add(pen);\n  }\n\n  // The writing. Strokes, never glyphs.\n  const inkColours = [0x2a2d33, 0x2a6fb0, 0xc0392b];\n  const stroke = (x: number, y: number, len: number, tall: number, colour: number): void => {\n    const mark = new Mesh(\n      new PlaneGeometry(len, tall),\n      new MeshStandardMaterial({ color: colour, roughness: 0.6 })\n    );\n    mark.position.set(x, y, 0.0195);\n    group.add(mark);\n  };\n  const lines = Math.round(7 * fill);\n  for (let i = 0; i < lines; i++) {\n    const colour = rng.pick(inkColours);\n    const y = h * 0.36 - (i / Math.max(1, lines)) * h * 0.6;\n    const x = -w * rng.range(0.1, 0.36);\n    stroke(x, y, w * rng.range(0.14, 0.42), 0.012, colour);\n  }\n  // A boxed diagram off to one side, which is what a whiteboard always has.\n  const bx = w * rng.range(0.16, 0.28);\n  const by = h * rng.range(-0.1, 0.2);\n  const bw2 = w * 0.2;\n  const bh2 = h * 0.24;\n  const diagram = rng.pick(inkColours);\n  for (const [ox, oy, lx, ly] of [\n    [0, bh2 / 2, bw2, 0.008],\n    [0, -bh2 / 2, bw2, 0.008],\n    [-bw2 / 2, 0, 0.008, bh2],\n    [bw2 / 2, 0, 0.008, bh2],\n  ]) {\n    stroke(bx + ox, by + oy, lx, ly, diagram);\n  }\n  stroke(bx - bw2 * 0.75, by, bw2 * 0.4, 0.008, diagram); // an arrow into it\n  return { object: group, obstacleRadius: 0 };\n}\n\nexport interface StickyNotesOptions {\n  /** How many. Default 5. */\n  count?: number;\n  /** Note edge in metres. Default 0.075. */\n  size?: number;\n  /** Spread them over this area (metres). Default 0.4 × 0.3. */\n  width?: number;\n  height?: number;\n  seed?: number;\n}\n\n/**\n * A cluster of sticky notes.\n *\n * Origin at the wall face, facing +z, so this goes straight onto a wall, the\n * edge of a monitor, or a whiteboard. They cluster and they overlap, because\n * nobody spaces them out.\n */\nexport function createStickyNotes(options: StickyNotesOptions = {}): Prop {\n  const seed = options.seed ?? 1;\n  const rng = new Rng(seed);\n  const count = options.count ?? 5;\n  const size = options.size ?? 0.075;\n  const w = options.width ?? 0.4;\n  const h = options.height ?? 0.3;\n\n  const group = new Group();\n  group.name = 'stickyNotes';\n  const colours = [0xf2e06a, 0xf2a86a, 0x9ad86a, 0x7ac6e8, 0xf28aa8];\n  // One busy corner rather than an even scatter — the same argument as\n  // `dress`, at a tenth of the scale.\n  const focusX = rng.range(-0.3, 0.3) * w;\n  const focusY = rng.range(-0.3, 0.3) * h;\n  for (let i = 0; i < count; i++) {\n    const s = size * rng.range(0.85, 1.15);\n    const note = new Mesh(\n      new PlaneGeometry(s, s),\n      new MeshStandardMaterial({ color: rng.pick(colours), roughness: 0.92 })\n    );\n    note.position.set(\n      focusX + (rng.next() + rng.next() - 1) * w * 0.42,\n      focusY + (rng.next() + rng.next() - 1) * h * 0.42,\n      0.001 + i * 0.0004\n    );\n    note.rotation.z = rng.range(-0.24, 0.24);\n    group.add(note);\n    // Two scribbled lines. Any more and they start looking like text.\n    const ink = new MeshStandardMaterial({ color: 0x3a3d44, roughness: 0.7 });\n    for (let l = 0; l < 2; l++) {\n      const mark = new Mesh(new PlaneGeometry(s * rng.range(0.34, 0.62), s * 0.05), ink);\n      mark.position.set(\n        note.position.x - s * rng.range(0.0, 0.14),\n        note.position.y + s * (0.16 - l * 0.22),\n        note.position.z + 0.0002\n      );\n      mark.rotation.z = note.rotation.z;\n      group.add(mark);\n    }\n  }\n  return { object: group, obstacleRadius: 0 };\n}\n","import {\n  BoxGeometry,\n  Color,\n  Group,\n  IcosahedronGeometry,\n  Mesh,\n  MeshStandardMaterial,\n} from 'three';\nimport { Rng } from '../core/random';\nimport { DEFAULT_PALETTE, type Palette } from '../core/palette';\nimport { createSurface } from '../materials/surface';\nimport { createVessel, type VesselStyle } from './vessels';\nimport type { Prop } from '../core/types';\n\n/**\n * Clutter — the small stuff that sits on things.\n *\n * The kit already had carryables, and every one of them is a *carryable*: a\n * basket is 48 cm across, so three of them is a full table and a tabletop\n * dressed from that set says nothing except \"somebody left the shopping\n * out\". What was missing is the 5–25 cm layer — books, papers, folded cloth,\n * a couple of pieces of fruit — which is what actually makes a shelf look\n * like a shelf rather than a shelf-shaped object.\n *\n * ```ts\n * dress(shelf.surfaces[0], createClutter({ theme: 'study', count: 7, seed: 2 }));\n * ```\n *\n * Everything here is deliberately cheap: a book is one box, a stack is five.\n * At the size these occupy on screen that is already more detail than\n * survives, and the budget belongs to having *more different things* rather\n * than better ones.\n */\n\nexport interface ClutterOptions {\n  seed?: number;\n  palette?: Palette;\n}\n\n/** Spine colours that look like books rather than like a paint chart. */\nfunction bookColours(palette: Palette): number[] {\n  return [\n    0x7d3b3b, 0x2f4a6b, 0x4a5a35, 0x6b4a2f, 0x3d3a4a, 0x8a6a3a, 0x2f5a52,\n    new Color(palette.roof).getHex(),\n    new Color(palette.woodDark).getHex(),\n  ];\n}\n\nexport type BookStyle =\n  /** Lying flat, largest at the bottom. */\n  | 'stack'\n  /** Standing in a row, shoulder to shoulder. */\n  | 'row'\n  /** A short row with the last one leaning on it. */\n  | 'leaning'\n  /** One book, open, face down. */\n  | 'open';\n\nexport interface BooksOptions extends ClutterOptions {\n  style?: BookStyle;\n  /** How many. Default 4. */\n  count?: number;\n}\n\n/**\n * Books.\n *\n * A row of spines with varied heights, a few leaning, one stack lying flat is\n * most of what a bookshelf is, and none of it needs more than a box each.\n */\nexport function createBooks(options: BooksOptions = {}): Prop {\n  const seed = options.seed ?? 1;\n  const rng = new Rng(seed);\n  const style = options.style ?? 'stack';\n  const palette = options.palette ?? DEFAULT_PALETTE;\n  const colours = bookColours(palette);\n  const count = options.count ?? (style === 'open' ? 1 : 3 + Math.floor(rng.next() * 3));\n\n  const group = new Group();\n  group.name = `books-${style}`;\n  const mat = (): MeshStandardMaterial =>\n    new MeshStandardMaterial({ color: rng.pick(colours), roughness: 0.85, flatShading: true });\n\n  if (style === 'stack') {\n    let y = 0;\n    // Biggest at the bottom, and each one askew — a stack squared up is a\n    // single box with lines drawn on it.\n    let w = rng.range(0.15, 0.19);\n    let d = rng.range(0.11, 0.14);\n    for (let i = 0; i < count; i++) {\n      const t = rng.range(0.022, 0.042);\n      const book = new Mesh(new BoxGeometry(w, t, d), mat());\n      book.position.set(rng.range(-0.012, 0.012), y + t / 2, rng.range(-0.012, 0.012));\n      book.rotation.y = rng.range(-0.22, 0.22);\n      group.add(book);\n      y += t;\n      w *= rng.range(0.9, 0.99);\n      d *= rng.range(0.9, 0.99);\n    }\n  } else if (style === 'open') {\n    // Face down, splayed: two leaves at a shallow angle over a spine.\n    const w = rng.range(0.13, 0.16);\n    const d = rng.range(0.1, 0.13);\n    const cover = mat();\n    const tilt = 0.13;\n    const cos = Math.cos(tilt);\n    const sin = Math.sin(tilt);\n    const leafT = 0.008;\n    const pagesT = 0.012;\n    // Splayed leaves are tilted boxes, and a tilted box has to be lifted by\n    // its rotated half-extent or a corner ends up under the table.\n    const pagesY = (pagesT * cos + w * 0.94 * sin) / 2;\n    const coverY = pagesY + ((pagesT + leafT) / 2) * cos;\n    for (const s of [-1, 1]) {\n      const pages = new Mesh(\n        new BoxGeometry(w * 0.94, pagesT, d * 0.92),\n        new MeshStandardMaterial({ color: 0xe8e2d2, roughness: 0.95, flatShading: true })\n      );\n      pages.position.set(s * w * 0.5, pagesY, 0);\n      pages.rotation.z = s * tilt;\n      group.add(pages);\n      const leaf = new Mesh(new BoxGeometry(w, leafT, d), cover);\n      leaf.position.set(s * w * 0.5, coverY, 0);\n      leaf.rotation.z = s * tilt;\n      group.add(leaf);\n    }\n  } else {\n    // Standing. `leaning` tips the last one against the rest, which needs a\n    // real gap left for it or it just intersects its neighbour.\n    let x = 0;\n    for (let i = 0; i < count; i++) {\n      const h = rng.range(0.15, 0.22);\n      const w = rng.range(0.024, 0.042);\n      const d = rng.range(0.1, 0.14);\n      const last = i === count - 1;\n      const tip = style === 'leaning' && last ? rng.range(0.34, 0.5) : 0;\n      const book = new Mesh(new BoxGeometry(w, h, d), mat());\n      // A tipped box is lifted by its OWN half-extent after rotation, which\n      // includes its thickness: h*cos/2 alone leaves the low corner w*sin/2\n      // below the shelf, and a leaning book that sinks into the wood is more\n      // obviously wrong than one that never leaned.\n      book.position.set(\n        x + w / 2 + Math.sin(tip) * h * 0.5,\n        (Math.cos(tip) * h + Math.sin(tip) * w) / 2,\n        0\n      );\n      book.rotation.z = -tip;\n      group.add(book);\n      x += w + (tip > 0 ? Math.sin(tip) * h * 0.5 : rng.range(0.001, 0.004));\n    }\n    group.position.x = -x / 2;\n  }\n  return { object: group, obstacleRadius: 0 };\n}\n\nexport interface PapersOptions extends ClutterOptions {\n  /** How many sheets. Default 6. */\n  count?: number;\n  /** Sheet long edge in metres. Default 0.24. */\n  size?: number;\n}\n\n/** A slew of loose sheets: a stack, never square, with one clear of the pile. */\nexport function createPapers(options: PapersOptions = {}): Prop {\n  const seed = options.seed ?? 1;\n  const rng = new Rng(seed);\n  const count = options.count ?? 6;\n  const long = options.size ?? 0.24;\n  const short = long * 0.707;\n\n  const group = new Group();\n  group.name = 'papers';\n  const paper = new MeshStandardMaterial({ color: 0xeae6da, roughness: 0.95, flatShading: true });\n  const scrap = new MeshStandardMaterial({ color: 0xdcd6c4, roughness: 0.95, flatShading: true });\n\n  for (let i = 0; i < count; i++) {\n    const stray = i === count - 1 && count > 2;\n    const sheet = new Mesh(new BoxGeometry(long, 0.0012, short), rng.next() < 0.3 ? scrap : paper);\n    sheet.position.set(\n      stray ? rng.range(0.05, 0.09) : rng.range(-0.014, 0.014),\n      0.0007 + i * 0.0013,\n      stray ? rng.range(-0.05, 0.05) : rng.range(-0.012, 0.012)\n    );\n    // The whole prop is the fact that no two sheets line up.\n    // A sheet skewed too far off the pile turns the whole prop into a 44 cm\n    // spread, which `dress` then has to find room for as a single footprint.\n    sheet.rotation.y = stray ? rng.range(-0.5, 0.5) : rng.range(-0.1, 0.1);\n    if (stray) sheet.position.y = 0.0007;\n    group.add(sheet);\n  }\n  return { object: group, obstacleRadius: 0 };\n}\n\nexport interface FoldedOptions extends ClutterOptions {\n  /** Folded width in metres. Default 0.2. */\n  width?: number;\n  /** Cloth colour. Defaults to a seeded pick from the palette. */\n  color?: number;\n}\n\n/** Folded cloth: a towel, a napkin pile, a blanket on the end of a bed. */\nexport function createFolded(options: FoldedOptions = {}): Prop {\n  const seed = options.seed ?? 1;\n  const rng = new Rng(seed);\n  const palette = options.palette ?? DEFAULT_PALETTE;\n  const w = options.width ?? 0.2;\n  const d = w * rng.range(0.6, 0.78);\n\n  const group = new Group();\n  group.name = 'folded';\n  const base = new Color(\n    options.color ?? rng.pick([0xb8b0a0, 0x8a9aa8, 0xa89080, 0x9aa88c, new Color(palette.wall).getHex()])\n  );\n  const layers = 2 + Math.floor(rng.next() * 3);\n  let y = 0;\n  for (let i = 0; i < layers; i++) {\n    const t = rng.range(0.014, 0.026);\n    const shade = base.clone().offsetHSL(0, 0, rng.range(-0.06, 0.06));\n    const slab = new Mesh(\n      new BoxGeometry(w * rng.range(0.94, 1.0), t, d * rng.range(0.94, 1.0)),\n      createSurface('canvas', { color: shade.getHex(), roughness: 0.95, seed: seed + i })\n    );\n    // Folded cloth never stacks square; the offsets are the whole read.\n    slab.position.set(rng.range(-0.008, 0.008), y + t / 2, rng.range(-0.008, 0.008));\n    slab.rotation.y = rng.range(-0.08, 0.08);\n    group.add(slab);\n    y += t;\n  }\n  return { object: group, obstacleRadius: 0 };\n}\n\nexport interface TrinketOptions extends ClutterOptions {\n  /** Long edge in metres. Default 0.1. */\n  size?: number;\n}\n\n/** A small lidded box — the filler that reads as \"something of theirs\". */\nexport function createTrinket(options: TrinketOptions = {}): Prop {\n  const seed = options.seed ?? 1;\n  const rng = new Rng(seed);\n  const palette = options.palette ?? DEFAULT_PALETTE;\n  const w = (options.size ?? 0.1) * rng.range(0.8, 1.2);\n  const d = w * rng.range(0.6, 0.95);\n  const h = w * rng.range(0.35, 0.6);\n\n  const group = new Group();\n  group.name = 'trinket';\n  const wood = createSurface('wood', { color: palette.woodDark, seed });\n  const body = new Mesh(new BoxGeometry(w, h * 0.78, d), wood);\n  body.position.y = (h * 0.78) / 2;\n  group.add(body);\n  const lid = new Mesh(new BoxGeometry(w * 1.06, h * 0.22, d * 1.06), wood);\n  lid.position.y = h * 0.78 + (h * 0.22) / 2;\n  group.add(lid);\n  if (rng.next() < 0.6) {\n    const clasp = new Mesh(\n      new BoxGeometry(w * 0.14, h * 0.2, 0.004),\n      new MeshStandardMaterial({ color: 0xb8983f, roughness: 0.4, metalness: 0.6 })\n    );\n    clasp.position.set(0, h * 0.72, d / 2 + 0.002);\n    group.add(clasp);\n  }\n  return { object: group, obstacleRadius: 0 };\n}\n\nexport interface FruitBowlOptions extends ClutterOptions {\n  /** How many pieces. Default 5. */\n  count?: number;\n}\n\n/**\n * A bowl with fruit in it — the one piece here that composes the two tracks,\n * since the bowl is a lathe and the fruit are not.\n */\nexport function createFruitBowl(options: FruitBowlOptions = {}): Prop {\n  const seed = options.seed ?? 1;\n  const rng = new Rng(seed);\n  const bowl = createVessel({ style: 'bowl', seed, palette: options.palette });\n  const group = bowl.object;\n  group.name = 'fruitBowl';\n\n  const count = options.count ?? 5;\n  const hues = [0.02, 0.09, 0.14, 0.28, 0.85];\n  for (let i = 0; i < count; i++) {\n    const r = bowl.radius * rng.range(0.16, 0.24);\n    const fruit = new Mesh(\n      new IcosahedronGeometry(r, 0),\n      new MeshStandardMaterial({\n        color: new Color().setHSL(rng.pick(hues), rng.range(0.45, 0.7), rng.range(0.35, 0.5)).getHex(),\n        roughness: 0.75,\n        flatShading: true,\n      })\n    );\n    // Inside the bowl and resting on its floor, not floating over the rim.\n    const a = rng.next() * Math.PI * 2;\n    const spread = bowl.radius * rng.range(0, 0.42);\n    fruit.position.set(\n      Math.cos(a) * spread,\n      bowl.height * 0.28 + r * 0.7 + (i > 2 ? r : 0),\n      Math.sin(a) * spread\n    );\n    fruit.scale.y = rng.range(0.82, 1.0);\n    group.add(fruit);\n  }\n  return { object: group, obstacleRadius: 0 };\n}\n\nexport type ClutterTheme = 'domestic' | 'kitchen' | 'study' | 'workshop';\n\nexport interface ClutterKitOptions extends ClutterOptions {\n  theme?: ClutterTheme;\n  /** How many pieces to make. Default 6. */\n  count?: number;\n}\n\ntype Maker = (seed: number, palette: Palette) => Prop;\n\nconst vessel = (style: VesselStyle): Maker => (seed, palette) =>\n  createVessel({ style, seed, palette });\n\nconst THEMES: Record<ClutterTheme, Maker[]> = {\n  domestic: [\n    vessel('vase'),\n    vessel('bowl'),\n    vessel('candlestick'),\n    (s, p) => createBooks({ style: 'stack', seed: s, palette: p }),\n    (s, p) => createFolded({ seed: s, palette: p }),\n    (s, p) => createFruitBowl({ seed: s, palette: p }),\n    (s, p) => createTrinket({ seed: s, palette: p }),\n  ],\n  kitchen: [\n    vessel('jug'),\n    vessel('pot'),\n    vessel('bowl'),\n    vessel('bottle'),\n    (s, p) => createFruitBowl({ seed: s, palette: p }),\n    (s, p) => createFolded({ seed: s, width: 0.16, palette: p }),\n  ],\n  study: [\n    (s, p) => createBooks({ style: 'row', seed: s, palette: p }),\n    (s, p) => createBooks({ style: 'stack', seed: s, palette: p }),\n    (s, p) => createBooks({ style: 'leaning', seed: s, palette: p }),\n    (s, p) => createBooks({ style: 'open', seed: s, palette: p }),\n    (s, p) => createPapers({ seed: s, palette: p }),\n    vessel('bottle'),\n    vessel('candlestick'),\n    (s, p) => createTrinket({ seed: s, palette: p }),\n  ],\n  workshop: [\n    vessel('pot'),\n    vessel('bottle'),\n    vessel('urn'),\n    (s, p) => createPapers({ seed: s, count: 3, palette: p }),\n    (s, p) => createTrinket({ seed: s, size: 0.13, palette: p }),\n    (s, p) => createFolded({ seed: s, width: 0.15, palette: p }),\n  ],\n};\n\n/**\n * A mixed set of small things, ready to hand straight to `dress`.\n *\n * The pool is drawn from **without replacement until it runs out**, so a set\n * of six is six different things rather than the same vase six times — which\n * is what picking at random gives you, and which is exactly as obviously\n * generated as an even spread.\n */\nexport function createClutter(options: ClutterKitOptions = {}): Prop[] {\n  const seed = options.seed ?? 1;\n  const rng = new Rng(seed);\n  const palette = options.palette ?? DEFAULT_PALETTE;\n  const pool = THEMES[options.theme ?? 'domestic'];\n  const count = options.count ?? 6;\n\n  const out: Prop[] = [];\n  let bag: Maker[] = [];\n  for (let i = 0; i < count; i++) {\n    if (bag.length === 0) bag = pool.slice();\n    const pick = Math.floor(rng.next() * bag.length);\n    const maker = bag[pick];\n    bag.splice(pick, 1);\n    out.push(maker(seed * 31 + i * 7 + 1, palette));\n  }\n  return out;\n}\n\nexport const CLUTTER_THEMES: ClutterTheme[] = ['domestic', 'kitchen', 'study', 'workshop'];\n","import {\n  BoxGeometry,\n  CylinderGeometry,\n  Group,\n  Mesh,\n  MeshStandardMaterial,\n  Object3D,\n  Quaternion,\n  Vector3,\n  type Material,\n} from 'three';\nimport { Rng } from '../core/random';\nimport type { Palette } from '../core/palette';\nimport { createSurface } from '../materials/surface';\nimport { createGlass } from '../materials/glass';\nimport { sharedBy } from '../materials/shared';\nimport { createSlot, type Prop, type PropSlot } from '../core/types';\nimport type { RailTrack, TrackPoint } from '../environment/track';\n\n/**\n * Rolling stock: locomotives, carriages, and goods wagons — and the coupling\n * that makes a list of them into a train.\n *\n * ```ts\n * const train = createConsist(track, [\n *   createLocomotive({ seed: 1 }),\n *   createCarriage({ seed: 2 }),\n *   createCarriage({ seed: 3 }),\n * ]);\n * scene.add(train.object);\n * train.place(120);        // the whole train, 120 m along the line\n * ```\n *\n * ## Why a consist is not just N props in a row\n *\n * A vehicle on a curve does not face the way the track faces at its centre. It\n * is a rigid body resting on two bogies, and it faces along the CHORD between\n * them — which on a bend is measurably different, and is the difference\n * between a train that looks like a train and a string of boxes shrink-wrapped\n * to a spline.\n *\n * So `place` samples the track twice per vehicle, at its bogie centres, and\n * puts the body on the midpoint facing the chord. Two extra samples per\n * carriage per frame, and it is the whole trick.\n */\n\nexport interface RollingStockOptions {\n  seed?: number;\n  palette?: Palette;\n  /** Body colour. Seeded from a livery set when omitted. */\n  color?: number;\n  /** Length over couplings, metres. Sensible defaults per kind. */\n  length?: number;\n}\n\n/** A vehicle that can be coupled into a consist. */\nexport interface RollingStock extends Prop {\n  /** Length over couplings, metres — what the consist spaces by. */\n  length: number;\n  /** Distance between bogie centres. The chord `place` faces along. */\n  bogieSpacing: number;\n  /**\n   * Door centres as offsets from the vehicle's own centre, in metres.\n   *\n   * Empty on a goods wagon. This is what a platform aligns to, and what makes\n   * \"the doors stopped 40 cm past their markers\" a number rather than a\n   * complaint.\n   */\n  doors: number[];\n  /** The bogies, so a caller can spin the wheels at the right rate. */\n  wheels: Object3D[];\n  /** Wheel radius, so that rate is derivable rather than guessed. */\n  wheelRadius: number;\n}\n\nconst LIVERY = [0x1f4e79, 0x7a1f2b, 0x1d5b34, 0x37474f, 0x6b4c2a];\nconst UP = new Vector3(0, 1, 0);\n\n/** Bogie: a frame and four wheels, returned so the caller can roll them. */\nfunction bogie(steel: Material, dark: Material, radius: number): Object3D {\n  const pivot = new Object3D();\n  pivot.name = 'bogie';\n  const frame = new Mesh(new BoxGeometry(1.9, 0.18, 1.7), dark);\n  frame.position.y = radius + 0.18;\n  pivot.add(frame);\n  for (const z of [-0.72, 0.72]) {\n    for (const x of [-0.78, 0.78]) {\n      const wheel = new Mesh(new CylinderGeometry(radius, radius, 0.08, 12), steel);\n      wheel.rotation.z = Math.PI / 2;\n      wheel.position.set(x, radius, z);\n      wheel.name = 'wheel';\n      pivot.add(wheel);\n    }\n  }\n  return pivot;\n}\n\n/** The shared skeleton of every vehicle: underframe, bogies, buffers. */\nfunction chassis(\n  group: Group,\n  length: number,\n  bogieSpacing: number,\n  steel: Material,\n  dark: Material,\n  wheelRadius: number\n): Object3D[] {\n  const deck = new Mesh(new BoxGeometry(2.8, 0.22, length - 0.4), dark);\n  deck.position.y = wheelRadius + 0.42;\n  group.add(deck);\n  const bogies: Object3D[] = [];\n  for (const z of [-bogieSpacing / 2, bogieSpacing / 2]) {\n    const b = bogie(steel, dark, wheelRadius);\n    b.position.z = z;\n    group.add(b);\n    bogies.push(b);\n  }\n  // Buffers and a coupling hook at each end — the bit that says \"this joins\n  // to another one of these\".\n  for (const end of [-1, 1]) {\n    for (const x of [-0.85, 0.85]) {\n      const buffer = new Mesh(new CylinderGeometry(0.17, 0.17, 0.3, 8), steel);\n      buffer.rotation.x = Math.PI / 2;\n      buffer.position.set(x, wheelRadius + 0.42, end * (length / 2 - 0.1));\n      group.add(buffer);\n    }\n  }\n  return bogies;\n}\n\n/** A passenger carriage: body, window band, roof, and doors that matter. */\nexport function createCarriage(options: RollingStockOptions = {}): RollingStock {\n  const rng = new Rng(options.seed ?? 1);\n  const length = options.length ?? 19;\n  const bogieSpacing = length * 0.68;\n  const wheelRadius = 0.45;\n  const color = options.color ?? rng.pick(LIVERY);\n\n  const group = new Group();\n  group.name = 'carriage';\n  const steel = createSurface('steel', { seed: rng.int(1, 999) });\n  const dark = new MeshStandardMaterial({ color: 0x22262b, roughness: 0.85, flatShading: true });\n  const body = createSurface('paintedMetal', { color, seed: rng.int(1, 999) });\n  const glass = createGlass({ tint: 0x9fc4d8 });\n\n  const bogies = chassis(group, length, bogieSpacing, steel, dark, wheelRadius);\n\n  // Roofs are a light grey, NOT the underframe's near-black. Station canopies\n  // are dark too, and a dark roof under a dark canopy makes the train\n  // disappear into the building — visible the moment the railway example was\n  // first rendered, and invisible in any test.\n  const roofGrey = new MeshStandardMaterial({ color: 0x9aa3ab, roughness: 0.78, flatShading: true });\n  const bodyY = wheelRadius + 0.53;\n  const shell = new Mesh(new BoxGeometry(2.9, 2.5, length - 0.5), body);\n  shell.position.y = bodyY + 1.25;\n  group.add(shell);\n  const roof = new Mesh(new BoxGeometry(2.75, 0.22, length - 0.8), roofGrey);\n  roof.position.y = bodyY + 2.6;\n  group.add(roof);\n\n  // Window band: one mesh per side, not one per window — a carriage with\n  // sixteen separate panes is sixteen draw calls for a stripe.\n  for (const side of [-1, 1]) {\n    const band = new Mesh(new BoxGeometry(0.06, 0.95, length - 3.4), glass);\n    band.position.set(side * 1.47, bodyY + 1.75, 0);\n    band.name = 'window-band';\n    group.add(band);\n  }\n\n  // Doors, and the offsets that go with them. A carriage has one pair near\n  // each end, which is what platform alignment is measured against.\n  const doors = [-length * 0.32, length * 0.32];\n  const doorMaterial = sharedBy((c: number) =>\n    new MeshStandardMaterial({ color: c, roughness: 0.5, metalness: 0.2, flatShading: true })\n  );\n  const slots: PropSlot[] = [];\n  for (const z of doors) {\n    for (const side of [-1, 1]) {\n      const leaf = new Mesh(new BoxGeometry(0.08, 2.0, 1.25), doorMaterial(0x2b3138));\n      leaf.position.set(side * 1.48, bodyY + 1.05, z);\n      leaf.name = 'door';\n      group.add(leaf);\n    }\n    slots.push(\n      createSlot('seat', 'sit', group, 0.75, bodyY + 0.55, z + 1.6, Math.PI)\n    );\n  }\n\n  return {\n    object: group,\n    obstacleRadius: length / 2,\n    slots,\n    length,\n    bogieSpacing,\n    doors,\n    wheels: bogies,\n    wheelRadius,\n  };\n}\n\n/** A locomotive: the same chassis, a cab you can stand in, and a nose. */\nexport function createLocomotive(options: RollingStockOptions = {}): RollingStock {\n  const rng = new Rng(options.seed ?? 1);\n  const length = options.length ?? 17;\n  const bogieSpacing = length * 0.62;\n  const wheelRadius = 0.52;\n  const color = options.color ?? rng.pick(LIVERY);\n\n  const group = new Group();\n  group.name = 'locomotive';\n  const steel = createSurface('steel', { seed: rng.int(1, 999) });\n  const dark = new MeshStandardMaterial({ color: 0x22262b, roughness: 0.85, flatShading: true });\n  const body = createSurface('paintedMetal', { color, seed: rng.int(1, 999) });\n  const glass = createGlass({ tint: 0x9fc4d8 });\n\n  const bogies = chassis(group, length, bogieSpacing, steel, dark, wheelRadius);\n  const bodyY = wheelRadius + 0.6;\n\n  // Long hood, then a taller cab set back from the leading end.\n  const hood = new Mesh(new BoxGeometry(2.85, 2.1, length - 6), body);\n  hood.position.set(0, bodyY + 1.05, 1.4);\n  group.add(hood);\n  const cab = new Mesh(new BoxGeometry(2.95, 2.7, 4.2), body);\n  cab.position.set(0, bodyY + 1.35, -length / 2 + 2.6);\n  group.add(cab);\n  const cabRoof = new Mesh(\n    new BoxGeometry(3.05, 0.2, 4.4),\n    new MeshStandardMaterial({ color: 0x9aa3ab, roughness: 0.78, flatShading: true })\n  );\n  cabRoof.position.set(0, bodyY + 2.8, -length / 2 + 2.6);\n  group.add(cabRoof);\n\n  // Windscreen and side lights — the face of the thing.\n  const screen = new Mesh(new BoxGeometry(2.5, 1.0, 0.1), glass);\n  screen.position.set(0, bodyY + 2.0, -length / 2 + 0.55);\n  group.add(screen);\n  const lamp = sharedBy((c: number) =>\n    new MeshStandardMaterial({ color: c, emissive: c, emissiveIntensity: 0.6 })\n  );\n  for (const x of [-0.9, 0.9]) {\n    const light = new Mesh(new BoxGeometry(0.34, 0.24, 0.1), lamp(0xfff2cc));\n    light.position.set(x, bodyY + 0.75, -length / 2 + 0.12);\n    group.add(light);\n  }\n\n  const slots = [createSlot('driver', 'drive', group, 0.55, bodyY + 0.35, -length / 2 + 2.2, Math.PI)];\n\n  return {\n    object: group,\n    obstacleRadius: length / 2,\n    slots,\n    length,\n    bogieSpacing,\n    doors: [],\n    wheels: bogies,\n    wheelRadius,\n  };\n}\n\nexport interface WagonOptions extends RollingStockOptions {\n  /** `open` for mineral/coal, `van` for a closed box, `flat` for a bed. */\n  kind?: 'open' | 'van' | 'flat';\n}\n\n/** A goods wagon. No doors to align, no seats — freight, not people. */\nexport function createWagon(options: WagonOptions = {}): RollingStock {\n  const rng = new Rng(options.seed ?? 1);\n  const kind = options.kind ?? rng.pick(['open', 'van', 'flat'] as const);\n  const length = options.length ?? 12;\n  const bogieSpacing = length * 0.6;\n  const wheelRadius = 0.42;\n\n  const group = new Group();\n  group.name = `wagon-${kind}`;\n  const steel = createSurface('steel', { seed: rng.int(1, 999) });\n  const dark = new MeshStandardMaterial({ color: 0x22262b, roughness: 0.85, flatShading: true });\n  // Weathered rather than painted: a goods wagon is a working thing.\n  const plate = createSurface('metal', { color: 0x6a5a4c, seed: rng.int(1, 999) });\n\n  const bogies = chassis(group, length, bogieSpacing, steel, dark, wheelRadius);\n  const deckY = wheelRadius + 0.53;\n\n  if (kind === 'van') {\n    const box = new Mesh(new BoxGeometry(2.85, 2.6, length - 0.6), plate);\n    box.position.y = deckY + 1.3;\n    group.add(box);\n    const roof = new Mesh(new BoxGeometry(2.7, 0.18, length - 0.9), dark);\n    roof.position.y = deckY + 2.7;\n    group.add(roof);\n  } else if (kind === 'open') {\n    // Four walls, no lid. Cheaper than a hollowed box and it reads the same.\n    for (const [w, h, d, x, z] of [\n      [2.85, 1.5, 0.14, 0, -(length / 2 - 0.35)],\n      [2.85, 1.5, 0.14, 0, length / 2 - 0.35],\n      [0.14, 1.5, length - 0.7, -1.36, 0],\n      [0.14, 1.5, length - 0.7, 1.36, 0],\n    ] as const) {\n      const wall = new Mesh(new BoxGeometry(w, h, d), plate);\n      wall.position.set(x, deckY + 0.75, z);\n      group.add(wall);\n    }\n  } else {\n    const bed = new Mesh(new BoxGeometry(2.85, 0.16, length - 0.6), plate);\n    bed.position.y = deckY + 0.08;\n    group.add(bed);\n  }\n\n  return {\n    object: group,\n    obstacleRadius: length / 2,\n    length,\n    bogieSpacing,\n    doors: [],\n    wheels: bogies,\n    wheelRadius,\n  };\n}\n\nexport interface ConsistOptions {\n  /** Gap between coupled vehicles, metres. Default 0.6. */\n  coupling?: number;\n  /** Roll the wheels as the train moves. Default true. */\n  rollWheels?: boolean;\n}\n\nexport interface Consist {\n  object: Group;\n  vehicles: RollingStock[];\n  /** Length over the whole train, including couplings. */\n  length: number;\n  /**\n   * Put the train's FRONT at `distance` along the track.\n   *\n   * The front, not the centre, because a station stop is expressed as \"the\n   * front of the train at the stopping mark\" — that is what a driver aims at\n   * and what a platform is measured from.\n   */\n  place(distance: number): void;\n  /** Where `vehicles[v]`'s door `d` is in world space, after the last `place`. */\n  doorPosition(vehicle: number, door: number, out?: Vector3): Vector3;\n  /** Every door on the train, in order. Convenience over `doorPosition`. */\n  doorPositions(): Vector3[];\n}\n\n/**\n * Couple vehicles onto a track.\n *\n * `track` is taken structurally — anything with `length` and `at()` — so this\n * works with a `RailTrack`, a test double, or whatever a game lays its own\n * lines with.\n */\nexport function createConsist(\n  track: Pick<RailTrack, 'length' | 'at'>,\n  vehicles: RollingStock[],\n  options: ConsistOptions = {}\n): Consist {\n  const coupling = options.coupling ?? 0.6;\n  const rollWheels = options.rollWheels ?? true;\n\n  const group = new Group();\n  group.name = 'consist';\n  for (const v of vehicles) group.add(v.object);\n\n  // Distance from the train's front to each vehicle's CENTRE.\n  const centres: number[] = [];\n  let run = 0;\n  for (const v of vehicles) {\n    centres.push(run + v.length / 2);\n    run += v.length + coupling;\n  }\n  const length = Math.max(0, run - coupling);\n\n  const front = { position: new Vector3(), tangent: new Vector3(), rotation: new Quaternion() };\n  const back = { position: new Vector3(), tangent: new Vector3(), rotation: new Quaternion() };\n  const chord = new Vector3();\n  let placedAt = 0;\n\n  const place = (distance: number): void => {\n    placedAt = distance;\n    for (const [i, vehicle] of vehicles.entries()) {\n      const centre = distance - centres[i];\n      const half = vehicle.bogieSpacing / 2;\n      // The two bogies, sampled where they actually sit on the rails.\n      track.at(centre + half, front as TrackPoint);\n      track.at(centre - half, back as TrackPoint);\n      // Body on the midpoint, facing the chord between them — NOT the tangent\n      // at the centre, which is what makes a train on a curve look wrong.\n      vehicle.object.position.lerpVectors(back.position, front.position, 0.5);\n      chord.subVectors(front.position, back.position);\n      if (chord.lengthSq() > 1e-9) {\n        chord.normalize();\n        vehicle.object.quaternion.setFromAxisAngle(UP, Math.atan2(chord.x, chord.z) + Math.PI);\n      }\n      if (rollWheels) {\n        // Rotation follows DISTANCE, not time: a wheel that spins on a timer\n        // slips whenever the train changes speed, which is the rail version of\n        // foot skate and just as invisible in a still frame.\n        const angle = centre / vehicle.wheelRadius;\n        for (const b of vehicle.wheels) {\n          for (const wheel of b.children) {\n            if (wheel.name === 'wheel') wheel.rotation.y = -angle;\n          }\n        }\n      }\n    }\n  };\n\n  const doorPosition = (vehicle: number, door: number, out = new Vector3()): Vector3 => {\n    const v = vehicles[vehicle];\n    const offset = v.doors[door];\n    return out\n      .set(0, 0, offset)\n      .applyQuaternion(v.object.quaternion)\n      .add(v.object.position);\n  };\n\n  place(0);\n  void placedAt;\n\n  return {\n    object: group,\n    vehicles,\n    length,\n    place,\n    doorPosition,\n    doorPositions(): Vector3[] {\n      const out: Vector3[] = [];\n      for (const [i, v] of vehicles.entries()) {\n        for (let d = 0; d < v.doors.length; d++) out.push(doorPosition(i, d));\n      }\n      return out;\n    },\n  };\n}\n","import {\n  BoxGeometry,\n  CylinderGeometry,\n  Group,\n  InstancedMesh,\n  Matrix4,\n  Mesh,\n  MeshStandardMaterial,\n  Quaternion,\n  Vector3,\n} from 'three';\nimport { Rng } from '../core/random';\nimport { DEFAULT_PALETTE, type Palette } from '../core/palette';\nimport { createSurface } from '../materials/surface';\nimport { buildTextGeometry } from '../text/textGeometry';\nimport { createSlot, type PropSlot } from '../core/types';\nimport type { RailTrack, TrackPoint } from '../environment/track';\n\n/**\n * A station platform, laid alongside a track.\n *\n * ```ts\n * const platform = createPlatform(track, {\n *   from: 400, to: 520, name: 'HAVENBROOK',\n * });\n * scene.add(platform.object);\n * platform.stopMark;        // where a train's FRONT should come to rest\n * platform.doorMarks;       // where its doors are expected to land\n * ```\n *\n * ## The marks are the point\n *\n * A platform is easy to build and easy to build wrong, and the wrongness is\n * invisible in a screenshot: a train stops, the doors open, and they are two\n * metres past the gap in the fence. So the platform publishes where it expects\n * a train to stop and where it expects the doors to be, and those are numbers\n * a test can hold to a few centimetres.\n *\n * `doorMarks` is derived from the consist you intend to run, not guessed —\n * pass the door offsets and the platform puts a marking on the paving at each\n * one. If the train changes length, the markings move, which is exactly what\n * happens on a real railway when the timetable changes.\n */\nexport interface StationPlatformOptions {\n  /** Distance along the track where the platform starts, metres. */\n  from: number;\n  /** Distance along the track where it ends. */\n  to: number;\n  /** Which side of the track, looking along it. Default 'left'. */\n  side?: 'left' | 'right';\n  /** Platform width, metres. Default 6. */\n  width?: number;\n  /** Height above rail level. Default 0.9 — a step up into a carriage. */\n  height?: number;\n  /** Station name, carved into the running-in board. Omit for no board. */\n  name?: string;\n  /**\n   * Door offsets of the train that stops here, from `RollingStock.doors`\n   * mapped through the consist. Each gets a marking on the paving.\n   */\n  doorOffsets?: number[];\n  /** Where the train's FRONT stops. Defaults to the far end minus a margin. */\n  stopAt?: number;\n  /** Canopy over part of the platform. Default true. */\n  canopy?: boolean;\n  seed?: number;\n  palette?: Palette;\n}\n\nexport interface StationPlatform {\n  object: Group;\n  obstacleRadius: number;\n  slots: PropSlot[];\n  /** Distance along the track a train's front should stop at. */\n  stopMark: number;\n  /** World positions the doors are expected to land on. */\n  doorMarks: Vector3[];\n  /** The platform edge, for a crowd to queue behind. */\n  edge: { from: Vector3; to: Vector3 };\n  from: number;\n  to: number;\n  dispose(): void;\n}\n\n/** A station platform beside a track, with the marks a train aligns to. */\nexport function createStationPlatform(\n  track: Pick<RailTrack, 'at' | 'gauge' | 'length'>,\n  options: StationPlatformOptions\n): StationPlatform {\n  const rng = new Rng(options.seed ?? 1);\n  const palette = options.palette ?? DEFAULT_PALETTE;\n  const width = options.width ?? 6;\n  const height = options.height ?? 0.9;\n  const sideSign = (options.side ?? 'left') === 'left' ? -1 : 1;\n  const from = Math.min(options.from, options.to);\n  const to = Math.max(options.from, options.to);\n  const span = to - from;\n  // The train stops with its nose short of the far end — nobody parks a train\n  // with the buffers touching the ramp.\n  const stopMark = options.stopAt ?? to - 4;\n\n  const group = new Group();\n  group.name = 'platform';\n\n  const paving = createSurface('concrete', { seed: rng.int(1, 999) });\n  const kerb = createSurface('stone', { color: 0xb8b2a6, seed: rng.int(1, 999) });\n  const steel = createSurface('paintedMetal', { color: palette.metal ?? 0x51606b, seed: rng.int(1, 999) });\n\n  // Offset from the track centreline to the platform's inner face: half the\n  // gauge, plus the loading-gauge clearance a carriage body needs.\n  const inner = track.gauge / 2 + 1.05;\n  const probe: TrackPoint = {\n    position: new Vector3(),\n    tangent: new Vector3(),\n    rotation: new Quaternion(),\n  };\n  const perp = new Vector3();\n  const place = (distance: number, lateral: number, out = new Vector3()): Vector3 => {\n    track.at(distance, probe);\n    perp.set(-probe.tangent.z, 0, probe.tangent.x).multiplyScalar(sideSign * lateral);\n    return out.copy(probe.position).add(perp);\n  };\n\n  // The deck. One box per 12 m section, oriented to the track, so a platform\n  // beside a curve follows it instead of cutting the corner.\n  const sections = Math.max(1, Math.round(span / 12));\n  const sectionLength = span / sections;\n  const deckGeometry = new BoxGeometry(width, height, sectionLength + 0.04);\n  const deck = new InstancedMesh(deckGeometry, paving, sections);\n  deck.name = 'deck';\n  const matrix = new Matrix4();\n  const one = new Vector3(1, 1, 1);\n  const seat = new Vector3();\n  for (let i = 0; i < sections; i++) {\n    const d = from + (i + 0.5) * sectionLength;\n    place(d, inner + width / 2, seat);\n    track.at(d, probe);\n    matrix.compose(seat.setY(seat.y + height / 2), probe.rotation, one);\n    deck.setMatrixAt(i, matrix);\n  }\n  deck.instanceMatrix.needsUpdate = true;\n  group.add(deck);\n\n  // The edge strip — the tactile line you are told to stand behind.\n  const edgeGeometry = new BoxGeometry(0.6, 0.04, sectionLength + 0.04);\n  const edgeStrip = new InstancedMesh(edgeGeometry, kerb, sections);\n  edgeStrip.name = 'edge';\n  for (let i = 0; i < sections; i++) {\n    const d = from + (i + 0.5) * sectionLength;\n    place(d, inner + 0.35, seat);\n    track.at(d, probe);\n    matrix.compose(seat.setY(seat.y + height + 0.02), probe.rotation, one);\n    edgeStrip.setMatrixAt(i, matrix);\n  }\n  edgeStrip.instanceMatrix.needsUpdate = true;\n  group.add(edgeStrip);\n\n  // Door markings, one per door of the train that stops here.\n  const doorMarks: Vector3[] = [];\n  const offsets = options.doorOffsets ?? [];\n  if (offsets.length) {\n    const markGeometry = new BoxGeometry(1.3, 0.03, 0.5);\n    const markMaterial = new MeshStandardMaterial({ color: 0xf2c14e, roughness: 0.7 });\n    const marks = new InstancedMesh(markGeometry, markMaterial, offsets.length);\n    marks.name = 'door-marks';\n    for (const [i, offset] of offsets.entries()) {\n      const d = stopMark + offset;\n      const at = place(d, inner + 1.1);\n      track.at(d, probe);\n      matrix.compose(at.clone().setY(at.y + height + 0.03), probe.rotation, one);\n      marks.setMatrixAt(i, matrix);\n      doorMarks.push(place(d, inner + 0.2).setY(at.y + height));\n    }\n    marks.instanceMatrix.needsUpdate = true;\n    group.add(marks);\n  }\n\n  // Canopy: posts and a roof over the middle third, where people wait.\n  if (options.canopy ?? true) {\n    const cover = Math.min(span * 0.55, 44);\n    const mid = (from + to) / 2;\n    const postCount = Math.max(2, Math.round(cover / 8));\n    const postGeometry = new CylinderGeometry(0.09, 0.09, 3.2, 8);\n    const posts = new InstancedMesh(postGeometry, steel, postCount * 2);\n    posts.name = 'canopy-posts';\n    let n = 0;\n    for (let i = 0; i < postCount; i++) {\n      const d = mid - cover / 2 + (i / Math.max(1, postCount - 1)) * cover;\n      for (const lateral of [inner + 1.3, inner + width - 1.3]) {\n        place(d, lateral, seat);\n        matrix.compose(seat.setY(seat.y + height + 1.6), new Quaternion(), one);\n        posts.setMatrixAt(n++, matrix);\n      }\n    }\n    posts.instanceMatrix.needsUpdate = true;\n    group.add(posts);\n\n    const roofSections = Math.max(1, Math.round(cover / 12));\n    const roofGeometry = new BoxGeometry(width - 1.6, 0.16, cover / roofSections + 0.04);\n    const roof = new InstancedMesh(roofGeometry, steel, roofSections);\n    roof.name = 'canopy-roof';\n    for (let i = 0; i < roofSections; i++) {\n      const d = mid - cover / 2 + ((i + 0.5) / roofSections) * cover;\n      place(d, inner + width / 2, seat);\n      track.at(d, probe);\n      matrix.compose(seat.setY(seat.y + height + 3.25), probe.rotation, one);\n      roof.setMatrixAt(i, matrix);\n    }\n    roof.instanceMatrix.needsUpdate = true;\n    group.add(roof);\n  }\n\n  // Benches, facing the track, with a slot each — this is where ANIMA sits.\n  //\n  // Instanced, because they scale with the platform: a 390 m platform has\n  // fifteen of them and one Mesh each cost fifteen draw calls. Caught by this\n  // module's own test, which is the point of having written it.\n  const slots: PropSlot[] = [];\n  const benchCount = Math.max(1, Math.floor(span / 26));\n  const benches = new InstancedMesh(new BoxGeometry(0.55, 0.12, 1.8), kerb, benchCount);\n  benches.name = 'benches';\n  for (let i = 0; i < benchCount; i++) {\n    const d = from + ((i + 0.5) / benchCount) * span;\n    const at = place(d, inner + width - 1.5);\n    track.at(d, probe);\n    seat.copy(at).setY(at.y + height + 0.45);\n    matrix.compose(seat, probe.rotation, one);\n    benches.setMatrixAt(i, matrix);\n    // The slot anchor is an Object3D, not a mesh, so seating stays per-bench\n    // while the rendering stays one call.\n    slots.push(createSlot('seat', 'sit', group, seat.x, seat.y, seat.z));\n  }\n  benches.instanceMatrix.needsUpdate = true;\n  group.add(benches);\n\n  // The running-in board: the station's name, carved, in the embedded font.\n  if (options.name) {\n    const at = place((from + to) / 2, inner + width - 0.7);\n    track.at((from + to) / 2, probe);\n    const board = new Mesh(new BoxGeometry(0.16, 0.9, 5.4), steel);\n    board.position.copy(at).setY(at.y + height + 2.1);\n    board.quaternion.copy(probe.rotation);\n    board.name = 'running-in-board';\n    group.add(board);\n    const letters = buildTextGeometry(options.name, { size: 0.42, depth: 0.05, align: 'center' });\n    const text = new Mesh(\n      letters.geometry,\n      new MeshStandardMaterial({ color: 0xf5f2ea, roughness: 0.8 })\n    );\n    text.position.copy(board.position);\n    text.quaternion.copy(probe.rotation);\n    text.translateZ(0);\n    text.translateX(-sideSign * 0.1);\n    text.rotateY(-Math.PI / 2);\n    text.name = 'station-name';\n    group.add(text);\n  }\n\n  const edge = { from: place(from, inner), to: place(to, inner) };\n\n  return {\n    object: group,\n    obstacleRadius: 0, // you walk on a platform, you do not steer round it\n    slots,\n    stopMark,\n    doorMarks,\n    edge,\n    from,\n    to,\n    dispose(): void {\n      group.traverse((o) => {\n        const mesh = o as Mesh;\n        if (mesh.geometry) mesh.geometry.dispose();\n      });\n      paving.dispose();\n      kerb.dispose();\n      steel.dispose();\n    },\n  };\n}\n","import {\n  BoxGeometry,\n  ConeGeometry,\n  CylinderGeometry,\n  Group,\n  InstancedMesh,\n  Matrix4,\n  Mesh,\n  MeshStandardMaterial,\n  Object3D,\n  Quaternion,\n  SphereGeometry,\n  Vector3,\n  type BufferGeometry,\n  type Material,\n} from 'three';\nimport { Rng } from '../core/random';\nimport { createSurface } from '../materials/surface';\nimport type { Prop } from '../core/types';\n\n/**\n * Ammunition — the whole supply chain, not a shelf of models.\n *\n * A round is never just a round. The same cartridge is a thing in a crate, a\n * thing in a magazine, a thing in a hand and a case on the floor, and a game\n * that wants ammunition wants all four or none of them. So this module is\n * organised by STATE rather than by object:\n *\n *   stored   `createAmmoBox`   — sealed or open, rounds visible inside\n *   ready    `createMagazine`  `createBelt`  `createQuiver`  `createRack`\n *   carried  `createRound`     — one, `Holdable`, in a hand\n *   spent    `createCasing`    — brass on the ground, links, an empty box\n *\n * and every one of them is DERIVED from a single measured spec per kind. The\n * magazine is as long as its rounds are, the belt's link pitch is the case\n * head diameter, the crate's stack count falls out of the crate's inside\n * dimensions divided by the round. Author forty models by hand and forty\n * models drift; author one table and a 12.7 mm belt is visibly heavier than a\n * 5.56 mm one because it *is*.\n *\n * ## The handshake that matters\n *\n * `ballisticsOf(kind)` returns exactly what GAMA's `Projectiles` and\n * `Missiles` want — muzzle velocity, drop, tracer size and colour. The same\n * table that decides how long the cartridge model is decides how fast it\n * flies and how far it falls. That is the point of putting them together:\n * a game cannot make the prop and the projectile disagree, because there is\n * only one number.\n *\n * ```ts\n * const b = ballisticsOf('rifle');\n * const shots = new Projectiles({ gravity: b.gravity, size: b.size, color: b.color });\n * shots.fire(muzzle, aim.multiplyScalar(b.speed));\n * mag.setCount(mag.count - 1);            // the belt/magazine visibly empties\n * ```\n *\n * ## Instancing is not an optimisation here, it is the feature\n *\n * A 200-link belt is 200 rounds. Built as meshes that is 400 draw calls for\n * one prop and the geometry gate refuses it — correctly. Every container\n * renders its rounds as ONE `InstancedMesh` per part, and `setCount` rewrites\n * instance matrices rather than adding or removing anything. A magazine that\n * empties therefore costs the same as a full one, which is what lets a game\n * put a belt on every gunner in a firefight.\n */\n\n/** A quantity of one kind of ammunition, in the state a game finds it in. */\nexport type AmmoKind =\n  // Small arms — carried by a person, fed from magazines and belts.\n  | 'pistol'\n  | 'rifle'\n  | 'shotgun'\n  | 'heavy-mg'\n  // Crew-served and vehicle weapons — fed by hand from racks and boxes.\n  | 'autocannon'\n  | 'tank'\n  | 'artillery'\n  | 'mortar'\n  // Aviation and naval ordnance — hung, racked or tubed, never \"loaded\".\n  | 'rocket'\n  | 'missile'\n  | 'bomb'\n  | 'torpedo'\n  | 'depth-charge'\n  // Thrown, and launched off a muzzle.\n  | 'grenade'\n  | 'rifle-grenade'\n  // Smoothbore anti-personnel loads. Same bore as round shot, different load\n  // entirely — which is the point of them being separate kinds rather than a\n  // flag on the cannonball.\n  | 'canister'\n  | 'grapeshot'\n  // Pre-modern. The same four states, a thousand years earlier.\n  | 'arrow'\n  | 'bolt'\n  | 'sling'\n  | 'cannonball'\n  | 'ballista';\n\nexport const AMMO_KINDS: AmmoKind[] = [\n  'pistol', 'rifle', 'shotgun', 'heavy-mg',\n  'autocannon', 'tank', 'artillery', 'mortar',\n  'rocket', 'missile', 'bomb', 'torpedo', 'depth-charge',\n  'grenade', 'rifle-grenade',\n  'canister', 'grapeshot',\n  'arrow', 'bolt', 'sling', 'cannonball', 'ballista',\n];\n\n/**\n * How a round is put together, which decides how it is drawn.\n *\n * `case` is the material story and `head` is the silhouette, and they are\n * separate because they vary independently: a tank round is a brass case with\n * a fin-stabilised dart in it, an artillery shell is a bagged charge with no\n * case at all, and a crossbow bolt is neither.\n */\nexport type CaseKind = 'brass' | 'steel' | 'plastic' | 'bagged' | 'none';\nexport type HeadKind =\n  | 'spitzer'   // pointed jacketed bullet\n  | 'ball'      // round-nose\n  | 'shot'      // a shotgun's crimped plastic hull\n  | 'dart'      // fin-stabilised sub-calibre penetrator\n  | 'shell'     // ogive artillery/tank shell\n  | 'finned'    // mortar bomb, aircraft bomb, torpedo\n  | 'sphere'    // cannonball, sling stone, grenade body\n  | 'shaft'     // arrow, bolt, ballista bolt\n  | 'tin'       // canister: a thin can of musket balls, bore-diameter\n  | 'stand';    // grapeshot: balls tiered around a spindle on a base plate\n\n/** Everything about one kind, measured once. */\nexport interface AmmoSpec {\n  /** Projectile diameter, metres. The number everything else is scaled from. */\n  calibre: number;\n  /** Overall length of the complete round, metres. */\n  length: number;\n  /** Mass of the complete round, kilograms. */\n  mass: number;\n  /**\n   * Muzzle velocity, m/s. Zero for anything not launched from a barrel — a\n   * bomb is dropped, a grenade is thrown, a depth charge is rolled. A game\n   * reading zero here is being told \"you supply the launch\", which is the\n   * honest answer rather than a made-up number.\n   */\n  muzzle: number;\n  case: CaseKind;\n  head: HeadKind;\n  /** How many fit in one standard container of the kind below. */\n  perContainer: number;\n  /** Which ready-state container this kind actually ships in. */\n  container: 'magazine' | 'belt' | 'quiver' | 'rack' | 'box';\n  /** Tracer / body colour, for both the model and the projectile. */\n  color: number;\n  label: string;\n}\n\n/**\n * The table.\n *\n * Real calibres and real masses, because the whole value of deriving the\n * containers is lost if the source numbers are invented: a 12.7 mm belt is\n * supposed to look punishing next to a 5.56 mm one, and it only does if the\n * two are actually 12.7 and 5.56.\n *\n * Muzzle velocities are the honest ones too — an APFSDS dart really does\n * leave a tank gun at 1750 m/s, and a game that gives it 300 because that\n * looked nice in the editor has thrown away the only reason to have a table.\n */\nexport const AMMO: Record<AmmoKind, AmmoSpec> = {\n  pistol: {\n    calibre: 0.009, length: 0.0295, mass: 0.012, muzzle: 375,\n    case: 'brass', head: 'ball', perContainer: 15, container: 'magazine',\n    color: 0xc9a227, label: '9×19 mm pistol',\n  },\n  rifle: {\n    calibre: 0.00556, length: 0.0575, mass: 0.012, muzzle: 920,\n    case: 'brass', head: 'spitzer', perContainer: 30, container: 'magazine',\n    color: 0xc9a227, label: '5.56×45 mm rifle',\n  },\n  shotgun: {\n    calibre: 0.01852, length: 0.0700, mass: 0.045, muzzle: 400,\n    case: 'plastic', head: 'shot', perContainer: 8, container: 'magazine',\n    color: 0xb03a2e, label: '12-gauge shell',\n  },\n  'heavy-mg': {\n    calibre: 0.0127, length: 0.1384, mass: 0.117, muzzle: 890,\n    case: 'brass', head: 'spitzer', perContainer: 100, container: 'belt',\n    color: 0xb8952f, label: '12.7×99 mm heavy MG',\n  },\n  autocannon: {\n    calibre: 0.030, length: 0.290, mass: 0.84, muzzle: 1080,\n    case: 'steel', head: 'shell', perContainer: 60, container: 'belt',\n    color: 0x8a8f98, label: '30 mm autocannon',\n  },\n  tank: {\n    calibre: 0.120, length: 0.982, mass: 21.0, muzzle: 1750,\n    case: 'steel', head: 'dart', perContainer: 6, container: 'rack',\n    color: 0x6f7680, label: '120 mm APFSDS',\n  },\n  artillery: {\n    calibre: 0.155, length: 0.860, mass: 43.5, muzzle: 827,\n    case: 'bagged', head: 'shell', perContainer: 8, container: 'rack',\n    color: 0x5f6a52, label: '155 mm howitzer shell',\n  },\n  mortar: {\n    calibre: 0.081, length: 0.480, mass: 4.2, muzzle: 260,\n    case: 'none', head: 'finned', perContainer: 6, container: 'box',\n    color: 0x4f5b45, label: '81 mm mortar bomb',\n  },\n  rocket: {\n    calibre: 0.070, length: 1.060, mass: 11.0, muzzle: 700,\n    case: 'none', head: 'finned', perContainer: 19, container: 'rack',\n    color: 0x6b6f5c, label: '70 mm folding-fin rocket',\n  },\n  missile: {\n    calibre: 0.178, length: 2.870, mass: 86.0, muzzle: 0,\n    case: 'none', head: 'finned', perContainer: 4, container: 'rack',\n    color: 0xd8d5cc, label: 'air-to-air missile',\n  },\n  bomb: {\n    calibre: 0.273, length: 2.210, mass: 227.0, muzzle: 0,\n    case: 'none', head: 'finned', perContainer: 6, container: 'rack',\n    color: 0x5c6b52, label: '500 lb general-purpose bomb',\n  },\n  torpedo: {\n    calibre: 0.533, length: 6.400, mass: 1600.0, muzzle: 0,\n    case: 'none', head: 'finned', perContainer: 4, container: 'rack',\n    color: 0x3f4a52, label: '533 mm heavyweight torpedo',\n  },\n  'depth-charge': {\n    calibre: 0.450, length: 0.710, mass: 190.0, muzzle: 0,\n    case: 'none', head: 'shell', perContainer: 8, container: 'rack',\n    color: 0x39434a, label: 'depth charge',\n  },\n  grenade: {\n    calibre: 0.058, length: 0.099, mass: 0.4, muzzle: 0,\n    case: 'none', head: 'sphere', perContainer: 6, container: 'box',\n    color: 0x4a5340, label: 'fragmentation grenade',\n  },\n  'rifle-grenade': {\n    calibre: 0.040, length: 0.430, mass: 0.60, muzzle: 75,\n    case: 'none', head: 'finned', perContainer: 4, container: 'box',\n    color: 0x4d5545, label: 'rifle grenade',\n  },\n  // Canister and grape are the same bore as round shot and nothing like it in\n  // effect: a tin of musket balls and a tiered stand of them, both of which\n  // come apart at the muzzle. Muzzle velocity is lower than solid shot\n  // because the load is lighter but far less efficient in the bore.\n  canister: {\n    calibre: 0.110, length: 0.180, mass: 3.2, muzzle: 300,\n    case: 'none', head: 'tin', perContainer: 12, container: 'rack',\n    color: 0x9a8f6f, label: 'canister shot',\n  },\n  grapeshot: {\n    calibre: 0.110, length: 0.230, mass: 4.5, muzzle: 320,\n    case: 'none', head: 'stand', perContainer: 10, container: 'rack',\n    color: 0x3a3d42, label: 'stand of grape',\n  },\n  arrow: {\n    calibre: 0.008, length: 0.750, mass: 0.030, muzzle: 55,\n    case: 'none', head: 'shaft', perContainer: 24, container: 'quiver',\n    color: 0x8a6a43, label: 'arrow',\n  },\n  bolt: {\n    calibre: 0.009, length: 0.330, mass: 0.055, muzzle: 90,\n    case: 'none', head: 'shaft', perContainer: 18, container: 'quiver',\n    color: 0x7d6039, label: 'crossbow bolt',\n  },\n  sling: {\n    calibre: 0.035, length: 0.035, mass: 0.050, muzzle: 40,\n    case: 'none', head: 'sphere', perContainer: 20, container: 'box',\n    color: 0x8c8878, label: 'sling stone',\n  },\n  cannonball: {\n    calibre: 0.110, length: 0.110, mass: 5.4, muzzle: 340,\n    case: 'none', head: 'sphere', perContainer: 12, container: 'rack',\n    color: 0x3a3d42, label: 'round shot',\n  },\n  ballista: {\n    calibre: 0.030, length: 1.300, mass: 1.1, muzzle: 90,\n    case: 'none', head: 'shaft', perContainer: 10, container: 'quiver',\n    color: 0x6f5a3a, label: 'ballista bolt',\n  },\n};\n\n/**\n * What a projectile system needs, from the same table that shaped the model.\n *\n * Structurally what GAMA's `Projectiles` options and `fire()` want, and\n * deliberately not an import of them — the trilogy composes on shapes, not\n * packages. A game that never draws a single round can still use this to make\n * its shots behave like the calibre it claims they are.\n */\nexport interface Ballistics {\n  /** Muzzle velocity, m/s. Zero means this is not launched from a barrel. */\n  speed: number;\n  /** Downward pull to fly it under, m/s². */\n  gravity: number;\n  /** A sensible tracer radius: visible, and proportional to the calibre. */\n  size: number;\n  color: number;\n  mass: number;\n  /** Rounds in one full standard container. */\n  perContainer: number;\n}\n\n/**\n * Ballistics for a kind.\n *\n * `gravity` is the interesting one. Everything unpowered gets 9.81 — a bullet\n * drops exactly as hard as a cannonball does, and pretending otherwise is the\n * single most common lie in game ballistics. What differs is TIME OF FLIGHT,\n * and that falls out of `speed` on its own. Powered rounds are the exception\n * and get a reduced figure, because a rocket under thrust genuinely does not\n * fall like a stone; a missile with its own guidance gets zero, since whatever\n * flies it owns its path.\n */\nexport function ballisticsOf(\n  kind: AmmoKind,\n  options: {\n    /**\n     * Charge increments loaded, for separate-loading kinds. Omit for a full\n     * charge. Ignored by anything that is not bag-loaded, because a rifle\n     * round's propellant is not a decision anybody makes at the gun.\n     */\n    increments?: number;\n    /** Increments in a full charge. Default 7. */\n    chargeCapacity?: number;\n  } = {}\n): Ballistics {\n  const spec = AMMO[kind];\n  const powered = kind === 'rocket' || kind === 'missile' || kind === 'torpedo';\n  const cap = options.chargeCapacity ?? 7;\n  const speed =\n    spec.case === 'bagged' && options.increments !== undefined\n      ? chargeVelocity(kind, options.increments, cap)\n      : spec.muzzle;\n  return {\n    speed,\n    gravity: kind === 'missile' || kind === 'torpedo' ? 0 : powered ? 3.2 : 9.81,\n    // Real calibres are millimetres and a true-to-life 5.56 mm tracer is one\n    // pixel at any useful range, so a floor is needed. It has to be a floor\n    // PLUS a proportion, not a `Math.max` of the two: a max flattens every\n    // small arm in the set to exactly the same size, which is the whole range\n    // a player is ever asked to tell apart. Written as a max first, and the\n    // test that says a 12.7 draws bigger than a 5.56 caught it — the comment\n    // claimed the behaviour the code did not have.\n    size: 0.05 + spec.calibre * 0.6,\n    color: spec.color,\n    mass: spec.mass,\n    perContainer: spec.perContainer,\n  };\n}\n\n/** A one-line description, for editors, tooltips and debug overlays. */\nexport function describeAmmo(kind: AmmoKind): string {\n  const s = AMMO[kind];\n  const v = s.muzzle > 0 ? `${s.muzzle} m/s` : 'not gun-launched';\n  return `${s.label} — ${(s.calibre * 1000).toFixed(1)} mm, ${s.mass} kg, ${v}, ${s.perContainer} per ${s.container}`;\n}\n\n// ── materials ────────────────────────────────────────────────────────────\n// One cache per (kind, role). Two magazines of the same calibre share every\n// material they have; the geometry gate counts distinct material OBJECTS, and\n// a set this size would otherwise allocate hundreds of identical ones.\n\nconst materials = new Map<string, MeshStandardMaterial>();\nconst shared = (key: string, make: () => MeshStandardMaterial): MeshStandardMaterial => {\n  let m = materials.get(key);\n  if (!m) {\n    m = make();\n    materials.set(key, m);\n  }\n  return m;\n};\n\nconst CASE_COLOR: Record<CaseKind, number> = {\n  brass: 0xc9a227,\n  steel: 0x8a8f98,\n  plastic: 0xb03a2e,\n  bagged: 0xd8d2bd,\n  none: 0x6f7680,\n};\n\nconst caseMaterial = (c: CaseKind): MeshStandardMaterial =>\n  shared(`case:${c}`, () =>\n    new MeshStandardMaterial({\n      color: CASE_COLOR[c],\n      // Brass and steel are the only genuinely specular things here. A cloth\n      // powder bag and a plastic hull are not, and giving all five the same\n      // finish is what makes a set like this read as one grey mass.\n      metalness: c === 'brass' || c === 'steel' ? 0.85 : 0.05,\n      roughness: c === 'brass' ? 0.28 : c === 'steel' ? 0.38 : c === 'bagged' ? 0.92 : 0.7,\n    })\n  );\n\nconst bodyMaterial = (kind: AmmoKind): MeshStandardMaterial =>\n  shared(`body:${kind}`, () =>\n    new MeshStandardMaterial({\n      color: AMMO[kind].color,\n      metalness: AMMO[kind].head === 'shaft' ? 0.05 : 0.55,\n      roughness: AMMO[kind].head === 'shaft' ? 0.85 : 0.5,\n    })\n  );\n\nconst TIP = 0xb5651d; // copper jacket / driving band\nconst tipMaterial = (): MeshStandardMaterial =>\n  shared('tip', () => new MeshStandardMaterial({ color: TIP, metalness: 0.8, roughness: 0.35 }));\n\nconst steelMaterial = (): MeshStandardMaterial =>\n  shared('steel', () => new MeshStandardMaterial({ color: 0x55595f, metalness: 0.8, roughness: 0.45 }));\n\nconst fletchMaterial = (): MeshStandardMaterial =>\n  shared('fletch', () => new MeshStandardMaterial({ color: 0xd8d4c8, metalness: 0, roughness: 0.95 }));\n\n// ── the round itself ─────────────────────────────────────────────────────\n\n/**\n * The parts of one round, as geometry and a material, in Z-forward layout.\n *\n * Returned as parts rather than a mesh because EVERY container needs them\n * instanced: a belt draws its hundred rounds as one InstancedMesh per part,\n * and it can only do that if the parts are separable and shared. Building a\n * round as a finished `Group` and cloning it per link is the version of this\n * module that the geometry gate rejects.\n */\ninterface RoundParts {\n  geometry: BufferGeometry;\n  material: Material;\n  /** Offset along +Z from the round's base. */\n  z: number;\n  /** Rotation to apply, if the part is not a Z-aligned cylinder. */\n  tilt?: Quaternion;\n}\n\nconst geometries = new Map<string, BufferGeometry>();\nconst geo = <T extends BufferGeometry>(key: string, make: () => T): T => {\n  let g = geometries.get(key) as T | undefined;\n  if (!g) {\n    g = make();\n    geometries.set(key, g);\n  }\n  return g;\n};\n\n/** Z-forward: `CylinderGeometry` builds along Y, so everything is tipped. */\nconst LIE = new Quaternion().setFromAxisAngle(new Vector3(1, 0, 0), Math.PI / 2);\n\nfunction roundParts(kind: AmmoKind): RoundParts[] {\n  const s = AMMO[kind];\n  const r = s.calibre / 2;\n  const L = s.length;\n  const parts: RoundParts[] = [];\n  const seg = s.calibre > 0.05 ? 12 : 8;\n\n  switch (s.head) {\n    case 'spitzer':\n    case 'ball': {\n      // Case, then the shoulder, then the bullet. The case is most of the\n      // length of a rifle round and almost none of a pistol round, which is\n      // the whole visual difference between the two.\n      const caseLen = kind === 'pistol' ? L * 0.64 : L * 0.72;\n      const bulletLen = L - caseLen;\n      parts.push({\n        geometry: geo(`case:${kind}`, () => new CylinderGeometry(r * 1.08, r * 1.14, caseLen, seg)),\n        material: caseMaterial(s.case),\n        z: caseLen / 2,\n        tilt: LIE,\n      });\n      parts.push({\n        geometry: geo(`bullet:${kind}`, () =>\n          s.head === 'spitzer'\n            ? new ConeGeometry(r, bulletLen, seg)\n            : new CylinderGeometry(r * 0.72, r, bulletLen, seg)\n        ),\n        material: tipMaterial(),\n        z: caseLen + bulletLen / 2,\n        tilt: LIE,\n      });\n      break;\n    }\n    case 'shot': {\n      // A hull and a brass head — the two-tone that makes a shotgun shell\n      // instantly recognisable at any distance.\n      const headLen = L * 0.16;\n      parts.push({\n        geometry: geo(`hull:${kind}`, () => new CylinderGeometry(r, r, L - headLen, seg)),\n        material: caseMaterial('plastic'),\n        z: headLen + (L - headLen) / 2,\n        tilt: LIE,\n      });\n      parts.push({\n        geometry: geo(`shead:${kind}`, () => new CylinderGeometry(r * 1.05, r * 1.05, headLen, seg)),\n        material: caseMaterial('brass'),\n        z: headLen / 2,\n        tilt: LIE,\n      });\n      break;\n    }\n    case 'dart': {\n      // A big case with a thin sub-calibre dart in it. The dart being much\n      // narrower than the bore is the entire point of the round and the only\n      // thing that tells it apart from a shell.\n      const caseLen = L * 0.62;\n      parts.push({\n        geometry: geo(`case:${kind}`, () => new CylinderGeometry(r * 0.98, r, caseLen, seg)),\n        material: caseMaterial(s.case),\n        z: caseLen / 2,\n        tilt: LIE,\n      });\n      parts.push({\n        geometry: geo(`dart:${kind}`, () => new CylinderGeometry(r * 0.22, r * 0.26, L - caseLen, seg)),\n        material: steelMaterial(),\n        z: caseLen + (L - caseLen) / 2,\n        tilt: LIE,\n      });\n      parts.push({\n        geometry: geo(`darttip:${kind}`, () => new ConeGeometry(r * 0.22, L * 0.09, seg)),\n        material: steelMaterial(),\n        z: L + L * 0.045,\n        tilt: LIE,\n      });\n      break;\n    }\n    case 'shell': {\n      const bodyLen = L * 0.72;\n      parts.push({\n        geometry: geo(`sbody:${kind}`, () => new CylinderGeometry(r, r, bodyLen, seg)),\n        material: bodyMaterial(kind),\n        z: bodyLen / 2,\n        tilt: LIE,\n      });\n      parts.push({\n        geometry: geo(`sogive:${kind}`, () => new ConeGeometry(r, L - bodyLen, seg)),\n        material: bodyMaterial(kind),\n        z: bodyLen + (L - bodyLen) / 2,\n        tilt: LIE,\n      });\n      // The driving band: a copper ring near the base. It is 3 mm of geometry\n      // and it is the difference between \"a shell\" and \"a grey cylinder\".\n      parts.push({\n        geometry: geo(`band:${kind}`, () => new CylinderGeometry(r * 1.06, r * 1.06, L * 0.045, seg)),\n        material: tipMaterial(),\n        z: bodyLen * 0.18,\n        tilt: LIE,\n      });\n      break;\n    }\n    case 'finned': {\n      const bodyLen = L * 0.66;\n      const noseLen = L * 0.2;\n      parts.push({\n        geometry: geo(`fbody:${kind}`, () => new CylinderGeometry(r, r, bodyLen, seg)),\n        material: bodyMaterial(kind),\n        z: L - bodyLen / 2 - noseLen,\n        tilt: LIE,\n      });\n      parts.push({\n        geometry: geo(`fnose:${kind}`, () => new ConeGeometry(r, noseLen, seg)),\n        material: bodyMaterial(kind),\n        z: L - noseLen / 2,\n        tilt: LIE,\n      });\n      // Four fins at the tail, as one cross-shaped part so the instancing\n      // stays at one draw rather than four.\n      parts.push({\n        geometry: geo(`fins:${kind}`, () => new BoxGeometry(r * 2.6, r * 0.12, L * 0.16)),\n        material: steelMaterial(),\n        z: L * 0.09,\n      });\n      parts.push({\n        geometry: geo(`finsB:${kind}`, () => new BoxGeometry(r * 0.12, r * 2.6, L * 0.16)),\n        material: steelMaterial(),\n        z: L * 0.09,\n      });\n      break;\n    }\n    case 'sphere': {\n      parts.push({\n        geometry: geo(`ball:${kind}`, () => new SphereGeometry(r, seg, Math.max(6, seg - 2))),\n        material: bodyMaterial(kind),\n        z: r,\n      });\n      if (kind === 'grenade') {\n        // The spoon and the ring. Without them a grenade is a pebble.\n        parts.push({\n          geometry: geo('spoon', () => new BoxGeometry(r * 0.3, r * 0.16, r * 1.8)),\n          material: steelMaterial(),\n          z: r,\n        });\n      }\n      break;\n    }\n    case 'tin': {\n      // A thin sheet-metal can, bore diameter, with a lid seam. It flies for\n      // about a metre and then is not a projectile any more.\n      parts.push({\n        geometry: geo(`tin:${kind}`, () => new CylinderGeometry(r, r, L, seg)),\n        material: bodyMaterial(kind),\n        z: L / 2,\n        tilt: LIE,\n      });\n      parts.push({\n        geometry: geo(`tinlid:${kind}`, () => new CylinderGeometry(r * 1.04, r * 1.04, L * 0.09, seg)),\n        material: steelMaterial(),\n        z: L * 0.955,\n        tilt: LIE,\n      });\n      // A sabot disc at the base — what the powder actually pushes on.\n      parts.push({\n        geometry: geo(`tinbase:${kind}`, () => new CylinderGeometry(r, r, L * 0.12, seg)),\n        material: fletchMaterial(),\n        z: L * 0.06,\n        tilt: LIE,\n      });\n      break;\n    }\n    case 'stand': {\n      // Base plate, spindle, and three tiers of balls around it. Three tiers\n      // rather than the nine individual balls of the real thing: each ball is\n      // its own PART, and a part is an InstancedMesh in every container that\n      // holds one, so nine of them would cost a rack nine draw calls to say\n      // something three already say.\n      const ballR = r * 0.3;\n      parts.push({\n        geometry: geo(`plate:${kind}`, () => new CylinderGeometry(r, r, L * 0.08, seg)),\n        material: fletchMaterial(),\n        z: L * 0.04,\n        tilt: LIE,\n      });\n      parts.push({\n        geometry: geo(`spindle:${kind}`, () => new CylinderGeometry(r * 0.14, r * 0.14, L * 0.92, 6)),\n        material: steelMaterial(),\n        z: L * 0.54,\n        tilt: LIE,\n      });\n      for (let t = 0; t < 3; t++) {\n        parts.push({\n          geometry: geo(`grape:${kind}:${t}`, () => new SphereGeometry(ballR, 8, 6)),\n          material: bodyMaterial(kind),\n          z: L * (0.24 + t * 0.28),\n          tilt: LIE,\n        });\n      }\n      break;\n    }\n    case 'shaft': {\n      const shaftLen = L * 0.86;\n      parts.push({\n        geometry: geo(`shaft:${kind}`, () => new CylinderGeometry(r * 0.5, r * 0.5, shaftLen, 6)),\n        material: bodyMaterial(kind),\n        z: shaftLen / 2,\n        tilt: LIE,\n      });\n      parts.push({\n        geometry: geo(`head:${kind}`, () => new ConeGeometry(r, L * 0.1, 6)),\n        material: steelMaterial(),\n        z: shaftLen + L * 0.05,\n        tilt: LIE,\n      });\n      // Fletching. A crossbow bolt and a ballista bolt have it too — they are\n      // not miniature spears, they are short arrows.\n      parts.push({\n        geometry: geo(`fletch:${kind}`, () => new BoxGeometry(r * 2.4, r * 0.1, L * 0.13)),\n        material: fletchMaterial(),\n        z: L * 0.08,\n      });\n      break;\n    }\n  }\n  return parts;\n}\n\n/** Triangles in one round, for anyone budgeting a container. */\nexport function roundTriangles(kind: AmmoKind): number {\n  return roundParts(kind).reduce((n, p) => n + (p.geometry.index?.count ?? 0) / 3, 0);\n}\n\n// ── the four states ──────────────────────────────────────────────────────\n\nexport interface RoundOptions {\n  seed?: number;\n  /** Scale the whole round. Real calibres are small; a HUD wants them bigger. */\n  scale?: number;\n}\n\n/**\n * One round, `Holdable` and `Prop`.\n *\n * Laid out along +Z with its base at the origin, so a game can point it the\n * way it is going without an offset, and ANIMA's `Carry` can hold it.\n */\nexport interface Round extends Prop {\n  kind: AmmoKind;\n  /** ANIMA's `Holdable` carry style — small rounds go in one hand. */\n  carry: 'side' | 'crate';\n  /** Length along +Z, after scale. */\n  length: number;\n  ballistics: Ballistics;\n}\n\nexport function createRound(kind: AmmoKind, options: RoundOptions = {}): Round {\n  const scale = options.scale ?? 1;\n  const group = new Group();\n  group.name = `round-${kind}`;\n  const parts = roundParts(kind);\n  for (const part of parts) {\n    const mesh = new Mesh(part.geometry, part.material);\n    mesh.position.z = part.z;\n    if (part.tilt) mesh.quaternion.copy(part.tilt);\n    mesh.castShadow = true;\n    group.add(mesh);\n  }\n  group.scale.setScalar(scale);\n  const s = AMMO[kind];\n  return {\n    object: group,\n    kind,\n    // A torpedo is not going in anybody's hand. The threshold is the same one\n    // ANIMA uses to decide a two-handed carry, expressed here in metres of\n    // round rather than as a guess per kind.\n    carry: s.length > 0.6 || s.mass > 12 ? 'crate' : 'side',\n    length: s.length * scale,\n    obstacleRadius: s.length > 1 ? (s.length * scale) / 2 : 0,\n    ballistics: ballisticsOf(kind),\n  };\n}\n\n/**\n * Anything holding a countable number of rounds.\n *\n * A magazine, a belt, a quiver and a shell rack are the same object as far as\n * a game is concerned: they hold N of something, N goes down, and the model\n * has to show it. One interface, so a HUD or a reload routine written against\n * a rifle magazine works on a howitzer's ready rack without knowing.\n */\nexport interface Countable extends Prop {\n  kind: AmmoKind;\n  readonly capacity: number;\n  readonly count: number;\n  /** Show `n` rounds. Clamped to `[0, capacity]`. Returns the count set. */\n  setCount(n: number): number;\n  /** Take one. Returns whether there was one to take. */\n  consume(): boolean;\n}\n\n/**\n * Lay out `capacity` rounds and be able to hide any suffix of them.\n *\n * The one piece of machinery every container shares. Each part of the round\n * becomes one `InstancedMesh` of `capacity` instances; hiding a round means\n * writing a zero-scale matrix, so the draw count never changes and neither\n * does the allocation. `setCount` is a matrix write and an\n * `instanceMatrix.needsUpdate`, which is why a belt can empty every frame.\n */\nfunction stack(\n  parent: Group,\n  kind: AmmoKind,\n  capacity: number,\n  place: (i: number, out: Object3D) => void\n): (n: number) => void {\n  const parts = roundParts(kind);\n  const meshes: InstancedMesh[] = [];\n  for (const part of parts) {\n    const im = new InstancedMesh(part.geometry, part.material, Math.max(1, capacity));\n    im.frustumCulled = false;\n    im.castShadow = true;\n    // Named, so anything walking the graph can tell the COUNTED instances\n    // from the structure holding them. A bandolier's strap and a belt's links\n    // are instanced too and are not the thing the container counts.\n    im.name = 'counted';\n    parent.add(im);\n    meshes.push(im);\n  }\n  const slot = new Object3D();\n  const partNode = new Object3D();\n  const hidden = new Matrix4().makeScale(0, 0, 0);\n  // Scratch, not a clone per part per round. `setCount` runs on every shot\n  // fired; a 100-link belt of three-part rounds allocating a Matrix4 each\n  // would be 300 objects a trigger pull, which is a garbage collector's\n  // problem in exactly the frame a player is looking at.\n  const composed = new Matrix4();\n  const write = (n: number): void => {\n    for (let i = 0; i < capacity; i++) {\n      const on = i < n;\n      slot.position.set(0, 0, 0);\n      // `.rotation`, not `.quaternion` — a placer that sets a single Euler\n      // axis (`out.rotation.z = …`, which the belt does) leaves the other two\n      // holding the PREVIOUS round's values, and the Euler's onChange writes\n      // all three back into the quaternion. Resetting the quaternion alone\n      // looks like it clears the pose and does not.\n      slot.rotation.set(0, 0, 0);\n      slot.scale.setScalar(1);\n      if (on) place(i, slot);\n      slot.updateMatrix();\n      for (let p = 0; p < parts.length; p++) {\n        if (!on) {\n          meshes[p].setMatrixAt(i, hidden);\n          continue;\n        }\n        partNode.position.set(0, 0, parts[p].z);\n        if (parts[p].tilt) partNode.quaternion.copy(parts[p].tilt!);\n        else partNode.quaternion.identity();\n        partNode.scale.setScalar(1);\n        partNode.updateMatrix();\n        meshes[p].setMatrixAt(i, composed.copy(slot.matrix).multiply(partNode.matrix));\n      }\n    }\n    for (const m of meshes) m.instanceMatrix.needsUpdate = true;\n  };\n  return write;\n}\n\n/** Wrap a layout into the `Countable` contract. */\nfunction countable(\n  group: Group,\n  kind: AmmoKind,\n  capacity: number,\n  write: (n: number) => void,\n  obstacleRadius: number,\n  start: number\n): Countable {\n  let count = Math.max(0, Math.min(capacity, start));\n  write(count);\n  return {\n    object: group,\n    kind,\n    capacity,\n    get count() {\n      return count;\n    },\n    setCount(n: number) {\n      const next = Math.max(0, Math.min(capacity, Math.round(n)));\n      if (next !== count) {\n        count = next;\n        write(count);\n      }\n      return count;\n    },\n    consume() {\n      if (count <= 0) return false;\n      count--;\n      write(count);\n      return true;\n    },\n    obstacleRadius,\n  };\n}\n\nexport interface ContainerOptions {\n  seed?: number;\n  /** How many rounds to start with. Default: full. */\n  count?: number;\n  /** Override the container's capacity. Default: the kind's `perContainer`. */\n  capacity?: number;\n  scale?: number;\n}\n\n/**\n * A box magazine — the small-arms one, rounds staggered in a column.\n *\n * The body is sized from the rounds rather than the other way round: a\n * 30-round 5.56 magazine and an 8-round 12-gauge tube come out visibly\n * different because their contents are, and neither was drawn by hand.\n */\nexport function createMagazine(kind: AmmoKind, options: ContainerOptions = {}): Countable {\n  const s = AMMO[kind];\n  const capacity = options.capacity ?? s.perContainer;\n  const scale = options.scale ?? 1;\n  const group = new Group();\n  group.name = `magazine-${kind}`;\n\n  const pitch = s.calibre * 1.16;\n  const stackHeight = pitch * Math.ceil(capacity / 2) + s.calibre;\n  const shell = new Mesh(\n    geo(`magshell:${kind}:${capacity}`, () =>\n      new BoxGeometry(s.calibre * 1.5, stackHeight, s.length * 1.06)\n    ),\n    steelMaterial()\n  );\n  shell.position.y = stackHeight / 2 - stackHeight;\n  shell.castShadow = true;\n  group.add(shell);\n\n  // Rounds ride nose-forward in a double stack, alternating side to side.\n  const write = stack(group, kind, capacity, (i, out) => {\n    const row = Math.floor(i / 2);\n    const side = i % 2 === 0 ? -1 : 1;\n    out.position.set(side * s.calibre * 0.22, -row * pitch, -s.length / 2);\n  });\n\n  group.scale.setScalar(scale);\n  return countable(group, kind, capacity, write, s.length * 0.5 * scale, options.count ?? capacity);\n}\n\nexport interface BeltOptions extends ContainerOptions {\n  /** Curve the belt into a hanging catenary. Default true. */\n  drape?: boolean;\n}\n\n/**\n * A linked belt — machine-gun and autocannon feed.\n *\n * The link pitch is the case head diameter, so a 12.7 mm belt is genuinely\n * 40% coarser than a 5.56 one. `setCount` feeds it: rounds disappear from the\n * front, which is the direction a belt actually empties.\n */\nexport function createBelt(kind: AmmoKind, options: BeltOptions = {}): Countable {\n  const s = AMMO[kind];\n  const capacity = options.capacity ?? s.perContainer;\n  const scale = options.scale ?? 1;\n  const drape = options.drape ?? true;\n  const group = new Group();\n  group.name = `belt-${kind}`;\n\n  const pitch = s.calibre * 1.35;\n  const span = pitch * capacity;\n  // A hanging belt is a catenary, and a straight one is the tell that an\n  // ammunition set was drawn rather than laid out. Approximated as a\n  // parabola, which is indistinguishable over this span and far cheaper.\n  const sag = drape ? span * 0.16 : 0;\n  const at = (i: number): { x: number; y: number; slope: number } => {\n    const u = capacity <= 1 ? 0 : (i / (capacity - 1)) * 2 - 1; // -1..1\n    return { x: (u * span) / 2, y: -sag * (1 - u * u), slope: drape ? 2 * sag * u / (span / 2) : 0 };\n  };\n\n  const write = stack(group, kind, capacity, (i, out) => {\n    const p = at(i);\n    out.position.set(p.x, p.y, -s.length / 2);\n    // Rounds hang perpendicular to the belt, so they fan out around the\n    // curve. A belt whose rounds all point the same way looks like a comb.\n    out.rotation.z = Math.atan(p.slope);\n  });\n\n  // The links themselves — one instanced mesh, sharing the belt's own layout.\n  const linkGeo = geo(`link:${kind}`, () =>\n    new BoxGeometry(pitch * 0.92, s.calibre * 0.9, s.calibre * 0.55)\n  );\n  const links = new InstancedMesh(linkGeo, steelMaterial(), Math.max(1, capacity));\n  links.name = 'links';\n  links.frustumCulled = false;\n  group.add(links);\n  const node = new Object3D();\n  const hidden = new Matrix4().makeScale(0, 0, 0);\n  const writeLinks = (n: number): void => {\n    for (let i = 0; i < capacity; i++) {\n      if (i >= n) {\n        links.setMatrixAt(i, hidden);\n        continue;\n      }\n      const p = at(i);\n      node.position.set(p.x, p.y, 0);\n      node.rotation.set(0, 0, Math.atan(p.slope));\n      node.scale.setScalar(1);\n      node.updateMatrix();\n      links.setMatrixAt(i, node.matrix);\n    }\n    links.instanceMatrix.needsUpdate = true;\n  };\n\n  const both = (n: number): void => {\n    write(n);\n    writeLinks(n);\n  };\n  group.scale.setScalar(scale);\n  return countable(group, kind, capacity, both, (span / 2) * scale, options.count ?? capacity);\n}\n\n/**\n * A quiver — arrows, bolts, ballista shafts, nocks up.\n *\n * The only container whose rounds stand vertically, and the only one where\n * the count is read at a glance from outside, which is why archers count them\n * and riflemen do not.\n */\nexport function createQuiver(kind: AmmoKind, options: ContainerOptions = {}): Countable {\n  const s = AMMO[kind];\n  const capacity = options.capacity ?? s.perContainer;\n  const scale = options.scale ?? 1;\n  const rng = new Rng(options.seed ?? 3);\n  const group = new Group();\n  group.name = `quiver-${kind}`;\n\n  const radius = s.calibre * 3.4;\n  const bodyH = s.length * 0.45;\n  const body = new Mesh(\n    geo(`quivbody:${kind}`, () => new CylinderGeometry(radius, radius * 0.86, bodyH, 12, 1, true)),\n    createSurface('leather', { seed: options.seed ?? 3 })\n  );\n  body.position.y = bodyH / 2;\n  body.castShadow = true;\n  group.add(body);\n\n  // Shafts splay outward slightly, and each gets its own small lean — a\n  // bundle of parallel sticks reads as a bundle of sticks.\n  const leans = Array.from({ length: capacity }, () => ({\n    a: rng.range(0, Math.PI * 2),\n    r: rng.range(0.25, 0.95),\n    tilt: rng.range(0.02, 0.09),\n  }));\n  const write = stack(group, kind, capacity, (i, out) => {\n    const l = leans[i];\n    out.position.set(Math.cos(l.a) * radius * l.r * 0.7, 0, Math.sin(l.a) * radius * l.r * 0.7);\n    // Built along +Z; stand it up, then lean it out from the quiver's axis.\n    out.rotation.set(-Math.PI / 2 + l.tilt * Math.sin(l.a), l.tilt * Math.cos(l.a), 0);\n  });\n\n  group.scale.setScalar(scale);\n  return countable(group, kind, capacity, write, radius * scale, options.count ?? capacity);\n}\n\nexport interface RackOptions extends ContainerOptions {\n  /** Rounds per row. Default: the square-ish arrangement. */\n  perRow?: number;\n}\n\n/**\n * A ready rack — artillery shells stood on end, bombs on a trolley, torpedoes\n * in a cradle, round shot in a pyramid frame.\n *\n * The heavy end of the set, and the one a game actually walks past. Rounds\n * stand or lie according to what the real thing does: a 155 mm shell stands,\n * a torpedo does not, and the rule is the round's own aspect ratio rather\n * than a per-kind flag.\n */\nexport function createRack(kind: AmmoKind, options: RackOptions = {}): Countable {\n  const s = AMMO[kind];\n  const capacity = options.capacity ?? s.perContainer;\n  const scale = options.scale ?? 1;\n  const group = new Group();\n  group.name = `rack-${kind}`;\n\n  // Slender and short enough to stand on its base; otherwise it lies down.\n  const stands = s.length / s.calibre < 7 && s.length < 1.2;\n  const cell = stands ? s.calibre * 1.5 : s.calibre * 1.7;\n  const perRow = options.perRow ?? Math.max(1, Math.ceil(Math.sqrt(capacity)));\n  const rows = Math.ceil(capacity / perRow);\n  const w = perRow * cell;\n  const d = stands ? rows * cell : s.length * 1.05;\n\n  const frame = new Mesh(\n    geo(`rackframe:${kind}:${capacity}`, () => new BoxGeometry(w, s.calibre * 0.5, d)),\n    createSurface('wood', { seed: options.seed ?? 5 })\n  );\n  frame.position.y = -s.calibre * 0.25;\n  frame.receiveShadow = true;\n  group.add(frame);\n\n  const write = stack(group, kind, capacity, (i, out) => {\n    const col = i % perRow;\n    const row = Math.floor(i / perRow);\n    const x = (col - (perRow - 1) / 2) * cell;\n    if (stands) {\n      out.position.set(x, 0, (row - (rows - 1) / 2) * cell);\n      out.rotation.x = -Math.PI / 2; // +Z round, stood upright\n    } else {\n      // Lying rounds stack in tiers, nested into the gaps of the tier below.\n      const tier = row;\n      const inset = tier % 2 === 1 ? cell / 2 : 0;\n      out.position.set(x + inset, s.calibre / 2 + tier * s.calibre * 0.92, -s.length / 2);\n    }\n  });\n\n  group.scale.setScalar(scale);\n  return countable(\n    group,\n    kind,\n    capacity,\n    write,\n    Math.max(w, d) * 0.5 * scale,\n    options.count ?? capacity\n  );\n}\n\nexport interface AmmoBoxOptions extends ContainerOptions {\n  /** Lid open, rounds visible. Default false. */\n  open?: boolean;\n}\n\n/**\n * The stored state — a crate with its lid on, or off and full of rounds.\n *\n * Closed it is a box and costs almost nothing; open it is the same box with\n * its contents instanced inside. `open` is a build-time choice rather than a\n * method because a sealed crate should not pay for geometry nobody can see,\n * and a level has a hundred of them.\n */\nexport function createAmmoBox(kind: AmmoKind, options: AmmoBoxOptions = {}): Countable {\n  const s = AMMO[kind];\n  const capacity = options.capacity ?? s.perContainer * 2;\n  const open = options.open ?? false;\n  const scale = options.scale ?? 1;\n  const group = new Group();\n  group.name = `ammobox-${kind}`;\n\n  const perRow = Math.max(1, Math.ceil(Math.sqrt(capacity)));\n  const rows = Math.ceil(capacity / perRow);\n  const inner = { x: perRow * s.calibre * 1.3, y: s.calibre * 1.4, z: s.length * 1.1 };\n  const wall = Math.max(0.006, s.calibre * 0.18);\n  const outer = { x: inner.x + wall * 2, y: inner.y * rows + wall * 2, z: inner.z + wall * 2 };\n\n  const crate = createSurface('wood', { seed: options.seed ?? 7 });\n  const shellMesh = new Mesh(\n    geo(`boxshell:${kind}:${capacity}`, () => new BoxGeometry(outer.x, outer.y, outer.z)),\n    crate\n  );\n  shellMesh.position.y = outer.y / 2;\n  shellMesh.castShadow = true;\n  shellMesh.receiveShadow = true;\n  group.add(shellMesh);\n\n  if (!open) {\n    // Sealed: one box, no contents, and `setCount` is honest about it — the\n    // rounds are in there, you just cannot see them.\n    return {\n      object: group,\n      kind,\n      capacity,\n      count: capacity,\n      setCount: () => capacity,\n      consume: () => true,\n      obstacleRadius: Math.max(outer.x, outer.z) * 0.5 * scale,\n    };\n  }\n\n  // Open: hollow it by insetting the contents, and tip the lid back.\n  const lid = new Mesh(\n    geo(`boxlid:${kind}:${capacity}`, () => new BoxGeometry(outer.x, wall, outer.z)),\n    crate\n  );\n  lid.position.set(0, outer.y, -outer.z / 2 - outer.z * 0.34);\n  lid.rotation.x = -1.15;\n  group.add(lid);\n\n  const write = stack(group, kind, capacity, (i, out) => {\n    const col = i % perRow;\n    const row = Math.floor(i / perRow);\n    out.position.set(\n      (col - (perRow - 1) / 2) * s.calibre * 1.3,\n      wall + s.calibre * 0.7 + row * inner.y,\n      -s.length / 2\n    );\n  });\n\n  group.scale.setScalar(scale);\n  return countable(\n    group,\n    kind,\n    capacity,\n    write,\n    Math.max(outer.x, outer.z) * 0.5 * scale,\n    options.count ?? capacity\n  );\n}\n\nexport interface CasingOptions {\n  seed?: number;\n  /** How many to scatter. Default 24. */\n  count?: number;\n  /** Radius of the scatter, metres. Default 0.6. */\n  spread?: number;\n  scale?: number;\n}\n\n/**\n * The spent state — a litter of empty cases where somebody stood.\n *\n * A whole scatter rather than one case, because one spent case is invisible\n * and a hundred of them is a story: this is where the gunner was. Ejected\n * brass lands on its side, in a loose cone off to the shooter's right, which\n * is what the scatter is shaped like.\n *\n * Kinds with no case — a mortar bomb, an arrow, a grenade — have nothing to\n * eject, and this returns an empty prop for them rather than inventing litter.\n */\nexport function createCasing(kind: AmmoKind, options: CasingOptions = {}): Prop {\n  const s = AMMO[kind];\n  const group = new Group();\n  group.name = `casings-${kind}`;\n  if (s.case === 'none' || s.case === 'bagged') {\n    return { object: group, obstacleRadius: 0 };\n  }\n\n  const count = options.count ?? 24;\n  const spread = options.spread ?? 0.6;\n  const scale = options.scale ?? 1;\n  const rng = new Rng(options.seed ?? 11);\n  const r = s.calibre / 2;\n  const caseLen = s.length * (s.head === 'shot' ? 0.84 : 0.7);\n\n  // The case only — a fired round has no bullet in it. Getting that wrong is\n  // the most common mistake in a scattered-brass prop, and it reads instantly\n  // to anyone who has seen a range floor.\n  const empty = geo(`empty:${kind}`, () => new CylinderGeometry(r * 1.08, r * 1.14, caseLen, 8));\n  const mesh = new InstancedMesh(empty, caseMaterial(s.case), count);\n  mesh.frustumCulled = false;\n  mesh.castShadow = true;\n  const node = new Object3D();\n  for (let i = 0; i < count; i++) {\n    // Off to one side and forward, denser near the shooter.\n    const a = rng.range(-0.9, 0.9);\n    const d = spread * Math.sqrt(rng.range(0.02, 1));\n    node.position.set(Math.sin(a) * d + spread * 0.35, r * 1.1, Math.cos(a) * d * 0.6);\n    // Lying down, rolled to a random angle about its own axis.\n    node.rotation.set(Math.PI / 2, rng.range(0, Math.PI * 2), rng.range(0, Math.PI * 2));\n    node.scale.setScalar(1);\n    node.updateMatrix();\n    mesh.setMatrixAt(i, node.matrix);\n  }\n  group.add(mesh);\n\n  // Belt-fed weapons drop LINKS as well as cases, at exactly one per round,\n  // and the links outnumber nothing — they are simply the other half of the\n  // litter. A machine-gun position without them is a position where somebody\n  // swept up half the floor.\n  if (s.container === 'belt') {\n    const linkGeo = geo(`spentlink:${kind}`, () =>\n      new BoxGeometry(s.calibre * 1.2, s.calibre * 0.5, s.calibre * 0.85)\n    );\n    const links = new InstancedMesh(linkGeo, steelMaterial(), count);\n    links.frustumCulled = false;\n    for (let i = 0; i < count; i++) {\n      const a = rng.range(-1.1, 1.1);\n      const d = spread * Math.sqrt(rng.range(0.02, 1));\n      node.position.set(Math.sin(a) * d + spread * 0.2, s.calibre * 0.25, Math.cos(a) * d * 0.7);\n      node.rotation.set(rng.range(-0.3, 0.3), rng.range(0, Math.PI * 2), rng.range(-0.3, 0.3));\n      node.scale.setScalar(1);\n      node.updateMatrix();\n      links.setMatrixAt(i, node.matrix);\n    }\n    group.add(links);\n  }\n\n  group.scale.setScalar(scale);\n  return { object: group, obstacleRadius: 0 };\n}\n\n/**\n * The right ready-container for a kind, without the caller knowing which.\n *\n * `AMMO[kind].container` already says whether a kind belts, magazines,\n * quivers, racks or boxes, so a level that just wants \"some ready ammunition\n * for this weapon\" should not have to switch on it. This is that switch,\n * written once.\n */\nexport function createReady(kind: AmmoKind, options: ContainerOptions = {}): Countable {\n  switch (AMMO[kind].container) {\n    case 'magazine':\n      return createMagazine(kind, options);\n    case 'belt':\n      return createBelt(kind, options);\n    case 'quiver':\n      return createQuiver(kind, options);\n    case 'rack':\n      return createRack(kind, options);\n    case 'box':\n      return createAmmoBox(kind, { ...options, open: true });\n  }\n}\n\n// ── the loading state ────────────────────────────────────────────────────\n// Between the crate and the weapon there is a fifth thing, and leaving it out\n// was the gap in the first pass: the device that gets a handful of loose\n// rounds into a magazine or a cylinder in one motion. It is not a container a\n// game stores ammunition in — it is a container ammunition passes THROUGH.\n\nexport type LoaderStyle =\n  /** A spine with rounds in a row, thumbed down into a magazine. */\n  | 'stripper'\n  /** A ring of rounds with a knob, dropped into a revolver cylinder. */\n  | 'speedloader'\n  /** A cage that goes INTO the rifle with the rounds and ejects after. */\n  | 'en-bloc';\n\nexport interface LoaderOptions extends ContainerOptions {\n  style?: LoaderStyle;\n}\n\n/**\n * A stripper clip, a speedloader or an en-bloc clip.\n *\n * The three differ in one thing that matters and it is not their shape: a\n * stripper clip stays in the hand, a speedloader stays in the hand, and an\n * en-bloc clip **goes into the rifle** and is ejected when the last round\n * fires. That is why `en-bloc` is a kind of loader and not a kind of magazine,\n * and why a game reloading a Garand ejects something and one reloading a\n * Mauser does not.\n *\n * Capacity defaults are the real ones — 5 for a stripper, 6 for a speedloader,\n * 8 for an en-bloc — rather than the kind's magazine capacity, because a clip\n * holds what a clip holds regardless of what the magazine under it takes.\n */\nexport function createLoader(\n  kind: AmmoKind,\n  options: LoaderOptions = {}\n): Countable & { style: LoaderStyle } {\n  const s = AMMO[kind];\n  const style = options.style ?? 'stripper';\n  const capacity =\n    options.capacity ?? (style === 'stripper' ? 5 : style === 'speedloader' ? 6 : 8);\n  const scale = options.scale ?? 1;\n  const group = new Group();\n  group.name = `loader-${style}-${kind}`;\n\n  const pitch = s.calibre * 1.18;\n  let write: (n: number) => void;\n  let radius: number;\n\n  if (style === 'speedloader') {\n    // Rounds on a circle whose diameter is the cylinder's, with the release\n    // knob in the middle. The circle is set by the ROUNDS, so a .38 loader\n    // and a .44 one are visibly different objects.\n    const ring = (pitch * capacity) / (2 * Math.PI);\n    const knob = new Mesh(\n      geo(`knob:${kind}:${capacity}`, () => new CylinderGeometry(ring * 0.42, ring * 0.5, s.calibre * 1.1, 10)),\n      caseMaterial('plastic')\n    );\n    knob.position.z = -s.length * 0.18;\n    knob.quaternion.copy(LIE);\n    group.add(knob);\n    write = stack(group, kind, capacity, (i, out) => {\n      const a = (i / capacity) * Math.PI * 2;\n      out.position.set(Math.cos(a) * ring, Math.sin(a) * ring, 0);\n    });\n    radius = ring + s.calibre;\n  } else {\n    // Stripper and en-bloc are both a row of rounds on a spine. The en-bloc's\n    // spine wraps them — it is a cage, because it has to survive being fired\n    // over — so it gets a second rail on the far side.\n    const span = pitch * capacity;\n    const spine = new Mesh(\n      geo(`spine:${kind}:${capacity}:${style}`, () =>\n        new BoxGeometry(span, s.calibre * 0.55, s.calibre * 0.5)\n      ),\n      steelMaterial()\n    );\n    spine.position.set(0, -s.calibre * 0.75, s.length * 0.14);\n    group.add(spine);\n    if (style === 'en-bloc') {\n      const far = spine.clone();\n      far.position.y = s.calibre * 0.75;\n      group.add(far);\n    }\n    write = stack(group, kind, capacity, (i, out) => {\n      out.position.set((i - (capacity - 1) / 2) * pitch, 0, -s.length / 2);\n    });\n    radius = span / 2;\n  }\n\n  group.scale.setScalar(scale);\n  const c = countable(group, kind, capacity, write, radius * scale, options.count ?? capacity);\n  return Object.assign(c, { style });\n}\n\nexport interface BandolierOptions extends ContainerOptions {\n  /** Loops along the strap. Default 20. */\n  loops?: number;\n  /** How far the strap sags across the chest, metres. Default 0.16. */\n  sag?: number;\n}\n\n/**\n * A bandolier — rounds in loops on a strap, worn across the body.\n *\n * The only container in the set that is WORN rather than held or set down, and\n * the difference shows in the handshake: it publishes `socket`, the name ANIMA\n * uses for the attachment point, and the caller parents it there. SCENA does\n * not know what a shoulder is; it knows what a strap that has to hang across\n * one looks like.\n *\n * The strap is a catenary, like the belt, for the same reason: a straight one\n * is the tell that this was drawn rather than laid out. It is authored in the\n * plane a torso presents, so parenting it to a chest socket needs no rotation.\n */\nexport function createBandolier(\n  kind: AmmoKind,\n  options: BandolierOptions = {}\n): Countable & { socket: string } {\n  const s = AMMO[kind];\n  const loops = options.loops ?? 20;\n  const capacity = options.capacity ?? loops;\n  const scale = options.scale ?? 1;\n  const sag = options.sag ?? 0.16;\n  const group = new Group();\n  group.name = `bandolier-${kind}`;\n\n  // A shoulder-to-hip run is about half a torso height; the strap is authored\n  // at that and the caller scales it to the body it goes on.\n  const span = 0.62;\n  const at = (u: number): { x: number; y: number; slope: number } => {\n    const t = u * 2 - 1; // -1..1\n    return { x: (t * span) / 2, y: -sag * (1 - t * t), slope: (2 * sag * t) / (span / 2) };\n  };\n\n  // The strap itself: short segments following the curve, instanced.\n  const SEGS = 24;\n  const strapGeo = geo(`strap:${kind}`, () =>\n    new BoxGeometry((span / SEGS) * 1.25, s.calibre * 1.5, s.calibre * 0.35)\n  );\n  const strap = new InstancedMesh(strapGeo, createSurface('leather', { seed: options.seed ?? 6 }), SEGS);\n  strap.name = 'strap';\n  strap.frustumCulled = false;\n  strap.castShadow = true;\n  const node = new Object3D();\n  for (let i = 0; i < SEGS; i++) {\n    const p = at((i + 0.5) / SEGS);\n    node.position.set(p.x, p.y, 0);\n    node.rotation.set(0, 0, Math.atan(p.slope));\n    node.scale.setScalar(1);\n    node.updateMatrix();\n    strap.setMatrixAt(i, node.matrix);\n  }\n  group.add(strap);\n\n  // Rounds sit nose-down in the loops, tilted with the strap.\n  const write = stack(group, kind, capacity, (i, out) => {\n    const p = at((i + 0.5) / capacity);\n    out.position.set(p.x, p.y - s.calibre * 0.4, 0);\n    out.rotation.set(-Math.PI / 2, 0, Math.atan(p.slope));\n  });\n\n  group.scale.setScalar(scale);\n  const c = countable(group, kind, capacity, write, (span / 2) * scale, options.count ?? capacity);\n  // ANIMA's socket names. A bandolier is a chest item; a game that wants it\n  // over the other shoulder mirrors the group's X scale.\n  return Object.assign(c, { socket: 'chest' });\n}\n\n// ── propellant ───────────────────────────────────────────────────────────\n\nexport interface ChargeOptions extends ContainerOptions {\n  /**\n   * Increments loaded, 1..`capacity`. This is the gunner's actual decision on\n   * a separate-loading piece: more bags, more velocity, more range, more wear.\n   */\n  increments?: number;\n}\n\n/**\n * Bagged propellant — the other half of a separate-loading round.\n *\n * A 155 mm shell is not a cartridge. The shell goes in, then a number of cloth\n * charge bags behind it, and how many is a decision made per shot. Modelling\n * the shell without the charge is modelling half the round, and it is the half\n * a gun crew spends its time on.\n *\n * `count` is the number of bags SHOWN; `chargeVelocity` says what that many\n * are worth. Only kinds whose case is `bagged` have these — asking for a\n * charge for a rifle round is asking for something that does not exist, and\n * this returns an empty prop rather than inventing one.\n */\nexport function createCharge(kind: AmmoKind, options: ChargeOptions = {}): Countable {\n  const s = AMMO[kind];\n  const capacity = options.capacity ?? 7;\n  const scale = options.scale ?? 1;\n  const group = new Group();\n  group.name = `charge-${kind}`;\n  const r = s.calibre * 0.46;\n  const bagH = s.length * 0.16;\n\n  if (s.case !== 'bagged') {\n    return {\n      object: group,\n      kind,\n      capacity: 0,\n      count: 0,\n      setCount: () => 0,\n      consume: () => false,\n      obstacleRadius: 0,\n    };\n  }\n\n  const bagGeo = geo(`bag:${kind}`, () => new CylinderGeometry(r, r * 0.94, bagH, 10));\n  const bags = new InstancedMesh(bagGeo, caseMaterial('bagged'), Math.max(1, capacity));\n  bags.name = 'counted';\n  bags.frustumCulled = false;\n  bags.castShadow = true;\n  group.add(bags);\n  const node = new Object3D();\n  const hidden = new Matrix4().makeScale(0, 0, 0);\n  const write = (n: number): void => {\n    for (let i = 0; i < capacity; i++) {\n      if (i >= n) {\n        bags.setMatrixAt(i, hidden);\n        continue;\n      }\n      node.position.set(0, bagH / 2 + i * bagH * 0.98, 0);\n      node.rotation.set(0, (i * 1.7) % Math.PI, 0);\n      node.scale.setScalar(1);\n      node.updateMatrix();\n      bags.setMatrixAt(i, node.matrix);\n    }\n    bags.instanceMatrix.needsUpdate = true;\n  };\n\n  group.scale.setScalar(scale);\n  return countable(group, kind, capacity, write, r * scale, options.increments ?? options.count ?? capacity);\n}\n\n/**\n * What `increments` bags of propellant are worth, in m/s.\n *\n * Muzzle energy is proportional to the propellant burnt and velocity goes as\n * its square root, so a half charge is **71%** of full velocity rather than\n * 50%. Getting that linear is the difference between a gunnery mechanic that\n * behaves like artillery and one that behaves like a slider.\n *\n * The full charge is the kind's own `muzzle`, so this and `ballisticsOf` can\n * never drift apart.\n */\nexport function chargeVelocity(kind: AmmoKind, increments: number, capacity = 7): number {\n  const full = AMMO[kind].muzzle;\n  const n = Math.max(0, Math.min(capacity, increments));\n  return full * Math.sqrt(n / capacity);\n}\n\nexport interface KegOptions {\n  seed?: number;\n  scale?: number;\n  /** Lid off, powder visible. Default false. */\n  open?: boolean;\n}\n\n/**\n * A powder keg — the bulk propellant that everything before the cartridge ran\n * on, and the most explosive thing on any pre-modern map.\n *\n * Not a `Countable`: a keg holds a mass, not a number of rounds, and giving it\n * a `count` would be inventing a unit nobody uses.\n */\nexport function createPowderKeg(options: KegOptions = {}): Prop {\n  const scale = options.scale ?? 1;\n  const seed = options.seed ?? 13;\n  const group = new Group();\n  group.name = 'powder-keg';\n  const r = 0.19;\n  const h = 0.44;\n\n  const body = new Mesh(\n    geo('kegbody', () => new CylinderGeometry(r, r * 0.88, h, 14)),\n    createSurface('wood', { seed })\n  );\n  body.position.y = h / 2;\n  body.castShadow = true;\n  group.add(body);\n\n  // Two iron hoops. A barrel without them reads as a bucket.\n  const hoopGeo = geo('keghoop', () => new CylinderGeometry(r * 1.03, r * 1.03, h * 0.07, 14));\n  const hoops = new InstancedMesh(hoopGeo, steelMaterial(), 2);\n  hoops.frustumCulled = false;\n  const node = new Object3D();\n  for (let i = 0; i < 2; i++) {\n    node.position.set(0, h * (0.22 + i * 0.56), 0);\n    node.rotation.set(0, 0, 0);\n    node.scale.setScalar(1);\n    node.updateMatrix();\n    hoops.setMatrixAt(i, node.matrix);\n  }\n  group.add(hoops);\n\n  if (options.open) {\n    const powder = new Mesh(\n      geo('kegpowder', () => new CylinderGeometry(r * 0.9, r * 0.9, h * 0.06, 14)),\n      shared('powder', () => new MeshStandardMaterial({ color: 0x24242a, roughness: 1, metalness: 0 }))\n    );\n    powder.position.y = h * 0.94;\n    group.add(powder);\n  }\n\n  group.scale.setScalar(scale);\n  return { object: group, obstacleRadius: r * scale };\n}\n\n// ── the dump ─────────────────────────────────────────────────────────────\n\nexport interface DumpOptions {\n  seed?: number;\n  /** Pallets of crates. Default 6. */\n  pallets?: number;\n  /** Crates per pallet. Default 6. */\n  perPallet?: number;\n  /** Fraction of pallets with the top crate open. Default 0.3. */\n  open?: number;\n  scale?: number;\n}\n\nexport interface AmmoDump extends Prop {\n  kind: AmmoKind;\n  /** Crates in the dump, of whatever this kind's crate holds. */\n  crates: number;\n  /** Rounds the whole dump represents. */\n  rounds: number;\n}\n\n/**\n * An ammunition dump — pallet scale.\n *\n * The state above `stored`: not a crate, a supply point. Crates stacked on\n * pallets in a loose grid, a few of them open, the rest sealed, with kegs or\n * charge bags alongside for the kinds that need them.\n *\n * The reason this is worth its own function rather than a loop in a level is\n * that a naive loop is a performance trap: thirty-six wooden crates is\n * thirty-six draws before anything is in them, and a sealed crate is exactly\n * the same box every time. The crates here are ONE instanced mesh, the pallets\n * another, and only the open ones pay for contents.\n */\nexport function createAmmoDump(kind: AmmoKind, options: DumpOptions = {}): AmmoDump {\n  const s = AMMO[kind];\n  const pallets = Math.max(1, options.pallets ?? 6);\n  const perPallet = Math.max(1, options.perPallet ?? 6);\n  const openFrac = options.open ?? 0.3;\n  const scale = options.scale ?? 1;\n  const rng = new Rng(options.seed ?? 17);\n  const group = new Group();\n  group.name = `ammodump-${kind}`;\n\n  // One crate size for the whole dump, from the round, as everything else is.\n  const box = {\n    x: Math.max(0.36, s.length * 1.25),\n    y: Math.max(0.22, s.calibre * 6),\n    z: Math.max(0.3, s.length * 0.75),\n  };\n  const palletSize = { x: box.x * 1.25, y: 0.11, z: box.z * 1.6 };\n  const cols = Math.ceil(Math.sqrt(pallets));\n  const spot = (i: number): { x: number; z: number; a: number } => {\n    const c = i % cols;\n    const r = Math.floor(i / cols);\n    return {\n      x: (c - (cols - 1) / 2) * palletSize.x * 1.5 + rng.range(-0.08, 0.08),\n      z: (r - (Math.ceil(pallets / cols) - 1) / 2) * palletSize.z * 1.7 + rng.range(-0.08, 0.08),\n      a: rng.range(-0.12, 0.12),\n    };\n  };\n  const spots = Array.from({ length: pallets }, (_, i) => spot(i));\n\n  const node = new Object3D();\n  const put = (mesh: InstancedMesh, i: number, x: number, y: number, z: number, a: number): void => {\n    node.position.set(x, y, z);\n    node.rotation.set(0, a, 0);\n    node.scale.setScalar(1);\n    node.updateMatrix();\n    mesh.setMatrixAt(i, node.matrix);\n  };\n\n  const palletMesh = new InstancedMesh(\n    geo(`pallet:${kind}`, () => new BoxGeometry(palletSize.x, palletSize.y, palletSize.z)),\n    createSurface('wood', { seed: (options.seed ?? 17) + 1 }),\n    pallets\n  );\n  palletMesh.frustumCulled = false;\n  palletMesh.receiveShadow = true;\n  group.add(palletMesh);\n\n  const crateMesh = new InstancedMesh(\n    geo(`dumpcrate:${kind}`, () => new BoxGeometry(box.x, box.y, box.z)),\n    createSurface('wood', { seed: options.seed ?? 17 }),\n    pallets * perPallet\n  );\n  crateMesh.frustumCulled = false;\n  crateMesh.castShadow = true;\n  group.add(crateMesh);\n\n  let crate = 0;\n  const openTops: Array<{ x: number; y: number; z: number; a: number }> = [];\n  for (let p = 0; p < pallets; p++) {\n    const at = spots[p];\n    put(palletMesh, p, at.x, palletSize.y / 2, at.z, at.a);\n    // Crates stack two wide and up; the top one of some pallets is open.\n    for (let c = 0; c < perPallet; c++) {\n      const tier = Math.floor(c / 2);\n      const side = c % 2 === 0 ? -1 : 1;\n      const y = palletSize.y + box.y / 2 + tier * box.y;\n      const x = at.x + side * box.x * 0.02;\n      put(crateMesh, crate++, x, y, at.z + side * box.z * 0.06, at.a + rng.range(-0.05, 0.05));\n      const top = c >= perPallet - 2;\n      if (top && rng.range(0, 1) < openFrac) openTops.push({ x, y: y + box.y / 2, z: at.z, a: at.a });\n    }\n  }\n\n  // Only the open ones pay for rounds — and they pay for them ONCE, as a\n  // single stack shared across every open crate in the dump.\n  if (openTops.length) {\n    const perCrate = Math.max(4, Math.min(24, s.perContainer));\n    const total = openTops.length * perCrate;\n    const write = stack(group, kind, total, (i, out) => {\n      const which = openTops[Math.floor(i / perCrate)];\n      const j = i % perCrate;\n      const row = Math.floor(j / 4);\n      const col = j % 4;\n      out.position.set(\n        which.x + (col - 1.5) * s.calibre * 1.35,\n        which.y - s.calibre * 0.6 + row * s.calibre * 1.2,\n        which.z - s.length / 2\n      );\n      out.rotation.set(0, which.a, 0);\n    });\n    write(total);\n  }\n\n  // Kinds that are loaded separately need their propellant standing beside\n  // them, or the dump is showing half of what it takes to fire.\n  if (s.case === 'bagged') {\n    const charge = createCharge(kind, { capacity: 6, seed: options.seed });\n    charge.object.position.set(spots[0].x - palletSize.x * 1.1, palletSize.y, spots[0].z);\n    group.add(charge.object);\n  } else if (s.muzzle > 0 && s.case === 'none' && AMMO[kind].head === 'sphere') {\n    const keg = createPowderKeg({ seed: options.seed });\n    keg.object.position.set(spots[0].x - palletSize.x * 1.1, 0, spots[0].z);\n    group.add(keg.object);\n  }\n\n  group.scale.setScalar(scale);\n  const spread = cols * palletSize.x * 1.5;\n  return {\n    object: group,\n    kind,\n    crates: crate,\n    rounds: crate * s.perContainer * 2,\n    obstacleRadius: (spread / 2) * scale,\n  };\n}\n","import { BoxGeometry, Group, Mesh, Vector3 } from 'three';\nimport { createSurface } from '../materials/surface';\nimport type { Obstacle } from '../core/types';\n\n/**\n * Breaking boards — *tameshiwari*, and a number SCENA is willing to be wrong\n * about in public.\n *\n * Everything else in this file exists to support one function. `boardStrength`\n * says what it takes to break a board, and it says so from published constants\n * and the board's own dimensions — nothing else:\n *\n *   MODULUS OF RUPTURE     the bending stress timber fails at (Wood Handbook)\n *   YOUNG'S MODULUS        how far it bends on the way there (same source)\n *   STRENGTH RATIO         the knock-down for knots and grain (ASTM D245)\n *   three-point bending    F = 2·σ·b·d² / 3L, the standard relation for a\n *                          simply supported beam loaded in the middle\n *\n * SCENA does not know what a punch is, has never heard of ANIMA, and imports\n * nothing from it. It declares what a board takes and stops.\n *\n * ## It has been checked against the world\n *\n * Feld, McNair and Wilk measured a hand going through a 30 × 15 × 2.5 cm pine\n * board in Scientific American in 1979 and put the breaking force at about\n * 3.1 kN. The formulae above, handed that board's dimensions and nothing else,\n * say 3.62 kN.\n *\n * That is a 17% error from four published numbers and no fitting, which is the\n * point of deriving rather than choosing: the number can be WRONG, out loud,\n * against somebody else's measurement.\n */\n\nexport type Timber = 'pine' | 'poplar' | 'cedar' | 'oak' | 'pineWet';\n\nexport interface TimberSpec {\n  label: string;\n  /**\n   * Modulus of rupture, pascals — the bending stress at which it snaps.\n   * Wood Handbook (USDA FPL) values for clear, kiln-dried, 12% moisture.\n   */\n  rupture: number;\n  /** Young's modulus in bending, pascals. Same source. */\n  stiffness: number;\n  /** Density, kg/m³ — for the mass of the halves once it is in two. */\n  density: number;\n}\n\n/**\n * The strength ratio for ordinary graded timber, ASTM D245.\n *\n * The moduli above are CLEAR WOOD — select, defect-free laboratory samples.\n * A board you can buy has knots and slope of grain, and the standard practice\n * for turning clear-wood values into working ones is a visual-grade strength\n * ratio, which for common construction grades sits around a third.\n *\n * It matters here rather than being a detail: without it a 25 mm pine board\n * comes out taking 10.4 kN, and the number that has actually been measured —\n * Feld, McNair and Wilk put a hand through one in Scientific American in 1979\n * — is about 3.1 kN. With it the same board comes out at 3.6 kN. A model that\n * is 3x out and looks fine is exactly what a published measurement is for.\n */\nexport const GRADE_RATIO = 0.35;\n\n/**\n * Five timbers, and not one of these numbers was chosen to make a demo work.\n *\n * Pine at 40 MPa is the standard tameshiwari board and the reason a beginner\n * can break one. Oak at 100 MPa is two and a half times as hard and is the\n * reason nobody uses it. `pineWet` is the same pine at 20% moisture rather\n * than 12%, which is a real and well-documented 25% loss — and is why boards\n * are kept in a dry room and why a demonstration in the rain goes wrong.\n */\nexport const TIMBERS: Record<Timber, TimberSpec> = {\n  pine: { label: 'Eastern white pine', rupture: 41.4e6, stiffness: 9.0e9, density: 380 },\n  poplar: { label: 'Yellow poplar', rupture: 69.6e6, stiffness: 10.9e9, density: 455 },\n  cedar: { label: 'Western red cedar', rupture: 51.7e6, stiffness: 7.7e9, density: 350 },\n  oak: { label: 'White oak', rupture: 102.3e6, stiffness: 12.3e9, density: 755 },\n  pineWet: { label: 'Eastern white pine, green', rupture: 34.5e6, stiffness: 6.8e9, density: 380 },\n};\n\nexport const TIMBER_NAMES = Object.keys(TIMBERS) as Timber[];\n\nexport interface BoardShape {\n  timber?: Timber;\n  /** Across the grain, metres. A competition board is 0.30. */\n  width?: number;\n  /** Along the grain, metres. Also 0.30 — boards are square. */\n  length?: number;\n  /** The one that matters, metres. A competition board is 0.019 (¾\"). */\n  thickness?: number;\n  /**\n   * Distance between the two supports, metres. Defaults to 85% of the\n   * length, which is where hands or blocks actually sit.\n   */\n  span?: number;\n}\n\nexport interface BoardStrength {\n  timber: Timber;\n  /** Peak force the board takes before it snaps, newtons. */\n  force: number;\n  /** How far the middle has moved by then, metres. */\n  deflection: number;\n  /**\n   * The work done bending it to failure, joules — the area under a linear\n   * force-against-deflection curve, so half of force times deflection.\n   *\n   * Reported because it is derivable and because it settles an argument: a\n   * pine board needs 1.9 J and ANIMA independently puts a hammerfist at 113 J,\n   * sixty times more. ENERGY IS NOT WHAT LIMITS BOARD BREAKING. The force is,\n   * and `force` is the number to compare against.\n   */\n  energy: number;\n  /** Mass of the board, kg. */\n  mass: number;\n}\n\n/**\n * How hard a board is, from what it is made of and how thick it is.\n *\n * Three-point bending, which is what a board across two supports with a fist\n * in the middle is:\n *\n *   I = b·d³/12                   second moment of area of a rectangle\n *   F = 2·σ·b·d² / (3·L)          the load at which the outer fibre reaches σ\n *   δ = F·L³ / (48·E·I)           how far the middle has gone by then\n *   U = ½·F·δ                     the work done getting there\n *\n * Thickness is squared in the force and cubed in the stiffness. The obvious\n * conclusion — that doubling it takes eight times as much — is wrong, and was\n * written here that way first: the `d³` is in the STIFFNESS, and a stiffer\n * beam reaches its failure stress sooner, so the deflection at failure falls\n * as `1/d` and the energy comes out linear. See `stackStrength`.\n *\n * The FORCE really is quadratic, and that is the one a person runs out of.\n */\nexport function boardStrength(shape: BoardShape = {}): BoardStrength {\n  const timber = shape.timber ?? 'pine';\n  const spec = TIMBERS[timber];\n  const b = shape.width ?? 0.3;\n  const len = shape.length ?? 0.3;\n  const d = shape.thickness ?? 0.019;\n  const L = shape.span ?? len * 0.85;\n  const I = (b * d * d * d) / 12;\n  const force = (GRADE_RATIO * 2 * spec.rupture * b * d * d) / (3 * L);\n  const deflection = (force * L * L * L) / (48 * spec.stiffness * I);\n  return {\n    timber,\n    force,\n    deflection,\n    energy: 0.5 * force * deflection,\n    mass: b * len * d * spec.density,\n  };\n}\n\n/**\n * A stack of them, spaced against glued — and the answer is not the one you\n * would guess.\n *\n * The force to break a beam goes as `d²` and its stiffness as `d³`, so the\n * deflection at failure goes as `1/d` and the ENERGY — half force times\n * deflection — comes out LINEAR in thickness. Six boards glued into one thick\n * beam take exactly the same energy as six separate ones, to the joule.\n *\n * That was written here as \"216 times harder\" first, on the strength of the\n * `d³`, and it is simply wrong: the `d³` is in the stiffness, and stiffness\n * makes a beam break SOONER, not later. The algebra says `U ∝ σ²bdL/E`.\n *\n * The difference between spaced and glued is entirely in the FORCE, and it is\n * enormous: six spaced boards need 3.6 kN each, one at a time, and the same\n * six glued need 130 kN all at once — which no person can produce. That is\n * what the spacers are for, and nothing about it is about energy.\n */\nexport function stackStrength(count: number, shape: BoardShape = {}): {\n  /** Joules for the whole stack, spaced. */\n  spaced: number;\n  /** ...and glued into one beam. The same number, which is the point. */\n  solid: number;\n  /** Newtons needed for ONE spaced board. */\n  spacedForce: number;\n  /** ...and for the glued beam. This is where the difference lives. */\n  solidForce: number;\n} {\n  const n = Math.max(1, Math.round(count));\n  const one = boardStrength(shape);\n  const glued = boardStrength({ ...shape, thickness: (shape.thickness ?? 0.019) * n });\n  return {\n    spaced: one.energy * n,\n    solid: glued.energy,\n    spacedForce: one.force,\n    solidForce: glued.force,\n  };\n}\n\n// ------------------------------------------------------------- the prop\n\nexport type BoardState = 'intact' | 'broken';\n\nexport interface BoardOptions extends BoardShape {\n  seed?: number;\n  /** How many boards, held apart by spacers. Default 1. */\n  count?: number;\n  /** Height of the supports off the ground, metres. Default 0.9. */\n  height?: number;\n}\n\nexport interface BoardStack {\n  group: Group;\n  trigger: Obstacle;\n  /** What one board of this stack takes, in joules. */\n  readonly strength: BoardStrength;\n  /** How many are still whole. */\n  readonly standing: number;\n  readonly state: BoardState;\n  /**\n   * Hit it with this much FORCE, in newtons.\n   *\n   * Force rather than energy, because that is what breaks a beam: the outer\n   * fibre reaches its rupture stress or it does not, and how much kinetic\n   * energy happened to be behind it is a separate question. Returns how many\n   * boards broke.\n   *\n   * Nothing here knows or cares where the newtons came from — a fist, a\n   * hammer, a falling rock. It is a force against a threshold computed from\n   * the timber, and both sides of that comparison can be derived independently\n   * by people who have never heard of each other.\n   */\n  strike(newtons: number): number;\n  reset(): void;\n  update(dt: number): void;\n}\n\nconst GRAVITY = 9.8;\n\n/**\n * Boards on two blocks, and a `strike` that takes joules.\n *\n * The halves fly with whatever energy was left after breaking them, which is\n * the honest thing to do with it: a strike that only just breaks the board\n * drops the pieces, and one with a lot to spare throws them.\n */\nexport function createBoard(options: BoardOptions = {}): BoardStack {\n  const seed = options.seed ?? 1;\n  const count = Math.max(1, Math.round(options.count ?? 1));\n  const width = options.width ?? 0.3;\n  const length = options.length ?? 0.3;\n  const thickness = options.thickness ?? 0.019;\n  const height = options.height ?? 0.9;\n  const strength = boardStrength(options);\n  const span = options.span ?? length * 0.85;\n\n  const group = new Group();\n  group.name = 'boards';\n\n  // The two supports. Their spacing IS the span the strength was computed\n  // from, so moving them changes the number — as it does in a dojo.\n  const blockMat = createSurface('stone', { seed });\n  for (const s of [-1, 1]) {\n    const block = new Mesh(new BoxGeometry(0.09, height, width * 1.1), blockMat);\n    block.position.set(0, height / 2, (s * span) / 2);\n    group.add(block);\n  }\n\n  const timberMat = createSurface('plank', { seed: seed + 1 });\n  const gap = thickness * 1.6; // the spacer, and the reason `d` stays small\n  interface Half {\n    mesh: Mesh;\n    vel: Vector3;\n    spin: Vector3;\n    home: Vector3;\n    resting: boolean;\n  }\n  const boards: Array<{ whole: Mesh; halves: Half[]; broken: boolean }> = [];\n  for (let i = 0; i < count; i++) {\n    const y = height + thickness / 2 + i * (thickness + gap);\n    const whole = new Mesh(new BoxGeometry(width, thickness, length), timberMat);\n    whole.position.set(0, y, 0);\n    group.add(whole);\n    const halves: Half[] = [];\n    for (const s of [-1, 1]) {\n      const half = new Mesh(new BoxGeometry(width, thickness, length / 2), timberMat);\n      half.position.set(0, y, (s * length) / 4);\n      half.visible = false;\n      group.add(half);\n      halves.push({\n        mesh: half,\n        vel: new Vector3(),\n        spin: new Vector3(),\n        home: half.position.clone(),\n        resting: false,\n      });\n    }\n    boards.push({ whole, halves, broken: false });\n  }\n\n  const trigger: Obstacle = { center: group.position, radius: Math.max(width, length) * 0.7 };\n  let standing = count;\n\n  return {\n    group,\n    trigger,\n    strength,\n    get standing() {\n      return standing;\n    },\n    get state(): BoardState {\n      return standing === count ? 'intact' : 'broken';\n    },\n    strike(newtons: number): number {\n      const force = Math.max(0, newtons);\n      if (force < strength.force) return 0;\n      // Everything the force has over the threshold goes into the halves. A\n      // strike that only just breaks the board drops the pieces; one with a\n      // lot to spare throws them.\n      let left = ((force - strength.force) * strength.deflection) / 2;\n      let broke = 0;\n      for (const board of boards) {\n        if (board.broken) continue;\n        if (broke > 0 && left < strength.energy) break;\n        left = Math.max(0, left - (broke > 0 ? strength.energy : 0));\n        board.broken = true;\n        broke++;\n        standing--;\n        board.whole.visible = false;\n        // Whatever is left over goes into the halves, split between them.\n        // Half the mass each, so v = sqrt(2E/m) per side.\n        const each = left / 2;\n        const speed = Math.sqrt((2 * each) / Math.max(0.01, strength.mass / 2));\n        for (const [k, half] of board.halves.entries()) {\n          half.mesh.visible = true;\n          half.resting = false;\n          const s = k === 0 ? -1 : 1;\n          half.vel.set(0, Math.min(4, speed * 0.35), s * Math.min(6, speed * 0.5));\n          half.spin.set(s * Math.min(9, speed), 0, 0);\n        }\n      }\n      return broke;\n    },\n    reset(): void {\n      standing = count;\n      for (const board of boards) {\n        board.broken = false;\n        board.whole.visible = true;\n        for (const half of board.halves) {\n          half.mesh.visible = false;\n          half.mesh.position.copy(half.home);\n          half.mesh.rotation.set(0, 0, 0);\n          half.vel.set(0, 0, 0);\n          half.resting = false;\n        }\n      }\n    },\n    update(dt: number): void {\n      for (const board of boards) {\n        if (!board.broken) continue;\n        for (const half of board.halves) {\n          if (half.resting) continue;\n          half.vel.y -= GRAVITY * dt;\n          half.mesh.position.addScaledVector(half.vel, dt);\n          half.mesh.rotation.x += half.spin.x * dt;\n          if (half.mesh.position.y <= thickness / 2) {\n            half.mesh.position.y = thickness / 2;\n            half.resting = true;\n            half.vel.set(0, 0, 0);\n          }\n        }\n      }\n    },\n  };\n}\n","import { BoxGeometry, CylinderGeometry, Group, Mesh } from 'three';\nimport { createSurface } from '../materials/surface';\n\n/**\n * Armour — what a plate takes, and the second half of a handshake.\n *\n * SCENA has never heard of an arrow. This file declares what it costs to push\n * a hard point through a sheet of metal, from the metal's yield strength and a\n * ruler, and stops.\n *\n * ## The mechanism is indentation, not punching\n *\n * The obvious model is shearing a plug: force equals perimeter times thickness\n * times shear strength, which is what every press-tool handbook uses for\n * punching holes. Handed a 9 mm bodkin and 2 mm of wrought iron it says\n * **19.6 joules**, and the measured figure is nearly ten times that.\n *\n * It is the wrong mechanism. A sharp point does not shear a plug out — it\n * OPENS A HOLE, pushing metal aside radially, and the pressure that takes is\n * the metal's INDENTATION pressure. Tabor measured that in 1951 and it is\n * about three times the yield stress:\n *\n *   p ≈ 3·σ_y                     Tabor's relation. It is also what a hardness\n *                                 test measures, which is why hardness numbers\n *                                 and yield strengths sit in that ratio\n *   F = p · π·d²/4                over the point's own frontal area\n *   E = F · t                     through the thickness of the plate\n *\n * Same 9 mm bodkin, same 2 mm plate: **114 joules**, against a measured 175.\n * 35% out from two published numbers and a ruler.\n *\n * ## What it is wrong against\n *\n * Alan Williams (*The Knight and the Blast Furnace*, 2003) measured energies to\n * defeat armour and put 2 mm of wrought iron plate at about **175 J**, and mail\n * over padding at around **120 J**. English war-bow arrows carry 80-120 J.\n *\n * Those are system figures — they include dishing the plate over a hand's\n * breadth, the arrow bending, and whatever is underneath. This file models the\n * hole and nothing else, so it should and does come out UNDER them.\n *\n * ## And the part this file deliberately hands off\n *\n * `mailStrength` says what one riveted ring takes, and the answer is almost\n * nothing: a couple of joules. Mail is not what stops the arrow. **The padding\n * under it is**, and the padding is textile — which SCENA has no business\n * knowing the fracture toughness of. That number lives in ANIMA, in a module\n * about cutting people, and neither package imports the other.\n */\n\nexport type Alloy = 'wroughtIron' | 'mildSteel' | 'mediumCarbon' | 'hardened' | 'bronze' | 'aluminium';\n\nexport interface AlloySpec {\n  label: string;\n  /** Yield strength, pascals. Ordinary published values. */\n  yield: number;\n  /** Ultimate tensile strength, pascals. */\n  ultimate: number;\n  /** kg/m³. */\n  density: number;\n}\n\n/**\n * Tabor's relation: the indentation pressure of a ductile metal is about three\n * times its yield stress.\n *\n * Measured, in *The Hardness of Metals* (1951), and it is the reason a Vickers\n * number and a yield strength sit in that ratio. It is the single number that\n * turns \"how strong is this steel\" into \"what does it cost to push a spike\n * through it\", and there is no fitting anywhere near it.\n */\nexport const TABOR = 3;\n\n/**\n * Six metals. Wrought iron is the one that matters, because it is what most\n * surviving armour is and it is nothing like modern steel.\n */\nexport const ALLOYS: Record<Alloy, AlloySpec> = {\n  /** Medieval bloomery iron: soft, slaggy, and what most armour actually was. */\n  wroughtIron: { label: 'Wrought iron', yield: 200e6, ultimate: 300e6, density: 7750 },\n  mildSteel: { label: 'Mild steel', yield: 250e6, ultimate: 400e6, density: 7850 },\n  /** Air-cooled medium carbon: the best late-medieval munition plate. */\n  mediumCarbon: { label: 'Medium-carbon steel', yield: 400e6, ultimate: 650e6, density: 7850 },\n  /** Quenched and tempered — Milanese and Innsbruck work, and rare. */\n  hardened: { label: 'Hardened steel', yield: 1100e6, ultimate: 1400e6, density: 7850 },\n  bronze: { label: 'Bronze', yield: 180e6, ultimate: 350e6, density: 8800 },\n  aluminium: { label: 'Aluminium alloy', yield: 275e6, ultimate: 310e6, density: 2700 },\n};\n\nexport const ALLOY_NAMES = Object.keys(ALLOYS) as Alloy[];\n\nexport interface PlateShape {\n  alloy?: Alloy;\n  /** Metres. Munition plate is 1.5-2 mm; a jousting breastplate is 4 mm. */\n  thickness?: number;\n  /** The hole that has to be made, metres — the point's widest diameter. */\n  hole?: number;\n  /** Metres, for the mass. */\n  width?: number;\n  height?: number;\n}\n\nexport interface PlateStrength {\n  alloy: Alloy;\n  /** Pa — the indentation pressure, 3σ_y. */\n  pressure: number;\n  /** Newtons to keep the point moving. */\n  force: number;\n  /** Joules to open a hole all the way through. */\n  energy: number;\n  /** kg of the panel. */\n  mass: number;\n  /**\n   * What the WRONG model says, joules — shearing a plug out instead of opening\n   * a hole.\n   *\n   * Kept and reported because it is the model everybody reaches for first, it\n   * is off by nearly ten times, and a number that is only ever right is a\n   * number nobody has checked against the alternative.\n   */\n  punchingEnergy: number;\n}\n\n/**\n * What it costs to put a hard point through a plate.\n *\n * Indentation, not shearing: the point opens a hole of its own diameter\n * against the metal's indentation pressure, all the way through.\n */\nexport function plateStrength(shape: PlateShape = {}): PlateStrength {\n  const alloy = shape.alloy ?? 'wroughtIron';\n  const spec = ALLOYS[alloy];\n  const t = shape.thickness ?? 0.002;\n  const d = shape.hole ?? 0.009;\n  const w = shape.width ?? 0.35;\n  const h = shape.height ?? 0.45;\n\n  const pressure = TABOR * spec.yield;\n  const area = (Math.PI * d * d) / 4;\n  const force = pressure * area;\n\n  // The plug-shearing model, for comparison. τ = σ_uts/√3, von Mises.\n  const shear = spec.ultimate / Math.sqrt(3);\n  const punchForce = Math.PI * d * t * shear;\n\n  return {\n    alloy,\n    pressure,\n    force,\n    energy: force * t,\n    mass: w * h * t * spec.density,\n    punchingEnergy: punchForce * t,\n  };\n}\n\nexport interface MailShape {\n  alloy?: Alloy;\n  /** Wire diameter, metres. Surviving mail is 1.0-1.6 mm. */\n  wire?: number;\n  /** Ring inner diameter, metres. Typically 8-10 mm. */\n  ring?: number;\n}\n\nexport interface MailStrength {\n  alloy: Alloy;\n  /** Newtons to burst one riveted ring — two wire sections in tension. */\n  force: number;\n  /** Joules, over the distance the point has to open the ring. */\n  energy: number;\n  /** kg/m² of the fabric. */\n  areal: number;\n}\n\n/**\n * What one riveted ring takes, and it is not much.\n *\n * A point entering a ring loads it in tension across two sections of wire. The\n * wire is a millimetre and a bit, so the force is a few hundred newtons and the\n * energy is a couple of joules — against the hundred-odd joules an arrow\n * carries.\n *\n * That is not a defect in the model. It is the reason mail was never worn on\n * its own. What stops the arrow is the padding, and the padding is textile.\n */\nexport function mailStrength(shape: MailShape = {}): MailStrength {\n  const alloy = shape.alloy ?? 'wroughtIron';\n  const spec = ALLOYS[alloy];\n  const wire = shape.wire ?? 0.0012;\n  const ring = shape.ring ?? 0.009;\n\n  const section = (Math.PI * wire * wire) / 4;\n  const force = 2 * section * spec.ultimate;\n  // The point has to open the ring by about its own radius before the wire\n  // parts, which is the stroke the work is done over.\n  const energy = force * (ring / 2);\n  // Four-in-one mail: roughly four rings' worth of wire per ring pitch.\n  const perRing = section * Math.PI * (ring + wire) * spec.density;\n  const pitch = (ring + wire) * (ring + wire);\n  return { alloy, force, energy, areal: pitch > 0 ? (4 * perRing) / pitch : 0 };\n}\n\n// ------------------------------------------------------------- the prop\n\nexport interface ArmourOptions extends PlateShape {\n  seed?: number;\n  /** How many strikes it takes before the panel is holed. */\n  hits?: number;\n}\n\nexport interface ArmourProp {\n  group: Group;\n  strength: PlateStrength;\n  /** Holes made so far. */\n  holes: number;\n  /**\n   * Strike it with an energy in JOULES.\n   *\n   * Joules and not newtons, and that is the opposite of `createBoard`: a board\n   * fails when the outer fibre reaches its rupture stress, so what runs out is\n   * force. A plate fails when a hole has been opened all the way through, so\n   * what runs out is WORK — force through the thickness. The two props take\n   * different units because they fail by different mechanisms, and pretending\n   * otherwise would be tidier and wrong.\n   */\n  strike(joules: number): boolean;\n  reset(): void;\n}\n\nexport function createArmour(options: ArmourOptions = {}): ArmourProp {\n  const strength = plateStrength(options);\n  const seed = options.seed ?? 1;\n  const w = options.width ?? 0.35;\n  const h = options.height ?? 0.45;\n  const t = options.thickness ?? 0.002;\n\n  const group = new Group();\n  const panel = new Mesh(\n    new BoxGeometry(w, h, Math.max(0.004, t * 3)),\n    createSurface('steel', { seed })\n  );\n  panel.position.y = h / 2;\n  group.add(panel);\n\n  const marks: Mesh[] = [];\n  const prop: ArmourProp = {\n    group,\n    strength,\n    holes: 0,\n    strike(joules: number): boolean {\n      if (!(joules >= strength.energy)) return false;\n      prop.holes++;\n      const hole = new Mesh(\n        new CylinderGeometry(0.008, 0.008, t * 4, 10),\n        createSurface('steel', { seed: seed + prop.holes })\n      );\n      hole.rotation.x = Math.PI / 2;\n      hole.position.set(\n        ((prop.holes * 37) % 100) / 100 - 0.5,\n        h / 2 + (((prop.holes * 61) % 100) / 100 - 0.5) * h * 0.6,\n        0\n      );\n      hole.position.x *= w * 0.7;\n      group.add(hole);\n      marks.push(hole);\n      return true;\n    },\n    reset(): void {\n      for (const m of marks) group.remove(m);\n      marks.length = 0;\n      prop.holes = 0;\n    },\n  };\n  return prop;\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;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AA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAuP9B,IAAM;AAAA;AAAA,EAAsB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA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","names":["import_three","import_three","import_three","import_three","import_three","import_three","import_three","slot","geo","mat","g","head","slot","import_three","import_three","head","import_three","import_three","import_three","mat","g","import_three","import_three","geo","import_three","geo","import_three","head","stock","import_three","slot","import_three","mat","geo","import_three","import_three","import_three","import_three","import_three","mat","g","import_three","ALL_STYLES","g","import_three","import_three","postH","board","g","geo","import_three","import_three","tint","import_three","head","import_three","shell","import_three","tint","UP","import_three","import_three","out","import_three","shell","head","slot","import_three","import_three","head","shell","import_three","makeWheel","chassis","stack","import_three","import_three","import_three","dir","hinge","slot","import_three","import_three","import_three","tint","head","import_three","shell","tint","slot","import_three","slot","shell","import_three","import_three","import_three","import_three","import_three","import_three","slot","slot","shell","import_three","import_three","clamp01","mat","slot","import_three","clamp01","g","state","tint","import_three","KINDS","head","slot","import_three","KINDS","clamp01","drive","import_three","clamp01","import_three","KINDS","clamp01","slot","drive","import_three","import_three","STYLES","ERAS","clamp01","smooth","shell","slot","api","running","head","import_three","clamp01","TAU","clamp01","KINDS","engine","drive","shell","g","worldQ","mat","import_three","clamp01","KINDS","import_three","clamp01","KINDS","import_three","RHO","G","clamp01","KINDS","head","mat","import_three","ERAS","g","axis","stack","drive","geo","import_three","clamp01","g","mat","slot","drive","geo","import_three","mat","import_three","head","g","import_three","import_three","import_three","geo","import_three","geo","mat","import_three","geo","slot","import_three","TAU","KINDS","basket","import_three","G","RHO","clamp01","import_three","clamp01","KINDS","head","import_three","ERAS","clamp01","top","import_three","KINDS","clamp01","import_three","KINDS","clamp01","smooth","g","import_three","ERAS","clamp01","smooth","bw","running","import_three","ERAS","clamp01","smooth","shell","running","import_three","mat","import_three","import_three","mat","import_three","UP","shell","import_three","import_three","g","slot","shell","SEGS","import_three","GRAVITY","import_three"]}