@adatechnology/game-items-three 0.1.5 → 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/index.ts","../src/kit.ts","../src/wear.ts","../src/shapes.ts","../src/data/models.json","../src/models/canned-beans.ts","../src/models/water-bottle.ts","../src/models/rice.ts","../src/models/military-ration.ts","../src/models/cachaca.ts","../src/models/first-aid-kit.ts","../src/models/bandage.ts","../src/models/amoxicillin.ts","../src/models/crowbar.ts","../src/models/hammer.ts","../src/models/machete.ts","../src/models/axe.ts","../src/models/nail-bat.ts","../src/models/hiking-backpack-40l.ts","../src/models/flashlight.ts","../src/models/portable-radio.ts","../src/models/house-key.ts","../src/models/survivor-diary.ts","../src/models/motorcycle-helmet.ts","../src/models/lpg-cylinder-13kg.ts","../src/models/fuel-jerrycan.ts","../src/models/walkie-talkies.ts","../src/models/batteries.ts","../src/models/wooden-plank.ts","../src/models/shipped.ts","../src/models/registry.ts","../src/build-item.ts","../../game-props3d/src/colors.ts","../../game-props3d/src/atlas.ts","../../game-props3d/src/catalog.ts","../../game-props3d/src/builders/ceiling.ts","../../game-props3d/src/builders/floors.ts","../../game-props3d/src/builders/shared.ts","../../game-props3d/src/builders/furniture.ts","../../game-props3d/src/builders/house-state.ts","../../game-props3d/src/builders/plants.ts","../../game-props3d/src/builders/wall.ts","../../game-props3d/src/builders/yard.ts","../../game-props3d/src/cover.ts","../../game-props3d/src/kit.ts","../../game-props3d/src/locale.ts","../../game-props3d/src/create.ts","../../game-props3d/src/node-skin.ts","../../game-props3d/src/recorder.ts","../../game-props3d/src/merge-by-material.ts","../src/merge.ts","../src/budgets.ts","../src/lod.ts","../src/models/deviations.ts","../src/thumbnails.ts","../../game-interactables/src/colliders.ts","../../game-interactables/src/rng.ts","../../game-interactables/src/loot.ts","../../game-interactables/src/locale.ts","../../game-interactables/src/math.ts","../../game-interactables/src/world.ts","../../game-contracts/src/impact.ts","../../game-contracts/src/body.ts","../../game-contracts/src/spec.ts","../../game-contracts/src/weapons.ts","../../game-contracts/src/animation.ts","../../game-contracts/src/tool-animation.ts","../../game-contracts/src/registry.ts","../../game-contracts/src/bench.ts","../../game-contracts/src/environment.ts","../../game-items/src/create-items.ts","../../game-items/src/categories.ts","../../game-items/src/types.ts","../../game-items/src/check-items.ts","../../game-items/src/rules.ts","../../game-items/src/decay.ts","../../game-items/src/protection.ts","../../game-items/src/carry.ts","../../game-items/src/use-effect.ts","../../game-items/src/recipes.ts","../../game-items/src/finds/depletion.ts","../../game-items/src/finds/rarity-pool.ts","../../game-items/src/finds/category-roll.ts","../../game-items/src/finds/explicit-pool.ts","../../game-items/src/finds/provider.ts","../../game-items/src/finds/spawn-state.ts","../../game-items/src/finds/place-finds.ts","../../game-items/src/finds/loot-tables.ts","../../game-items/src/arsenal-items.ts","../src/area-layout.ts","../src/area.ts"],"sourcesContent":["export { createItemKit, WEAR_TAGS } from './kit'\nexport type { ItemKit, ItemMaterialData, Vec3Tuple, WearTag } from './kit'\nexport { setWear, wearableMaterials, WEAR_AMOUNT, WEAR_TARGET } from './wear'\nexport type { WearStage } from './wear'\nexport { canonicalFrame, drawShape, isShape, shade, shapeOf, SHAPES } from './shapes'\nexport type { ShapeContext, ShapeId, ShapeSubject } from './shapes'\nexport { buildItem } from './build-item'\nexport type { BuildItemOptions, DrawableItem, ItemModel } from './build-item'\nexport { mergeItem } from './merge'\nexport { buildItemLod } from './lod'\nexport type { ItemLod, ItemLodOptions } from './lod'\nexport { checkBudget, countDrawCalls, countTriangles, cullDistanceOf, ITEM_BUDGETS, sizeClassOf, triangleBudgetOf } from './budgets'\nexport type { BudgetReport, ItemBudgets, ItemSizeClass, Vec3Like } from './budgets'\nexport { hasItemModel, itemModelBuilder, itemModelEntry, listItemModels, registerItemModel, unregisterItemModel } from './models/registry'\nexport type { ItemModelBuilder, ItemModelEntry } from './models/registry'\nexport { SHIPPED_MODELS } from './models/shipped'\nexport { MODEL_BUDGET_DEVIATIONS } from './models/deviations'\nexport { composeThumbnailScene, itemThumbnail, itemThumbnailSvg, renderItemThumbnail, shapeThumbnailSvg, thumbnailPatch } from './thumbnails'\nexport type { ThumbnailRenderer, ThumbnailRenderOptions, ThumbnailScene } from './thumbnails'\nexport { createItemsTestModule, FINDS_TABLE_ID, HUMAN_HEIGHT, HUMAN_ID, RULER_HEIGHT, RULER_ID, SHOWCASE_STAND_ID } from './area'\nexport type { ItemsAreaState, ItemsTestModule, ItemsTestModuleOptions, ScenarioLike } from './area'\nexport { ITEM_PREFIX, ROW_LIMIT, SHELF_HEIGHT, SHELF_PREFIX, SHOWCASE_PREFIX, shelvesLayout } from './area-layout'\nexport type { LayoutItem, ShelfPlan } from './area-layout'\n","import type * as THREE_NS from 'three'\n\ntype Three = typeof THREE_NS\n\n/** The material tags the team's showcase wears: what `setWear` turns toward its spoiled colour. */\nexport const WEAR_TAGS = ['metal', 'wood', 'cloth', 'plastic', 'paper', 'food', 'glass'] as const\nexport type WearTag = (typeof WEAR_TAGS)[number]\n\n/** What a material of the kit remembers so that `setWear` can go back to new: the colour it was made with (as three read it, and as sRGB floats), its tag and its roughness. */\nexport interface ItemMaterialData {\n base: THREE_NS.Color\n baseRgb: readonly [number, number, number]\n tag: string\n rough: number\n}\n\nexport type Vec3Tuple = readonly [number, number, number]\ntype Triple = [number, number, number]\n\n/**\n * The helpers the showcase page defines before its models (`M`, `mesh`, `cyl`, `bx`, `lathe`, `torus`, `extrude`, `G` and the seven material makers), so that the\n * builders ported from the page read the same as the originals. `T` is the three.js the kit was made with; `materials` lists every material it made, in order.\n */\nexport interface ItemKit {\n readonly T: Three\n readonly materials: THREE_NS.MeshStandardMaterial[]\n M(color: number, tag: string, options?: THREE_NS.MeshStandardMaterialParameters): THREE_NS.MeshStandardMaterial\n mesh(geometry: THREE_NS.BufferGeometry, material: THREE_NS.Material, position?: Vec3Tuple, rotation?: Vec3Tuple, scale?: Vec3Tuple): THREE_NS.Mesh\n cyl(radiusTop: number, radiusBottom: number, height: number, segments?: number): THREE_NS.CylinderGeometry\n bx(width: number, height: number, depth: number): THREE_NS.BoxGeometry\n lathe(points: ReadonlyArray<readonly [number, number]>, segments?: number): THREE_NS.LatheGeometry\n torus(radius: number, tube: number, arc?: number): THREE_NS.TorusGeometry\n extrude(points: ReadonlyArray<readonly [number, number]>, depth: number, bevel?: number): THREE_NS.ExtrudeGeometry\n G(...children: THREE_NS.Object3D[]): THREE_NS.Group\n metal(color: number): THREE_NS.MeshStandardMaterial\n wood(color: number): THREE_NS.MeshStandardMaterial\n cloth(color: number): THREE_NS.MeshStandardMaterial\n plastic(color: number): THREE_NS.MeshStandardMaterial\n paper(color: number): THREE_NS.MeshStandardMaterial\n food(color: number): THREE_NS.MeshStandardMaterial\n glass(color: number, opacity: number): THREE_NS.MeshStandardMaterial\n}\n\n/** The channels of a hex as r128 (the team's three.js) stores them: each one over 255, as given, with no conversion. */\nconst channelsOf = (hex: number): readonly [number, number, number] => [((hex >> 16) & 255) / 255, ((hex >> 8) & 255) / 255, (hex & 255) / 255]\n\n/** The helpers of the showcase page on a given three.js; every kit has its own list of materials. */\nexport function createItemKit(T: Three): ItemKit {\n const materials: THREE_NS.MeshStandardMaterial[] = []\n const M: ItemKit['M'] = (color, tag, options = {}) => {\n const material = new T.MeshStandardMaterial(Object.assign({ color, roughness: 0.78, metalness: 0 }, options))\n const base = new T.Color(color)\n const data: ItemMaterialData = { base, baseRgb: channelsOf(color), tag, rough: material.roughness }\n material.userData = data\n materials.push(material)\n return material\n }\n const mesh: ItemKit['mesh'] = (geometry, material, position = [0, 0, 0], rotation = [0, 0, 0], scale) => {\n const object = new T.Mesh(geometry, material)\n object.position.set(...(position as Triple))\n object.rotation.set(...(rotation as Triple))\n if (scale) object.scale.set(...(scale as Triple))\n return object\n }\n return {\n T,\n materials,\n M,\n mesh,\n cyl: (radiusTop, radiusBottom, height, segments = 14) => new T.CylinderGeometry(radiusTop, radiusBottom, height, segments),\n bx: (width, height, depth) => new T.BoxGeometry(width, height, depth),\n lathe: (points, segments = 16) => new T.LatheGeometry(points.map(([x, y]) => new T.Vector2(x, y)), segments),\n torus: (radius, tube, arc = Math.PI * 2) => new T.TorusGeometry(radius, tube, 8, 18, arc),\n extrude: (points, depth, bevel = 0.015) => {\n const shape = new T.Shape()\n points.forEach(([x, y], index) => (index ? shape.lineTo(x, y) : shape.moveTo(x, y)))\n return new T.ExtrudeGeometry(shape, { depth, bevelEnabled: true, bevelThickness: bevel, bevelSize: bevel, bevelSegments: 2 })\n },\n G: (...children) => {\n const group = new T.Group()\n children.forEach((child) => group.add(child))\n return group\n },\n metal: (color) => M(color, 'metal', { metalness: 0.55, roughness: 0.45 }),\n wood: (color) => M(color, 'wood'),\n cloth: (color) => M(color, 'cloth', { roughness: 0.95 }),\n plastic: (color) => M(color, 'plastic', { roughness: 0.6 }),\n paper: (color) => M(color, 'paper', { roughness: 0.9 }),\n food: (color) => M(color, 'food', { roughness: 0.85 }),\n glass: (color, opacity) => M(color, 'glass', { roughness: 0.15, metalness: 0.1, transparent: true, opacity }),\n }\n}\n","import type * as THREE_NS from 'three'\n\nimport type { ItemMaterialData } from './kit'\n\n/** 0 new, 1 used, 2 spoiled (the three stages of the showcase). */\nexport type WearStage = 0 | 1 | 2\n\n/** The colour each material tag turns toward as it wears (`STAGE_TARGET` of the showcase). */\nexport const WEAR_TARGET: Readonly<Record<string, number>> = { food: 0x5d6b2e, metal: 0x7a3e1d, wood: 0x3f3326, cloth: 0x4a4033, plastic: 0x6b6556, paper: 0x8a7a52, glass: 0x55503a }\n\n/** How far toward the target colour each stage goes (`AMT`). */\nexport const WEAR_AMOUNT: readonly [number, number, number] = [0, 0.3, 0.62]\n\nconst hexToRgb = (hex: number): readonly [number, number, number] => [((hex >> 16) & 255) / 255, ((hex >> 8) & 255) / 255, (hex & 255) / 255]\n\nconst dataOf = (material: THREE_NS.Material): ItemMaterialData | undefined => {\n const data = material.userData as Partial<ItemMaterialData>\n return data.base && data.baseRgb && data.tag !== undefined && data.rough !== undefined ? (data as ItemMaterialData) : undefined\n}\n\n/** Every material under `root` that the kit made (with a tag), once each. */\nexport function wearableMaterials(root: THREE_NS.Object3D): THREE_NS.MeshStandardMaterial[] {\n const found = new Set<THREE_NS.MeshStandardMaterial>()\n root.traverse((object) => {\n const mesh = object as THREE_NS.Mesh\n if (!mesh.isMesh) return\n for (const material of Array.isArray(mesh.material) ? mesh.material : [mesh.material]) if (dataOf(material)) found.add(material as THREE_NS.MeshStandardMaterial)\n })\n return [...found]\n}\n\n/**\n * Sets the wear of an item (`setStage` of the showcase): each material goes from its own colour toward the target of its tag by `WEAR_AMOUNT[stage]`, gets rougher, and\n * metal loses its shine. The colours are mixed in sRGB, as the page mixes them (three r128 had no colour management), so stage 0 is exactly the colour the material was made with.\n * Takes the object or the list of materials of a kit.\n */\nexport function setWear(target: THREE_NS.Object3D | readonly THREE_NS.MeshStandardMaterial[], stage: WearStage): void {\n const materials = 'traverse' in target ? wearableMaterials(target) : target\n if ('traverse' in target) target.userData.wear = stage\n const amount = WEAR_AMOUNT[stage]\n for (const material of materials) {\n const data = dataOf(material)\n if (!data) continue\n const goal = WEAR_TARGET[data.tag]\n if (goal === undefined) continue\n const [tr, tg, tb] = hexToRgb(goal)\n const [r, g, b] = data.baseRgb\n material.color.setRGB(r + (tr - r) * amount, g + (tg - g) * amount, b + (tb - b) * amount, 'srgb')\n material.roughness = Math.min(1, data.rough + (0.2 * stage) / 2)\n if (data.tag === 'metal') material.metalness = Math.max(0.1, 0.55 - 0.2 * stage)\n }\n}\n","import type * as THREE_NS from 'three'\n\nimport type { ItemKit, Vec3Tuple } from './kit'\n\n/** The simple shapes the kit draws at the real size of an item, by the `shape` hint of its definition. */\nexport const SHAPES = [\n 'can', 'bag', 'box', 'bottle', 'tool', 'roll', 'dish', 'cloth', 'shoe', 'jar', 'paper', 'fruit', 'cup', 'tube',\n 'blade', 'long_tool', 'garment', 'backpack', 'jerrycan', 'tank', 'book', 'key', 'battery', 'plank', 'device',\n] as const\nexport type ShapeId = (typeof SHAPES)[number]\n\n/** What a shape drawer is given: the kit, the size in metres, the colour of the item and the level of detail (1 full, 0.5 half the segments). */\nexport interface ShapeContext {\n k: ItemKit\n w: number\n h: number\n d: number\n color: number\n detail: number\n}\ntype Drawer = (c: ShapeContext) => THREE_NS.Group\n\nconst DEFAULT_COLOR = 0x8a8f94\nconst PI = Math.PI\n\n/** The colour `factor` times lighter (above 1) or darker (below 1), per channel. */\nexport function shade(color: number, factor: number): number {\n const channel = (shift: number): number => Math.max(0, Math.min(255, Math.round(((color >> shift) & 255) * factor)))\n return (channel(16) << 16) | (channel(8) << 8) | channel(0)\n}\n\n/** Segments of a round part at a level of detail: never below 5. */\nconst seg = (c: ShapeContext, n: number): number => Math.max(5, Math.round(n * c.detail))\n\n/** The long axis of a size and the three sides in the frame where that axis is x: `L` long, `a` the next, `b` the shortest of the other two in their own order. */\nexport function canonicalFrame(size: Vec3Tuple): { axis: 0 | 1 | 2; L: number; a: number; b: number } {\n const [w, h, d] = size\n if (h >= w && h >= d) return { axis: 1, L: h, a: w, b: d }\n if (d >= w && d >= h) return { axis: 2, L: d, a: h, b: w }\n return { axis: 0, L: w, a: h, b: d }\n}\n\n/** Turns a group drawn with its long side on x so that the long side lies on the given axis. */\nfunction orient(c: ShapeContext, group: THREE_NS.Group, axis: 0 | 1 | 2): THREE_NS.Group {\n if (axis === 0) return group\n const holder = c.k.G(group)\n if (axis === 1) holder.rotation.z = PI / 2\n else holder.rotation.y = -PI / 2\n return holder\n}\n\n/** A shape drawn along x in the frame `(L, a, b)`, then turned onto the long axis of the size. */\nconst alongLong = (draw: (c: ShapeContext, L: number, a: number, b: number) => THREE_NS.Group): Drawer => (c) => {\n const { axis, L, a, b } = canonicalFrame([c.w, c.h, c.d])\n return orient(c, draw(c, L, a, b), axis)\n}\n\n/** A group drawn with a radius of 0.5 and stretched to the width and depth of the item (an oval can fills its box). */\nconst across = (c: ShapeContext, group: THREE_NS.Group): THREE_NS.Group => {\n group.scale.set(c.w, 1, c.d)\n return c.k.G(group)\n}\n\nconst can: Drawer = (c) => {\n const { k, h } = c\n const body = k.metal(0x8d9096)\n return across(c, k.G(k.mesh(k.cyl(0.5, 0.5, h * 0.94, seg(c, 14)), body), k.mesh(k.cyl(0.5, 0.5, h * 0.5, seg(c, 14)), k.food(c.color), [0, 0, 0], [0, 0, 0], [1.0, 1, 1.0]), k.mesh(k.cyl(0.5, 0.5, h * 0.03, seg(c, 14)), body, [0, h * 0.485, 0]), k.mesh(k.cyl(0.5, 0.5, h * 0.03, seg(c, 14)), body, [0, -h * 0.485, 0])))\n}\n\nconst bottle: Drawer = (c) => {\n const { k, h } = c\n const r = 0.5\n const profile: Array<[number, number]> = [[0, -h / 2], [r, -h / 2], [r, h * 0.12], [r * 0.45, h * 0.3], [r * 0.4, h * 0.4], [0, h * 0.4]]\n return across(c, k.G(k.mesh(k.lathe(profile, seg(c, 14)), k.glass(c.color, 0.6)), k.mesh(k.cyl(r * 0.42, r * 0.42, h * 0.1, seg(c, 10)), k.plastic(shade(c.color, 0.5)), [0, h * 0.45, 0])))\n}\n\nconst jar: Drawer = (c) => {\n const { k, h } = c\n return across(c, k.G(k.mesh(k.cyl(0.5, 0.5, h * 0.82, seg(c, 14)), k.glass(c.color, 0.55), [0, -h * 0.09, 0]), k.mesh(k.cyl(0.5, 0.5, h * 0.18, seg(c, 14)), k.metal(0xb8913a), [0, h * 0.41, 0])))\n}\n\nconst bag: Drawer = (c) => {\n const { k, w, h, d } = c\n return k.G(k.mesh(k.bx(w, h * 0.88, d), k.paper(c.color), [0, -h * 0.06, 0]), k.mesh(k.bx(w * 1.0, h * 0.12, d * 0.5), k.paper(shade(c.color, 0.85)), [0, h * 0.44, 0]), k.mesh(k.bx(w * 0.7, h * 0.3, d * 1.0), k.paper(shade(c.color, 1.2)), [0, 0, 0]))\n}\n\nconst box: Drawer = (c) => {\n const { k, w, h, d } = c\n return k.G(k.mesh(k.bx(w, h, d), k.paper(c.color)), k.mesh(k.bx(w, h * 0.12, d), k.paper(shade(c.color, 0.8)), [0, h * 0.44, 0]), k.mesh(k.bx(w * 0.62, h * 0.4, d), k.paper(shade(c.color, 1.25)), [0, -h * 0.02, 0]))\n}\n\nconst cloth: Drawer = (c) => {\n const { k, w, h, d } = c\n const material = k.cloth(c.color)\n return k.G(k.mesh(k.bx(w, h * 0.55, d), material, [0, -h * 0.225, 0]), k.mesh(k.bx(w * 0.96, h * 0.45, d * 0.96), k.cloth(shade(c.color, 0.9)), [0, h * 0.275, 0]))\n}\n\nconst paper: Drawer = (c) => {\n const { k, w, h, d } = c\n const sheet = k.paper(c.color)\n return k.G(k.mesh(k.bx(w, h / 3, d), sheet, [0, -h / 3, 0]), k.mesh(k.bx(w * 0.98, h / 3, d * 0.98), k.paper(shade(c.color, 0.95)), [0, 0, 0]), k.mesh(k.bx(w, h / 3, d), sheet, [0, h / 3, 0]))\n}\n\nconst fruit: Drawer = (c) => {\n const { k, w, h, d } = c\n const sphere = new k.T.SphereGeometry(0.5, seg(c, 12), seg(c, 8))\n return k.G(k.mesh(sphere, k.food(c.color), [0, -h * 0.04, 0], [0, 0, 0], [w, h * 0.92, d]), k.mesh(k.cyl(h * 0.02, h * 0.02, h * 0.1, 6), k.wood(0x5a3a22), [0, h * 0.45, 0]))\n}\n\nconst dish: Drawer = (c) => {\n const { k, w, h, d } = c\n return k.G(k.mesh(k.cyl(0.5, 0.35, h, seg(c, 16)), k.plastic(c.color), [0, 0, 0], [0, 0, 0], [w, 1, d]))\n}\n\nconst cup: Drawer = (c) => {\n const { k, w, h, d } = c\n const profile: Array<[number, number]> = [[0, -h / 2], [0.38, -h / 2], [0.5, h / 2], [0.44, h / 2], [0.33, -h / 2 + h * 0.06], [0, -h / 2 + h * 0.06]]\n return k.G(k.mesh(k.lathe(profile, seg(c, 14)), k.plastic(c.color), [0, 0, 0], [0, 0, 0], [w, 1, d]))\n}\n\nconst tube: Drawer = (c) => {\n const { k, h } = c\n const material = k.plastic(c.color)\n return across(c, k.G(k.mesh(k.cyl(0.5, 0.42, h * 0.86, seg(c, 12)), material, [0, -h * 0.04, 0]), k.mesh(k.cyl(0.35, 0.35, h * 0.12, seg(c, 12)), k.plastic(shade(c.color, 0.6)), [0, h * 0.44, 0]), k.mesh(k.bx(1, h * 0.06, 0.25), material, [0, -h * 0.47, 0])))\n}\n\nconst roll: Drawer = (c) => {\n const { k, w, h, d } = c\n // the roll lies with its axis along the shortest side; the other two sides are the (oval) section\n const body = k.G(k.mesh(k.cyl(0.5, 0.5, 1, seg(c, 18)), k.paper(c.color)), k.mesh(k.cyl(0.18, 0.18, 0.98, seg(c, 12)), k.paper(0xb59d78)))\n if (h <= w && h <= d) body.scale.set(w, h, d)\n else if (w <= d) {\n body.rotation.z = PI / 2\n body.scale.set(h, w, d)\n } else {\n body.rotation.x = PI / 2\n body.scale.set(w, d, h)\n }\n return k.G(body)\n}\n\nconst shoe: Drawer = (c) => {\n const { k, w, h, d } = c\n const upper = k.cloth(c.color)\n return k.G(k.mesh(k.bx(w, h * 0.22, d), k.plastic(0x22251f), [0, -h * 0.39, 0]), k.mesh(k.bx(w * 0.42, h * 0.78, d * 0.96), upper, [-w * 0.29, h * 0.11, 0]), k.mesh(k.bx(w * 0.5, h * 0.5, d * 0.96), upper, [w * 0.25, -h * 0.03, 0]))\n}\n\nconst tool: Drawer = alongLong((c, L, a, b) => {\n const { k } = c\n const radius = Math.max(0.004, Math.min(a, b) / 2)\n return k.G(k.mesh(k.cyl(radius, radius, L * 0.74, seg(c, 10)), k.wood(0x8a643c), [-L * 0.13, 0, 0], [0, 0, PI / 2]), k.mesh(k.bx(L * 0.26, a, b), k.metal(shade(c.color, 1)), [L * 0.37, 0, 0]))\n})\n\nconst longTool: Drawer = alongLong((c, L, a, b) => {\n const { k } = c\n const radius = Math.max(0.004, Math.min(a, b) / 2) * 0.55\n return k.G(k.mesh(k.cyl(radius, radius, L * 0.94, seg(c, 10)), k.wood(0x9a7448), [0, 0, 0], [0, 0, PI / 2]), k.mesh(k.bx(L * 0.12, a, b), k.metal(c.color), [L * 0.44, 0, 0]))\n})\n\nconst blade: Drawer = alongLong((c, L, a, b) => {\n const { k } = c\n const edge = Math.min(0.0002, b * 0.05)\n const steel = k.extrude([[0, 0], [L * 0.66, 0], [L * 0.68, a * 0.4], [0, a]], Math.max(0.0005, b * 0.4 - 2 * edge), edge)\n return k.G(k.mesh(steel, k.metal(0xa9adb0), [-L * 0.18, -a / 2, -b * 0.2 + edge]), k.mesh(k.bx(L * 0.34, a * 0.6, b), k.wood(0x3b2a20), [-L * 0.33, 0, 0]))\n})\n\nconst garment: Drawer = (c) => {\n const { k, w, h, d } = c\n const material = k.cloth(c.color)\n return k.G(k.mesh(k.bx(w * 0.56, h, d), material), k.mesh(k.bx(w * 0.22, h * 0.42, d * 0.9), material, [-w * 0.39, h * 0.29, 0]), k.mesh(k.bx(w * 0.22, h * 0.42, d * 0.9), material, [w * 0.39, h * 0.29, 0]))\n}\n\nconst backpack: Drawer = (c) => {\n const { k, w, h, d } = c\n const material = k.cloth(c.color)\n const dome = new k.T.SphereGeometry(0.5, seg(c, 12), seg(c, 6), 0, PI * 2, 0, PI / 2)\n const strap = k.cloth(shade(c.color, 0.6))\n return k.G(k.mesh(k.bx(w, h * 0.78, d * 0.68), material, [0, -h * 0.11, -d * 0.14]), k.mesh(dome, material, [0, h * 0.28, -d * 0.14], [0, 0, 0], [w, h * 0.44, d * 0.68]), k.mesh(k.bx(w * 0.7, h * 0.4, d * 0.3), k.cloth(shade(c.color, 0.75)), [0, -h * 0.18, d * 0.35]), k.mesh(k.bx(w * 0.1, h * 0.7, d * 0.04), strap, [-w * 0.25, -h * 0.05, -d * 0.48]), k.mesh(k.bx(w * 0.1, h * 0.7, d * 0.04), strap, [w * 0.25, -h * 0.05, -d * 0.48]))\n}\n\nconst jerrycan: Drawer = (c) => {\n const { k, w, h, d } = c\n const material = k.plastic(c.color)\n return k.G(k.mesh(k.bx(w, h * 0.86, d), material, [0, -h * 0.07, 0]), k.mesh(k.bx(w * 0.4, h * 0.1, d * 0.5), material, [-w * 0.2, h * 0.45, 0]), k.mesh(k.cyl(d * 0.14, d * 0.18, h * 0.12, seg(c, 10)), k.plastic(0xd9a441), [w * 0.3, h * 0.44, 0]))\n}\n\nconst tank: Drawer = (c) => {\n const { k, h } = c\n const r = 0.5\n const profile: Array<[number, number]> = [[0, -h / 2], [r * 0.9, -h / 2], [r, -h * 0.4], [r, h * 0.22], [r * 0.6, h * 0.36], [r * 0.2, h * 0.4], [0, h * 0.4]]\n const metal = k.metal(c.color)\n return across(c, k.G(k.mesh(k.lathe(profile, seg(c, 14)), metal), k.mesh(k.cyl(r * 0.62, r * 0.62, h * 0.05, seg(c, 14)), metal, [0, h * 0.3, 0]), k.mesh(k.cyl(r * 0.18, r * 0.18, h * 0.12, seg(c, 8)), k.metal(0xb8913a), [0, h * 0.44, 0])))\n}\n\nconst book: Drawer = (c) => {\n const { k, w, h, d } = c\n const cover = k.paper(c.color)\n return k.G(k.mesh(k.bx(w, h, d * 0.14), cover, [0, 0, d * 0.43]), k.mesh(k.bx(w, h, d * 0.14), cover, [0, 0, -d * 0.43]), k.mesh(k.bx(w * 0.94, h * 0.96, d * 0.72), k.paper(0xe9e1cc), [w * 0.02, 0, 0]), k.mesh(k.bx(w * 0.08, h, d), k.paper(shade(c.color, 0.8)), [-w * 0.46, 0, 0]))\n}\n\nconst key: Drawer = alongLong((c, L, a, b) => {\n const { k } = c\n const metal = k.metal(0xb8913a)\n const ring = a * 0.5\n const tube = Math.min(b * 0.4, ring * 0.2)\n return k.G(k.mesh(new c.k.T.TorusGeometry(ring * 0.8, tube, 5, seg(c, 10)), k.metal(0x9a9da0), [-L / 2 + ring * 0.8 + tube, 0, 0]), k.mesh(k.bx(L * 0.62, a * 0.28, b), metal, [L * 0.12, 0, 0]), k.mesh(k.bx(L * 0.08, a * 0.22, b), metal, [L * 0.36, -a * 0.2, 0]), k.mesh(k.bx(L * 0.06, a * 0.22, b), metal, [L * 0.2, -a * 0.2, 0]))\n})\n\nconst battery: Drawer = alongLong((c, L, a, b) => {\n const { k } = c\n const r = Math.min(a, b) / 2\n return k.G(k.mesh(k.cyl(r, r, L * 0.94, seg(c, 14)), k.metal(c.color), [0, 0, 0], [0, 0, PI / 2]), k.mesh(k.cyl(r * 0.36, r * 0.36, L * 0.06, seg(c, 8)), k.metal(0xb9bdc0), [L * 0.47, 0, 0], [0, 0, PI / 2]))\n})\n\nconst plank: Drawer = alongLong((c, L, a, b) => {\n const { k } = c\n const nail = k.metal(0x7d8186)\n return k.G(k.mesh(k.bx(L, a, b), k.wood(0xa88459)), k.mesh(k.cyl(Math.min(a, b) * 0.1, Math.min(a, b) * 0.1, b * 0.98, 6), nail, [-L * 0.4, 0, 0], [PI / 2, 0, 0]), k.mesh(k.cyl(Math.min(a, b) * 0.1, Math.min(a, b) * 0.1, b * 0.98, 6), nail, [L * 0.4, 0, 0], [PI / 2, 0, 0]))\n})\n\nconst device: Drawer = (c) => {\n const { k, w, h, d } = c\n const screen = k.M(0x9fbf8a, 'glass', { emissive: 0x2f4a22, emissiveIntensity: 0.6, roughness: 0.2 })\n return k.G(k.mesh(k.bx(w, h, d * 0.96), k.plastic(c.color), [0, 0, -d * 0.02]), k.mesh(k.bx(w * 0.7, h * 0.32, d * 0.06), screen, [0, h * 0.22, d * 0.47]), k.mesh(k.cyl(Math.min(w, h) * 0.08, Math.min(w, h) * 0.08, d * 0.1, seg(c, 8)), k.metal(0xb9bdc0), [w * 0.25, -h * 0.18, d * 0.45], [PI / 2, 0, 0]))\n}\n\nconst DRAWERS: Readonly<Record<ShapeId, Drawer>> = {\n can, bag, box, bottle, tool, roll, dish, cloth, shoe, jar, paper, fruit, cup, tube, blade, long_tool: longTool, garment, backpack, jerrycan, tank, book, key, battery, plank, device,\n}\n\nexport const isShape = (value: string | undefined): value is ShapeId => value !== undefined && value in DRAWERS\n\n/** The item fields the shape choice reads. */\nexport interface ShapeSubject {\n category: string\n size: Vec3Tuple\n shape?: string\n color?: number\n}\n\n/**\n * The shape an item is drawn with: its own `shape` when it names one of the 25, else a box. The hints the household catalog uses (`tool`, `cloth`, `bag`, `box`, `paper`) are\n * refined by the category and the proportions, so that a rake is a long tool, a jacket a garment, a rucksack a backpack, a phone a device and a diary a book.\n */\nexport function shapeOf(subject: ShapeSubject): ShapeId {\n const hint = subject.shape\n if (!isShape(hint)) return 'box'\n const [w, h, d] = subject.size\n const { L, a, b } = canonicalFrame(subject.size)\n const long = L / Math.max(a, b, 1e-6) >= 4\n const flat = Math.min(w, h, d) / Math.max(w, h, d) <= 0.2\n switch (hint) {\n case 'tool':\n if (subject.category === 'keys') return 'key'\n if (subject.category === 'electronics') return 'device'\n if (long) return subject.category === 'melee' && Math.min(a, b) / L <= 0.1 && flat ? 'blade' : 'long_tool'\n return hint\n case 'cloth':\n return subject.category === 'clothing' ? 'garment' : hint\n case 'bag':\n return subject.category === 'bags' ? 'backpack' : hint\n case 'box':\n if (subject.category === 'electronics') return 'device'\n if (subject.category === 'books') return 'book'\n if (subject.category === 'keys') return 'key'\n return hint\n case 'paper':\n return subject.category === 'books' ? 'book' : hint\n default:\n return hint\n }\n}\n\n/** Draws the simple shape of an item at its real size, centred on the origin (the long side of long shapes lies on the long axis of `size`). */\nexport function drawShape(k: ItemKit, shape: ShapeId, size: Vec3Tuple, options: { color?: number; detail?: number } = {}): THREE_NS.Group {\n const [w, h, d] = size\n return DRAWERS[shape]({ k, w, h, d, color: options.color ?? DEFAULT_COLOR, detail: options.detail ?? 1 })\n}\n","[\n {\n \"id\": \"canned_beans\",\n \"teamId\": \"feijao_lata\",\n \"teamBox\": [\n 0.67,\n 0.57,\n 0.66\n ],\n \"scale\": 0.119403\n },\n {\n \"id\": \"water_bottle\",\n \"teamId\": \"agua_500\",\n \"teamBox\": [\n 0.452,\n 1.25,\n 0.452\n ],\n \"scale\": 0.146018\n },\n {\n \"id\": \"rice\",\n \"teamId\": \"arroz\",\n \"teamBox\": [\n 0.72,\n 1.055,\n 0.3\n ],\n \"scale\": 0.236967\n },\n {\n \"id\": \"military_ration\",\n \"teamId\": \"racao_militar\",\n \"teamBox\": [\n 0.77,\n 1.03,\n 0.235\n ],\n \"scale\": 0.252427\n },\n {\n \"id\": \"cachaca\",\n \"teamId\": \"cachaca\",\n \"teamBox\": [\n 0.552,\n 1.31,\n 0.552\n ],\n \"scale\": 0.163043\n },\n {\n \"id\": \"first_aid_kit\",\n \"teamId\": \"kit_ps\",\n \"teamBox\": [\n 1.07,\n 0.915,\n 0.41\n ],\n \"scale\": 0.233645\n },\n {\n \"id\": \"bandage\",\n \"teamId\": \"atadura\",\n \"teamBox\": [\n 0.9851,\n 0.7575,\n 0.43\n ],\n \"scale\": 0.102528\n },\n {\n \"id\": \"amoxicillin\",\n \"teamId\": \"amoxicilina\",\n \"teamBox\": [\n 0.8859,\n 0.47,\n 0.607\n ],\n \"scale\": 0.11288\n },\n {\n \"id\": \"crowbar\",\n \"teamId\": \"pe_cabra\",\n \"teamBox\": [\n 0.428,\n 1.7087,\n 0.11\n ],\n \"scale\": 0.43893\n },\n {\n \"id\": \"hammer\",\n \"teamId\": \"martelo\",\n \"teamBox\": [\n 0.6487,\n 1.3477,\n 0.19\n ],\n \"scale\": 0.244862\n },\n {\n \"id\": \"machete\",\n \"teamId\": \"facao\",\n \"teamBox\": [\n 1.8759,\n 0.2906,\n 0.12\n ],\n \"scale\": 0.293193\n },\n {\n \"id\": \"axe\",\n \"teamId\": \"machado\",\n \"teamBox\": [\n 0.5952,\n 1.6693,\n 0.14\n ],\n \"scale\": 0.419337\n },\n {\n \"id\": \"nail_bat\",\n \"teamId\": \"taco_pregos\",\n \"teamBox\": [\n 0.4384,\n 1.69,\n 0.4352\n ],\n \"scale\": 0.508876\n },\n {\n \"id\": \"hiking_backpack_40l\",\n \"teamId\": \"mochila_trilha\",\n \"teamBox\": [\n 0.8,\n 1.07,\n 0.62\n ],\n \"scale\": 0.514019\n },\n {\n \"id\": \"flashlight\",\n \"teamId\": \"lanterna\",\n \"teamBox\": [\n 0.38,\n 1.08,\n 0.38\n ],\n \"scale\": 0.148148\n },\n {\n \"id\": \"portable_radio\",\n \"teamId\": \"radio_portatil\",\n \"teamBox\": [\n 1.1041,\n 1.4821,\n 0.35\n ],\n \"scale\": 0.199257\n },\n {\n \"id\": \"house_key\",\n \"teamId\": \"chave_casa\",\n \"teamBox\": [\n 1.5433,\n 0.8305,\n 0.08\n ],\n \"scale\": 0.055077\n },\n {\n \"id\": \"survivor_diary\",\n \"teamId\": \"diario\",\n \"teamBox\": [\n 0.8,\n 1.04,\n 0.27\n ],\n \"scale\": 0.201923\n },\n {\n \"id\": \"motorcycle_helmet\",\n \"teamId\": \"capacete_moto\",\n \"teamBox\": [\n 1.11,\n 1.0825,\n 1.17\n ],\n \"scale\": 0.234234\n },\n {\n \"id\": \"lpg_cylinder_13kg\",\n \"teamId\": \"botijao\",\n \"teamBox\": [\n 0.9257,\n 1.285,\n 0.94\n ],\n \"scale\": 0.381323\n },\n {\n \"id\": \"fuel_jerrycan\",\n \"teamId\": \"galao\",\n \"teamBox\": [\n 0.8788,\n 1.342,\n 0.44\n ],\n \"scale\": 0.350224\n },\n {\n \"id\": \"walkie_talkies\",\n \"teamId\": \"walkie\",\n \"teamBox\": [\n 0.465,\n 1.47,\n 0.22\n ],\n \"scale\": 0.14966\n },\n {\n \"id\": \"batteries\",\n \"teamId\": \"pilha_aa\",\n \"teamBox\": [\n 0.744,\n 1.005,\n 0.344\n ],\n \"scale\": 0.050249\n },\n {\n \"id\": \"wooden_plank\",\n \"teamId\": \"tabua\",\n \"teamBox\": [\n 1.5203,\n 0.4741,\n 0.5377\n ],\n \"scale\": 0.526212\n }\n]\n","import type { ItemModelBuilder } from './registry'\n\n/**\n * `MODELS[\"feijao_lata\"]` of the Itens do Vale Cinzento showcase (`armas-itens__itens-vale-cinzento.js` L145), ported as it is: same units, same parts, same order, same materials by tag.\n * It draws in the units of the page; `data/models.json` gives the scale to metres of the item `canned_beans`.\n */\nexport const cannedBeans: ItemModelBuilder = ({ mesh, cyl, torus, G, metal, paper, food }) => { const m = metal(0x8d9096); return G(mesh(cyl(.32, .32, .52), m), mesh(cyl(.326, .326, .34, 14), food(0x9b3a24)), mesh(cyl(.33, .33, .06), paper(0xe2c36a), [0, .02, 0]), mesh(torus(.31, .025), m, [0, .26, 0], [Math.PI / 2, 0, 0]), mesh(torus(.31, .025), m, [0, -.26, 0], [Math.PI / 2, 0, 0])); }\n","import type { ItemModelBuilder } from './registry'\n\n/**\n * `MODELS[\"agua_500\"]` of the Itens do Vale Cinzento showcase (`armas-itens__itens-vale-cinzento.js` L146), ported as it is: same units, same parts, same order, same materials by tag.\n * It draws in the units of the page; `data/models.json` gives the scale to metres of the item `water_bottle`.\n */\nexport const waterBottle: ItemModelBuilder = ({ mesh, cyl, lathe, G, plastic, paper, glass }) => G(mesh(lathe([[0, -.6], [.2, -.6], [.22, -.5], [.22, .2], [.19, .32], [.09, .45], [.08, .55], [0, .55]]), glass(0x8fc3dc, .55)), mesh(cyl(.085, .085, .1, 12), plastic(0x2c5d8a), [0, .6, 0]), mesh(cyl(.225, .225, .22, 16), paper(0xe9ecef), [0, -.15, 0]), mesh(cyl(.226, .226, .05, 16), plastic(0x3a78a8), [0, -.12, 0]))\n","import type { ItemModelBuilder } from './registry'\n\n/**\n * `MODELS[\"arroz\"]` of the Itens do Vale Cinzento showcase (`armas-itens__itens-vale-cinzento.js` L147), ported as it is: same units, same parts, same order, same materials by tag.\n * It draws in the units of the page; `data/models.json` gives the scale to metres of the item `rice`.\n */\nexport const rice: ItemModelBuilder = ({ mesh, bx, G, paper, food }) => G(mesh(bx(.7, .95, .28), paper(0xe6dcc0)), mesh(bx(.72, .12, .1), paper(0xd5c9a8), [0, .52, 0]), mesh(bx(.5, .3, .02), food(0xb5521f), [0, .05, .15]), mesh(bx(.3, .1, .02), paper(0x3f7a45), [0, -.25, .15]))\n","import type { ItemModelBuilder } from './registry'\n\n/**\n * `MODELS[\"racao_militar\"]` of the Itens do Vale Cinzento showcase (`armas-itens__itens-vale-cinzento.js` L148), ported as it is: same units, same parts, same order, same materials by tag.\n * It draws in the units of the page; `data/models.json` gives the scale to metres of the item `military_ration`.\n */\nexport const militaryRation: ItemModelBuilder = ({ mesh, bx, G, plastic, paper }) => G(mesh(bx(.75, 1, .22), plastic(0x5a6146)), mesh(bx(.77, .1, .23), plastic(0x474d37), [0, .48, 0]), mesh(bx(.5, .14, .01), paper(0x22251f), [0, .18, .115]), mesh(bx(.36, .06, .01), paper(0x22251f), [0, -.02, .115]))\n","import type { ItemModelBuilder } from './registry'\n\n/**\n * `MODELS[\"cachaca\"]` of the Itens do Vale Cinzento showcase (`armas-itens__itens-vale-cinzento.js` L149), ported as it is: same units, same parts, same order, same materials by tag.\n * It draws in the units of the page; `data/models.json` gives the scale to metres of the item `cachaca`.\n */\nexport const cachaca: ItemModelBuilder = ({ mesh, cyl, lathe, G, wood, paper, food, glass }) => G(mesh(lathe([[0, -.6], [.25, -.6], [.27, -.52], [.27, .1], [.2, .25], [.09, .35], [.09, .58], [0, .58]]), glass(0xc28a2a, .78)), mesh(cyl(.08, .07, .14, 10), wood(0x8a6a44), [0, .64, 0]), mesh(cyl(.275, .275, .34, 16), paper(0xe9e1cc), [0, -.25, 0]), mesh(cyl(.276, .276, .06, 16), food(0x7a2f1f), [0, -.15, 0]))\n","import type { ItemModelBuilder } from './registry'\n\n/**\n * `MODELS[\"kit_ps\"]` of the Itens do Vale Cinzento showcase (`armas-itens__itens-vale-cinzento.js` L150), ported as it is: same units, same parts, same order, same materials by tag.\n * It draws in the units of the page; `data/models.json` gives the scale to metres of the item `first_aid_kit`.\n */\nexport const firstAidKit: ItemModelBuilder = ({ mesh, bx, torus, G, plastic }) => { const r = plastic(0xb23a2c); return G(mesh(bx(1.05, .72, .38), plastic(0xe6e3d8)), mesh(bx(1.07, .06, .4), plastic(0xbdb8aa), [0, 0, 0]), mesh(bx(.36, .1, .02), r, [0, .1, .2]), mesh(bx(.1, .36, .02), r, [0, .1, .2]), mesh(torus(.16, .035, Math.PI), plastic(0x55534c), [0, .36, 0])); }\n","import type { ItemModelBuilder } from './registry'\n\n/**\n * `MODELS[\"atadura\"]` of the Itens do Vale Cinzento showcase (`armas-itens__itens-vale-cinzento.js` L151), ported as it is: same units, same parts, same order, same materials by tag.\n * It draws in the units of the page; `data/models.json` gives the scale to metres of the item `bandage`.\n */\nexport const bandage: ItemModelBuilder = ({ mesh, cyl, bx, G, cloth }) => { const c = cloth(0xece5d2); return G(mesh(cyl(.34, .34, .38, 18), c, [0, 0, 0], [Math.PI / 2, 0, 0]), mesh(cyl(.1, .1, .4, 12), cloth(0x8a8577), [0, 0, 0], [Math.PI / 2, 0, 0]), mesh(bx(.36, .02, .36), c, [.2, -.33, .05], [0, 0, -.25]), mesh(bx(.3, .02, .36), c, [.5, -.4, .05], [0, 0, -.05])); }\n","import type { ItemModelBuilder } from './registry'\n\n/**\n * `MODELS[\"amoxicilina\"]` of the Itens do Vale Cinzento showcase (`armas-itens__itens-vale-cinzento.js` L152), ported as it is: same units, same parts, same order, same materials by tag.\n * It draws in the units of the page; `data/models.json` gives the scale to metres of the item `amoxicillin`.\n */\nexport const amoxicillin: ItemModelBuilder = ({ T, mesh, bx, G, metal, plastic, paper }) => G(mesh(bx(.8, .42, .24), paper(0xf0eee6)), mesh(bx(.81, .1, .25), plastic(0x4e7287), [0, .1, 0]), mesh(bx(.6, .04, .3), metal(0xb9bdc0), [.15, -.24, .25], [0, .3, 0]), ...[0, 1, 2, 3].map(k => mesh(new T.SphereGeometry(.05, 10, 8), plastic(0xd9a441), [-.05 + k * .14, -.21, .3], [0, 0, 0], [1, .6, 1])))\n","import type { ItemModelBuilder } from './registry'\n\n/**\n * `MODELS[\"pe_cabra\"]` of the Itens do Vale Cinzento showcase (`armas-itens__itens-vale-cinzento.js` L153), ported as it is: same units, same parts, same order, same materials by tag.\n * It draws in the units of the page; `data/models.json` gives the scale to metres of the item `crowbar`.\n */\nexport const crowbar: ItemModelBuilder = ({ T, mesh, cyl, G, metal }) => { const c = new T.CatmullRomCurve3([[0, -.8, 0], [0, .45, 0], [.02, .62, 0], [.12, .72, 0], [.26, .7, 0], [.32, .6, 0]].map(p => new T.Vector3(...p))); return G(mesh(new T.TubeGeometry(c, 30, .055, 8), metal(0x9b2a1f)), mesh(cyl(.02, .055, .14, 8), metal(0x3a3c3e), [0, -.86, 0])); }\n","import type { ItemModelBuilder } from './registry'\n\n/**\n * `MODELS[\"martelo\"]` of the Itens do Vale Cinzento showcase (`armas-itens__itens-vale-cinzento.js` L154), ported as it is: same units, same parts, same order, same materials by tag.\n * It draws in the units of the page; `data/models.json` gives the scale to metres of the item `hammer`.\n */\nexport const hammer: ItemModelBuilder = ({ T, mesh, cyl, bx, G, metal, wood, plastic }) => G(mesh(cyl(.05, .065, 1.1, 10), wood(0x8a643c), [0, -.15, 0]), mesh(cyl(.07, .07, .3, 10), plastic(0x22251f), [0, -.6, 0]), mesh(bx(.28, .15, .15), metal(0x55595d), [.05, .45, 0]), mesh(cyl(.08, .08, .1, 12), metal(0x55595d), [.22, .45, 0], [0, 0, Math.PI / 2]), mesh(new T.ConeGeometry(.06, .3, 6), metal(0x55595d), [-.22, .5, .035], [0, 0, 1.9]), mesh(new T.ConeGeometry(.06, .3, 6), metal(0x55595d), [-.22, .5, -.035], [0, 0, 1.9]))\n","import type { ItemModelBuilder } from './registry'\n\n/**\n * `MODELS[\"facao\"]` of the Itens do Vale Cinzento showcase (`armas-itens__itens-vale-cinzento.js` L155), ported as it is: same units, same parts, same order, same materials by tag.\n * It draws in the units of the page; `data/models.json` gives the scale to metres of the item `machete`.\n */\nexport const machete: ItemModelBuilder = ({ mesh, cyl, bx, extrude, G, metal, wood }) => G(mesh(extrude([[0, 0], [1.25, .05], [1.4, .14], [1.3, .26], [0, .2]], .03), metal(0xa9adb0), [-.55, 0, 0]), mesh(bx(.45, .2, .1), wood(0x3b2a20), [-.78, .1, .015]), ...[-.9, -.68].map(x => mesh(cyl(.025, .025, .12, 8), metal(0xb8913a), [x, .1, .015], [Math.PI / 2, 0, 0])))\n","import type { ItemModelBuilder } from './registry'\n\n/**\n * `MODELS[\"machado\"]` of the Itens do Vale Cinzento showcase (`armas-itens__itens-vale-cinzento.js` L156), ported as it is: same units, same parts, same order, same materials by tag.\n * It draws in the units of the page; `data/models.json` gives the scale to metres of the item `axe`.\n */\nexport const axe: ItemModelBuilder = ({ M, mesh, cyl, bx, extrude, G, metal, wood }) => G(mesh(cyl(.05, .06, 1.5, 10), wood(0x9a7448), [0, -.1, 0]), mesh(extrude([[0, 0], [.42, -.16], [.5, .05], [.48, .3], [.4, .42], [0, .22]], .07), metal(0x6c7075), [.02, .38, -.05]), mesh(bx(.12, .26, .14), metal(0x4a4d50), [0, .5, 0]), mesh(bx(.1, .2, .08), M(0x9b2a1f, \"plastic\"), [0, .55, 0]))\n","import type { ItemModelBuilder } from './registry'\n\n/**\n * `MODELS[\"taco_pregos\"]` of the Itens do Vale Cinzento showcase (`armas-itens__itens-vale-cinzento.js` L157), ported as it is: same units, same parts, same order, same materials by tag.\n * It draws in the units of the page; `data/models.json` gives the scale to metres of the item `nail_bat`.\n */\nexport const nailBat: ItemModelBuilder = ({ mesh, cyl, lathe, G, metal, wood }) => { const g = G(mesh(lathe([[0, -.85], [.05, -.85], [.05, -.8], [.035, -.75], [.04, -.2], [.09, .3], [.11, .7], [.09, .82], [0, .84]], 14), wood(0xb08a5a))); const nm = metal(0x7d8186); for (let k = 0; k < 9; k++) { const a = k * 2.4, y = .25 + (k % 5) * .12; const n = mesh(cyl(.012, .012, .2, 6), nm, [Math.cos(a) * .12, y, Math.sin(a) * .12], [0, 0, 0]); n.lookAt(Math.cos(a) * 2, y, Math.sin(a) * 2); n.rotateX(Math.PI / 2); g.add(n); } return g; }\n","import type { ItemModelBuilder } from './registry'\n\n/**\n * `MODELS[\"mochila_trilha\"]` of the Itens do Vale Cinzento showcase (`armas-itens__itens-vale-cinzento.js` L158), ported as it is: same units, same parts, same order, same materials by tag.\n * It draws in the units of the page; `data/models.json` gives the scale to metres of the item `hiking_backpack_40l`.\n */\nexport const hikingBackpack40L: ItemModelBuilder = ({ T, mesh, bx, G, cloth, plastic }) => { const c = cloth(0x4f6b3a), d = cloth(0x36472a); return G(mesh(bx(.78, .9, .42), c), mesh(new T.SphereGeometry(.4, 14, 8, 0, Math.PI * 2, 0, Math.PI / 2), c, [0, .44, 0], [0, 0, 0], [.98, .45, .53]), mesh(bx(.56, .4, .16), d, [0, -.15, .27]), mesh(bx(.8, .12, .46), d, [0, .2, 0]), mesh(bx(.06, .9, .06), cloth(0x22251f), [-.22, 0, -.24]), mesh(bx(.06, .9, .06), cloth(0x22251f), [.22, 0, -.24]), mesh(bx(.1, .08, .04), plastic(0xd9a441), [0, .2, .24])); }\n","import type { ItemModelBuilder } from './registry'\n\n/**\n * `MODELS[\"lanterna\"]` of the Itens do Vale Cinzento showcase (`armas-itens__itens-vale-cinzento.js` L159), ported as it is: same units, same parts, same order, same materials by tag.\n * It draws in the units of the page; `data/models.json` gives the scale to metres of the item `flashlight`.\n */\nexport const flashlight: ItemModelBuilder = ({ M, mesh, cyl, bx, torus, G, metal, plastic }) => G(mesh(cyl(.11, .11, .8, 14), metal(0x2a2c2e), [0, -.15, 0]), mesh(cyl(.19, .12, .28, 16), metal(0x3a3d40), [0, .37, 0]), mesh(cyl(.17, .17, .02, 16), M(0xfff1c0, \"glass\", { emissive: 0xffe08a, emissiveIntensity: .9 }), [0, .52, 0]), mesh(bx(.06, .1, .05), plastic(0xb5521f), [0, .05, .11]), ...[-.4, -.3, -.2].map(y => mesh(torus(.112, .012), plastic(0x1b1c1d), [0, y, 0], [Math.PI / 2, 0, 0])))\n","import type { ItemModelBuilder } from './registry'\n\n/**\n * `MODELS[\"radio_portatil\"]` of the Itens do Vale Cinzento showcase (`armas-itens__itens-vale-cinzento.js` L160), ported as it is: same units, same parts, same order, same materials by tag.\n * It draws in the units of the page; `data/models.json` gives the scale to metres of the item `portable_radio`.\n */\nexport const portableRadio: ItemModelBuilder = ({ M, mesh, cyl, bx, torus, G, metal, plastic }) => { const g = G(mesh(bx(1.05, .62, .3), plastic(0x3a3d35)), mesh(cyl(.2, .2, .02, 18), plastic(0x1e1f1b), [-.24, -.04, .16], [Math.PI / 2, 0, 0]), mesh(bx(.36, .14, .02), M(0xd9a441, \"glass\", { emissive: 0x6a4a10, emissiveIntensity: .6 }), [.26, .1, .16]), mesh(cyl(.06, .06, .06, 12), plastic(0x8d8a80), [.18, -.15, .17], [Math.PI / 2, 0, 0]), mesh(cyl(.06, .06, .06, 12), plastic(0x8d8a80), [.36, -.15, .17], [Math.PI / 2, 0, 0]), mesh(torus(.24, .03, Math.PI), plastic(0x22251f), [0, .3, 0])); const a = mesh(cyl(.012, .02, .95, 6), metal(0xb9bdc0), [.4, .72, 0], [0, 0, -.35]); g.add(a); return g; }\n","import type { ItemModelBuilder } from './registry'\n\n/**\n * `MODELS[\"chave_casa\"]` of the Itens do Vale Cinzento showcase (`armas-itens__itens-vale-cinzento.js` L161), ported as it is: same units, same parts, same order, same materials by tag.\n * It draws in the units of the page; `data/models.json` gives the scale to metres of the item `house_key`.\n */\nexport const houseKey: ItemModelBuilder = ({ mesh, bx, torus, extrude, G, metal, plastic }) => { const b = metal(0xb8913a); return G(mesh(torus(.22, .04), metal(0x9a9da0), [-.55, .1, 0]), mesh(extrude([[0, -.2], [.25, -.22], [.3, -.1], [.3, .1], [.25, .22], [0, .2]], .05), b, [-.38, .02, -.025]), mesh(extrude([[0, 0], [.75, 0], [.75, -.08], [.66, -.08], [.66, -.14], [.56, -.08], [.46, -.14], [.4, -.08], [0, -.08]], .035), b, [-.1, .06, -.017]), mesh(bx(.24, .34, .03), plastic(0xb5521f), [-.72, -.28, 0], [0, 0, .25])); }\n","import type { ItemModelBuilder } from './registry'\n\n/**\n * `MODELS[\"diario\"]` of the Itens do Vale Cinzento showcase (`armas-itens__itens-vale-cinzento.js` L162), ported as it is: same units, same parts, same order, same materials by tag.\n * It draws in the units of the page; `data/models.json` gives the scale to metres of the item `survivor_diary`.\n */\nexport const survivorDiary: ItemModelBuilder = ({ mesh, bx, G, cloth, paper }) => G(mesh(bx(.78, 1.02, .05), paper(0x6b3f2a), [0, 0, .1]), mesh(bx(.78, 1.02, .05), paper(0x6b3f2a), [0, 0, -.1]), mesh(bx(.74, .98, .16), paper(0xe9e1cc), [.01, 0, 0]), mesh(bx(.06, 1.02, .25), paper(0x5a3322), [-.38, 0, 0]), mesh(bx(.03, 1.04, .27), cloth(0x22251f), [.25, 0, 0]), mesh(bx(.18, .3, .002), paper(0xd5c9a8), [.05, .2, .126], [0, 0, .08]))\n","import type { ItemModelBuilder } from './registry'\n\n/**\n * `MODELS[\"capacete_moto\"]` of the Itens do Vale Cinzento showcase (`armas-itens__itens-vale-cinzento.js` L163), ported as it is: same units, same parts, same order, same materials by tag.\n * It draws in the units of the page; `data/models.json` gives the scale to metres of the item `motorcycle_helmet`.\n */\nexport const motorcycleHelmet: ItemModelBuilder = ({ T, M, mesh, cyl, bx, G, plastic }) => G(mesh(new T.SphereGeometry(.55, 18, 12), plastic(0x2b2f3a), [0, 0, 0], [0, 0, 0], [1, .95, 1.08]), mesh(new T.SphereGeometry(.56, 18, 10, -0.9, 1.8, 1.05, .75), M(0x14171c, \"glass\", { roughness: .15, metalness: .4 }), [0, .02, .02], [0, 0, 0], [1, .95, 1.08]), mesh(bx(.2, .12, .02), plastic(0xe0773f), [.42, .2, .22], [0, .95, 0]), mesh(cyl(.5, .55, .12, 18), plastic(0x1d2028), [0, -.5, 0]))\n","import type { ItemModelBuilder } from './registry'\n\n/**\n * `MODELS[\"botijao\"]` of the Itens do Vale Cinzento showcase (`armas-itens__itens-vale-cinzento.js` L164), ported as it is: same units, same parts, same order, same materials by tag.\n * It draws in the units of the page; `data/models.json` gives the scale to metres of the item `lpg_cylinder_13kg`.\n */\nexport const lpgCylinder13Kg: ItemModelBuilder = ({ mesh, cyl, bx, lathe, torus, G, metal }) => G(mesh(lathe([[0, -.6], [.38, -.6], [.42, -.55], [.45, -.3], [.45, .15], [.4, .32], [.28, .42], [.12, .46], [0, .46]], 18), metal(0x355f86)), mesh(cyl(.47, .47, .1, 18), metal(0x29486a), [0, -.62, 0]), mesh(torus(.24, .035), metal(0x29486a), [0, .58, 0], [Math.PI / 2, 0, 0]), mesh(cyl(.07, .07, .14, 10), metal(0xb8913a), [0, .5, 0]), mesh(bx(.04, .2, .04), metal(0x29486a), [.22, .5, 0]), mesh(bx(.04, .2, .04), metal(0x29486a), [-.22, .5, 0]))\n","import type { ItemModelBuilder } from './registry'\n\n/**\n * `MODELS[\"galao\"]` of the Itens do Vale Cinzento showcase (`armas-itens__itens-vale-cinzento.js` L165), ported as it is: same units, same parts, same order, same materials by tag.\n * It draws in the units of the page; `data/models.json` gives the scale to metres of the item `fuel_jerrycan`.\n */\nexport const fuelJerrycan: ItemModelBuilder = ({ mesh, cyl, bx, G, plastic }) => G(mesh(bx(.85, 1, .42), plastic(0xa3322a)), mesh(bx(.6, .1, .3), plastic(0x7e2620), [0, .45, 0]), mesh(bx(.36, .2, .1), plastic(0xa3322a), [-.12, .62, 0]), mesh(cyl(.05, .07, .35, 10), plastic(0xd9a441), [.3, .66, 0], [0, 0, -.6]), mesh(bx(.6, .5, .02), plastic(0x8a2a22), [0, -.1, .22]))\n","import type { ItemModelBuilder } from './registry'\n\n/**\n * `MODELS[\"walkie\"]` of the Itens do Vale Cinzento showcase (`armas-itens__itens-vale-cinzento.js` L166), ported as it is: same units, same parts, same order, same materials by tag.\n * It draws in the units of the page; `data/models.json` gives the scale to metres of the item `walkie_talkies`.\n */\nexport const walkieTalkies: ItemModelBuilder = ({ M, mesh, cyl, bx, G, plastic }) => G(mesh(bx(.42, .9, .2), plastic(0x2a2d27)), mesh(bx(.34, .3, .02), plastic(0x161814), [0, -.12, .11]), mesh(bx(.24, .12, .02), M(0x9fbf8a, \"glass\", { emissive: 0x2f4a22, emissiveIntensity: .7 }), [0, .22, .11]), mesh(cyl(.035, .045, .6, 8), plastic(0x1b1c1a), [.12, .72, 0]), mesh(cyl(.04, .04, .08, 10), plastic(0xb5521f), [-.12, .48, 0]), mesh(bx(.05, .2, .1), plastic(0x3a3d35), [-.23, .05, 0]))\n","import type { ItemModelBuilder } from './registry'\n\n/**\n * `MODELS[\"pilha_aa\"]` of the Itens do Vale Cinzento showcase (`armas-itens__itens-vale-cinzento.js` L167), ported as it is: same units, same parts, same order, same materials by tag.\n * It draws in the units of the page; `data/models.json` gives the scale to metres of the item `batteries`.\n */\nexport const batteries: ItemModelBuilder = ({ mesh, cyl, G, metal }) => { const g = G(); [-.2, .2].forEach((x, k) => g.add(mesh(cyl(.17, .17, .95, 16), metal(k ? 0xb5521f : 0x2a2c2e), [x, 0, 0]), mesh(cyl(.172, .172, .3, 16), metal(0xc9a227), [x, .33, 0]), mesh(cyl(.06, .06, .06, 10), metal(0xb9bdc0), [x, .5, 0]))); return g; }\n","import type { ItemModelBuilder } from './registry'\n\n/**\n * `MODELS[\"tabua\"]` of the Itens do Vale Cinzento showcase (`armas-itens__itens-vale-cinzento.js` L168), ported as it is: same units, same parts, same order, same materials by tag.\n * It draws in the units of the page; `data/models.json` gives the scale to metres of the item `wooden_plank`.\n */\nexport const woodenPlank: ItemModelBuilder = ({ mesh, cyl, bx, G, metal, wood }) => { const g = G(); [0xa88459, 0x8e6c45, 0xb49268].forEach((c, k) => g.add(mesh(bx(1.5, .07, .26), wood(c), [0, -.15 + k * .12, (k - 1) * .05], [0, (k - 1) * .12, 0]))); const nm = metal(0x7d8186); [-.5, -.3, .4].forEach((x, k) => g.add(mesh(cyl(.012, .012, .18, 6), nm, [x, .18 + k * .01, .2], [0, 0, (k - 1) * .3]))); return g; }\n","import data from '../data/models.json'\n\nimport { cannedBeans } from './canned-beans'\nimport { waterBottle } from './water-bottle'\nimport { rice } from './rice'\nimport { militaryRation } from './military-ration'\nimport { cachaca } from './cachaca'\nimport { firstAidKit } from './first-aid-kit'\nimport { bandage } from './bandage'\nimport { amoxicillin } from './amoxicillin'\nimport { crowbar } from './crowbar'\nimport { hammer } from './hammer'\nimport { machete } from './machete'\nimport { axe } from './axe'\nimport { nailBat } from './nail-bat'\nimport { hikingBackpack40L } from './hiking-backpack-40l'\nimport { flashlight } from './flashlight'\nimport { portableRadio } from './portable-radio'\nimport { houseKey } from './house-key'\nimport { survivorDiary } from './survivor-diary'\nimport { motorcycleHelmet } from './motorcycle-helmet'\nimport { lpgCylinder13Kg } from './lpg-cylinder-13kg'\nimport { fuelJerrycan } from './fuel-jerrycan'\nimport { walkieTalkies } from './walkie-talkies'\nimport { batteries } from './batteries'\nimport { woodenPlank } from './wooden-plank'\nimport type { ItemModelBuilder, ItemModelEntry } from './registry'\n\n/** The builder of each model of the showcase, by catalog id. */\nconst BUILDERS: Readonly<Record<string, ItemModelBuilder>> = {\n canned_beans: cannedBeans,\n water_bottle: waterBottle,\n rice: rice,\n military_ration: militaryRation,\n cachaca: cachaca,\n first_aid_kit: firstAidKit,\n bandage: bandage,\n amoxicillin: amoxicillin,\n crowbar: crowbar,\n hammer: hammer,\n machete: machete,\n axe: axe,\n nail_bat: nailBat,\n hiking_backpack_40l: hikingBackpack40L,\n flashlight: flashlight,\n portable_radio: portableRadio,\n house_key: houseKey,\n survivor_diary: survivorDiary,\n motorcycle_helmet: motorcycleHelmet,\n lpg_cylinder_13kg: lpgCylinder13Kg,\n fuel_jerrycan: fuelJerrycan,\n walkie_talkies: walkieTalkies,\n batteries: batteries,\n wooden_plank: woodenPlank,\n}\n\n/** The 24 models of the showcase in the page's order: the entry of `data/models.json` (generated by `tools/items-catalog`) and the builder ported from the page. */\nexport const SHIPPED_MODELS: ReadonlyArray<{ readonly entry: ItemModelEntry; readonly builder: ItemModelBuilder }> = (data as unknown as ItemModelEntry[]).map((entry) => {\n const builder = BUILDERS[entry.id]\n if (!builder) throw new Error(`game-items-three: no builder for the model \"${entry.id}\"`)\n return { entry, builder }\n})\n","import type * as THREE_NS from 'three'\n\nimport type { ItemKit } from '../kit'\nimport { SHIPPED_MODELS } from './shipped'\n\n/** One model of the showcase as `data/models.json` keeps it: the item it draws, the id the team gave it, the box it has in the units of the page and the scale to metres. */\nexport interface ItemModelEntry {\n /** Catalog id of the item (`canned_beans`). */\n readonly id: string\n /** The id in the team's `MODELS` (`feijao_lata`). */\n readonly teamId: string\n /** Box of the builder's group in the page's units (`Box3.setFromObject`), x y z. */\n readonly teamBox: readonly [number, number, number]\n /** Metres per unit of the page, from one real measure of the object. */\n readonly scale: number\n}\n\n/** A builder of the showcase, ported as it is: it draws in the page's units and returns the group. */\nexport type ItemModelBuilder = (kit: ItemKit) => THREE_NS.Group\n\nconst entries = new Map<string, ItemModelEntry>(SHIPPED_MODELS.map(({ entry }) => [entry.id, entry]))\nconst builders = new Map<string, ItemModelBuilder>(SHIPPED_MODELS.map(({ entry, builder }) => [entry.id, builder]))\n\n/** Adds (or replaces) the model of an item: `entry.id` is the catalog id the item's `model` field names. */\nexport function registerItemModel(entry: ItemModelEntry, builder: ItemModelBuilder): void {\n entries.set(entry.id, entry)\n builders.set(entry.id, builder)\n}\n\n/** Takes a model out (a game that wants the simple shape instead). */\nexport function unregisterItemModel(id: string): void {\n entries.delete(id)\n builders.delete(id)\n}\n\nexport const itemModelEntry = (id: string): ItemModelEntry | undefined => entries.get(id)\nexport const itemModelBuilder = (id: string): ItemModelBuilder | undefined => builders.get(id)\nexport const hasItemModel = (id: string): boolean => builders.has(id)\n/** The ids of the models registered, in the order of registration (the order of the showcase for the ones the kit ships). */\nexport const listItemModels = (): string[] => [...entries.keys()]\n","import type * as THREE_NS from 'three'\n\nimport { createItemKit } from './kit'\nimport type { ItemKit, Vec3Tuple } from './kit'\nimport { itemModelBuilder, itemModelEntry } from './models/registry'\nimport { drawShape, shapeOf } from './shapes'\nimport type { ShapeId, ShapeSubject } from './shapes'\nimport { setWear } from './wear'\nimport type { WearStage } from './wear'\n\n/** The fields of an item the drawing reads (an `ItemDef` of `game-items` has them all). */\nexport interface DrawableItem extends ShapeSubject {\n id: string\n size: Vec3Tuple\n /** Key of a showcase model; without one (or when the model is not registered) the simple shape is drawn. */\n model?: string\n}\n\nexport interface BuildItemOptions {\n /** Wear of the materials, 0 new (default), 1 used, 2 spoiled. */\n wear?: WearStage\n /** Draw the simple shape even when the item has a model (the second level of detail). */\n simple?: boolean\n /** Level of detail of the simple shape, 1 (default) or 0.5 for half the segments. */\n detail?: number\n /** A kit to draw with (and to collect the materials in); default a new one. */\n kit?: ItemKit\n}\n\n/** What `buildItem` returns. */\nexport interface ItemModel {\n /** The object to add to a scene: origin at the bottom centre of the item, y up, in metres. */\n readonly root: THREE_NS.Group\n /** `model` when the showcase builder drew it, `shape` otherwise. */\n readonly kind: 'model' | 'shape'\n readonly shape?: ShapeId\n /** Size in metres the drawing was fitted to (the item's `size`). */\n readonly size: Vec3Tuple\n /** The materials made for this item. */\n readonly materials: readonly THREE_NS.MeshStandardMaterial[]\n}\n\n/** Moves a group so that its box has the centre of its base at the origin. */\nfunction restOnBase(T: typeof THREE_NS, inner: THREE_NS.Object3D): void {\n const box = new T.Box3().setFromObject(inner)\n const centre = box.getCenter(new T.Vector3())\n inner.position.set(-centre.x, -box.min.y, -centre.z)\n}\n\n/**\n * Draws an item at its real size. An item whose `model` is registered gets the showcase builder, ported as it is (page units, scaled to metres by the scale of\n * `models.json` on the root, so that the group inside is still the team's); every other item gets the simple shape of its `shape` hint (refined by category and\n * proportions) at its `size`. Either way the origin is the bottom centre and y is up.\n */\nexport function buildItem(T: typeof THREE_NS, item: DrawableItem, options: BuildItemOptions = {}): ItemModel {\n const kit = options.kit ?? createItemKit(T)\n const first = kit.materials.length\n const root = new T.Group()\n root.name = item.id\n const entry = item.model === undefined ? undefined : itemModelEntry(item.model)\n const builder = item.model === undefined ? undefined : itemModelBuilder(item.model)\n let kind: ItemModel['kind'] = 'shape'\n let shape: ShapeId | undefined\n if (entry && builder && !options.simple) {\n kind = 'model'\n const inner = builder(kit)\n inner.name = entry.teamId\n root.scale.setScalar(entry.scale)\n root.add(inner)\n restOnBase(T, inner)\n } else {\n shape = shapeOf(item)\n const inner = drawShape(kit, shape, item.size, { ...(item.color === undefined ? {} : { color: item.color }), ...(options.detail === undefined ? {} : { detail: options.detail }) })\n inner.name = shape\n root.add(inner)\n restOnBase(T, inner)\n }\n const materials = kit.materials.slice(first)\n if (options.wear) setWear(materials, options.wear)\n root.userData.wear = options.wear ?? 0\n return { root, kind, ...(shape ? { shape } : {}), size: item.size, materials }\n}\n","import type { Color, PropItem } from './types'\n\n/** Deterministic PRNG (mulberry32 variant) returning floats in [0, 1). */\nexport function rng(seed: number): () => number {\n let s = seed >>> 0\n return () => {\n s = (s + 0x6d2b79f5) >>> 0\n let t = s\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\n/** Seed of the details draw: `M.seed` (number or string) or a hash of the position. */\nexport const seedOf = (M: PropItem): number =>\n (M.seed != null\n ? typeof M.seed === 'number'\n ? M.seed\n : [...String(M.seed)].reduce((a, c) => (a * 31 + c.charCodeAt(0)) | 0, 7)\n : Math.round((M.x || 0) * 37 + (M.z || 0) * 91 + 1000)) >>> 0\n\n/** `'#rrggbb'` or number to number. */\nexport const hex = (v: Color): number => (typeof v === 'string' ? parseInt(v.replace('#', ''), 16) : v)\n\n/** Scales the brightness of a colour by factor `f` (clamped per channel). */\nexport const shade = (c: Color, f: number): number => {\n const n = hex(c)\n const r = Math.min(255, Math.round(((n >> 16) & 255) * f))\n const g = Math.min(255, Math.round(((n >> 8) & 255) * f))\n const b = Math.min(255, Math.round((n & 255) * f))\n return (r << 16) | (g << 8) | b\n}\n\n/** Linear mix of two colours. */\nexport const mix = (a: Color, b: Color, t: number): number => {\n const x = hex(a)\n const y = hex(b)\n const m = (s: number) => Math.round(((x >> s) & 255) * (1 - t) + ((y >> s) & 255) * t)\n return (m(16) << 16) | (m(8) << 8) | m(0)\n}\n","import { rng } from './colors'\nimport type { AtlasMap, AtlasName, DocumentLike, FloorAtlas, FloorKind, PictureAtlas, Uv, WaterAtlas } from './types'\n\ntype Ctx = CanvasRenderingContext2D\ntype Rand = () => number\n\nconst makeCanvas = (doc: DocumentLike, w: number, h: number): HTMLCanvasElement => {\n const c = doc.createElement('canvas')\n c.width = w\n c.height = h\n return c\n}\n\n// draws f() nine times (offsets of +-n) inside the clipped cell, so the pattern tiles without a seam\nfunction seamless(g: Ctx, x0: number, y0: number, n: number, f: () => void) {\n g.save()\n g.beginPath()\n g.rect(x0, y0, n, n)\n g.clip()\n for (let dy = -n; dy <= n; dy += n)\n for (let dx = -n; dx <= n; dx += n) {\n g.save()\n g.translate(x0 + dx, y0 + dy)\n f()\n g.restore()\n }\n g.restore()\n}\nconst noise = (g: Ctx, x0: number, y0: number, n: number, r: Rand, a: number) => {\n for (let i = 0; i < (n * n) / 6; i++) {\n const v = r() < 0.5 ? 0 : 255\n g.fillStyle = `rgba(${v},${v},${v},${r() * a})`\n g.fillRect(x0 + r() * n, y0 + r() * n, 1 + r() * 2, 1 + r() * 2)\n }\n}\n\n/** Floor kinds that live in the floor atlas: atlas cells and the world size (meters) one cell covers. */\nexport const FLOORS: Record<FloorKind, { cells: number[]; size: number }> = {\n lawn: { cells: [0, 1], size: 2.0 },\n tile_floor: { cells: [2], size: 1.0 },\n concrete: { cells: [3], size: 2.0 },\n deck_floor: { cells: [4], size: 1.2 },\n dirt: { cells: [5], size: 2.0 },\n pool_tile: { cells: [6], size: 1.0 },\n paving: { cells: [7], size: 1.0 },\n}\nconst PICTURE_CELLS = 8 // 0-3 abstract, 4-6 landscapes, 7 mirror\n\nfunction floorAtlas(doc: DocumentLike): FloorAtlas {\n const N = 256, cv = makeCanvas(doc, N * 4, N * 2), g = cv.getContext('2d')!, P = (c: number): [number, number] => [(c % 4) * N, Math.floor(c / 4) * N];\n const cell = (c: number, seed: number, f: (g: Ctx, x0: number, y0: number, r: Rand) => void) => { const [x0, y0] = P(c), r = rng(seed); f(g, x0, y0, r); };\n for (const [c, seed] of [[0, 11], [1, 12]] as Array<[number, number]>) cell(c, seed, (g, x0, y0, r) => { // lawn: base + blades + dry patches\n g.fillStyle = c ? '#648f3a' : '#5b8a37'; g.fillRect(x0, y0, N, N);\n seamless(g, x0, y0, N, () => { for (let i = 0; i < 40; i++) { g.fillStyle = `rgba(${r() < 0.5 ? '160,170,60' : '40,80,30'},${0.12 + r() * 0.12})`; g.beginPath(); g.arc(r() * N, r() * N, 8 + r() * 22, 0, 6.3); g.fill(); }\n for (let i = 0; i < 520; i++) { r(); /* the original drew a blade height here and never used it; the call keeps the random sequence identical */ g.strokeStyle = `hsl(${85 + r() * 30},${40 + r() * 25}%,${22 + r() * 24}%)`; g.lineWidth = 1; const x = r() * N, y = r() * N; g.beginPath(); g.moveTo(x, y); g.lineTo(x + (r() - 0.5) * 6, y - 4 - r() * 9); g.stroke(); } }); });\n cell(2, 21, (g, x0, y0, r) => { // beige 4x4 ceramic tiles with grout\n const q = N / 4; g.fillStyle = '#8c877b'; g.fillRect(x0, y0, N, N);\n for (let j = 0; j < 4; j++) for (let i = 0; i < 4; i++) { const v = 204 + (r() - 0.5) * 16; g.fillStyle = `rgb(${v},${v - 6},${v - 18})`; g.fillRect(x0 + i * q + 2, y0 + j * q + 2, q - 4, q - 4); g.fillStyle = 'rgba(255,255,255,.18)'; g.fillRect(x0 + i * q + 3, y0 + j * q + 3, q - 8, 3); }\n for (let k = 0; k < 14; k++) { const gr = g.createRadialGradient(0, 0, 0, 0, 0, 40); const x = x0 + r() * N, y = y0 + r() * N; g.save(); g.beginPath(); g.rect(x0, y0, N, N); g.clip(); g.translate(x, y); gr.addColorStop(0, 'rgba(90,80,60,.10)'); gr.addColorStop(1, 'rgba(90,80,60,0)'); g.fillStyle = gr; g.fillRect(-40, -40, 80, 80); g.restore(); } });\n cell(3, 31, (g, x0, y0, r) => { // concrete: slab, expansion joint, crack, stain\n g.fillStyle = '#a7a7a0'; g.fillRect(x0, y0, N, N);\n for (let k = 0; k < 18; k++) { const gr = g.createRadialGradient(0, 0, 0, 0, 0, 50); g.save(); g.beginPath(); g.rect(x0, y0, N, N); g.clip(); g.translate(x0 + r() * N, y0 + r() * N); gr.addColorStop(0, `rgba(${r() < 0.5 ? '70,70,60' : '200,200,190'},.12)`); gr.addColorStop(1, 'rgba(0,0,0,0)'); g.fillStyle = gr; g.fillRect(-50, -50, 100, 100); g.restore(); }\n noise(g, x0, y0, N, r, 0.25); g.fillStyle = 'rgba(40,40,36,.55)'; g.fillRect(x0, y0 + N / 2 - 1, N, 2); g.fillRect(x0 + N / 2 - 1, y0, 2, N); g.fillRect(x0, y0, N, 1); g.fillRect(x0, y0, 1, N);\n g.strokeStyle = 'rgba(50,50,46,.5)'; g.lineWidth = 1; let x = x0 + 30 + r() * 60, y = y0 + 8; g.beginPath(); g.moveTo(x, y); for (let s = 0; s < 8; s++) { x += (r() - 0.5) * 16; y += 12 + r() * 8; g.lineTo(x, y); } g.stroke(); });\n cell(4, 41, (g, x0, y0, r) => { // deck: 12 boards in staggered rows\n const th = N / 12; g.fillStyle = '#2a1c10'; g.fillRect(x0, y0, N, N);\n for (let j = 0; j < 12; j++) { const cut = r() * N; for (const [a, b] of [[0, cut], [cut, N]]) { const v = 150 + (r() - 0.5) * 36; g.fillStyle = `rgb(${v},${v * 0.68 | 0},${v * 0.42 | 0})`; g.fillRect(x0 + a + 1, y0 + j * th + 1, b - a - 2, th - 2);\n g.strokeStyle = 'rgba(50,28,12,.3)'; for (let s = 0; s < 3; s++) { const y = y0 + j * th + 3 + r() * (th - 6); g.beginPath(); g.moveTo(x0 + a, y); g.lineTo(x0 + b, y + (r() - 0.5) * 2); g.stroke(); }\n g.fillStyle = 'rgba(30,20,10,.7)'; g.fillRect(x0 + a + 4, y0 + j * th + th / 2, 2, 2); g.fillRect(x0 + b - 6, y0 + j * th + th / 2, 2, 2); } } });\n cell(5, 51, (g, x0, y0, r) => { // packed dirt\n g.fillStyle = '#7b5538'; g.fillRect(x0, y0, N, N);\n seamless(g, x0, y0, N, () => { for (let k = 0; k < 30; k++) { g.fillStyle = `rgba(${r() < 0.5 ? '60,38,24' : '150,112,80'},${0.12 + r() * 0.15})`; g.beginPath(); g.arc(r() * N, r() * N, 6 + r() * 20, 0, 6.3); g.fill(); }\n for (let k = 0; k < 90; k++) { const v = 90 + r() * 90; g.fillStyle = `rgb(${v},${v * 0.85 | 0},${v * 0.7 | 0})`; g.fillRect(r() * N, r() * N, 1 + r() * 3, 1 + r() * 3); } }); });\n cell(6, 61, (g, x0, y0, r) => { // 8x8 pool tiles\n const q = N / 8; g.fillStyle = '#d4e8ee'; g.fillRect(x0, y0, N, N);\n for (let j = 0; j < 8; j++) for (let i = 0; i < 8; i++) { const v = (r() - 0.5) * 24; g.fillStyle = `rgb(${50 + v},${150 + v},${190 + v})`; g.fillRect(x0 + i * q + 1, y0 + j * q + 1, q - 2, q - 2); g.fillStyle = 'rgba(255,255,255,.2)'; g.fillRect(x0 + i * q + 2, y0 + j * q + 2, q - 6, 2); } });\n cell(7, 71, (g, x0, y0, r) => { // reddish interlocking paving (small bricks)\n const bw = N / 4, bh = N / 8; g.fillStyle = '#7a7268'; g.fillRect(x0, y0, N, N);\n for (let j = 0; j < 8; j++) for (let i = -1; i < 4; i++) { const off = (j % 2) * bw / 2, v = 150 + (r() - 0.5) * 30; g.fillStyle = `rgb(${v + 20},${v * 0.55 | 0},${v * 0.42 | 0})`; g.fillRect(x0 + ((i * bw + off) % N + N) % N + 1, y0 + j * bh + 1, bw - 2, bh - 2); }\n noise(g, x0, y0, N, r, 0.2); });\n const cells = {} as Record<FloorKind, Uv[]>; for (const k of Object.keys(FLOORS) as FloorKind[]) cells[k] = FLOORS[k].cells.map(c => ({ u0: (c % 4) / 4, u1: (c % 4 + 1) / 4, v0: 1 - (Math.floor(c / 4) + 1) / 2, v1: 1 - Math.floor(c / 4) / 2 }));\n const e = 1.5 / (N * 4), ev = 1.5 / (N * 2); // inset of one and a half pixels: no bleeding from the neighbouring cell\n return { canvas: cv, cells, size: (k: FloorKind) => FLOORS[k].size, uv(k: FloorKind, v = 0) { const L = cells[k]; const c = L[v % L.length]; return { u0: c.u0 + e, u1: c.u1 - e, v0: c.v0 + ev, v1: c.v1 - ev }; }, variants: (k: FloorKind) => FLOORS[k].cells.length };\n}\n\nfunction pictureAtlas(doc: DocumentLike, names: string[]): PictureAtlas {\n const N = 256, cv = makeCanvas(doc, N * 4, N * 2), g = cv.getContext('2d')!;\n const cell = (c: number, seed: number, f: (r: Rand) => void) => { const x0 = (c % 4) * N, y0 = Math.floor(c / 4) * N, r = rng(seed); g.save(); g.beginPath(); g.rect(x0, y0, N, N); g.clip(); g.translate(x0, y0); f(r); g.restore(); };\n cell(0, 101, r => { g.fillStyle = '#e8dcc4'; g.fillRect(0, 0, N, N); g.fillStyle = '#c0613c'; g.beginPath(); g.arc(90 + r() * 30, 110, 60, 0, 6.3); g.fill(); g.fillStyle = '#2f7f84'; g.fillRect(120, 40 + r() * 30, 90, 150); g.fillStyle = '#d9a43a'; g.beginPath(); g.arc(150, 200, 70, Math.PI, 0); g.fill(); g.strokeStyle = '#2a2a2a'; g.lineWidth = 3; g.beginPath(); g.moveTo(20, 230); g.lineTo(236, 30); g.stroke(); });\n cell(1, 102, r => { g.fillStyle = '#1f3a5f'; g.fillRect(0, 0, N, N); for (let i = 0; i < 7; i++) { g.fillStyle = ['#f08a3c', '#f4e4c1', '#d94f4f', '#7fb5a5'][i % 4]; g.globalAlpha = 0.85; g.beginPath(); g.ellipse(r() * N, r() * N, 20 + r() * 50, 12 + r() * 30, r() * 3, 0, 6.3); g.fill(); } g.globalAlpha = 1; g.strokeStyle = '#f4e4c1'; g.lineWidth = 4; for (let i = 0; i < 3; i++) { g.beginPath(); g.moveTo(0, 50 + i * 70); g.bezierCurveTo(80, 10 + i * 70, 170, 120 + i * 40, N, 60 + i * 60); g.stroke(); } });\n cell(2, 103, r => { const cs = ['#e9e1cf', '#c8553d', '#2e5e7e', '#e4b23e', '#4b4b4b']; let x = 0; while (x < N) { const w = 30 + r() * 60; g.fillStyle = cs[(r() * cs.length) | 0]; g.fillRect(x, 0, w, N); x += w; } g.fillStyle = '#e9e1cf'; g.fillRect(40, 60, 176, 136); g.fillStyle = cs[1]; g.fillRect(70, 90, 60, 76); g.fillStyle = cs[2]; g.fillRect(140, 90, 50, 36); });\n cell(3, 104, r => { g.fillStyle = '#f2f0ea'; g.fillRect(0, 0, N, N); g.fillStyle = '#1a1a1a'; g.fillRect(40, 190, 176, 8); g.fillStyle = '#b8352e'; g.beginPath(); g.arc(128, 100, 52, 0, 6.3); g.fill(); g.strokeStyle = '#1a1a1a'; g.lineWidth = 2; for (let i = 0; i < 5; i++) { g.beginPath(); g.moveTo(40, 30 + i * 8 + r() * 4); g.lineTo(216, 30 + i * 8); g.stroke(); } });\n cell(4, 105, r => { const gr = g.createLinearGradient(0, 0, 0, N * 0.7); gr.addColorStop(0, '#5a4a8a'); gr.addColorStop(0.5, '#e8805a'); gr.addColorStop(1, '#f7d27a'); g.fillStyle = gr; g.fillRect(0, 0, N, N); g.fillStyle = '#fff3c0'; g.beginPath(); g.arc(150, 150, 36, 0, 6.3); g.fill();\n ([['#7a5a6a', 150], ['#4a4a5e', 175], ['#2a3a3a', 205]] as Array<[string, number]>).forEach(([c, y], k) => { g.fillStyle = c; g.beginPath(); g.moveTo(0, N); g.lineTo(0, y); for (let x = 0; x <= N; x += 32) g.lineTo(x, y - 10 + r() * 24 - k * 3); g.lineTo(N, N); g.fill(); }); });\n cell(5, 106, r => { const gr = g.createLinearGradient(0, 0, 0, N); gr.addColorStop(0, '#9fc8e8'); gr.addColorStop(0.55, '#e8f0f4'); gr.addColorStop(0.56, '#3d7a9a'); gr.addColorStop(1, '#22506a'); g.fillStyle = gr; g.fillRect(0, 0, N, N);\n g.fillStyle = '#5a6a78'; g.beginPath(); g.moveTo(0, 140); for (let x = 0; x <= N; x += 28) g.lineTo(x, 70 + r() * 50); g.lineTo(N, 140); g.fill(); g.fillStyle = '#3a5a4a'; g.beginPath(); g.moveTo(150, 140); g.quadraticCurveTo(200, 60, 230, 140); g.fill(); });\n cell(6, 107, () => { const gr = g.createLinearGradient(0, 0, 0, N); gr.addColorStop(0, '#f6e0a8'); gr.addColorStop(0.5, '#fbeed0'); gr.addColorStop(0.5, '#4bb0c4'); gr.addColorStop(0.72, '#2e8aa8'); gr.addColorStop(0.72, '#ecd8a2'); gr.addColorStop(1, '#d9bd7e'); g.fillStyle = gr; g.fillRect(0, 0, N, N);\n g.strokeStyle = '#4a3a22'; g.lineWidth = 5; g.beginPath(); g.moveTo(60, 255); g.quadraticCurveTo(70, 160, 100, 70); g.stroke(); g.fillStyle = '#2f6a3a'; for (let i = 0; i < 6; i++) { g.beginPath(); g.moveTo(100, 70); g.quadraticCurveTo(100 + Math.cos(i) * 40, 40 + Math.sin(i * 2) * 20, 100 + Math.cos(i * 1.1) * 60, 80 + i * 6); g.quadraticCurveTo(100 + Math.cos(i) * 30, 70, 100, 70); g.fill(); } });\n cell(7, 108, () => { const gr = g.createLinearGradient(0, 0, N, N); gr.addColorStop(0, '#e4e9eb'); gr.addColorStop(0.5, '#c4ccd0'); gr.addColorStop(1, '#a8b2b8'); g.fillStyle = gr; g.fillRect(0, 0, N, N);\n g.fillStyle = 'rgba(255,255,255,.35)'; g.beginPath(); g.moveTo(30, 0); g.lineTo(90, 0); g.lineTo(0, 120); g.lineTo(0, 60); g.fill(); g.beginPath(); g.moveTo(150, 0); g.lineTo(175, 0); g.lineTo(0, 256); g.lineTo(0, 232); g.fill();\n const v = g.createRadialGradient(128, 128, 90, 128, 128, 190); v.addColorStop(0, 'rgba(0,0,0,0)'); v.addColorStop(1, 'rgba(0,0,0,.18)'); g.fillStyle = v; g.fillRect(0, 0, N, N); });\n const uvc = (c: number): Uv => ({ u0: (c % 4) / 4 + 1.5 / (N * 4), u1: (c % 4 + 1) / 4 - 1.5 / (N * 4), v0: 1 - (Math.floor(c / 4) + 1) / 2 + 1.5 / (N * 2), v1: 1 - Math.floor(c / 4) / 2 - 1.5 / (N * 2) });\n return { canvas: cv, n: PICTURE_CELLS - 1, uv: c => uvc(c), mirror: () => uvc(7), names };\n}\n\n// light/dark ripple that tiles; the host scrolls texture.offset for the shimmer\nfunction waterAtlas(doc: DocumentLike): WaterAtlas {\n const N = 128, cv = makeCanvas(doc, N, N), g = cv.getContext('2d')!, r = rng(901);\n g.fillStyle = '#e6f2f8'; g.fillRect(0, 0, N, N);\n seamless(g, 0, 0, N, () => { for (let i = 0; i < 26; i++) { const x = r() * N, y = r() * N, w = 14 + r() * 26; g.strokeStyle = r() < 0.55 ? 'rgba(255,255,255,.9)' : 'rgba(110,170,200,.5)'; g.lineWidth = 1 + r() * 1.5; g.beginPath(); g.moveTo(x, y); g.quadraticCurveTo(x + w / 2, y - 5 - r() * 4, x + w, y); g.stroke(); } });\n return { canvas: cv };\n}\n\n/** Lazily builds and caches the procedural canvas atlases (one canvas per atlas; the host makes one texture per canvas). */\nexport function createAtlasProvider(doc: DocumentLike | null, pictureNames: string[]) {\n const cache: { [K in AtlasName]?: AtlasMap[AtlasName] } = {}\n return function atlas<K extends AtlasName>(name: K): AtlasMap[K] {\n if (!doc) throw new Error('game-props3d: a document is needed to build the atlases (pass options.document)')\n const made = cache[name]\n if (made) return made as AtlasMap[K]\n const build = { floor: () => floorAtlas(doc), picture: () => pictureAtlas(doc, pictureNames), water: () => waterAtlas(doc) }[name]\n return (cache[name] = build()) as AtlasMap[K]\n }\n}\n","import type { PropGroup, TypeDef } from './types'\n\nconst T = <I extends string>(id: I, interior: boolean, w: number, d: number, h: number, y: number, solid: boolean, group: PropGroup): TypeDef<I> => ({ id, interior, w, d, h, y, solid, group })\n\n/** id, interior, w, d, h, y (mounting height), solid (false = no collision), group. Names live in the locale table. */\nexport const TYPE_DEFS = [\n T('ceiling_light', true, 0.4, 0.4, 0.07, 0, false, 'ceiling'),\n T('pendant', true, 0.34, 0.34, 1.0, 0, false, 'ceiling'),\n T('track_spot', true, 1.2, 0.1, 0.2, 0, false, 'ceiling'),\n T('chandelier', true, 0.7, 0.7, 0.7, 0, false, 'ceiling'),\n T('wall_ac', true, 0.9, 0.2, 0.28, 2.15, false, 'wall'),\n T('picture_small', true, 0.35, 0.03, 0.45, 1.3, false, 'wall'),\n T('picture_large', true, 1.0, 0.04, 0.7, 1.2, false, 'wall'),\n T('mirror', true, 0.6, 0.03, 1.2, 0.9, false, 'wall'),\n T('curtain', true, 1.6, 0.12, 2.3, 0.1, false, 'wall'),\n T('blinds', true, 1.2, 0.08, 1.3, 1.0, false, 'wall'),\n T('flat_tv', true, 1.2, 0.06, 0.7, 1.0, false, 'wall'),\n T('floor_plant', true, 0.5, 0.5, 1.1, 0, true, 'plants'),\n T('table_plant', true, 0.2, 0.2, 0.3, 0, false, 'plants'),\n T('hanging_plant', true, 0.5, 0.5, 1.0, 0, false, 'plants'),\n T('tv_stand', true, 1.6, 0.42, 1.05, 0, true, 'furniture'),\n T('breakfast_bar', true, 2.0, 1.6, 0.95, 0, true, 'furniture'),\n T('sofa_l', true, 2.8, 1.7, 0.85, 0, true, 'furniture'),\n T('double_bed_modern', true, 1.6, 2.1, 1.2, 0, true, 'furniture'),\n T('home_office', true, 1.4, 0.75, 1.2, 0, true, 'furniture'),\n T('closet', true, 2.2, 0.6, 2.3, 0, true, 'furniture'),\n T('vanity', true, 0.6, 0.45, 1.5, 0, true, 'furniture'),\n T('ac_condenser', false, 0.8, 0.3, 0.55, 0.5, true, 'yard'),\n T('lawn', false, 4, 4, 0.02, 0, false, 'floor'),\n T('tile_floor', false, 4, 3, 0.03, 0, false, 'floor'),\n T('concrete', false, 4, 4, 0.03, 0, false, 'floor'),\n T('deck_floor', false, 4, 3, 0.04, 0, false, 'floor'),\n T('dirt', false, 4, 4, 0.02, 0, false, 'floor'),\n T('gourmet_counter', false, 4.2, 3.0, 2.9, 0, true, 'yard'),\n T('sauna', false, 2.0, 1.8, 2.1, 0, true, 'yard'),\n T('soaking_tub', false, 1.3, 1.3, 0.8, 0, true, 'yard'),\n T('pool', false, 4.5, 2.8, 0.1, 0, true, 'yard'),\n T('deck', false, 3.5, 3.0, 0.22, 0, true, 'yard'),\n T('sun_lounger', false, 0.62, 1.9, 0.5, 0, true, 'yard'),\n T('garden_bed', false, 2.0, 1.0, 0.9, 0, true, 'yard'),\n T('fruit_tree', false, 2.4, 2.4, 3.2, 0, true, 'yard'),\n T('palm_tree', false, 2.0, 2.0, 4.5, 0, true, 'yard'),\n T('pergola', false, 3.5, 3.0, 2.4, 0, true, 'yard'),\n T('slide', false, 0.8, 2.6, 1.5, 0, true, 'yard'),\n T('swing', false, 2.2, 1.7, 2.2, 0, true, 'yard'),\n T('bbq_simple', false, 0.9, 0.6, 1.0, 0, true, 'yard'),\n T('garage_car', false, 1.8, 4.2, 1.45, 0, true, 'yard'),\n T('window_boards', true, 1.2, 0.06, 1.15, 1.0, false, 'house_state'),\n T('barricade', true, 1.5, 0.7, 1.8, 0, true, 'house_state'),\n T('sandbags', false, 1.6, 0.5, 0.6, 0, true, 'house_state'),\n T('barbed_wire', false, 4.0, 0.2, 0.6, 0, false, 'house_state'),\n T('razor_wire', false, 4.0, 0.6, 0.6, 0, false, 'house_state'),\n T('water_bottle_crates', true, 0.9, 0.6, 0.65, 0, true, 'house_state'),\n T('canned_food', true, 0.4, 0.3, 0.3, 0, false, 'house_state'),\n T('water_jug', true, 0.3, 0.3, 0.5, 0, true, 'house_state'),\n T('floor_mattress', true, 0.9, 1.9, 0.3, 0, false, 'house_state'),\n T('lantern', true, 0.16, 0.16, 0.3, 0, false, 'house_state'),\n T('candles', true, 0.25, 0.25, 0.2, 0, false, 'house_state'),\n T('open_suitcases', true, 1.5, 0.7, 0.6, 0, false, 'house_state'),\n T('clothes_on_floor', true, 1.2, 1.0, 0.05, 0, false, 'house_state'),\n T('fallen_chair', true, 0.5, 0.5, 0.5, 0, false, 'house_state'),\n T('blood_stains', true, 1.2, 1.2, 0.01, 0, false, 'house_state'),\n T('open_door', true, 0.9, 0.15, 2.15, 0, false, 'house_state'),\n]\n\nexport type PropType = (typeof TYPE_DEFS)[number]['id']\n\nexport const DEFS = Object.fromEntries(TYPE_DEFS.map((t) => [t.id, t])) as Record<PropType, (typeof TYPE_DEFS)[number]>\n\nexport const MATERIALS = ['plain', 'metal', 'wood', 'glass', 'fabric', 'plant', 'water', 'emissive', 'atlas_picture', 'atlas_floor'] as const\n","import type { BuilderContext, BuilderMap } from '../types'\n\nexport function ceilingBuilders({ kit }: BuilderContext): Partial<BuilderMap> {\n const B: Partial<BuilderMap> = {}\n B.ceiling_light = (M, a) => { const K = kit(M, a), t = K.ceiling(), on = !!M.on;\n K.cyl('plain', 0, t - 0.05, 0, 0.2, 0.05, 0xece8e0); K.cyl('plain', 0, t - 0.07, 0, 0.15, 0.02, 0xd8d4c8); K.cyl(on ? 'emissive' : 'plain', 0, t - 0.078, 0, 0.12, 0.012, on ? 0xfff0c8 : 0xf4f0e6);\n if (on) K.light(0, t - 0.15, 0, 0xffe8b8, 6, 'ceiling_light'); };\n B.pendant = (M, a) => { const K = kit(M, a), t = K.ceiling(), { h } = K.dim('pendant'), ys = t - h, color = K.main(0x2a2a2a);\n K.box('plain', 0, ys + 0.1, 0, 0.012, h - 0.1, 0.012, 0x1a1a1a); K.cyl('plain', 0, t - 0.03, 0, 0.05, 0.03, 0xe8e4dc);\n K.cyl('plain', 0, ys, 0, 0.17, 0.14, color, 0, 0, 'sphere'); K.cyl('emissive', 0, ys - 0.035, 0, 0.045, 0.09, 0xffe0a0, 0, 0, 'sphere');\n if (M.light) K.light(0, ys - 0.1, 0, 0xffc880, 6, 'pendant'); };\n B.track_spot = (M, a) => { const K = kit(M, a), t = K.ceiling(), { w } = K.dim('track_spot'), on = !!M.on;\n K.box('metal', 0, t - 0.025, 0, w, 0.025, 0.035, 0x2a2a2a);\n for (let i = -1; i <= 1; i++) { const u = i * w / 3; K.box('metal', u, t - 0.1, 0, 0.02, 0.075, 0.02, 0x2a2a2a); K.cyl('metal', u, t - 0.16, 0.04, 0.035, 0.11, 0x222222, 2.6, 0); K.cyl(on ? 'emissive' : 'plain', u, t - 0.208, 0.069, 0.028, 0.006, on ? 0xfff0c8 : 0xe8e8e8, 2.6, 0); } };\n B.chandelier = (M, a) => { const K = kit(M, a), t = K.ceiling(), on = !!M.on, y = t - 0.5, gold = K.metal(0x8a7a5a);\n K.box('metal', 0, y, 0, 0.012, 0.5, 0.012, gold); K.cyl('metal', 0, y - 0.04, 0, 0.06, 0.08, gold); K.cyl('metal', 0, y - 0.06, 0, 0.14, 0.015, gold);\n for (let i = 0; i < 6; i++) { const an = i * Math.PI / 3, cx = Math.cos(an), cz = Math.sin(an);\n K.box('metal', cx * 0.14, y - 0.06, cz * 0.14, 0.28, 0.012, 0.012, gold, -an); K.cyl('plain', cx * 0.28, y - 0.06, cz * 0.28, 0.02, 0.09, 0xf0e6c8); K.cyl(on ? 'emissive' : 'plain', cx * 0.28, y + 0.03, cz * 0.28, 0.012, 0.03, on ? 0xffd890 : 0xe6d8b0, 0, 0, 'sphere');\n K.box('glass', cx * 0.3, y - 0.2, cz * 0.3, 0.025, 0.14, 0.025, 0xffffff, -an); K.box('glass', cx * 0.14, y - 0.18, cz * 0.14, 0.02, 0.12, 0.02, 0xffffff); }\n K.box('glass', 0, y - 0.3, 0, 0.05, 0.2, 0.05, 0xffffff, 0.7);\n if (M.light) K.light(0, y - 0.1, 0, 0xffd8a0, 6, 'chandelier'); };\n return B\n}\n","import type { BuilderContext, BuilderMap, FloorKind } from '../types'\n\nconst FLOOR_ITEMS: Array<FloorKind & keyof BuilderMap> = ['lawn', 'tile_floor', 'concrete', 'deck_floor', 'dirt']\n\n/** Ground cover items: one builder each, tiling the item's rectangle (or `M.poly`) with the floor atlas. */\nexport function floorBuilders({ cover }: BuilderContext): Partial<BuilderMap> {\n const B: Partial<BuilderMap> = {}\n for (const kind of FLOOR_ITEMS) B[kind] = (M, api) => cover(api, M, kind, { color: M.color })\n return B\n}\n","import { shade } from '../colors'\nimport type { Kit } from '../types'\n\nexport const GREENS = [0x3f7a3a, 0x2f6a30, 0x4f8a42, 0x5a9448]\n/** i-th shade of green (from the `plant` palette role or the defaults), alternating darker. */\nexport const green = (K: Kit, i: number): number => {\n const v = K.color('plant', GREENS[i % GREENS.length])\n return i % 2 ? shade(v, 0.85) : v\n}\nexport const pick = <T>(K: Kit, L: T[]): T => L[Math.floor(K.rnd() * L.length) % L.length]\n\n// flat TV: panel, screen, back box and either a stand (two feet) or a wall bracket; returns the panel height\nexport const drawTv = (K: Kit, x: number, y: number, z: number, w: number, stand: boolean): number => { const h = w * 0.5625, yb = stand ? y + 0.07 : y;\n K.box('plain', x, yb, z, w, h, 0.035, 0x101112); K.box('metal', x, yb + 0.015, z + 0.0175, w - 0.03, h - 0.03, 0.004, 0x0a0c10); K.box('plain', x, yb + h * 0.2, z - 0.035, w * 0.5, h * 0.55, 0.04, 0x1a1a1a);\n if (stand) { for (const s of [-1, 1]) K.box('metal', x + s * w * 0.33, y, z, 0.1, 0.07, 0.22, 0x1a1a1a); } else K.box('metal', x, yb + h * 0.35, z - 0.065, w * 0.3, 0.03, 0.03, 0x2a2a2a); return h; };\n","import type { BuilderContext, BuilderMap } from '../types'\nimport { shade } from '../colors'\nimport { drawTv, pick } from './shared'\n\nexport function furnitureBuilders({ kit, atlas }: BuilderContext): Partial<BuilderMap> {\n const B: Partial<BuilderMap> = {}\n B.breakfast_bar = (M, a) => { const K = kit(M, a), { w, d } = K.dim('breakfast_bar'), zb = -d / 2, cd = 0.65, body = K.color('wall_kitchen', 0xf0eee8), wood = K.wood(0xa07a50), paving = 0xf4f4f0;\n K.box('plain', 0, 0, zb + cd / 2 - 0.03, w - 0.06, 0.08, cd - 0.08, 0x2a2a2a); K.box('plain', 0, 0.08, zb + cd / 2, w, 0.8, cd, body);\n for (let i = 0; i < 4; i++) { K.box('wood', -w / 2 + (i + 0.5) * w / 4, 0.12, zb - 0.004, w / 4 - 0.025, 0.72, 0.012, wood); K.box('metal', -w / 2 + (i + 0.5) * w / 4 + (i % 2 ? -0.12 : 0.12), 0.75, zb - 0.012, 0.012, 0.14, 0.016, 0x9a9a9a); }\n K.box('plain', 0, 0.88, zb + (cd + 0.32) / 2, w + 0.04, 0.04, cd + 0.32, paving);\n for (const s of [-1, 1]) K.box('metal', s * (w / 2 - 0.05), 0, zb + cd + 0.24, 0.05, 0.88, 0.05, 0x2a2a2a);\n K.box('metal', -w * 0.22, 0.915, zb + cd / 2, 0.52, 0.006, 0.38, 0xb0b4b8); K.box('metal', -w * 0.22, 0.92, zb + cd / 2, 0.46, 0.004, 0.32, 0x70767a); K.cyl('metal', -w * 0.22, 0.92, zb + 0.1, 0.014, 0.26, 0xb8bcc0); K.box('metal', -w * 0.22, 1.16, zb + 0.15, 0.02, 0.02, 0.1, 0xb8bcc0);\n K.cyl('plain', w * 0.25, 0.92, zb + cd / 2 + 0.2, 0.13, 0.05, 0xf0f0ea); for (let i = 0; i < 3; i++) K.cyl('plain', w * 0.25 + (i - 1) * 0.07, 0.97, zb + cd / 2 + 0.2 + (i % 2) * 0.03, 0.045, 0.09, [0xe8801c, 0xc83030, 0xd8c040][i], 0, 0, 'sphere');\n const stool = K.accent(0x8a5a38); for (let i = 0; i < 3; i++) { const x = (i - 1) * w * 0.3, z = zb + cd + 0.5;\n K.cyl('plain', x, 0.62, z, 0.17, 0.05, stool); K.cyl('metal', x, 0.04, z, 0.02, 0.58, 0x2a2a2a); K.cyl('metal', x, 0, z, 0.17, 0.02, 0x2a2a2a); K.cyl('metal', x, 0.25, z, 0.14, 0.012, 0x2a2a2a); } };\n B.sofa_l = (M, a) => { const K = kit(M, a), { w, d } = K.dim('sofa_l'), c = K.fabric(pick(K, [0x6e7078, 0x8a7a68, 0x45586a])), cd = shade(c, 0.82), zb = -d / 2, pf = 0.95, ac = K.accent(0xc89a4a), cw = 0.95;\n for (const sx of [-1, 1]) for (const sz of [-1, 1]) K.box('wood', sx * (w / 2 - 0.1), 0, sz * (d / 2 - 0.1), 0.05, 0.08, 0.05, K.wood(0x2a1d14));\n K.box('fabric', -(cw / 2), 0.08, zb + pf / 2, w - cw, 0.26, pf, cd); K.box('fabric', w / 2 - cw / 2, 0.08, 0, cw, 0.26, d, cd);\n K.box('fabric', 0, 0.08, zb + 0.11, w, 0.72, 0.22, cd); K.box('fabric', -w / 2 + 0.09, 0.08, zb + pf / 2, 0.18, 0.55, pf, cd);\n const nm = 2, mw = (w - cw - 0.18) / nm; for (let i = 0; i < nm; i++) K.box('fabric', -w / 2 + 0.18 + (i + 0.5) * mw, 0.34, zb + 0.12 + 0.39, mw - 0.02, 0.16, 0.78, c);\n K.box('fabric', w / 2 - cw / 2, 0.34, 0.035, cw - 0.04, 0.16, d - 0.2, c);\n for (let i = 0; i < 4; i++) K.box('fabric', -w / 2 + 0.18 + (i + 0.5) * (w - 0.2) / 4, 0.42, zb + 0.28, (w - 0.2) / 4 - 0.03, 0.4, 0.14, c, 0, 0.15);\n K.box('fabric', -w * 0.3, 0.5, zb + 0.5, 0.4, 0.38, 0.12, ac, 0.3, 0.3); K.box('fabric', w * 0.32, 0.5, zb + 0.5, 0.38, 0.36, 0.12, shade(ac, 0.8), -0.3, 0.3); };\n B.double_bed_modern = (M, a) => { const K = kit(M, a), { w, d } = K.dim('double_bed_modern'), wood = K.wood(0x6a4c34), edr = K.fabric(0x8a8d92), accent = K.accent(0xc89a4a);\n K.box('wood', 0, 0.05, 0.02, w + 0.06, 0.2, d + 0.02, shade(wood, 0.85)); K.box('fabric', 0, 0.25, 0.05, w - 0.04, 0.24, d - 0.1, 0xf2f0ea);\n K.box('fabric', 0, 0.47, 0.35, w, 0.06, d * 0.64, edr); K.box('fabric', 0, 0.5, -0.05, w * 0.98, 0.05, 0.3, shade(edr, 1.12)); K.box('fabric', 0, 0.52, d / 2 - 0.4, w * 0.9, 0.03, 0.3, accent);\n for (const s of [-1, 1]) K.box('fabric', s * w * 0.24, 0.49, -d / 2 + 0.3, w * 0.4, 0.13, 0.36, 0xf4f2ec, s * 0.06);\n K.box('fabric', 0, 0.55, -d / 2 + 0.5, 0.4, 0.16, 0.12, accent, 0, 0.5);\n const hw = w + 0.5, n = Math.round(hw / 0.11); K.box('wood', 0, 0.2, -d / 2 - 0.05, hw, 1.0, 0.04, shade(wood, 0.7)); for (let i = 0; i < n; i++) K.box('wood', -hw / 2 + (i + 0.5) * hw / n, 0.25, -d / 2 - 0.02, hw / n - 0.025, 0.95, 0.04, i % 2 ? wood : shade(wood, 1.12));\n for (const s of [-1, 1]) { K.box('wood', s * (w / 2 + 0.3), 0.35, -d / 2 + 0.22, 0.4, 0.16, 0.36, shade(wood, 1.05)); K.cyl('plain', s * (w / 2 + 0.3), 0.51, -d / 2 + 0.2, 0.06, 0.03, 0xe8e4dc); K.cyl('plain', s * (w / 2 + 0.3), 0.54, -d / 2 + 0.2, 0.012, 0.18, 0xe8e4dc); K.cyl('plain', s * (w / 2 + 0.3), 0.72, -d / 2 + 0.2, 0.09, 0.12, 0xf0e6c8); } };\n B.home_office = (M, a) => { const K = kit(M, a), { w, d } = K.dim('home_office'), wood = K.wood(0xd2b48c), zb = -d / 2;\n K.box('wood', 0, 0.72, 0, w, 0.035, d, wood); for (const s of [-1, 1]) K.box('metal', s * (w / 2 - 0.04), 0, 0, 0.035, 0.72, d - 0.1, 0x222226); K.box('metal', 0, 0.3, zb + 0.05, w - 0.1, 0.03, 0.02, 0x222226);\n K.box('plain', w / 2 - 0.25, 0.28, 0, 0.4, 0.44, d - 0.08, 0xe8e4dc); for (let i = 0; i < 2; i++) { K.box('plain', w / 2 - 0.25, 0.3 + i * 0.2, d / 2 - 0.04, 0.37, 0.18, 0.01, 0xf2eee6); K.box('metal', w / 2 - 0.25, 0.39 + i * 0.2, d / 2 - 0.03, 0.12, 0.012, 0.012, 0x9a9a9a); }\n K.box('metal', 0, 0.755, zb + 0.2, 0.22, 0.012, 0.16, 0x1a1a1a); K.box('metal', 0, 0.76, zb + 0.14, 0.04, 0.2, 0.025, 0x1a1a1a); K.box('plain', 0, 0.88, zb + 0.15, 0.62, 0.36, 0.035, 0x101112); K.box('metal', 0, 0.895, zb + 0.1685, 0.6, 0.33, 0.004, 0x0a0c10);\n K.box('plain', 0, 0.755, zb + 0.43, 0.42, 0.014, 0.14, 0x1a1a1c); K.box('plain', 0.34, 0.755, zb + 0.43, 0.06, 0.025, 0.1, 0x1a1a1c, 0.2);\n K.cyl('metal', -w * 0.4, 0.755, zb + 0.2, 0.07, 0.015, 0x2a2a2a); K.box('metal', -w * 0.4, 0.77, zb + 0.2, 0.012, 0.3, 0.012, 0x2a2a2a, 0, 0.3); K.cyl('plain', -w * 0.4, 1.02, zb + 0.28, 0.06, 0.05, K.main(0xd8d4c8), 0.7, 0);\n K.box('fabric', -0.5, 0.755, 0.05, 0.2, 0.02, 0.28, K.accent(0x2e5e7e), 0.2); K.cyl('plain', -0.3, 0.755, 0.12, 0.04, 0.09, 0xd8d0c0);\n const zc = d / 2 + 0.3, cc = K.fabric(0x2a2a2e); K.box('plain', 0, 0.44, zc, 0.48, 0.07, 0.46, cc); K.box('plain', 0, 0.52, zc + 0.22, 0.44, 0.52, 0.07, cc, 0, 0.12); K.cyl('metal', 0, 0.06, zc, 0.025, 0.38, 0x2a2a2a);\n for (let i = 0; i < 5; i++) { const an = i * 1.2566, x = Math.cos(an) * 0.17, z = zc + Math.sin(an) * 0.17; K.box('metal', Math.cos(an) * 0.085, 0.06, zc + Math.sin(an) * 0.085, 0.18, 0.025, 0.03, 0x2a2a2a, -an); K.cyl('plain', x, 0, z, 0.03, 0.05, 0x1a1a1a); } };\n B.closet = (M, a) => { const K = kit(M, a), { w, d, h } = K.dim('closet'), wood = K.color('wall_bedroom', 0xe6e0d4), mw = K.wood(0xb89468), dv = -w * 0.1;\n K.box('plain', 0, 0, -d / 2 + 0.01, w, h, 0.02, shade(wood, 0.95)); for (const s of [-1, 1]) K.box('plain', s * (w / 2 - 0.015), 0, 0, 0.03, h, d, wood); K.box('plain', 0, h - 0.03, 0, w, 0.03, d, wood); K.box('plain', 0, 0.06, 0, w - 0.06, 0.02, d - 0.02, wood); K.box('plain', 0, 0, 0.0, w - 0.04, 0.06, d - 0.06, 0x2a2a2a); K.box('plain', dv, 0.06, 0, 0.025, h - 0.09, d - 0.02, wood);\n const rod = h * 0.76; K.cyl('metal', (-w / 2 + dv) / 2, rod, 0, 0.012, dv + w / 2 - 0.06, 0xb0b4b8, 0, Math.PI / 2); K.box('plain', (-w / 2 + dv) / 2, rod + 0.05, 0, dv + w / 2 - 0.05, 0.02, d - 0.04, wood);\n const nc = 9, L0 = -w / 2 + 0.06, L1 = dv - 0.05, cs = [0x2a2a30, 0xc8c0a8, 0x4a6a8a, 0xa8483a, 0xe0dcd0, 0x6a8a5a, 0x3a3a3a, 0x8a7a68, 0xd8b8a0];\n for (let i = 0; i < nc; i++) { const gh = 0.6 + K.rnd() * 0.5; K.box('fabric', L0 + (i + 0.5) * (L1 - L0) / nc, rod - gh - 0.02, 0, 0.045, gh, 0.4, i % 3 === 0 ? K.accent(cs[i]) : cs[i]); K.box('metal', L0 + (i + 0.5) * (L1 - L0) / nc, rod - 0.04, 0, 0.004, 0.04, 0.2, 0xb0b4b8); }\n const sx = (dv + w / 2) / 2 + dv / 2 + 0.0, rx0 = dv + 0.015, rw = w / 2 - 0.015 - rx0, rc = rx0 + rw / 2;\n for (let i = 0; i < 5; i++) { const y = 0.5 + i * 0.35; K.box('plain', rc, y, 0, rw, 0.022, d - 0.02, wood); if (i < 4) for (let j = 0; j < 3; j++) { const sh = 0.04 + K.rnd() * 0.12; K.box('fabric', rc - rw * 0.3 + j * rw * 0.3, y + 0.022, 0.0, 0.26, sh, 0.32, cs[(i * 3 + j) % cs.length]); } }\n for (let i = 0; i < 2; i++) { K.box('wood', rc, 0.08 + i * 0.2, d / 2 - 0.01, rw - 0.03, 0.18, 0.02, mw); K.box('metal', rc, 0.2 + i * 0.2, d / 2 + 0.005, 0.2, 0.012, 0.014, 0xb0b4b8); } void sx; };\n B.vanity = (M, a) => { const K = kit(M, a), { w, d } = K.dim('vanity'), zb = -d / 2, br = 0xf4f4f0;\n K.cyl('plain', 0, 0, zb + 0.12, 0.08, 0.7, br); K.cyl('plain', 0, 0, zb + 0.12, 0.1, 0.03, br); K.box('plain', 0, 0.74, 0, w, 0.12, d, br); K.box('plain', 0, 0.865, 0.02, w - 0.1, 0.012, d - 0.1, 0xd4d8da); K.cyl('metal', 0, 0.87, 0.05, 0.02, 0.01, 0x70767a);\n K.cyl('metal', 0, 0.87, zb + 0.05, 0.014, 0.1, 0xb8bcc0); K.box('metal', 0, 0.96, zb + 0.09, 0.02, 0.014, 0.09, 0xb8bcc0); K.box('metal', w * 0.3, 0.87, zb + 0.06, 0.04, 0.06, 0.04, 0x2a7a8a);\n K.box('plain', 0, 1.1, zb + 0.012, 0.52, 0.72, 0.024, K.color('metal', 0xe4e0d8)); K.plane('atlas_picture', 0, 1.46, zb + 0.026, 0.46, 0.66, 0xffffff, 0, 0, 0, atlas('picture').mirror());\n K.box('metal', -w / 2 - 0.02, 0.95, zb + 0.06, 0.03, 0.03, 0.03, 0xb0b4b8); K.box('metal', -w / 2 - 0.02, 0.95, zb + 0.06, 0.28, 0.014, 0.014, 0xb0b4b8); K.box('fabric', -w / 2 - 0.02, 0.62, zb + 0.065, 0.26, 0.34, 0.02, K.accent(0x2e6e7e)); };\n B.tv_stand = (M, a) => { const K = kit(M, a), { w, d } = K.dim('tv_stand'), wood = K.wood(0xc8a070), br = K.color('fabric_main', 0xf0ede6);\n for (const sx of [-1, 1]) for (const sz of [-1, 1]) K.box('metal', sx * (w / 2 - 0.08), 0, sz * (d / 2 - 0.06), 0.035, 0.16, 0.035, 0x1a1a1a);\n K.box('wood', 0, 0.16, 0, w, 0.32, d, wood); K.box('plain', 0, 0.48, 0, w + 0.02, 0.025, d + 0.02, br);\n for (let i = 0; i < 2; i++) K.box('plain', -w / 2 + (i + 0.5) * 0.375 * w, 0.18, d / 2 + 0.004, 0.375 * w - 0.02, 0.28, 0.01, shade(br, 0.97)); // two doors on the left\n K.box('plain', w / 4 + w / 8, 0.19, 0, w / 4 - 0.04, 0.2, d - 0.04, 0x1c1c20); K.box('plain', w / 4 + w / 8, 0.22, 0.05, 0.28, 0.06, 0.2, 0x2a2a30); K.box('fabric', w / 4 + w / 8 + 0.03, 0.29, 0.0, 0.2, 0.05, 0.14, K.accent(0x8a4a3a)); // open niche: console and books\n const th = drawTv(K, 0, 0.5, 0, Math.min(1.3, w * 0.78), true); K.box('plain', 0, 0.5, d / 2 - 0.06, Math.min(1.0, w * 0.55), 0.06, 0.06, 0x16161a); void th; };\n return B\n}\n","import { seedOf, shade } from '../colors'\nimport type { BuilderContext, BuilderMap, Material, PropItem, PropsApi } from '../types'\n\nexport function houseStateBuilders({ kit }: BuilderContext): Partial<BuilderMap> {\n const B: Partial<BuilderMap> = {}\n B.window_boards = (M, a) => { const K = kit(M, a), { w, h, d } = K.dim('window_boards'), y = M.y || 1.0, x = M.variant ? M.variant === 'x' : (seedOf(M) & 1) === 0, cs = [0x7a5634, 0x6b4a2a, 0x8a6a44, 0x5e4228], z = d / 2;\n if (x) { const L = Math.hypot(w, h) + 0.15, an = Math.atan2(h, w); for (const s of [-1, 1]) K.box('wood', 0, y + h / 2 - 0.075, z + (s > 0 ? 0 : 0.03), L, 0.15, 0.03, cs[s > 0 ? 0 : 1], 0, 0, s * an + (K.rnd() - 0.5) * 0.05); K.box('wood', 0, y + h * 0.3, z + 0.06, w + 0.3, 0.15, 0.03, cs[2], 0, 0, (K.rnd() - 0.5) * 0.06); for (const [nx, ny] of [[-w / 2, y], [w / 2, y], [-w / 2, y + h], [w / 2, y + h], [0, y + h / 2]]) K.cyl('metal', nx, ny, z + 0.09, 0.012, 0.02, 0x5a5a5e, Math.PI / 2, 0); }\n else { const n = Math.ceil(h / 0.17); for (let i = 0; i < n; i++) { const yy = y + i * (h - 0.15) / (n - 1 || 1), ww = w + 0.2 + K.rnd() * 0.15; K.box('wood', (K.rnd() - 0.5) * 0.1, yy, z + (i % 2) * 0.03, ww, 0.15, 0.03, cs[i % 4], 0, 0, (K.rnd() - 0.5) * 0.05); for (const s of [-1, 1]) K.cyl('metal', s * (w / 2 + 0.02), yy + 0.075, z + (i % 2) * 0.03 + 0.016, 0.01, 0.015, 0x5a5a5e, Math.PI / 2, 0); } } };\n B.barricade = (M, a) => { const K = kit(M, a), { w, d, h } = K.dim('barricade'), wood = K.wood(0x6a4a34), z0 = -d / 2;\n K.box('wood', -w * 0.22, 0, z0 + 0.3, w * 0.5, h * 0.8, 0.45, wood, 0.06, -0.12); K.box('plain', -w * 0.22, h * 0.3, z0 + 0.54, 0.3, 0.012, 0.01, 0x9a9a9a);\n K.box('fabric', w * 0.2, 0, z0 + 0.4, w * 0.5, h * 0.95, 0.18, K.fabric(0xc8c0b0), -0.08, -0.28); K.box('fabric', w * 0.2, 0, z0 + 0.4, w * 0.5 - 0.1, h * 0.9, 0.19, K.accent(0x5a7a9a), -0.08, -0.28);\n K.box('plain', w * 0.38, 0, z0 + 0.35, 0.5, 0.4, 0.4, 0xb89a6a, 0.2); K.box('plain', w * 0.4, 0.4, z0 + 0.33, 0.45, 0.35, 0.38, 0xa8885a, -0.3);\n for (let i = 0; i < 4; i++) { K.box('wood', 0, 0.45 + i * 0.3, z0 + 0.62, w + 0.3, 0.14, 0.04, [0x7a5634, 0x8a6a44, 0x6b4a2a, 0x7a5a38][i], 0, 0, (i % 2 ? 1 : -1) * (0.06 + K.rnd() * 0.08)); for (const s of [-1, 1]) K.cyl('metal', s * w * 0.4, 0.45 + i * 0.3, z0 + 0.65, 0.012, 0.02, 0x5a5a5e, Math.PI / 2, 0); }\n K.box('wood', -w * 0.4, 0.0, z0 + 0.9, 0.4, 0.04, 0.4, wood, 0.3, 0, 0.4); K.box('wood', -w * 0.45, 0.0, z0 + 0.7, 0.04, 0.5, 0.04, wood, 0, 0.9, 0.2); };\n B.sandbags = (M, a) => { const K = kit(M, a), { w, d, h } = K.dim('sandbags'), cs = [K.fabric(0xb8a678), 0xa89868, 0xc4b284], bw = 0.46, bh = 0.17, nl = Math.max(1, Math.min(4, Math.round(h / bh)));\n for (let l = 0; l < nl; l++) { const nb = Math.max(1, Math.floor((w - l * 0.18) / bw)); for (let i = 0; i < nb; i++) { const x = -nb * bw / 2 + (i + 0.5) * bw + (l % 2) * 0.12; K.box('fabric', x, l * bh * 0.95, (K.rnd() - 0.5) * 0.04, bw * 0.97, bh, Math.min(d, 0.3), cs[(i + l) % 3], (K.rnd() - 0.5) * 0.08, 0, (K.rnd() - 0.5) * 0.04); K.box('fabric', x + bw * 0.46, l * bh * 0.95 + 0.04, 0, 0.03, 0.09, 0.2, shade(cs[(i + l) % 3], 0.8)); } } };\n B.barbed_wire = (M, a) => { const K = kit(M, a), { w } = K.dim('barbed_wire'), np = Math.max(2, Math.round(w / 2) + 1), wire = 0x8a8c90;\n for (let i = 0; i < np; i++) { const x = -w / 2 + i * w / (np - 1); K.box('wood', x, 0, 0, 0.07, 0.6, 0.07, 0x5a4a3a); }\n for (const y of [0.25, 0.4, 0.55]) { K.box('metal', 0, y, 0.04, w, 0.008, 0.008, wire); const nb = Math.floor(w / 0.16); for (let i = 0; i < nb; i++) { const x = -w / 2 + (i + 0.5) * w / nb; K.box('metal', x, y - 0.012, 0.04, 0.05, 0.006, 0.006, wire, 0, 0, 0.8); K.box('metal', x, y - 0.012, 0.04, 0.05, 0.006, 0.006, wire, 0, 0, -0.8); } } };\n B.razor_wire = (M, a) => { const K = kit(M, a), { w } = K.dim('razor_wire'), r = 0.28, wire = 0x9a9ca0, nr = Math.max(3, Math.round(w / 0.22)), ns = 8, sl = 2 * Math.PI * r / ns * 1.05, y0 = M.y || 0;\n for (let i = 0; i < nr; i++) { const x = -w / 2 + (i + 0.5) * w / nr, lean = (i % 2 ? 0.1 : -0.1); for (let s = 0; s < ns; s++) { const th = (s + 0.5) / ns * Math.PI * 2; K.box('metal', x + Math.sin(th) * lean * 0.3, y0 + r + Math.sin(th) * r - 0.006, Math.cos(th) * r, 0.01, 0.012, sl, wire, 0, -(th + Math.PI / 2), lean); } }\n for (const s of [-1, 1]) K.box('metal', s * w / 2, y0, 0, 0.03, 0.12, 0.03, 0x5a5a5e); };\n B.water_bottle_crates = (M, a) => { const K = kit(M, a), { w, d } = K.dim('water_bottle_crates'), pw = 0.4, pd = 0.28, ph = 0.27, nx = Math.max(1, Math.floor(w / pw)), nz = Math.max(1, Math.floor(d / pd)), nl = 2;\n K.box('wood', 0, 0, 0, nx * pw, 0.05, nz * pd, 0x8a6a44);\n for (let l = 0; l < nl; l++) for (let i = 0; i < nx; i++) for (let j = 0; j < nz; j++) { const x = -nx * pw / 2 + (i + 0.5) * pw, z = -nz * pd / 2 + (j + 0.5) * pd, y = 0.05 + l * ph; K.box('plain', x, y, z, pw - 0.01, ph, pd - 0.01, 0xdceaf4); K.box('plain', x, y + 0.08, z, pw - 0.005, 0.08, pd - 0.005, K.accent(0x2a6aa8)); if (l === nl - 1) for (let u = 0; u < 3; u++) for (let v = 0; v < 2; v++) K.cyl('plain', x - 0.11 + u * 0.11, y + ph, z - 0.06 + v * 0.12, 0.028, 0.02, 0x2a6aa8); } };\n B.canned_food = (M, a) => { const K = kit(M, a), y = M.y || 0, cs = [0xc8a030, 0xb03a2a, 0x4a7a3a, 0xd8d0b0, 0x8a3a2a], rw = [4, 3, 2];\n rw.forEach((n, r) => { for (let i = 0; i < n; i++) { const x = (i - (n - 1) / 2) * 0.072, c = cs[(i + r * 2) % cs.length]; K.cyl('plain', x, y + r * 0.1, 0, 0.033, 0.1, c); K.cyl('plain', x, y + r * 0.1 + 0.02, 0, 0.0345, 0.055, 0xe8e4d8); K.cyl('metal', x, y + r * 0.1 + 0.1, 0, 0.031, 0.004, 0xb8bcc0); } });\n K.cyl('plain', 0.3, y + 0.033, 0.1, 0.033, 0.1, 0xc8a030, 0, Math.PI / 2); K.cyl('plain', -0.32, y + 0.033, 0.12, 0.033, 0.1, 0xb03a2a, 0, 1.2); };\n B.water_jug = (M, a) => { const K = kit(M, a), y = M.y || 0, az = K.accent(0x5aa0d8);\n K.cyl('plain', 0, y, 0, 0.13, 0.32, az); K.cyl('plain', 0, y + 0.32, 0, 0.1, 0.05, az); K.cyl('plain', 0, y + 0.37, 0, 0.05, 0.08, az); K.cyl('plain', 0, y + 0.45, 0, 0.055, 0.035, 0x2a5a9a); K.cyl('plain', 0, y + 0.12, 0, 0.1325, 0.1, 0xf4f4f0); K.box('plain', 0.14, y + 0.22, 0, 0.04, 0.12, 0.05, shade(az, 0.85)); };\n B.floor_mattress = (M, a) => { const K = kit(M, a), { w, d } = K.dim('floor_mattress'), h = 0.17, c = K.fabric(0xc8c0b0), ac = K.accent(0x6a4a3a);\n K.box('fabric', 0, 0, 0, w, h, d, c); for (let i = 0; i < 4; i++) K.box('fabric', -w / 2 + (i + 0.5) * w / 4, h, 0, w / 8, 0.003, d - 0.04, shade(c, 0.86)); K.box('fabric', 0, h, -d / 2 + 0.28, w * 0.7, 0.1, 0.38, 0xf0ece0, 0.05);\n K.box('fabric', 0.03, h, 0.3, w * 0.95, 0.05, d * 0.55, ac, 0.05); K.box('fabric', 0.15, h + 0.05, 0.0, w * 0.5, 0.05, 0.4, shade(ac, 1.2), 0.3); K.box('fabric', -0.2, h + 0.05, 0.5, w * 0.3, 0.06, 0.3, shade(ac, 0.8), -0.4); };\n B.lantern = (M, a) => { const K = kit(M, a), y = M.y || 0;\n K.cyl('metal', 0, y, 0, 0.07, 0.03, 0x2a4a2a); K.cyl('emissive', 0, y + 0.03, 0, 0.055, 0.18, 0xffd890); for (const sx of [-1, 1]) for (const sz of [-1, 1]) K.box('metal', sx * 0.05, y + 0.03, sz * 0.05, 0.01, 0.18, 0.01, 0x2a2a2a);\n K.cyl('metal', 0, y + 0.21, 0, 0.075, 0.025, 0x2a4a2a); K.box('metal', 0, y + 0.235, 0, 0.1, 0.012, 0.012, 0x2a2a2a); for (const s of [-1, 1]) K.box('metal', s * 0.05, y + 0.235, 0, 0.01, 0.045, 0.01, 0x2a2a2a);\n if (M.lit !== false) K.light(0, y + 0.15, 0, 0xffc880, 7, 'lantern'); };\n B.candles = (M, a) => { const K = kit(M, a), y = M.y || 0;\n K.cyl('plain', 0, y, 0, 0.09, 0.012, 0xf0f0ea); [[0, 0, 0.16], [0.06, 0.03, 0.1], [-0.05, 0.04, 0.12], [0.02, -0.06, 0.07]].forEach(([x, z, h], i) => { K.cyl('plain', x, y + 0.012, z, 0.017, h, 0xf0e6c8); K.cyl('emissive', x, y + 0.012 + h, z, 0.008, 0.03, i % 2 ? 0xffc060 : 0xffd890, 0, 0, 'sphere'); });\n K.cyl('plain', 0.02, y + 0.012, 0.0, 0.05, 0.008, 0xf0e6c8); if (M.lit !== false) K.light(0, y + 0.22, 0, 0xffb060, 5, 'candles'); };\n B.open_suitcases = (M, a) => { const K = kit(M, a), cs = [K.main(0xb03a34), 0x2a3a5a], rs = [0xc8c0a8, 0x4a6a8a, 0xe0dcd0, 0xa8483a];\n const suitcase = (x: number, z: number, ww: number, dd: number, c: number, ry: number, al: number) => { const lx = x, hz = z - dd / 2;\n K.box('plain', lx, 0, z, ww, 0.16, dd, c, ry); K.box('fabric', lx, 0.12, z, ww - 0.06, 0.05, dd - 0.06, 0xd8d0c0, ry);\n for (let i = 0; i < 5; i++) K.box('fabric', lx + (K.rnd() - 0.5) * (ww - 0.2), 0.16, z + (K.rnd() - 0.5) * (dd - 0.2), 0.14 + K.rnd() * 0.1, 0.04 + K.rnd() * 0.04, 0.12 + K.rnd() * 0.1, rs[i % 4], K.rnd() * 3);\n K.ramp('plain', lx, 0.16, hz, ww, 0.07, dd, c, al); K.box('metal', lx + ww * 0.3, 0.1, z + dd / 2, 0.04, 0.03, 0.01, 0xc0c0c0); };\n suitcase(-0.4, 0, 0.75, 0.5, cs[0], 0.15, 1.35); suitcase(0.45, 0.1, 0.6, 0.42, cs[1], -0.3, 1.2); };\n B.clothes_on_floor = (M, a) => { const K = kit(M, a), { w, d } = K.dim('clothes_on_floor'), cs = [0xc8c0a8, 0x4a6a8a, 0xa8483a, 0xe0dcd0, 0x6a8a5a, 0x2a2a30, K.accent(0xc89a4a)];\n for (let i = 0; i < 9; i++) { const x = (K.rnd() - 0.5) * (w - 0.3), z = (K.rnd() - 0.5) * (d - 0.3), r = K.rnd() * 6, c = cs[i % cs.length], y = 0.012 + i * 0.003;\n if (i % 3 === 0) { K.box('fabric', x, y, z, 0.3, 0.012, 0.36, c, r); for (const s of [-1, 1]) K.box('fabric', x + Math.cos(r) * s * 0.2, y, z - Math.sin(r) * s * 0.2, 0.2, 0.012, 0.09, shade(c, 0.9), r + s * 0.5); }\n else if (i % 3 === 1) { for (const s of [-1, 1]) K.box('fabric', x + s * 0.06, y, z, 0.13, 0.014, 0.5, 0x3a4a6a, r + s * 0.15); } else K.box('fabric', x, y, z, 0.14, 0.01, 0.07, c, r); }\n const sx = (K.rnd() - 0.5) * (w - 0.4), sz = (K.rnd() - 0.5) * (d - 0.4); K.box('plain', sx, 0.012, sz, 0.09, 0.07, 0.27, 0x2a2a2a, 0.4); K.box('plain', sx + 0.15, 0.012, sz + 0.05, 0.09, 0.07, 0.27, 0x2a2a2a, 0.9); };\n B.fallen_chair = (M, a) => { // wooden chair knocked over on its side: the parts are axis-aligned boxes, rotated 90 degrees around z\n const g = Math.PI / 2, dy = 0.23, api = { box: (Mm: PropItem, mat: Material, x: number, y: number, z: number, w: number, h: number, d: number, color: number, ry: number, rx: number, rz?: number) => { const cy = y + h / 2; a.box(Mm, mat, -cy + 0.0, dy + x - h / 2 + 0.0 - 0.0, z, w, h, d, color, ry, rx, g + (rz || 0)); } };\n const K = kit(M, api as unknown as PropsApi), c = K.main(0x6a4a30); // center (x, y, z) becomes (-cy, x): the api y is the base, so h/2 is subtracted\n K.box('wood', 0, 0.44, 0, 0.42, 0.04, 0.42, c); for (const sx of [-1, 1]) for (const sz of [-1, 1]) K.box('wood', sx * 0.18, 0, sz * 0.18, 0.035, 0.44, 0.035, shade(c, 0.85));\n K.box('wood', 0, 0.48, -0.19, 0.42, 0.45, 0.03, c); };\n B.blood_stains = (M, a) => { const K = kit(M, a), { w, d } = K.dim('blood_stains');\n for (let k = 0; k < 7; k++) K.cyl('plain', (K.rnd() - 0.5) * w * 0.3, 0.012 + k * 0.0004, (K.rnd() - 0.5) * d * 0.3, 0.12 + K.rnd() * 0.18, 0.003, k < 2 ? 0x3a0806 : 0x5a100c);\n for (let k = 0; k < 8; k++) { const an = K.rnd() * 6.28, r = 0.3 + K.rnd() * Math.min(w, d) * 0.4; K.cyl('plain', Math.cos(an) * r, 0.013 + k * 0.0002, Math.sin(an) * r, 0.02 + K.rnd() * 0.05, 0.003, 0x4a0a08); }\n if (M.drag !== false) for (let k = 1; k < 6; k++) K.box('plain', 0.3 + k * 0.1, 0.012, 0.15 + k * 0.17, 0.16 - k * 0.015, 0.003, 0.2, 0x4a0c0a, 0.5); };\n B.open_door = (M, a) => { const K = kit(M, a), { w, d, h } = K.dim('open_door'), wood = K.wood(0x6a4a2c), angle = M.angle != null ? M.angle : 1.2, L = w - 0.06, hx = -w / 2 + 0.03;\n K.box('wood', -w / 2 - 0.03, 0, 0, 0.06, h + 0.06, d, shade(wood, 0.8)); K.box('wood', w / 2 + 0.03, 0, 0, 0.06, h + 0.06, d, shade(wood, 0.8)); K.box('wood', 0, h, 0, w + 0.12, 0.06, d, shade(wood, 0.8));\n K.box('wood', hx + Math.cos(angle) * L / 2, 0.0, Math.sin(angle) * L / 2, L, h - 0.02, 0.04, wood, -angle); K.cyl('metal', hx + Math.cos(angle) * (L - 0.08), 1.0, Math.sin(angle) * (L - 0.08) + 0.04, 0.025, 0.06, 0xc8b070, Math.PI / 2, 0);\n for (const y of [0.2, 1.0, 1.8]) K.box('metal', hx, y, 0.0, 0.02, 0.1, 0.02, 0x8a8a8a); };\n return B\n}\n","import type { BuilderContext, BuilderMap } from '../types'\nimport { shade } from '../colors'\nimport type { Kit } from '../types'\nimport { green } from './shared'\n\nexport function plantBuilders({ kit }: BuilderContext): Partial<BuilderMap> {\n const B: Partial<BuilderMap> = {}\n const foliage = (K: Kit, x: number, y: number, z: number, n: number, w: number, h0: number, h1: number, tilt0: number, tilt1: number, twist = 2.4) => { for (let i = 0; i < n; i++) { const an = i * twist + K.rnd() * 0.5, t = tilt0 + (tilt1 - tilt0) * K.rnd(); K.leaf(x + Math.cos(an) * 0.03, y, z + Math.sin(an) * 0.03, w * (0.8 + K.rnd() * 0.4), h0 + (h1 - h0) * K.rnd(), green(K, i), an, t); } };\n B.floor_plant = (M, a) => { const K = kit(M, a), { w } = K.dim('floor_plant'), r = Math.min(0.24, w * 0.4), pot = K.main(0xb5603c);\n K.cyl('plain', 0, 0, 0, r, 0.38, pot); K.cyl('plain', 0, 0.34, 0, r * 1.07, 0.05, shade(pot, 0.92)); K.cyl('plain', 0, 0.385, 0, r * 0.92, 0.012, 0x3a2a1e);\n foliage(K, 0, 0.39, 0, 11, 0.2, 0.5, 0.85, 0.2, 0.85); };\n B.table_plant = (M, a) => { const K = kit(M, a), y = M.y || 0, pot = K.main(0xf0eee8);\n K.cyl('plain', 0, y, 0, 0.05, 0.08, pot); K.cyl('plain', 0, y + 0.08, 0, 0.045, 0.008, 0x3a2a1e); foliage(K, 0, y + 0.085, 0, 7, 0.07, 0.1, 0.2, 0.2, 0.9); };\n B.hanging_plant = (M, a) => { const K = kit(M, a), t = K.ceiling(), h = K.dim('hanging_plant').h, yp = t - h, pot = K.main(0xf0eee8), rope = K.accent(0xd8ccb0);\n K.box('metal', 0, t - 0.025, 0, 0.03, 0.025, 0.03, 0x8a8a8a); for (let i = 0; i < 3; i++) { const an = i * 2.09; K.box('fabric', Math.cos(an) * 0.08, yp + 0.12, Math.sin(an) * 0.08, 0.01, t - yp - 0.15, 0.01, rope); }\n K.cyl('plain', 0, yp, 0, 0.1, 0.14, pot); K.cyl('plain', 0, yp + 0.135, 0, 0.09, 0.01, 0x3a2a1e);\n for (let i = 0; i < 11; i++) { const an = i * 2.4, up = i < 3; K.leaf(Math.cos(an) * 0.06, yp + 0.14, Math.sin(an) * 0.06, 0.09, up ? 0.22 : 0.4 + K.rnd() * 0.3, green(K, i), an, up ? 0.5 : 2.3 + K.rnd() * 0.3); } };\n return B\n}\n","import type { BuilderContext, BuilderMap } from '../types'\nimport type { PropType } from '../catalog'\nimport { hex, shade } from '../colors'\nimport type { Kit } from '../types'\nimport { drawTv, pick } from './shared'\n\nexport function wallBuilders({ kit, atlas }: BuilderContext): Partial<BuilderMap> {\n const B: Partial<BuilderMap> = {}\n B.wall_ac = (M, a) => { const K = kit(M, a), { w, d, h } = K.dim('wall_ac'), y = M.y || 2.15;\n K.box('plain', 0, y, 0, w, h, d, 0xf0f0ee); K.box('plain', 0, y + h - 0.02, d * 0.1, w - 0.04, 0.02, d * 0.8, 0xe6e6e2); // curved cover\n K.box('plain', 0, y + 0.02, d / 2 - 0.02, w - 0.1, 0.035, 0.04, 0x30343a); K.box('plain', 0, y - 0.005, d / 2 - 0.03, w - 0.12, 0.012, 0.07, 0xe6e6e2, 0, 0.45); // slot and flap\n K.box('plain', w / 2 - 0.1, y + h - 0.1, d / 2 + 0.001, 0.05, 0.02, 0.004, 0x2a3a30); K.box('plain', -w / 2 + 0.01, y + 0.02, 0.0, 0.01, h - 0.04, d - 0.02, 0xdcdcd8); };\n const frame = (K: Kit, id: PropType, def: number, large: boolean) => { const { w, d, h } = K.dim(id), y = K.M.y || def, fr = Math.min(w, h) * 0.07 + 0.008, margin = large ? 0.05 : 0.035, A = atlas('picture'), idx = K.M.art != null ? K.M.art % 7 : Math.floor(K.rnd() * 7);\n const cm = K.color('picture_accent', pick(K, [0x4a3324, 0x1c1c1c, 0xe8e2d4, 0x8a6a44])); K.box('wood', 0, y, 0, w, h, d, K.M.color != null ? hex(K.M.color) : cm);\n K.box('plain', 0, y + fr, d / 2 + 0.0005, w - 2 * fr, h - 2 * fr, 0.004, 0xf4f1e8); K.plane('atlas_picture', 0, y + h / 2, d / 2 + 0.005, w - 2 * fr - 2 * margin, h - 2 * fr - 2 * margin, 0xffffff, 0, 0, 0, A.uv(idx)); };\n B.picture_small = (M, a) => frame(kit(M, a), 'picture_small', 1.3, false);\n B.picture_large = (M, a) => frame(kit(M, a), 'picture_large', 1.2, true);\n B.mirror = (M, a) => { const K = kit(M, a), { w, d, h } = K.dim('mirror'), y = M.y || 0.9, A = atlas('picture'), cm = K.color('metal', 0x3a3a3c);\n K.box('metal', 0, y, 0, w, h, d, M.color != null ? hex(M.color) : cm); K.plane('atlas_picture', 0, y + h / 2, d / 2 + 0.003, w - 0.05, h - 0.05, 0xffffff, 0, 0, 0, A.mirror()); };\n B.curtain = (M, a) => { const K = kit(M, a), { w, h } = K.dim('curtain'), y = M.y != null && M.y > 0 ? M.y : 0.1, color = K.fabric(pick(K, [0xd8cdb4, 0x9fb0be, 0xc5a88c, 0xe0dcd0])), isOpen = M.open !== false, top = y + h;\n K.box('metal', 0, top, 0, w + 0.1, 0.025, 0.025, K.metal(0x5a5048)); for (const s of [-1, 1]) K.cyl('metal', s * (w / 2 + 0.07), top - 0.02, 0, 0.03, 0.07, 0x5a5048, 0, 0, 'sphere');\n const pw = isOpen ? Math.min(0.5, w * 0.3) : w / 2 + 0.03, n = Math.max(4, Math.round(pw / 0.08));\n for (const s of [-1, 1]) for (let i = 0; i < n; i++) { const ux = isOpen ? s * (w / 2 + 0.03 - pw + (i + 0.5) * pw / n) : s * ((i + 0.5) * pw / n); K.box('fabric', ux, y, (i % 2 ? 0.025 : -0.01), pw / n * 1.15, h - 0.02, 0.02, i % 2 ? shade(color, 0.9) : color); }\n if (isOpen) for (const s of [-1, 1]) K.box('fabric', s * (w / 2 - pw * 0.25), y + h * 0.4, 0.04, pw * 0.5, 0.05, 0.02, shade(color, 0.7)); }; // tie-back\n B.blinds = (M, a) => { const K = kit(M, a), { w, h } = K.dim('blinds'), y = M.y || 1.0, retract = M.retracted != null ? M.retracted : 0.15, isWood = M.variant === 'wood', color = isWood ? K.wood(0x9a7a52) : K.color('wall_living', 0xe8e2d4), mat = isWood ? 'wood' : 'plain', yb = y + h * retract, n = Math.floor((y + h - yb) / 0.055);\n K.box('plain', 0, y + h - 0.05, 0, w, 0.05, 0.06, 0xdcd8d0); for (let i = 0; i < n; i++) K.box(mat, 0, y + h - 0.06 - (i + 1) * 0.055, 0.0, w - 0.05, 0.01, 0.035, color, 0, 0.3);\n for (const s of [-1, 1]) K.box('plain', s * (w / 2 - 0.05), yb, 0.02, 0.008, y + h - 0.05 - yb, 0.008, 0xb8b4ac); K.box('plain', 0, yb - 0.02, 0, w - 0.03, 0.025, 0.04, 0xdcd8d0); };\n B.flat_tv = (M, a) => { const K = kit(M, a), { w } = K.dim('flat_tv'); drawTv(K, 0, M.y != null && M.y > 0 ? M.y : 1.0, 0, w, false); };\n return B\n}\n","import type { BuilderContext, BuilderMap } from '../types'\nimport { hex, shade } from '../colors'\nimport { green, pick } from './shared'\n\nexport function yardBuilders({ kit, cover }: BuilderContext): Partial<BuilderMap> {\n const B: Partial<BuilderMap> = {}\n B.ac_condenser = (M, a) => { const K = kit(M, a), { w, d, h } = K.dim('ac_condenser'), y = M.y != null && M.y > 0 ? M.y : 0.5;\n for (const s of [-1, 1]) { K.box('metal', s * w * 0.32, y - 0.06, -d / 2 - 0.2, 0.04, 0.04, 0.3, 0x6a6a6a); K.box('metal', s * w * 0.32, y - 0.5 + 0.06, -d / 2 - 0.2 - 0.0, 0.035, 0.46, 0.035, 0x6a6a6a, 0, 0.0); }\n K.box('plain', 0, y, 0, w, h, d, 0xe8e8e4); K.box('plain', 0, y + h - 0.02, 0, w + 0.02, 0.025, d + 0.02, 0xd8d8d4);\n K.cyl('metal', -w * 0.12, y + h / 2, d / 2 + 0.004, 0.2, 0.012, 0x2a2a2e, Math.PI / 2, 0); K.cyl('metal', -w * 0.12, y + h / 2, d / 2 + 0.012, 0.085, 0.02, 0x4a4a4e, Math.PI / 2, 0);\n for (let i = 0; i < 4; i++) K.box('metal', -w * 0.12, y + h / 2 - 0.2, d / 2 + 0.018, 0.4, 0.008, 0.008, 0x8a8a8a, 0, 0, i * 0.785);\n for (let i = 0; i < 3; i++) K.cyl('metal', -w * 0.12, y + h / 2, d / 2 + 0.02, 0.07 + i * 0.043, 0.006, 0x7a7a7e, Math.PI / 2, 0);\n for (let i = 0; i < 6; i++) K.box('plain', w * 0.33, y + 0.06 + i * 0.075, d / 2 + 0.003, 0.14, 0.03, 0.006, 0xc4c4c0);\n K.cyl('metal', w / 2 - 0.05, y + 0.1, -d / 2 - 0.08, 0.012, 0.18, 0xb8733c, Math.PI / 2, 0); K.box('plain', w / 2 - 0.05, y + 0.06, -d / 2 - 0.02, 0.05, 0.12, 0.05, 0xe0e0dc); };\n B.pool = (M, a) => { const K = kit(M, a), { w, d } = K.dim('pool'), t = 0.32, bo = K.color('exterior_floor', 0xe8e4da);\n K.box('plain', 0, 0, -d / 2 - t / 2, w + 2 * t, 0.1, t, bo); K.box('plain', 0, 0, d / 2 + t / 2, w + 2 * t, 0.1, t, bo); for (const s of [-1, 1]) K.box('plain', s * (w / 2 + t / 2), 0, 0, t, 0.1, d, bo);\n cover(a, M, 'pool_tile', { w, d, y: 0.035, size: 1.0 });\n K.plane('water', 0, 0.075, 0, w, d, 0x8fd4ee, 0, -Math.PI / 2, 0);\n for (let i = 0; i < 3; i++) K.box('plain', w / 2 - 0.35 + i * 0.0, 0.035 + i * 0.01, d / 2 - 0.2 - i * 0.28, 0.7 - i * 0.05, 0.03, 0.26, 0xdfeef2);\n for (const s of [-1, 1]) { K.box('metal', -w / 4 + s * 0.2, 0.0, d / 2 + t * 0.6, 0.03, 0.85, 0.03, 0xc8ccd0); K.box('metal', -w / 4 + s * 0.2, 0.85, d / 2 + t * 0.6 - 0.1, 0.03, 0.03, 0.22, 0xc8ccd0); K.box('metal', -w / 4 + s * 0.2, 0.0, d / 2 - 0.25, 0.03, 0.88, 0.03, 0xc8ccd0, 0, 0.0); }\n for (let i = 0; i < 3; i++) K.box('metal', -w / 4, 0.02, d / 2 - 0.08 - i * 0.07, 0.4, 0.015, 0.05, 0xc8ccd0); };\n B.deck = (M, a) => { const K = kit(M, a), { w, d } = K.dim('deck'), h = 0.2, wood = K.wood(0x6a4a30);\n K.box('wood', 0, 0, 0, w - 0.05, h, d - 0.05, shade(wood, 0.7)); cover(a, M, 'deck_floor', { w, d, y: h + 0.012, size: 1.2, color: M.color });\n for (const [x, z, ww, dd] of [[0, -d / 2, w, 0.05], [0, d / 2, w, 0.05], [-w / 2, 0, 0.05, d], [w / 2, 0, 0.05, d]]) K.box('wood', x, 0, z, ww, h + 0.02, dd, wood);\n K.box('wood', 0, 0, d / 2 + 0.17, 1.4, 0.1, 0.34, wood); K.box('wood', 0, 0.1, d / 2 + 0.17, 1.4, 0.012, 0.34, shade(wood, 1.2)); };\n B.sun_lounger = (M, a) => { const K = kit(M, a), { w } = K.dim('sun_lounger'), fr = K.metal(0xe8e8e4), al = 0.95, cu = K.fabric(0x3a6a9a), stripe = K.accent(0xf0ece0);\n for (const s of [-1, 1]) { K.box('metal', s * (w / 2 - 0.03), 0.17, -0.3, 0.035, 0.035, 1.35, fr); K.box('metal', s * (w / 2 - 0.03), 0.0, 0.95, 0.035, 0.2, 0.035, fr); K.box('metal', s * (w / 2 - 0.03), 0.0, -0.3, 0.035, 0.2, 0.035, fr); K.cyl('plain', s * (w / 2 - 0.03), 0.07, -0.3, 0.07, 0.03, 0x2a2a2a, 0, Math.PI / 2); }\n K.box('fabric', 0, 0.21, 0.35, w - 0.1, 0.06, 1.3, cu); K.ramp('fabric', 0, 0.2, -0.3, w - 0.1, 0.06, 0.8, cu, al);\n for (let i = 0; i < 4; i++) { K.box('fabric', 0, 0.265, 0.0 + i * 0.3, w - 0.098, 0.004, 0.08, stripe); } K.ramp('metal', w / 2 - 0.03, 0.18, -0.3, 0.03, 0.03, 0.5, fr, al - 0.3); K.ramp('metal', -w / 2 + 0.03, 0.18, -0.3, 0.03, 0.03, 0.5, fr, al - 0.3); };\n B.garden_bed = (M, a) => { const K = kit(M, a), { w, d } = K.dim('garden_bed'), wood = K.wood(0x9a7048), hb = 0.3;\n for (const s of [-1, 1]) { K.box('wood', 0, 0, s * (d / 2 - 0.015), w, hb, 0.03, wood); K.box('wood', s * (w / 2 - 0.015), 0, 0, 0.03, hb, d - 0.06, shade(wood, 0.9)); }\n K.box('plain', 0, 0.02, 0, w - 0.06, hb - 0.05, d - 0.06, 0x3a2a1e);\n const lin = d > 0.8 ? 3 : 2, n = Math.max(3, Math.round(w / 0.4));\n for (let r = 0; r < lin; r++) for (let i = 0; i < n; i++) { const x = -w / 2 + (i + 0.5) * w / n, z = (r - (lin - 1) / 2) * 0.3;\n if (r === 0) { for (let j = 0; j < 6; j++) K.leaf(x, hb - 0.02, z, 0.11, 0.14, green(K, j) , j * 1.05, 0.9); }\n else if (r === 1) { K.box('wood', x, hb - 0.03, z, 0.015, 0.75, 0.015, 0x8a7048); K.cyl('plant', x, hb + 0.05, z, 0.1, 0.28, green(K, i), 0, 0, 'sphere'); K.cyl('plain', x + 0.05, hb + 0.18, z + 0.07, 0.03, 0.06, 0xc83030, 0, 0, 'sphere'); K.cyl('plain', x - 0.06, hb + 0.3, z + 0.05, 0.03, 0.06, 0xd04030, 0, 0, 'sphere'); }\n else { K.cyl('plant', x, hb - 0.02, z, 0.1, 0.17, 0x8ab05a, 0, 0, 'sphere'); for (let j = 0; j < 5; j++) K.leaf(x, hb, z, 0.14, 0.2, green(K, j + 1), j * 1.3, 1.0); } } };\n B.fruit_tree = (M, a) => { const K = kit(M, a), { w, h } = K.dim('fruit_tree'), fruit = M.fruit || pick(K, [0xe8801c, 0xe8a030, 0xb8c050, 0xc83030, 0xd8d040]), tr = K.wood(0x6a4a30);\n K.cyl('wood', 0, 0, 0, 0.13, h * 0.5, tr); K.box('wood', 0.2, h * 0.35, 0, 0.08, 0.6, 0.08, tr, 0, 0, -0.7); K.box('wood', -0.2, h * 0.35, 0.05, 0.08, 0.55, 0.08, tr, 0, 0, 0.7);\n const bl = [[0, h * 0.72, 0, 1.0], [0.55, h * 0.62, 0.2, 0.7], [-0.55, h * 0.64, -0.1, 0.72], [0.1, h * 0.6, -0.55, 0.65], [0.1, h * 0.9, 0.1, 0.6]];\n bl.forEach(([x, y, z, r], i) => K.cyl('plant', x * w / 2.4, y - r * 0.4, z * w / 2.4, r * w / 2.4, r * 1.5 * w / 2.4, green(K, i), 0, 0, 'sphere'));\n for (let i = 0; i < 16; i++) { const b = bl[i % 4], an = K.rnd() * 6.28, el = K.rnd() * 0.9, r = b[3] * w / 2.4 * 0.95; K.cyl('plain', b[0] * w / 2.4 + Math.cos(an) * r * Math.cos(el), b[1] * 1.0 - b[3] * 0.4 + Math.sin(el) * r * 0.5, b[2] * w / 2.4 + Math.sin(an) * r * Math.cos(el), 0.055, 0.11, fruit, 0, 0, 'sphere'); } };\n B.palm_tree = (M, a) => { const K = kit(M, a), { h } = K.dim('palm_tree'), tr = K.wood(0x8a7a5a), lean = 0.35, n = 9, sh = h * 0.78 / n; let x = 0, y = 0;\n for (let i = 0; i < n; i++) { const r = 0.14 - i * 0.006; K.cyl('wood', x, y, 0, r, sh, i % 2 ? tr : shade(tr, 0.82)); y += sh; x += lean * (2 * i + 1) / (n * n) * 1.2; }\n const top = y;\n for (let i = 0; i < 10; i++) { const an = i * 0.628 + K.rnd() * 0.2, t1 = 0.7 + K.rnd() * 0.4, L = 1.5, w = 0.5; K.leaf(x, top, 0, w, L, green(K, i), an, t1);\n const ex = x + Math.sin(t1) * Math.sin(an) * L, ey = top + Math.cos(t1) * L, ez = Math.sin(t1) * Math.cos(an) * L; K.leaf(ex, ey, ez, w * 0.7, 0.9, green(K, i + 1), an, t1 + 1.0); }\n for (let i = 0; i < 3; i++) K.cyl('wood', x + Math.cos(i * 2.1) * 0.14, top - 0.2, Math.sin(i * 2.1) * 0.14, 0.09, 0.2, 0x6a5a3a, 0, 0, 'sphere'); };\n B.pergola = (M, a) => { const K = kit(M, a), { w, d, h } = K.dim('pergola'), wood = M.variant === 'dark' ? shade(K.wood(0x6a4a30), 0.8) : K.color('exterior_floor', 0xe8e2d4), pc = M.color != null ? hex(M.color) : wood;\n for (const sx of [-1, 1]) for (const sz of [-1, 1]) K.box('wood', sx * (w / 2 - 0.1), 0, sz * (d / 2 - 0.1), 0.14, h, 0.14, pc);\n for (const sz of [-1, 1]) K.box('wood', 0, h - 0.04, sz * (d / 2 - 0.1), w + 0.2, 0.16, 0.08, pc); const n = Math.round(w / 0.4);\n for (let i = 0; i <= n; i++) K.box('wood', -w / 2 - 0.1 + i * (w + 0.2) / n, h + 0.12, 0, 0.06, 0.08, d + 0.3, shade(pc, 0.92));\n for (let i = 0; i < 9; i++) K.leaf(-w / 2 + 0.1 + (i % 2) * 0.06, 0.2 + i * 0.25, -d / 2 + 0.1, 0.2, 0.28, green(K, i), i * 1.7, 0.7); for (let i = 0; i < 7; i++) K.leaf(-w / 2 + 0.2 + i * 0.35, h + 0.2, -d / 4 + K.rnd() * 0.3, 0.22, 0.3, green(K, i), i * 2.0, 1.3); };\n B.slide = (M, a) => { const K = kit(M, a), { d, h } = K.dim('slide'), py = h * 0.8, pz = -d / 2 + 0.55, az = K.accent(0xe8c030), vm = K.main(0xc8403a), az2 = 0x3a6ab0;\n for (const sx of [-1, 1]) for (const sz of [-1, 1]) K.box('metal', sx * 0.3, 0, pz + sz * 0.3, 0.05, py, 0.05, az2);\n K.box('plain', 0, py, pz, 0.74, 0.05, 0.74, vm); for (const s of [-1, 1]) { K.box('plain', s * 0.35, py + 0.05, pz, 0.04, 0.42, 0.74, az); }\n K.box('plain', 0, py + 0.05, pz - 0.35, 0.74, 0.42, 0.04, az); const run = d / 2 - pz - 0.4, al = Math.atan2(py - 0.1, run);\n K.ramp('plain', 0, py, pz + 0.37, 0.5, 0.04, Math.hypot(run, py - 0.1) + 0.1, 0xd8d0c0, -al + 0.0 + 0); for (const s of [-1, 1]) K.ramp('plain', s * 0.27, py + 0.03, pz + 0.37, 0.04, 0.12, Math.hypot(run, py - 0.1) + 0.1, az, -al);\n for (const s of [-1, 1]) K.box('metal', s * 0.28, 0, pz - 0.45, 0.04, py + 0.1, 0.04, az2, 0, -0.1 + 0); for (let i = 0; i < 5; i++) K.box('metal', 0, 0.2 + i * (py - 0.2) / 5, pz - 0.46, 0.56, 0.03, 0.03, 0xc8ccd0); K.box('plain', 0, py + 0.4, pz, 0.8, 0.04, 0.8, vm); };\n B.swing = (M, a) => { const K = kit(M, a), { w, d, h } = K.dim('swing'), mt = K.color('metal', 0x3a6ab0), L = Math.hypot(h, d / 2), an = Math.atan2(d / 2, h);\n for (const sx of [-1, 1]) for (const sz of [-1, 1]) K.box('metal', sx * w / 2, h / 2 - L / 2 + 0.0, sz * d / 4, 0.07, L, 0.07, mt, 0, -sz * an, 0);\n K.box('metal', 0, h - 0.04, 0, w + 0.1, 0.1, 0.1, shade(mt, 0.85)); const cs = [K.accent(0xc8403a), 0x2a2a2a];\n for (let i = 0; i < 2; i++) { const x = (i - 0.5) * w * 0.45, sy = 0.5, sw = 0.46; for (const s of [-1, 1]) K.box('metal', x + s * (sw / 2 - 0.02), sy, 0, 0.012, h - 0.05 - sy, 0.012, 0xa0a4a8); K.box('plain', x, sy - 0.04, 0, sw, 0.045, 0.17, cs[i]); } };\n B.bbq_simple = (M, a) => { const K = kit(M, a), { w, d } = K.dim('bbq_simple'), br = K.color('exterior_floor', 0xb25a40), hb = 0.78;\n K.box('plain', 0, 0, 0, w, 0.45, d, br); for (const [x, z, ww, dd] of [[0, -d / 2 + 0.06, w, 0.12], [0, d / 2 - 0.06, w, 0.12], [-w / 2 + 0.06, 0, 0.12, d - 0.2], [w / 2 - 0.06, 0, 0.12, d - 0.2]]) K.box('plain', x, 0.45, z, ww, hb - 0.45, dd, br);\n K.box('plain', 0, 0.45, 0, w - 0.22, 0.04, d - 0.22, 0x2a2624); for (let i = 0; i < 10; i++) K.box('plain', (K.rnd() - 0.5) * (w - 0.3), 0.49, (K.rnd() - 0.5) * (d - 0.3), 0.08, 0.02, 0.07, i % 3 ? 0xc84a1a : 0x3a2a24, K.rnd() * 3);\n for (let i = 0; i < 7; i++) K.box('metal', -w / 2 + 0.16 + i * (w - 0.32) / 6, hb + 0.01, 0, 0.012, 0.012, d - 0.1, 0x5a5a5e); K.box('metal', 0, hb + 0.01, -d / 2 + 0.2, w - 0.1, 0.012, 0.02, 0x5a5a5e);\n for (let i = 0; i < 3; i++) { const z = (i - 1) * 0.15; K.cyl('metal', 0, hb + 0.05, z, 0.006, w + 0.12, 0xb0b4b8, 0, Math.PI / 2); for (let j = 0; j < 3; j++) K.cyl('plain', -w * 0.25 + j * w * 0.22, hb + 0.05, z, 0.035, 0.07, [0x8a3a2a, 0xa8483a, 0xd8b090][j], 0, Math.PI / 2); }\n for (let i = 0; i < 4; i++) K.cyl('wood', w / 2 + 0.2, 0.05 + (i > 2 ? 0.1 : 0), -0.1 + (i % 3) * 0.1, 0.04, 0.3, 0x8a6a44, 0, Math.PI / 2); };\n B.garage_car = (M, a) => { const K = kit(M, a), { w, d } = K.dim('garage_car'), c = K.main(pick(K, [0xa8aaac, 0xe8e8e6, 0x2a3a5a, 0xa83a34, 0x222426])), zf = d / 2;\n K.box('plain', 0, 0.26, 0, w, 0.5, d, c); K.box('plain', 0, 0.5, zf - 0.7, w - 0.04, 0.1, 1.4, shade(c, 1.04), 0, 0.04); K.box('plain', 0, 0.76, -zf + 0.3, w - 0.04, 0.1, 0.6, c);\n const cz = -0.35; for (const sx of [-1, 1]) for (const sz of [-1, 1]) K.box('plain', sx * (w / 2 - 0.1), 0.76, cz + sz * 0.8, 0.07, 0.5, 0.07, shade(c, 0.9)); K.box('plain', 0, 1.26, cz, w - 0.1, 0.05, 1.75, shade(c, 1.04));\n K.box('glass', 0, 0.76, cz, w - 0.06, 0.5, 1.6, 0xffffff); K.box('glass', 0, 0.76, cz + 0.8, w - 0.12, 0.5, 0.04, 0xffffff, 0, 0.5); for (const s of [-1, 1]) { K.box('plain', s * 0.4, 0.55, cz + 0.4, 0.4, 0.3, 0.4, 0x2a2a2e); K.box('plain', s * 0.4, 0.55, cz - 0.45, 0.4, 0.3, 0.4, 0x2a2a2e); }\n for (const sx of [-1, 1]) for (const sz of [-1, 1]) { K.cyl('plain', sx * (w / 2 - 0.1), 0.3, sz * 1.3, 0.3, 0.2, 0x1a1a1a, 0, Math.PI / 2); K.cyl('metal', sx * (w / 2 - 0.0), 0.3, sz * 1.3, 0.17, 0.02, 0xb8bcc0, 0, Math.PI / 2); }\n for (const s of [-1, 1]) { K.box('plain', s * 0.62, 0.5, zf - 0.02, 0.32, 0.12, 0.05, 0xf4f0d8); K.box('plain', s * 0.62, 0.52, -zf + 0.02, 0.3, 0.1, 0.05, 0xb02a24); K.box('plain', s * (w / 2 + 0.03), 0.9, cz + 0.55, 0.1, 0.1, 0.14, shade(c, 0.9)); }\n K.box('plain', 0, 0.2, zf - 0.01, w, 0.16, 0.06, 0x2a2a2a); K.box('plain', 0, 0.2, -zf + 0.01, w, 0.16, 0.06, 0x2a2a2a); K.box('plain', 0, 0.32, zf + 0.02, 0.5, 0.16, 0.02, 0x1c1c1c); K.box('plain', 0, 0.28, -zf - 0.015, 0.4, 0.12, 0.01, 0xf0e8c0); };\n B.gourmet_counter = (M, a) => { const K = kit(M, a), { w, d } = K.dim('gourmet_counter'), br = K.color('exterior_floor', 0xa8553c), zc = -d / 2 + 0.35, xa = -w / 2 + 0.8, xb = xa + 0.8 + 0.72, xc = xb + 0.72 + 0.65, wood = K.wood(0x8a5a38), gr = 0x4a4844, cab = K.color('wall_kitchen', 0xe8e4dc);\n K.box('plain', xa, 0, zc, 1.6, 0.85, 0.7, br); for (let i = 1; i < 4; i++) K.box('plain', xa, i * 0.2, zc + 0.351, 1.6, 0.012, 0.004, shade(br, 0.7)); K.box('plain', xa, 0.12, zc + 0.352, 0.7, 0.4, 0.004, 0x1a1612);\n for (const [x, z, ww, dd] of [[xa, zc - 0.25, 1.6, 0.2], [xa, zc + 0.3, 1.6, 0.1], [xa - 0.75, zc, 0.1, 0.7], [xa + 0.75, zc, 0.1, 0.7]]) K.box('plain', x, 0.85, z, ww, 0.12, dd, br);\n K.box('plain', xa, 0.85, zc + 0.02, 1.4, 0.025, 0.4, 0x2a2624); for (let i = 0; i < 8; i++) K.box('metal', xa - 0.62 + i * 0.18, 0.97, zc + 0.02, 0.012, 0.012, 0.4, 0x5a5a5e); for (let i = 0; i < 6; i++) K.box('plain', xa + (K.rnd() - 0.5) * 1.2, 0.88, zc + (K.rnd() - 0.5) * 0.3, 0.1, 0.02, 0.08, i % 2 ? 0xc84a1a : 0x3a2a24, K.rnd() * 3);\n K.box('plain', xa, 1.5, zc - 0.07, 1.5, 0.4, 0.56, br); K.box('plain', xa, 1.5, zc + 0.215, 1.5, 0.4, 0.01, 0x1a1612); K.box('plain', xa, 1.9, zc - 0.12, 0.62, 1.0, 0.46, br); K.box('plain', xa, 2.9, zc - 0.12, 0.76, 0.08, 0.6, shade(br, 0.8)); K.box('plain', xa, 2.98, zc - 0.12, 0.5, 0.06, 0.4, shade(br, 0.75));\n K.box('plain', xb, 0, zc, 1.44, 0.85, 0.7, cab); for (let i = 0; i < 3; i++) K.box('wood', xb - 0.48 + i * 0.48, 0.08, zc + 0.355, 0.44, 0.7, 0.012, wood); K.box('plain', (xb + xc) / 2, 0.85, zc, 0.72 * 2 + 0.65 + 0.04, 0.04, 0.74, gr);\n K.box('metal', xb, 0.89, zc, 0.5, 0.01, 0.38, 0xb0b4b8); K.box('metal', xb, 0.895, zc, 0.44, 0.006, 0.32, 0x70767a); K.cyl('metal', xb, 0.89, zc - 0.28, 0.014, 0.3, 0xb8bcc0); K.box('metal', xb, 1.17, zc - 0.2, 0.02, 0.02, 0.11, 0xb8bcc0);\n K.box('plain', xc, 0, zc, 1.3, 0.85, 0.7, cab); for (let i = 0; i < 2; i++) K.box('wood', xc - 0.32 + i * 0.64, 0.08, zc + 0.355, 0.6, 0.7, 0.012, wood);\n K.cyl('plain', xc, 0.89, zc, 0.1, 0.05, 0xf0f0ea); K.cyl('plain', xc + 0.4, 0.89, zc, 0.04, 0.26, 0x2a6a3a);\n const tz = 0.55, tl = Math.min(2.6, w * 0.65); K.box('wood', 0, 0.74, tz, tl, 0.05, 0.85, wood); for (const s of [-1, 1]) { K.box('wood', s * (tl / 2 - 0.2), 0, tz, 0.08, 0.74, 0.7, shade(wood, 0.8)); K.box('wood', s * (tl / 2 - 0.2), 0.3, tz - 0.001, 0.0 + 0.6, 0.04, 0.05, shade(wood, 0.75)); }\n for (const s of [-1, 1]) { K.box('wood', 0, 0.42, tz + s * 0.72, tl - 0.2, 0.04, 0.3, shade(wood, 1.1)); for (const sx of [-1, 1]) K.box('wood', sx * (tl / 2 - 0.4), 0, tz + s * 0.72, 0.06, 0.42, 0.26, shade(wood, 0.8)); }\n K.cyl('plain', 0.3, 0.79, tz, 0.15, 0.08, 0xd8d0c0); K.cyl('plain', -0.5, 0.79, tz + 0.1, 0.035, 0.26, 0x2a6a3a); for (let i = 0; i < 3; i++) K.cyl('plain', -0.9 + i * 0.2, 0.79, tz - 0.2, 0.035, 0.1, 0xe8e4d8); };\n B.sauna = (M, a) => { const K = kit(M, a), { w, d, h } = K.dim('sauna'), t = 0.08, wood = K.wood(0xc08a54), shade1 = shade(wood, 0.88), dw = 0.7, dx = w / 2 - 0.55;\n K.box('wood', 0, 0, 0, w, 0.05, d, shade(wood, 0.75)); K.box('wood', 0, 0.05, -d / 2 + t / 2, w, h - 0.11, t, wood); for (const s of [-1, 1]) K.box('wood', s * (w / 2 - t / 2), 0.05, 0, t, h - 0.11, d - 2 * t * 0 , wood);\n K.box('wood', 0, h - 0.06, 0, w + 0.12, 0.06, d + 0.12, shade(wood, 0.75));\n const lx0 = -w / 2, lx1 = dx - dw / 2; K.box('wood', (lx0 + lx1) / 2, 0.05, d / 2 - t / 2, lx1 - lx0, h - 0.11, t, wood); K.box('wood', (dx + dw / 2 + w / 2) / 2, 0.05, d / 2 - t / 2, w / 2 - (dx + dw / 2), h - 0.11, t, wood); K.box('wood', dx, 1.85, d / 2 - t / 2, dw, h - 0.11 - 1.8, t, wood);\n for (let i = 0; i < 12; i++) { const x = lx0 + 0.1 + i * (lx1 - lx0) / 12; K.box('wood', x, 0.05, d / 2 + 0.003, 0.012, h - 0.11, 0.005, shade(wood, 0.6)); }\n K.box('wood', dx - dw / 2 - 0.025, 0.05, d / 2 - 0.02, 0.05, 1.82, 0.06, shade1); K.box('wood', dx + dw / 2 + 0.025, 0.05, d / 2 - 0.02, 0.05, 1.82, 0.06, shade1); K.box('glass', dx, 0.06, d / 2 - 0.02, dw, 1.75, 0.02, 0xffffff); K.box('metal', dx - dw / 2 + 0.08, 0.7, d / 2 + 0.03, 0.02, 0.5, 0.03, 0xc8ccd0);\n K.box('wood', 0, 0.85, -d / 2 + t + 0.25, w - 2 * t, 0.05, 0.5, shade(wood, 1.1)); K.box('wood', 0, 0.45, -d / 2 + t + 0.65, w - 2 * t, 0.05, 0.4, shade(wood, 1.1)); K.box('wood', 0, 0.05, -d / 2 + t + 0.1, w - 2 * t, 0.8, 0.04, shade(wood, 0.8));\n K.cyl('metal', -w / 2 + 0.3, 0.05, d / 2 - 0.4, 0.14, 0.55, 0x2a2a2e); for (let i = 0; i < 5; i++) K.cyl('plain', -w / 2 + 0.3 + Math.cos(i * 1.3) * 0.06, 0.6, d / 2 - 0.4 + Math.sin(i * 1.3) * 0.06, 0.04, 0.07, 0x6a6a6a, 0, 0, 'sphere');\n K.box('plain', 0, h - 0.2, -d / 2 + t + 0.02, 0.4, 0.06, 0.04, 0xfff0c8); K.box('emissive', 0, h - 0.19, -d / 2 + t + 0.045, 0.34, 0.01, 0.006, 0xffe0a0); };\n B.soaking_tub = (M, a) => { const K = kit(M, a), { w } = K.dim('soaking_tub'), r = Math.min(0.62, w * 0.48), wood = K.wood(0xa8784a);\n K.cyl('wood', 0, 0, 0, r, 0.78, wood, 0, 0, 'cyl'); K.cyl('wood', 0, 0.76, 0, r + 0.025, 0.04, shade(wood, 1.15)); for (const y of [0.15, 0.5]) K.cyl('metal', 0, y, 0, r + 0.012, 0.03, 0x2a2a2e);\n K.cyl('water', 0, 0.74, 0, r - 0.04, 0.01, 0x9ad4e8); for (let i = 0; i < 8; i++) K.box('wood', Math.cos(i * 0.785) * (r + 0.001), 0.02, Math.sin(i * 0.785) * (r + 0.001), 0.012, 0.74, 0.12, shade(wood, 0.7), -i * 0.785 + 0);\n K.box('wood', 0, 0, r + 0.4, 0.5, 0.3, 0.34, shade(wood, 0.9)); K.cyl('wood', 0.2, 0.3, r + 0.4, 0.1, 0.14, shade(wood, 1.1)); K.box('wood', -0.1, 0.34, r + 0.4, 0.3, 0.02, 0.025, shade(wood, 1.1), 0.5); K.box('fabric', -0.1, 0.3, r + 0.42, 0.26, 0.03, 0.2, K.accent(0xf0ece0)); };\n return B\n}\n","import { hex, mix, rng, seedOf } from './colors'\nimport type { AtlasMap, CoverOptions, FloorKind, PropItem, PropsApi, Uv } from './types'\n\n/** Default height of each floor kind above the ground. */\nconst HEIGHTS: Record<FloorKind, number> = { lawn: 0.02, dirt: 0.025, concrete: 0.03, tile_floor: 0.035, deck_floor: 0.04, pool_tile: 0.04, paving: 0.035 }\n\nconst inside = (poly: Array<[number, number]>, x: number, z: number): boolean => {\n let in_ = false\n for (let i = 0, j = poly.length - 1; i < poly.length; j = i++) {\n const [xi, zi] = poly[i]\n const [xj, zj] = poly[j]\n if (zi > z !== zj > z && x < ((xj - xi) * (z - zi)) / (zj - zi) + xi) in_ = !in_\n }\n return in_\n}\n\n/**\n * Covers a rectangle centered on M (w x d) or a polygon `[[x, z], ...]` in local coordinates with floor tiles:\n * one atlas square per cell (repeats and tiles); the polygon uses cells of a quarter of the size.\n */\nexport function createCover(atlas: <K extends 'floor'>(name: K) => AtlasMap[K]) {\n return function cover(api: PropsApi, M: PropItem, kind: FloorKind, o: CoverOptions = {}): void {\n const A = atlas('floor')\n const size = o.size || A.size(kind)\n const nv = A.variants(kind)\n const y = o.y != null ? o.y : HEIGHTS[kind] || 0.03\n const color = o.color != null ? hex(o.color) : 0xffffff\n const poly = o.poly || M.poly\n const sd = seedOf(M)\n const rnd = rng(sd)\n const tint = () => {\n const v = 0.93 + rnd() * 0.07\n return mix(0x000000, color, v)\n }\n const quad = (cx: number, cz: number, qw: number, qd: number, uv: Uv) => api.plane(M, 'atlas_floor', cx, y, cz, qw, qd, tint(), 0, -Math.PI / 2, 0, uv)\n if (!poly) {\n const w = o.w || M.w || 4\n const d = o.d || M.d || 4\n for (let j = 0, v = 0; v < d - 1e-6; j++, v += size)\n for (let i = 0, u = 0; u < w - 1e-6; i++, u += size) {\n const qw = Math.min(size, w - u)\n const qd = Math.min(size, d - v)\n const b = A.uv(kind, (i * 7 + j * 13 + sd) % nv)\n const uv = { u0: b.u0, u1: b.u0 + ((b.u1 - b.u0) * qw) / size, v1: b.v1, v0: b.v1 - ((b.v1 - b.v0) * qd) / size }\n quad(-w / 2 + u + qw / 2, -d / 2 + v + qd / 2, qw, qd, uv)\n }\n return\n }\n let x0 = 1e9\n let z0 = 1e9\n let x1 = -1e9\n let z1 = -1e9\n for (const [x, z] of poly) {\n x0 = Math.min(x0, x)\n x1 = Math.max(x1, x)\n z0 = Math.min(z0, z)\n z1 = Math.max(z1, z)\n }\n const st = size / 4\n for (let j = 0; z0 + j * st < z1; j++)\n for (let i = 0; x0 + i * st < x1; i++) {\n const cx = x0 + (i + 0.5) * st\n const cz = z0 + (j + 0.5) * st\n if (!inside(poly, cx, cz)) continue\n const b = A.uv(kind, (((i >> 2) * 7 + (j >> 2) * 13 + sd) % nv))\n const du = (b.u1 - b.u0) / 4\n const dv = (b.v1 - b.v0) / 4\n const ui = i & 3\n const vj = j & 3\n quad(cx, cz, st, st, { u0: b.u0 + ui * du, u1: b.u0 + (ui + 1) * du, v1: b.v1 - vj * dv, v0: b.v1 - (vj + 1) * dv })\n }\n }\n}\n","import { DEFS } from './catalog'\nimport { hex, rng, seedOf } from './colors'\nimport type { EmitFn, Kit, PropItem, PropsApi } from './types'\n\n/** Shortcuts that fix `M` and the api, so builders read as a list of primitives. */\nexport function makeKit(M: PropItem, api: PropsApi, emit: EmitFn): Kit {\n const role = (name: string): number | null => {\n const v = M.palette && M.palette[name]\n return v != null ? hex(v) : null\n }\n const K: Kit = {\n M,\n api,\n rnd: rng(seedOf(M)),\n box: (material, x, y, z, w, h, d, color, ry, rx, rz) => api.box(M, material, x, y, z, w, h, d, hex(color), ry || 0, rx || 0, rz || 0),\n cyl: (material, x, y, z, r, h, color, rx, rz, shape) => api.cylinder(M, material, x, y, z, r, h, hex(color), rx || 0, rz || 0, shape),\n leaf: (x, y, z, w, h, color, ry, rx) => api.leaf(M, x, y, z, w, h, hex(color), ry || 0, rx || 0),\n plane: (material, x, y, z, w, h, color, ry, rx, rz, uv) => api.plane(M, material, x, y, z, w, h, hex(color), ry || 0, rx || 0, rz || 0, uv),\n light: (x, y, z, color, range, kind) => {\n if (api.light) api.light(M, x, y, z, hex(color), range, kind)\n else emit('light', { M, x, y, z, color: hex(color), range, kind })\n },\n // colours: role in the house palette (M.palette) or the default; main = M.color\n color: (name, fallback) => role(name) ?? hex(fallback),\n main: (fallback) => (M.color != null ? hex(M.color) : hex(fallback)),\n fabric: (fallback) => (M.color != null ? hex(M.color) : (role('fabric_main') ?? hex(fallback))),\n accent: (fallback) => role('fabric_accent') ?? hex(fallback),\n wood: (fallback) => role('wood') ?? hex(fallback),\n metal: (fallback) => role('metal') ?? hex(fallback),\n dim: (id) => {\n const t = DEFS[id]\n return { w: M.w || t.w, d: M.d || t.d, h: M.h || t.h }\n },\n ceiling: () => M.ceiling || 2.9,\n // long tilted box: starts at (x, y, z) and follows u = (0, sin a, -cos a) for L meters\n ramp(material, x, y, z, w, t, L, color, alpha) {\n const cy = y + (Math.sin(alpha) * L) / 2\n const cz = z - (Math.cos(alpha) * L) / 2\n K.box(material, x, cy - t / 2, cz, w, t, L, color, 0, alpha + Math.PI, 0)\n },\n }\n return K\n}\n","import type { PropType } from './catalog'\n\n/** Locales shipped with the package. Unknown locales fall back to `en`. */\nexport type PropsLocale = 'en' | 'pt-BR'\n\nexport interface PropsStrings {\n /** Display name of each prop type. */\n typeNames: Record<PropType, string>\n /** Names of the picture atlas cells (4 abstract, 3 landscapes, the mirror). */\n pictureNames: string[]\n}\n\nexport const locales: Record<PropsLocale, PropsStrings> = {\n en: {\n typeNames: {\n ceiling_light: \"Ceiling light\",\n pendant: \"Pendant lamp\",\n track_spot: \"Track spot\",\n chandelier: \"Chandelier\",\n wall_ac: \"Indoor AC unit (split)\",\n picture_small: \"Small picture\",\n picture_large: \"Large picture\",\n mirror: \"Mirror\",\n curtain: \"Curtain\",\n blinds: \"Blinds\",\n flat_tv: \"Flat TV\",\n floor_plant: \"Floor plant\",\n table_plant: \"Table plant\",\n hanging_plant: \"Hanging plant\",\n tv_stand: \"TV stand with flat TV\",\n breakfast_bar: \"Breakfast bar\",\n sofa_l: \"L-shaped sofa\",\n double_bed_modern: \"Modern double bed\",\n home_office: \"Home office\",\n closet: \"Closet\",\n vanity: \"Bathroom vanity\",\n ac_condenser: \"AC condenser\",\n lawn: \"Lawn\",\n tile_floor: \"Ceramic tile floor\",\n concrete: \"Concrete slab\",\n deck_floor: \"Deck (flooring)\",\n dirt: \"Packed dirt\",\n gourmet_counter: \"Gourmet counter\",\n sauna: \"Sauna\",\n soaking_tub: \"Soaking tub\",\n pool: \"Pool\",\n deck: \"Raised deck\",\n sun_lounger: \"Sun lounger\",\n garden_bed: \"Vegetable garden bed\",\n fruit_tree: \"Fruit tree\",\n palm_tree: \"Palm tree\",\n pergola: \"Pergola\",\n slide: \"Slide\",\n swing: \"Swing\",\n bbq_simple: \"Simple barbecue\",\n garage_car: \"Car\",\n window_boards: \"Boards on the window\",\n barricade: \"Barricade\",\n sandbags: \"Sandbags\",\n barbed_wire: \"Barbed wire\",\n razor_wire: \"Razor wire\",\n water_bottle_crates: \"Mineral water crates\",\n canned_food: \"Canned food\",\n water_jug: \"Water jug\",\n floor_mattress: \"Mattress on the floor\",\n lantern: \"Lantern\",\n candles: \"Candles\",\n open_suitcases: \"Open suitcases\",\n clothes_on_floor: \"Clothes on the floor\",\n fallen_chair: \"Fallen chair\",\n blood_stains: \"Blood stains\",\n open_door: \"Open door\",\n },\n pictureNames: ['warm abstract', 'blue abstract', 'color blocks', 'minimal', 'sunset', 'mountains and lake', 'beach with palm tree', 'mirror'],\n },\n 'pt-BR': {\n typeNames: {\n ceiling_light: \"Plafon\",\n pendant: \"Pendente\",\n track_spot: \"Spot de trilho\",\n chandelier: \"Lustre\",\n wall_ac: \"Split interno\",\n picture_small: \"Quadro pequeno\",\n picture_large: \"Quadro grande\",\n mirror: \"Espelho\",\n curtain: \"Cortina\",\n blinds: \"Persiana\",\n flat_tv: \"TV plana\",\n floor_plant: \"Vaso de chão\",\n table_plant: \"Vaso de mesa\",\n hanging_plant: \"Planta pendente\",\n tv_stand: \"Rack com TV plana\",\n breakfast_bar: \"Bancada americana\",\n sofa_l: \"Sofá em L\",\n double_bed_modern: \"Cama de casal moderna\",\n home_office: \"Home office\",\n closet: \"Closet\",\n vanity: \"Lavabo\",\n ac_condenser: \"Condensadora\",\n lawn: \"Gramado\",\n tile_floor: \"Piso cerâmico\",\n concrete: \"Cimentado\",\n deck_floor: \"Deck (piso)\",\n dirt: \"Terra batida\",\n gourmet_counter: \"Bancada gourmet\",\n sauna: \"Sauna\",\n soaking_tub: \"Ofurô\",\n pool: \"Piscina\",\n deck: \"Deck elevado\",\n sun_lounger: \"Espreguiçadeira\",\n garden_bed: \"Canteiro de horta\",\n fruit_tree: \"Árvore frutífera\",\n palm_tree: \"Palmeira\",\n pergola: \"Pergolado\",\n slide: \"Escorregador\",\n swing: \"Balanço\",\n bbq_simple: \"Churrasqueira simples\",\n garage_car: \"Carro\",\n window_boards: \"Tábuas na janela\",\n barricade: \"Barricada\",\n sandbags: \"Sacos de areia\",\n barbed_wire: \"Arame farpado\",\n razor_wire: \"Concertina\",\n water_bottle_crates: \"Caixas de água mineral\",\n canned_food: \"Enlatados\",\n water_jug: \"Galão de água\",\n floor_mattress: \"Colchão no chão\",\n lantern: \"Lanterna\",\n candles: \"Velas\",\n open_suitcases: \"Malas abertas\",\n clothes_on_floor: \"Roupas no chão\",\n fallen_chair: \"Cadeira caída\",\n blood_stains: \"Manchas de sangue\",\n open_door: \"Porta aberta\",\n },\n pictureNames: ['abstrato quente', 'abstrato azul', 'blocos de cor', 'minimal', 'pôr do sol', 'montanhas e lago', 'praia com coqueiro', 'espelho'],\n },\n}\n\nexport const resolveStrings = (locale?: string): PropsStrings => locales[locale as PropsLocale] ?? locales.en\n","import { createAtlasProvider } from './atlas'\nimport { DEFS, MATERIALS, TYPE_DEFS, type PropType } from './catalog'\nimport { ceilingBuilders } from './builders/ceiling'\nimport { floorBuilders } from './builders/floors'\nimport { furnitureBuilders } from './builders/furniture'\nimport { houseStateBuilders } from './builders/house-state'\nimport { plantBuilders } from './builders/plants'\nimport { wallBuilders } from './builders/wall'\nimport { yardBuilders } from './builders/yard'\nimport { createCover } from './cover'\nimport { makeKit } from './kit'\nimport { resolveStrings } from './locale'\nimport type { BuilderContext, BuilderMap, DocumentLike, EmitFn, Props3d, Props3dOptions, TypeInfo } from './types'\n\n/** Type metadata with display names for a locale (`en` by default). */\nexport function listTypes(locale?: string): TypeInfo[] {\n const names = resolveStrings(locale).typeNames\n return TYPE_DEFS.map((t) => ({ ...t, name: names[t.id] }))\n}\n\n/**\n * Creates the props kit. Builders only describe primitives through the `api` you pass to them; nothing here touches a renderer.\n *\n * `three` is accepted so the call looks like the other game-kit packages, but the props never use it.\n *\n * ```ts\n * const props = create(THREE, { document })\n * props.builders.sofa_l({ w: 2.8, d: 1.7, h: 0.85, seed: 'living' }, api)\n * ```\n */\nexport function create(_three?: unknown, options: Props3dOptions = {}): Props3d {\n const emit: EmitFn = options.emit || (() => {})\n const doc: DocumentLike | null = options.document || (typeof document !== 'undefined' ? document : null)\n const strings = resolveStrings(options.locale)\n const atlas = createAtlasProvider(doc, strings.pictureNames)\n const cover = createCover(atlas)\n const ctx: BuilderContext = { kit: (M, api) => makeKit(M, api, emit), atlas, cover }\n const builders = Object.assign(\n {},\n ceilingBuilders(ctx),\n wallBuilders(ctx),\n plantBuilders(ctx),\n furnitureBuilders(ctx),\n floorBuilders(ctx),\n yardBuilders(ctx),\n houseStateBuilders(ctx),\n ) as BuilderMap\n return {\n builders,\n types: listTypes(options.locale),\n names: Object.keys(builders) as PropType[],\n atlas,\n cover,\n materials: MATERIALS,\n }\n}\n\nexport { DEFS, MATERIALS, TYPE_DEFS }\n","import type * as ThreeNamespace from 'three'\n\ntype Three = typeof ThreeNamespace\n\n/** What `createNodeSkin` makes: one mesh that stands for a whole tree of meshes, each vertex tied to the node of the tree that moves it. */\nexport type NodeSkin = {\n readonly mesh: ThreeNamespace.Mesh\n /** The nodes the animation moves, in the order of the skin's `aNodeIndex`. */\n readonly nodes: readonly ThreeNamespace.Object3D[]\n /** The matrix of each node, uploaded as the `uNodes` uniform. */\n readonly matrices: { readonly value: ThreeNamespace.Matrix4[] }\n /** Copies the world matrix of every node into `matrices`: call it once per frame, after the tree was animated. */\n update(): void\n}\n\nexport type NodeSkinOptions = {\n /** Meshes the animation moves and that therefore stay nodes of their own (a head ball, an eye). Groups and meshes with children are always nodes. */\n readonly nodes?: Iterable<ThreeNamespace.Object3D>\n}\n\nconst MAX_WALK_DEPTH = 3\n\n/**\n * Every Object3D reachable from the fields of `owner` (up to 3 levels, skipping the keys in `skip`): what the animation of a tree keeps in its own\n * state (head, jaw, wings, legs). Pass the result as `nodes` so those meshes are not merged into their parents.\n */\nexport const collectReferencedNodes = (owner: object, skip: readonly string[] = []): Set<ThreeNamespace.Object3D> => {\n const found = new Set<ThreeNamespace.Object3D>()\n const seen = new Set<unknown>()\n const walk = (value: unknown, depth: number): void => {\n if (!value || typeof value !== 'object' || depth > MAX_WALK_DEPTH || seen.has(value)) return\n seen.add(value)\n const candidate = value as { isObject3D?: boolean; isMaterial?: boolean; isBufferGeometry?: boolean }\n if (candidate.isObject3D) {\n found.add(value as ThreeNamespace.Object3D)\n return\n }\n if (candidate.isMaterial || candidate.isBufferGeometry) return\n for (const key in value) walk((value as Record<string, unknown>)[key], depth + 1)\n }\n for (const key in owner) if (!skip.includes(key)) walk((owner as Record<string, unknown>)[key], 0)\n return found\n}\n\ntype TextureSample = { readonly data: Uint8ClampedArray; readonly width: number; readonly height: number }\n\nconst isVisibleInTree = (object: ThreeNamespace.Object3D): boolean => {\n for (let node: ThreeNamespace.Object3D | null = object; node; node = node.parent) if (!node.visible) return false\n return true\n}\n\n/**\n * A GPU \"node skin\": a tree of about fifty meshes (an animal, a character prop) merged into one mesh, every vertex tied to the node that moves it.\n * The tree stays out of the scene and keeps animating; `update()` copies its node matrices each frame. Colour (with the texture sampled at the uv),\n * roughness, metalness and emissive are baked per vertex, so the 40 animals of a scene cost 40 draw calls instead of 2,000.\n * Generalised from the game's `bichoPele` (G 66536); the colours are read the way r160 does (linear converted to sRGB), as the game does.\n */\nexport const createNodeSkin = (THREE: Three, root: ThreeNamespace.Object3D, options: NodeSkinOptions = {}): NodeSkin => {\n const referenced = new Set(options.nodes ?? [])\n const nodes: ThreeNamespace.Object3D[] = []\n const indexOf = new Map<ThreeNamespace.Object3D, number>()\n root.traverse((object) => {\n const mesh = object as ThreeNamespace.Mesh\n if (!mesh.isMesh || object.children.length > 0 || referenced.has(object)) {\n indexOf.set(object, nodes.length)\n nodes.push(object)\n }\n })\n\n const positions: number[] = []\n const normals: number[] = []\n const tints: number[] = []\n const surfaces: number[] = []\n const nodeIndices: number[] = []\n const samples = new Map<ThreeNamespace.Texture, TextureSample>()\n const color = new THREE.Color()\n const vertex = new THREE.Vector3()\n const normal = new THREE.Vector3()\n\n const sampleOf = (texture: ThreeNamespace.Texture): TextureSample | undefined => {\n const image = texture.image as { getContext?: (kind: string) => CanvasRenderingContext2D | null; width: number; height: number } | undefined\n if (!image?.getContext) return undefined\n const cached = samples.get(texture)\n if (cached) return cached\n const context = image.getContext('2d')\n if (!context) return undefined\n const sample = { data: context.getImageData(0, 0, image.width, image.height).data, width: image.width, height: image.height }\n samples.set(texture, sample)\n return sample\n }\n\n root.traverse((object) => {\n const mesh = object as ThreeNamespace.Mesh\n if (!mesh.isMesh || !isVisibleInTree(object)) return\n const material = (Array.isArray(mesh.material) ? mesh.material[0] : mesh.material) as ThreeNamespace.MeshStandardMaterial\n const geometry = mesh.geometry\n const position = geometry.attributes.position as ThreeNamespace.BufferAttribute\n const normalAttribute = geometry.attributes.normal as ThreeNamespace.BufferAttribute | undefined\n const uv = geometry.attributes.uv as ThreeNamespace.BufferAttribute | undefined\n const matrix = new THREE.Matrix4()\n let nodeIndex = indexOf.get(object)\n if (nodeIndex === undefined) {\n nodeIndex = indexOf.get(object.parent as ThreeNamespace.Object3D) ?? 0\n object.updateMatrix()\n matrix.copy(object.matrix)\n }\n const normalMatrix = new THREE.Matrix3().getNormalMatrix(matrix)\n const sample = material.map ? sampleOf(material.map) : undefined\n const emissive = material.emissive ? (material.emissive.r + material.emissive.g + material.emissive.b) * (material.emissiveIntensity ?? 1) : 0\n const index = geometry.index ? geometry.index.array : null\n const count = index ? index.length : position.count\n for (let item = 0; item < count; item++) {\n const at = index ? (index[item] as number) : item\n vertex.fromBufferAttribute(position, at).applyMatrix4(matrix)\n positions.push(vertex.x, vertex.y, vertex.z)\n if (normalAttribute) normal.fromBufferAttribute(normalAttribute, at).applyMatrix3(normalMatrix).normalize()\n else normal.set(0, 1, 0)\n normals.push(normal.x, normal.y, normal.z)\n color.copy(material.color || color.set(1, 1, 1)).convertLinearToSRGB()\n if (sample && uv && material.map) {\n const repeat = material.map.repeat\n const u = (((uv.getX(at) * repeat.x) % 1) + 1) % 1\n const v = (((uv.getY(at) * repeat.y) % 1) + 1) % 1\n const pixelX = Math.min(sample.width - 1, (u * sample.width) | 0)\n const pixelY = Math.min(sample.height - 1, ((1 - v) * sample.height) | 0)\n const offset = (pixelY * sample.width + pixelX) * 4\n color.multiply(new THREE.Color().setRGB((sample.data[offset] as number) / 255, (sample.data[offset + 1] as number) / 255, (sample.data[offset + 2] as number) / 255, THREE.SRGBColorSpace))\n }\n if (emissive > 0.3) color.lerp(material.emissive, 0.7)\n tints.push(color.r, color.g, color.b)\n surfaces.push(material.roughness ?? 0.8, material.metalness ?? 0, emissive > 0.3 ? 1 : 0)\n nodeIndices.push(nodeIndex)\n }\n })\n\n const geometry = new THREE.BufferGeometry()\n geometry.setAttribute('position', new THREE.Float32BufferAttribute(positions, 3))\n geometry.setAttribute('normal', new THREE.Float32BufferAttribute(normals, 3))\n geometry.setAttribute('aTint', new THREE.Float32BufferAttribute(tints, 3))\n geometry.setAttribute('aSurface', new THREE.Float32BufferAttribute(surfaces, 3))\n geometry.setAttribute('aNodeIndex', new THREE.Float32BufferAttribute(nodeIndices, 1))\n geometry.computeBoundingSphere()\n\n const matrices = { value: nodes.map(() => new THREE.Matrix4()) }\n const skinVertex = (shader: ThreeNamespace.WebGLProgramParametersWithUniforms): void => {\n shader.uniforms.uNodes = matrices\n shader.vertexShader = shader.vertexShader\n .replace(\n '#include <common>',\n `#include <common>\\nuniform mat4 uNodes[${nodes.length}]; attribute float aNodeIndex; attribute vec3 aTint; attribute vec3 aSurface; varying vec3 vTint; varying vec3 vSurface;`,\n )\n .replace('#include <beginnormal_vertex>', 'vec3 objectNormal = mat3(uNodes[int(aNodeIndex + .5)]) * normal;')\n .replace('#include <begin_vertex>', 'vec3 transformed = (uNodes[int(aNodeIndex + .5)] * vec4(position, 1.)).xyz; vTint = aTint; vSurface = aSurface;')\n }\n\n const material = new THREE.MeshStandardMaterial({ roughness: 1, metalness: 0 })\n material.onBeforeCompile = (shader) => {\n skinVertex(shader)\n shader.fragmentShader = shader.fragmentShader\n .replace('#include <common>', '#include <common>\\nvarying vec3 vTint; varying vec3 vSurface;')\n .replace('vec4 diffuseColor = vec4( diffuse, opacity );', 'vec4 diffuseColor = vec4( vTint, opacity );')\n .replace('#include <roughnessmap_fragment>', 'float roughnessFactor = vSurface.x;')\n .replace('#include <metalnessmap_fragment>', 'float metalnessFactor = vSurface.y;')\n .replace('#include <emissivemap_fragment>', 'totalEmissiveRadiance = vTint * vSurface.z * 1.5;')\n }\n material.customProgramCacheKey = () => `nodeSkin${nodes.length}`\n const depthMaterial = new THREE.MeshDepthMaterial({ depthPacking: THREE.RGBADepthPacking })\n depthMaterial.onBeforeCompile = skinVertex\n depthMaterial.customProgramCacheKey = () => `nodeSkinDepth${nodes.length}`\n\n const mesh = new THREE.Mesh(geometry, material)\n mesh.customDepthMaterial = depthMaterial\n mesh.frustumCulled = false\n root.updateMatrixWorld(true)\n return {\n mesh,\n nodes,\n matrices,\n update() {\n root.updateMatrixWorld(true)\n for (let index = 0; index < nodes.length; index++) (matrices.value[index] as ThreeNamespace.Matrix4).copy((nodes[index] as ThreeNamespace.Object3D).matrixWorld)\n },\n }\n}\n","import type { Primitive, PropsApi } from './types'\n\n/**\n * An api that records every primitive instead of drawing it. Handy for tests, previews and for measuring a prop.\n *\n * ```ts\n * const { api, primitives } = createRecorder()\n * props.builders.sofa_l(item, api)\n * console.log(primitives.length)\n * ```\n * Pass `{ light: false }` to leave `api.light` undefined, so builders fall back to `emit('light', ...)`.\n */\nexport function createRecorder(options: { light?: boolean } = {}): { api: PropsApi; primitives: Primitive[] } {\n const primitives: Primitive[] = []\n const api: PropsApi = {\n box: (M, material, x, y, z, w, h, d, color, ry, rx, rz) => void primitives.push({ kind: 'box', M, material, x, y, z, w, h, d, color, ry, rx, rz }),\n cylinder: (M, material, x, y, z, r, h, color, rx, rz, shape) => void primitives.push({ kind: 'cylinder', M, material, x, y, z, r, h, color, rx, rz, shape }),\n leaf: (M, x, y, z, w, h, color, ry, rx) => void primitives.push({ kind: 'leaf', M, x, y, z, w, h, color, ry, rx }),\n plane: (M, material, x, y, z, w, h, color, ry, rx, rz, uv) => void primitives.push({ kind: 'plane', M, material, x, y, z, w, h, color, ry, rx, rz, uv }),\n }\n if (options.light !== false) {\n api.light = (M, x, y, z, color, range, lightKind) => void primitives.push({ kind: 'light', M, x, y, z, color, range, lightKind })\n }\n return { api, primitives }\n}\n","import type * as THREE_NS from 'three'\n\nconst ATTRIBUTES = ['position', 'normal', 'uv'] as const\n\nconst isVisible = (object: THREE_NS.Object3D): boolean => {\n for (let node: THREE_NS.Object3D | null = object; node; node = node.parent) if (!node.visible) return false\n return true\n}\n\n/** A copy of the geometry with the matrix baked in, not indexed, keeping only what every model has (position, normal, uv), so that any two of them can be joined. */\nconst bake = (THREE: typeof THREE_NS, mesh: THREE_NS.Mesh, matrix: THREE_NS.Matrix4): THREE_NS.BufferGeometry => {\n const source = mesh.geometry.index ? mesh.geometry.toNonIndexed() : mesh.geometry.clone()\n const baked = new THREE.BufferGeometry()\n const count = source.getAttribute('position').count\n for (const name of ATTRIBUTES) {\n const attribute = source.getAttribute(name)\n baked.setAttribute(name, attribute ?? new THREE.BufferAttribute(new Float32Array(count * (name === 'uv' ? 2 : 3)), name === 'uv' ? 2 : 3))\n }\n source.dispose()\n return baked.applyMatrix4(matrix)\n}\n\n/** One non-indexed geometry out of several, in order (the port of `mergeGeometries` of three/addons for the three attributes above). */\nconst join = (THREE: typeof THREE_NS, geometries: readonly THREE_NS.BufferGeometry[]): THREE_NS.BufferGeometry => {\n const merged = new THREE.BufferGeometry()\n for (const name of ATTRIBUTES) {\n const size = (geometries[0]?.getAttribute(name) as THREE_NS.BufferAttribute).itemSize\n const total = geometries.reduce((sum, geometry) => sum + geometry.getAttribute(name).count, 0)\n const array = new Float32Array(total * size)\n let offset = 0\n for (const geometry of geometries) {\n array.set(geometry.getAttribute(name).array, offset)\n offset += geometry.getAttribute(name).count * size\n }\n merged.setAttribute(name, new THREE.BufferAttribute(array, size))\n }\n return merged\n}\n\n/**\n * Every visible mesh under `root` (whose world matrix must be up to date), baked into the space of `space` and joined by material: one mesh per material, no shadow cast.\n * Weapons lying on a counter are never animated, so the hundreds of meshes of a model cost one draw call per material instead.\n */\nexport function mergeByMaterial(THREE: typeof THREE_NS, root: THREE_NS.Object3D, space: THREE_NS.Object3D): THREE_NS.Mesh[] {\n const toSpace = space.matrixWorld.clone().invert()\n const byMaterial = new Map<THREE_NS.Material, THREE_NS.BufferGeometry[]>()\n root.traverse((object) => {\n const mesh = object as THREE_NS.Mesh\n if (!mesh.isMesh || Array.isArray(mesh.material) || !isVisible(mesh)) return\n const list = byMaterial.get(mesh.material) ?? []\n list.push(bake(THREE, mesh, new THREE.Matrix4().multiplyMatrices(toSpace, mesh.matrixWorld)))\n byMaterial.set(mesh.material, list)\n })\n return [...byMaterial].map(([material, geometries]) => {\n const merged = new THREE.Mesh(join(THREE, geometries), material)\n for (const geometry of geometries) geometry.dispose()\n merged.castShadow = false\n merged.receiveShadow = true\n return merged\n })\n}\n","import { mergeByMaterial } from '@adatechnology/game-props3d'\nimport type * as THREE_NS from 'three'\n\nimport type { ItemModel } from './build-item'\n\n/**\n * The same item with its meshes joined by material: one mesh and one draw call per material instead of one per part (the \"one material for all the items\" of the page's\n * budget, as far as the materials of the kit allow). The materials are the same objects, so `setWear` still reaches them. The model's scale stays on the root.\n */\nexport function mergeItem(T: typeof THREE_NS, model: ItemModel): ItemModel {\n model.root.updateMatrixWorld(true)\n const merged = new T.Group()\n merged.name = model.root.name\n merged.scale.copy(model.root.scale)\n merged.userData = { ...model.root.userData }\n // baked into the space of the root, which leaves the root's own scale out of the geometry\n merged.add(...mergeByMaterial(T, model.root, model.root))\n return { ...model, root: merged }\n}\n","import type * as THREE_NS from 'three'\n\nexport type Vec3Like = readonly [number, number, number]\n\n/** The draw budgets of the Itens do Vale Cinzento page (section \"Desempenho com hordas\"). */\nexport interface ItemBudgets {\n /** Draw calls of all the items in a frame. */\n drawCalls: number\n /** A small item: at most this many triangles, and it disappears at `cullDistance`. */\n small: { triangles: number; cullDistance: number }\n /** A large item. */\n large: { triangles: number; cullDistance: number }\n /** The second level of detail has this share of the triangles of the first. */\n lod1Ratio: number\n /** Longest side (m) from which an item counts as large: the page does not say where small ends, so this is the kit's reading and a game can change it. */\n largeFrom: number\n}\n\nexport const ITEM_BUDGETS: ItemBudgets = {\n drawCalls: 30,\n small: { triangles: 400, cullDistance: 30 },\n large: { triangles: 1200, cullDistance: 60 },\n lod1Ratio: 0.5,\n largeFrom: 0.6,\n}\n\nexport type ItemSizeClass = 'small' | 'large'\n\nexport const sizeClassOf = (size: Vec3Like, budgets: ItemBudgets = ITEM_BUDGETS): ItemSizeClass => (Math.max(...size) >= budgets.largeFrom ? 'large' : 'small')\n\nexport const triangleBudgetOf = (size: Vec3Like, budgets: ItemBudgets = ITEM_BUDGETS): number => budgets[sizeClassOf(size, budgets)].triangles\n\nexport const cullDistanceOf = (size: Vec3Like, budgets: ItemBudgets = ITEM_BUDGETS): number => budgets[sizeClassOf(size, budgets)].cullDistance\n\n/** Triangles under `root`: visible meshes only, indexed or not. */\nexport function countTriangles(root: THREE_NS.Object3D): number {\n let total = 0\n root.traverse((object) => {\n const mesh = object as THREE_NS.Mesh\n if (!mesh.isMesh || !mesh.visible) return\n const geometry = mesh.geometry\n total += geometry.index ? geometry.index.count / 3 : geometry.getAttribute('position').count / 3\n })\n return Math.round(total)\n}\n\n/** Draw calls under `root`: one per visible mesh (a mesh with a material list counts once per group). */\nexport function countDrawCalls(root: THREE_NS.Object3D): number {\n let total = 0\n root.traverse((object) => {\n const mesh = object as THREE_NS.Mesh\n if (!mesh.isMesh || !mesh.visible) return\n total += Array.isArray(mesh.material) ? Math.max(1, mesh.geometry.groups.length) : 1\n })\n return total\n}\n\nexport interface BudgetReport {\n triangles: number\n limit: number\n drawCalls: number\n sizeClass: ItemSizeClass\n ok: boolean\n}\n\n/** How an item's model measures against its triangle budget (a model of the team above it is a known deviation, not an error). */\nexport function checkBudget(root: THREE_NS.Object3D, size: Vec3Like, budgets: ItemBudgets = ITEM_BUDGETS): BudgetReport {\n const triangles = countTriangles(root)\n const limit = triangleBudgetOf(size, budgets)\n return { triangles, limit, drawCalls: countDrawCalls(root), sizeClass: sizeClassOf(size, budgets), ok: triangles <= limit }\n}\n","import type * as THREE_NS from 'three'\n\nimport { ITEM_BUDGETS, cullDistanceOf } from './budgets'\nimport type { ItemBudgets } from './budgets'\nimport { buildItem } from './build-item'\nimport type { BuildItemOptions, DrawableItem, ItemModel } from './build-item'\nimport { createItemKit } from './kit'\nimport { mergeItem } from './merge'\n\nexport interface ItemLodOptions extends Omit<BuildItemOptions, 'simple' | 'detail' | 'kit'> {\n budgets?: ItemBudgets\n /** Join the meshes of each level by material (default true). */\n merge?: boolean\n /** Distance of the second level in metres; default a third of the distance at which the item disappears. */\n lod1Distance?: number\n}\n\nexport interface ItemLod {\n /** Add this to the scene and call `update(camera)` (or let the renderer do it). */\n readonly root: THREE_NS.LOD\n /** Full detail: the showcase model, or the shape at full segments. */\n readonly near: ItemModel\n /** The simple shape at half the segments. */\n readonly far: ItemModel\n /** Metres from the camera at which the item is no longer drawn. */\n readonly cullDistance: number\n readonly lod1Distance: number\n}\n\n/**\n * Three levels of an item: the model (or the shape) up close, the simple shape at half the segments from `lod1Distance`, and nothing from the distance of its class\n * (a small item goes at 30 m, a large one at 60 m).\n */\nexport function buildItemLod(T: typeof THREE_NS, item: DrawableItem, options: ItemLodOptions = {}): ItemLod {\n const budgets = options.budgets ?? ITEM_BUDGETS\n const cullDistance = cullDistanceOf(item.size, budgets)\n const lod1Distance = options.lod1Distance ?? cullDistance / 3\n const joined = (model: ItemModel): ItemModel => (options.merge === false ? model : mergeItem(T, model))\n const wear = options.wear === undefined ? {} : { wear: options.wear }\n const near = joined(buildItem(T, item, { ...wear, kit: createItemKit(T) }))\n const far = joined(buildItem(T, item, { ...wear, simple: true, detail: budgets.lod1Ratio, kit: createItemKit(T) }))\n const root = new T.LOD()\n root.name = item.id\n root.addLevel(near.root, 0)\n root.addLevel(far.root, lod1Distance)\n root.addLevel(new T.Group(), cullDistance)\n root.userData.wear = options.wear ?? 0\n return { root, near, far, cullDistance, lod1Distance }\n}\n","/**\n * Models of the showcase that go over the triangle budget of their class (400 for a small item, 1200 for a large one) as the team drew them, with the count they have.\n * The page set the budget for the game and drew the models for a showcase; the models stay as delivered (the builder is the team's) and a scene at a distance wears the\n * simple shape of the second level of detail (`buildItemLod`), which is inside the budget. A model that changes its count is a drawing that changed: the test flags it.\n */\nexport const MODEL_BUDGET_DEVIATIONS: Readonly<Record<string, number>> = {\n canned_beans: 744,\n amoxicillin: 596,\n flashlight: 1060,\n portable_radio: 504,\n house_key: 472,\n motorcycle_helmet: 840,\n lpg_cylinder_13kg: 712,\n}\n","import type { Thumbnail } from '@adatechnology/game-contracts'\nimport type * as THREE_NS from 'three'\n\nimport { buildItem } from './build-item'\nimport type { DrawableItem } from './build-item'\nimport { hasItemModel } from './models/registry'\nimport { shade, shapeOf } from './shapes'\nimport type { ShapeId } from './shapes'\nimport { setWear } from './wear'\nimport type { WearStage } from './wear'\n\nconst hex = (color: number): string => `#${(color & 0xffffff).toString(16).padStart(6, '0')}`\nconst DEFAULT_COLOR = 0x8a8f94\nconst STEEL = '#9aa0a6'\nconst BRASS = '#b8913a'\nconst WOOD = '#8a643c'\nconst PAPER = '#ece4d0'\n\n/** The SVG art of each shape on a 64 x 64 board, from the colour of the item (`c`), a darker (`d`) and a lighter (`l`) tone of it. */\nconst ART: Readonly<Record<ShapeId, (c: string, d: string, l: string) => string>> = {\n can: (c, d, l) => `<rect x=\"19\" y=\"13\" width=\"26\" height=\"42\" rx=\"3\" fill=\"${c}\"/><rect x=\"19\" y=\"24\" width=\"26\" height=\"18\" fill=\"${l}\"/><rect x=\"18\" y=\"11\" width=\"28\" height=\"5\" rx=\"2\" fill=\"${STEEL}\"/><rect x=\"18\" y=\"52\" width=\"28\" height=\"4\" rx=\"2\" fill=\"${STEEL}\"/>`,\n bag: (c, d, l) => `<path d=\"M16 55 L13 25 Q32 14 51 25 L48 55 Z\" fill=\"${c}\"/><rect x=\"14\" y=\"17\" width=\"36\" height=\"7\" rx=\"2\" fill=\"${d}\"/><rect x=\"22\" y=\"32\" width=\"20\" height=\"14\" rx=\"2\" fill=\"${l}\"/>`,\n box: (c, d, l) => `<rect x=\"11\" y=\"18\" width=\"42\" height=\"37\" fill=\"${c}\"/><rect x=\"11\" y=\"18\" width=\"42\" height=\"8\" fill=\"${d}\"/><rect x=\"22\" y=\"33\" width=\"20\" height=\"13\" fill=\"${l}\"/>`,\n bottle: (c, d) => `<rect x=\"28\" y=\"7\" width=\"8\" height=\"8\" rx=\"2\" fill=\"${d}\"/><path d=\"M23 56 V30 Q23 23 28 18 H36 Q41 23 41 30 V56 Z\" fill=\"${c}\" fill-opacity=\".75\"/><rect x=\"23\" y=\"34\" width=\"18\" height=\"14\" fill=\"${PAPER}\" fill-opacity=\".9\"/>`,\n tool: (c) => `<rect x=\"29\" y=\"20\" width=\"6\" height=\"37\" rx=\"2\" fill=\"${WOOD}\"/><rect x=\"17\" y=\"9\" width=\"30\" height=\"13\" rx=\"2\" fill=\"${c === '#808080' ? STEEL : c}\"/>`,\n roll: (c, d) => `<circle cx=\"32\" cy=\"34\" r=\"22\" fill=\"${c}\"/><circle cx=\"32\" cy=\"34\" r=\"8\" fill=\"${d}\"/>`,\n dish: (c, d, l) => `<ellipse cx=\"32\" cy=\"44\" rx=\"27\" ry=\"9\" fill=\"${c}\"/><ellipse cx=\"32\" cy=\"42\" rx=\"19\" ry=\"5\" fill=\"${l}\"/><ellipse cx=\"32\" cy=\"42\" rx=\"9\" ry=\"2\" fill=\"${d}\"/>`,\n cloth: (c, d) => `<rect x=\"9\" y=\"34\" width=\"46\" height=\"21\" rx=\"3\" fill=\"${c}\"/><rect x=\"13\" y=\"22\" width=\"38\" height=\"14\" rx=\"3\" fill=\"${d}\"/>`,\n shoe: (c) => `<path d=\"M9 48 V27 H26 L30 36 H47 Q56 38 56 48 Z\" fill=\"${c}\"/><rect x=\"7\" y=\"48\" width=\"50\" height=\"7\" rx=\"2\" fill=\"#22251f\"/>`,\n jar: (c) => `<rect x=\"17\" y=\"22\" width=\"30\" height=\"33\" rx=\"6\" fill=\"${c}\" fill-opacity=\".7\"/><rect x=\"16\" y=\"13\" width=\"32\" height=\"10\" rx=\"2\" fill=\"${BRASS}\"/>`,\n paper: (c, d) => `<rect x=\"14\" y=\"10\" width=\"36\" height=\"46\" fill=\"${PAPER}\"/><rect x=\"19\" y=\"18\" width=\"26\" height=\"3\" fill=\"${d}\"/><rect x=\"19\" y=\"26\" width=\"26\" height=\"3\" fill=\"${d}\"/><rect x=\"19\" y=\"34\" width=\"18\" height=\"3\" fill=\"${d}\"/><rect x=\"19\" y=\"42\" width=\"22\" height=\"3\" fill=\"${c}\"/>`,\n fruit: (c) => `<circle cx=\"32\" cy=\"38\" r=\"18\" fill=\"${c}\"/><rect x=\"31\" y=\"13\" width=\"3\" height=\"9\" fill=\"#5a3a22\"/><path d=\"M34 16 Q44 10 48 16 Q40 20 34 16 Z\" fill=\"#4f7a3a\"/>`,\n cup: (c, d) => `<path d=\"M18 16 H46 L41 56 H23 Z\" fill=\"${c}\"/><rect x=\"18\" y=\"14\" width=\"28\" height=\"4\" fill=\"${d}\"/>`,\n tube: (c, d) => `<path d=\"M23 15 H41 V48 L37 56 H27 L23 48 Z\" fill=\"${c}\"/><rect x=\"25\" y=\"7\" width=\"14\" height=\"9\" rx=\"2\" fill=\"${d}\"/>`,\n blade: () => `<rect x=\"5\" y=\"33\" width=\"18\" height=\"8\" rx=\"2\" fill=\"#3b2a20\"/><path d=\"M23 33 H55 L60 38 L23 42 Z\" fill=\"#a9adb0\"/><rect x=\"22\" y=\"31\" width=\"3\" height=\"12\" fill=\"${BRASS}\"/>`,\n long_tool: (c) => `<rect x=\"5\" y=\"30\" width=\"50\" height=\"5\" rx=\"2\" fill=\"${WOOD}\"/><rect x=\"47\" y=\"21\" width=\"12\" height=\"22\" rx=\"2\" fill=\"${c === '#808080' ? STEEL : c}\"/>`,\n garment: (c, d) => `<path d=\"M20 12 L6 24 L13 33 L20 28 V56 H44 V28 L51 33 L58 24 L44 12 Q32 22 20 12 Z\" fill=\"${c}\"/><path d=\"M20 12 Q32 22 44 12 Q32 28 20 12 Z\" fill=\"${d}\"/>`,\n backpack: (c, d) => `<path d=\"M24 18 Q32 4 40 18\" fill=\"none\" stroke=\"${d}\" stroke-width=\"3\"/><rect x=\"15\" y=\"16\" width=\"34\" height=\"40\" rx=\"9\" fill=\"${c}\"/><rect x=\"21\" y=\"35\" width=\"22\" height=\"16\" rx=\"3\" fill=\"${d}\"/>`,\n jerrycan: (c, d) => `<rect x=\"13\" y=\"17\" width=\"38\" height=\"39\" rx=\"3\" fill=\"${c}\"/><rect x=\"17\" y=\"8\" width=\"16\" height=\"10\" rx=\"2\" fill=\"${d}\"/><rect x=\"39\" y=\"9\" width=\"9\" height=\"9\" fill=\"#d9a441\"/>`,\n tank: (c, d) => `<rect x=\"21\" y=\"18\" width=\"22\" height=\"38\" rx=\"10\" fill=\"${c}\"/><rect x=\"28\" y=\"9\" width=\"8\" height=\"10\" fill=\"${BRASS}\"/><rect x=\"20\" y=\"43\" width=\"24\" height=\"3\" fill=\"${d}\"/>`,\n book: (c, d) => `<rect x=\"14\" y=\"9\" width=\"37\" height=\"47\" fill=\"${c}\"/><rect x=\"14\" y=\"9\" width=\"6\" height=\"47\" fill=\"${d}\"/><rect x=\"23\" y=\"13\" width=\"25\" height=\"39\" fill=\"#e9e1cc\"/>`,\n key: () => `<circle cx=\"16\" cy=\"32\" r=\"9\" fill=\"none\" stroke=\"#9a9da0\" stroke-width=\"5\"/><rect x=\"24\" y=\"30\" width=\"33\" height=\"5\" fill=\"${BRASS}\"/><rect x=\"45\" y=\"35\" width=\"4\" height=\"7\" fill=\"${BRASS}\"/><rect x=\"51\" y=\"35\" width=\"3\" height=\"5\" fill=\"${BRASS}\"/>`,\n battery: (c, d, l) => `<rect x=\"23\" y=\"14\" width=\"18\" height=\"42\" rx=\"2\" fill=\"${c}\"/><rect x=\"28\" y=\"9\" width=\"8\" height=\"6\" fill=\"#b9bdc0\"/><rect x=\"23\" y=\"26\" width=\"18\" height=\"16\" fill=\"${l}\"/><rect x=\"23\" y=\"47\" width=\"18\" height=\"9\" fill=\"${d}\"/>`,\n plank: (c) => `<rect x=\"5\" y=\"26\" width=\"54\" height=\"13\" fill=\"${WOOD}\"/><rect x=\"5\" y=\"30\" width=\"54\" height=\"2\" fill=\"${c === '#808080' ? '#6b4a2c' : c}\" fill-opacity=\".5\"/><circle cx=\"12\" cy=\"32\" r=\"2\" fill=\"#7d8186\"/><circle cx=\"52\" cy=\"32\" r=\"2\" fill=\"#7d8186\"/>`,\n device: (c) => `<rect x=\"15\" y=\"7\" width=\"34\" height=\"50\" rx=\"5\" fill=\"${c}\"/><rect x=\"20\" y=\"13\" width=\"24\" height=\"18\" rx=\"2\" fill=\"#9fbf8a\"/><circle cx=\"26\" cy=\"43\" r=\"4\" fill=\"#b9bdc0\"/><rect x=\"35\" y=\"40\" width=\"9\" height=\"6\" rx=\"1\" fill=\"#b9bdc0\"/>`,\n}\n\n/** The SVG picture of a shape in the colour of an item: a 64 x 64 board with plain shapes, no script and no reference. */\nexport function shapeThumbnailSvg(shape: ShapeId, color: number = DEFAULT_COLOR): string {\n const art = ART[shape]\n return `<svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 64 64\">${art(hex(color), hex(shade(color, 0.7)), hex(shade(color, 1.3)))}</svg>`\n}\n\n/**\n * The picture of an item for catalogues and inventories: an item that has a 3D model asks the host to draw it (`render: true`), every other gets the SVG of its shape in\n * its colour.\n */\nexport function itemThumbnail(item: DrawableItem): Thumbnail {\n if (item.model !== undefined && hasItemModel(item.model)) return { render: true }\n return { svg: shapeThumbnailSvg(shapeOf(item), item.color) }\n}\n\n/** The SVG of an item whatever it has: its shape in its colour (what a host with no renderer shows for a modeled item). */\nexport const itemThumbnailSvg = (item: DrawableItem): string => shapeThumbnailSvg(shapeOf(item), item.color)\n\n/** `{ id: { thumbnail } }` for `createItems({ patch })`, so that a catalog carries its pictures. */\nexport function thumbnailPatch(items: Iterable<DrawableItem>): Record<string, { thumbnail: Thumbnail }> {\n const patch: Record<string, { thumbnail: Thumbnail }> = {}\n for (const item of items) patch[item.id] = { thumbnail: itemThumbnail(item) }\n return patch\n}\n\nexport interface ThumbnailRenderOptions {\n /** Side of the picture in pixels (default 128). */\n size?: number\n /** Turn of the item around y and the lift of the camera, radians (default a three-quarter view from above). */\n yaw?: number\n pitch?: number\n /** Multiplies the distance that just fits the item (default 1). */\n distance?: number\n wear?: WearStage\n}\n\nexport interface ThumbnailScene {\n scene: THREE_NS.Scene\n camera: THREE_NS.PerspectiveCamera\n}\n\nconst FIT_MARGIN = 1.15\nconst FIELD_OF_VIEW = 30\n\n/** The scene and camera that frame an item for its picture: the item at the origin, lit like the showcase (hemisphere, sun, rim), the camera far enough to fit all of it. */\nexport function composeThumbnailScene(T: typeof THREE_NS, item: DrawableItem, options: ThumbnailRenderOptions = {}): ThumbnailScene {\n const { yaw = -0.6, pitch = 0.45, distance = 1, wear = 0 } = options\n const scene = new T.Scene()\n const model = buildItem(T, item)\n if (wear) setWear(model.root, wear)\n scene.add(model.root)\n scene.add(new T.HemisphereLight(0xdfe6ee, 0x3a3428, 0.85))\n const sun = new T.DirectionalLight(0xffe2bf, 1.1)\n sun.position.set(2.5, 3.5, 2.5)\n scene.add(sun)\n const rim = new T.DirectionalLight(0x8fb2d6, 0.45)\n rim.position.set(-3, 1, -2.5)\n scene.add(rim)\n const box = new T.Box3().setFromObject(model.root)\n const centre = box.getCenter(new T.Vector3())\n const radius = box.getSize(new T.Vector3()).length() / 2\n const camera = new T.PerspectiveCamera(FIELD_OF_VIEW, 1, radius / 50, radius * 40)\n const fit = (radius * FIT_MARGIN) / Math.sin((FIELD_OF_VIEW * Math.PI) / 360)\n const away = fit * distance\n camera.position.set(centre.x + away * Math.cos(pitch) * Math.sin(yaw), centre.y + away * Math.sin(pitch), centre.z + away * Math.cos(pitch) * Math.cos(yaw))\n camera.lookAt(centre)\n camera.updateMatrixWorld(true)\n return { scene, camera }\n}\n\n/** What `renderItemThumbnail` needs of a renderer (a `WebGLRenderer`, or anything that draws a scene to a canvas). */\nexport interface ThumbnailRenderer {\n setSize(width: number, height: number): void\n setClearColor?(color: number, alpha?: number): void\n render(scene: THREE_NS.Scene, camera: THREE_NS.Camera): void\n domElement: { toDataURL(type?: string): string }\n}\n\n/** Draws the item with the host's renderer and returns the PNG as a data URL (transparent background). */\nexport function renderItemThumbnail(T: typeof THREE_NS, renderer: ThumbnailRenderer, item: DrawableItem, options: ThumbnailRenderOptions = {}): string {\n const { scene, camera } = composeThumbnailScene(T, item, options)\n const size = options.size ?? 128\n renderer.setSize(size, size)\n renderer.setClearColor?.(0x000000, 0)\n renderer.render(scene, camera)\n return renderer.domElement.toDataURL('image/png')\n}\n","import type { ColliderOptions, WorldCollider } from './types'\n\ninterface Box {\n ids: string[]\n object: string\n u0: number\n u1: number\n v0: number\n v1: number\n y0: number\n y1: number\n}\n\nconst volume = (b: Box): number => (b.u1 - b.u0) * (b.v1 - b.v0) * (b.y1 - b.y0)\nconst overlap = (a0: number, a1: number, b0: number, b1: number): number => Math.max(0, Math.min(a1, b1) - Math.max(a0, b0))\n\nfunction tryMerge(a: Box, b: Box, gap: number, slack: number): Box | null {\n if (a.u0 - gap > b.u1 || b.u0 - gap > a.u1) return null\n if (a.v0 - gap > b.v1 || b.v0 - gap > a.v1) return null\n if (a.y0 - gap > b.y1 || b.y0 - gap > a.y1) return null\n const u0 = Math.min(a.u0, b.u0)\n const u1 = Math.max(a.u1, b.u1)\n const v0 = Math.min(a.v0, b.v0)\n const v1 = Math.max(a.v1, b.v1)\n const y0 = Math.min(a.y0, b.y0)\n const y1 = Math.max(a.y1, b.y1)\n const hull = (u1 - u0) * (v1 - v0) * (y1 - y0)\n const common = overlap(a.u0, a.u1, b.u0, b.u1) * overlap(a.v0, a.v1, b.v0, b.v1) * overlap(a.y0, a.y1, b.y0, b.y1)\n const real = volume(a) + volume(b) - common\n if (hull > real * (1 + slack) + 1e-9) return null\n return { ids: [...a.ids, ...b.ids], object: a.object, u0, u1, v0, v1, y0, y1 }\n}\n\n/**\n * Union overlapping or adjacent colliders of the same object (same rotation) into fewer OBBs.\n * A merge happens only when the merged box adds at most `slack` extra volume over the real union, so coverage is never lost\n * and never grows noticeably. Colliders of different objects or rotations are left alone.\n */\nexport function mergeColliders(list: WorldCollider[], options: Pick<ColliderOptions, 'gap' | 'slack'> = {}): WorldCollider[] {\n const gap = options.gap ?? 0.02\n const slack = options.slack ?? 0.1\n const groups = new Map<string, WorldCollider[]>()\n for (const c of list) {\n const key = `${c.object}|${Math.round(c.ry * 1000)}`\n const g = groups.get(key)\n if (g) g.push(c)\n else groups.set(key, [c])\n }\n const out: WorldCollider[] = []\n for (const g of groups.values()) {\n const ry = g[0]?.ry ?? 0\n const cs = Math.cos(ry)\n const sn = Math.sin(ry)\n let boxes: Box[] = g.map((c) => {\n const u = c.cx * cs - c.cz * sn\n const v = c.cx * sn + c.cz * cs\n return { ids: [c.id], object: c.object, u0: u - c.hw, u1: u + c.hw, v0: v - c.hd, v1: v + c.hd, y0: c.y0, y1: c.y1 }\n })\n let changed = boxes.length > 1\n while (changed) {\n changed = false\n outer: for (let i = 0; i < boxes.length; i++) {\n for (let j = i + 1; j < boxes.length; j++) {\n const m = tryMerge(boxes[i] as Box, boxes[j] as Box, gap, slack)\n if (!m) continue\n boxes = boxes.filter((_, k) => k !== i && k !== j)\n boxes.push(m)\n changed = true\n break outer\n }\n }\n }\n for (const b of boxes) {\n const u = (b.u0 + b.u1) / 2\n const v = (b.v0 + b.v1) / 2\n out.push({\n id: b.ids.length === 1 ? (b.ids[0] as string) : `${b.ids[0]}+${b.ids.length - 1}`,\n object: b.object,\n cx: u * cs + v * sn,\n cz: -u * sn + v * cs,\n hw: (b.u1 - b.u0) / 2,\n hd: (b.v1 - b.v0) / 2,\n ry,\n y0: b.y0,\n y1: b.y1,\n })\n }\n }\n return out\n}\n","/** FNV-1a hash of a string to a 32-bit unsigned integer. */\nexport function hashString(text: string): number {\n let h = 2166136261\n for (let i = 0; i < text.length; i++) {\n h ^= text.charCodeAt(i)\n h = Math.imul(h, 16777619)\n }\n return h >>> 0\n}\n\n/** Deterministic random generator (mulberry32). Returns a function producing floats in [0, 1). Numbers and strings are accepted as seeds. */\nexport function rng(seed: number | string = 1): () => number {\n let a = (typeof seed === 'number' ? Math.floor(seed) >>> 0 : hashString(seed)) || 0x9e3779b9\n return () => {\n a = (a + 0x6d2b79f5) >>> 0\n let t = a\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","import { rng } from './rng'\nimport type { ItemCatalog, ItemStack, LootTables, SlotSpec, Vec3 } from './types'\n\n/** True when an item of `size` [w, h, d] fits in a slot of `max`; width and depth may be swapped (the item is turned). */\nexport function fitsSize(size: Vec3, max: Vec3): boolean {\n const eps = 1e-9\n if (size[1] > max[1] + eps) return false\n return (size[0] <= max[0] + eps && size[2] <= max[2] + eps) || (size[2] <= max[0] + eps && size[0] <= max[2] + eps)\n}\n\n/** Does the item type fit the slot. Types missing from the catalog are accepted (the host owns unknown items). */\nexport function fitsSlot(type: string, slot: SlotSpec, items?: ItemCatalog): boolean {\n const def = items?.[type]\n return def ? fitsSize(def.size, slot.max) : true\n}\n\n/**\n * Deterministic contents for a container: one entry per slot. A slot is filled with probability `fill`; the entry is a weighted pick\n * among the table entries whose item fits the slot. Same seed, same table and same slots always give the same result.\n */\nexport function generateLoot(\n tables: LootTables | undefined,\n tableId: string,\n slots: SlotSpec[],\n seed: number | string,\n items?: ItemCatalog,\n): Array<ItemStack | null> {\n const table = tables?.[tableId]\n const out: Array<ItemStack | null> = slots.map(() => null)\n if (!table) return out\n const rand = rng(seed)\n slots.forEach((slot, i) => {\n // Always draw the same number of random values per slot so a change in one slot does not shift the others.\n const roll = rand()\n const pick = rand()\n const q = rand()\n if (roll >= table.fill) return\n const candidates = table.entries.filter((e) => e.weight > 0 && fitsSlot(e.type, slot, items))\n const total = candidates.reduce((s, e) => s + e.weight, 0)\n if (total <= 0) return\n let r = pick * total\n let chosen = candidates[candidates.length - 1]\n for (const e of candidates) {\n r -= e.weight\n if (r < 0) {\n chosen = e\n break\n }\n }\n const [lo, hi] = chosen.qty ?? [1, 1]\n const def = items?.[chosen.type]\n const stackMax = def ? (def.stack ?? 1) : Number.POSITIVE_INFINITY\n const qty = Math.max(1, Math.min(stackMax, lo + Math.floor(q * (hi - lo + 1))))\n out[i] = { type: chosen.type, qty }\n })\n return out\n}\n","import type { InteractablesLocale, Strings } from './types'\n\n/** Engine-level prompts and messages. Content packs add their own keys through `WorldOptions.strings`. */\nexport const locales: Record<InteractablesLocale, Strings> = {\n en: {\n 'prompt.open': 'Open {name}',\n 'prompt.close': 'Close {name}',\n 'prompt.turn_on': 'Turn on {name}',\n 'prompt.turn_off': 'Turn off {name}',\n 'prompt.take': 'Take',\n 'prompt.sit': 'Sit',\n 'prompt.lie_down': 'Lie down',\n 'prompt.get_up': 'Get up',\n 'prompt.light': 'Light',\n 'prompt.change_channel': 'Change channel',\n 'prompt.read': 'Read',\n 'prompt.breaker_on': 'Switch on {circuit}',\n 'prompt.breaker_off': 'Switch off {circuit}',\n 'prompt.open_valve': 'Open valve',\n 'prompt.close_valve': 'Close valve',\n no_power: 'No power',\n no_gas: 'No gas',\n no_water: 'No water',\n locked: 'Locked',\n requires_open: 'Open it first',\n already_lit: 'Already lit',\n needs_ignition: 'Light it first',\n turn_on_first: 'Turn it on first',\n empty: 'Empty',\n full: 'Full',\n },\n 'pt-BR': {\n 'prompt.open': 'Abrir {name}',\n 'prompt.close': 'Fechar {name}',\n 'prompt.turn_on': 'Ligar {name}',\n 'prompt.turn_off': 'Desligar {name}',\n 'prompt.take': 'Pegar',\n 'prompt.sit': 'Sentar',\n 'prompt.lie_down': 'Deitar',\n 'prompt.get_up': 'Levantar',\n 'prompt.light': 'Acender',\n 'prompt.change_channel': 'Trocar de canal',\n 'prompt.read': 'Ler',\n 'prompt.breaker_on': 'Ligar {circuit}',\n 'prompt.breaker_off': 'Desligar {circuit}',\n 'prompt.open_valve': 'Abrir registro',\n 'prompt.close_valve': 'Fechar registro',\n no_power: 'Sem energia',\n no_gas: 'Sem gás',\n no_water: 'Sem água',\n locked: 'Trancado',\n requires_open: 'Abra primeiro',\n already_lit: 'Já está aceso',\n needs_ignition: 'Acenda primeiro',\n turn_on_first: 'Ligue primeiro',\n empty: 'Vazio',\n full: 'Cheio',\n },\n}\n\n/** Pick a built-in locale for an arbitrary tag (`pt`, `pt-br`, `en-GB`...). Unknown tags give `en`. */\nexport function pickLocale(locale: string | undefined): InteractablesLocale {\n if (!locale) return 'en'\n const l = locale.toLowerCase()\n if (l === 'pt-br' || l === 'pt') return 'pt-BR'\n return 'en'\n}\n\n/**\n * Merged table for a locale: built-in `en`, then the built-in table of `locale`, then the extra strings for `en` and for `locale`.\n * Lookup therefore falls back to English, and the caller never gets undefined for engine keys.\n */\nexport function resolveStrings(locale?: string, extra?: Partial<Record<InteractablesLocale, Strings>>): Strings {\n const loc = pickLocale(locale)\n return { ...locales.en, ...locales[loc], ...(extra?.en ?? {}), ...(loc === 'en' ? {} : (extra?.[loc] ?? {})) }\n}\n\n/** Replace `{name}` placeholders. Unknown placeholders are left untouched. */\nexport function format(text: string, vars?: Record<string, string | number>): string {\n if (!vars) return text\n return text.replace(/\\{(\\w+)\\}/g, (m, k: string) => (k in vars ? String(vars[k]) : m))\n}\n","import type { Motion, Transform, Vec3 } from './types'\n\nexport interface Pose {\n /** Translation relative to the pivot. */\n position: Vec3\n /** Rotation around `axis` (in the part frame) by `angle` radians. */\n rotation: { axis: Vec3; angle: number }\n scale: Vec3\n}\n\nconst DEFAULT_AXIS: Vec3 = [0, 1, 0]\n\n/**\n * Pose of a part at animation value `t` (0..1), relative to its pivot, so any renderer can apply it:\n * `position`, then `rotation` around the pivot, then `scale` along the axis.\n */\nexport function poseOf(motion: Motion, t: number): Pose {\n const tt = Math.max(0, Math.min(1, t))\n const axis = motion.axis ?? DEFAULT_AXIS\n const pose: Pose = { position: [0, 0, 0], rotation: { axis: [axis[0], axis[1], axis[2]], angle: 0 }, scale: [1, 1, 1] }\n switch (motion.kind) {\n case 'hinge':\n case 'rocker':\n case 'knob':\n pose.rotation.angle = (motion.angle ?? Math.PI / 2) * tt\n break\n case 'slide': {\n const d = (motion.distance ?? 0.4) * tt\n pose.position = [axis[0] * d, axis[1] * d, axis[2] * d]\n break\n }\n case 'scale': {\n const k = 1 + ((motion.scale ?? 0.2) - 1) * tt\n pose.scale = [axis[0] !== 0 ? k : 1, axis[1] !== 0 ? k : 1, axis[2] !== 0 ? k : 1]\n break\n }\n }\n return pose\n}\n\n/** Rotate a vector around +y by `ry` radians (same convention as three.js `rotation.y`). */\nexport function rotY(v: Vec3, ry: number): Vec3 {\n const c = Math.cos(ry)\n const s = Math.sin(ry)\n return [c * v[0] + s * v[2], v[1], -s * v[0] + c * v[2]]\n}\n\n/** Object-local point to world space. */\nexport function localToWorld(transform: Transform, v: Vec3): Vec3 {\n const r = rotY(v, transform.ry)\n return [transform.x + r[0], transform.y + r[1], transform.z + r[2]]\n}\n\n/** World point to object-local space. */\nexport function worldToLocal(transform: Transform, v: Vec3): Vec3 {\n return rotY([v[0] - transform.x, v[1] - transform.y, v[2] - transform.z], -transform.ry)\n}\n\n/** Rodrigues rotation of `v` around a unit-length-normalised `axis` by `angle`. */\nexport function rotateAxis(v: Vec3, axis: Vec3, angle: number): Vec3 {\n const len = Math.hypot(axis[0], axis[1], axis[2]) || 1\n const k: Vec3 = [axis[0] / len, axis[1] / len, axis[2] / len]\n const c = Math.cos(angle)\n const s = Math.sin(angle)\n const dot = k[0] * v[0] + k[1] * v[1] + k[2] * v[2]\n const cross: Vec3 = [k[1] * v[2] - k[2] * v[1], k[2] * v[0] - k[0] * v[2], k[0] * v[1] - k[1] * v[0]]\n return [v[0] * c + cross[0] * s + k[0] * dot * (1 - c), v[1] * c + cross[1] * s + k[1] * dot * (1 - c), v[2] * c + cross[2] * s + k[2] * dot * (1 - c)]\n}\n\nexport function clamp(v: number, lo: number, hi: number): number {\n return v < lo ? lo : v > hi ? hi : v\n}\n\nexport function dist3(a: Vec3, b: Vec3): number {\n return Math.hypot(a[0] - b[0], a[1] - b[1], a[2] - b[2])\n}\n","import { mergeColliders } from './colliders'\nimport { fitsSlot, generateLoot } from './loot'\nimport { format, resolveStrings } from './locale'\nimport { clamp, dist3, localToWorld, rotateAxis, rotY, worldToLocal } from './math'\nimport type {\n ActiveEmitter,\n BurnerSpec,\n ColliderOptions,\n DeviceSpec,\n FixtureSpec,\n FuelSourceSpec,\n Interactable,\n InteractionSpec,\n ItemStack,\n ObjectSpec,\n PartSpec,\n SeatResult,\n SoftSpec,\n TankSpec,\n TargetOptions,\n Transform,\n Vec3,\n World,\n WorldCollider,\n WorldEvent,\n WorldObject,\n WorldOptions,\n WorldState,\n} from './types'\n\n// ---------------------------------------------------------------------------------------------------------------------------------\n// Constants\n// ---------------------------------------------------------------------------------------------------------------------------------\n\nconst DEFAULT_ACTOR = 'player'\nconst DEFAULT_RADIUS = 1.2\nconst AUTO_RANGE = 2\nconst SMOKE_TAIL = 20\nconst FLUSH_SECONDS = 2\nconst ACTOR_HEIGHT = 1.7\nconst PUSH_GAIN = 1.2\nconst SWEEP_STEPS = 24\nconst FLOW_DEFAULTS: Record<string, number> = { tap: 6, shower: 8, utility_sink: 6, flush: 0, hose: 10, filter: 1 }\n\n// ---------------------------------------------------------------------------------------------------------------------------------\n// Internal state\n// ---------------------------------------------------------------------------------------------------------------------------------\n\ninterface PartState {\n spec: PartSpec\n t: number\n target: number\n maxT: number\n}\n\ninterface DeviceState {\n spec: DeviceSpec\n on: boolean\n channel: number\n}\n\ninterface FuelState {\n spec: FuelSourceSpec\n level: number\n}\n\ninterface BurnerState {\n spec: BurnerSpec\n on: boolean\n lit: boolean\n /** Seconds of smoke left after a solid-fuel fire went out. */\n smoke: number\n}\n\ninterface TankState {\n spec: TankSpec\n level: number\n}\n\ninterface FixtureState {\n spec: FixtureSpec\n on: boolean\n flowing: boolean\n /** Delivered / wanted in the last step, 0..1. */\n frac: number\n /** Seconds left of a flush. */\n timer: number\n}\n\ninterface SoftState {\n spec: SoftSpec\n ax: number\n az: number\n vax: number\n vaz: number\n phase: number\n}\n\ninterface DamageState {\n max: number\n hp: number\n}\n\ninterface ObjState {\n id: string\n public: WorldObject\n spec: ObjectSpec\n parts: Map<string, PartState>\n contents: Map<string, Array<ItemStack | null>>\n devices: Map<string, DeviceState>\n fuels: Map<string, FuelState>\n burners: Map<string, BurnerState>\n tanks: Map<string, TankState>\n fixtures: Map<string, FixtureState>\n soft: Map<string, SoftState>\n hp: Map<string, DamageState>\n interactions: InteractionSpec[]\n}\n\nfunction cloneStack(s: ItemStack | null): ItemStack | null {\n return s ? { type: s.type, qty: s.qty, ...(s.data ? { data: JSON.parse(JSON.stringify(s.data)) as Record<string, unknown> } : {}) } : null\n}\n\nfunction humanize(id: string): string {\n const s = id.replace(/[_-]+/g, ' ').trim()\n return s.charAt(0).toUpperCase() + s.slice(1)\n}\n\n// ---------------------------------------------------------------------------------------------------------------------------------\n// World\n// ---------------------------------------------------------------------------------------------------------------------------------\n\nexport function createWorld(options: WorldOptions = {}): World {\n const seed = options.seed ?? 1\n const objs = new Map<string, ObjState>()\n const breakers = new Map<string, boolean>()\n const seats = new Map<string, { object: string; seat: string }>()\n const plugs = new Map<string, string | null>()\n let locale = options.locale ?? 'en'\n let table = resolveStrings(locale, options.strings)\n let grid = options.grid ?? true\n let rain = options.rain ?? 0\n let wind: [number, number] = options.wind ? [options.wind[0], options.wind[1]] : [0, 0]\n let defaultTank: string | null = null\n let defaultTankExplicit = false\n let time = 0\n\n // ------------------------------------------------------------------ text & events\n function t(key: string, vars?: Record<string, string | number>): string {\n return format(table[key] ?? key, vars)\n }\n\n function emit(e: WorldEvent): void {\n options.onEvent?.(e)\n }\n\n function message(key: string): void {\n emit({ type: 'message', key, text: t(key) })\n }\n\n // ------------------------------------------------------------------ lookup helpers\n function gid(o: ObjState, local: string): string {\n return `${o.id}:${local}`\n }\n\n /** Find the first entity matching a world-wide id `objectId:localId`. */\n function findGlobal<T>(id: string, pick: (o: ObjState, local: string) => T | undefined): { o: ObjState; value: T; local: string } | null {\n for (const o of objs.values()) {\n if (!id.startsWith(o.id + ':')) continue\n const local = id.slice(o.id.length + 1)\n const value = pick(o, local)\n if (value !== undefined) return { o, value, local }\n }\n return null\n }\n\n function objectOrThrow(id: string): ObjState {\n const o = objs.get(id)\n if (!o) throw new Error(`Unknown object \"${id}\"`)\n return o\n }\n\n function originOf(o: ObjState): Vec3 {\n const tr = o.public.transform\n return [tr.x, tr.y, tr.z]\n }\n\n function toWorld(o: ObjState, v: Vec3): Vec3 {\n return localToWorld(o.public.transform, v)\n }\n\n // ------------------------------------------------------------------ parts\n function openThreshold(p: PartState): number {\n return Math.min(0.5, p.maxT * 0.9)\n }\n\n function isOpen(o: ObjState, partId: string | undefined): boolean {\n if (!partId) return true\n const p = o.parts.get(partId)\n if (!p) return true\n return p.maxT >= 0.1 && p.t >= openThreshold(p)\n }\n\n function targetIsOpen(p: PartState): boolean {\n return p.maxT >= 0.1 && p.target >= openThreshold(p)\n }\n\n function writeT(o: ObjState, p: PartState, v: number): void {\n p.t = v\n o.public.parts[p.spec.id] = v\n }\n\n function gated(o: ObjState, p: PartState): boolean {\n return !!p.spec.requires && o.parts.has(p.spec.requires) && !isOpen(o, p.spec.requires)\n }\n\n function setOnePart(o: ObjState, p: PartState, target: number, instant: boolean): void {\n const next = clamp(target, 0, p.maxT)\n const changed = next !== p.target\n p.target = next\n if (instant) writeT(o, p, next)\n if (changed || instant) emit({ type: 'part', object: o.id, part: p.spec.id, t: p.t, target: p.target })\n }\n\n function setPartTarget(o: ObjState, partId: string, target: number, instant = false): void {\n const p = o.parts.get(partId)\n if (!p) return\n const group = p.spec.group\n const members = group ? [...o.parts.values()].filter((q) => q.spec.group === group) : [p]\n for (const q of members) {\n setOne(o, q, target, instant)\n }\n }\n\n function setOne(o: ObjState, p: PartState, target: number, instant: boolean): void {\n setOnePart(o, p, target, instant)\n // a part that other parts require closes them with it (the drawer behind a door closes with the door)\n if (!targetIsOpen(p)) {\n for (const q of o.parts.values()) {\n if (q.spec.requires === p.spec.id && q.target > 0) setPartTarget(o, q.spec.id, 0, instant)\n }\n }\n }\n\n /** Frame of a part right now: rotation (axis in object-local, angle) and translation, both about its pivot. */\n function partFrame(o: ObjState, partId: string | undefined): { pivot: Vec3; axis: Vec3; angle: number; offset: Vec3 } | null {\n if (!partId) return null\n const p = o.parts.get(partId)\n if (!p) return null\n const m = p.spec.motion\n const axis = rotY(m.axis ?? [0, 1, 0], p.spec.ry ?? 0)\n const frame = { pivot: p.spec.pivot, axis, angle: 0, offset: [0, 0, 0] as Vec3 }\n if (m.kind === 'slide') {\n const d = (m.distance ?? 0.4) * p.t\n frame.offset = [axis[0] * d, axis[1] * d, axis[2] * d]\n } else if (m.kind !== 'scale') {\n frame.angle = (m.angle ?? Math.PI / 2) * p.t\n }\n return frame\n }\n\n function applyPart(o: ObjState, partId: string | undefined, local: Vec3): Vec3 {\n const f = partFrame(o, partId)\n if (!f) return local\n const rel: Vec3 = [local[0] - f.pivot[0], local[1] - f.pivot[1], local[2] - f.pivot[2]]\n const r = f.angle !== 0 ? rotateAxis(rel, f.axis, f.angle) : rel\n return [f.pivot[0] + r[0] + f.offset[0], f.pivot[1] + r[1] + f.offset[1], f.pivot[2] + r[2] + f.offset[2]]\n }\n\n /** Moves the full closed-pose slab of a part and returns the largest t whose pose keeps every sampled point clear. */\n function fitBounds(o: ObjState, p: PartState, b: NonNullable<PartSpec['bounds']>, blockedAt: (x: number, z: number) => boolean): number {\n const STEP = 0.05\n const ANGLES = 48\n const m = p.spec.motion\n const axis = rotY(m.axis ?? [0, 1, 0], p.spec.ry ?? 0)\n const lo: Vec3 = [Math.min(b[0], b[3]), Math.min(b[1], b[4]), Math.min(b[2], b[5])]\n const hi: Vec3 = [Math.max(b[0], b[3]), Math.max(b[1], b[4]), Math.max(b[2], b[5])]\n const axisPoints = (i: number): number[] => {\n const n = Math.max(1, Math.ceil((hi[i] - lo[i]) / STEP))\n return Array.from({ length: n + 1 }, (_, k) => lo[i] + ((hi[i] - lo[i]) * k) / n)\n }\n const xs = axisPoints(0)\n const ys = axisPoints(1)\n const zs = axisPoints(2)\n // `blocked` only sees x/z, so only the floor footprint matters. About a vertical axis (and for slides) y never changes\n // the footprint, so the x/z outline is enough; otherwise the footprint boundary is the projection of the box edges.\n const flat = m.kind === 'slide' || Math.abs(axis[1]) > 0.999\n const seen = new Set<string>()\n const pts: Vec3[] = []\n const add = (x: number, y: number, z: number): void => {\n const key = `${x.toFixed(5)},${y.toFixed(5)},${z.toFixed(5)}`\n if (seen.has(key)) return\n seen.add(key)\n pts.push([x, y, z])\n }\n if (flat) {\n for (const x of xs) for (const z of [lo[2], hi[2]]) add(x, lo[1], z)\n for (const z of zs) for (const x of [lo[0], hi[0]]) add(x, lo[1], z)\n } else {\n for (const x of xs) for (const y of [lo[1], hi[1]]) for (const z of [lo[2], hi[2]]) add(x, y, z)\n for (const y of ys) for (const x of [lo[0], hi[0]]) for (const z of [lo[2], hi[2]]) add(x, y, z)\n for (const z of zs) for (const x of [lo[0], hi[0]]) for (const y of [lo[1], hi[1]]) add(x, y, z)\n }\n const tr = o.public.transform\n const pivot = p.spec.pivot\n for (let i = 1; i <= ANGLES; i++) {\n const tt = i / ANGLES\n const angle = m.kind === 'slide' ? 0 : (m.angle ?? Math.PI / 2) * tt\n const d = m.kind === 'slide' ? (m.distance ?? 0.4) * tt : 0\n for (const [x, y, z] of pts) {\n let q: Vec3 = [x, y, z]\n if (angle !== 0) {\n const r = rotateAxis([x - pivot[0], y - pivot[1], z - pivot[2]], axis, angle)\n q = [pivot[0] + r[0], pivot[1] + r[1], pivot[2] + r[2]]\n }\n const w = localToWorld(tr, [q[0] + axis[0] * d, 0, q[2] + axis[2] * d])\n if (blockedAt(w[0], w[2])) return (i - 1) / ANGLES\n }\n }\n return 1\n }\n\n function fitSweep(objectId: string, partId: string, blocked: (x: number, z: number) => boolean): number {\n const o = objectOrThrow(objectId)\n const p = o.parts.get(partId)\n if (!p) throw new Error(`Unknown part \"${partId}\" on \"${objectId}\"`)\n const sweep = p.spec.sweep\n let result = 1\n const bounds = p.spec.bounds\n const mk = p.spec.motion.kind\n if (bounds && (mk === 'hinge' || mk === 'rocker' || mk === 'knob' || mk === 'slide')) {\n result = fitBounds(o, p, bounds, blocked)\n } else if (sweep) {\n const x0 = Math.min(sweep[0], sweep[2])\n const x1 = Math.max(sweep[0], sweep[2])\n const z0 = Math.min(sweep[1], sweep[3])\n const z1 = Math.max(sweep[1], sweep[3])\n const tr = o.public.transform\n const hit = (lx: number, lz: number): boolean => {\n const w = localToWorld(tr, [lx, 0, lz])\n return blocked(w[0], w[2])\n }\n const m = p.spec.motion\n const axis = rotY(m.axis ?? [0, 1, 0], p.spec.ry ?? 0)\n if (m.kind === 'hinge' || m.kind === 'rocker' || m.kind === 'knob') {\n if (Math.abs(axis[1]) >= 0.5) {\n const angle = m.angle ?? Math.PI / 2\n const total = -angle * Math.sign(axis[1])\n const [px, , pz] = p.spec.pivot\n const cx = (x0 + x1) / 2\n const cz = (z0 + z1) / 2\n const w = x1 - x0\n const d = z1 - z0\n const radius = Math.abs(angle) > 1.7 ? Math.min(w, d) : Math.max(w, d)\n const tol = 0.05\n const inRect = (x: number, z: number) => x >= x0 - tol && x <= x1 + tol && z >= z0 - tol && z <= z1 + tol\n const centered = Math.hypot(cx - px, cz - pz) < 1e-6\n const mid = Math.atan2(cz - pz, cx - px)\n for (let i = 1; i <= SWEEP_STEPS && result === 1; i++) {\n const tt = i / SWEEP_STEPS\n let isHit = false\n if (centered) {\n for (let x = x0; x <= x1 + 1e-9 && !isHit; x += 0.1) for (let z = z0; z <= z1 + 1e-9 && !isHit; z += 0.1) isHit = hit(x, z)\n } else {\n const phi = mid - total / 2 + total * tt\n const steps = Math.max(2, Math.ceil(radius / 0.1))\n for (let k = 1; k <= steps && !isHit; k++) {\n const r = (radius * k) / steps\n const x = px + Math.cos(phi) * r\n const z = pz + Math.sin(phi) * r\n if (inRect(x, z)) isHit = hit(x, z)\n }\n }\n if (isHit) result = (i - 1) / SWEEP_STEPS\n }\n }\n } else if (m.kind === 'slide') {\n const len = Math.hypot(axis[0], axis[2])\n if (len > 1e-6) {\n const dx = axis[0] / len\n const dz = axis[2] / len\n const proj = [x0 * dx + z0 * dz, x1 * dx + z0 * dz, x0 * dx + z1 * dz, x1 * dx + z1 * dz]\n const pmin = Math.min(...proj)\n const pmax = Math.max(...proj)\n const nx = Math.max(1, Math.ceil((x1 - x0) / 0.1))\n const nz = Math.max(1, Math.ceil((z1 - z0) / 0.1))\n for (let i = 1; i <= SWEEP_STEPS && result === 1; i++) {\n const limit = pmin + (pmax - pmin) * (i / SWEEP_STEPS)\n let isHit = false\n for (let a = 0; a <= nx && !isHit; a++) {\n for (let b = 0; b <= nz && !isHit; b++) {\n const x = x0 + ((x1 - x0) * a) / nx\n const z = z0 + ((z1 - z0) * b) / nz\n if (x * dx + z * dz <= limit + 1e-9 && hit(x, z)) isHit = true\n }\n }\n if (isHit) result = (i - 1) / SWEEP_STEPS\n }\n }\n }\n }\n p.maxT = result\n if (p.target > result) p.target = result\n if (p.t > result) writeT(o, p, result)\n return result\n }\n\n // ------------------------------------------------------------------ containers\n function containerOf(o: ObjState, id: string) {\n return o.spec.containers?.find((c) => c.id === id)\n }\n\n function accessible(objectId: string, containerId: string): boolean {\n const o = objs.get(objectId)\n if (!o) return false\n const c = containerOf(o, containerId)\n if (!c) return false\n return isOpen(o, c.access)\n }\n\n function contents(objectId: string, containerId: string): Array<ItemStack | null> {\n return (objs.get(objectId)?.contents.get(containerId) ?? []).map(cloneStack)\n }\n\n function take(objectId: string, containerId: string, slot: number, actor: string = DEFAULT_ACTOR): ItemStack | null {\n const o = objs.get(objectId)\n if (!o) return null\n const list = o.contents.get(containerId)\n if (!list || !accessible(objectId, containerId)) return null\n const stack = list[slot]\n if (!stack) return null\n const def = options.items?.[stack.type]\n if (def && def.pickable === false) return null\n list[slot] = null\n emit({ type: 'pickup', object: objectId, container: containerId, slot, stack: cloneStack(stack) as ItemStack, actor })\n return stack\n }\n\n function put(objectId: string, containerId: string, stack: ItemStack): number | null {\n const o = objs.get(objectId)\n if (!o) return null\n const c = containerOf(o, containerId)\n const list = o.contents.get(containerId)\n if (!c || !list || !accessible(objectId, containerId)) return null\n const maxStack = options.items?.[stack.type]?.stack ?? 1\n for (let i = 0; i < list.length; i++) {\n const cur = list[i]\n if (cur && cur.type === stack.type && !cur.data && !stack.data && cur.qty + stack.qty <= maxStack) {\n cur.qty += stack.qty\n return i\n }\n }\n for (let i = 0; i < list.length; i++) {\n if (!list[i] && fitsSlot(stack.type, c.slots[i], options.items)) {\n list[i] = cloneStack(stack)\n return i\n }\n }\n message('full')\n return null\n }\n\n function slotPosition(objectId: string, containerId: string, slot: number): Vec3 {\n const o = objectOrThrow(objectId)\n const c = containerOf(o, containerId)\n const s = c?.slots[slot]\n if (!c || !s) throw new Error(`Unknown slot ${slot} of \"${containerId}\" on \"${objectId}\"`)\n return toWorld(o, applyPart(o, s.part, s.pos))\n }\n\n // ------------------------------------------------------------------ power\n function rebuildPlugs(): void {\n plugs.clear()\n const sockets: Array<{ id: string; pos: Vec3; circuit?: string; local: string }> = []\n for (const o of objs.values()) {\n for (const s of o.spec.sockets ?? []) sockets.push({ id: gid(o, s.id), local: s.id, pos: toWorld(o, s.pos), circuit: s.circuit })\n }\n const used = new Set<string>()\n const autos: Array<{ o: ObjState; d: DeviceState }> = []\n for (const o of objs.values()) {\n for (const d of o.devices.values()) {\n const key = gid(o, d.spec.id)\n const want = d.spec.socket\n if (want === undefined || d.spec.circuit) {\n plugs.set(key, null)\n } else if (want === 'auto') {\n plugs.set(key, null)\n autos.push({ o, d })\n } else {\n const s = sockets.find((x) => x.id === want) ?? sockets.find((x) => x.id === gid(o, want)) ?? sockets.find((x) => x.local === want)\n plugs.set(key, s ? s.id : null)\n if (s) used.add(s.id)\n }\n }\n }\n for (const { o, d } of autos) {\n const from = d.spec.plug ? toWorld(o, d.spec.plug) : originOf(o)\n let best: (typeof sockets)[number] | null = null\n let bestD = AUTO_RANGE\n for (const s of sockets) {\n if (used.has(s.id)) continue\n const dd = dist3(from, s.pos)\n if (dd <= bestD) {\n best = s\n bestD = dd\n }\n }\n if (best) {\n used.add(best.id)\n plugs.set(gid(o, d.spec.id), best.id)\n }\n }\n }\n\n function breaker(circuit: string): boolean {\n return breakers.get(circuit) ?? true\n }\n\n function devicePowered(o: ObjState, d: DeviceState): boolean {\n if (d.spec.electric === false) return true\n if (!grid) return false\n if (d.spec.circuit) return breaker(d.spec.circuit)\n if (d.spec.socket === undefined) return false\n const sid = plugs.get(gid(o, d.spec.id))\n if (!sid) return false\n const found = findGlobal(sid, (oo, local) => oo.spec.sockets?.find((s) => s.id === local))\n if (!found) return false\n return found.value.circuit ? breaker(found.value.circuit) : true\n }\n\n function getDevice(objectId: string, deviceId: string): { o: ObjState; d: DeviceState } | null {\n const o = objs.get(objectId)\n const d = o?.devices.get(deviceId)\n return o && d ? { o, d } : null\n }\n\n function powerSnapshot(): Map<string, boolean> {\n const m = new Map<string, boolean>()\n for (const o of objs.values()) for (const d of o.devices.values()) m.set(gid(o, d.spec.id), d.on && devicePowered(o, d))\n return m\n }\n\n function emitPowerChanges(before: Map<string, boolean>): void {\n for (const o of objs.values()) {\n for (const d of o.devices.values()) {\n const key = gid(o, d.spec.id)\n const now = d.on && devicePowered(o, d)\n if (before.get(key) !== now && d.on) emit({ type: 'device', object: o.id, device: d.spec.id, on: d.on, powered: devicePowered(o, d), channel: d.spec.kind === 'screen' ? d.channel : undefined })\n }\n }\n }\n\n function setDeviceOn(o: ObjState, d: DeviceState, on: boolean): void {\n d.on = on\n if (d.spec.part) setPartTarget(o, d.spec.part, on ? 1 : 0)\n const powered = devicePowered(o, d)\n emit({ type: 'device', object: o.id, device: d.spec.id, on, powered, channel: d.spec.kind === 'screen' ? d.channel : undefined })\n if (on && !powered) message('no_power')\n }\n\n function setDevice(objectId: string, deviceId: string, on: boolean): boolean {\n const f = getDevice(objectId, deviceId)\n if (!f) return false\n if (f.d.on !== on) setDeviceOn(f.o, f.d, on)\n return true\n }\n\n function setFixture(objectId: string, fixtureId: string, on: boolean): boolean {\n const fx = objs.get(objectId)?.fixtures.get(fixtureId)\n if (!fx) return false\n if (fx.on !== on) toggleFixture(objs.get(objectId) as ObjState, fixtureId)\n return fx.on === on\n }\n\n function setBurner(objectId: string, burnerId: string, on: boolean): boolean {\n const o = objs.get(objectId)\n const b = o?.burners.get(burnerId)\n if (!o || !b) return false\n const isOn = b.on || b.lit\n if (on === isOn) return true\n if (!on) return toggleBurner(o, burnerId)\n return b.spec.needsIgnition ? ignite(o, burnerId) : toggleBurner(o, burnerId)\n }\n\n function resolveDevice(o: ObjState, id: string): { o: ObjState; d: DeviceState } | null {\n if (id.includes(':')) {\n const f = findGlobal(id, (oo, local) => oo.devices.get(local))\n return f ? { o: f.o, d: f.value } : null\n }\n const local = o.devices.get(id)\n if (local) return { o, d: local }\n for (const oo of objs.values()) {\n const d = oo.devices.get(id)\n if (d) return { o: oo, d }\n }\n return null\n }\n\n function switchIsOn(o: ObjState, spec: { part?: string; controls: string[] }): boolean {\n if (spec.part && o.parts.has(spec.part)) return targetIsOpen(o.parts.get(spec.part) as PartState)\n return spec.controls.some((id) => resolveDevice(o, id)?.d.on)\n }\n\n function toggleSwitch(o: ObjState, id: string): boolean {\n const sw = o.spec.switches?.find((s) => s.id === id)\n if (!sw) return false\n const on = !switchIsOn(o, sw)\n if (sw.part) setPartTarget(o, sw.part, on ? 1 : 0)\n let unpowered = false\n for (const ref of sw.controls) {\n const r = resolveDevice(o, ref)\n if (!r) continue\n r.d.on = on\n if (r.d.spec.part) setPartTarget(r.o, r.d.spec.part, on ? 1 : 0)\n const powered = devicePowered(r.o, r.d)\n if (on && !powered) unpowered = true\n emit({ type: 'device', object: r.o.id, device: r.d.spec.id, on, powered })\n }\n emit({ type: 'switch', object: o.id, switch: sw.id, on })\n if (unpowered) message('no_power')\n return true\n }\n\n // ------------------------------------------------------------------ fuel\n function resolveFuel(o: ObjState, b: BurnerState): { o: ObjState; f: FuelState } | null {\n const want = b.spec.fuel\n if (want === 'auto') {\n const from = toWorld(o, b.spec.pos)\n let best: { o: ObjState; f: FuelState } | null = null\n let bestD = AUTO_RANGE\n for (const oo of objs.values()) {\n for (const f of oo.fuels.values()) {\n if (f.spec.kind !== 'gas') continue\n const d = dist3(from, originOf(oo))\n if (d <= bestD) {\n best = { o: oo, f }\n bestD = d\n }\n }\n }\n return best\n }\n if (want.includes(':')) {\n const f = findGlobal(want, (oo, local) => oo.fuels.get(local))\n return f ? { o: f.o, f: f.value } : null\n }\n const local = o.fuels.get(want)\n return local ? { o, f: local } : null\n }\n\n function valveOpen(o: ObjState, f: FuelState): boolean {\n const v = f.spec.valve\n if (!v || !o.parts.has(v)) return true\n return targetIsOpen(o.parts.get(v) as PartState)\n }\n\n function canBurn(b: BurnerState, ref: { o: ObjState; f: FuelState } | null): boolean {\n return !!ref && ref.f.level > 0 && valveOpen(ref.o, ref.f)\n }\n\n function isSolid(ref: { f: FuelState } | null): boolean {\n return !!ref && ref.f.spec.kind !== 'gas'\n }\n\n function emitBurner(o: ObjState, b: BurnerState): void {\n emit({ type: 'burner', object: o.id, burner: b.spec.id, on: b.on, lit: b.lit })\n }\n\n function extinguish(o: ObjState, b: BurnerState, turnOff: boolean): void {\n const ref = resolveFuel(o, b)\n const wasLit = b.lit\n b.lit = false\n if (turnOff) b.on = false\n if (b.spec.part) setPartTarget(o, b.spec.part, b.on ? 1 : 0)\n if (wasLit && isSolid(ref)) b.smoke = SMOKE_TAIL\n emitBurner(o, b)\n }\n\n function toggleBurner(o: ObjState, id: string): boolean {\n const b = o.burners.get(id)\n if (!b) return false\n if (b.on || b.lit) {\n extinguish(o, b, true)\n return true\n }\n if (b.spec.needsIgnition) return false\n const ref = resolveFuel(o, b)\n b.on = true\n b.lit = canBurn(b, ref)\n if (b.lit) b.smoke = 0\n if (b.spec.part) setPartTarget(o, b.spec.part, 1)\n emitBurner(o, b)\n if (!b.lit) message(ref && ref.f.level <= 0 ? 'empty' : 'no_gas')\n return true\n }\n\n function ignite(o: ObjState, id: string): boolean {\n const b = o.burners.get(id)\n if (!b || b.lit) return false\n const ref = resolveFuel(o, b)\n if (!canBurn(b, ref)) {\n message(ref && ref.f.level <= 0 ? 'empty' : 'no_gas')\n return false\n }\n b.on = true\n b.lit = true\n b.smoke = 0\n if (b.spec.part) setPartTarget(o, b.spec.part, 1)\n emitBurner(o, b)\n return true\n }\n\n function toggleFuel(o: ObjState, id: string): boolean {\n const f = o.fuels.get(id)\n if (!f || !f.spec.valve || !o.parts.has(f.spec.valve)) return false\n const p = o.parts.get(f.spec.valve) as PartState\n setPartTarget(o, f.spec.valve, targetIsOpen(p) ? 0 : 1)\n return true\n }\n\n // ------------------------------------------------------------------ water\n function resolveTank(o: ObjState, id: string | undefined): { o: ObjState; t: TankState } | null {\n const want = id === undefined || id === 'auto' ? defaultTank : id\n if (!want) return null\n const f = findGlobal(want, (oo, local) => oo.tanks.get(local))\n if (f) return { o: f.o, t: f.value }\n const local = o.tanks.get(want)\n return local ? { o, t: local } : null\n }\n\n function drawWater(o: ObjState, fx: FixtureState, liters: number): number {\n if (liters <= 0) return 0\n if (options.waterSupply) return Math.max(0, Math.min(liters, options.waterSupply.draw(gid(o, fx.spec.id), liters)))\n const tank = resolveTank(o, fx.spec.tank)\n if (!tank) return 0\n const got = Math.min(liters, tank.t.level)\n tank.t.level -= got\n return got\n }\n\n function emitFixture(o: ObjState, fx: FixtureState): void {\n emit({ type: 'fixture', object: o.id, fixture: fx.spec.id, on: fx.on, flowing: fx.flowing })\n }\n\n function flowOf(fx: FixtureState): number {\n return fx.spec.flow ?? FLOW_DEFAULTS[fx.spec.kind] ?? 6\n }\n\n function stepFixture(o: ObjState, fx: FixtureState, dt: number): void {\n if (!fx.on) return\n if (fx.spec.kind === 'flush') {\n fx.timer -= dt\n if (fx.timer <= 0) {\n fx.on = false\n fx.flowing = false\n fx.frac = 0\n if (fx.spec.part) setPartTarget(o, fx.spec.part, 0)\n emitFixture(o, fx)\n }\n return\n }\n if (dt <= 0) return\n const wanted = (flowOf(fx) / 60) * dt\n const got = drawWater(o, fx, wanted)\n const flowing = got > 1e-9\n fx.frac = wanted > 0 ? Math.min(1, got / wanted) : 0\n if (flowing !== fx.flowing) {\n fx.flowing = flowing\n emitFixture(o, fx)\n }\n }\n\n function toggleFixture(o: ObjState, id: string): boolean {\n const fx = o.fixtures.get(id)\n if (!fx) return false\n if (fx.on) {\n fx.on = false\n fx.flowing = false\n fx.frac = 0\n if (fx.spec.part) setPartTarget(o, fx.spec.part, 0)\n emitFixture(o, fx)\n return true\n }\n fx.on = true\n if (fx.spec.part) setPartTarget(o, fx.spec.part, 1)\n if (fx.spec.kind === 'flush') {\n const volume = fx.spec.volume ?? 6\n const got = drawWater(o, fx, volume)\n fx.flowing = got > 1e-9\n fx.frac = fx.flowing ? 1 : 0\n fx.timer = FLUSH_SECONDS\n if (!fx.flowing) {\n fx.on = false\n if (fx.spec.part) setPartTarget(o, fx.spec.part, 0)\n }\n } else {\n fx.flowing = false\n fx.frac = 0\n stepFixture(o, fx, 1 / 60)\n }\n emitFixture(o, fx)\n if (!fx.flowing) message('no_water')\n return true\n }\n\n // ------------------------------------------------------------------ seats\n function seatTaken(objectId: string, seatId: string): string | null {\n for (const [actor, s] of seats) if (s.object === objectId && s.seat === seatId) return actor\n return null\n }\n\n function stand(actor: string = DEFAULT_ACTOR): Vec3 | null {\n const s = seats.get(actor)\n if (!s) return null\n seats.delete(actor)\n const o = objs.get(s.object)\n const spec = o?.spec.seats?.find((x) => x.id === s.seat)\n emit({ type: 'seat', object: s.object, seat: s.seat, actor, seated: false })\n if (!o || !spec) return null\n return toWorld(o, spec.exit)\n }\n\n function sit(objectId: string, seatId: string, actor: string = DEFAULT_ACTOR): SeatResult | null {\n const o = objs.get(objectId)\n const seat = o?.spec.seats?.find((s) => s.id === seatId)\n if (!o || !seat) return null\n const holder = seatTaken(objectId, seatId)\n if (holder && holder !== actor) return null\n if (seats.has(actor) && !holder) stand(actor)\n seats.set(actor, { object: objectId, seat: seatId })\n const eye = seat.eye ?? (seat.pose === 'lie' ? 0.18 : 0.62)\n emit({ type: 'seat', object: objectId, seat: seatId, actor, seated: true })\n return { eye: toWorld(o, [seat.pos[0], seat.pos[1] + eye, seat.pos[2]]), yaw: o.public.transform.ry + seat.ry + Math.PI, pose: seat.pose }\n }\n\n // ------------------------------------------------------------------ soft volumes\n function push(pos: Vec3, radius: number, vel: Vec3): void {\n for (const o of objs.values()) {\n if (!o.soft.size) continue\n const tr = o.public.transform\n const lp = worldToLocal(tr, pos)\n const lv = rotY(vel, -tr.ry)\n for (const s of o.soft.values()) {\n const [w, h, d] = s.spec.size\n const hx = w / 2\n const hz = Math.max(d, 0.1) / 2\n const dx = Math.max(Math.abs(lp[0] - s.spec.anchor[0]) - hx, 0)\n const dz = Math.max(Math.abs(lp[2] - s.spec.anchor[2]) - hz, 0)\n if (Math.hypot(dx, dz) > radius) continue\n const top = tr.y + s.spec.anchor[1]\n if (pos[1] + ACTOR_HEIGHT < top - h || pos[1] > top) continue\n const cap = 8\n s.vax = clamp(s.vax - lv[2] * PUSH_GAIN, -cap, cap)\n s.vaz = clamp(s.vaz + lv[0] * PUSH_GAIN, -cap, cap)\n if (s.spec.kind === 'panel' && s.spec.part && lv[2] < -0.05 && lp[2] > s.spec.anchor[2]) setPartTarget(o, s.spec.part, 1)\n }\n }\n }\n\n function stepSoft(dt: number): void {\n const sub = Math.max(1, Math.ceil(dt / (1 / 120)))\n const h = dt / sub\n for (const o of objs.values()) {\n if (!o.soft.size) continue\n const wl = rotY([wind[0], 0, wind[1]], -o.public.transform.ry)\n for (const s of o.soft.values()) {\n const k = s.spec.stiffness ?? 30\n const c = s.spec.damping ?? 4\n const max = s.spec.maxAngle ?? 0.7\n const gain = s.spec.wind ?? (s.spec.kind === 'panel' ? 0 : 1)\n const gust = gain * (0.6 + 0.4 * Math.sin(time * 1.7 + s.phase)) * 0.1\n const fx = -wl[2] * gust\n const fz = wl[0] * gust\n for (let i = 0; i < sub; i++) {\n s.vax += (-k * s.ax - c * s.vax + fx) * h\n s.vaz += (-k * s.az - c * s.vaz + fz) * h\n s.ax += s.vax * h\n s.az += s.vaz * h\n }\n if (Math.abs(s.ax) > max) {\n s.ax = Math.sign(s.ax) * max\n s.vax = 0\n }\n if (Math.abs(s.az) > max) {\n s.az = Math.sign(s.az) * max\n s.vaz = 0\n }\n }\n }\n }\n\n // ------------------------------------------------------------------ damage\n function damage(objectId: string, target: string, amount: number, _kind?: string): { hp: number; destroyed: boolean } | null {\n const o = objs.get(objectId)\n if (o && options.destruction) {\n const pos = toWorld(o, [0, 0.5, 0])\n const type = _kind === 'gas' ? 'explosive' : _kind === 'fabric' ? 'slash' : 'blunt'\n const result = options.destruction.hitPart(objectId, target, { type, point: pos, energy: Math.max(0, amount), source: 'interactables' }) as { events?: Array<{ type?: string; part?: string }> } | null | undefined\n const destroyed = !!result?.events?.some((e) => e.type === 'fracture' && e.part === target)\n emit({ type: 'damage', object: objectId, target, hp: -1, destroyed })\n return { hp: -1, destroyed }\n }\n const st = o?.hp.get(target)\n if (!o || !st) return null\n if (st.hp <= 0) return { hp: 0, destroyed: true }\n const before = st.hp\n st.hp = Math.max(0, st.hp - Math.max(0, amount))\n const destroyed = st.hp <= 0\n emit({ type: 'damage', object: objectId, target, hp: st.hp, destroyed })\n const pos = toWorld(o, [0, 0.5, 0])\n const fuel = o.fuels.get(target)\n if (fuel && destroyed && fuel.spec.kind === 'gas' && fuel.level > 0) {\n emit({ type: 'explosion', object: objectId, pos, radius: 2 + fuel.level / 5 })\n fuel.level = 0\n }\n const tank = o.tanks.get(target)\n if (tank && before === st.max && st.hp < before) emit({ type: 'leak', object: objectId, target, pos })\n return { hp: st.hp, destroyed }\n }\n\n // ------------------------------------------------------------------ interactions\n function deriveInteractions(spec: ObjectSpec): InteractionSpec[] {\n const out: InteractionSpec[] = []\n const used = new Set<string>()\n const partPos = (id: string | undefined, fallback: Vec3): Vec3 => spec.parts?.find((p) => p.id === id)?.pivot ?? fallback\n const partLabel = (id: string | undefined): string => spec.parts?.find((p) => p.id === id)?.label ?? ''\n const claim = (id: string | undefined) => {\n if (id) used.add(id)\n }\n for (const d of spec.devices ?? []) {\n claim(d.part)\n const pos = d.part ? partPos(d.part, [0, 1, 0]) : (d.plug ?? [0, 1, 0])\n // a hard-wired lamp (circuit, no plug, no part to press) is driven by switches and `setDevice`: it never steals the interact key\n if (d.kind === 'lamp' && !d.part && !d.plug && d.electric !== false) continue\n out.push({ id: `device.${d.id}`, pos, action: { do: 'toggle_device', device: d.id }, label: partLabel(d.part) })\n if (d.kind === 'screen' && (d.channels ?? 1) > 1) out.push({ id: `channel.${d.id}`, pos, action: { do: 'cycle_device', device: d.id }, label: '' })\n }\n for (const s of spec.switches ?? []) {\n claim(s.part)\n out.push({ id: `switch.${s.id}`, pos: partPos(s.part, [0, 1.2, 0]), action: { do: 'toggle_switch', switch: s.id }, label: partLabel(s.part) })\n }\n const driven = new Set((spec.devices ?? []).map((d) => d.fixture))\n for (const f of spec.fixtures ?? []) {\n claim(f.part)\n if (driven.has(f.id)) continue\n out.push({ id: `fixture.${f.id}`, pos: f.part ? partPos(f.part, f.outlet) : f.outlet, action: { do: 'toggle_fixture', fixture: f.id }, label: partLabel(f.part) })\n }\n for (const b of spec.burners ?? []) {\n claim(b.part)\n const pos = b.part ? partPos(b.part, b.pos) : b.pos\n if (b.needsIgnition) out.push({ id: `ignite.${b.id}`, pos, action: { do: 'ignite', burner: b.id }, label: '' })\n out.push({ id: `burner.${b.id}`, pos, action: { do: 'toggle_burner', burner: b.id }, label: partLabel(b.part) })\n }\n for (const f of spec.fuels ?? []) {\n if (!f.valve) continue\n claim(f.valve)\n out.push({ id: `fuel.${f.id}`, pos: partPos(f.valve, [0, 0.5, 0]), action: { do: 'toggle_fuel', fuel: f.id }, label: partLabel(f.valve) })\n }\n for (const c of spec.containers ?? []) {\n if (!c.access) out.push({ id: `open.${c.id}`, pos: c.volume.center, action: { do: 'open_container', container: c.id }, label: '' })\n }\n for (const p of spec.parts ?? []) {\n if (used.has(p.id)) continue\n if (p.label) out.push({ id: `part.${p.id}`, pos: p.pivot, action: { do: 'toggle_part', part: p.id }, label: p.label })\n }\n for (const c of spec.containers ?? []) {\n if (c.access && !spec.parts?.find((p) => p.id === c.access)?.label) {\n out.push({ id: `open.${c.id}`, pos: partPos(c.access, c.volume.center), action: { do: 'open_container', container: c.id }, label: '' })\n }\n }\n for (const s of spec.seats ?? []) out.push({ id: `seat.${s.id}`, pos: s.pos, action: { do: 'sit', seat: s.id }, label: '' })\n return out\n }\n\n function typeName(o: ObjState): string {\n return table[`type.${o.spec.type}`] ?? humanize(o.spec.type)\n }\n\n function promptOf(o: ObjState, i: InteractionSpec): { label: string; verb: string; object: string } {\n const a = i.action\n let state: string | null = null\n let def = ''\n switch (a.do) {\n case 'toggle_part': {\n const p = o.parts.get(a.part)\n const open = !!p && targetIsOpen(p)\n state = open ? 'open' : 'closed'\n def = open ? 'prompt.close' : 'prompt.open'\n break\n }\n case 'open_container': {\n const c = containerOf(o, a.container)\n const p = c?.access ? o.parts.get(c.access) : undefined\n const open = p ? targetIsOpen(p) : false\n state = p ? (open ? 'open' : 'closed') : null\n def = open ? 'prompt.close' : 'prompt.open'\n break\n }\n case 'toggle_device': {\n const on = !!o.devices.get(a.device)?.on\n state = on ? 'on' : 'off'\n def = on ? 'prompt.turn_off' : 'prompt.turn_on'\n break\n }\n case 'toggle_switch': {\n const sw = o.spec.switches?.find((s) => s.id === a.switch)\n const on = !!sw && switchIsOn(o, sw)\n state = on ? 'on' : 'off'\n def = on ? 'prompt.turn_off' : 'prompt.turn_on'\n break\n }\n case 'toggle_breaker': {\n const on = breaker(a.circuit)\n state = on ? 'on' : 'off'\n def = on ? 'prompt.breaker_off' : 'prompt.breaker_on'\n break\n }\n case 'toggle_fixture': {\n const on = !!o.fixtures.get(a.fixture)?.on\n state = on ? 'on' : 'off'\n def = on ? 'prompt.turn_off' : 'prompt.turn_on'\n break\n }\n case 'toggle_burner': {\n const b = o.burners.get(a.burner)\n const on = !!b && (b.on || b.lit)\n state = on ? 'on' : 'off'\n def = on ? 'prompt.turn_off' : 'prompt.turn_on'\n break\n }\n case 'toggle_fuel': {\n const f = o.fuels.get(a.fuel)\n const open = !!f && valveOpen(o, f)\n state = open ? 'open' : 'closed'\n def = open ? 'prompt.close_valve' : 'prompt.open_valve'\n break\n }\n case 'take':\n def = 'prompt.take'\n break\n case 'read':\n def = 'prompt.read'\n break\n case 'ignite':\n def = 'prompt.light'\n break\n case 'cycle_device':\n def = 'prompt.change_channel'\n break\n case 'sit': {\n const seat = o.spec.seats?.find((s) => s.id === a.seat)\n const mine = seats.get(DEFAULT_ACTOR)\n def = mine && mine.object === o.id && mine.seat === a.seat ? 'prompt.get_up' : seat?.pose === 'lie' ? 'prompt.lie_down' : 'prompt.sit'\n break\n }\n }\n let key = def\n if (i.label) {\n if (state && table[`${i.label}.${state}`] !== undefined) key = `${i.label}.${state}`\n else if (table[i.label] !== undefined) key = i.label\n }\n const vars = { name: typeName(o), circuit: a.do === 'toggle_breaker' ? (a.name ?? a.circuit) : '' }\n const label = t(key, vars)\n // structured prompt: explicit `<key>.verb` / `<key>.object` entries win; otherwise the first word is the verb and the rest the object\n let verb: string\n let object: string\n if (table[`${key}.verb`] !== undefined) {\n verb = t(`${key}.verb`, vars)\n object = table[`${key}.object`] ? t(`${key}.object`, vars) : vars.name\n } else {\n const sp = label.indexOf(' ')\n verb = sp < 0 ? label : label.slice(0, sp)\n object = sp < 0 ? vars.name : label.slice(sp + 1)\n }\n return { label, verb, object }\n }\n\n /** Locale key of the reason an interaction cannot be used right now, or null when it can. */\n function unavailableReason(o: ObjState, i: InteractionSpec): string | null {\n const a = i.action\n if (!requirementMet(i)) return 'requires_open'\n switch (a.do) {\n case 'toggle_part': {\n const p = o.parts.get(a.part)\n return p && gated(o, p) ? 'requires_open' : null\n }\n case 'open_container': {\n const c = containerOf(o, a.container)\n const p = c?.access ? o.parts.get(c.access) : undefined\n return p && gated(o, p) ? 'requires_open' : null\n }\n case 'toggle_breaker': {\n const rocker = a.part ? o.parts.get(a.part) : undefined\n return rocker && gated(o, rocker) ? 'requires_open' : null\n }\n case 'take':\n case 'read':\n return accessible(o.id, a.container) ? null : 'requires_open'\n case 'ignite':\n return o.burners.get(a.burner)?.lit ? 'already_lit' : null\n case 'toggle_burner': {\n const b = o.burners.get(a.burner)\n return !b?.spec.needsIgnition || b.lit ? null : 'needs_ignition'\n }\n case 'cycle_device': {\n const d = o.devices.get(a.device)\n if (!d || !d.on) return 'turn_on_first'\n return devicePowered(o, d) ? null : 'no_power'\n }\n default:\n return null\n }\n }\n\n function requirementMet(i: InteractionSpec): boolean {\n if (!i.requires) return true\n const p = objs.get(i.requires.object)?.parts.get(i.requires.part)\n return !!p && targetIsOpen(p)\n }\n\n function interactablesOf(o: ObjState): Array<{ item: Interactable; spec: InteractionSpec; o: ObjState }> {\n return o.interactions.map((i) => {\n const id = gid(o, i.id)\n const p = promptOf(o, i)\n const item: Interactable = {\n id,\n object: o.id,\n kind: i.action.do,\n pos: toWorld(o, i.pos),\n radius: i.radius ?? DEFAULT_RADIUS,\n label: p.label,\n verb: p.verb,\n noun: p.object,\n available: true,\n act: (actor) => act(id, actor),\n }\n const reason = unavailableReason(o, i) ?? (options.canInteract?.(item, DEFAULT_ACTOR) === false ? 'locked' : null)\n if (reason) {\n item.available = false\n item.reason = reason\n }\n return { item, spec: i, o }\n })\n }\n\n function interactables(): Interactable[] {\n const out: Interactable[] = []\n for (const o of objs.values()) for (const e of interactablesOf(o)) out.push(e.item)\n return out\n }\n\n function target(eye: { x: number; y: number; z: number; yaw: number; pitch: number }, opts: TargetOptions = {}): Interactable | null {\n const reach = opts.reach ?? 1.8\n const cone = opts.cone ?? 0.45\n const dir: Vec3 = [-Math.sin(eye.yaw) * Math.cos(eye.pitch), Math.sin(eye.pitch), -Math.cos(eye.yaw) * Math.cos(eye.pitch)]\n let best: Interactable | null = null\n let bestScore = Infinity\n for (const o of objs.values()) {\n for (const e of interactablesOf(o)) {\n if (!e.item.available && !opts.includeUnavailable) continue\n if (opts.kinds && !opts.kinds.includes(e.item.kind)) continue\n if (opts.filter && !opts.filter(e.item)) continue\n const v: Vec3 = [e.item.pos[0] - eye.x, e.item.pos[1] - eye.y, e.item.pos[2] - eye.z]\n const d = Math.hypot(v[0], v[1], v[2])\n if (d > reach) continue\n const cos = d < 1e-6 ? 1 : clamp((v[0] * dir[0] + v[1] * dir[1] + v[2] * dir[2]) / d, -1, 1)\n const angle = Math.acos(cos)\n if (angle > cone) continue\n const score = (angle / cone) * 0.6 + (d / reach) * 0.4\n if (score < bestScore) {\n bestScore = score\n best = e.item\n }\n }\n }\n return best\n }\n\n function act(interactableId: string, actor: string = DEFAULT_ACTOR): boolean {\n let found: { item: Interactable; spec: InteractionSpec; o: ObjState } | null = null\n for (const o of objs.values()) {\n if (!interactableId.startsWith(o.id + ':')) continue\n const local = interactableId.slice(o.id.length + 1)\n if (!o.interactions.some((i) => i.id === local)) continue\n found = interactablesOf(o).find((e) => e.spec.id === local) ?? null\n if (found) break\n }\n if (!found) return false\n if (!requirementMet(found.spec)) return false\n if (options.canInteract?.(found.item, actor) === false) return false\n return execute(found.o, found.spec.action, actor)\n }\n\n function execute(o: ObjState, a: InteractionSpec['action'], actor: string): boolean {\n switch (a.do) {\n case 'toggle_part': {\n const p = o.parts.get(a.part)\n if (!p || gated(o, p)) return false\n setPartTarget(o, a.part, targetIsOpen(p) ? 0 : 1)\n return true\n }\n case 'open_container': {\n const c = containerOf(o, a.container)\n if (!c) return false\n if (c.access) return execute(o, { do: 'toggle_part', part: c.access }, actor)\n emit({ type: 'container', object: o.id, container: c.id, open: true })\n return true\n }\n case 'take': {\n if (!accessible(o.id, a.container)) return false\n const list = o.contents.get(a.container)\n if (!list) return false\n const slot = a.slot ?? list.findIndex((s) => s !== null)\n if (slot < 0 || !list[slot]) {\n message('empty')\n return false\n }\n return take(o.id, a.container, slot, actor) !== null\n }\n case 'read': {\n if (!accessible(o.id, a.container)) return false\n const stack = o.contents.get(a.container)?.[a.slot]\n if (!stack) {\n message('empty')\n return false\n }\n const key = typeof stack.data?.text === 'string' ? stack.data.text : null\n if (!key) return false\n message(key)\n return true\n }\n case 'toggle_device': {\n const d = o.devices.get(a.device)\n if (!d) return false\n setDeviceOn(o, d, !d.on)\n return true\n }\n case 'cycle_device': {\n const d = o.devices.get(a.device)\n if (!d || !d.on) return false\n if (!devicePowered(o, d)) {\n message('no_power')\n return false\n }\n d.channel = (d.channel + 1) % Math.max(1, d.spec.channels ?? 1)\n emit({ type: 'device', object: o.id, device: d.spec.id, on: true, powered: true, channel: d.channel })\n return true\n }\n case 'toggle_switch':\n return toggleSwitch(o, a.switch)\n case 'toggle_breaker': {\n const rocker = a.part ? o.parts.get(a.part) : undefined\n if (rocker && gated(o, rocker)) return false\n const on = !breaker(a.circuit)\n if (a.part) setPartTarget(o, a.part, on ? 1 : 0)\n world.power.setBreaker(a.circuit, on)\n return true\n }\n case 'toggle_fixture':\n return toggleFixture(o, a.fixture)\n case 'toggle_burner':\n return toggleBurner(o, a.burner)\n case 'ignite':\n return ignite(o, a.burner)\n case 'toggle_fuel':\n return toggleFuel(o, a.fuel)\n case 'sit': {\n const mine = seats.get(actor)\n if (mine && mine.object === o.id && mine.seat === a.seat) {\n stand(actor)\n return true\n }\n return sit(o.id, a.seat, actor) !== null\n }\n }\n }\n\n // ------------------------------------------------------------------ emitters, mirrors, colliders\n function emitters(): ActiveEmitter[] {\n const out: ActiveEmitter[] = []\n for (const o of objs.values()) {\n for (const e of o.spec.emitters ?? []) {\n let intensity = 0\n const b = o.burners.get(e.source)\n const fx = o.fixtures.get(e.source)\n const dev = o.devices.get(e.source)\n const fuel = o.fuels.get(e.source)\n if (b) {\n const ref = resolveFuel(o, b)\n const frac = ref ? clamp(ref.f.level / ref.f.spec.capacity, 0, 1) : 0\n if (b.lit) intensity = 0.35 + 0.65 * frac\n else if (e.kind === 'smoke' && b.smoke > 0) intensity = 0.6 * (b.smoke / SMOKE_TAIL)\n } else if (fx) {\n if (fx.on && fx.flowing) intensity = fx.frac\n } else if (dev) {\n if (dev.on && devicePowered(o, dev)) intensity = 1\n } else if (fuel) {\n const lit = [...o.burners.values()].some((bb) => bb.lit && resolveFuel(o, bb)?.f === fuel)\n if (lit) intensity = 0.35 + 0.65 * clamp(fuel.level / fuel.spec.capacity, 0, 1)\n }\n if (intensity <= 0) continue\n const dir = rotY(e.dir ?? [0, 1, 0], o.public.transform.ry)\n out.push({ id: gid(o, e.id), object: o.id, kind: e.kind, pos: toWorld(o, e.pos), dir, size: e.size ?? 0.3, ...(e.reach !== undefined ? { reach: e.reach } : {}), intensity: clamp(intensity, 0, 1) })\n }\n }\n return out\n }\n\n function mirrors(eye: Vec3, maxDistance = 10, count = 4) {\n const out: Array<{ id: string; center: Vec3; normal: Vec3; w: number; h: number; distance: number }> = []\n for (const o of objs.values()) {\n for (const m of o.spec.mirrors ?? []) {\n const center = toWorld(o, applyPart(o, m.part, m.center))\n const f = partFrame(o, m.part)\n const ln = f && f.angle !== 0 ? rotateAxis(m.normal, f.axis, f.angle) : m.normal\n const normal = rotY(ln, o.public.transform.ry)\n const len = Math.hypot(normal[0], normal[1], normal[2]) || 1\n const n: Vec3 = [normal[0] / len, normal[1] / len, normal[2] / len]\n const to: Vec3 = [eye[0] - center[0], eye[1] - center[1], eye[2] - center[2]]\n if (n[0] * to[0] + n[1] * to[1] + n[2] * to[2] <= 0) continue\n const distance = Math.hypot(to[0], to[1], to[2])\n if (distance > maxDistance) continue\n out.push({ id: gid(o, m.id), center, normal: n, w: m.w, h: m.h, distance })\n }\n }\n return out.sort((a, b) => a.distance - b.distance).slice(0, count)\n }\n\n function colliders(opts: ColliderOptions = {}): WorldCollider[] {\n const out: WorldCollider[] = []\n const fixed: WorldCollider[] = []\n for (const o of objs.values()) {\n const tr = o.public.transform\n for (const c of o.spec.colliders ?? []) {\n if (c.part && c.offWhenOpen && (o.parts.get(c.part)?.t ?? 0) > 0.5) continue\n let extra = 0\n if (c.part) {\n const f = partFrame(o, c.part)\n if (f && f.angle !== 0 && Math.abs(f.axis[1]) >= 0.5) extra = f.angle * Math.sign(f.axis[1])\n }\n const center = toWorld(o, applyPart(o, c.part, c.center))\n ;(c.part ? out : fixed).push({\n id: gid(o, c.id),\n object: o.id,\n cx: center[0],\n cz: center[2],\n hw: c.half[0],\n hd: c.half[2],\n ry: tr.ry + (c.ry ?? 0) + extra,\n y0: center[1] - c.half[1],\n y1: center[1] + c.half[1],\n })\n }\n }\n if (opts.merge) return [...mergeColliders(fixed, { gap: opts.gap, slack: opts.slack }), ...out]\n return [...fixed, ...out]\n }\n\n // ------------------------------------------------------------------ update\n function update(dt: number): void {\n if (!(dt > 0)) return\n time += dt\n for (const o of objs.values()) {\n for (const p of o.parts.values()) {\n if (p.t === p.target) continue\n if (gated(o, p) && p.target > p.t) continue // a gated part may still close\n const step = (p.spec.motion.speed ?? 2.5) * dt\n const next = p.t < p.target ? Math.min(p.target, p.t + step) : Math.max(p.target, p.t - step)\n writeT(o, p, next)\n if (next === p.target) emit({ type: 'part', object: o.id, part: p.spec.id, t: next, target: p.target })\n }\n }\n stepSoft(dt)\n for (const o of objs.values()) {\n for (const b of o.burners.values()) {\n if (b.lit) {\n const ref = resolveFuel(o, b)\n if (!ref || !valveOpen(ref.o, ref.f)) {\n extinguish(o, b, !!b.spec.needsIgnition)\n } else {\n ref.f.level = Math.max(0, ref.f.level - b.spec.rate * dt)\n if (ref.f.level <= 0) extinguish(o, b, !!b.spec.needsIgnition)\n }\n } else if (b.on && !b.spec.needsIgnition && canBurn(b, resolveFuel(o, b))) {\n // a gas knob left open without gas lights as soon as the bottle valve opens\n b.lit = true\n b.smoke = 0\n emitBurner(o, b)\n } else if (b.smoke > 0) {\n b.smoke = Math.max(0, b.smoke - dt)\n }\n }\n if (rain > 0) {\n for (const tk of o.tanks.values()) {\n if (tk.spec.rainArea) tk.level = Math.min(tk.spec.capacity, tk.level + ((rain * tk.spec.rainArea) / 3600) * dt)\n }\n }\n for (const tk of o.tanks.values()) {\n const st = o.hp.get(tk.spec.id)\n if (st && st.hp < st.max && tk.level > 0) {\n const rate = 0.5 + 2.5 * (1 - st.hp / st.max)\n tk.level = Math.max(0, tk.level - rate * dt)\n }\n }\n }\n for (const o of objs.values()) {\n for (const d of o.devices.values()) {\n const fx = d.spec.fixture ? o.fixtures.get(d.spec.fixture) : undefined\n if (!fx) continue\n const run = d.on && devicePowered(o, d)\n if (fx.on === run) continue\n fx.on = run\n if (!run) {\n fx.flowing = false\n fx.frac = 0\n emitFixture(o, fx)\n }\n }\n for (const fx of o.fixtures.values()) stepFixture(o, fx, dt)\n }\n }\n\n // ------------------------------------------------------------------ add / remove\n function add(id: string, spec: ObjectSpec, transform: Transform): WorldObject {\n if (objs.has(id)) throw new Error(`Object \"${id}\" already exists`)\n const pub: WorldObject = { id, spec, transform: { ...transform }, parts: {} }\n const o: ObjState = {\n id,\n public: pub,\n spec,\n parts: new Map(),\n contents: new Map(),\n devices: new Map(),\n fuels: new Map(),\n burners: new Map(),\n tanks: new Map(),\n fixtures: new Map(),\n soft: new Map(),\n hp: new Map(),\n interactions: spec.interactions ?? deriveInteractions(spec),\n }\n for (const p of spec.parts ?? []) {\n const t0 = clamp(p.t0 ?? 0, 0, 1)\n o.parts.set(p.id, { spec: p, t: t0, target: t0, maxT: 1 })\n pub.parts[p.id] = t0\n }\n for (const c of spec.containers ?? []) {\n let list: Array<ItemStack | null>\n if (c.contents) list = c.slots.map((_, i) => cloneStack(c.contents?.[i] ?? null))\n else if (c.loot) list = generateLoot(options.loot, c.loot, c.slots, `${seed}|${id}|${c.id}`, options.items)\n else list = c.slots.map(() => null)\n o.contents.set(c.id, list)\n }\n for (const d of spec.devices ?? []) {\n o.devices.set(d.id, { spec: d, on: !!d.on, channel: 0 })\n if (d.on && d.part) {\n const p = o.parts.get(d.part)\n if (p) {\n p.target = p.maxT\n writeT(o, p, p.maxT)\n }\n }\n }\n for (const f of spec.fuels ?? []) o.fuels.set(f.id, { spec: f, level: clamp(f.level ?? f.capacity, 0, f.capacity) })\n for (const b of spec.burners ?? []) o.burners.set(b.id, { spec: b, on: false, lit: false, smoke: 0 })\n for (const tk of spec.tanks ?? []) o.tanks.set(tk.id, { spec: tk, level: clamp(tk.level ?? tk.capacity, 0, tk.capacity) })\n for (const f of spec.fixtures ?? []) o.fixtures.set(f.id, { spec: f, on: false, flowing: false, frac: 0, timer: 0 })\n let n = 0\n for (const s of spec.soft ?? []) {\n o.soft.set(s.id, { spec: s, ax: 0, az: 0, vax: 0, vaz: 0, phase: (n++ * 2.399963) % (Math.PI * 2) })\n }\n for (const d of spec.damage ?? []) o.hp.set(d.target, { max: d.hp, hp: d.hp })\n objs.set(id, o)\n if (!defaultTankExplicit && defaultTank === null && o.tanks.size) defaultTank = gid(o, [...o.tanks.keys()][0])\n rebuildPlugs()\n return pub\n }\n\n function remove(id: string): void {\n const o = objs.get(id)\n if (!o) return\n for (const [actor, s] of [...seats]) if (s.object === id) seats.delete(actor)\n objs.delete(id)\n if (defaultTank && defaultTank.startsWith(id + ':')) defaultTank = null\n rebuildPlugs()\n }\n\n // ------------------------------------------------------------------ save / load\n function serialize(): WorldState {\n const objects: WorldState['objects'] = {}\n for (const o of objs.values()) {\n objects[o.id] = {\n parts: Object.fromEntries([...o.parts].map(([k, p]) => [k, p.t])),\n contents: Object.fromEntries([...o.contents].map(([k, v]) => [k, v.map(cloneStack)])),\n devices: Object.fromEntries([...o.devices].map(([k, d]) => [k, { on: d.on, channel: d.channel }])),\n fuels: Object.fromEntries([...o.fuels].map(([k, f]) => [k, { level: f.level, open: valveOpen(o, f) }])),\n burners: Object.fromEntries([...o.burners].map(([k, b]) => [k, { on: b.on, lit: b.lit }])),\n tanks: Object.fromEntries([...o.tanks].map(([k, tk]) => [k, tk.level])),\n fixtures: Object.fromEntries([...o.fixtures].map(([k, f]) => [k, f.on])),\n hp: Object.fromEntries([...o.hp].map(([k, h]) => [k, h.hp])),\n }\n }\n return {\n version: 1,\n objects,\n grid,\n breakers: Object.fromEntries(breakers),\n seats: Object.fromEntries([...seats].map(([a, s]) => [a, { object: s.object, seat: s.seat }])),\n defaultTank,\n }\n }\n\n function load(state: WorldState): void {\n for (const [id, st] of Object.entries(state.objects)) {\n const o = objs.get(id)\n if (!o) continue\n for (const [k, v] of Object.entries(st.parts)) {\n const p = o.parts.get(k)\n if (p) {\n // keep the limit found by fitSweep: a loaded save must not let a door open through a wall again\n p.target = clamp(v, 0, p.maxT)\n writeT(o, p, p.target)\n }\n }\n for (const [k, v] of Object.entries(st.contents)) {\n const c = containerOf(o, k)\n if (c) o.contents.set(k, c.slots.map((_, i) => cloneStack(v[i] ?? null)))\n }\n for (const [k, v] of Object.entries(st.devices)) {\n const d = o.devices.get(k)\n if (d) {\n d.on = v.on\n d.channel = v.channel\n }\n }\n for (const [k, v] of Object.entries(st.fuels)) {\n const f = o.fuels.get(k)\n if (f) f.level = v.level\n }\n for (const [k, v] of Object.entries(st.burners)) {\n const b = o.burners.get(k)\n if (b) {\n b.on = v.on\n b.lit = v.lit\n b.smoke = 0\n }\n }\n for (const [k, v] of Object.entries(st.tanks)) {\n const tk = o.tanks.get(k)\n if (tk) tk.level = v\n }\n for (const [k, v] of Object.entries(st.fixtures)) {\n const f = o.fixtures.get(k)\n if (f) {\n f.on = v\n f.flowing = false\n f.frac = 0\n f.timer = v && f.spec.kind === 'flush' ? FLUSH_SECONDS : 0\n }\n }\n for (const [k, v] of Object.entries(st.hp)) {\n const h = o.hp.get(k)\n if (h) h.hp = v\n }\n }\n grid = state.grid\n breakers.clear()\n for (const [k, v] of Object.entries(state.breakers)) breakers.set(k, v)\n seats.clear()\n for (const [a, s] of Object.entries(state.seats)) if (objs.has(s.object)) seats.set(a, { object: s.object, seat: s.seat })\n defaultTank = state.defaultTank\n defaultTankExplicit = true\n }\n\n // ------------------------------------------------------------------ public surface\n const world: World = {\n add,\n remove,\n get: (id) => objs.get(id)?.public,\n objects: () => [...objs.values()].map((o) => o.public),\n update,\n interactables,\n target,\n act,\n partT: (objectId, partId) => objs.get(objectId)?.parts.get(partId)?.t ?? 0,\n setDevice,\n setFixture,\n setBurner,\n setPart: (objectId, partId, targetT, instant) => {\n const o = objs.get(objectId)\n if (o) setPartTarget(o, partId, targetT, instant)\n },\n fitSweep,\n contents,\n accessible,\n take,\n put,\n slotPosition,\n power: {\n get grid() {\n return grid\n },\n set grid(on: boolean) {\n world.power.setGrid(on)\n },\n setGrid(on) {\n if (on === grid) return\n const before = powerSnapshot()\n grid = on\n emit({ type: 'power', grid })\n emitPowerChanges(before)\n },\n setBreaker(circuit, on) {\n if (breaker(circuit) === on) {\n breakers.set(circuit, on)\n return\n }\n const before = powerSnapshot()\n breakers.set(circuit, on)\n emitPowerChanges(before)\n },\n breaker,\n isPowered: (objectId, deviceId) => {\n const r = getDevice(objectId, deviceId)\n return r ? devicePowered(r.o, r.d) : false\n },\n isOn: (objectId, deviceId) => getDevice(objectId, deviceId)?.d.on ?? false,\n pluggedInto: (objectId, deviceId) => plugs.get(`${objectId}:${deviceId}`) ?? null,\n channel: (objectId, deviceId) => getDevice(objectId, deviceId)?.d.channel ?? 0,\n },\n fuelLevel: (objectId, fuelId) => objs.get(objectId)?.fuels.get(fuelId)?.level ?? 0,\n isLit: (objectId, burnerId) => objs.get(objectId)?.burners.get(burnerId)?.lit ?? false,\n water: {\n setDefaultTank(tankId) {\n defaultTank = tankId\n defaultTankExplicit = true\n },\n level(tankId) {\n return findGlobal(tankId, (oo, local) => oo.tanks.get(local))?.value.level ?? 0\n },\n refill(tankId, liters) {\n const f = findGlobal(tankId, (oo, local) => oo.tanks.get(local))\n if (!f) return 0\n const added = Math.max(0, Math.min(liters, f.value.spec.capacity - f.value.level))\n f.value.level += added\n return added\n },\n setRain(mm) {\n rain = Math.max(0, mm)\n },\n isFlowing: (objectId, fixtureId) => {\n const fx = objs.get(objectId)?.fixtures.get(fixtureId)\n return !!fx && fx.on && fx.flowing\n },\n },\n sit,\n stand,\n seatOf: (actor = DEFAULT_ACTOR) => {\n const s = seats.get(actor)\n return s ? { object: s.object, seat: s.seat } : null\n },\n push,\n sway: (objectId, softId) => {\n const s = objs.get(objectId)?.soft.get(softId)\n return s ? { ax: s.ax, az: s.az } : { ax: 0, az: 0 }\n },\n setWind: (x, z) => {\n wind = [x, z]\n },\n emitters,\n mirrors,\n colliders,\n damage,\n hp: (objectId, target) => (options.destruction ? null : (objs.get(objectId)?.hp.get(target)?.hp ?? null)),\n t,\n setLocale: (l) => {\n locale = l\n table = resolveStrings(locale, options.strings)\n },\n serialize,\n load,\n }\n return world\n}\n","import type { DamageType, DestructibleSpec, DestructionEvent, Hit, JointSpec, ObjectState, ToolKind, Vec3 } from './destruction'\n\n/**\n * What a game module implements for an object whose behaviour it owns (a vehicle with its own panel deformation, a creature, a machine). The\n * world (`DestructionWorld.register`) hosts it next to its own objects: raycast, shoot, explode, hit, disassemble, extinguish, update, state,\n * reset and `on` all route to it.\n *\n * Space: the impl receives hits in WORLD space and returns events in WORLD space (it owns its transform; the transform given to `register` or\n * `setTransform` is only used by the world for raycasts and blast range). Every event must carry `object === id` and name parts listed by\n * `describe()`.\n */\nexport interface DestructibleImpl {\n readonly id: string\n readonly name?: string\n /** Parts, joints and structure in the impl's local space, for raycast, inspector and log. Called often: keep it cheap. */\n describe(): DestructibleSpec\n /** Apply one hit (see `IMPACT_CONTRACT` for the fields per type) and return the events it caused. */\n hit(hit: Hit): DestructionEvent[]\n /** Advance fire, melting, collapse and other timed behaviour. */\n update?(dt: number): DestructionEvent[]\n state(): ObjectState\n reset?(): void\n /** Same contract as `DestructionWorld.disassemble`: progress 0..1, or -1 when the tool cannot undo the joint. */\n disassemble?(jointId: string, tool: ToolKind, dt: number): number\n extinguish?(partId?: string): void\n /** Optional: an animation moved a part; `position` / `rotation` (Euler XYZ, radians) are object-local. Keep raycast and hit shapes in sync. */\n setPartPose?(partId: string, position: Vec3, rotation?: Vec3): void\n /** Plain JSON of the impl's own state, stored in `DestructionSnapshot.impls`. */\n serialize?(): unknown\n load?(data: unknown): void\n}\n\n/** The fields a weapon or hazard must put in a `Hit`, per damage type. THE impact contract. */\nexport interface ImpactContract {\n required: string[]\n optional: string[]\n note: string\n}\n\nexport const IMPACT_CONTRACT: Record<DamageType, ImpactContract> = {\n ballistic: { required: ['type', 'point', 'direction', 'energy', 'caliber'], optional: ['space', 'source'], note: 'bullets and pellets: joules and diameter in millimetres' },\n blunt: { required: ['type', 'point', 'energy'], optional: ['direction', 'radius', 'space', 'source'], note: 'contact radius in metres (default 3 cm)' },\n slash: { required: ['type', 'point', 'energy'], optional: ['direction', 'radius', 'space', 'source'], note: 'axes, knives, machetes' },\n explosive: { required: ['type', 'point', 'energy', 'radius'], optional: ['space', 'source'], note: 'point is the centre of the blast, radius the range in metres' },\n fire: { required: ['type', 'point', 'temperature', 'radius'], optional: ['duration', 'space', 'source'], note: 'flame temperature in °C; duration in seconds (call every frame with `dt`)' },\n heat: { required: ['type', 'point', 'temperature', 'radius'], optional: ['duration', 'space', 'source'], note: 'heat without flame (cutting torch, hot plate)' },\n}\n\n/** Problems with a hit according to the impact contract (empty when it is valid). */\nexport const checkHit = (hit: Hit): string[] => {\n const c = IMPACT_CONTRACT[hit.type]\n if (!c) return [`unknown damage type \"${String(hit.type)}\"`]\n const out: string[] = []\n for (const f of c.required) {\n const v = (hit as unknown as Record<string, unknown>)[f]\n if (v === undefined || (Array.isArray(v) ? v.some((n) => !Number.isFinite(n)) : typeof v === 'number' && !Number.isFinite(v))) out.push(`${hit.type} hit needs \"${f}\"`)\n }\n return out\n}\n\nexport interface CheckOptions {\n /**\n * Ids of every material the impl may use (the contracts package does not know the materials of your world: pass the ids of\n * `world.materials`, or the built-in plus your own). When omitted, the material check is skipped.\n */\n materials?: Iterable<string>\n}\n\nconst finiteJson = (v: unknown, path: string, out: string[]) => {\n if (typeof v === 'number') {\n if (!Number.isFinite(v)) out.push(`${path} is not a finite number`)\n } else if (Array.isArray(v)) v.forEach((x, i) => finiteJson(x, `${path}[${i}]`, out))\n else if (v && typeof v === 'object') for (const [k, x] of Object.entries(v)) finiteJson(x, `${path}.${k}`, out)\n else if (typeof v === 'function' || typeof v === 'symbol' || typeof v === 'bigint') out.push(`${path} is not JSON`)\n}\n\n/**\n * Contract checker for the test room (it needs no world): `describe()` is valid, a 500 J ballistic hit at a part centre returns well-formed events of this impl, `state()`\n * matches `describe()`, hit points never go negative, `update(0.016)` returns an array and every event is JSON-serializable. It hits the impl\n * (and calls `reset()` afterwards when there is one).\n */\nexport const checkDestructible = (impl: DestructibleImpl, options: CheckOptions = {}): { ok: boolean; problems: string[] } => {\n const problems: string[] = []\n const known = options.materials ? new Set(options.materials) : null\n let spec: DestructibleSpec | undefined\n try {\n spec = impl.describe()\n } catch (e) {\n return { ok: false, problems: [`describe() threw: ${String(e)}`] }\n }\n if (!spec || !Array.isArray(spec.parts) || spec.parts.length === 0) return { ok: false, problems: ['describe() must return at least one part'] }\n const ids = new Set<string>()\n for (const p of spec.parts) {\n if (ids.has(p.id)) problems.push(`duplicate part id \"${p.id}\"`)\n ids.add(p.id)\n if (known && !known.has(p.material)) problems.push(`part \"${p.id}\" has unknown material \"${p.material}\"`)\n if (!p.shape || !['box', 'cylinder', 'sphere'].includes(p.shape.kind)) problems.push(`part \"${p.id}\" has no valid shape`)\n if (!Array.isArray(p.position) || p.position.length !== 3) problems.push(`part \"${p.id}\" has no position`)\n }\n const jointIds = new Set<string>()\n for (const j of (spec.joints ?? []) as JointSpec[]) {\n if (!ids.has(j.a) || !ids.has(j.b)) problems.push(`joint \"${j.id ?? `${j.a}~${j.b}`}\" references an unknown part`)\n const jid = j.id ?? `${j.a}~${j.b}`\n if (jointIds.has(jid)) problems.push(`duplicate joint id \"${jid}\"`)\n jointIds.add(jid)\n }\n const checkState = (label: string) => {\n let st: ObjectState\n try {\n st = impl.state()\n } catch (e) {\n problems.push(`state() threw ${label}: ${String(e)}`)\n return\n }\n const sids = st.parts.map((p) => p.id).sort().join(',')\n if (sids !== [...ids].sort().join(',')) problems.push(`state() part ids do not match describe() ${label}`)\n for (const p of st.parts) if (!(p.hp >= 0)) problems.push(`part \"${p.id}\" has negative or invalid hp ${label}`)\n }\n const checkEvents = (events: unknown, label: string) => {\n if (!Array.isArray(events)) {\n problems.push(`${label} must return an array`)\n return\n }\n const evs = events as DestructionEvent[]\n evs.forEach((e, i) => {\n if (e.object !== impl.id) problems.push(`${label} event ${i} (${e.type}) has object \"${String(e.object)}\", expected \"${impl.id}\"`)\n const part = (e as { part?: string }).part\n if (part !== undefined && !ids.has(part)) problems.push(`${label} event ${i} (${e.type}) names unknown part \"${part}\"`)\n })\n const bad: string[] = []\n finiteJson(evs, 'events', bad)\n problems.push(...bad.map((b) => `${label}: ${b}`))\n try {\n const s = JSON.stringify(evs)\n if (JSON.stringify(JSON.parse(s)) !== s) problems.push(`${label} events do not survive a JSON round trip`)\n } catch (e) {\n problems.push(`${label} events are not JSON-serializable: ${String(e)}`)\n }\n }\n checkState('before the hit')\n const target = spec.parts[0]\n try {\n const hit: Hit = { type: 'ballistic', point: [target.position[0], target.position[1], target.position[2]], direction: [0, 0, -1], energy: 500, caliber: 9 }\n checkEvents(impl.hit(hit), 'hit()')\n } catch (e) {\n problems.push(`hit() threw: ${String(e)}`)\n }\n checkState('after the hit')\n if (impl.update) {\n try {\n checkEvents(impl.update(0.016), 'update()')\n } catch (e) {\n problems.push(`update() threw: ${String(e)}`)\n }\n checkState('after update')\n }\n try {\n impl.reset?.()\n } catch (e) {\n problems.push(`reset() threw: ${String(e)}`)\n }\n return { ok: problems.length === 0, problems }\n}\n","/** The slots of a body an item can cover (the item slot vocabulary: game-items imports it from here). */\nexport type BodySlot = 'head' | 'eyes' | 'torso' | 'arms' | 'hands' | 'legs' | 'feet' | 'over'\n\n/** The 11 segments of the detailed body model (the Arsenal ids). */\nexport type SegmentKind = 'head' | 'jaw' | 'neck' | 'torso' | 'pelvis' | 'upperArm' | 'forearm' | 'hand' | 'thigh' | 'shin' | 'foot'\n\n/** The 6 regions of the crowd model (the game regions 0..5). */\nexport type BodyRegion = 'head' | 'torso' | 'armL' | 'armR' | 'legL' | 'legR'\n\n/** Bits of the `missing` mask of a body. The instanced body shader reads them, so the values are part of the contract. */\nexport const MISSING_BITS = {\n head: 1,\n armL: 2,\n armR: 4,\n legL: 8,\n legR: 16,\n armLBroken: 32,\n armRBroken: 64,\n legLBroken: 128,\n legRBroken: 256,\n jaw: 512,\n} as const\n","import type { DestructibleSpec, PartSpec } from './destruction'\n\nexport interface CheckSpecOptions {\n /** Known material ids. When given, every part's material must be one of them. */\n materials?: Iterable<string>\n}\n\nexport interface SpecReport {\n /** False when there is at least one problem (warnings do not count). */\n ok: boolean\n problems: string[]\n /** Things that are legal but probably wrong, e.g. structural parts that cannot reach an anchored part. */\n warnings: string[]\n}\n\nconst STRUCTURE_ROLES = ['foundation', 'column', 'beam', 'slab', 'wall', 'partition', 'roof', 'stair', 'none']\nconst BEARS = [true, false, 'a_on_b', 'b_on_a']\n\nconst finite = (n: unknown): n is number => typeof n === 'number' && Number.isFinite(n)\nconst positive = (n: unknown): boolean => finite(n) && n > 0\nconst vec3 = (v: unknown): boolean => Array.isArray(v) && v.length === 3 && v.every(finite)\nconst nonNegative = (n: unknown): boolean => n === undefined || (finite(n) && n >= 0)\n\nconst FACES = ['both', '+', '-']\nconst BONDS = ['running', 'stack']\n\n/** Layers, reinforcement, units and breach: known materials, finite positive sizes. */\nconst checkStagedFields = (p: PartSpec | undefined, label: string, materials: Set<string> | null, problems: string[]): void => {\n const known = (m: unknown, what: string): void => {\n if (materials && !materials.has(m as string)) problems.push(`${label} ${what} has unknown material \"${String(m)}\"`)\n }\n ;(p?.layers ?? []).forEach((l, i) => {\n known(l?.material, `layer ${i}`)\n if (!positive(l?.thickness)) problems.push(`${label} layer ${i} thickness must be finite and positive`)\n if (!FACES.includes(l?.faces)) problems.push(`${label} layer ${i} has an invalid faces \"${String(l?.faces)}\"`)\n })\n const r = p?.reinforcement\n if (r) {\n known(r.material, 'reinforcement')\n if (!positive(r.spacing) || !positive(r.diameter)) problems.push(`${label} reinforcement spacing and diameter must be finite and positive`)\n if (r.residualCapacity !== undefined && !(finite(r.residualCapacity) && r.residualCapacity >= 0 && r.residualCapacity <= 1)) problems.push(`${label} reinforcement residualCapacity must be between 0 and 1`)\n }\n const u = p?.units\n if (u) {\n known(u.mortar, 'units mortar')\n if (!vec3(u.size) || !u.size.every(positive)) problems.push(`${label} units size must be three finite positive numbers`)\n if (!BONDS.includes(u.bond)) problems.push(`${label} units has an invalid bond \"${String(u.bond)}\"`)\n }\n if (p?.breach && p.breach.area !== undefined && !positive(p.breach.area)) problems.push(`${label} breach area must be finite and positive`)\n}\n\n/**\n * Static checks on a `DestructibleSpec` (no world needed), for items that give a `spec` instead of an `impl`: unique part ids, known materials\n * (when `options.materials` is given), joints that reference existing, different parts, finite positive sizes, non-negative mass / hp / capacity,\n * valid structure roles and `bears` directions. A structural part with no path of joints to an anchored part is a warning, not a problem: it\n * is allowed, it just falls.\n */\nexport const checkSpec = (spec: DestructibleSpec, options: CheckSpecOptions = {}): SpecReport => {\n const problems: string[] = []\n const warnings: string[] = []\n const materials = options.materials ? new Set(options.materials) : null\n const parts = Array.isArray(spec?.parts) ? spec.parts : []\n if (!Array.isArray(spec?.parts) || parts.length === 0) problems.push('the spec needs at least one part')\n const ids = new Set<string>()\n for (const p of parts) {\n const id = String(p?.id ?? '')\n const label = `part \"${id}\"`\n if (id === '') problems.push('a part has no id')\n else if (ids.has(id)) problems.push(`duplicate part id \"${id}\"`)\n ids.add(id)\n if (materials && !materials.has(p?.material)) problems.push(`${label} has unknown material \"${String(p?.material)}\"`)\n else if (typeof p?.material !== 'string' || p.material === '') problems.push(`${label} needs a material`)\n const s = p?.shape\n if (s?.kind === 'box') {\n if (!Array.isArray(s.size) || s.size.length !== 3 || !s.size.every(positive)) problems.push(`${label} box size must be three finite positive numbers`)\n } else if (s?.kind === 'cylinder') {\n if (!positive(s.radius) || !positive(s.height)) problems.push(`${label} cylinder radius and height must be finite and positive`)\n } else if (s?.kind === 'sphere') {\n if (!positive(s.radius)) problems.push(`${label} sphere radius must be finite and positive`)\n } else problems.push(`${label} has an unknown shape`)\n if (!vec3(p?.position)) problems.push(`${label} needs a finite position [x, y, z]`)\n if (p?.rotation !== undefined && !vec3(p.rotation)) problems.push(`${label} has an invalid rotation`)\n for (const f of ['mass', 'hp', 'thickness'] as const) if (!nonNegative(p?.[f])) problems.push(`${label} ${f} must be a finite number >= 0`)\n if (p?.fill !== undefined && !(finite(p.fill) && p.fill >= 0 && p.fill <= 1)) problems.push(`${label} fill must be between 0 and 1`)\n if (p?.structure) {\n if (!STRUCTURE_ROLES.includes(p.structure.role)) problems.push(`${label} has an invalid structure role \"${String(p.structure.role)}\"`)\n if (!nonNegative(p.structure.capacity)) problems.push(`${label} structure capacity must be a finite number >= 0`)\n }\n if (p?.contains && !nonNegative(p.contains.liters)) problems.push(`${label} contains.liters must be a finite number >= 0`)\n checkStagedFields(p, label, materials, problems)\n }\n\n const jointIds = new Set<string>()\n const edges: Array<[string, string]> = []\n for (const j of spec?.joints ?? []) {\n const id = j.id ?? `${j.a}~${j.b}`\n const label = `joint \"${id}\"`\n if (jointIds.has(id)) problems.push(`duplicate joint id \"${id}\"`)\n jointIds.add(id)\n if (!ids.has(j.a)) problems.push(`${label} references unknown part \"${String(j.a)}\"`)\n if (!ids.has(j.b)) problems.push(`${label} references unknown part \"${String(j.b)}\"`)\n if (j.a === j.b) problems.push(`${label} joins part \"${String(j.a)}\" to itself`)\n if (j.bears !== undefined && !BEARS.includes(j.bears)) problems.push(`${label} has an invalid bears \"${String(j.bears)}\"`)\n if (!nonNegative(j.strength)) problems.push(`${label} strength must be a finite number >= 0`)\n if (!nonNegative(j.seconds)) problems.push(`${label} seconds must be a finite number >= 0`)\n if (j.bears !== false && ids.has(j.a) && ids.has(j.b) && j.a !== j.b) edges.push([j.a, j.b])\n }\n\n // structural parts must reach an anchored part over the joints (only when the spec lists its joints: otherwise they are inferred later)\n const structural = parts.filter((p) => p?.structure && p.structure.role !== 'none')\n if (structural.length && spec.joints) {\n const anchored = parts.filter((p) => p.anchored || p.structure?.role === 'foundation').map((p) => p.id)\n const adj = new Map<string, string[]>()\n for (const [a, b] of edges) {\n adj.set(a, [...(adj.get(a) ?? []), b])\n adj.set(b, [...(adj.get(b) ?? []), a])\n }\n const seen = new Set(anchored)\n const queue = [...anchored]\n while (queue.length) {\n for (const n of adj.get(queue.pop()!) ?? []) {\n if (seen.has(n)) continue\n seen.add(n)\n queue.push(n)\n }\n }\n const lost = structural.filter((p) => !seen.has(p.id)).map((p) => p.id)\n if (lost.length) warnings.push(`structural part(s) ${lost.map((i) => `\"${i}\"`).join(', ')} cannot reach an anchored part, so they will fall`)\n }\n return { ok: problems.length === 0, problems, warnings }\n}\n","import type { Hit, Vec3 } from './destruction'\n\n/**\n * A ballistic shot (one per pellet) as a weapon module produces it. Plain data: any damage model can consume it (`shotToHit` makes the `Hit`).\n */\nexport interface Shot {\n origin: Vec3\n /** Unit vector. */\n direction: Vec3\n /** Muzzle energy in joules. */\n energy: number\n /** Bullet diameter in millimetres. */\n caliber: number\n /** snake_case calibre id, e.g. `9x19`. */\n caliberId: string\n /** Muzzle speed in m/s. */\n speed: number\n /** Projectile mass in grams (one pellet for a shotgun load). */\n mass?: number\n /** Energy at a distance in metres, with the calibre's drag. */\n energyAt(distance: number): number\n pellet: number\n /** snake_case weapon id. */\n weapon: string\n source?: string\n}\n\n/** One use of a non-firearm (melee swing, flame tick, heat tick, throw, tool tick, extinguisher tick). */\nexport type Use =\n | { kind: 'melee'; damage: 'blunt' | 'slash'; energy: number; radius: number; reach: number; origin: Vec3; direction: Vec3 }\n | { kind: 'flame'; temperature: number; radius: number; range: number; cone: boolean; duration: number; origin: Vec3; direction: Vec3 }\n | { kind: 'heat'; temperature: number; radius: number; range: number; duration: number; origin: Vec3; direction: Vec3 }\n | {\n kind: 'throw'\n energy: number\n radius: number\n fuse: number\n velocity: Vec3\n origin: Vec3\n fire?: { temperature: number; radius: number; seconds: number }\n /** Explosive id (`m67`, `molotov`, `pg7v`...): the host looks the numbers up in the arsenal. Absent on a plain thrown object. */\n explosive?: string\n /** What sets it off: `timer` after `fuse` seconds, `impact` on the first hit once armed. */\n trigger?: 'timer' | 'impact'\n /** Metres the projectile must fly before an impact sets it off; closer, it hits without exploding (rocket launchers). */\n armDistance?: number\n /** Radius in metres of the wounding area (`radius` is the lethal one). */\n injuryRadius?: number\n /** Seconds the blast stuns whoever is inside the injury radius (flashbang). */\n stunSeconds?: number\n /** Seconds the thrower held it after pulling the pin: `fuse` is what was left of the full fuse when it left the hand. */\n cooked?: number\n /** Went off in the thrower's hand (held past the fuse): no velocity, `fuse` is 0 and the blast is at `origin`. */\n inHand?: boolean\n }\n /** An explosive set down where the trigger is pulled (mine, C4, charge): it waits for its trigger instead of flying. */\n | {\n kind: 'place'\n explosive: string\n /** `wire`: something trips it; `remote`: the player fires it; `timer`: after `fuse` seconds. */\n triggers: readonly ('timer' | 'wire' | 'remote')[]\n energy: number\n /** Lethal radius in metres. */\n radius: number\n injuryRadius: number\n /** Cone the blast goes through, in front of `direction` (mine); absent for a blast in every direction. */\n cone?: { halfAngleDeg: number; length: number }\n /** The wire a `wire` charge stretches from where it is set down: metres out, degrees from its facing (counter-clockwise from above) and metres above it. */\n tripwire?: { length: number; angleDeg: number; height: number }\n fuse?: number\n origin: Vec3\n direction: Vec3\n }\n /** The blast behind a rocket launcher: dangerous inside `radius` metres, in the cone around `direction` (pointing away from the target). */\n | { kind: 'backblast'; radius: number; halfAngleDeg: number; origin: Vec3; direction: Vec3 }\n | { kind: 'tool'; tool: string; reach: number; duration: number; origin: Vec3; direction: Vec3 }\n | { kind: 'extinguish'; range: number; coolC: number; duration: number; origin: Vec3; direction: Vec3 }\n | { kind: 'hand'; reach: number; origin: Vec3; direction: Vec3 }\n\n/**\n * The `Hit` a ballistic shot makes at `point` (world space): the energy is what is left of the shot at that distance from its origin\n * (`shot.energyAt`), the direction and calibre come from the shot. `normal` (the surface normal at the point, when the caller knows it) does not\n * change the hit; it is accepted so that callers can pass what their raycast returned and so that a stricter implementation could use it.\n */\nexport const shotToHit = (shot: Shot, point: Vec3, normal?: Vec3): Hit => {\n void normal\n const dx = point[0] - shot.origin[0]\n const dy = point[1] - shot.origin[1]\n const dz = point[2] - shot.origin[2]\n const distance = Math.hypot(dx, dy, dz)\n return {\n type: 'ballistic',\n point: [point[0], point[1], point[2]],\n direction: [shot.direction[0], shot.direction[1], shot.direction[2]],\n energy: shot.energyAt(distance),\n caliber: shot.caliber,\n ...(shot.mass === undefined ? {} : { mass: shot.mass }),\n source: shot.source ?? shot.weapon,\n }\n}\n","import type { Vec3 } from './destruction'\n\n/** Pose of one part (or of the whole item) at a key: position offset in metres and Euler XYZ rotation in radians, both relative to the rest pose. */\nexport interface AnimationPose {\n position?: Vec3\n rotation?: Vec3\n}\n\nexport interface AnimationKey {\n /** Seconds from the start of the clip. */\n t: number\n /** Pose of the item's root. */\n position?: Vec3\n rotation?: Vec3\n /** Poses of named parts: the key is a destruction part id (a pistol `reload` moves `mag`; a car door `open` rotates `door_l`). */\n parts?: Record<string, AnimationPose>\n}\n\nexport interface AnimationEventSpec {\n /** Seconds from the start of the clip. */\n t: number\n /** snake_case type the host maps (`sound`, `eject_casing`, `door_latch`...). */\n type: string\n data?: Record<string, unknown>\n}\n\n/** A use animation a module brings with its item. Poses between keys are interpolated by the player (the test room does it linearly). */\nexport interface AnimationClipSpec {\n /** snake_case: `reload`, `open`, `drink`... Unique within the item. */\n id: string\n /** Seconds. */\n duration: number\n keys: AnimationKey[]\n events?: AnimationEventSpec[]\n}\n\n/** What an item exposes when it brings its own animations. */\nexport interface ItemAnimationContract {\n animations: AnimationClipSpec[]\n}\n\nconst finite3 = (v: unknown): boolean => Array.isArray(v) && v.length === 3 && v.every((n) => typeof n === 'number' && Number.isFinite(n))\n\n/**\n * Problems with a clip (empty when it is valid): a snake_case id, a positive finite duration, at least one key, key and event times inside\n * `[0, duration]` and not going backwards, finite vectors, every named part one of `partIds`, event types that are non-empty strings and\n * JSON-serializable event data.\n */\nexport const checkAnimation = (clip: AnimationClipSpec, partIds: Iterable<string>): { ok: boolean; problems: string[] } => {\n const problems: string[] = []\n const parts = new Set(partIds)\n const id = String(clip?.id ?? '')\n if (!/^[a-z][a-z0-9_]*$/.test(id)) problems.push(`clip id \"${id}\" must be snake_case`)\n const label = `clip \"${id}\"`\n if (!(typeof clip?.duration === 'number' && Number.isFinite(clip.duration) && clip.duration > 0)) problems.push(`${label} needs a positive finite duration`)\n const dur = typeof clip?.duration === 'number' && clip.duration > 0 ? clip.duration : Infinity\n if (!Array.isArray(clip?.keys) || clip.keys.length === 0) {\n problems.push(`${label} needs at least one key`)\n return { ok: false, problems }\n }\n let prev = -Infinity\n clip.keys.forEach((k, i) => {\n if (!(typeof k.t === 'number' && Number.isFinite(k.t)) || k.t < 0 || k.t > dur + 1e-9) problems.push(`${label} key ${i} has t=${String(k.t)} outside 0..${dur}`)\n else if (k.t < prev) problems.push(`${label} key ${i} goes back in time (${k.t} < ${prev})`)\n else prev = k.t\n for (const f of ['position', 'rotation'] as const) if (k[f] !== undefined && !finite3(k[f])) problems.push(`${label} key ${i} has an invalid ${f}`)\n for (const [pid, pose] of Object.entries(k.parts ?? {})) {\n if (!parts.has(pid)) problems.push(`${label} key ${i} moves unknown part \"${pid}\"`)\n for (const f of ['position', 'rotation'] as const) if (pose?.[f] !== undefined && !finite3(pose[f])) problems.push(`${label} key ${i} part \"${pid}\" has an invalid ${f}`)\n }\n })\n let prevEv = -Infinity\n ;(clip.events ?? []).forEach((e, i) => {\n if (!(typeof e.t === 'number' && Number.isFinite(e.t)) || e.t < 0 || e.t > dur + 1e-9) problems.push(`${label} event ${i} has t=${String(e.t)} outside 0..${dur}`)\n else if (e.t < prevEv) problems.push(`${label} event ${i} goes back in time`)\n else prevEv = e.t\n if (typeof e.type !== 'string' || e.type === '') problems.push(`${label} event ${i} needs a type`)\n try {\n JSON.stringify(e.data ?? {})\n } catch {\n problems.push(`${label} event ${i} data is not JSON`)\n }\n })\n return { ok: problems.length === 0, problems }\n}\n","import type { AnimationClipSpec, AnimationEventSpec, AnimationPose } from './animation'\nimport { checkAnimation } from './animation'\nimport type { HostEvent } from './module'\n\n/** Clips a tool can bring, one per move of its cycle. A tool brings the ones it has; a missing clip is simply not played. */\nexport const TOOL_CLIP = {\n DRAW: 'draw',\n SHOT: 'shot',\n MISFIRE: 'misfire',\n EMPTY: 'empty',\n CYCLE: 'cycle',\n RELOAD: 'reload',\n FEED: 'feed',\n FAULT: 'fault',\n CLEAR: 'clear',\n SAFETY_ON: 'safety_on',\n SAFETY_OFF: 'safety_off',\n MODE: 'mode',\n /** A throwable with the pin out, held until it is thrown. */\n COOK: 'cook',\n /** The stock folds, unfolds, slides in or out (variants `fold`, `unfold`, `collapse`, `extend`). */\n STOCK: 'stock',\n /** A light or a laser is switched (variants `on`, `off`). */\n TOGGLE: 'toggle',\n} as const\nexport type ToolClipId = (typeof TOOL_CLIP)[keyof typeof TOOL_CLIP]\n\n/** What a renderer does when a rule event arrives. `variant` picks `<clip>_<variant>` when the tool has it, else `<clip>`. */\nexport type ToolAnimationStep =\n | { readonly type: 'play'; readonly clip: ToolClipId; readonly variant?: string; readonly duration?: number; readonly repeat?: number }\n /** Move the clip that is playing to the marker (a clip event `stage` with `data.stage`) the rule just reached. */\n | { readonly type: 'sync'; readonly stage: string }\n /** The rule says the phase is over: the clip jumps to its end if it is still running. */\n | { readonly type: 'finish'; readonly clip: ToolClipId }\n\nconst stockVariant = (event: Extract<HostEvent, { type: 'stock' }>): string => {\n const isFolding = event.kind === undefined ? false : event.kind.includes('fold')\n if (event.state === 'collapsed') return isFolding ? 'fold' : 'collapse'\n return isFolding ? 'unfold' : 'extend'\n}\n\n/** The move a host event asks of the tool in hand, or null when it has no motion. */\nexport const toolAnimationStep = (event: HostEvent): ToolAnimationStep | null => {\n switch (event.type) {\n case 'tool':\n return { type: 'play', clip: TOOL_CLIP.DRAW, ...(event.duration === undefined ? {} : { duration: event.duration }) }\n case 'shot':\n return { type: 'play', clip: TOOL_CLIP.SHOT, repeat: Math.max(1, event.rounds ?? 1) }\n case 'misfire':\n return { type: 'play', clip: TOOL_CLIP.MISFIRE }\n case 'empty':\n return { type: 'play', clip: TOOL_CLIP.EMPTY }\n case 'mode':\n return { type: 'play', clip: TOOL_CLIP.MODE, variant: event.mode }\n case 'fault':\n return { type: 'play', clip: TOOL_CLIP.FAULT, variant: event.fault }\n case 'clear':\n if (event.phase === 'end') return { type: 'finish', clip: TOOL_CLIP.CLEAR }\n return { type: 'play', clip: TOOL_CLIP.CLEAR, variant: event.fault, ...(event.duration === undefined ? {} : { duration: event.duration }) }\n case 'safety':\n return { type: 'play', clip: event.on ? TOOL_CLIP.SAFETY_ON : TOOL_CLIP.SAFETY_OFF }\n case 'cycle':\n if (event.phase === 'end') return { type: 'finish', clip: TOOL_CLIP.CYCLE }\n return { type: 'play', clip: TOOL_CLIP.CYCLE, ...(event.duration === undefined ? {} : { duration: event.duration }) }\n case 'reload':\n if (event.phase === 'end') return { type: 'finish', clip: TOOL_CLIP.RELOAD }\n return { type: 'play', clip: TOOL_CLIP.RELOAD, ...(event.kind === undefined ? {} : { variant: event.kind }), ...(event.duration === undefined ? {} : { duration: event.duration }) }\n case 'stage':\n return { type: 'sync', stage: event.stage }\n case 'feed':\n return { type: 'play', clip: TOOL_CLIP.FEED }\n case 'cook':\n if (event.phase === 'start') return { type: 'play', clip: TOOL_CLIP.COOK, duration: event.fuse }\n return { type: 'finish', clip: TOOL_CLIP.COOK }\n case 'stock':\n return { type: 'play', clip: TOOL_CLIP.STOCK, variant: stockVariant(event), ...(event.duration === undefined ? {} : { duration: event.duration }) }\n case 'toggle':\n return { type: 'play', clip: TOOL_CLIP.TOGGLE, variant: event.on ? 'on' : 'off' }\n default:\n return null\n }\n}\n\n/** Where a renderer puts the poses: every part of the tool by id (the ids the clips move), and the whole tool. Poses are offsets from rest. */\nexport interface ToolRig {\n setPartPose(partId: string, pose: AnimationPose): void\n setRootPose?(pose: AnimationPose): void\n}\n\n/** Clips by id, with the variants as `<clip>_<variant>`. */\nexport type ToolClipSet = Readonly<Record<string, AnimationClipSpec>>\n\n/** A renderer's tool animator: feed it the host events and the frame time. */\nexport interface ToolAnimator {\n handle(event: HostEvent): void\n update(dt: number): void\n /** Ids of the clips playing now. */\n readonly playing: readonly string[]\n dispose(): void\n}\n\nexport const STAGE_EVENT = 'stage'\n\n/** The clip with its times (keys and events) scaled so that it lasts `duration` seconds. */\nexport const scaleClip = (clip: AnimationClipSpec, duration: number): AnimationClipSpec => {\n const factor = clip.duration > 0 ? duration / clip.duration : 1\n return {\n ...clip,\n duration,\n keys: clip.keys.map((key) => ({ ...key, t: key.t * factor })),\n ...(clip.events ? { events: clip.events.map((event) => ({ ...event, t: event.t * factor })) } : {}),\n }\n}\n\nconst ZERO: [number, number, number] = [0, 0, 0]\nconst mix = (from: readonly number[], to: readonly number[], fraction: number): [number, number, number] => [\n (from[0] ?? 0) + ((to[0] ?? 0) - (from[0] ?? 0)) * fraction,\n (from[1] ?? 0) + ((to[1] ?? 0) - (from[1] ?? 0)) * fraction,\n (from[2] ?? 0) + ((to[2] ?? 0) - (from[2] ?? 0)) * fraction,\n]\n\n/** Pose of the whole tool (`partId` undefined) or of one part at `time`, linear between keys; a key that does not name it means rest. */\nexport const sampleClip = (clip: AnimationClipSpec, partId: string | undefined, time: number): { position: [number, number, number]; rotation: [number, number, number] } => {\n const points = clip.keys.map((key) => {\n const pose = partId === undefined ? key : key.parts?.[partId]\n return { t: key.t, position: pose?.position ?? ZERO, rotation: pose?.rotation ?? ZERO }\n })\n const first = points[0]\n if (!first || first.t > 0) points.unshift({ t: 0, position: ZERO, rotation: ZERO })\n const last = points[points.length - 1]\n if (!last) return { position: ZERO, rotation: ZERO }\n if (time >= last.t) return { position: mix(last.position, last.position, 0), rotation: mix(last.rotation, last.rotation, 0) }\n const index = Math.max(0, points.findIndex((point, i) => time >= point.t && time < (points[i + 1]?.t ?? Infinity)))\n const from = points[index]\n const to = points[index + 1]\n if (!from || !to) return { position: ZERO, rotation: ZERO }\n const fraction = to.t > from.t ? (time - from.t) / (to.t - from.t) : 0\n return { position: mix(from.position, to.position, fraction), rotation: mix(from.rotation, to.rotation, fraction) }\n}\n\n/** Problems with a clip set (empty when valid): each key is the clip id (or `<clip>_<variant>`), every clip passes `checkAnimation`, and a `stage` event names its stage. */\nexport const checkToolClips = (clips: ToolClipSet, partIds: Iterable<string>): { ok: boolean; problems: string[] } => {\n const parts = [...partIds]\n const problems: string[] = []\n for (const [key, clip] of Object.entries(clips)) {\n if (clip.id !== key) problems.push(`clip \"${key}\" has the id \"${clip.id}\"`)\n if (!(clip.duration > 0)) problems.push(`clip \"${key}\" has no duration`)\n problems.push(...checkAnimation(clip, parts).problems)\n for (const event of clip.events ?? []) if (event.type === STAGE_EVENT && typeof event.data?.stage !== 'string') problems.push(`clip \"${key}\" has a stage event without data.stage`)\n }\n return { ok: problems.length === 0, problems }\n}\n\ninterface Instance {\n readonly name: string\n readonly clip: AnimationClipSpec\n time: number\n delay: number\n fired: number\n}\n\nexport interface ToolClipPlayerOptions {\n clips: ToolClipSet\n rig: ToolRig\n /** Called for each clip event as its time passes (`eject_casing`, `drop_magazine`, `stage`...). */\n onEvent?(event: AnimationEventSpec, clip: string): void\n /** Seconds between the rounds of a `repeat` (a burst): default 0.1. */\n repeatInterval?(): number\n}\n\n/** The default player of a tool's clips: runs the steps of `toolAnimationStep` against a rig, scaled to the duration the rule gives. */\nexport interface ToolClipPlayer {\n apply(step: ToolAnimationStep): void\n update(dt: number): void\n readonly playing: readonly string[]\n}\n\nexport const createToolClipPlayer = (options: ToolClipPlayerOptions): ToolClipPlayer => {\n const { clips, rig, onEvent } = options\n let instances: Instance[] = []\n\n const find = (clip: string, variant?: string): { name: string; clip: AnimationClipSpec } | undefined => {\n const name = variant !== undefined && clips[`${clip}_${variant}`] ? `${clip}_${variant}` : clip\n const found = clips[name]\n return found ? { name, clip: found } : undefined\n }\n\n const render = (instance: Instance): void => {\n const time = Math.min(instance.time, instance.clip.duration)\n const root = sampleClip(instance.clip, undefined, time)\n if (instance.clip.keys.some((key) => key.position || key.rotation)) rig.setRootPose?.(root)\n const touched = new Set(instance.clip.keys.flatMap((key) => Object.keys(key.parts ?? {})))\n for (const id of touched) rig.setPartPose(id, sampleClip(instance.clip, id, time))\n }\n\n const fireEvents = (instance: Instance, upTo: number): void => {\n const events = instance.clip.events ?? []\n while (instance.fired < events.length && (events[instance.fired]?.t ?? Infinity) <= upTo + 1e-9) {\n const event = events[instance.fired]\n instance.fired += 1\n if (event) onEvent?.(event, instance.name)\n }\n }\n\n return {\n apply(step) {\n if (step.type === 'sync') {\n for (const instance of instances) {\n const marker = (instance.clip.events ?? []).find((event) => event.type === STAGE_EVENT && event.data?.stage === step.stage)\n if (marker && instance.time < marker.t) instance.time = marker.t\n }\n return\n }\n if (step.type === 'finish') {\n for (const instance of instances) {\n if (instance.name !== step.clip && !instance.name.startsWith(`${step.clip}_`)) continue\n fireEvents(instance, instance.clip.duration)\n instance.time = instance.clip.duration\n }\n return\n }\n const found = find(step.clip, step.variant)\n if (!found) return\n const clip = step.duration && step.duration > 0 ? scaleClip(found.clip, step.duration) : found.clip\n const interval = options.repeatInterval?.() ?? 0.1\n instances = instances.filter((existing) => existing.name !== found.name || existing.delay > 0)\n for (let round = 0; round < (step.repeat ?? 1); round++) {\n instances.push({ name: found.name, clip, time: 0, delay: round * interval, fired: 0 })\n }\n },\n update(dt) {\n for (const instance of instances) {\n const carried = instance.delay > 0 ? dt - instance.delay : dt\n if (instance.delay > 0) {\n instance.delay = Math.max(0, instance.delay - dt)\n if (instance.delay > 0) continue\n }\n instance.time += carried\n fireEvents(instance, instance.time)\n render(instance)\n }\n instances = instances.filter((instance) => instance.delay > 0 || instance.time < instance.clip.duration)\n },\n get playing() {\n return instances.map((instance) => instance.name)\n },\n }\n}\n","type PlainObject = Record<string, unknown>\ntype Entry = { readonly id: string }\n\n/** Keys that would reach the prototype of the result when a patch comes from parsed JSON. */\nconst UNSAFE_KEYS: ReadonlySet<string> = new Set(['__proto__', 'constructor', 'prototype'])\n\nconst isPlainObject = (value: unknown): value is PlainObject =>\n typeof value === 'object' && value !== null && !Array.isArray(value) && Object.getPrototypeOf(value) === Object.prototype\n\n/** Recursively optional; arrays and functions are replaced as a whole, objects are merged. */\nexport type DeepPartial<TValue> = TValue extends (...args: never[]) => unknown\n ? TValue\n : TValue extends readonly unknown[]\n ? TValue\n : TValue extends object\n ? { [TKey in keyof TValue]?: DeepPartial<TValue[TKey]> }\n : TValue\n\n/** Merges `patch` over `base`: plain objects merge field by field, arrays, functions and primitives replace. `undefined` in the patch is ignored. */\nexport const deepMerge = <TBase extends object>(base: TBase, patch: object | undefined): TBase => {\n if (!patch) return base\n const result: PlainObject = { ...(base as PlainObject) }\n for (const [key, value] of Object.entries(patch)) {\n if (value === undefined || UNSAFE_KEYS.has(key)) continue\n const current = result[key]\n result[key] = isPlainObject(current) && isPlainObject(value) ? deepMerge(current, value) : value\n }\n return result as TBase\n}\n\n/** The shipped entries with the ones from `extra` added or, when the id exists, replaced. */\nexport const mergeById = <TEntry extends Entry>(shipped: readonly TEntry[], extra: readonly TEntry[] | undefined): Map<string, TEntry> => {\n const entries = new Map<string, TEntry>()\n for (const entry of [...shipped, ...(extra ?? [])]) entries.set(entry.id, entry)\n return entries\n}\n\n/** Applies `patch` by id; a patch for an id that does not exist is ignored. */\nexport const applyPatches = <TEntry extends Entry>(entries: Map<string, TEntry>, patches: Readonly<Record<string, DeepPartial<TEntry> | Partial<TEntry>>> | undefined): void => {\n for (const [id, patch] of Object.entries(patches ?? {})) {\n const entry = entries.get(id)\n if (entry) entries.set(id, deepMerge(entry, patch))\n }\n}\n\nexport const removeIds = (entries: Map<string, unknown>, ids: readonly string[] | undefined): void => {\n for (const id of ids ?? []) entries.delete(id)\n}\n","import type { Vec3 } from './destruction'\n\n/**\n * The bench of a module: controls, layers and counters it declares as data. The host keeps the values, draws them in a generic way and hands\n * every change back through `ModuleHost.bench`. Nothing here is specific to a kind of module.\n */\nexport type ControlValue = number | boolean | string\n\nexport interface ChoiceOption {\n readonly id: string\n readonly name: string\n /** Heading the host lists the option under (`optgroup`, a grouped row of buttons). Options of a group must sit next to each other. */\n readonly group?: string\n}\n\ninterface ControlBase {\n /** snake_case, unique across the module's controls, layers and metrics. */\n readonly id: string\n /** Display name, already translated for the locale the host asked for. */\n readonly name: string\n readonly hint?: string\n readonly hidden?: boolean\n}\n\nexport interface NumberControl extends ControlBase {\n readonly kind: 'number'\n readonly min: number\n readonly max: number\n readonly step?: number\n readonly unit?: string\n readonly default: number\n}\n\nexport interface BooleanControl extends ControlBase {\n readonly kind: 'boolean'\n readonly default: boolean\n}\n\nexport interface ChoiceControl extends ControlBase {\n readonly kind: 'choice'\n readonly options: readonly ChoiceOption[]\n readonly default: string\n}\n\n/** A button: no value, only the press. */\nexport interface ActionControl extends ControlBase {\n readonly kind: 'action'\n}\n\nexport type ModuleControl = NumberControl | BooleanControl | ChoiceControl | ActionControl\n\n/** Something of the module the viewer turns on or off (smoke, flash, casings). */\nexport interface ModuleLayer {\n readonly id: string\n readonly name: string\n /** On unless `false`. */\n readonly default?: boolean\n}\n\n/** Pulled: the room calls read only when it samples (~4 Hz, or on TestRoom.metrics()). */\nexport interface ModuleMetric {\n readonly id: string\n readonly name: string\n readonly unit?: string\n /** Budget: the host shows a bar and warns past it. */\n readonly max?: number\n readonly digits?: number\n read(): number | string\n}\n\nexport type BenchChange =\n | { readonly kind: 'control'; readonly id: string; readonly value: ControlValue }\n | { readonly kind: 'layer'; readonly id: string; readonly on: boolean }\n | { readonly kind: 'action'; readonly id: string }\n\nexport interface ControlPatch {\n readonly hidden?: boolean\n readonly disabled?: boolean\n readonly options?: readonly ChoiceOption[]\n readonly value?: ControlValue\n}\n\n/** What the host lends a module that declares a bench: the current values and the changes. */\nexport interface ModuleBench {\n value(id: string): ControlValue | undefined\n layer(id: string): boolean\n /** Right after attach returns, the host sends one change per control (not actions) and per layer, in declaration order. */\n onChange(listener: (change: BenchChange) => void): () => void\n /** `value` sets without emitting (no echo loops); `options` falls back to the first option if the value is no longer offered. */\n patch(id: string, patch: ControlPatch): void\n /** Move the host camera (a near / middle / far choice). */\n look(eye: Vec3, target: Vec3): void\n /** Shows a sheet on the host's panel, or takes it down with `null`. A host without a sheet area ignores it. */\n sheet?(sheet: BenchSheet | null): void\n}\n\n/**\n * A card of text the module puts on the host's panel (the sheet of an effect, of a weapon): what it is, its numbers, its steps, its colours and,\n * optionally, a strip of segments over time. Names and texts are already translated for the host's locale.\n */\nexport interface BenchSheet {\n readonly kicker?: string\n readonly title: string\n readonly body?: string\n readonly facts?: readonly { readonly label: string; readonly value: string }[]\n readonly steps?: readonly { readonly at: string; readonly text: string }[]\n readonly swatches?: readonly { readonly color: string; readonly name: string }[]\n readonly note?: string\n /** A strip of named segments (seconds), with tick marks and a playhead that follows the module metric `metric`. */\n readonly timeline?: {\n readonly segments: readonly { readonly name: string; readonly start: number; readonly end: number; readonly color: string }[]\n readonly ticks: readonly number[]\n readonly metric: string\n }\n}\n\nexport interface BenchReport {\n readonly ok: boolean\n readonly problems: readonly string[]\n}\n\nexport interface BenchDeclaration {\n readonly controls?: readonly ModuleControl[]\n readonly layers?: readonly ModuleLayer[]\n readonly metrics?: readonly ModuleMetric[]\n}\n\nconst SNAKE_CASE = /^[a-z][a-z0-9_]*$/\nconst finite = (n: unknown): n is number => typeof n === 'number' && Number.isFinite(n)\n\nfunction checkControl(control: ModuleControl, problems: string[]): void {\n const label = `control \"${control.id}\"`\n if (control.kind === 'number') {\n if (!finite(control.min) || !finite(control.max) || control.min >= control.max) problems.push(`${label} needs min < max`)\n if (control.step !== undefined && !(finite(control.step) && control.step > 0)) problems.push(`${label} needs a step > 0`)\n if (!finite(control.default) || control.default < control.min || control.default > control.max) problems.push(`${label} default ${String(control.default)} is outside ${control.min}..${control.max}`)\n return\n }\n if (control.kind !== 'choice') return\n if (control.options.length === 0) {\n problems.push(`${label} needs at least one option`)\n return\n }\n const seen = new Set<string>()\n const groups = new Set<string>()\n let previousGroup: string | undefined\n for (const option of control.options) {\n if (seen.has(option.id)) problems.push(`${label} repeats option \"${option.id}\"`)\n seen.add(option.id)\n if (option.group !== undefined && (typeof option.group !== 'string' || option.group === '')) problems.push(`${label} option \"${option.id}\" has an empty group`)\n else if (option.group !== undefined && option.group !== previousGroup && groups.has(option.group)) problems.push(`${label} group \"${option.group}\" is split: its options must be next to each other`)\n if (typeof option.group === 'string' && option.group !== '') groups.add(option.group)\n previousGroup = option.group\n }\n if (!seen.has(control.default)) problems.push(`${label} default \"${control.default}\" is not among its options`)\n}\n\n/** snake_case ids unique across controls, layers and metrics; min < max; step > 0; default in range; options non-empty, unique, default among them, each group in one run; metric max > 0. */\nexport function checkBench(declared: BenchDeclaration): BenchReport {\n const problems: string[] = []\n const ids = new Set<string>()\n const claim = (kind: string, id: string): void => {\n if (!SNAKE_CASE.test(id)) problems.push(`${kind} id \"${id}\" must be snake_case`)\n if (ids.has(id)) problems.push(`duplicate id \"${id}\" across controls, layers and metrics`)\n ids.add(id)\n }\n for (const control of declared.controls ?? []) {\n claim('control', control.id)\n checkControl(control, problems)\n }\n for (const layer of declared.layers ?? []) claim('layer', layer.id)\n for (const metric of declared.metrics ?? []) {\n claim('metric', metric.id)\n if (metric.max !== undefined && !(finite(metric.max) && metric.max > 0)) problems.push(`metric \"${metric.id}\" needs a max > 0`)\n }\n return { ok: problems.length === 0, problems }\n}\n","/** The weather, light and ground as the world is right now. Written by whoever drives the weather, read by whoever reacts to it. */\nexport interface EnvironmentState {\n /** Rain in mm/h; 0 is dry. */\n readonly rain: number\n /** Wind in m/s along x and z, and its strength (the length of that vector). */\n readonly windX: number\n readonly windZ: number\n readonly windSpeed: number\n /** Strongest gust in m/s. */\n readonly gust: number\n /** Render fog far distance in metres. */\n readonly fogFar: number\n /** How far one can see for gameplay, in metres (not the render fog). */\n readonly visibility: number\n /** 0 is full daylight, 1 is the darkest night. */\n readonly nightFactor: number\n readonly temperatureC: number\n /** Wet ground, 0..1: rises with rain and dries after it stops. */\n readonly wetness: number\n}\n\nexport type EnvironmentKey = keyof EnvironmentState\n\n/** A calm dry day (the normal world, before anything went wrong). */\nexport const DEFAULT_ENVIRONMENT: EnvironmentState = {\n rain: 0,\n windX: 0,\n windZ: 0,\n windSpeed: 0,\n gust: 0,\n fogFar: 220,\n visibility: 220,\n nightFactor: 0,\n temperatureC: 20,\n wetness: 0,\n}\n\n/** The host's environment (`ModuleHost.environment`): a store the weather module writes to and the others read. */\nexport interface EnvironmentBus {\n get(): EnvironmentState\n /** Merges `patch` into the state; listeners hear it only when a value really changed. */\n set(patch: Partial<EnvironmentState>): void\n /** Hears every change with the keys that changed. Returns the unsubscribe function. */\n on(listener: (state: EnvironmentState, changed: readonly EnvironmentKey[]) => void): () => void\n}\n\n/** A plain store that implements the bus; the test room and tests use it, a game may bring its own. */\nexport function createEnvironmentBus(initial: Partial<EnvironmentState> = {}): EnvironmentBus {\n let state: EnvironmentState = { ...DEFAULT_ENVIRONMENT, ...initial }\n const listeners = new Set<(state: EnvironmentState, changed: readonly EnvironmentKey[]) => void>()\n return {\n get: () => state,\n set(patch) {\n const changed = (Object.keys(patch) as EnvironmentKey[]).filter((key) => patch[key] !== undefined && patch[key] !== state[key])\n if (changed.length === 0) return\n const next = { ...state } as { -readonly [Key in EnvironmentKey]: number }\n for (const key of changed) next[key] = patch[key] as number\n state = next\n for (const listener of [...listeners]) listener(state, changed)\n },\n on(listener) {\n listeners.add(listener)\n return () => void listeners.delete(listener)\n },\n }\n}\n","import { applyPatches, deepMerge, mergeById, removeIds } from '@adatechnology/game-contracts'\n\nimport { ITEM_CATEGORIES } from './categories'\nimport type { ItemsCatalog, ItemsOptions } from './catalog-types'\nimport { checkItems, findDuplicateIds } from './check-items'\nimport { DEFAULT_RULES } from './rules'\nimport type { RecipeDef } from './recipe-types'\nimport type { ContainerDef, ItemDef, PlaceDef, PoolEntry } from './types'\nimport type { UseEffectDef } from './use-types'\n\nconst LITRES_PER_CUBIC_METRE = 1000\n\n/** Fills what a pack leaves out: the volume comes from the size. */\nconst withDerivedFields = (item: ItemDef): ItemDef => (item.volume === undefined ? { ...item, volume: item.size[0] * item.size[1] * item.size[2] * LITRES_PER_CUBIC_METRE } : item)\n\nconst buildPools = (options: ItemsOptions, packs: NonNullable<ItemsOptions['packs']>): Map<string, readonly PoolEntry[]> => {\n const pools = new Map<string, readonly PoolEntry[]>()\n for (const source of [...packs, options]) for (const [key, entries] of Object.entries(source.pools ?? {})) pools.set(key, entries)\n const problems: string[] = []\n for (const source of [...packs, options]) {\n for (const [alias, key] of Object.entries(source.poolAliases ?? {})) {\n const entries = pools.get(key)\n if (entries) pools.set(alias, entries)\n else problems.push(`pool alias \"${alias}\" points to unknown pool \"${key}\"`)\n }\n }\n if (problems.length > 0) throw new Error(`game-items: the catalog is not consistent:\\n${problems.map((problem) => ` - ${problem}`).join('\\n')}`)\n return pools\n}\n\nconst groupBy = (items: Iterable<ItemDef>, keysOf: (item: ItemDef) => readonly string[]): Map<string, ItemDef[]> => {\n const groups = new Map<string, ItemDef[]>()\n for (const item of items) for (const key of keysOf(item)) groups.set(key, [...(groups.get(key) ?? []), item])\n return groups\n}\n\n/**\n * Create the catalog. Order: the packs in order (added or replaced by id), then `patch`, then `remove`, then `include`; categories, places and\n * containers are those of the packs plus the options, by id. Every inconsistency found is reported in one error.\n */\nexport const createItems = (options: ItemsOptions = {}): ItemsCatalog => {\n const packs = options.packs ?? []\n const items = mergeById([] as ItemDef[], packs.flatMap((pack) => pack.items))\n applyPatches<ItemDef>(items, options.patch)\n removeIds(items, options.remove)\n if (options.include) for (const [id, item] of items) if (!options.include(item)) items.delete(id)\n for (const [id, item] of items) items.set(id, withDerivedFields(item))\n\n const categories = mergeById(ITEM_CATEGORIES, [...packs.flatMap((pack) => pack.categories ?? []), ...(options.categories ?? [])])\n const places = mergeById<PlaceDef>([], [...packs.flatMap((pack) => pack.places ?? []), ...(options.places ?? [])])\n const containers = mergeById<ContainerDef>([], [...packs.flatMap((pack) => pack.containers ?? []), ...(options.containers ?? [])])\n const useEffects = [...mergeById<UseEffectDef>([], [...packs.flatMap((pack) => pack.useEffects ?? []), ...(options.useEffects ?? [])]).values()]\n const recipes = mergeById<RecipeDef>([], [...packs.flatMap((pack) => pack.recipes ?? []), ...(options.recipes ?? [])])\n const pools = buildPools(options, packs)\n const rules = deepMerge(DEFAULT_RULES, options.rules)\n\n const problems = [\n ...packs.flatMap((pack) => findDuplicateIds(`item in pack \"${pack.id}\"`, pack.items)),\n ...findDuplicateIds('category', options.categories),\n ...findDuplicateIds('place', options.places),\n ...findDuplicateIds('container', options.containers),\n ...findDuplicateIds('use effect', options.useEffects),\n ...findDuplicateIds('recipe', options.recipes),\n ...checkItems({ items, categories, places, containers, rules }),\n ]\n if (problems.length > 0) throw new Error(`game-items: the catalog is not consistent:\\n${problems.map((problem) => ` - ${problem}`).join('\\n')}`)\n\n const byCategory = groupBy(items.values(), (item) => [item.category])\n const byPlace = groupBy(items.values(), (item) => item.finds?.places ?? [])\n const byTag = groupBy(items.values(), (item) => item.tags ?? [])\n\n return {\n items,\n categories,\n places,\n containers,\n pools,\n useEffects,\n recipes,\n rules,\n has: (id) => items.has(id),\n get(id) {\n const item = items.get(id)\n if (!item) throw new Error(`game-items: unknown item \"${id}\"`)\n return item\n },\n list: () => [...items.values()],\n byCategory: (category) => [...(byCategory.get(category) ?? [])],\n byPlace: (place) => [...(byPlace.get(place) ?? [])],\n byTag: (tag) => [...(byTag.get(tag) ?? [])],\n }\n}\n","import type { CategoryDef } from './types'\n\n/** The 14 categories of the team's catalog; always registered. */\nexport const ITEM_CATEGORIES: readonly CategoryDef[] = [\n { id: 'food', name: 'Food' },\n { id: 'drink', name: 'Drink' },\n { id: 'medical', name: 'Medical' },\n { id: 'tools', name: 'Tools' },\n { id: 'melee', name: 'Melee' },\n { id: 'materials', name: 'Materials' },\n { id: 'clothing', name: 'Clothing' },\n { id: 'bags', name: 'Bags' },\n { id: 'electronics', name: 'Electronics' },\n { id: 'fuel', name: 'Fuel' },\n { id: 'outdoors', name: 'Outdoors' },\n { id: 'books', name: 'Books' },\n { id: 'collectibles', name: 'Collectibles' },\n { id: 'keys', name: 'Keys' },\n]\n","/**\n * Public types of @adatechnology/game-items.\n *\n * An `ItemDef` is a real-world thing (a can of beans, a hammer, a jacket) with its true size and weight; the rest of the fields are optional groups that\n * only the categories that need them fill (nutrition for food, protection for clothing, carry for bags). Units: metres, kilograms, litres, days.\n */\nimport type { BodySlot } from '@adatechnology/game-contracts'\nimport type { ItemDef as BaseItemDef } from '@adatechnology/game-interactables'\n\nimport type { RecipeDef } from './recipe-types'\nimport type { UseEffectDef } from './use-types'\n\nexport type { BaseItemDef }\n\nexport const RARITIES = ['common', 'uncommon', 'rare', 'very_rare', 'legendary', 'unique'] as const\nexport type Rarity = (typeof RARITIES)[number]\n\n/** The body slots an item covers: the vocabulary is `BodySlot` of game-contracts (`over` is a layer worn over the others, such as a coat or a vest). */\nexport type { BodySlot } from '@adatechnology/game-contracts'\nexport const BODY_SLOTS: readonly BodySlot[] = ['head', 'eyes', 'torso', 'arms', 'hands', 'legs', 'feet', 'over']\n\nexport const DURABILITY_KINDS = ['uses', 'portions', 'doses', 'hits', 'cuts', 'shots', 'condition', 'charges', 'seconds', 'days', 'infinite', 'container'] as const\nexport type DurabilityKind = (typeof DURABILITY_KINDS)[number]\n\n/** How long an item lasts, read from the source text (\"10 uses\", \"4 portions\", \"300 hits\", \"infinite\"). */\nexport interface Durability {\n kind: DurabilityKind\n amount?: number\n /** Source qualifier when the amount alone is not enough (for example the voltage of a battery). */\n per?: string\n}\n\n/** Id of a place where items turn up (house, hospital, farm...). Places are a registry: a pack or the game declares the ones it uses. */\nexport type PlaceTag = string\n\n/** Id of an item category. The 14 of `ITEM_CATEGORIES` are always present; a game adds its own through `createItems({ categories })`. */\nexport type ItemCategory = string\n\nexport interface CategoryDef {\n id: ItemCategory\n /** Display name in English; games translate by id. */\n name?: string\n}\n\nexport interface PlaceDef {\n id: PlaceTag\n name?: string\n}\n\n/**\n * Where items are found inside a place (a fridge, a drawer, a locker): which categories it draws from and how many stacks. The finds roll reads `count`,\n * `categories` (or `categoriesByPlace`, with `*` for any other place) and `places`; other fields of a pack's container are kept and ignored.\n */\nexport interface ContainerDef {\n id: string\n name?: string\n /** Places the container turns up in (`toLootTables` only); empty or missing means any. */\n places?: readonly PlaceTag[]\n /** Weight of each category when a stack is drawn for this container. */\n categories?: Readonly<Record<ItemCategory, number>>\n /** When `categories` is missing: the weights by place (a shop shelf stocks what the shop sells). */\n categoriesByPlace?: Readonly<Record<PlaceTag, Readonly<Record<ItemCategory, number>>>>\n /** Range of stacks a container holds when it is filled. */\n count?: readonly [number, number]\n}\n\n/** One thing an explicit pool can hold (a fridge: water bottle, milk, eggs...): `item` is the catalog id, `weight` the odds, `qty` the range. */\nexport interface PoolEntry {\n item: string\n weight: number\n qty: readonly [number, number]\n /** Supplies (food, water, medicine, tools) are what a fortified house stocks up on. */\n isSupply?: boolean\n}\n\nexport interface ItemDef extends BaseItemDef {\n category: ItemCategory\n /** The old household category (`kitchen`, `hygiene`, `office`...), `perishable` or `craft_only`. */\n tags?: readonly string[]\n rarity: Rarity\n /** Litres. Derived from `size` when the pack does not give it. */\n volume?: number\n durability?: Durability\n /** Days to spoil at room temperature. */\n shelfLife?: number\n portions?: number\n cookable?: boolean\n nutrition?: { satiety?: number; hydration?: number }\n /** Fractions 0..1 per attack, per body slot covered. */\n protection?: {\n slots: readonly BodySlot[]\n bite?: number\n scratch?: number\n warmth?: number\n /** Against projectiles (read by game-characters): `resistance` in penetration units; a stopped projectile does `blunt` of its damage, one that goes through `pass`. */\n ballistic?: { resistance: number; blunt?: number; pass?: number; consumable?: boolean }\n }\n carry?: { capacityKg: number; weightReduction: number; quickSlots: number; wheels?: boolean }\n /** Id of the weapon in the arsenal when the item is also one. */\n weapon?: string\n /** Id of the liquid (`game-fluids`) when the item holds one. */\n fluid?: { liquid: string; liters: number }\n uses?: readonly string[]\n finds?: { places: readonly PlaceTag[] }\n /** Battery-like items: share of the charge lost per month. */\n charge?: { lossPerMonth: number }\n /** Fuel-like items: after `afterDays` each use fails with probability `chance`. */\n agingFault?: { afterDays: number; chance: number }\n /** Key of the 3D model in `game-items-three`; without it a simple shape from `shape` is drawn. */\n model?: string\n}\n\n/** A bundle of content: items plus the categories, places and containers they rely on. */\nexport interface ItemPack {\n id: string\n items: readonly ItemDef[]\n categories?: readonly CategoryDef[]\n places?: readonly PlaceDef[]\n containers?: readonly ContainerDef[]\n /** What using an item does, in priority order (`resolveUse`). */\n useEffects?: readonly UseEffectDef[]\n recipes?: readonly RecipeDef[]\n /** Explicit pools of what a kind of furniture holds, by key (`fridge`, `sink`...); they win over the category roll of a container. */\n pools?: Readonly<Record<string, readonly PoolEntry[]>>\n /** Keys that share another key's pool (`garage_wardrobe` -> `wardrobe`). */\n poolAliases?: Readonly<Record<string, string>>\n}\n","import type { ItemRules } from './rules-types'\nimport type { CategoryDef, ContainerDef, ItemDef, PlaceDef } from './types'\nimport { BODY_SLOTS, DURABILITY_KINDS, RARITIES } from './types'\n\nexport interface ItemsParts {\n readonly items: ReadonlyMap<string, ItemDef>\n readonly categories: ReadonlyMap<string, CategoryDef>\n readonly places: ReadonlyMap<string, PlaceDef>\n readonly containers: ReadonlyMap<string, ContainerDef>\n readonly rules: ItemRules\n}\n\n/** Ids that appear more than once in a list a game passed in. */\nexport const findDuplicateIds = (kind: string, entries: readonly { readonly id: string }[] | undefined): string[] => {\n const seen = new Set<string>()\n const problems: string[] = []\n for (const { id } of entries ?? []) {\n if (seen.has(id)) problems.push(`${kind} \"${id}\" is listed more than once`)\n seen.add(id)\n }\n return problems\n}\n\nconst isFraction = (value: number | undefined): boolean => value === undefined || (value >= 0 && value <= 1)\nconst isPositive = (value: number): boolean => Number.isFinite(value) && value > 0\n\nconst checkItem = (item: ItemDef, { categories, places }: ItemsParts): string[] => {\n const problems: string[] = []\n const issue = (text: string): number => problems.push(`item \"${item.id}\" ${text}`)\n if (!categories.has(item.category)) issue(`has unknown category \"${item.category}\"`)\n if (!RARITIES.includes(item.rarity)) issue(`has unknown rarity \"${item.rarity}\"`)\n if (item.size.length !== 3 || !item.size.every(isPositive)) issue(`has an invalid size [${item.size.join(', ')}]`)\n if (!(item.weight >= 0) || !Number.isFinite(item.weight)) issue(`has a weight of ${item.weight} kg`)\n if (item.volume !== undefined && !isPositive(item.volume)) issue(`has a volume of ${item.volume} L`)\n if (item.shelfLife !== undefined && !isPositive(item.shelfLife)) issue(`has a shelf life of ${item.shelfLife} days`)\n if (item.portions !== undefined && !(Number.isInteger(item.portions) && item.portions > 0)) issue(`has ${item.portions} portions`)\n if (item.durability && !DURABILITY_KINDS.includes(item.durability.kind)) issue(`has unknown durability kind \"${item.durability.kind}\"`)\n const { protection } = item\n if (protection) {\n for (const slot of protection.slots) if (!BODY_SLOTS.includes(slot)) issue(`protects unknown body slot \"${slot}\"`)\n if (protection.slots.length === 0) issue('has protection but covers no body slot')\n if (![protection.bite, protection.scratch, protection.warmth].every(isFraction)) issue('has a protection value outside 0..1')\n }\n if (item.carry && !(item.carry.capacityKg > 0 && isFraction(item.carry.weightReduction))) issue('has an invalid carry (capacity above 0, reduction within 0..1)')\n if (places.size > 0) for (const place of item.finds?.places ?? []) if (!places.has(place)) issue(`is found in unknown place \"${place}\"`)\n return problems\n}\n\nconst checkContainer = (container: ContainerDef, { categories }: ItemsParts): string[] => {\n const problems: string[] = []\n for (const category of Object.keys(container.categories ?? {})) {\n if (!categories.has(category)) problems.push(`container \"${container.id}\" draws from unknown category \"${category}\"`)\n }\n const [low, high] = container.count ?? [0, 0]\n if (low < 0 || high < low) problems.push(`container \"${container.id}\" has an invalid count [${low}, ${high}]`)\n return problems\n}\n\nconst checkRules = ({ rarity, freshness, storage, carry, protection }: ItemRules): string[] => {\n const problems: string[] = []\n const hasNegativeWeight = RARITIES.some((id) => !(rarity.weights[id] >= 0))\n if (hasNegativeWeight || !RARITIES.some((id) => rarity.weights[id] > 0 && !rarity.fixedOnly.includes(id))) {\n problems.push('rules.rarity.weights must be non-negative with at least one rollable rarity above 0')\n }\n if (!(freshness.stale > 0 && freshness.stale < freshness.spoiled && freshness.spoiled < freshness.rotten)) problems.push('rules.freshness must rise: 0 < stale < spoiled < rotten')\n for (const [id, rule] of Object.entries(storage)) if (!isPositive(rule.multiplier) || (rule.limitDays !== undefined && !isPositive(rule.afterLimit ?? 0))) problems.push(`rules.storage \"${id}\" is invalid`)\n if (!(isPositive(carry.baseKg) && carry.perStrengthKg >= 0 && isPositive(carry.factor) && carry.encumbered > 0 && carry.overloaded > carry.encumbered)) problems.push('rules.carry is invalid')\n if (!(protection.cap > 0 && protection.cap <= 1 && isFraction(protection.tornShare))) problems.push('rules.protection is invalid')\n return problems\n}\n\n/** Every inconsistency of a catalog, one line each; empty when it is sound. */\nexport const checkItems = (parts: ItemsParts): string[] => [\n ...[...parts.items.values()].flatMap((item) => checkItem(item, parts)),\n ...[...parts.containers.values()].flatMap((container) => checkContainer(container, parts)),\n ...checkRules(parts.rules),\n]\n","import type { ItemRules } from './rules-types'\n\n/**\n * The numbers of the rules, from the team's Vale Cinzento delivery. `storage` was read by hand from its table (Validade e apodrecimento) so the\n * skeleton runs; the source test of the catalog tool proves it against the HTML (legendary and unique are never rolled: L276). Every field is an option of `createItems({ rules })`.\n */\nexport const DEFAULT_RULES: ItemRules = {\n rarity: {\n weights: { common: 60, uncommon: 28, rare: 9, very_rare: 2.5, legendary: 0.5, unique: 0 },\n fixedOnly: ['legendary', 'unique'],\n },\n freshness: { stale: 0.5, spoiled: 1, rotten: 1.5 },\n storage: {\n fridge: { multiplier: 0.33, needsPower: true },\n freezer: { multiplier: 0.1, needsPower: true },\n cooler: { multiplier: 0.5, limitDays: 2, afterLimit: 1 },\n delivery_bag: { multiplier: 0.8 },\n cellar: { multiplier: 0.66 },\n ambient: { multiplier: 1 },\n hot: { multiplier: 2 },\n },\n carry: { baseKg: 8, perStrengthKg: 2.5, factor: 1.2, encumbered: 1, overloaded: 1.5 },\n protection: { cap: 0.9, wear: { bite: 8, scratch: 3 }, tornShare: 0.25, repairMargin: 10 },\n aging: { thawShelfDays: { freezer: 2 } },\n inventory: { defaultSlots: 10, encumberedRunFactor: 0.75 },\n use: {\n freshness: {\n stale: { satietyFactor: 0.7, poisonChance: 0.1, morale: 0, isEdible: true },\n spoiled: { satietyFactor: 0.7, poisonChance: 0.5, morale: -20, isEdible: true },\n rotten: { satietyFactor: 0, poisonChance: 0, morale: 0, isEdible: false },\n },\n cookedPoisonFactor: 0.25,\n },\n spawn: {\n retailNew: true,\n retailPlaces: ['supermarket', 'pharmacy', 'mall', 'gas_station', 'gun_shop'],\n retailContainers: ['store_shelf', 'stockroom'],\n condition: { common: [30, 90], uncommon: [40, 90], rare: [50, 100], very_rare: [50, 100], legendary: [50, 100], unique: [50, 100] },\n ageShare: [0, 0.6],\n charge: [0.2, 1],\n fillable: ['fuel_jerrycan'],\n fill: [0, 0.6],\n },\n finds: {\n fallbackContainer: 'zombie_corpse',\n rollExcluded: ['ammo_7_62x39'],\n depletion: [\n { places: ['pharmacy', 'gun_shop', 'police_station'], perDay: 0.05, floor: 0.3 },\n { places: ['supermarket', 'gas_station'], perDay: 0.04, floor: 0.35 },\n { places: ['mall', 'hospital'], perDay: 0.025, floor: 0.5 },\n { places: ['house', 'apartment'], perDay: 0.01, floor: 0.7 },\n { places: ['farm', 'warehouse', 'mine', 'dam', 'lodge', 'church'], perDay: 0.005, floor: 0.85 },\n { places: ['military_base'], perDay: 0, floor: 1 },\n ],\n regionMultiplier: {},\n states: { normal: 'normal', fortified: 'fortified', abandoned: 'abandoned' },\n pool: {\n defaultFootprint: 0.5,\n offset: 1.5,\n perSquareMetre: 3,\n jitter: 1.5,\n min: 2,\n max: 5,\n fortifiedExtra: 2,\n supplyWeight: 2.5,\n supplyExtraQty: 1,\n abandonedEmptyChance: 0.4,\n abandonedKept: 1,\n junkChance: 0.5,\n junkItem: 'food_packaging',\n spoiledFoodItem: 'leftover_meal',\n coldContainers: ['geladeira', 'refrig_exp', 'freezer'],\n },\n },\n}\n","import { DEFAULT_RULES } from './rules'\nimport type { ItemRules, StorageId } from './rules-types'\nimport type { ItemDef } from './types'\n\nexport type Freshness = 'fresh' | 'stale' | 'spoiled' | 'rotten'\n\n/**\n * What an item remembers about its age. Nothing ticks: the account is closed lazily, when the item moves or someone looks at it.\n * Times are in days on the host's clock.\n */\nexport interface AgeState {\n /** Effective age: days at room temperature. */\n ageDays: number\n /** Time at which `ageDays` was last closed. */\n since: number\n storage: StorageId\n /** Time at which the item entered `storage` (a cooler only helps for its first days). */\n storedAt: number\n /** Replaces the item's shelf life (a thawed freezer leaves 2 days). */\n shelfLife?: number\n}\n\nexport interface AgeOptions {\n /** Whether the storage has power right now (fridge, freezer). Default true. */\n powered?: boolean\n rules?: ItemRules\n}\n\nconst storageRuleOf = (rules: ItemRules, storage: StorageId) => {\n const rule = rules.storage[storage]\n if (!rule) throw new Error(`game-items: unknown storage \"${storage}\"`)\n return rule\n}\n\n/** The multiplier of the age at one instant: `heldDays` is how long the item has been in `storage`. */\nexport const storageMultiplier = (storage: StorageId, options: AgeOptions & { heldDays?: number } = {}): number => {\n const { powered = true, rules = DEFAULT_RULES, heldDays = 0 } = options\n const rule = storageRuleOf(rules, storage)\n if (rule.needsPower && !powered) return 1\n if (rule.limitDays !== undefined && heldDays >= rule.limitDays) return rule.afterLimit ?? 1\n return rule.multiplier\n}\n\n/** Days of effective age accrued between `from` and `to` in a storage the item entered at `storedAt`. */\nconst accruedDays = (storage: StorageId, window: { storedAt: number; from: number; to: number }, options: AgeOptions): number => {\n const { powered = true, rules = DEFAULT_RULES } = options\n const rule = storageRuleOf(rules, storage)\n const elapsed = window.to - window.from\n if (elapsed <= 0) return 0\n if (rule.needsPower && !powered) return elapsed\n if (rule.limitDays === undefined) return elapsed * rule.multiplier\n const limitEnd = window.storedAt + rule.limitDays\n const early = Math.max(0, Math.min(window.to, limitEnd) - Math.max(window.from, window.storedAt))\n return early * rule.multiplier + (elapsed - early) * (rule.afterLimit ?? 1)\n}\n\n/** Closes the account up to `now`: `ageDays += (now - since) x multiplier`. Pure: returns the new state. */\nexport const advanceAge = (state: AgeState, now: number, options: AgeOptions = {}): AgeState => {\n const { powered = true, rules = DEFAULT_RULES } = options\n const rule = storageRuleOf(rules, state.storage)\n const thawDays = rules.aging.thawShelfDays[state.storage]\n const isThawing = rule.needsPower === true && !powered && thawDays !== undefined && state.shelfLife === undefined\n const base = isThawing ? { ...state, ageDays: 0, shelfLife: thawDays } : state\n const ageDays = base.ageDays + accruedDays(state.storage, { storedAt: state.storedAt, from: state.since, to: now }, options)\n return { ...base, ageDays, since: Math.max(now, state.since) }\n}\n\n/** Moves the item to another storage: closes the account in the old one, then the new multiplier applies from `now`. */\nexport const moveToStorage = (state: AgeState, now: number, storage: StorageId, options: AgeOptions = {}): AgeState => ({\n ...advanceAge(state, now, options),\n storage,\n storedAt: now,\n})\n\n/** Age as a share of the shelf life; 0 for an item that does not spoil. */\nexport const shelfRatio = (item: ItemDef, state: AgeState): number => {\n const shelfLife = state.shelfLife ?? item.shelfLife\n return shelfLife === undefined ? 0 : state.ageDays / shelfLife\n}\n\n/** `fresh`, `stale`, `spoiled` or `rotten` at 0.5, 1 and 1.5 of the shelf life (the rule's `freshness`). Closes the account up to `now` first. */\nexport const freshness = (item: ItemDef, state: AgeState, now: number, options: AgeOptions = {}): Freshness => {\n const { rules = DEFAULT_RULES } = options\n const ratio = shelfRatio(item, advanceAge(state, now, options))\n if (ratio >= rules.freshness.rotten) return 'rotten'\n if (ratio >= rules.freshness.spoiled) return 'spoiled'\n if (ratio >= rules.freshness.stale) return 'stale'\n return 'fresh'\n}\n\n/** Charge left (0..1) of a battery-like item: it loses `charge.lossPerMonth` of the full charge per 30 days of effective age. */\nexport const chargeLevel = (item: ItemDef, initialCharge: number, ageDays: number): number => {\n if (!item.charge) return initialCharge\n return Math.max(0, initialCharge - item.charge.lossPerMonth * (ageDays / 30))\n}\n\n/** True when one use of an old fuel-like item fails: past `agingFault.afterDays` each use fails with probability `chance`. Draws once, only when it can fail. */\nexport const failsToStart = (item: ItemDef, ageDays: number, random: () => number): boolean => {\n if (!item.agingFault || ageDays <= item.agingFault.afterDays) return false\n return random() < item.agingFault.chance\n}\n","import { DEFAULT_RULES } from './rules'\nimport type { ItemRules } from './rules-types'\nimport type { BodySlot, ItemDef } from './types'\n\nexport type AttackKind = 'bite' | 'scratch'\n\n/** A piece of clothing on a body: the item and its condition, 0 (torn) to 100 (new). */\nexport interface WornPiece {\n item: ItemDef\n condition: number\n}\n\nconst FULL_CONDITION = 100\n\nconst covers = (piece: WornPiece, slot: BodySlot): boolean => piece.item.protection?.slots.includes(slot) ?? false\n\n/** What one piece blocks of an attack: its value times its condition; a torn piece (condition 0) keeps `tornShare` of the value. */\nexport const pieceBlock = (piece: WornPiece, attack: AttackKind, rules: ItemRules = DEFAULT_RULES): number => {\n const value = piece.item.protection?.[attack] ?? 0\n const share = piece.condition <= 0 ? rules.protection.tornShare : piece.condition / FULL_CONDITION\n return value * share\n}\n\n/** Share of an attack on `slot` that clothing blocks: `1 - PROD(1 - value x condition)`, never above the cap (there is always some risk). */\nexport const blockChance = (pieces: readonly WornPiece[], slot: BodySlot, attack: AttackKind, rules: ItemRules = DEFAULT_RULES): number => {\n const unblocked = pieces.filter((piece) => covers(piece, slot)).reduce((product, piece) => product * (1 - pieceBlock(piece, attack, rules)), 1)\n return Math.min(rules.protection.cap, 1 - unblocked)\n}\n\n/** A blocked attack wears every piece that covers the slot and blocks something: bite -8, scratch -3 (never below 0). */\nexport const wearBlocked = (pieces: readonly WornPiece[], slot: BodySlot, attack: AttackKind, rules: ItemRules = DEFAULT_RULES): WornPiece[] =>\n pieces.map((piece) => {\n if (!covers(piece, slot) || pieceBlock(piece, attack, rules) <= 0) return piece\n return { ...piece, condition: Math.max(0, piece.condition - rules.protection.wear[attack]) }\n })\n\n/** A repair kit restores up to the maximum condition minus the margin (10); a piece already better is left alone. */\nexport const repairPiece = (piece: WornPiece, rules: ItemRules = DEFAULT_RULES, maxCondition: number = FULL_CONDITION): WornPiece => ({\n ...piece,\n condition: Math.max(piece.condition, maxCondition - rules.protection.repairMargin),\n})\n","import { DEFAULT_RULES } from './rules'\nimport type { ItemRules } from './rules-types'\nimport type { ItemDef } from './types'\n\nexport interface CarryEntry {\n item: ItemDef\n count: number\n}\n\nexport type LoadLevel = 'normal' | 'encumbered' | 'overloaded'\n\nexport interface LoadState {\n /** Load as a share of the maximum. */\n ratio: number\n level: LoadLevel\n /** Multiplier of running speed and breath. */\n runFactor: number\n canRun: boolean\n}\n\n/** What a character can carry, kg: `(8 + 2.5 x strength) x 1.2` with the default rules. */\nexport const maxLoadKg = (strength: number, rules: ItemRules = DEFAULT_RULES): number => (rules.carry.baseKg + rules.carry.perStrengthKg * strength) * rules.carry.factor\n\nconst sumKg = (entries: readonly CarryEntry[]): number => entries.reduce((total, entry) => total + entry.item.weight * entry.count, 0)\n\n/** Weight carried: what is outside the bag counts in full, what is inside counts times `(1 - weightReduction)`. */\nexport const carriedKg = (parts: { loose: readonly CarryEntry[]; packed?: readonly CarryEntry[]; weightReduction?: number }): number =>\n sumKg(parts.loose) + sumKg(parts.packed ?? []) * (1 - (parts.weightReduction ?? 0))\n\n/** Above 100% of the maximum, running and breath drop 25%; above 150% the character cannot run. */\nexport const loadState = (loadKg: number, maxKg: number, rules: ItemRules = DEFAULT_RULES): LoadState => {\n const ratio = maxKg > 0 ? loadKg / maxKg : Number.POSITIVE_INFINITY\n if (ratio > rules.carry.overloaded) return { ratio, level: 'overloaded', runFactor: 0, canRun: false }\n if (ratio > rules.carry.encumbered) return { ratio, level: 'encumbered', runFactor: rules.inventory.encumberedRunFactor, canRun: true }\n return { ratio, level: 'normal', runFactor: 1, canRun: true }\n}\n\n/** The bag of a character: how many item slots it has and how much it holds. */\nexport interface BagOption {\n slots: number\n capacityKg: number\n}\n\n/** The bag a bag item gives: its `carry.capacityKg` is the slot count the team's game reads from `cap`; the weight limit is the character's. */\nexport const bagOption = (bag: ItemDef | undefined, characterMaxKg: number, rules: ItemRules = DEFAULT_RULES): BagOption => ({\n slots: bag?.carry ? Math.round(bag.carry.capacityKg) : rules.inventory.defaultSlots,\n capacityKg: characterMaxKg,\n})\n\nexport type TakeResult = 'ok' | 'bag_full' | 'too_heavy'\n\n/** Whether `item` can go into the bag now: first the slots, then the weight. */\nexport const canTake = (item: ItemDef, bag: BagOption, used: { slots: number; loadKg: number }): TakeResult => {\n if (used.slots >= bag.slots) return 'bag_full'\n if (used.loadKg + item.weight > bag.capacityKg) return 'too_heavy'\n return 'ok'\n}\n","import type { Freshness } from './decay'\nimport { DEFAULT_RULES } from './rules'\nimport type { ItemRules } from './rules-types'\nimport type { ItemDef } from './types'\nimport type { UseEffectDef } from './use-types'\n\nexport interface UseContext {\n /** State of the food, from `freshness()`. Default `fresh`. */\n freshness?: Freshness\n /** The food was cooked: it keeps only `cookedPoisonFactor` of its poison chance. */\n isCooked?: boolean\n}\n\nexport interface NutritionResult {\n satiety: number\n hydration: number\n morale: number\n poisonChance: number\n isEdible: boolean\n}\n\nexport interface UseResult {\n useId: string\n effect: string\n params: Readonly<Record<string, unknown>>\n /** The item is spent (false for food too rotten to eat). */\n consumes: boolean\n /** Only for `consume_nutrition`. */\n nutrition?: NutritionResult\n}\n\nconst FRESH_NUTRITION = { satietyFactor: 1, poisonChance: 0, morale: 0, isEdible: true }\n\nconst nutritionOf = (item: ItemDef, context: UseContext, rules: ItemRules): NutritionResult => {\n const state = context.freshness ?? 'fresh'\n const effect = state === 'fresh' ? FRESH_NUTRITION : rules.use.freshness[state]\n const poisonShare = context.isCooked ? rules.use.cookedPoisonFactor : 1\n return {\n satiety: (item.nutrition?.satiety ?? 0) * effect.satietyFactor,\n hydration: item.nutrition?.hydration ?? 0,\n morale: effect.morale,\n poisonChance: effect.poisonChance * poisonShare,\n isEdible: effect.isEdible,\n }\n}\n\nconst findEffect = (item: ItemDef, effects: readonly UseEffectDef[]): UseEffectDef | undefined =>\n effects.find((entry) => entry.items?.includes(item.id)) ?? effects.find((entry) => entry.category?.includes(item.category))\n\n/**\n * What using `item` does, as data: the host applies it (the player, the needs, the world). Pure. The first effect that lists the item wins, then the first\n * that lists its category; `undefined` when nothing happens. Food past its best follows `rules.use.freshness`.\n */\nexport const resolveUse = (item: ItemDef, effects: readonly UseEffectDef[], context: UseContext = {}, rules: ItemRules = DEFAULT_RULES): UseResult | undefined => {\n const def = findEffect(item, effects)\n if (!def) return undefined\n const base = { useId: def.id, effect: def.effect, params: def.params ?? {}, consumes: def.consumes }\n if (def.effect !== 'consume_nutrition') return base\n const nutrition = nutritionOf(item, context, rules)\n return { ...base, consumes: def.consumes && nutrition.isEdible, nutrition }\n}\n","import type { ItemsCatalog } from './catalog-types'\nimport type { RecipeDef, RecipeInput, RecipeOutput } from './recipe-types'\n\nexport interface CraftContext {\n catalog: ItemsCatalog\n /** Count of each item the character has, by id. */\n inventory: ReadonlyMap<string, number>\n /** Litres of each fluid at hand, by fluid id. */\n fluids?: Readonly<Record<string, number>>\n /** Stations and things of the world that are near (`fire`, `table`, `soil`). */\n world?: ReadonlySet<string>\n /** Skill levels by id. Without it the skill requirement is ignored. */\n skills?: Readonly<Record<string, number>>\n /** Ids unlocked so far. Without it `unlockedBy` is ignored. */\n unlocked?: ReadonlySet<string>\n}\n\nexport interface CraftCheck {\n isPossible: boolean\n /** One entry per unmet requirement: `item:nails`, `any:salt|sugar`, `match:cookable`, `fluid:water`, `world:fire`, `tool:hammer|axe`, `skill:carpentry:2`, `unlock:magazine`. */\n missing: string[]\n}\n\nexport type Consumption = { item: string; count: number; meters?: number } | { fluid: string; liters: number }\n\nexport type CraftOutcome = { item: string; count: number } | { effect: string; params: Readonly<Record<string, unknown>>; text?: string }\n\nexport type CraftResult = { isCrafted: true; seconds: number; consumed: Consumption[]; output: CraftOutcome } | { isCrafted: false; missing: string[] }\n\nconst countOf = (context: CraftContext, id: string): number => context.inventory.get(id) ?? 0\n\n/** Ids that satisfy an item input, in the order they are used. */\nconst candidatesOf = (input: RecipeInput, context: CraftContext): string[] => {\n if (input.item !== undefined) return [input.item]\n if (input.any) return [...input.any]\n if (!input.match) return []\n const { category, cookable } = input.match\n return context.catalog.list().filter((item) => (category === undefined || item.category === category) && (cookable === undefined || item.cookable === cookable)).map((item) => item.id)\n}\n\nconst describeInput = (input: RecipeInput): string => {\n if (input.item !== undefined) return `item:${input.item}`\n if (input.any) return `any:${input.any.join('|')}`\n if (input.match) return `match:${input.match.category ?? 'cookable'}`\n if (input.fluid !== undefined) return `fluid:${input.fluid}`\n return `world:${(input.world ?? []).join('|')}`\n}\n\n/** Takes `needed` units from the candidates in order; returns what was taken, or undefined when there is not enough. */\nconst takeUnits = (candidates: readonly string[], needed: number, context: CraftContext): Consumption[] | undefined => {\n const taken: Consumption[] = []\n let remaining = needed\n for (const id of candidates) {\n if (remaining <= 0) break\n const count = Math.min(remaining, countOf(context, id))\n if (count > 0) taken.push({ item: id, count })\n remaining -= count\n }\n return remaining > 0 ? undefined : taken\n}\n\nconst consumptionFor = (input: RecipeInput, context: CraftContext): Consumption[] | undefined => {\n if (input.world) return input.world.some((thing) => context.world?.has(thing)) ? [] : undefined\n if (input.fluid !== undefined) {\n const liters = input.liters ?? 1\n return (context.fluids?.[input.fluid] ?? 0) >= liters ? [{ fluid: input.fluid, liters }] : undefined\n }\n const taken = takeUnits(candidatesOf(input, context), input.qty ?? 1, context)\n if (!taken || input.meters === undefined) return taken\n return taken.map((entry) => ('item' in entry ? { ...entry, meters: input.meters as number } : entry))\n}\n\nconst toolMissing = (recipe: RecipeDef, context: CraftContext): string[] =>\n recipe.tools.flatMap((tool) => {\n const missing: string[] = []\n if (tool.anyOf.length > 0 && !tool.anyOf.some((id) => countOf(context, id) > 0)) missing.push(`tool:${tool.anyOf.join('|')}`)\n if (tool.world && !tool.world.some((station) => context.world?.has(station))) missing.push(`world:${tool.world.join('|')}`)\n return missing\n })\n\nconst gateMissing = (recipe: RecipeDef, context: CraftContext): string[] => {\n const missing: string[] = []\n if (context.skills && recipe.skill && (context.skills[recipe.skill.id] ?? 0) < recipe.skill.level) missing.push(`skill:${recipe.skill.id}:${recipe.skill.level}`)\n if (context.unlocked && recipe.unlockedBy !== undefined && !context.unlocked.has(recipe.unlockedBy)) missing.push(`unlock:${recipe.unlockedBy}`)\n return missing\n}\n\n/** Whether the character can make the recipe now, and what is missing when not. Skill and `unlockedBy` are ignored when the host does not pass `skills` or `unlocked`. */\nexport const canCraft = (recipe: RecipeDef, context: CraftContext): CraftCheck => {\n const missing = [\n ...gateMissing(recipe, context),\n ...toolMissing(recipe, context),\n ...recipe.inputs.filter((input) => consumptionFor(input, context) === undefined).map(describeInput),\n ]\n return { isPossible: missing.length === 0, missing }\n}\n\nconst outcomeOf = (output: RecipeOutput, random: () => number): CraftOutcome => {\n if ('effect' in output) return { effect: output.effect, params: output.params, ...(output.text === undefined ? {} : { text: output.text }) }\n const [low, high] = output.qty\n return { item: output.item, count: low + Math.floor(random() * (high - low + 1)) }\n}\n\n/**\n * Makes the recipe: what is consumed and what comes out. Pure: the host takes the consumed things from its inventory and applies the output (an item is\n * added, an effect such as \"window with 200 life\" is the host's to handle). Draws one number only when the output quantity is a range.\n */\nexport const craft = (recipe: RecipeDef, context: CraftContext, random: () => number): CraftResult => {\n const check = canCraft(recipe, context)\n if (!check.isPossible) return { isCrafted: false, missing: check.missing }\n const consumed = recipe.inputs.flatMap((input) => consumptionFor(input, context) ?? [])\n return { isCrafted: true, seconds: recipe.seconds, consumed, output: outcomeOf(recipe.output, random) }\n}\n","import type { DepletionRule } from '../rules-types'\nimport type { ItemRules } from '../rules-types'\nimport type { PlaceTag } from '../types'\n\n/** Share of the normal stock a place still has `day` days into the outbreak: `max(floor, 1 - perDay x day)`; 1 on day 0 and where no rule names the place. */\nexport const depletionFactor = (place: PlaceTag, day: number, rules: ItemRules): number => {\n if (day <= 0) return 1\n const rule: DepletionRule | undefined = rules.finds.depletion.find((entry) => entry.places.includes(place))\n return rule ? Math.max(rule.floor, 1 - rule.perDay * day) : 1\n}\n\n/** The count of stacks after the days of the outbreak and the region: the roll is drawn first, so day 0 and an unknown region leave it as it was. */\nexport const scaleCount = (count: number, scale: { place: PlaceTag; day: number; region?: string }, rules: ItemRules): number => {\n const region = scale.region === undefined ? 1 : (rules.finds.regionMultiplier[scale.region] ?? 1)\n return Math.round(count * depletionFactor(scale.place, scale.day, rules) * region)\n}\n","import type { ItemsCatalog } from '../catalog-types'\nimport type { ItemCategory, ItemDef, PlaceTag } from '../types'\n\n/** The items of `category` a roll can draw in `place`: no fixed-spot rarity, nothing excluded; when none lists the place, every one of the category (the game's recuo). */\nexport const rollableItems = (catalog: ItemsCatalog, category: ItemCategory, place: PlaceTag): ItemDef[] => {\n const { rules } = catalog\n const rollable = catalog.byCategory(category).filter((item) => !rules.rarity.fixedOnly.includes(item.rarity) && !rules.finds.rollExcluded.includes(item.id))\n const here = rollable.filter((item) => item.finds?.places.includes(place))\n return here.length > 0 ? here : rollable\n}\n\nexport const rarityWeight = (catalog: ItemsCatalog, item: ItemDef): number => catalog.rules.rarity.weights[item.rarity]\n","import type { ItemsCatalog } from '../catalog-types'\nimport type { ItemCategory } from '../types'\n\nimport { scaleCount } from './depletion'\nimport { rarityWeight, rollableItems } from './rarity-pool'\nimport type { FindsQuery } from './types'\n\nconst pickCategory = (weights: Readonly<Record<ItemCategory, number>>, random: () => number): ItemCategory | undefined => {\n let remaining = random()\n const categories = Object.keys(weights)\n for (const category of categories) {\n remaining -= weights[category] as number\n if (remaining <= 0) return category\n }\n return categories[0]\n}\n\n/**\n * Port of the team game's `rollItems` (jogo.js L68796-68812) on the container table (`CONT_TAB`) and the rarity weights (`RAR_W`).\n *\n * Order of the random draws, the contract the golden test holds: one for the count; then for each stack one to pick the category, and (unless the category\n * has nothing to draw) one to pick the item among those of the place, by rarity weight. Nothing else draws. The count is scaled by the day and the region\n * after it is drawn, so day 0 gives exactly the game's rolls. Returns the item ids, one per stack.\n */\nexport const rollByCategory = (catalog: ItemsCatalog, query: FindsQuery): string[] => {\n const { rules } = catalog\n const table = catalog.containers.get(query.container) ?? catalog.containers.get(rules.finds.fallbackContainer)\n if (!table) return []\n const [low, high] = table.count ?? [0, 0]\n const drawn = low + Math.floor(query.rng() * (high - low + 1))\n const count = scaleCount(drawn, { place: query.place, day: query.day ?? 0, ...(query.region === undefined ? {} : { region: query.region }) }, rules)\n const weights = table.categories ?? table.categoriesByPlace?.[query.place] ?? table.categoriesByPlace?.['*']\n if (!weights) return []\n\n const picked: string[] = []\n for (let stack = 0; stack < count; stack++) {\n const category = pickCategory(weights, query.rng)\n const pool = category === undefined ? [] : rollableItems(catalog, category, query.place)\n if (pool.length === 0) continue\n const total = pool.reduce((sum, item) => sum + rarityWeight(catalog, item), 0)\n let remaining = query.rng() * total\n for (const item of pool) {\n remaining -= rarityWeight(catalog, item)\n if (remaining <= 0) {\n picked.push(item.id)\n break\n }\n }\n }\n return picked\n}\n","import type { ItemRules } from '../rules-types'\nimport type { FindState } from '../rules-types'\nimport type { PoolEntry } from '../types'\n\nimport type { FindsQuery } from './types'\n\nexport interface PoolPick {\n itemId: string\n count: number\n /** The pool entry it came from; none for the junk an abandoned container leaves. */\n entry?: PoolEntry\n}\n\ninterface Candidate {\n entry: PoolEntry\n weight: number\n}\n\n/** Draws without replacement by weight (the viewer's `ordemPonderada`): one draw per candidate, all of them, before anything is cut. */\nconst weightedOrder = (candidates: readonly Candidate[], random: () => number): Candidate[] => {\n const remaining = [...candidates]\n const ordered: Candidate[] = []\n while (remaining.length > 0) {\n const total = remaining.reduce((sum, candidate) => sum + candidate.weight, 0)\n let x = random() * total\n let index = 0\n for (; index < remaining.length - 1; index++) {\n x -= (remaining[index] as Candidate).weight\n if (x < 0) break\n }\n ordered.push(...remaining.splice(index, 1))\n }\n return ordered\n}\n\nconst countFor = (pool: readonly PoolEntry[], state: FindState, footprint: number, query: FindsQuery, rules: ItemRules): number => {\n const settings = rules.finds.pool\n const base = Math.max(settings.min, Math.min(settings.max, Math.round(settings.offset + footprint * settings.perSquareMetre + query.rng() * settings.jitter)))\n if (state === 'fortified') return Math.min(pool.length, base + settings.fortifiedExtra)\n if (state === 'abandoned') return query.rng() < settings.abandonedEmptyChance ? 0 : settings.abandonedKept\n return base\n}\n\n/**\n * Port of the 3D house viewer's `sorteiaConteudo` (visor-casas-3d.js L10837-10863) over a pool of what a kind of furniture holds.\n *\n * Order of the random draws, the contract the golden test holds: one for the count (`base`); for an abandoned container one more (empty or not); then a full\n * weighted order of the pool (one draw per entry, before the cut to the count); then one per kept entry for its quantity; and only for an abandoned and empty\n * container one last draw for the junk. Fortified: more entries, supplies weigh x2.5 and give +1. Abandoned: 40% empty, otherwise one entry, plus junk and,\n * in a fridge or freezer, spoiled food.\n */\nexport const rollExplicitPool = (pool: readonly PoolEntry[], state: FindState, query: FindsQuery, rules: ItemRules): PoolPick[] => {\n const settings = rules.finds.pool\n const n = countFor(pool, state, query.footprint ?? settings.defaultFootprint, query, rules)\n const isFortified = state === 'fortified'\n const candidates = pool.map((entry) => ({ entry, weight: isFortified && entry.isSupply ? entry.weight * settings.supplyWeight : entry.weight }))\n\n const picks: PoolPick[] = []\n for (const { entry } of weightedOrder(candidates, query.rng).slice(0, n)) {\n const [low, high] = entry.qty\n const bonus = isFortified && entry.isSupply ? settings.supplyExtraQty : 0\n picks.push({ itemId: entry.item, count: low + Math.floor(query.rng() * (high - low + 1)) + bonus, entry })\n }\n if (state === 'abandoned') {\n if (picks.length === 0 && query.rng() < settings.junkChance) picks.push({ itemId: settings.junkItem, count: 1 })\n if (settings.coldContainers.includes(query.container) || (query.key !== undefined && settings.coldContainers.includes(query.key))) picks.push({ itemId: settings.spoiledFoodItem, count: 1 })\n }\n return picks\n}\n","import { deepMerge } from '@adatechnology/game-contracts'\nimport type { DeepPartial } from '@adatechnology/game-contracts'\n\nimport type { ItemsCatalog } from '../catalog-types'\nimport type { ItemRules } from '../rules-types'\n\nimport { rollByCategory } from './category-roll'\nimport { rollExplicitPool } from './explicit-pool'\nimport { spawnData } from './spawn-state'\nimport type { FindStack, FindsProvider, FindsQuery } from './types'\n\nexport interface FindsProviderOptions {\n /** `team` (default): a container with an explicit pool in the catalog uses it; `none`: always the category roll. */\n pools?: 'team' | 'none'\n /** Changes to the `finds` and `spawn` rules for this provider. */\n rules?: DeepPartial<Pick<ItemRules, 'finds' | 'spawn'>>\n /** Names a host uses for a place, mapped to the place tags of the catalog (a floorplan `cabin` is a `lodge`). */\n placeAliases?: Readonly<Record<string, string>>\n /** Places where the explicit pools apply (the viewer's pools describe dwellings); the others use the category roll. Default: every place. */\n poolPlaces?: readonly string[]\n /** A container with neither a pool nor a table: `fallback` (default) uses the table of `rules.finds.fallbackContainer`, like the game; `pass` answers `null` so the host's own default applies. */\n unknownContainers?: 'fallback' | 'pass'\n}\n\n/**\n * What a container holds, as the floorplan's `FindsProvider` asks it. A container with an explicit pool (`query.key` or the container id) draws from it\n * (port of the viewer); otherwise the category roll of the game draws on the container table. Every stack is chosen first, in the order of the sources, and\n * only then each gets its state (age, condition, charge, fill) from the same generator. Items the catalog no longer has (removed by a game) are dropped\n * after the draws, so the others do not change.\n */\nexport function createFindsProvider(catalog: ItemsCatalog, options: FindsProviderOptions & { unknownContainers: 'pass' }): FindsProvider\nexport function createFindsProvider(catalog: ItemsCatalog, options?: FindsProviderOptions): { findsFor(query: FindsQuery): readonly FindStack[] }\nexport function createFindsProvider(catalog: ItemsCatalog, options: FindsProviderOptions = {}): FindsProvider {\n const rules = options.rules ? deepMerge(catalog.rules, options.rules) : catalog.rules\n const scoped: ItemsCatalog = rules === catalog.rules ? catalog : { ...catalog, rules }\n const usesPools = (options.pools ?? 'team') === 'team'\n\n const aliases = options.placeAliases ?? {}\n const poolPlaces = options.poolPlaces\n\n const passes = options.unknownContainers === 'pass'\n\n const choose = (query: FindsQuery): FindStack[] | null => {\n const pool = usesPools && (poolPlaces === undefined || poolPlaces.includes(query.place)) ? (scoped.pools.get(query.key ?? query.container) ?? scoped.pools.get(query.container)) : undefined\n if (!pool && passes && !scoped.containers.has(query.container)) return null\n if (!pool) return rollByCategory(scoped, query).map((itemId) => ({ itemId, count: 1 }))\n return rollExplicitPool(pool, rules.finds.states[query.state] ?? 'normal', query, rules).map(({ itemId, count }) => ({ itemId, count }))\n }\n\n return {\n findsFor(asked) {\n const query = aliases[asked.place] === undefined ? asked : { ...asked, place: aliases[asked.place] as string }\n const chosen = choose(query)\n if (chosen === null) return null\n return chosen\n .filter((stack) => scoped.has(stack.itemId))\n .map((stack) => {\n const data = spawnData(scoped.get(stack.itemId), query, scoped)\n return data ? { ...stack, data } : stack\n })\n },\n }\n}\n","import type { ItemsCatalog } from '../catalog-types'\nimport type { ItemDef } from '../types'\n\nimport type { FindData, FindsQuery } from './types'\n\nconst WEARING_DURABILITY = ['condition', 'hits', 'cuts']\n\nconst hasCondition = (item: ItemDef): boolean => item.protection !== undefined || item.weapon !== undefined || WEARING_DURABILITY.includes(item.durability?.kind ?? '')\n\nconst between = (range: readonly [number, number], random: () => number): number => range[0] + random() * (range[1] - range[0])\n\n/** Age of food when it turns up: the days since the outbreak plus 0 to 60% of the shelf life. On day 0 that is the normal turnover of the shelf. One draw. */\nexport const spawnAgeDays = (item: ItemDef, outbreakDays: number, random: () => number, catalog: ItemsCatalog): number | undefined =>\n item.shelfLife === undefined ? undefined : outbreakDays + between(catalog.rules.spawn.ageShare, random) * item.shelfLife\n\nconst isRetailStock = (query: FindsQuery, catalog: ItemsCatalog): boolean => {\n const { spawn } = catalog.rules\n const isRetail = spawn.retailNew && (query.day ?? 0) <= 0 && spawn.retailPlaces.includes(query.place)\n return isRetail && (spawn.retailContainers.length === 0 || spawn.retailContainers.includes(query.container))\n}\n\n/**\n * The state an item has when it turns up, drawn after all the stacks of a container were chosen (so the choice itself matches the sources): food age, condition\n * by rarity (100 for shop stock on day 0), battery charge and how full a jerrycan is. Draws in that order, only what applies.\n */\nexport const spawnData = (item: ItemDef, query: FindsQuery, catalog: ItemsCatalog): FindData | undefined => {\n const { spawn } = catalog.rules\n const data: { ageDays?: number; condition?: number; charge?: number; fill?: number } = {}\n const ageDays = spawnAgeDays(item, query.day ?? 0, query.rng, catalog)\n if (ageDays !== undefined) data.ageDays = ageDays\n if (hasCondition(item)) data.condition = isRetailStock(query, catalog) ? 100 : Math.round(between(spawn.condition[item.rarity], query.rng))\n if (item.charge) data.charge = between(spawn.charge, query.rng)\n if (spawn.fillable.includes(item.id)) data.fill = between(spawn.fill, query.rng)\n return Object.keys(data).length > 0 ? data : undefined\n}\n","import { fitsSize } from '@adatechnology/game-interactables'\nimport type { ItemStack, SlotSpec } from '@adatechnology/game-interactables'\n\nimport type { ItemsCatalog } from '../catalog-types'\n\nimport type { FindStack } from './types'\n\nexport interface PlacedFinds {\n /** One entry per slot, in the order of `slots`; null is empty. */\n contents: Array<ItemStack | null>\n /** Stacks that fit no free slot. */\n leftover: FindStack[]\n}\n\n/**\n * Puts the stacks in the slots of a container: each in the first free slot its item fits (`fitsSize`, width and depth may swap), a stack larger than the\n * item's `stack` splits over several slots. Pure and in order, so the same finds always land in the same slots. The result is the floorplan's `contents`.\n */\nexport const placeFinds = (stacks: readonly FindStack[], slots: readonly SlotSpec[], catalog: ItemsCatalog): PlacedFinds => {\n const contents: Array<ItemStack | null> = slots.map(() => null)\n const leftover: FindStack[] = []\n for (const stack of stacks) {\n const item = catalog.get(stack.itemId)\n const stackMax = item.stack ?? 1\n let remaining = stack.count\n while (remaining > 0) {\n const index = slots.findIndex((slot, position) => contents[position] === null && fitsSize(item.size, slot.max))\n if (index < 0) break\n const qty = Math.min(remaining, stackMax)\n contents[index] = { type: item.id, qty, ...(stack.data ? { data: { ...stack.data } } : {}) }\n remaining -= qty\n }\n if (remaining > 0) leftover.push({ ...stack, count: remaining })\n }\n return { contents, leftover }\n}\n","import type { LootTable, LootTables } from '@adatechnology/game-interactables'\n\nimport type { ItemsCatalog } from '../catalog-types'\nimport type { ContainerDef } from '../types'\n\nimport { depletionFactor } from './depletion'\nimport { rarityWeight, rollableItems } from './rarity-pool'\n\nexport interface LootTablesQuery {\n place: string\n /** Outbreak days; 0 is the normal world. */\n day?: number\n region?: string\n}\n\nconst weightsOf = (container: ContainerDef, place: string): Readonly<Record<string, number>> | undefined => container.categories ?? container.categoriesByPlace?.[place] ?? container.categoriesByPlace?.['*']\n\nconst tableFor = (catalog: ItemsCatalog, container: ContainerDef, query: LootTablesQuery): LootTable | undefined => {\n const weights = weightsOf(container, query.place)\n if (!weights) return undefined\n const entries = Object.entries(weights).flatMap(([category, categoryWeight]) => {\n const pool = rollableItems(catalog, category, query.place)\n const total = pool.reduce((sum, item) => sum + rarityWeight(catalog, item), 0)\n return total > 0 ? pool.map((item) => ({ type: item.id, weight: (categoryWeight * rarityWeight(catalog, item)) / total })) : []\n })\n const [low, high] = container.count ?? [0, 0]\n const region = query.region === undefined ? 1 : (catalog.rules.finds.regionMultiplier[query.region] ?? 1)\n const expected = ((low + high) / 2) * depletionFactor(query.place, query.day ?? 0, catalog.rules) * region\n return entries.length > 0 && high > 0 ? { fill: Math.min(1, expected / high), entries } : undefined\n}\n\n/**\n * The finds as the loot tables of `game-interactables`, for worlds that have no floorplan: one table per container of the place, named by the container id.\n * A table has one entry per rollable item, weighted by the container's category weight and the rarity (60/28/9/2.5). A slot is filled with probability\n * `fill` = expected count / most stacks, taking the container to have as many slots as its largest count; the day and the region scale the expected count.\n */\nexport const toLootTables = (catalog: ItemsCatalog, query: LootTablesQuery): LootTables => {\n const tables: LootTables = {}\n for (const container of catalog.containers.values()) {\n if (container.places && container.places.length > 0 && !container.places.includes(query.place)) continue\n const table = tableFor(catalog, container, query)\n if (table) tables[container.id] = table\n }\n return tables\n}\n","import type { CategoryDef, ItemDef, ItemPack, Rarity } from './types'\n\n/** The part of a weapon definition the bridge reads; `WeaponDef` of `@adatechnology/game-weapons` fits it without importing the package. */\nexport interface ArsenalWeaponLike {\n readonly id: string\n readonly mass: number\n readonly action: { readonly kind: string; readonly explosive?: string }\n readonly dimensions?: { readonly length: number }\n}\n\n/** The part of a calibre definition the bridge reads; `CaliberDef` fits it. */\nexport interface ArsenalCaliberLike {\n readonly id: string\n readonly bulletGrams: number\n readonly pellets?: number\n readonly caseType?: string\n readonly cartridge?: { readonly caseDiameter: number; readonly overallLength: number }\n}\n\n/** The part of an `Arsenal` the bridge reads. */\nexport interface ArsenalLike {\n readonly weapons: ReadonlyMap<string, ArsenalWeaponLike>\n readonly calibers: ReadonlyMap<string, ArsenalCaliberLike>\n}\n\n/** What the team's game says of a box or an arsenal item (`ammo-boxes.json`, from its `EXTRA` table); it wins over the estimates below. */\nexport interface ArsenalItemRecord {\n /** Id of the item; without it the bridge uses `ammo_<caliber>`, `firearm_<weapon>` or `throwable_<weapon>`. */\n id?: string\n kind: 'ammo_box' | 'firearm' | 'throwable'\n /** Calibre id of a box. */\n caliber?: string\n /** Weapon id of a firearm or throwable; for a throwable also the explosive it uses. */\n weapon?: string\n rounds?: number\n weight: number\n rarity: Rarity\n}\n\nexport interface ArsenalItemsOptions {\n records?: readonly ArsenalItemRecord[]\n}\n\nexport const ARSENAL_CATEGORIES: readonly CategoryDef[] = [\n { id: 'ammo', name: 'Ammo' },\n { id: 'firearms', name: 'Firearms' },\n { id: 'throwables', name: 'Throwables' },\n]\n\nconst MM = 0.001\nconst BOX_TARE_KG = 0.03\nconst BOX_WALL = 6 * MM\nconst ROUNDS_BY_CASE: Readonly<Record<string, number>> = { tiny: 50, pistol: 50, rifle: 20, shell: 25, big: 10 }\nconst DEFAULT_ROUNDS = 12\nconst CARTRIDGE_MASS_FACTOR = 2.3\nconst SHELL_MASS_FACTOR = 1.5\nconst BOX_DENSITY_KG_PER_M3 = 600\nconst THROWABLE_DENSITY_KG_PER_M3 = 1500\n\nconst cubeSide = (mass: number, density: number): number => Math.cbrt(mass / density)\n\n/** Estimates (REF) for a calibre the game has no box for: rounds by case type, mass of the rounds plus a tare, a box that packs them in a near-square tray. */\nconst estimateBox = (caliber: ArsenalCaliberLike): { rounds: number; weight: number; size: [number, number, number] } => {\n const rounds = ROUNDS_BY_CASE[caliber.caseType ?? ''] ?? DEFAULT_ROUNDS\n const factor = caliber.caseType === 'shell' ? SHELL_MASS_FACTOR : CARTRIDGE_MASS_FACTOR\n const weight = Number((rounds * caliber.bulletGrams * (caliber.pellets ?? 1) * factor * 0.001 + BOX_TARE_KG).toFixed(3))\n return { rounds, weight, size: boxSize(caliber, rounds, weight) }\n}\n\nconst boxSize = (caliber: ArsenalCaliberLike, rounds: number, weight: number): [number, number, number] => {\n if (!caliber.cartridge) {\n const side = cubeSide(weight, BOX_DENSITY_KG_PER_M3)\n return [side, side, side]\n }\n const rows = Math.ceil(Math.sqrt(rounds))\n const columns = Math.ceil(rounds / rows)\n const { caseDiameter, overallLength } = caliber.cartridge\n return [rows * caseDiameter * MM + BOX_WALL, overallLength * MM + BOX_WALL, columns * caseDiameter * MM + BOX_WALL]\n}\n\nconst ammoItem = (caliber: ArsenalCaliberLike, record: ArsenalItemRecord | undefined): ItemDef => {\n const estimate = estimateBox(caliber)\n const weight = record?.weight ?? estimate.weight\n return {\n id: record?.id ?? `ammo_${caliber.id}`,\n category: 'ammo',\n size: record?.weight === undefined ? estimate.size : boxSize(caliber, record.rounds ?? estimate.rounds, weight),\n weight,\n stack: 4,\n shape: 'box',\n rarity: record?.rarity ?? 'uncommon',\n }\n}\n\n/** A firearm's size from its length: height and thickness grow with it (a pistol 0.2 m is 0.10 x 0.03, a rifle 1 m is 0.20 x 0.05). Without a length, one from the mass. */\nconst firearmSize = (weapon: ArsenalWeaponLike): [number, number, number] => {\n const length = weapon.dimensions?.length ?? 0.15 + 0.2 * weapon.mass\n return [length, 0.08 + 0.12 * length, 0.02 + 0.03 * length]\n}\n\nconst weaponItem = (weapon: ArsenalWeaponLike, record: ArsenalItemRecord | undefined): ItemDef => {\n const isFirearm = weapon.action.kind === 'firearm'\n const side = cubeSide(weapon.mass, THROWABLE_DENSITY_KG_PER_M3)\n return {\n id: record?.id ?? `${isFirearm ? 'firearm' : 'throwable'}_${weapon.id}`,\n category: isFirearm ? 'firearms' : 'throwables',\n size: isFirearm ? firearmSize(weapon) : [side, side, side],\n weight: record?.weight ?? weapon.mass,\n stack: 1,\n shape: isFirearm ? 'long_tool' : 'jar',\n rarity: record?.rarity ?? 'unique',\n weapon: weapon.id,\n }\n}\n\nconst recordFor = (records: readonly ArsenalItemRecord[], match: (record: ArsenalItemRecord) => boolean): ArsenalItemRecord | undefined => records.find(match)\n\n/**\n * The arsenal as items, so a bag can carry it: a box `ammo_<caliber>` for every calibre, `firearm_<id>` for every firearm and `throwable_<id>` for every\n * throwable, with the mass and the real dimensions of the `WeaponDef` (`mass`, `dimensions.length`). A record from the team's game (`records`) gives the rounds\n * per box, the weight and the rarity of what it listed (9x19: 20 rounds, 0.24 kg); the rest are estimated from the calibre (REF): rounds by case type,\n * weight from the bullet. Returns a pack (with the `ammo`, `firearms` and `throwables` categories) for `createItems({ packs })`.\n */\nexport const itemsFromArsenal = (arsenal: ArsenalLike, options: ArsenalItemsOptions = {}): ItemPack => {\n const records = options.records ?? []\n const items: ItemDef[] = []\n for (const caliber of arsenal.calibers.values()) items.push(ammoItem(caliber, recordFor(records, (record) => record.kind === 'ammo_box' && record.caliber === caliber.id)))\n for (const weapon of arsenal.weapons.values()) {\n const kind = weapon.action.kind\n if (kind !== 'firearm' && kind !== 'throwable') continue\n items.push(weaponItem(weapon, recordFor(records, (record) => record.kind === kind && (record.weapon === weapon.id || record.weapon === weapon.action.explosive))))\n }\n return { id: 'arsenal', items, categories: ARSENAL_CATEGORIES }\n}\n","import type { AreaPlacement, Vec3 } from '@adatechnology/game-contracts'\n\n/** What the layout needs of an item: its id, category and real size [width, height, depth] in metres. */\nexport interface LayoutItem {\n readonly id: string\n readonly category: string\n readonly size: readonly [number, number, number]\n}\n\n/** Height of the top of a shelf, metres. */\nexport const SHELF_HEIGHT = 0.9\n/** Longest row of items on a shelf, metres. */\nexport const ROW_LIMIT = 5\nconst GAP = 0.06\nconst EDGE = 0.12\nconst COLUMNS = 4\nconst COLUMN_PITCH = 6.2\nconst ROW_GAP = 1.5\nconst FIRST_Z = -11\n\n/** One shelf: a category's items laid out in rows at real size, the shelf's footprint and where its items sit on its top. */\nexport interface ShelfPlan {\n category: string\n /** Item id of the shelf in the module (`shelf_<category>`). */\n id: string\n /** Footprint on the floor: length along x, depth along z. */\n length: number\n depth: number\n position: Vec3\n /** Where each item sits, in world coordinates. */\n items: AreaPlacement[]\n}\n\nexport const SHELF_PREFIX = 'shelf_'\nexport const ITEM_PREFIX = 'item_'\nexport const SHOWCASE_PREFIX = 'showcase_'\n\ninterface Row {\n items: LayoutItem[]\n width: number\n depth: number\n}\n\nconst rowsOf = (items: readonly LayoutItem[]): Row[] => {\n const rows: Row[] = []\n for (const item of items) {\n const [w, , d] = item.size\n let row = rows[rows.length - 1]\n if (!row || (row.items.length > 0 && row.width + w + GAP > ROW_LIMIT)) {\n row = { items: [], width: 0, depth: 0 }\n rows.push(row)\n }\n row.items.push(item)\n row.width += w + GAP\n row.depth = Math.max(row.depth, d)\n }\n return rows\n}\n\n/**\n * The shelves of the area: one per category, in the order the categories come, with every item of the category side by side at real size, wrapped in rows of at most\n * `ROW_LIMIT` metres. Shelves stand in a grid of four columns; an item that is longer than the row limit gets a row to itself. Pure: the same items always land in the same spots.\n */\nexport function shelvesLayout(items: readonly LayoutItem[], categories: readonly string[]): ShelfPlan[] {\n const plans = categories.flatMap((category) => {\n const own = items.filter((item) => item.category === category)\n if (own.length === 0) return []\n const rows = rowsOf(own)\n const length = Math.max(...rows.map((row) => row.width - GAP)) + 2 * EDGE\n const depth = rows.reduce((sum, row) => sum + row.depth + GAP, 0) - GAP + 2 * EDGE\n return [{ category, rows, length, depth }]\n })\n const result: ShelfPlan[] = []\n let z = FIRST_Z\n for (let start = 0; start < plans.length; start += COLUMNS) {\n const line = plans.slice(start, start + COLUMNS)\n const lineDepth = Math.max(...line.map((plan) => plan.depth))\n line.forEach((plan, column) => {\n const x = (column - (COLUMNS - 1) / 2) * COLUMN_PITCH\n const centre: Vec3 = [x, 0, z + plan.depth / 2]\n const placed: AreaPlacement[] = []\n let rowZ = -plan.depth / 2 + EDGE\n for (const row of plan.rows) {\n let cursor = -plan.length / 2 + EDGE\n for (const item of row.items) {\n const [w, , d] = item.size\n placed.push({ item: `${ITEM_PREFIX}${item.id}`, position: [centre[0] + cursor + w / 2, SHELF_HEIGHT + 0.01, centre[2] + rowZ + d / 2], asleep: true })\n cursor += w + GAP\n }\n rowZ += row.depth + GAP\n }\n result.push({ category: plan.category, id: `${SHELF_PREFIX}${plan.category}`, length: plan.length, depth: plan.depth, position: centre, items: placed })\n })\n z += lineDepth + ROW_GAP\n }\n return result\n}\n","import type * as THREE_NS from 'three'\nimport type { AreaPlacement, BenchChange, ModuleArea, ModuleControl, ModuleHost, ModuleLayer, ModuleMetric, ModuleScenario, TestableItem, TestableModule, Vec3 } from '@adatechnology/game-contracts'\nimport { rng } from '@adatechnology/game-interactables'\nimport { canCraft, craft, createFindsProvider, freshness, ITEM_CATEGORIES } from '@adatechnology/game-items'\nimport type { FindStack, FindsProvider, FindsQuery, ItemDef, ItemsCatalog, RecipeDef } from '@adatechnology/game-items'\n\nimport { ITEM_PREFIX, SHELF_HEIGHT, SHOWCASE_PREFIX, shelvesLayout } from './area-layout'\nimport type { ShelfPlan } from './area-layout'\nimport { buildItem } from './build-item'\nimport type { DrawableItem } from './build-item'\nimport { checkBudget, countDrawCalls, countTriangles, ITEM_BUDGETS } from './budgets'\nimport { MODEL_BUDGET_DEVIATIONS } from './models/deviations'\nimport { itemThumbnailSvg } from './thumbnails'\nimport { hasItemModel, itemModelEntry, listItemModels } from './models/registry'\nimport { setWear } from './wear'\nimport type { WearStage } from './wear'\n\nexport interface ItemsTestModuleOptions {\n /** The catalog to lay out (for example `createGoodsItems()` of `game-items-goods`). The module knows no content of its own. */\n catalog: ItemsCatalog\n /** `en` or `pt-BR` (default). */\n locale?: string\n /** Text of a key such as `item.canned_beans`, `place.house`, `category.food`, `container.fridge`, `recipe.stew` (the goods package has them in `goodsText`); without it the module falls back to the id. */\n translate?: (key: string, locale: string) => string | undefined\n /** Seed of the finds roll (default 1). */\n seed?: number\n /** Wear the items start with: `new` (default), `used` or `spoiled`. */\n wear?: string\n /** The finds provider; default the one of `game-items` over `catalog`. A game gives its own (floorplan bindings, pools). */\n provider?: FindsProvider\n}\n\nexport const SHOWCASE_STAND_ID = 'stand_models'\nexport const RULER_ID = 'ruler_155'\nexport const HUMAN_ID = 'human_180'\nexport const FINDS_TABLE_ID = 'finds_table'\nexport const RULER_HEIGHT = 1.55\nexport const HUMAN_HEIGHT = 1.8\n\nconst STAND = { at: [0, 0, 9.5] as Vec3, radius: 2.1, height: 0.8, ring: 1.35 }\nconst RULER_AT: Vec3 = [-6.5, 0, 9]\nconst HUMAN_AT: Vec3 = [-5.4, 0, 9]\nconst TABLE = { at: [7, 0, 9.5] as Vec3, length: 3.2, depth: 1, height: 0.8 }\nconst WEARS = ['new', 'used', 'spoiled'] as const\nconst WEAR_STAGE: Readonly<Record<string, WearStage>> = { new: 0, used: 1, spoiled: 2 }\nconst SPIN = 0.6\nconst MAX_COPIES = 5\nconst CATEGORY_ALL = 'all'\nconst BOX_COLOR = 0x4fc3f7\nconst HIGHLIGHT = 0x6a3a00\n\ninterface Text {\n group: string\n name: string\n shelf: string\n stand: string\n ruler: string\n human: string\n table: string\n control: Record<'category' | 'wear' | 'age_days' | 'storage' | 'powered' | 'place' | 'container' | 'state' | 'day' | 'seed' | 'roll_finds' | 'recipe' | 'craft', string>\n hint: Record<'age_days' | 'powered' | 'day' | 'roll_finds' | 'craft', string>\n all: string\n wears: Record<(typeof WEARS)[number], string>\n states: Record<'normal' | 'fortified' | 'abandoned', string>\n storages: Record<string, string>\n layers: Record<'labels' | 'boxes' | 'simple_shapes', string>\n metrics: Record<'items' | 'draw_calls' | 'triangles' | 'modeled' | 'finds', string>\n rolled: string\n rolledNothing: string\n crafted: string\n craftMissing: string\n craftEffect: string\n scenarios: Record<'real_size' | 'models' | 'budgets' | 'ruler' | 'finds' | 'freshness' | 'craft', string>\n}\n\nconst TEXT: Record<string, Text> = {\n en: {\n group: 'Items',\n name: 'Items area',\n shelf: 'Shelf of {category}',\n stand: 'Showcase stand of the 3D models',\n ruler: 'Ruler 1.55 m',\n human: 'Human figure 1.80 m',\n table: 'Finds table',\n control: {\n category: 'Category',\n wear: 'Wear',\n age_days: 'Age',\n storage: 'Storage',\n powered: 'Storage has power',\n place: 'Place',\n container: 'Container',\n state: 'State of the place',\n day: 'Outbreak day',\n seed: 'Seed',\n roll_finds: 'Roll finds',\n recipe: 'Recipe',\n craft: 'Craft',\n },\n hint: {\n age_days: 'Days the food has been kept: it spoils by its shelf life, faster or slower by the storage',\n powered: 'A fridge or freezer only keeps the food while it has power',\n day: 'Days since the outbreak: 0 is the normal world',\n roll_finds: 'Draws what the container holds and lays the stacks on the finds table',\n craft: 'Makes the recipe with exactly what it asks for and lays the result on the finds table',\n },\n all: 'All',\n wears: { new: 'New', used: 'Used', spoiled: 'Spoiled' },\n states: { normal: 'Normal', fortified: 'Fortified', abandoned: 'Abandoned' },\n storages: {},\n layers: { labels: 'Labels', boxes: 'Size boxes', simple_shapes: 'Highlight simple shapes' },\n metrics: { items: 'Items shown', draw_calls: 'Draw calls', triangles: 'Triangles', modeled: 'With a team model', finds: 'Stacks on the table' },\n rolled: 'Finds in {container} of {place} ({state}, day {day}): {stacks} stacks',\n rolledNothing: '{container} of {place} holds nothing',\n crafted: 'Crafted {recipe}: {output} ({seconds} s)',\n craftMissing: 'Cannot craft {recipe}: missing {missing}',\n craftEffect: 'effect {effect}',\n scenarios: {\n real_size: 'Every item is drawn at its real size',\n models: 'The 24 models of the team are shipped and draw their items',\n budgets: 'Models and shapes stay within the triangle and draw call budgets',\n ruler: 'The ruler is 1.55 m and the human figure 1.80 m',\n finds: 'The finds roll is the same for the same seed',\n freshness: 'Food spoils with age and the fridge slows it down',\n craft: 'A recipe made with what it asks for gives its output',\n },\n },\n 'pt-BR': {\n group: 'Itens',\n name: 'Área de itens',\n shelf: 'Prateleira de {category}',\n stand: 'Pedestal dos modelos 3D',\n ruler: 'Régua de 1,55 m',\n human: 'Silhueta humana de 1,80 m',\n table: 'Mesa de achados',\n control: {\n category: 'Categoria',\n wear: 'Desgaste',\n age_days: 'Idade',\n storage: 'Armazenamento',\n powered: 'Armazenamento com energia',\n place: 'Lugar',\n container: 'Recipiente',\n state: 'Estado do lugar',\n day: 'Dia do surto',\n seed: 'Semente',\n roll_finds: 'Sortear achados',\n recipe: 'Receita',\n craft: 'Fabricar',\n },\n hint: {\n age_days: 'Dias que a comida ficou guardada: estraga pela validade, mais rápido ou mais devagar conforme onde está',\n powered: 'Geladeira e freezer só conservam enquanto têm energia',\n day: 'Dias desde o surto: 0 é o mundo normal',\n roll_finds: 'Sorteia o que o recipiente guarda e põe as pilhas na mesa de achados',\n craft: 'Faz a receita com exatamente o que ela pede e põe o resultado na mesa de achados',\n },\n all: 'Todas',\n wears: { new: 'Novo', used: 'Usado', spoiled: 'Estragado' },\n states: { normal: 'Normal', fortified: 'Fortificado', abandoned: 'Abandonado' },\n storages: {},\n layers: { labels: 'Rótulos', boxes: 'Caixas de tamanho', simple_shapes: 'Destacar formas simples' },\n metrics: { items: 'Itens à mostra', draw_calls: 'Chamadas de desenho', triangles: 'Triângulos', modeled: 'Com modelo do time', finds: 'Pilhas na mesa' },\n rolled: 'Achados em {container} de {place} ({state}, dia {day}): {stacks} pilhas',\n rolledNothing: '{container} de {place} não tem nada',\n crafted: 'Fabricou {recipe}: {output} ({seconds} s)',\n craftMissing: 'Não dá para fabricar {recipe}: falta {missing}',\n craftEffect: 'efeito {effect}',\n scenarios: {\n real_size: 'Todo item é desenhado no tamanho real',\n models: 'Os 24 modelos do time vêm no kit e desenham os seus itens',\n budgets: 'Modelos e formas ficam dentro do orçamento de triângulos e de chamadas de desenho',\n ruler: 'A régua tem 1,55 m e a silhueta humana 1,80 m',\n finds: 'O sorteio de achados é o mesmo para a mesma semente',\n freshness: 'A comida estraga com a idade e a geladeira atrasa isso',\n craft: 'Uma receita feita com o que ela pede dá o que promete',\n },\n },\n}\nconst textOf = (locale: string): Text => TEXT[locale] ?? (TEXT.en as Text)\nconst fill = (template: string, vars: Record<string, string | number>): string => template.replace(/\\{(\\w+)\\}/g, (_, key: string) => String(vars[key] ?? ''))\nconst humanize = (id: string): string => id.replace(/_/g, ' ').replace(/^./, (c) => c.toUpperCase())\n\n/** What the scenarios of the area ask of the module (and what a host or a test may read). */\nexport interface ItemsAreaState {\n readonly category: string\n readonly wear: string\n readonly ageDays: number\n readonly storage: string\n readonly powered: boolean\n readonly place: string\n readonly container: string\n readonly state: string\n readonly day: number\n readonly seed: number\n readonly recipe: string\n}\n\nexport interface ItemsTestModule extends TestableModule {\n /** Everything the module has put in the scene so far, with what was measured when it was drawn. */\n placed(): ReadonlyArray<{ id: string; itemId: string; group: 'shelf' | 'showcase'; kind: 'model' | 'shape'; size: readonly [number, number, number]; root: THREE_NS.Object3D }>\n /** The stacks now on the finds table. */\n finds(): readonly FindStack[]\n /** The shelves of the layout. */\n shelves(): readonly ShelfPlan[]\n readonly state: ItemsAreaState\n /** The bench actions, callable without a host (what the buttons do). */\n rollFinds(): readonly FindStack[]\n craftSelected(): { ok: boolean; missing: readonly string[] }\n selectRecipe(id: string): void\n /** The box of a drawn object, metres [x, y, z] (needs the host's three.js namespace: null before the module is attached or an item built). */\n measure(root: THREE_NS.Object3D): [number, number, number] | null\n}\n\n/** Wear stage of an item from the age the bench sets: a food past its best turns spoiled, a food getting old turns used. */\nconst stageOf = (catalog: ItemsCatalog, item: ItemDef, base: WearStage, ageDays: number, storage: string, powered: boolean): WearStage => {\n if (item.shelfLife === undefined || ageDays <= 0) return base\n const state = freshness(item, { ageDays: 0, since: 0, storage, storedAt: 0 }, ageDays, { powered, rules: catalog.rules })\n const aged: WearStage = state === 'fresh' ? 0 : state === 'stale' ? 1 : 2\n return Math.max(base, aged) as WearStage\n}\n\nconst sizeOfModel = (id: string): [number, number, number] | undefined => {\n const entry = itemModelEntry(id)\n return entry ? [entry.teamBox[0] * entry.scale, entry.teamBox[1] * entry.scale, entry.teamBox[2] * entry.scale] : undefined\n}\n\n/**\n * The items test area as a `TestableModule` of @adatechnology/game-contracts: every item of a catalog on shelves by category at real size (the real model of the team where there is\n * one, the simple shape of its category elsewhere), a stand where the 24 models turn, a ruler and a human figure to judge the scale, and a table where the finds of a container\n * and the result of a recipe are laid. The bench sets wear, age and storage, the place, container, state, outbreak day and seed of the finds, and the recipe.\n */\nexport function createItemsTestModule(options: ItemsTestModuleOptions): ItemsTestModule {\n const { catalog } = options\n const locale = options.locale ?? 'pt-BR'\n const text = textOf(locale)\n const label = (key: string, fallback: string): string => {\n const found = options.translate?.(key, locale)\n return found !== undefined && found !== key ? found : fallback\n }\n const nameOf = (item: ItemDef): string => label(item.name ?? `item.${item.id}`, label(`item.${item.id}`, humanize(item.id)))\n const categoryName = (id: string): string => label(`category.${id}`, humanize(id))\n const provider = options.provider ?? createFindsProvider(catalog)\n\n const items = catalog.list()\n const categories = [...ITEM_CATEGORIES.map((c) => c.id), ...[...catalog.categories.keys()].filter((id) => !ITEM_CATEGORIES.some((c) => c.id === id))].filter((id) => items.some((item) => item.category === id))\n const shelves = shelvesLayout(items, categories)\n const showcase = listItemModels().map((id) => ({ id, size: sizeOfModel(id) as [number, number, number], def: catalog.has(id) ? catalog.get(id) : undefined }))\n\n const state: { -readonly [K in keyof ItemsAreaState]: ItemsAreaState[K] } = {\n category: CATEGORY_ALL,\n wear: WEARS.includes(options.wear as (typeof WEARS)[number]) ? (options.wear as string) : 'new',\n ageDays: 0,\n storage: catalog.rules.storage.ambient ? 'ambient' : (Object.keys(catalog.rules.storage)[0] ?? 'ambient'),\n powered: true,\n place: catalog.places.has('house') ? 'house' : ([...catalog.places.keys()][0] ?? 'house'),\n container: catalog.containers.has('fridge') ? 'fridge' : ([...catalog.containers.keys()][0] ?? 'fridge'),\n state: 'normal',\n day: 0,\n seed: options.seed ?? 1,\n recipe: [...catalog.recipes.keys()][0] ?? '',\n }\n\n interface Entry {\n id: string\n itemId: string\n group: 'shelf' | 'showcase'\n category: string\n def: ItemDef | undefined\n kind: 'model' | 'shape'\n size: readonly [number, number, number]\n root: THREE_NS.Group\n triangles: number\n drawCalls: number\n }\n const entries: Entry[] = []\n let host: ModuleHost | null = null\n let latestTHREE: typeof THREE_NS | null = null\n let stack: FindStack[] = []\n let findsGroup: THREE_NS.Group | null = null\n let boxes: THREE_NS.Object3D[] = []\n const layers = { labels: true, boxes: false, simple_shapes: false }\n\n const baseStage = (): WearStage => WEAR_STAGE[state.wear] ?? 0\n const stageFor = (def: ItemDef | undefined): WearStage => (def ? stageOf(catalog, def, baseStage(), state.ageDays, state.storage, state.powered) : baseStage())\n\n const drawable = (def: ItemDef): DrawableItem => def\n const register = (entry: Omit<Entry, 'triangles' | 'drawCalls'>): void => {\n entries.push({ ...entry, triangles: countTriangles(entry.root), drawCalls: countDrawCalls(entry.root) })\n }\n\n const shelfItem = (plan: ShelfPlan): TestableItem => ({\n id: plan.id,\n name: fill(text.shelf, { category: categoryName(plan.category) }),\n movable: false,\n build: (THREE: unknown) => {\n const T = THREE as typeof THREE_NS\n const group = new T.Group()\n const wood = new T.MeshStandardMaterial({ color: 0x8a6a45, roughness: 0.85 })\n const frame = new T.MeshStandardMaterial({ color: 0x4a4d52, roughness: 0.7, metalness: 0.3 })\n const top = new T.Mesh(new T.BoxGeometry(plan.length, 0.04, plan.depth), wood)\n top.position.y = SHELF_HEIGHT - 0.02\n group.add(top)\n for (const sx of [-1, 1]) for (const sz of [-1, 1]) {\n const leg = new T.Mesh(new T.BoxGeometry(0.05, SHELF_HEIGHT - 0.04, 0.05), frame)\n leg.position.set((sx * (plan.length - 0.1)) / 2, (SHELF_HEIGHT - 0.04) / 2, (sz * (plan.depth - 0.1)) / 2)\n group.add(leg)\n }\n group.userData.category = plan.category\n group.userData.shelf = true\n shelfRoots.push(group)\n return group\n },\n })\n const shelfRoots: THREE_NS.Group[] = []\n\n const itemOf = (def: ItemDef): TestableItem => ({\n id: `${ITEM_PREFIX}${def.id}`,\n name: nameOf(def),\n movable: true,\n thumbnail: itemThumbnailSvg(drawable(def)),\n build: (THREE: unknown) => {\n const T = THREE as typeof THREE_NS\n latestTHREE = T\n const model = buildItem(T, drawable(def), { wear: stageFor(def) })\n register({ id: `${ITEM_PREFIX}${def.id}`, itemId: def.id, group: 'shelf', category: def.category, def, kind: model.kind, size: def.size, root: model.root })\n return model.root\n },\n })\n\n const showcaseItem = (model: (typeof showcase)[number]): TestableItem => ({\n id: `${SHOWCASE_PREFIX}${model.id}`,\n name: model.def ? nameOf(model.def) : label(`item.${model.id}`, humanize(model.id)),\n movable: false,\n build: (THREE: unknown) => {\n const T = THREE as typeof THREE_NS\n const subject: DrawableItem = { id: model.id, category: model.def?.category ?? '', size: model.size, model: model.id }\n const built = buildItem(T, subject, { wear: stageFor(model.def) })\n register({ id: `${SHOWCASE_PREFIX}${model.id}`, itemId: model.id, group: 'showcase', category: model.def?.category ?? '', def: model.def, kind: built.kind, size: model.size, root: built.root })\n return built.root\n },\n })\n\n const standItem = (): TestableItem => ({\n id: SHOWCASE_STAND_ID,\n name: text.stand,\n movable: false,\n build: (THREE: unknown) => {\n const T = THREE as typeof THREE_NS\n const group = new T.Group()\n const base = new T.Mesh(new T.CylinderGeometry(STAND.radius, STAND.radius + 0.1, STAND.height - 0.04, 40), new T.MeshStandardMaterial({ color: 0x3a3d44, roughness: 0.8 }))\n base.position.y = (STAND.height - 0.04) / 2\n const top = new T.Mesh(new T.CylinderGeometry(STAND.radius, STAND.radius, 0.04, 40), new T.MeshStandardMaterial({ color: 0xcfcab8, roughness: 0.6 }))\n top.position.y = STAND.height - 0.02\n group.add(base, top)\n return group\n },\n })\n\n const rulerItem = (): TestableItem => ({\n id: RULER_ID,\n name: text.ruler,\n movable: false,\n build: (THREE: unknown) => {\n const T = THREE as typeof THREE_NS\n const group = new T.Group()\n const post = new T.Mesh(new T.BoxGeometry(0.06, RULER_HEIGHT, 0.02), new T.MeshStandardMaterial({ color: 0xe8e2c8, roughness: 0.7 }))\n post.position.y = RULER_HEIGHT / 2\n group.add(post)\n const tick = new T.MeshStandardMaterial({ color: 0x1b1b1b })\n for (let cm = 0; cm <= 155; cm += 5) {\n const long = cm % 10 === 0\n const mark = new T.Mesh(new T.BoxGeometry(long ? 0.05 : 0.03, 0.004, 0.024), tick)\n mark.position.set(0.03 + (long ? 0.025 : 0.015), cm / 100, 0)\n group.add(mark)\n }\n const base = new T.Mesh(new T.BoxGeometry(0.3, 0.03, 0.3), new T.MeshStandardMaterial({ color: 0x55585c }))\n base.position.y = 0.015\n group.add(base)\n group.userData.height = RULER_HEIGHT\n return group\n },\n })\n\n const humanItem = (): TestableItem => ({\n id: HUMAN_ID,\n name: text.human,\n movable: false,\n build: (THREE: unknown) => {\n const T = THREE as typeof THREE_NS\n const group = new T.Group()\n const skin = new T.MeshStandardMaterial({ color: 0x9aa3ad, roughness: 0.9 })\n const part = (geometry: THREE_NS.BufferGeometry, x: number, y: number): void => {\n const mesh = new T.Mesh(geometry, skin)\n mesh.position.set(x, y, 0)\n group.add(mesh)\n }\n // 1.80 m: legs to 0.88, torso to 1.50, neck and head to 1.80\n for (const x of [-0.09, 0.09]) part(new T.CylinderGeometry(0.075, 0.06, 0.88, 10), x, 0.44)\n part(new T.BoxGeometry(0.4, 0.62, 0.22), 0, 0.88 + 0.31)\n for (const x of [-0.26, 0.26]) part(new T.CylinderGeometry(0.045, 0.04, 0.6, 8), x, 1.2)\n part(new T.CylinderGeometry(0.05, 0.055, 0.07, 8), 0, 1.535)\n part(new T.SphereGeometry(0.115, 14, 10), 0, 1.685)\n group.userData.height = HUMAN_HEIGHT\n return group\n },\n })\n\n const tableItem = (): TestableItem => ({\n id: FINDS_TABLE_ID,\n name: text.table,\n movable: false,\n build: (THREE: unknown) => {\n const T = THREE as typeof THREE_NS\n const group = new T.Group()\n const top = new T.Mesh(new T.BoxGeometry(TABLE.length, 0.05, TABLE.depth), new T.MeshStandardMaterial({ color: 0x7a6a55, roughness: 0.8 }))\n top.position.y = TABLE.height - 0.025\n group.add(top)\n const frame = new T.MeshStandardMaterial({ color: 0x3d3f44 })\n for (const sx of [-1, 1]) for (const sz of [-1, 1]) {\n const leg = new T.Mesh(new T.BoxGeometry(0.06, TABLE.height - 0.05, 0.06), frame)\n leg.position.set((sx * (TABLE.length - 0.12)) / 2, (TABLE.height - 0.05) / 2, (sz * (TABLE.depth - 0.12)) / 2)\n group.add(leg)\n }\n return group\n },\n })\n\n const liveEntries = (): Entry[] => entries.filter((entry) => entry.root.parent !== null)\n const visibleEntries = (): Entry[] => liveEntries().filter((entry) => entry.root.visible)\n\n const applyCategory = (): void => {\n for (const entry of entries) if (entry.group === 'shelf') entry.root.visible = state.category === CATEGORY_ALL || entry.category === state.category\n for (const shelf of shelfRoots) shelf.visible = state.category === CATEGORY_ALL || shelf.userData.category === state.category\n }\n const applyWear = (): void => {\n for (const entry of entries) setWear(entry.root, stageFor(entry.def))\n }\n const applyHighlight = (): void => {\n for (const entry of entries) {\n entry.root.traverse((object) => {\n const mesh = object as THREE_NS.Mesh\n if (!mesh.isMesh) return\n for (const material of Array.isArray(mesh.material) ? mesh.material : [mesh.material]) {\n const standard = material as THREE_NS.MeshStandardMaterial\n if (standard.emissive) standard.emissive.setHex(layers.simple_shapes && entry.kind === 'shape' ? HIGHLIGHT : 0x000000)\n }\n })\n }\n }\n const clearBoxes = (): void => {\n for (const box of boxes) {\n box.parent?.remove(box)\n }\n boxes = []\n }\n const applyBoxes = (): void => {\n clearBoxes()\n if (!layers.boxes || !host || !latestTHREE) return\n const T = latestTHREE\n const scene = host.scene as THREE_NS.Scene\n for (const entry of liveEntries()) {\n if (!entry.root.visible) continue\n const box = new T.Box3().setFromObject(entry.root)\n if (box.isEmpty()) continue\n const helper = new T.Box3Helper(box, BOX_COLOR)\n scene.add(helper)\n boxes.push(helper)\n }\n }\n\n const clearFinds = (): void => {\n if (findsGroup) {\n findsGroup.parent?.remove(findsGroup)\n findsGroup = null\n }\n }\n const labelSprite = (T: typeof THREE_NS, content: string): THREE_NS.Sprite | null => {\n if (typeof document === 'undefined') return null\n const canvas = document.createElement('canvas')\n const context = canvas.getContext('2d')\n if (!context) return null\n canvas.width = 256\n canvas.height = 64\n context.fillStyle = 'rgba(15,17,20,0.78)'\n context.fillRect(0, 0, 256, 64)\n context.fillStyle = '#ffffff'\n context.font = '24px sans-serif'\n context.textAlign = 'center'\n context.textBaseline = 'middle'\n context.fillText(content.length > 22 ? `${content.slice(0, 21)}…` : content, 128, 32)\n const texture = new T.CanvasTexture(canvas)\n const sprite = new T.Sprite(new T.SpriteMaterial({ map: texture, depthTest: false, transparent: true }))\n sprite.scale.set(0.5, 0.125, 1)\n sprite.renderOrder = 10\n return sprite\n }\n /** Draws the stacks on the finds table: each item once per unit (up to five) side by side at real size, with a label of its name and count. */\n const showFinds = (): void => {\n clearFinds()\n if (!host || !latestTHREE) return\n const T = latestTHREE\n const group = new T.Group()\n group.position.set(TABLE.at[0], TABLE.height + 0.005, TABLE.at[2])\n let cursor = -TABLE.length / 2 + 0.1\n const scale = 1\n for (const found of stack) {\n const def = catalog.get(found.itemId)\n const copies = Math.min(found.count, MAX_COPIES)\n const start = cursor\n for (let i = 0; i < copies; i++) {\n const model = buildItem(T, drawable(def), { wear: stageFor(def) })\n model.root.position.set(cursor + (def.size[0] * scale) / 2, 0, 0)\n group.add(model.root)\n cursor += def.size[0] + 0.03\n }\n const sprite = labelSprite(T, `${nameOf(def)} x${found.count}`)\n if (sprite) {\n sprite.position.set((start + cursor) / 2, Math.max(def.size[1], 0.1) + 0.12, 0)\n sprite.visible = layers.labels\n sprite.userData.label = true\n group.add(sprite)\n }\n cursor += 0.1\n }\n ;(host.scene as THREE_NS.Scene).add(group)\n findsGroup = group\n }\n const applyLabels = (): void => {\n findsGroup?.traverse((object) => {\n if (object.userData.label) object.visible = layers.labels\n })\n }\n\n const rollFinds = (): readonly FindStack[] => {\n const query: FindsQuery = { place: state.place, container: state.container, state: state.state, rng: rng(state.seed), day: state.day }\n stack = [...(provider.findsFor(query) ?? [])]\n showFinds()\n const container = label(`container.${state.container}`, humanize(state.container))\n const place = label(`place.${state.place}`, humanize(state.place))\n host?.log(stack.length > 0 ? fill(text.rolled, { container, place, state: text.states[state.state as keyof Text['states']] ?? state.state, day: state.day, stacks: stack.length }) : fill(text.rolledNothing, { container, place }), { place: state.place, container: state.container, seed: state.seed })\n return stack\n }\n\n /** What the character needs to make `recipe`: the items, the stations and the tools it asks for, once. */\n const kitFor = (recipe: RecipeDef): { inventory: Map<string, number>; world: Set<string> } => {\n const inventory = new Map<string, number>()\n const world = new Set<string>()\n const add = (id: string, count: number): void => void inventory.set(id, (inventory.get(id) ?? 0) + count)\n for (const input of recipe.inputs) {\n if (input.world) for (const w of input.world) world.add(w)\n else if (input.item !== undefined) add(input.item, input.qty ?? 1)\n else if (input.any?.[0] !== undefined) add(input.any[0], input.qty ?? 1)\n else if (input.match) {\n const pick = catalog.list().find((item) => (input.match?.category === undefined || item.category === input.match.category) && (input.match?.cookable === undefined || item.cookable === input.match.cookable))\n if (pick) add(pick.id, input.qty ?? 1)\n }\n }\n for (const tool of recipe.tools) {\n if (tool.anyOf[0] !== undefined) add(tool.anyOf[0], 1)\n for (const w of tool.world ?? []) world.add(w)\n }\n return { inventory, world }\n }\n const craftSelected = (): { ok: boolean; missing: readonly string[] } => {\n const recipe = catalog.recipes.get(state.recipe)\n if (!recipe) return { ok: false, missing: [state.recipe] }\n const { inventory, world } = kitFor(recipe)\n const fluids: Record<string, number> = {}\n for (const input of recipe.inputs) if (input.fluid !== undefined) fluids[input.fluid] = (fluids[input.fluid] ?? 0) + (input.liters ?? 1)\n const context = { catalog, inventory, world, fluids }\n const name = label(`recipe.${recipe.id}`, humanize(recipe.id))\n const check = canCraft(recipe, context)\n if (!check.isPossible) {\n host?.log(fill(text.craftMissing, { recipe: name, missing: check.missing.join(', ') }), { recipe: recipe.id })\n return { ok: false, missing: check.missing }\n }\n const result = craft(recipe, context, rng(state.seed))\n if (!result.isCrafted) return { ok: false, missing: result.missing }\n if ('item' in result.output) {\n stack = [{ itemId: result.output.item, count: result.output.count }]\n showFinds()\n }\n const output = 'item' in result.output ? `${nameOf(catalog.get(result.output.item))} x${result.output.count}` : fill(text.craftEffect, { effect: result.output.effect })\n host?.log(fill(text.crafted, { recipe: name, output, seconds: result.seconds }), { recipe: recipe.id })\n return { ok: true, missing: [] }\n }\n\n const areaPlacements = (): AreaPlacement[] => {\n const placements: AreaPlacement[] = []\n for (const shelf of shelves) {\n placements.push({ item: shelf.id, position: shelf.position, surface: { halfSize: [shelf.length / 2, shelf.depth / 2], height: SHELF_HEIGHT } }, ...shelf.items)\n }\n placements.push({ item: SHOWCASE_STAND_ID, position: STAND.at, surface: { halfSize: [STAND.radius, STAND.radius], height: STAND.height } })\n showcase.forEach((model, index) => {\n const angle = (index / showcase.length) * Math.PI * 2\n placements.push({ item: `${SHOWCASE_PREFIX}${model.id}`, position: [STAND.at[0] + Math.cos(angle) * STAND.ring, STAND.height + 0.01, STAND.at[2] + Math.sin(angle) * STAND.ring], asleep: true })\n })\n placements.push({ item: RULER_ID, position: RULER_AT }, { item: HUMAN_ID, position: HUMAN_AT })\n placements.push({ item: FINDS_TABLE_ID, position: TABLE.at, surface: { halfSize: [TABLE.length / 2, TABLE.depth / 2], height: TABLE.height } })\n return placements\n }\n\n const onChange = (change: BenchChange): void => {\n if (change.kind === 'layer') {\n if (change.id === 'labels' || change.id === 'boxes' || change.id === 'simple_shapes') layers[change.id] = change.on\n if (change.id === 'labels') applyLabels()\n else if (change.id === 'boxes') applyBoxes()\n else if (change.id === 'simple_shapes') applyHighlight()\n return\n }\n if (change.kind === 'action') {\n if (change.id === 'roll_finds') rollFinds()\n else if (change.id === 'craft') craftSelected()\n return\n }\n const value = change.value\n switch (change.id) {\n case 'category':\n state.category = String(value)\n applyCategory()\n if (layers.boxes) applyBoxes()\n break\n case 'wear':\n state.wear = String(value)\n applyWear()\n break\n case 'age_days':\n state.ageDays = Number(value)\n applyWear()\n break\n case 'storage':\n state.storage = String(value)\n applyWear()\n break\n case 'powered':\n state.powered = Boolean(value)\n applyWear()\n break\n case 'place':\n state.place = String(value)\n break\n case 'container':\n state.container = String(value)\n break\n case 'state':\n state.state = String(value)\n break\n case 'day':\n state.day = Number(value)\n break\n case 'seed':\n state.seed = Number(value)\n break\n case 'recipe':\n state.recipe = String(value)\n break\n }\n }\n\n const choice = (id: keyof Text['control'], values: ReadonlyArray<{ id: string; name: string }>, def: string): ModuleControl => ({ kind: 'choice', id, name: text.control[id], options: values, default: def })\n\n const module: ItemsTestModule = {\n id: 'items_area',\n name: text.name,\n group: text.group,\n state,\n placed: () => entries.map((entry) => ({ id: entry.id, itemId: entry.itemId, group: entry.group, kind: entry.kind, size: entry.size, root: entry.root })),\n finds: () => stack,\n shelves: () => shelves,\n rollFinds,\n craftSelected,\n selectRecipe: (id) => {\n state.recipe = id\n },\n measure: (root) => {\n if (!latestTHREE) return null\n const size = new latestTHREE.Box3().setFromObject(root).getSize(new latestTHREE.Vector3())\n return [size.x, size.y, size.z]\n },\n items: () => [\n ...items.map(itemOf),\n ...shelves.map(shelfItem),\n standItem(),\n ...showcase.map(showcaseItem),\n rulerItem(),\n humanItem(),\n tableItem(),\n ],\n area: (): ModuleArea => ({ placements: areaPlacements(), view: { eye: [0, 5.5, 16], target: [0, 0.8, 0] } }),\n controls: (): ModuleControl[] => [\n choice('category', [{ id: CATEGORY_ALL, name: text.all }, ...categories.map((id) => ({ id, name: categoryName(id) }))], CATEGORY_ALL),\n choice('wear', WEARS.map((id) => ({ id, name: text.wears[id] })), state.wear),\n { kind: 'number', id: 'age_days', name: text.control.age_days, hint: text.hint.age_days, unit: 'd', min: 0, max: 400, step: 5, default: 0 },\n choice('storage', Object.keys(catalog.rules.storage).map((id) => ({ id, name: label(`storage.${id}`, humanize(id)) })), state.storage),\n { kind: 'boolean', id: 'powered', name: text.control.powered, hint: text.hint.powered, default: true },\n choice('place', [...catalog.places.keys()].map((id) => ({ id, name: label(`place.${id}`, humanize(id)) })), state.place),\n choice('container', [...catalog.containers.keys()].map((id) => ({ id, name: label(`container.${id}`, humanize(id)) })), state.container),\n choice('state', (['normal', 'fortified', 'abandoned'] as const).map((id) => ({ id, name: text.states[id] })), 'normal'),\n { kind: 'number', id: 'day', name: text.control.day, hint: text.hint.day, unit: 'd', min: 0, max: 60, step: 1, default: 0 },\n { kind: 'number', id: 'seed', name: text.control.seed, min: 1, max: 9999, step: 1, default: state.seed },\n { kind: 'action', id: 'roll_finds', name: text.control.roll_finds, hint: text.hint.roll_finds },\n ...(state.recipe ? [choice('recipe', [...catalog.recipes.keys()].map((id) => ({ id, name: label(`recipe.${id}`, humanize(id)) })), state.recipe)] : []),\n ...(state.recipe ? [{ kind: 'action', id: 'craft', name: text.control.craft, hint: text.hint.craft } as ModuleControl] : []),\n ],\n layers: (): ModuleLayer[] => [\n { id: 'labels', name: text.layers.labels },\n { id: 'boxes', name: text.layers.boxes, default: false },\n { id: 'simple_shapes', name: text.layers.simple_shapes, default: false },\n ],\n metrics: (): ModuleMetric[] => [\n { id: 'items', name: text.metrics.items, digits: 0, read: () => visibleEntries().length },\n { id: 'draw_calls', name: text.metrics.draw_calls, digits: 0, read: () => visibleEntries().reduce((sum, entry) => sum + entry.drawCalls, 0) },\n { id: 'triangles', name: text.metrics.triangles, digits: 0, read: () => visibleEntries().reduce((sum, entry) => sum + entry.triangles, 0) },\n {\n id: 'modeled',\n name: text.metrics.modeled,\n read: () => {\n const shown = visibleEntries().filter((entry) => entry.group === 'shelf')\n return `${shown.filter((entry) => entry.kind === 'model').length}/${shown.length}`\n },\n },\n { id: 'finds', name: text.metrics.finds, digits: 0, read: () => stack.length },\n ],\n scenarios: (): Array<ModuleScenario<ScenarioLike>> => scenariosOf(module, catalog, text, provider),\n attach(lent) {\n host = lent\n latestTHREE = lent.THREE as typeof THREE_NS\n const offChange = lent.bench?.onChange(onChange)\n const offFrame = lent.onFrame((dt) => {\n for (const entry of entries) if (entry.group === 'showcase' && entry.root.parent) entry.root.rotation.y += dt * SPIN\n })\n return () => {\n offChange?.()\n offFrame()\n clearBoxes()\n clearFinds()\n host = null\n }\n },\n }\n return module\n}\n\n/** What the scenarios use of the context the test room passes (`ScenarioContext`). */\nexport interface ScenarioLike {\n expect(condition: boolean, label: string, data?: Record<string, unknown>): void\n}\n\n/** A drawing never grows past its item's size, and its longest side is within 8% of it (a bag is a little lower than its box). */\nconst OVER = 0.02\nconst UNDER = 0.08\n\nfunction scenariosOf(module: ItemsTestModule, catalog: ItemsCatalog, text: Text, provider: FindsProvider): Array<ModuleScenario<ScenarioLike>> {\n const names = text.scenarios\n const shelf = (): ReturnType<ItemsTestModule['placed']> => module.placed().filter((entry) => entry.group === 'shelf')\n return [\n {\n id: 'real_size',\n name: names.real_size,\n run: ({ expect }) => {\n const shown = shelf()\n expect(shown.length > 0, 'items are on the shelves', { count: shown.length })\n for (const entry of shown) {\n const measured = module.measure(entry.root)\n if (!measured) continue\n const longest = Math.max(...entry.size)\n const axis = entry.size.indexOf(longest)\n const ok = measured.every((side, a) => side <= (entry.size[a] as number) * (1 + OVER) + 0.002) && Math.abs((measured[axis] as number) - longest) <= longest * UNDER + 0.002\n expect(ok, `${entry.itemId} measures its real size`, { measured, size: entry.size })\n }\n },\n },\n {\n id: 'models',\n name: names.models,\n run: ({ expect }) => {\n const models = listItemModels()\n expect(models.length === 24, '24 models are shipped', { count: models.length })\n const withModel = catalog.list().filter((item) => item.model !== undefined && hasItemModel(item.model))\n expect(withModel.length === 23, '23 items of the catalog name a model', { count: withModel.length })\n const stand = module.placed().filter((entry) => entry.group === 'showcase')\n expect(stand.length === 0 || stand.every((entry) => entry.kind === 'model'), 'every piece of the stand is drawn by the model of the team')\n },\n },\n {\n id: 'budgets',\n name: names.budgets,\n run: ({ expect }) => {\n for (const entry of module.placed()) {\n const report = checkBudget(entry.root, entry.size)\n expect(report.drawCalls <= ITEM_BUDGETS.drawCalls, `${entry.itemId} stays within ${ITEM_BUDGETS.drawCalls} draw calls`, { drawCalls: report.drawCalls })\n const deviation = entry.kind === 'model' ? MODEL_BUDGET_DEVIATIONS[entry.itemId] : undefined\n expect(report.ok || (deviation !== undefined && report.triangles <= deviation), `${entry.itemId} stays within its triangle budget`, { triangles: report.triangles, limit: report.limit })\n }\n },\n },\n {\n id: 'ruler',\n name: names.ruler,\n run: ({ expect }) => {\n expect(RULER_HEIGHT === 1.55 && HUMAN_HEIGHT === 1.8, 'the references have the measures of the page')\n },\n },\n {\n id: 'finds',\n name: names.finds,\n run: ({ expect }) => {\n const query = (seed: number): FindsQuery => ({ place: module.state.place, container: module.state.container, state: 'normal', rng: rng(seed), day: 0 })\n const a = JSON.stringify(provider.findsFor(query(7)))\n const b = JSON.stringify(provider.findsFor(query(7)))\n expect(a === b, 'the same seed gives the same finds')\n expect((provider.findsFor(query(7)) ?? []).every((found) => catalog.has(found.itemId)), 'every find is an item of the catalog')\n },\n },\n {\n id: 'freshness',\n name: names.freshness,\n run: ({ expect }) => {\n const food = catalog.list().find((item) => item.shelfLife !== undefined && item.shelfLife > 0)\n if (!food) return expect(false, 'the catalog has a food that spoils')\n const at = (storage: string, days: number): string => freshness(food, { ageDays: 0, since: 0, storage, storedAt: 0 }, days, { rules: catalog.rules })\n const days = (food.shelfLife as number) * 1.2\n expect(at('ambient', days) !== 'fresh', 'at room temperature it is past its best', { food: food.id })\n if ('fridge' in catalog.rules.storage) expect(at('fridge', days) !== at('ambient', days) || at('fridge', days) === 'fresh', 'in the fridge it keeps better', { food: food.id })\n },\n },\n {\n id: 'craft',\n name: names.craft,\n run: ({ expect }) => {\n const before = module.state.recipe\n for (const id of catalog.recipes.keys()) {\n module.selectRecipe(id)\n const result = module.craftSelected()\n expect(result.ok, `recipe ${id} is made with what it asks for`, { missing: result.missing })\n }\n module.selectRecipe(before)\n },\n },\n ]\n}\n"],"mappings":"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","names":["hex","T","tube","hex","tube","paper","paper","paper","paper","paper","cloth","T","paper","T","T","T","cloth","cloth","paper","T","T","box","T","T","DEFAULT_COLOR","T","box","key","tool","deepMerge","key","entries","T","box","tool","days"]}
1
+ {"version":3,"sources":["../src/index.ts","../../game-shapes/src/color.ts","../../game-shapes/src/hash.ts","../../game-shapes/src/math.ts","../../game-shapes/src/primitives/three-generators.ts","../../game-shapes/src/primitives/difference.ts","../../game-shapes/src/primitives/earcut.ts","../../game-shapes/src/primitives/extrude.ts","../../game-shapes/src/primitives/index.ts","../../game-shapes/src/random.ts","../../game-shapes/src/registry.ts","../../game-shapes/schema/shape.schema.json","../../game-shapes/src/schema.ts","../../game-shapes/src/generate.ts","../../game-shapes/src/merge.ts","../../game-shapes/src/worker.ts","../../game-shapes-three/src/geometry.ts","../../game-shapes-three/src/namespace.ts","../../game-shapes-three/src/object.ts","../../game-shapes-three/src/merge-by-material.ts","../src/kit.ts","../src/wear.ts","../src/shapes.ts","../../game-fluids/src/data/liquids.json","../../game-fluids/src/liquids.ts","../../game-fluids/src/math.ts","../../game-fluids/src/landing.ts","../../game-fluids/src/locale.ts","../../game-fluids/src/shapes.ts","../../game-fluids/src/stains.ts","../../game-fluids/src/world.ts","../../game-fluids/src/data/item-uses.json","../../game-fluids/src/item-use.ts","../../game-fluids/src/film/deposit.ts","../../game-fluids/src/film/drops.ts","../../game-fluids/src/film/simulate.ts","../../game-fluids/src/film/sources.ts","../../game-fluids/src/film/film.ts","../../game-fluids/src/film/random.ts","../../game-fluids/src/film/noise.ts","../../game-fluids/src/film/layout.ts","../../game-fluids/src/film/surface-layout.ts","../../game-fluids/src/data/film-profiles.json","../../game-fluids/src/film/profiles.ts","../src/data/destruction.json","../src/destruction.ts","../src/data/models.json","../src/models/canned-beans.ts","../src/models/water-bottle.ts","../src/models/rice.ts","../src/models/military-ration.ts","../src/models/cachaca.ts","../src/models/first-aid-kit.ts","../src/models/bandage.ts","../src/models/amoxicillin.ts","../src/models/crowbar.ts","../src/models/hammer.ts","../src/models/machete.ts","../src/models/axe.ts","../src/models/nail-bat.ts","../src/models/hiking-backpack-40l.ts","../src/models/flashlight.ts","../src/models/portable-radio.ts","../src/models/house-key.ts","../src/models/survivor-diary.ts","../src/models/motorcycle-helmet.ts","../src/models/lpg-cylinder-13kg.ts","../src/models/fuel-jerrycan.ts","../src/models/walkie-talkies.ts","../src/models/batteries.ts","../src/models/wooden-plank.ts","../src/models/sugar.ts","../src/models/chocolate-bar.ts","../src/models/potatoes.ts","../src/models/biscuits.ts","../src/models/coffee.ts","../src/models/raw-beef.ts","../src/models/game-meat.ts","../src/models/jerked-beef.ts","../src/models/home-preserves.ts","../src/models/eggs.ts","../src/models/cassava-flour.ts","../src/models/beans.ts","../src/models/frozen-chicken.ts","../src/models/orange.ts","../src/models/condensed-milk.ts","../src/models/pasta.ts","../src/models/instant-noodles.ts","../src/models/cassava-root.ts","../src/models/canned-corn-and-peas.ts","../src/models/mortadella.ts","../src/models/fresh-fish.ts","../src/models/salted-fish.ts","../src/models/banana-bunch.ts","../src/models/honey-jar.ts","../src/models/bread.ts","../src/models/cheese.ts","../src/models/rapadura.ts","../src/models/dog-food.ts","../src/models/salt.ts","../src/models/snack-chips.ts","../src/models/canned-sausages.ts","../src/models/canned-sardines.ts","../src/models/cooking-oil.ts","../src/models/beer-can.ts","../src/models/energy-drink.ts","../src/models/water-jug-5l.ts","../src/models/sports-drink.ts","../src/models/milk-carton.ts","../src/models/soda-can.ts","../src/models/juice-box.ts","../src/models/communion-wine.ts","../src/models/coconut-water.ts","../src/models/dirty-water.ts","../src/models/painkillers.ts","../src/models/tramadol.ts","../src/models/ibuprofen.ts","../src/models/antihistamine.ts","../src/models/ceftriaxone.ts","../src/models/clonazepam.ts","../src/models/activated-charcoal.ts","../src/models/adhesive-bandages.ts","../src/models/medical-tape.ts","../src/models/sterile-gauze.ts","../src/models/povidone-iodine.ts","../src/models/suture-kit.ts","../src/models/exam-gloves.ts","../src/models/n95-mask.ts","../src/models/multivitamin.ts","../src/models/maintenance-medication.ts","../src/models/rehydration-salts.ts","../src/models/syringe.ts","../src/models/antivenom.ts","../src/models/saline-iv-bag.ts","../src/models/splint.ts","../src/models/thermometer.ts","../src/models/alcohol-70.ts","../src/models/can-opener.ts","../src/models/pliers.ts","../src/models/bolt-cutters.ts","../src/models/bucket.ts","../src/models/binoculars.ts","../src/models/matches.ts","../src/models/pocket-knife.ts","../src/models/screwdriver.ts","../src/models/adjustable-wrench.ts","../src/models/hoe.ts","../src/models/fire-extinguisher.ts","../src/models/duct-tape.ts","../src/models/camp-stove.ts","../src/models/lighter.ts","../src/models/lockpick-kit.ts","../src/models/sewing-kit.ts","../src/models/car-jack.ts","../src/models/mechanic-toolbox.ts","../src/models/gas-torch.ts","../src/models/inverter-welder.ts","../src/models/pot.ts","../src/models/cordless-drill.ts","../src/models/flint-striker.ts","../src/models/sharpening-stone.ts","../src/models/shovel.ts","../src/models/hacksaw.ts","../src/models/handsaw.ts","../src/models/scissors.ts","../src/models/recurve-bow.ts","../src/models/crossbow.ts","../src/models/iron-pipe.ts","../src/models/meat-cleaver.ts","../src/models/slingshot.ts","../src/models/knife.ts","../src/models/tactical-knife.ts","../src/models/arrows-and-bolts.ts","../src/models/sickle.ts","../src/models/cast-iron-skillet.ts","../src/models/improvised-spear.ts","../src/models/hatchet.ts","../src/models/sledgehammer.ts","../src/models/chainsaw.ts","../src/models/pickaxe.ts","../src/models/baseball-bat.ts","../src/models/police-baton.ts","../src/models/wire-roll.ts","../src/models/barbed-wire.ts","../src/models/glass-shards.ts","../src/models/sheet-metal.ts","../src/models/cement-bag.ts","../src/models/epoxy-glue.ts","../src/models/electronic-components.ts","../src/models/rope.ts","../src/models/copper-wire.ts","../src/models/pet-bottle.ts","../src/models/glass-bottle.ts","../src/models/empty-can.ts","../src/models/firewood.ts","../src/models/tarp.ts","../src/models/screws.ts","../src/models/nails.ts","../src/models/raffia-sack.ts","../src/models/scrap-metal.ts","../src/models/bricks.ts","../src/models/rag.ts","../src/models/rebar.ts","../src/models/lubricant-spray.ts","../src/models/army-camouflage-uniform.ts","../src/models/backpack.ts","../src/models/ballistic-vest.ts","../src/models/battery-9v.ts","../src/models/bean-seeds.ts","../src/models/beekeeper-suit.ts","../src/models/candles.ts","../src/models/car-alarm-remote.ts","../src/models/car-battery-12v.ts","../src/models/car-key.ts","../src/models/cash.ts","../src/models/cassava-cuttings.ts","../src/models/cb-radio.ts","../src/models/cell-key.ts","../src/models/charcoal-bag.ts","../src/models/cigarettes.ts","../src/models/city-map.ts","../src/models/combat-boots.ts","../src/models/cooler-box.ts","../src/models/corn-seeds.ts","../src/models/crossbody-bag.ts","../src/models/delivery-bag.ts","../src/models/denim-jacket.ts","../src/models/diesel.ts","../src/models/diy-magazine.ts","../src/models/dog-tag.ts","../src/models/electric-fence-energizer.ts","../src/models/extension-cord.ts","../src/models/fanny-pack.ts","../src/models/farmers-almanac.ts","../src/models/fertilizer-bag.ts","../src/models/firefighter-suit.ts","../src/models/fishing-net.ts","../src/models/fishing-rod.ts","../src/models/fishing-tackle-box.ts","../src/models/flip-flops.ts","../src/models/folding-solar-panel.ts","../src/models/gas-cartridge.ts","../src/models/gasoline.ts","../src/models/generator-key.ts","../src/models/hard-hat.ts","../src/models/headlamp.ts","../src/models/hoodie.ts","../src/models/janitor-keys.ts","../src/models/jeans.ts","../src/models/kale-and-lettuce-seeds.ts","../src/models/kerosene.ts","../src/models/laptop.ts","../src/models/leather-motorcycle-jacket.ts","../src/models/leather-motorcycle-pants.ts","../src/models/leather-work-gloves.ts","../src/models/led-camp-lantern.ts","../src/models/magazine-arm-guard.ts","../src/models/magazines-and-comics.ts","../src/models/master-key.ts","../src/models/mechanic-coveralls.ts","../src/models/military-backpack.ts","../src/models/military-radio.ts","../src/models/mobile-phone.ts","../src/models/motor-oil.ts","../src/models/night-vision-goggles.ts","../src/models/note.ts","../src/models/padded-coat.ts","../src/models/padlock-key.ts","../src/models/photo.ts","../src/models/portable-generator.ts","../src/models/power-bank.ts","../src/models/pumpkin-seeds.ts","../src/models/raincoat.ts","../src/models/road-map.ts","../src/models/rolling-suitcase.ts","../src/models/rubber-boots.ts","../src/models/safe-key.ts","../src/models/safety-goggles.ts","../src/models/sheet-metal-forearm-guard.ts","../src/models/shopping-bag.ts","../src/models/shopping-cart.ts","../src/models/skill-book.ts","../src/models/snare-trap.ts","../src/models/sneakers.ts","../src/models/tactical-vest.ts","../src/models/technical-manual.ts","../src/models/tool-belt.ts","../src/models/trash-bag.ts","../src/models/trekking-backpack-70l.ts","../src/models/tshirt.ts","../src/models/watering-can.ts","../src/models/wheelbarrow.ts","../src/models/windup-alarm-clock.ts","../src/models/shipped.ts","../src/models/registry.ts","../src/build-item.ts","../src/merge.ts","../src/budgets.ts","../src/lod.ts","../src/models/deviations.ts","../src/thumbnails.ts","../../game-interactables/src/colliders.ts","../../game-interactables/src/rng.ts","../../game-interactables/src/loot.ts","../../game-interactables/src/locale.ts","../../game-interactables/src/math.ts","../../game-interactables/src/world.ts","../../game-contracts/src/blast-shove.ts","../../game-contracts/src/impact.ts","../../game-contracts/src/body.ts","../../game-contracts/src/spec.ts","../../game-contracts/src/weapons.ts","../../game-contracts/src/ignition.ts","../../game-contracts/src/animation.ts","../../game-contracts/src/tool-animation.ts","../../game-contracts/src/registry.ts","../../game-contracts/src/bench.ts","../../game-contracts/src/environment.ts","../../game-contracts/src/categories.ts","../../game-items/src/create-items.ts","../../game-items/src/categories.ts","../../game-items/src/types.ts","../../game-items/src/check-items.ts","../../game-items/src/rules.ts","../../game-items/src/decay.ts","../../game-items/src/protection.ts","../../game-items/src/carry.ts","../../game-items/src/use-effect.ts","../../game-items/src/recipes.ts","../../game-items/src/finds/depletion.ts","../../game-items/src/finds/rarity-pool.ts","../../game-items/src/finds/category-roll.ts","../../game-items/src/finds/explicit-pool.ts","../../game-items/src/finds/provider.ts","../../game-items/src/finds/spawn-state.ts","../../game-items/src/finds/place-finds.ts","../../game-items/src/finds/loot-tables.ts","../../game-items/src/arsenal-items.ts","../src/area-layout.ts","../src/area.ts"],"sourcesContent":["export { createItemKit, WEAR_TAGS } from './kit'\nexport type { ItemKit, ItemMaterialData, Vec3Tuple, WearTag } from './kit'\nexport { setWear, wearableMaterials, WEAR_AMOUNT, WEAR_TARGET } from './wear'\nexport type { WearStage } from './wear'\nexport { canonicalFrame, drawShape, isShape, shade, shapeOf, SHAPES } from './shapes'\nexport type { ShapeContext, ShapeId, ShapeSubject } from './shapes'\nexport { buildItem } from './build-item'\nexport type { BuildItemOptions, DrawableItem, ItemModel } from './build-item'\nexport { DESTRUCTION_MATERIAL_BY_TAG, ITEM_FAMILIES, itemContents, itemDestruction, itemFamily, SHELL_PART_ID, tagForDestruction } from './destruction'\nexport type { ContentsSubject, DestructionTagOptions, ItemContents, ItemDestruction, ItemFamily } from './destruction'\nexport { mergeItem } from './merge'\nexport { buildItemLod } from './lod'\nexport type { ItemLod, ItemLodOptions } from './lod'\nexport { checkBudget, countDrawCalls, countTriangles, cullDistanceOf, ITEM_BUDGETS, sizeClassOf, triangleBudgetOf } from './budgets'\nexport type { BudgetReport, ItemBudgets, ItemSizeClass, Vec3Like } from './budgets'\nexport { hasItemModel, itemModelBuilder, itemModelEntry, listItemModels, registerItemModel, unregisterItemModel } from './models/registry'\nexport type { ItemModelBuilder, ItemModelEntry } from './models/registry'\nexport { SHIPPED_MODELS } from './models/shipped'\nexport { MODEL_BUDGET_DEVIATIONS } from './models/deviations'\nexport { composeThumbnailScene, itemThumbnail, itemThumbnailSvg, renderItemThumbnail, shapeThumbnailSvg, thumbnailPatch } from './thumbnails'\nexport type { ThumbnailRenderer, ThumbnailRenderOptions, ThumbnailScene } from './thumbnails'\nexport { createItemsTestModule, FINDS_TABLE_ID, HUMAN_HEIGHT, HUMAN_ID, RULER_HEIGHT, RULER_ID, SHOWCASE_STAND_ID } from './area'\nexport type { ItemsAreaState, ItemsTestModule, ItemsTestModuleOptions, ScenarioLike } from './area'\nexport { ITEM_PREFIX, ROW_LIMIT, SHELF_HEIGHT, SHELF_PREFIX, SHOWCASE_PREFIX, shelvesLayout } from './area-layout'\nexport type { LayoutItem, ShelfPlan } from './area-layout'\n","import type { Color } from './types'\n\n/** A colour as `0xRRGGBB`: numbers as given (floored, as three's `setHex`), `'#rrggbb'` strings parsed. */\nexport function colorHex(color: Color | undefined, fallback = 0xffffff): number {\n if (color === undefined) return fallback\n if (typeof color === 'number') return Math.floor(color)\n const match = /^#([0-9a-fA-F]{6})$/.exec(color)\n if (!match) throw new Error(`game-shapes: colour \"${color}\" is not 0xRRGGBB or #rrggbb`)\n return parseInt(match[1] as string, 16)\n}\n\n/** three's `SRGBToLinear` (r160 `ColorManagement`), the same constants. */\nexport const srgbToLinear = (c: number): number => (c < 0.04045 ? c * 0.0773993808 : Math.pow(c * 0.9478672986 + 0.0521327014, 2.4))\n\n/**\n * The rgb floats of a hex colour as three's `Color.setHex` stores them: the channels over 255 (`'srgb'`), converted to the linear working space\n * when colour management is on (`'linear'`).\n */\nexport function colorChannels(hex: number, space: 'linear' | 'srgb'): [number, number, number] {\n const r = ((hex >> 16) & 255) / 255\n const g = ((hex >> 8) & 255) / 255\n const b = (hex & 255) / 255\n return space === 'linear' ? [srgbToLinear(r), srgbToLinear(g), srgbToLinear(b)] : [r, g, b]\n}\n","/**\n * Canonical JSON (keys sorted, `undefined` left out, `-0` kept as `-0`, typed arrays as plain lists) and a 64-bit FNV-1a of it in two 32-bit\n * lanes: the key a shape is cached and shared by.\n */\nexport function canonicalJson(value: unknown): string {\n if (value === null) return 'null'\n if (typeof value === 'number') return Object.is(value, -0) ? '-0' : Number.isFinite(value) ? String(value) : JSON.stringify(String(value))\n if (typeof value === 'string') return JSON.stringify(value)\n if (typeof value === 'boolean') return value ? 'true' : 'false'\n if (typeof value === 'function') throw new Error('game-shapes: a function cannot be part of a shape (register it as a generator)')\n if (ArrayBuffer.isView(value)) return canonicalJson(Array.from(value as unknown as ArrayLike<number>))\n if (Array.isArray(value)) return `[${value.map((item) => (item === undefined ? 'null' : canonicalJson(item))).join(',')}]`\n if (typeof value === 'object') {\n const record = value as Record<string, unknown>\n const keys = Object.keys(record).filter((key) => record[key] !== undefined).sort()\n return `{${keys.map((key) => `${JSON.stringify(key)}:${canonicalJson(record[key])}`).join(',')}}`\n }\n return 'null'\n}\n\nconst lane = (text: string, offset: number, prime: number): string => {\n let hash = offset\n for (let index = 0; index < text.length; index++) {\n hash ^= text.charCodeAt(index)\n hash = Math.imul(hash, prime)\n }\n return (hash >>> 0).toString(16).padStart(8, '0')\n}\n\n/** 64-bit FNV-1a of a text as 16 hex digits (two independent 32-bit lanes). */\nexport const hash64 = (text: string): string => lane(text, 0x811c9dc5, 0x01000193) + lane(text, 0x050c5d1f, 0x5bd1e995)\n\n/** `hash64(canonicalJson(value))`. */\nexport const hashValue = (value: unknown): string => hash64(canonicalJson(value))\n","/*\n * Matrix and quaternion arithmetic as three.js r160 does it (MIT, https://github.com/mrdoob/three.js): the same expressions in the same order, so a\n * vertex baked here has the same bits as one baked by `Matrix4.compose` / `multiplyMatrices` / `Matrix3.getNormalMatrix` / `Vector3.normalize`.\n * Matrices are column-major arrays of 16 (4 x 4) or 9 (3 x 3) numbers, the layout of three's `elements`.\n */\nimport type { Mat4, RotationOrder, Transform, Vec3 } from './types'\n\nexport type Matrix4 = number[]\nexport type Matrix3 = number[]\n\nexport const identity4 = (): Matrix4 => [1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1]\n\n/** `Quaternion.setFromEuler` (x, y, z, w). */\nexport function quaternionFromEuler(x: number, y: number, z: number, order: RotationOrder = 'XYZ'): [number, number, number, number] {\n const cos = Math.cos\n const sin = Math.sin\n const c1 = cos(x / 2)\n const c2 = cos(y / 2)\n const c3 = cos(z / 2)\n const s1 = sin(x / 2)\n const s2 = sin(y / 2)\n const s3 = sin(z / 2)\n switch (order) {\n case 'XYZ':\n return [s1 * c2 * c3 + c1 * s2 * s3, c1 * s2 * c3 - s1 * c2 * s3, c1 * c2 * s3 + s1 * s2 * c3, c1 * c2 * c3 - s1 * s2 * s3]\n case 'YXZ':\n return [s1 * c2 * c3 + c1 * s2 * s3, c1 * s2 * c3 - s1 * c2 * s3, c1 * c2 * s3 - s1 * s2 * c3, c1 * c2 * c3 + s1 * s2 * s3]\n case 'ZXY':\n return [s1 * c2 * c3 - c1 * s2 * s3, c1 * s2 * c3 + s1 * c2 * s3, c1 * c2 * s3 + s1 * s2 * c3, c1 * c2 * c3 - s1 * s2 * s3]\n case 'ZYX':\n return [s1 * c2 * c3 - c1 * s2 * s3, c1 * s2 * c3 + s1 * c2 * s3, c1 * c2 * s3 - s1 * s2 * c3, c1 * c2 * c3 + s1 * s2 * s3]\n case 'YZX':\n return [s1 * c2 * c3 + c1 * s2 * s3, c1 * s2 * c3 + s1 * c2 * s3, c1 * c2 * s3 - s1 * s2 * c3, c1 * c2 * c3 - s1 * s2 * s3]\n case 'XZY':\n return [s1 * c2 * c3 - c1 * s2 * s3, c1 * s2 * c3 - s1 * c2 * s3, c1 * c2 * s3 + s1 * s2 * c3, c1 * c2 * c3 + s1 * s2 * s3]\n default:\n throw new Error(`game-shapes: unknown rotation order \"${String(order)}\"`)\n }\n}\n\n/** `Matrix4.compose(position, quaternion, scale)`. */\nexport function compose(px: number, py: number, pz: number, q: readonly [number, number, number, number], sx: number, sy: number, sz: number): Matrix4 {\n const [x, y, z, w] = q\n const x2 = x + x\n const y2 = y + y\n const z2 = z + z\n const xx = x * x2\n const xy = x * y2\n const xz = x * z2\n const yy = y * y2\n const yz = y * z2\n const zz = z * z2\n const wx = w * x2\n const wy = w * y2\n const wz = w * z2\n return [\n (1 - (yy + zz)) * sx, (xy + wz) * sx, (xz - wy) * sx, 0,\n (xy - wz) * sy, (1 - (xx + zz)) * sy, (yz + wx) * sy, 0,\n (xz + wy) * sz, (yz - wx) * sz, (1 - (xx + yy)) * sz, 0,\n px, py, pz, 1,\n ]\n}\n\n/** `Matrix4.makeRotationY(theta)` followed by `setPosition(x, y, z)`. */\nexport function headingMatrix(theta: number, x = 0, y = 0, z = 0): Matrix4 {\n const c = Math.cos(theta)\n const s = Math.sin(theta)\n return [c, 0, -s, 0, 0, 1, 0, 0, s, 0, c, 0, x, y, z, 1]\n}\n\n/** `Matrix4.multiplyMatrices(a, b)`: a x b. */\nexport function multiply(ae: readonly number[], be: readonly number[]): Matrix4 {\n const a11 = ae[0]!, a12 = ae[4]!, a13 = ae[8]!, a14 = ae[12]!\n const a21 = ae[1]!, a22 = ae[5]!, a23 = ae[9]!, a24 = ae[13]!\n const a31 = ae[2]!, a32 = ae[6]!, a33 = ae[10]!, a34 = ae[14]!\n const a41 = ae[3]!, a42 = ae[7]!, a43 = ae[11]!, a44 = ae[15]!\n const b11 = be[0]!, b12 = be[4]!, b13 = be[8]!, b14 = be[12]!\n const b21 = be[1]!, b22 = be[5]!, b23 = be[9]!, b24 = be[13]!\n const b31 = be[2]!, b32 = be[6]!, b33 = be[10]!, b34 = be[14]!\n const b41 = be[3]!, b42 = be[7]!, b43 = be[11]!, b44 = be[15]!\n return [\n a11 * b11 + a12 * b21 + a13 * b31 + a14 * b41,\n a21 * b11 + a22 * b21 + a23 * b31 + a24 * b41,\n a31 * b11 + a32 * b21 + a33 * b31 + a34 * b41,\n a41 * b11 + a42 * b21 + a43 * b31 + a44 * b41,\n a11 * b12 + a12 * b22 + a13 * b32 + a14 * b42,\n a21 * b12 + a22 * b22 + a23 * b32 + a24 * b42,\n a31 * b12 + a32 * b22 + a33 * b32 + a34 * b42,\n a41 * b12 + a42 * b22 + a43 * b32 + a44 * b42,\n a11 * b13 + a12 * b23 + a13 * b33 + a14 * b43,\n a21 * b13 + a22 * b23 + a23 * b33 + a24 * b43,\n a31 * b13 + a32 * b23 + a33 * b33 + a34 * b43,\n a41 * b13 + a42 * b23 + a43 * b33 + a44 * b43,\n a11 * b14 + a12 * b24 + a13 * b34 + a14 * b44,\n a21 * b14 + a22 * b24 + a23 * b34 + a24 * b44,\n a31 * b14 + a32 * b24 + a33 * b34 + a34 * b44,\n a41 * b14 + a42 * b24 + a43 * b34 + a44 * b44,\n ]\n}\n\n/** `Matrix3.getNormalMatrix(m)`: the inverse transpose of the upper 3 x 3 (all zeros when singular, as three). */\nexport function normalMatrix(me: readonly number[]): Matrix3 {\n // setFromMatrix4\n const n11 = me[0]!, n21 = me[1]!, n31 = me[2]!\n const n12 = me[4]!, n22 = me[5]!, n32 = me[6]!\n const n13 = me[8]!, n23 = me[9]!, n33 = me[10]!\n // invert\n const t11 = n33 * n22 - n32 * n23\n const t12 = n32 * n13 - n33 * n12\n const t13 = n23 * n12 - n22 * n13\n const det = n11 * t11 + n21 * t12 + n31 * t13\n if (det === 0) return [0, 0, 0, 0, 0, 0, 0, 0, 0]\n const detInv = 1 / det\n const te = [\n t11 * detInv,\n (n31 * n23 - n33 * n21) * detInv,\n (n32 * n21 - n31 * n22) * detInv,\n t12 * detInv,\n (n33 * n11 - n31 * n13) * detInv,\n (n31 * n12 - n32 * n11) * detInv,\n t13 * detInv,\n (n21 * n13 - n23 * n11) * detInv,\n (n22 * n11 - n21 * n12) * detInv,\n ]\n // transpose\n let tmp = te[1]!\n te[1] = te[3]!\n te[3] = tmp\n tmp = te[2]!\n te[2] = te[6]!\n te[6] = tmp\n tmp = te[5]!\n te[5] = te[7]!\n te[7] = tmp\n return te\n}\n\n/** True when the last row is (0, 0, 0, 1): `applyMatrix4`'s divide by w is then a multiply by exactly 1. */\nexport const isAffine = (e: readonly number[]): boolean => e[3] === 0 && e[7] === 0 && e[11] === 0 && e[15] === 1\n\n/** `Vector3.applyMatrix4`. */\nexport function transformPoint(e: readonly number[], x: number, y: number, z: number): [number, number, number] {\n const w = 1 / (e[3]! * x + e[7]! * y + e[11]! * z + e[15]!)\n return [(e[0]! * x + e[4]! * y + e[8]! * z + e[12]!) * w, (e[1]! * x + e[5]! * y + e[9]! * z + e[13]!) * w, (e[2]! * x + e[6]! * y + e[10]! * z + e[14]!) * w]\n}\n\nconst toVec3 = (scale: number | Vec3 | undefined): Vec3 => (scale === undefined ? [1, 1, 1] : typeof scale === 'number' ? [scale, scale, scale] : scale)\n\n/** True when the transform has no field set. */\nexport const isIdentityTransform = (t: Transform): boolean =>\n t.matrix === undefined && t.heading === undefined && t.position === undefined && t.rotation === undefined && t.scale === undefined\n\n/** The local matrix of a transform, or `null` when it has none. */\nexport function matrixOf(t: Transform): Matrix4 | null {\n if (t.matrix !== undefined) return [...t.matrix]\n if (t.heading !== undefined) {\n const p = t.position ?? [0, 0, 0]\n return headingMatrix(t.heading, p[0], p[1], p[2])\n }\n if (t.position === undefined && t.rotation === undefined && t.scale === undefined) return null\n const p = t.position ?? [0, 0, 0]\n const r = t.rotation ?? [0, 0, 0]\n const s = toVec3(t.scale)\n return compose(p[0], p[1], p[2], quaternionFromEuler(r[0], r[1], r[2], t.rotationOrder ?? 'XYZ'), s[0], s[1], s[2])\n}\n\n/** The matrix as given, as a plain array (for `ShapePart.matrix`). */\nexport const asMat4 = (m: Matrix4 | null): Mat4 => (m ? [...m] : identity4())\n","/*\n * The geometry generators of three.js r160 (MIT, https://github.com/mrdoob/three.js, src/geometries/*.js), ported line by line: the same loops,\n * the same expressions in the same order, numbers pushed into plain arrays and stored as Float32 at the end, exactly as `Float32BufferAttribute`\n * does. A test compares every array of every generator with three's, bit for bit, over a grid of parameters.\n */\nimport type { GeometryGroup, PrimitiveBuffers } from '../types'\n\nexport interface Arrays {\n vertices: number[]\n normals: number[]\n uvs: number[]\n indices: number[] | null\n groups: GeometryGroup[]\n}\n\n/** three's `arrayNeedsUint32`: 32-bit indices once any index reaches 65535. */\nexport function needsUint32(array: ArrayLike<number>): boolean {\n for (let i = array.length - 1; i >= 0; --i) if ((array[i] as number) >= 65535) return true\n return false\n}\n\nexport const indexArray = (indices: ArrayLike<number>): Uint16Array | Uint32Array => (needsUint32(indices) ? new Uint32Array(indices) : new Uint16Array(indices))\n\nexport function pack(type: string, parameters: Record<string, unknown>, a: Arrays): PrimitiveBuffers {\n return {\n type,\n parameters,\n positions: new Float32Array(a.vertices),\n normals: new Float32Array(a.normals),\n uvs: new Float32Array(a.uvs),\n ...(a.indices ? { indices: indexArray(a.indices) } : {}),\n groups: a.groups,\n }\n}\n\nconst normalize3 = (x: number, y: number, z: number): [number, number, number] => {\n const length = Math.sqrt(x * x + y * y + z * z)\n const s = 1 / (length || 1)\n return [x * s, y * s, z * s]\n}\n\nexport function box(width = 1, height = 1, depth = 1, widthSegments = 1, heightSegments = 1, depthSegments = 1): PrimitiveBuffers {\n const parameters = { width, height, depth, widthSegments, heightSegments, depthSegments }\n widthSegments = Math.floor(widthSegments)\n heightSegments = Math.floor(heightSegments)\n depthSegments = Math.floor(depthSegments)\n const indices: number[] = []\n const vertices: number[] = []\n const normals: number[] = []\n const uvs: number[] = []\n const groups: GeometryGroup[] = []\n let numberOfVertices = 0\n let groupStart = 0\n type Axis = 'x' | 'y' | 'z'\n const buildPlane = (u: Axis, v: Axis, w: Axis, udir: number, vdir: number, width: number, height: number, depth: number, gridX: number, gridY: number, materialIndex: number): void => {\n const segmentWidth = width / gridX\n const segmentHeight = height / gridY\n const widthHalf = width / 2\n const heightHalf = height / 2\n const depthHalf = depth / 2\n const gridX1 = gridX + 1\n const gridY1 = gridY + 1\n let vertexCounter = 0\n let groupCount = 0\n const vector = { x: 0, y: 0, z: 0 }\n for (let iy = 0; iy < gridY1; iy++) {\n const y = iy * segmentHeight - heightHalf\n for (let ix = 0; ix < gridX1; ix++) {\n const x = ix * segmentWidth - widthHalf\n vector[u] = x * udir\n vector[v] = y * vdir\n vector[w] = depthHalf\n vertices.push(vector.x, vector.y, vector.z)\n vector[u] = 0\n vector[v] = 0\n vector[w] = depth > 0 ? 1 : -1\n normals.push(vector.x, vector.y, vector.z)\n uvs.push(ix / gridX)\n uvs.push(1 - iy / gridY)\n vertexCounter += 1\n }\n }\n for (let iy = 0; iy < gridY; iy++) {\n for (let ix = 0; ix < gridX; ix++) {\n const a = numberOfVertices + ix + gridX1 * iy\n const b = numberOfVertices + ix + gridX1 * (iy + 1)\n const c = numberOfVertices + (ix + 1) + gridX1 * (iy + 1)\n const d = numberOfVertices + (ix + 1) + gridX1 * iy\n indices.push(a, b, d)\n indices.push(b, c, d)\n groupCount += 6\n }\n }\n groups.push({ start: groupStart, count: groupCount, materialIndex })\n groupStart += groupCount\n numberOfVertices += vertexCounter\n }\n buildPlane('z', 'y', 'x', -1, -1, depth, height, width, depthSegments, heightSegments, 0)\n buildPlane('z', 'y', 'x', 1, -1, depth, height, -width, depthSegments, heightSegments, 1)\n buildPlane('x', 'z', 'y', 1, 1, width, depth, height, widthSegments, depthSegments, 2)\n buildPlane('x', 'z', 'y', 1, -1, width, depth, -height, widthSegments, depthSegments, 3)\n buildPlane('x', 'y', 'z', 1, -1, width, height, depth, widthSegments, heightSegments, 4)\n buildPlane('x', 'y', 'z', -1, -1, width, height, -depth, widthSegments, heightSegments, 5)\n return pack('BoxGeometry', parameters, { vertices, normals, uvs, indices, groups })\n}\n\nfunction cylinderArrays(radiusTop: number, radiusBottom: number, height: number, radialSegments: number, heightSegments: number, openEnded: boolean, thetaStart: number, thetaLength: number): Arrays {\n radialSegments = Math.floor(radialSegments)\n heightSegments = Math.floor(heightSegments)\n const indices: number[] = []\n const vertices: number[] = []\n const normals: number[] = []\n const uvs: number[] = []\n const groups: GeometryGroup[] = []\n let index = 0\n const indexArray: number[][] = []\n const halfHeight = height / 2\n let groupStart = 0\n\n const generateTorso = (): void => {\n let groupCount = 0\n const slope = (radiusBottom - radiusTop) / height\n for (let y = 0; y <= heightSegments; y++) {\n const indexRow: number[] = []\n const v = y / heightSegments\n const radius = v * (radiusBottom - radiusTop) + radiusTop\n for (let x = 0; x <= radialSegments; x++) {\n const u = x / radialSegments\n const theta = u * thetaLength + thetaStart\n const sinTheta = Math.sin(theta)\n const cosTheta = Math.cos(theta)\n vertices.push(radius * sinTheta, -v * height + halfHeight, radius * cosTheta)\n const n = normalize3(sinTheta, slope, cosTheta)\n normals.push(n[0], n[1], n[2])\n uvs.push(u, 1 - v)\n indexRow.push(index++)\n }\n indexArray.push(indexRow)\n }\n for (let x = 0; x < radialSegments; x++) {\n for (let y = 0; y < heightSegments; y++) {\n const a = indexArray[y]![x]!\n const b = indexArray[y + 1]![x]!\n const c = indexArray[y + 1]![x + 1]!\n const d = indexArray[y]![x + 1]!\n indices.push(a, b, d)\n indices.push(b, c, d)\n groupCount += 6\n }\n }\n groups.push({ start: groupStart, count: groupCount, materialIndex: 0 })\n groupStart += groupCount\n }\n\n const generateCap = (top: boolean): void => {\n const centerIndexStart = index\n let groupCount = 0\n const radius = top === true ? radiusTop : radiusBottom\n const sign = top === true ? 1 : -1\n for (let x = 1; x <= radialSegments; x++) {\n vertices.push(0, halfHeight * sign, 0)\n normals.push(0, sign, 0)\n uvs.push(0.5, 0.5)\n index++\n }\n const centerIndexEnd = index\n for (let x = 0; x <= radialSegments; x++) {\n const u = x / radialSegments\n const theta = u * thetaLength + thetaStart\n const cosTheta = Math.cos(theta)\n const sinTheta = Math.sin(theta)\n vertices.push(radius * sinTheta, halfHeight * sign, radius * cosTheta)\n normals.push(0, sign, 0)\n uvs.push(cosTheta * 0.5 + 0.5, sinTheta * 0.5 * sign + 0.5)\n index++\n }\n for (let x = 0; x < radialSegments; x++) {\n const c = centerIndexStart + x\n const i = centerIndexEnd + x\n if (top === true) indices.push(i, i + 1, c)\n else indices.push(i + 1, i, c)\n groupCount += 3\n }\n groups.push({ start: groupStart, count: groupCount, materialIndex: top === true ? 1 : 2 })\n groupStart += groupCount\n }\n\n generateTorso()\n if (openEnded === false) {\n if (radiusTop > 0) generateCap(true)\n if (radiusBottom > 0) generateCap(false)\n }\n return { vertices, normals, uvs, indices, groups }\n}\n\nexport function cylinder(radiusTop = 1, radiusBottom = 1, height = 1, radialSegments = 32, heightSegments = 1, openEnded = false, thetaStart = 0, thetaLength = Math.PI * 2): PrimitiveBuffers {\n const parameters = { radiusTop, radiusBottom, height, radialSegments, heightSegments, openEnded, thetaStart, thetaLength }\n return pack('CylinderGeometry', parameters, cylinderArrays(radiusTop, radiusBottom, height, radialSegments, heightSegments, openEnded, thetaStart, thetaLength))\n}\n\nexport function cone(radius = 1, height = 1, radialSegments = 32, heightSegments = 1, openEnded = false, thetaStart = 0, thetaLength = Math.PI * 2): PrimitiveBuffers {\n const parameters = { radius, height, radialSegments, heightSegments, openEnded, thetaStart, thetaLength }\n return pack('ConeGeometry', parameters, cylinderArrays(0, radius, height, radialSegments, heightSegments, openEnded, thetaStart, thetaLength))\n}\n\nexport function sphere(radius = 1, widthSegments = 32, heightSegments = 16, phiStart = 0, phiLength = Math.PI * 2, thetaStart = 0, thetaLength = Math.PI): PrimitiveBuffers {\n const parameters = { radius, widthSegments, heightSegments, phiStart, phiLength, thetaStart, thetaLength }\n widthSegments = Math.max(3, Math.floor(widthSegments))\n heightSegments = Math.max(2, Math.floor(heightSegments))\n const thetaEnd = Math.min(thetaStart + thetaLength, Math.PI)\n let index = 0\n const grid: number[][] = []\n const indices: number[] = []\n const vertices: number[] = []\n const normals: number[] = []\n const uvs: number[] = []\n for (let iy = 0; iy <= heightSegments; iy++) {\n const verticesRow: number[] = []\n const v = iy / heightSegments\n let uOffset = 0\n if (iy === 0 && thetaStart === 0) uOffset = 0.5 / widthSegments\n else if (iy === heightSegments && thetaEnd === Math.PI) uOffset = -0.5 / widthSegments\n for (let ix = 0; ix <= widthSegments; ix++) {\n const u = ix / widthSegments\n const x = -radius * Math.cos(phiStart + u * phiLength) * Math.sin(thetaStart + v * thetaLength)\n const y = radius * Math.cos(thetaStart + v * thetaLength)\n const z = radius * Math.sin(phiStart + u * phiLength) * Math.sin(thetaStart + v * thetaLength)\n vertices.push(x, y, z)\n const n = normalize3(x, y, z)\n normals.push(n[0], n[1], n[2])\n uvs.push(u + uOffset, 1 - v)\n verticesRow.push(index++)\n }\n grid.push(verticesRow)\n }\n for (let iy = 0; iy < heightSegments; iy++) {\n for (let ix = 0; ix < widthSegments; ix++) {\n const a = grid[iy]![ix + 1]!\n const b = grid[iy]![ix]!\n const c = grid[iy + 1]![ix]!\n const d = grid[iy + 1]![ix + 1]!\n if (iy !== 0 || thetaStart > 0) indices.push(a, b, d)\n if (iy !== heightSegments - 1 || thetaEnd < Math.PI) indices.push(b, c, d)\n }\n }\n return pack('SphereGeometry', parameters, { vertices, normals, uvs, indices, groups: [] })\n}\n\nexport function plane(width = 1, height = 1, widthSegments = 1, heightSegments = 1): PrimitiveBuffers {\n const parameters = { width, height, widthSegments, heightSegments }\n const widthHalf = width / 2\n const heightHalf = height / 2\n const gridX = Math.floor(widthSegments)\n const gridY = Math.floor(heightSegments)\n const gridX1 = gridX + 1\n const gridY1 = gridY + 1\n const segmentWidth = width / gridX\n const segmentHeight = height / gridY\n const indices: number[] = []\n const vertices: number[] = []\n const normals: number[] = []\n const uvs: number[] = []\n for (let iy = 0; iy < gridY1; iy++) {\n const y = iy * segmentHeight - heightHalf\n for (let ix = 0; ix < gridX1; ix++) {\n const x = ix * segmentWidth - widthHalf\n vertices.push(x, -y, 0)\n normals.push(0, 0, 1)\n uvs.push(ix / gridX)\n uvs.push(1 - iy / gridY)\n }\n }\n for (let iy = 0; iy < gridY; iy++) {\n for (let ix = 0; ix < gridX; ix++) {\n const a = ix + gridX1 * iy\n const b = ix + gridX1 * (iy + 1)\n const c = ix + 1 + gridX1 * (iy + 1)\n const d = ix + 1 + gridX1 * iy\n indices.push(a, b, d)\n indices.push(b, c, d)\n }\n }\n return pack('PlaneGeometry', parameters, { vertices, normals, uvs, indices, groups: [] })\n}\n\nexport function circle(radius = 1, segments = 32, thetaStart = 0, thetaLength = Math.PI * 2): PrimitiveBuffers {\n const parameters = { radius, segments, thetaStart, thetaLength }\n segments = Math.max(3, segments)\n const indices: number[] = []\n const vertices: number[] = []\n const normals: number[] = []\n const uvs: number[] = []\n vertices.push(0, 0, 0)\n normals.push(0, 0, 1)\n uvs.push(0.5, 0.5)\n for (let s = 0, i = 3; s <= segments; s++, i += 3) {\n const segment = thetaStart + (s / segments) * thetaLength\n // the vector's z stays 0, as three's Vector3\n vertices.push(radius * Math.cos(segment), radius * Math.sin(segment), 0)\n normals.push(0, 0, 1)\n uvs.push(((vertices[i] as number) / radius + 1) / 2, ((vertices[i + 1] as number) / radius + 1) / 2)\n }\n for (let i = 1; i <= segments; i++) indices.push(i, i + 1, 0)\n return pack('CircleGeometry', parameters, { vertices, normals, uvs, indices, groups: [] })\n}\n\nexport function ring(innerRadius = 0.5, outerRadius = 1, thetaSegments = 32, phiSegments = 1, thetaStart = 0, thetaLength = Math.PI * 2): PrimitiveBuffers {\n const parameters = { innerRadius, outerRadius, thetaSegments, phiSegments, thetaStart, thetaLength }\n thetaSegments = Math.max(3, thetaSegments)\n phiSegments = Math.max(1, phiSegments)\n const indices: number[] = []\n const vertices: number[] = []\n const normals: number[] = []\n const uvs: number[] = []\n let radius = innerRadius\n const radiusStep = (outerRadius - innerRadius) / phiSegments\n for (let j = 0; j <= phiSegments; j++) {\n for (let i = 0; i <= thetaSegments; i++) {\n const segment = thetaStart + (i / thetaSegments) * thetaLength\n const x = radius * Math.cos(segment)\n const y = radius * Math.sin(segment)\n vertices.push(x, y, 0)\n normals.push(0, 0, 1)\n uvs.push((x / outerRadius + 1) / 2, (y / outerRadius + 1) / 2)\n }\n radius += radiusStep\n }\n for (let j = 0; j < phiSegments; j++) {\n const thetaSegmentLevel = j * (thetaSegments + 1)\n for (let i = 0; i < thetaSegments; i++) {\n const segment = i + thetaSegmentLevel\n const a = segment\n const b = segment + thetaSegments + 1\n const c = segment + thetaSegments + 2\n const d = segment + 1\n indices.push(a, b, d)\n indices.push(b, c, d)\n }\n }\n return pack('RingGeometry', parameters, { vertices, normals, uvs, indices, groups: [] })\n}\n\nexport function lathe(points: ReadonlyArray<readonly [number, number]>, segments = 12, phiStart = 0, phiLength = Math.PI * 2): PrimitiveBuffers {\n const parameters = { points: points.map(([x, y]) => ({ x, y })), segments, phiStart, phiLength }\n segments = Math.floor(segments)\n phiLength = Math.max(0, Math.min(Math.PI * 2, phiLength))\n const indices: number[] = []\n const vertices: number[] = []\n const uvs: number[] = []\n const initNormals: number[] = []\n const normals: number[] = []\n const inverseSegments = 1.0 / segments\n const normal = { x: 0, y: 0, z: 0 }\n const curNormal = { x: 0, y: 0, z: 0 }\n const prevNormal = { x: 0, y: 0, z: 0 }\n let dx = 0\n let dy = 0\n const last = points.length - 1\n const px = (j: number): number => (points[j] as readonly [number, number])[0]\n const py = (j: number): number => (points[j] as readonly [number, number])[1]\n const setNormalized = (): void => {\n const n = normalize3(normal.x, normal.y, normal.z)\n normal.x = n[0]\n normal.y = n[1]\n normal.z = n[2]\n }\n for (let j = 0; j <= last; j++) {\n if (j === 0) {\n dx = px(j + 1) - px(j)\n dy = py(j + 1) - py(j)\n normal.x = dy * 1.0\n normal.y = -dx\n normal.z = dy * 0.0\n prevNormal.x = normal.x\n prevNormal.y = normal.y\n prevNormal.z = normal.z\n setNormalized()\n initNormals.push(normal.x, normal.y, normal.z)\n } else if (j === last) {\n initNormals.push(prevNormal.x, prevNormal.y, prevNormal.z)\n } else {\n dx = px(j + 1) - px(j)\n dy = py(j + 1) - py(j)\n normal.x = dy * 1.0\n normal.y = -dx\n normal.z = dy * 0.0\n curNormal.x = normal.x\n curNormal.y = normal.y\n curNormal.z = normal.z\n normal.x += prevNormal.x\n normal.y += prevNormal.y\n normal.z += prevNormal.z\n setNormalized()\n initNormals.push(normal.x, normal.y, normal.z)\n prevNormal.x = curNormal.x\n prevNormal.y = curNormal.y\n prevNormal.z = curNormal.z\n }\n }\n for (let i = 0; i <= segments; i++) {\n const phi = phiStart + i * inverseSegments * phiLength\n const sin = Math.sin(phi)\n const cos = Math.cos(phi)\n for (let j = 0; j <= last; j++) {\n vertices.push(px(j) * sin, py(j), px(j) * cos)\n uvs.push(i / segments, j / (points.length - 1))\n const x = (initNormals[3 * j + 0] as number) * sin\n const y = initNormals[3 * j + 1] as number\n const z = (initNormals[3 * j + 0] as number) * cos\n normals.push(x, y, z)\n }\n }\n for (let i = 0; i < segments; i++) {\n for (let j = 0; j < points.length - 1; j++) {\n const base = j + i * points.length\n const a = base\n const b = base + points.length\n const c = base + points.length + 1\n const d = base + 1\n indices.push(a, b, d)\n indices.push(c, d, b)\n }\n }\n return pack('LatheGeometry', parameters, { vertices, normals, uvs, indices, groups: [] })\n}\n\nexport function torus(radius = 1, tube = 0.4, radialSegments = 12, tubularSegments = 48, arc = Math.PI * 2): PrimitiveBuffers {\n const parameters = { radius, tube, radialSegments, tubularSegments, arc }\n radialSegments = Math.floor(radialSegments)\n tubularSegments = Math.floor(tubularSegments)\n const indices: number[] = []\n const vertices: number[] = []\n const normals: number[] = []\n const uvs: number[] = []\n for (let j = 0; j <= radialSegments; j++) {\n for (let i = 0; i <= tubularSegments; i++) {\n const u = (i / tubularSegments) * arc\n const v = (j / radialSegments) * Math.PI * 2\n const x = (radius + tube * Math.cos(v)) * Math.cos(u)\n const y = (radius + tube * Math.cos(v)) * Math.sin(u)\n const z = tube * Math.sin(v)\n vertices.push(x, y, z)\n const cx = radius * Math.cos(u)\n const cy = radius * Math.sin(u)\n const n = normalize3(x - cx, y - cy, z - 0)\n normals.push(n[0], n[1], n[2])\n uvs.push(i / tubularSegments)\n uvs.push(j / radialSegments)\n }\n }\n for (let j = 1; j <= radialSegments; j++) {\n for (let i = 1; i <= tubularSegments; i++) {\n const a = (tubularSegments + 1) * j + i - 1\n const b = (tubularSegments + 1) * (j - 1) + i - 1\n const c = (tubularSegments + 1) * (j - 1) + i\n const d = (tubularSegments + 1) * j + i\n indices.push(a, b, d)\n indices.push(b, c, d)\n }\n }\n return pack('TorusGeometry', parameters, { vertices, normals, uvs, indices, groups: [] })\n}\n","import type { HoleSpec, PrimitiveBuffers, Vec3 } from '../types'\nimport { indexArray } from './three-generators'\n\n/**\n * A box (centred, `size = [w, h, d]`) minus rectangular prisms that go all the way through it along z: the cheap, exact boolean (walls with\n * windows and doors). The face is cut into a grid at every hole edge; each solid cell gets its front and back quads, and every cell edge between\n * solid and empty (a hole or the outside) gets a quad over the depth facing the empty side, so the outer sides and the reveals come out of the\n * same rule. Front uvs map the face to [0, 1]; side uvs run along the edge and the depth.\n */\nexport function difference(size: Vec3, subtract: readonly HoleSpec[]): PrimitiveBuffers {\n const [w, h, d] = size\n const hw = w / 2\n const hh = h / 2\n const hd = d / 2\n const holes = subtract\n .map((hole) => ({ x0: Math.max(-hw, Math.min(hole.min[0], hole.max[0])), x1: Math.min(hw, Math.max(hole.min[0], hole.max[0])), y0: Math.max(-hh, Math.min(hole.min[1], hole.max[1])), y1: Math.min(hh, Math.max(hole.min[1], hole.max[1])) }))\n .filter((hole) => hole.x1 > hole.x0 && hole.y1 > hole.y0)\n const cuts = (lo: number, hi: number, values: number[]): number[] => [...new Set([lo, hi, ...values.filter((v) => v > lo && v < hi)])].sort((a, b) => a - b)\n const xs = cuts(-hw, hw, holes.flatMap((hole) => [hole.x0, hole.x1]))\n const ys = cuts(-hh, hh, holes.flatMap((hole) => [hole.y0, hole.y1]))\n const nx = xs.length - 1\n const ny = ys.length - 1\n const solid = (i: number, j: number): boolean => {\n if (i < 0 || j < 0 || i >= nx || j >= ny) return false\n const cx = ((xs[i] as number) + (xs[i + 1] as number)) / 2\n const cy = ((ys[j] as number) + (ys[j + 1] as number)) / 2\n return !holes.some((hole) => cx > hole.x0 && cx < hole.x1 && cy > hole.y0 && cy < hole.y1)\n }\n const positions: number[] = []\n const normals: number[] = []\n const uvs: number[] = []\n const indices: number[] = []\n const quad = (corners: readonly (readonly [number, number, number])[], normal: readonly [number, number, number], uv: readonly (readonly [number, number])[]): void => {\n const base = positions.length / 3\n for (let k = 0; k < 4; k++) {\n positions.push(...(corners[k] as [number, number, number]))\n normals.push(...normal)\n uvs.push(...(uv[k] as [number, number]))\n }\n indices.push(base, base + 1, base + 2, base, base + 2, base + 3)\n }\n const fu = (x: number): number => (x + hw) / w\n const fv = (y: number): number => (y + hh) / h\n for (let j = 0; j < ny; j++) {\n for (let i = 0; i < nx; i++) {\n if (!solid(i, j)) continue\n const x0 = xs[i] as number\n const x1 = xs[i + 1] as number\n const y0 = ys[j] as number\n const y1 = ys[j + 1] as number\n quad([[x0, y0, hd], [x1, y0, hd], [x1, y1, hd], [x0, y1, hd]], [0, 0, 1], [[fu(x0), fv(y0)], [fu(x1), fv(y0)], [fu(x1), fv(y1)], [fu(x0), fv(y1)]])\n quad([[x1, y0, -hd], [x0, y0, -hd], [x0, y1, -hd], [x1, y1, -hd]], [0, 0, -1], [[1 - fu(x1), fv(y0)], [1 - fu(x0), fv(y0)], [1 - fu(x0), fv(y1)], [1 - fu(x1), fv(y1)]])\n const zu = (z: number): number => (z + hd) / d\n if (!solid(i - 1, j)) quad([[x0, y0, -hd], [x0, y0, hd], [x0, y1, hd], [x0, y1, -hd]], [-1, 0, 0], [[zu(-hd), fv(y0)], [zu(hd), fv(y0)], [zu(hd), fv(y1)], [zu(-hd), fv(y1)]])\n if (!solid(i + 1, j)) quad([[x1, y0, hd], [x1, y0, -hd], [x1, y1, -hd], [x1, y1, hd]], [1, 0, 0], [[zu(hd), fv(y0)], [zu(-hd), fv(y0)], [zu(-hd), fv(y1)], [zu(hd), fv(y1)]])\n if (!solid(i, j - 1)) quad([[x0, y0, -hd], [x1, y0, -hd], [x1, y0, hd], [x0, y0, hd]], [0, -1, 0], [[fu(x0), zu(-hd)], [fu(x1), zu(-hd)], [fu(x1), zu(hd)], [fu(x0), zu(hd)]])\n if (!solid(i, j + 1)) quad([[x0, y1, hd], [x1, y1, hd], [x1, y1, -hd], [x0, y1, -hd]], [0, 1, 0], [[fu(x0), zu(hd)], [fu(x1), zu(hd)], [fu(x1), zu(-hd)], [fu(x0), zu(-hd)]])\n }\n }\n return {\n type: 'BufferGeometry',\n parameters: { size: [w, h, d], subtract: holes.map((hole) => ({ min: [hole.x0, hole.y0], max: [hole.x1, hole.y1] })) },\n positions: new Float32Array(positions),\n normals: new Float32Array(normals),\n uvs: new Float32Array(uvs),\n indices: indexArray(indices),\n groups: [],\n }\n}\n","/* eslint-disable */\n// @ts-nocheck -- verbatim copy of three.js r160 src/extras/Earcut.js (MIT), itself a port of mapbox/earcut v2.2.4 (ISC); kept as is so triangulation matches three\n/**\n * Port from https://github.com/mapbox/earcut (v2.2.4)\n */\n\nconst Earcut = {\n\n\ttriangulate: function ( data, holeIndices, dim = 2 ) {\n\n\t\tconst hasHoles = holeIndices && holeIndices.length;\n\t\tconst outerLen = hasHoles ? holeIndices[ 0 ] * dim : data.length;\n\t\tlet outerNode = linkedList( data, 0, outerLen, dim, true );\n\t\tconst triangles = [];\n\n\t\tif ( ! outerNode || outerNode.next === outerNode.prev ) return triangles;\n\n\t\tlet minX, minY, maxX, maxY, x, y, invSize;\n\n\t\tif ( hasHoles ) outerNode = eliminateHoles( data, holeIndices, outerNode, dim );\n\n\t\t// if the shape is not too simple, we'll use z-order curve hash later; calculate polygon bbox\n\t\tif ( data.length > 80 * dim ) {\n\n\t\t\tminX = maxX = data[ 0 ];\n\t\t\tminY = maxY = data[ 1 ];\n\n\t\t\tfor ( let i = dim; i < outerLen; i += dim ) {\n\n\t\t\t\tx = data[ i ];\n\t\t\t\ty = data[ i + 1 ];\n\t\t\t\tif ( x < minX ) minX = x;\n\t\t\t\tif ( y < minY ) minY = y;\n\t\t\t\tif ( x > maxX ) maxX = x;\n\t\t\t\tif ( y > maxY ) maxY = y;\n\n\t\t\t}\n\n\t\t\t// minX, minY and invSize are later used to transform coords into integers for z-order calculation\n\t\t\tinvSize = Math.max( maxX - minX, maxY - minY );\n\t\t\tinvSize = invSize !== 0 ? 32767 / invSize : 0;\n\n\t\t}\n\n\t\tearcutLinked( outerNode, triangles, dim, minX, minY, invSize, 0 );\n\n\t\treturn triangles;\n\n\t}\n\n};\n\n// create a circular doubly linked list from polygon points in the specified winding order\nfunction linkedList( data, start, end, dim, clockwise ) {\n\n\tlet i, last;\n\n\tif ( clockwise === ( signedArea( data, start, end, dim ) > 0 ) ) {\n\n\t\tfor ( i = start; i < end; i += dim ) last = insertNode( i, data[ i ], data[ i + 1 ], last );\n\n\t} else {\n\n\t\tfor ( i = end - dim; i >= start; i -= dim ) last = insertNode( i, data[ i ], data[ i + 1 ], last );\n\n\t}\n\n\tif ( last && equals( last, last.next ) ) {\n\n\t\tremoveNode( last );\n\t\tlast = last.next;\n\n\t}\n\n\treturn last;\n\n}\n\n// eliminate colinear or duplicate points\nfunction filterPoints( start, end ) {\n\n\tif ( ! start ) return start;\n\tif ( ! end ) end = start;\n\n\tlet p = start,\n\t\tagain;\n\tdo {\n\n\t\tagain = false;\n\n\t\tif ( ! p.steiner && ( equals( p, p.next ) || area( p.prev, p, p.next ) === 0 ) ) {\n\n\t\t\tremoveNode( p );\n\t\t\tp = end = p.prev;\n\t\t\tif ( p === p.next ) break;\n\t\t\tagain = true;\n\n\t\t} else {\n\n\t\t\tp = p.next;\n\n\t\t}\n\n\t} while ( again || p !== end );\n\n\treturn end;\n\n}\n\n// main ear slicing loop which triangulates a polygon (given as a linked list)\nfunction earcutLinked( ear, triangles, dim, minX, minY, invSize, pass ) {\n\n\tif ( ! ear ) return;\n\n\t// interlink polygon nodes in z-order\n\tif ( ! pass && invSize ) indexCurve( ear, minX, minY, invSize );\n\n\tlet stop = ear,\n\t\tprev, next;\n\n\t// iterate through ears, slicing them one by one\n\twhile ( ear.prev !== ear.next ) {\n\n\t\tprev = ear.prev;\n\t\tnext = ear.next;\n\n\t\tif ( invSize ? isEarHashed( ear, minX, minY, invSize ) : isEar( ear ) ) {\n\n\t\t\t// cut off the triangle\n\t\t\ttriangles.push( prev.i / dim | 0 );\n\t\t\ttriangles.push( ear.i / dim | 0 );\n\t\t\ttriangles.push( next.i / dim | 0 );\n\n\t\t\tremoveNode( ear );\n\n\t\t\t// skipping the next vertex leads to less sliver triangles\n\t\t\tear = next.next;\n\t\t\tstop = next.next;\n\n\t\t\tcontinue;\n\n\t\t}\n\n\t\tear = next;\n\n\t\t// if we looped through the whole remaining polygon and can't find any more ears\n\t\tif ( ear === stop ) {\n\n\t\t\t// try filtering points and slicing again\n\t\t\tif ( ! pass ) {\n\n\t\t\t\tearcutLinked( filterPoints( ear ), triangles, dim, minX, minY, invSize, 1 );\n\n\t\t\t\t// if this didn't work, try curing all small self-intersections locally\n\n\t\t\t} else if ( pass === 1 ) {\n\n\t\t\t\tear = cureLocalIntersections( filterPoints( ear ), triangles, dim );\n\t\t\t\tearcutLinked( ear, triangles, dim, minX, minY, invSize, 2 );\n\n\t\t\t\t// as a last resort, try splitting the remaining polygon into two\n\n\t\t\t} else if ( pass === 2 ) {\n\n\t\t\t\tsplitEarcut( ear, triangles, dim, minX, minY, invSize );\n\n\t\t\t}\n\n\t\t\tbreak;\n\n\t\t}\n\n\t}\n\n}\n\n// check whether a polygon node forms a valid ear with adjacent nodes\nfunction isEar( ear ) {\n\n\tconst a = ear.prev,\n\t\tb = ear,\n\t\tc = ear.next;\n\n\tif ( area( a, b, c ) >= 0 ) return false; // reflex, can't be an ear\n\n\t// now make sure we don't have other points inside the potential ear\n\tconst ax = a.x, bx = b.x, cx = c.x, ay = a.y, by = b.y, cy = c.y;\n\n\t// triangle bbox; min & max are calculated like this for speed\n\tconst x0 = ax < bx ? ( ax < cx ? ax : cx ) : ( bx < cx ? bx : cx ),\n\t\ty0 = ay < by ? ( ay < cy ? ay : cy ) : ( by < cy ? by : cy ),\n\t\tx1 = ax > bx ? ( ax > cx ? ax : cx ) : ( bx > cx ? bx : cx ),\n\t\ty1 = ay > by ? ( ay > cy ? ay : cy ) : ( by > cy ? by : cy );\n\n\tlet p = c.next;\n\twhile ( p !== a ) {\n\n\t\tif ( p.x >= x0 && p.x <= x1 && p.y >= y0 && p.y <= y1 &&\n\t\t\tpointInTriangle( ax, ay, bx, by, cx, cy, p.x, p.y ) &&\n\t\t\tarea( p.prev, p, p.next ) >= 0 ) return false;\n\t\tp = p.next;\n\n\t}\n\n\treturn true;\n\n}\n\nfunction isEarHashed( ear, minX, minY, invSize ) {\n\n\tconst a = ear.prev,\n\t\tb = ear,\n\t\tc = ear.next;\n\n\tif ( area( a, b, c ) >= 0 ) return false; // reflex, can't be an ear\n\n\tconst ax = a.x, bx = b.x, cx = c.x, ay = a.y, by = b.y, cy = c.y;\n\n\t// triangle bbox; min & max are calculated like this for speed\n\tconst x0 = ax < bx ? ( ax < cx ? ax : cx ) : ( bx < cx ? bx : cx ),\n\t\ty0 = ay < by ? ( ay < cy ? ay : cy ) : ( by < cy ? by : cy ),\n\t\tx1 = ax > bx ? ( ax > cx ? ax : cx ) : ( bx > cx ? bx : cx ),\n\t\ty1 = ay > by ? ( ay > cy ? ay : cy ) : ( by > cy ? by : cy );\n\n\t// z-order range for the current triangle bbox;\n\tconst minZ = zOrder( x0, y0, minX, minY, invSize ),\n\t\tmaxZ = zOrder( x1, y1, minX, minY, invSize );\n\n\tlet p = ear.prevZ,\n\t\tn = ear.nextZ;\n\n\t// look for points inside the triangle in both directions\n\twhile ( p && p.z >= minZ && n && n.z <= maxZ ) {\n\n\t\tif ( p.x >= x0 && p.x <= x1 && p.y >= y0 && p.y <= y1 && p !== a && p !== c &&\n\t\t\tpointInTriangle( ax, ay, bx, by, cx, cy, p.x, p.y ) && area( p.prev, p, p.next ) >= 0 ) return false;\n\t\tp = p.prevZ;\n\n\t\tif ( n.x >= x0 && n.x <= x1 && n.y >= y0 && n.y <= y1 && n !== a && n !== c &&\n\t\t\tpointInTriangle( ax, ay, bx, by, cx, cy, n.x, n.y ) && area( n.prev, n, n.next ) >= 0 ) return false;\n\t\tn = n.nextZ;\n\n\t}\n\n\t// look for remaining points in decreasing z-order\n\twhile ( p && p.z >= minZ ) {\n\n\t\tif ( p.x >= x0 && p.x <= x1 && p.y >= y0 && p.y <= y1 && p !== a && p !== c &&\n\t\t\tpointInTriangle( ax, ay, bx, by, cx, cy, p.x, p.y ) && area( p.prev, p, p.next ) >= 0 ) return false;\n\t\tp = p.prevZ;\n\n\t}\n\n\t// look for remaining points in increasing z-order\n\twhile ( n && n.z <= maxZ ) {\n\n\t\tif ( n.x >= x0 && n.x <= x1 && n.y >= y0 && n.y <= y1 && n !== a && n !== c &&\n\t\t\tpointInTriangle( ax, ay, bx, by, cx, cy, n.x, n.y ) && area( n.prev, n, n.next ) >= 0 ) return false;\n\t\tn = n.nextZ;\n\n\t}\n\n\treturn true;\n\n}\n\n// go through all polygon nodes and cure small local self-intersections\nfunction cureLocalIntersections( start, triangles, dim ) {\n\n\tlet p = start;\n\tdo {\n\n\t\tconst a = p.prev,\n\t\t\tb = p.next.next;\n\n\t\tif ( ! equals( a, b ) && intersects( a, p, p.next, b ) && locallyInside( a, b ) && locallyInside( b, a ) ) {\n\n\t\t\ttriangles.push( a.i / dim | 0 );\n\t\t\ttriangles.push( p.i / dim | 0 );\n\t\t\ttriangles.push( b.i / dim | 0 );\n\n\t\t\t// remove two nodes involved\n\t\t\tremoveNode( p );\n\t\t\tremoveNode( p.next );\n\n\t\t\tp = start = b;\n\n\t\t}\n\n\t\tp = p.next;\n\n\t} while ( p !== start );\n\n\treturn filterPoints( p );\n\n}\n\n// try splitting polygon into two and triangulate them independently\nfunction splitEarcut( start, triangles, dim, minX, minY, invSize ) {\n\n\t// look for a valid diagonal that divides the polygon into two\n\tlet a = start;\n\tdo {\n\n\t\tlet b = a.next.next;\n\t\twhile ( b !== a.prev ) {\n\n\t\t\tif ( a.i !== b.i && isValidDiagonal( a, b ) ) {\n\n\t\t\t\t// split the polygon in two by the diagonal\n\t\t\t\tlet c = splitPolygon( a, b );\n\n\t\t\t\t// filter colinear points around the cuts\n\t\t\t\ta = filterPoints( a, a.next );\n\t\t\t\tc = filterPoints( c, c.next );\n\n\t\t\t\t// run earcut on each half\n\t\t\t\tearcutLinked( a, triangles, dim, minX, minY, invSize, 0 );\n\t\t\t\tearcutLinked( c, triangles, dim, minX, minY, invSize, 0 );\n\t\t\t\treturn;\n\n\t\t\t}\n\n\t\t\tb = b.next;\n\n\t\t}\n\n\t\ta = a.next;\n\n\t} while ( a !== start );\n\n}\n\n// link every hole into the outer loop, producing a single-ring polygon without holes\nfunction eliminateHoles( data, holeIndices, outerNode, dim ) {\n\n\tconst queue = [];\n\tlet i, len, start, end, list;\n\n\tfor ( i = 0, len = holeIndices.length; i < len; i ++ ) {\n\n\t\tstart = holeIndices[ i ] * dim;\n\t\tend = i < len - 1 ? holeIndices[ i + 1 ] * dim : data.length;\n\t\tlist = linkedList( data, start, end, dim, false );\n\t\tif ( list === list.next ) list.steiner = true;\n\t\tqueue.push( getLeftmost( list ) );\n\n\t}\n\n\tqueue.sort( compareX );\n\n\t// process holes from left to right\n\tfor ( i = 0; i < queue.length; i ++ ) {\n\n\t\touterNode = eliminateHole( queue[ i ], outerNode );\n\n\t}\n\n\treturn outerNode;\n\n}\n\nfunction compareX( a, b ) {\n\n\treturn a.x - b.x;\n\n}\n\n// find a bridge between vertices that connects hole with an outer ring and link it\nfunction eliminateHole( hole, outerNode ) {\n\n\tconst bridge = findHoleBridge( hole, outerNode );\n\tif ( ! bridge ) {\n\n\t\treturn outerNode;\n\n\t}\n\n\tconst bridgeReverse = splitPolygon( bridge, hole );\n\n\t// filter collinear points around the cuts\n\tfilterPoints( bridgeReverse, bridgeReverse.next );\n\treturn filterPoints( bridge, bridge.next );\n\n}\n\n// David Eberly's algorithm for finding a bridge between hole and outer polygon\nfunction findHoleBridge( hole, outerNode ) {\n\n\tlet p = outerNode,\n\t\tqx = - Infinity,\n\t\tm;\n\n\tconst hx = hole.x, hy = hole.y;\n\n\t// find a segment intersected by a ray from the hole's leftmost point to the left;\n\t// segment's endpoint with lesser x will be potential connection point\n\tdo {\n\n\t\tif ( hy <= p.y && hy >= p.next.y && p.next.y !== p.y ) {\n\n\t\t\tconst x = p.x + ( hy - p.y ) * ( p.next.x - p.x ) / ( p.next.y - p.y );\n\t\t\tif ( x <= hx && x > qx ) {\n\n\t\t\t\tqx = x;\n\t\t\t\tm = p.x < p.next.x ? p : p.next;\n\t\t\t\tif ( x === hx ) return m; // hole touches outer segment; pick leftmost endpoint\n\n\t\t\t}\n\n\t\t}\n\n\t\tp = p.next;\n\n\t} while ( p !== outerNode );\n\n\tif ( ! m ) return null;\n\n\t// look for points inside the triangle of hole point, segment intersection and endpoint;\n\t// if there are no points found, we have a valid connection;\n\t// otherwise choose the point of the minimum angle with the ray as connection point\n\n\tconst stop = m,\n\t\tmx = m.x,\n\t\tmy = m.y;\n\tlet tanMin = Infinity, tan;\n\n\tp = m;\n\n\tdo {\n\n\t\tif ( hx >= p.x && p.x >= mx && hx !== p.x &&\n\t\t\t\tpointInTriangle( hy < my ? hx : qx, hy, mx, my, hy < my ? qx : hx, hy, p.x, p.y ) ) {\n\n\t\t\ttan = Math.abs( hy - p.y ) / ( hx - p.x ); // tangential\n\n\t\t\tif ( locallyInside( p, hole ) && ( tan < tanMin || ( tan === tanMin && ( p.x > m.x || ( p.x === m.x && sectorContainsSector( m, p ) ) ) ) ) ) {\n\n\t\t\t\tm = p;\n\t\t\t\ttanMin = tan;\n\n\t\t\t}\n\n\t\t}\n\n\t\tp = p.next;\n\n\t} while ( p !== stop );\n\n\treturn m;\n\n}\n\n// whether sector in vertex m contains sector in vertex p in the same coordinates\nfunction sectorContainsSector( m, p ) {\n\n\treturn area( m.prev, m, p.prev ) < 0 && area( p.next, m, m.next ) < 0;\n\n}\n\n// interlink polygon nodes in z-order\nfunction indexCurve( start, minX, minY, invSize ) {\n\n\tlet p = start;\n\tdo {\n\n\t\tif ( p.z === 0 ) p.z = zOrder( p.x, p.y, minX, minY, invSize );\n\t\tp.prevZ = p.prev;\n\t\tp.nextZ = p.next;\n\t\tp = p.next;\n\n\t} while ( p !== start );\n\n\tp.prevZ.nextZ = null;\n\tp.prevZ = null;\n\n\tsortLinked( p );\n\n}\n\n// Simon Tatham's linked list merge sort algorithm\n// http://www.chiark.greenend.org.uk/~sgtatham/algorithms/listsort.html\nfunction sortLinked( list ) {\n\n\tlet i, p, q, e, tail, numMerges, pSize, qSize,\n\t\tinSize = 1;\n\n\tdo {\n\n\t\tp = list;\n\t\tlist = null;\n\t\ttail = null;\n\t\tnumMerges = 0;\n\n\t\twhile ( p ) {\n\n\t\t\tnumMerges ++;\n\t\t\tq = p;\n\t\t\tpSize = 0;\n\t\t\tfor ( i = 0; i < inSize; i ++ ) {\n\n\t\t\t\tpSize ++;\n\t\t\t\tq = q.nextZ;\n\t\t\t\tif ( ! q ) break;\n\n\t\t\t}\n\n\t\t\tqSize = inSize;\n\n\t\t\twhile ( pSize > 0 || ( qSize > 0 && q ) ) {\n\n\t\t\t\tif ( pSize !== 0 && ( qSize === 0 || ! q || p.z <= q.z ) ) {\n\n\t\t\t\t\te = p;\n\t\t\t\t\tp = p.nextZ;\n\t\t\t\t\tpSize --;\n\n\t\t\t\t} else {\n\n\t\t\t\t\te = q;\n\t\t\t\t\tq = q.nextZ;\n\t\t\t\t\tqSize --;\n\n\t\t\t\t}\n\n\t\t\t\tif ( tail ) tail.nextZ = e;\n\t\t\t\telse list = e;\n\n\t\t\t\te.prevZ = tail;\n\t\t\t\ttail = e;\n\n\t\t\t}\n\n\t\t\tp = q;\n\n\t\t}\n\n\t\ttail.nextZ = null;\n\t\tinSize *= 2;\n\n\t} while ( numMerges > 1 );\n\n\treturn list;\n\n}\n\n// z-order of a point given coords and inverse of the longer side of data bbox\nfunction zOrder( x, y, minX, minY, invSize ) {\n\n\t// coords are transformed into non-negative 15-bit integer range\n\tx = ( x - minX ) * invSize | 0;\n\ty = ( y - minY ) * invSize | 0;\n\n\tx = ( x | ( x << 8 ) ) & 0x00FF00FF;\n\tx = ( x | ( x << 4 ) ) & 0x0F0F0F0F;\n\tx = ( x | ( x << 2 ) ) & 0x33333333;\n\tx = ( x | ( x << 1 ) ) & 0x55555555;\n\n\ty = ( y | ( y << 8 ) ) & 0x00FF00FF;\n\ty = ( y | ( y << 4 ) ) & 0x0F0F0F0F;\n\ty = ( y | ( y << 2 ) ) & 0x33333333;\n\ty = ( y | ( y << 1 ) ) & 0x55555555;\n\n\treturn x | ( y << 1 );\n\n}\n\n// find the leftmost node of a polygon ring\nfunction getLeftmost( start ) {\n\n\tlet p = start,\n\t\tleftmost = start;\n\tdo {\n\n\t\tif ( p.x < leftmost.x || ( p.x === leftmost.x && p.y < leftmost.y ) ) leftmost = p;\n\t\tp = p.next;\n\n\t} while ( p !== start );\n\n\treturn leftmost;\n\n}\n\n// check if a point lies within a convex triangle\nfunction pointInTriangle( ax, ay, bx, by, cx, cy, px, py ) {\n\n\treturn ( cx - px ) * ( ay - py ) >= ( ax - px ) * ( cy - py ) &&\n ( ax - px ) * ( by - py ) >= ( bx - px ) * ( ay - py ) &&\n ( bx - px ) * ( cy - py ) >= ( cx - px ) * ( by - py );\n\n}\n\n// check if a diagonal between two polygon nodes is valid (lies in polygon interior)\nfunction isValidDiagonal( a, b ) {\n\n\treturn a.next.i !== b.i && a.prev.i !== b.i && ! intersectsPolygon( a, b ) && // dones't intersect other edges\n ( locallyInside( a, b ) && locallyInside( b, a ) && middleInside( a, b ) && // locally visible\n ( area( a.prev, a, b.prev ) || area( a, b.prev, b ) ) || // does not create opposite-facing sectors\n equals( a, b ) && area( a.prev, a, a.next ) > 0 && area( b.prev, b, b.next ) > 0 ); // special zero-length case\n\n}\n\n// signed area of a triangle\nfunction area( p, q, r ) {\n\n\treturn ( q.y - p.y ) * ( r.x - q.x ) - ( q.x - p.x ) * ( r.y - q.y );\n\n}\n\n// check if two points are equal\nfunction equals( p1, p2 ) {\n\n\treturn p1.x === p2.x && p1.y === p2.y;\n\n}\n\n// check if two segments intersect\nfunction intersects( p1, q1, p2, q2 ) {\n\n\tconst o1 = sign( area( p1, q1, p2 ) );\n\tconst o2 = sign( area( p1, q1, q2 ) );\n\tconst o3 = sign( area( p2, q2, p1 ) );\n\tconst o4 = sign( area( p2, q2, q1 ) );\n\n\tif ( o1 !== o2 && o3 !== o4 ) return true; // general case\n\n\tif ( o1 === 0 && onSegment( p1, p2, q1 ) ) return true; // p1, q1 and p2 are collinear and p2 lies on p1q1\n\tif ( o2 === 0 && onSegment( p1, q2, q1 ) ) return true; // p1, q1 and q2 are collinear and q2 lies on p1q1\n\tif ( o3 === 0 && onSegment( p2, p1, q2 ) ) return true; // p2, q2 and p1 are collinear and p1 lies on p2q2\n\tif ( o4 === 0 && onSegment( p2, q1, q2 ) ) return true; // p2, q2 and q1 are collinear and q1 lies on p2q2\n\n\treturn false;\n\n}\n\n// for collinear points p, q, r, check if point q lies on segment pr\nfunction onSegment( p, q, r ) {\n\n\treturn q.x <= Math.max( p.x, r.x ) && q.x >= Math.min( p.x, r.x ) && q.y <= Math.max( p.y, r.y ) && q.y >= Math.min( p.y, r.y );\n\n}\n\nfunction sign( num ) {\n\n\treturn num > 0 ? 1 : num < 0 ? - 1 : 0;\n\n}\n\n// check if a polygon diagonal intersects any polygon segments\nfunction intersectsPolygon( a, b ) {\n\n\tlet p = a;\n\tdo {\n\n\t\tif ( p.i !== a.i && p.next.i !== a.i && p.i !== b.i && p.next.i !== b.i &&\n\t\t\tintersects( p, p.next, a, b ) ) return true;\n\t\tp = p.next;\n\n\t} while ( p !== a );\n\n\treturn false;\n\n}\n\n// check if a polygon diagonal is locally inside the polygon\nfunction locallyInside( a, b ) {\n\n\treturn area( a.prev, a, a.next ) < 0 ?\n\t\tarea( a, b, a.next ) >= 0 && area( a, a.prev, b ) >= 0 :\n\t\tarea( a, b, a.prev ) < 0 || area( a, a.next, b ) < 0;\n\n}\n\n// check if the middle point of a polygon diagonal is inside the polygon\nfunction middleInside( a, b ) {\n\n\tlet p = a,\n\t\tinside = false;\n\tconst px = ( a.x + b.x ) / 2,\n\t\tpy = ( a.y + b.y ) / 2;\n\tdo {\n\n\t\tif ( ( ( p.y > py ) !== ( p.next.y > py ) ) && p.next.y !== p.y &&\n\t\t\t( px < ( p.next.x - p.x ) * ( py - p.y ) / ( p.next.y - p.y ) + p.x ) )\n\t\t\tinside = ! inside;\n\t\tp = p.next;\n\n\t} while ( p !== a );\n\n\treturn inside;\n\n}\n\n// link two polygon vertices with a bridge; if the vertices belong to the same ring, it splits polygon into two;\n// if one belongs to the outer ring and another to a hole, it merges it into a single ring\nfunction splitPolygon( a, b ) {\n\n\tconst a2 = new Node( a.i, a.x, a.y ),\n\t\tb2 = new Node( b.i, b.x, b.y ),\n\t\tan = a.next,\n\t\tbp = b.prev;\n\n\ta.next = b;\n\tb.prev = a;\n\n\ta2.next = an;\n\tan.prev = a2;\n\n\tb2.next = a2;\n\ta2.prev = b2;\n\n\tbp.next = b2;\n\tb2.prev = bp;\n\n\treturn b2;\n\n}\n\n// create a node and optionally link it with previous one (in a circular doubly linked list)\nfunction insertNode( i, x, y, last ) {\n\n\tconst p = new Node( i, x, y );\n\n\tif ( ! last ) {\n\n\t\tp.prev = p;\n\t\tp.next = p;\n\n\t} else {\n\n\t\tp.next = last.next;\n\t\tp.prev = last;\n\t\tlast.next.prev = p;\n\t\tlast.next = p;\n\n\t}\n\n\treturn p;\n\n}\n\nfunction removeNode( p ) {\n\n\tp.next.prev = p.prev;\n\tp.prev.next = p.next;\n\n\tif ( p.prevZ ) p.prevZ.nextZ = p.nextZ;\n\tif ( p.nextZ ) p.nextZ.prevZ = p.prevZ;\n\n}\n\nfunction Node( i, x, y ) {\n\n\t// vertex index in coordinates array\n\tthis.i = i;\n\n\t// vertex coordinates\n\tthis.x = x;\n\tthis.y = y;\n\n\t// previous and next vertex nodes in a polygon ring\n\tthis.prev = null;\n\tthis.next = null;\n\n\t// z-order curve value\n\tthis.z = 0;\n\n\t// previous and next nodes in z-order\n\tthis.prevZ = null;\n\tthis.nextZ = null;\n\n\t// indicates whether this is a steiner point\n\tthis.steiner = false;\n\n}\n\nfunction signedArea( data, start, end, dim ) {\n\n\tlet sum = 0;\n\tfor ( let i = start, j = end - dim; i < end; i += dim ) {\n\n\t\tsum += ( data[ j ] - data[ i ] ) * ( data[ i + 1 ] + data[ j + 1 ] );\n\t\tj = i;\n\n\t}\n\n\treturn sum;\n\n}\n\nexport { Earcut };\n","/*\n * three.js r160 `ExtrudeGeometry` (MIT) for straight-edged shapes, ported line by line: the outline is sampled as `Shape.extractPoints` samples a\n * path of `LineCurve`s, triangulated by three's `ShapeUtils.triangulateShape` (Earcut), bevelled and walled in the same order, with the\n * `WorldUVGenerator` uvs and `computeVertexNormals` on the Float32 positions. Path extrusion (`extrudePath`) is not supported.\n */\nimport type { BevelSpec, GeometryGroup, PrimitiveBuffers, ShapeOutline, Vec2 } from '../types'\nimport { Earcut } from './earcut'\n\ninterface P {\n x: number\n y: number\n}\n\nconst equals = (a: P, b: P): boolean => a.x === b.x && a.y === b.y\n\n/** `LineCurve.getPoint(t)`. */\nconst linePoint = (v1: P, v2: P, t: number): P => (t === 1 ? { x: v2.x, y: v2.y } : { x: (v2.x - v1.x) * t + v1.x, y: (v2.y - v1.y) * t + v1.y })\n\n/** `Path.setFromPoints(points).getPoints()`: one `LineCurve` per edge, resolution 1, consecutive duplicates dropped, not closed. */\nfunction pathPoints(points: readonly Vec2[]): P[] {\n const out: P[] = []\n let last: P | undefined\n for (let i = 1; i < points.length; i++) {\n const v1 = { x: (points[i - 1] as Vec2)[0], y: (points[i - 1] as Vec2)[1] }\n const v2 = { x: (points[i] as Vec2)[0], y: (points[i] as Vec2)[1] }\n for (let d = 0; d <= 1; d++) {\n const point = linePoint(v1, v2, d / 1)\n if (last && equals(last, point)) continue\n out.push(point)\n last = point\n }\n }\n return out\n}\n\nfunction area(contour: readonly P[]): number {\n const n = contour.length\n let a = 0.0\n for (let p = n - 1, q = 0; q < n; p = q++) a += (contour[p] as P).x * (contour[q] as P).y - (contour[q] as P).x * (contour[p] as P).y\n return a * 0.5\n}\nconst isClockWise = (pts: readonly P[]): boolean => area(pts) < 0\n\nfunction removeDupEndPts(points: P[]): void {\n const l = points.length\n if (l > 2 && equals(points[l - 1] as P, points[0] as P)) points.pop()\n}\n\nfunction triangulateShape(contour: P[], holes: P[][]): number[][] {\n const vertices: number[] = []\n const holeIndices: number[] = []\n const faces: number[][] = []\n removeDupEndPts(contour)\n for (const p of contour) vertices.push(p.x, p.y)\n let holeIndex = contour.length\n holes.forEach(removeDupEndPts)\n for (let i = 0; i < holes.length; i++) {\n holeIndices.push(holeIndex)\n holeIndex += (holes[i] as P[]).length\n for (const p of holes[i] as P[]) vertices.push(p.x, p.y)\n }\n const triangles: number[] = Earcut.triangulate(vertices, holeIndices)\n for (let i = 0; i < triangles.length; i += 3) faces.push(triangles.slice(i, i + 3))\n return faces\n}\n\n/** `BufferGeometry.computeVertexNormals` for non-indexed Float32 positions, then `normalizeNormals`, both stored as Float32. */\nexport function computeVertexNormals(positions: Float32Array, indices?: ArrayLike<number>): Float32Array {\n const normals = new Float32Array(positions.length)\n const get = (array: Float32Array, i: number): [number, number, number] => [array[i * 3] as number, array[i * 3 + 1] as number, array[i * 3 + 2] as number]\n const face = (vA: number, vB: number, vC: number): [number, number, number] => {\n const pA = get(positions, vA)\n const pB = get(positions, vB)\n const pC = get(positions, vC)\n const cb = [pC[0] - pB[0], pC[1] - pB[1], pC[2] - pB[2]] as const\n const ab = [pA[0] - pB[0], pA[1] - pB[1], pA[2] - pB[2]] as const\n // Vector3.cross\n return [cb[1] * ab[2] - cb[2] * ab[1], cb[2] * ab[0] - cb[0] * ab[2], cb[0] * ab[1] - cb[1] * ab[0]]\n }\n const set = (i: number, x: number, y: number, z: number): void => {\n normals[i * 3] = x\n normals[i * 3 + 1] = y\n normals[i * 3 + 2] = z\n }\n if (indices) {\n for (let i = 0; i < indices.length; i += 3) {\n const vA = indices[i] as number\n const vB = indices[i + 1] as number\n const vC = indices[i + 2] as number\n const cb = face(vA, vB, vC)\n for (const v of [vA, vB, vC]) {\n const n = get(normals, v)\n set(v, n[0] + cb[0], n[1] + cb[1], n[2] + cb[2])\n }\n }\n } else {\n for (let i = 0; i < positions.length / 3; i += 3) {\n const cb = face(i, i + 1, i + 2)\n set(i, cb[0], cb[1], cb[2])\n set(i + 1, cb[0], cb[1], cb[2])\n set(i + 2, cb[0], cb[1], cb[2])\n }\n }\n for (let i = 0; i < normals.length / 3; i++) {\n const [x, y, z] = get(normals, i)\n const s = 1 / (Math.sqrt(x * x + y * y + z * z) || 1)\n set(i, x * s, y * s, z * s)\n }\n return normals\n}\n\nexport function extrude(outline: ShapeOutline, depth = 1, steps = 1, bevel: false | BevelSpec | undefined = undefined): PrimitiveBuffers {\n const parameters = { shape: outline, depth, steps, bevel: bevel ?? {} }\n const verticesArray: number[] = []\n const uvArray: number[] = []\n const groups: GeometryGroup[] = []\n const placeholder: number[] = []\n\n const bevelEnabled = bevel !== false\n const spec: BevelSpec = bevel === false || bevel === undefined ? {} : bevel\n let bevelThickness = spec.thickness !== undefined ? spec.thickness : 0.2\n let bevelSize = spec.size !== undefined ? spec.size : bevelThickness - 0.1\n let bevelOffset = spec.offset !== undefined ? spec.offset : 0\n let bevelSegments = spec.segments !== undefined ? spec.segments : 3\n if (!bevelEnabled) {\n bevelSegments = 0\n bevelThickness = 0\n bevelSize = 0\n bevelOffset = 0\n }\n\n let vertices = pathPoints(outline.outer)\n const holes = (outline.holes ?? []).map(pathPoints)\n const reverse = !isClockWise(vertices)\n if (reverse) {\n vertices = vertices.reverse()\n for (let h = 0; h < holes.length; h++) {\n const ahole = holes[h] as P[]\n if (isClockWise(ahole)) holes[h] = ahole.reverse()\n }\n }\n const faces = triangulateShape(vertices, holes)\n const contour = vertices\n for (const ahole of holes) vertices = vertices.concat(ahole)\n\n const scalePt2 = (pt: P, vec: P, size: number): P => ({ x: pt.x + vec.x * size, y: pt.y + vec.y * size })\n const vlen = vertices.length\n const flen = faces.length\n\n const getBevelVec = (inPt: P, inPrev: P, inNext: P): P => {\n let vTransX: number\n let vTransY: number\n let shrinkBy: number\n const vPrevX = inPt.x - inPrev.x\n const vPrevY = inPt.y - inPrev.y\n const vNextX = inNext.x - inPt.x\n const vNextY = inNext.y - inPt.y\n const vPrevLensq = vPrevX * vPrevX + vPrevY * vPrevY\n const collinear0 = vPrevX * vNextY - vPrevY * vNextX\n if (Math.abs(collinear0) > Number.EPSILON) {\n const vPrevLen = Math.sqrt(vPrevLensq)\n const vNextLen = Math.sqrt(vNextX * vNextX + vNextY * vNextY)\n const ptPrevShiftX = inPrev.x - vPrevY / vPrevLen\n const ptPrevShiftY = inPrev.y + vPrevX / vPrevLen\n const ptNextShiftX = inNext.x - vNextY / vNextLen\n const ptNextShiftY = inNext.y + vNextX / vNextLen\n const sf = ((ptNextShiftX - ptPrevShiftX) * vNextY - (ptNextShiftY - ptPrevShiftY) * vNextX) / (vPrevX * vNextY - vPrevY * vNextX)\n vTransX = ptPrevShiftX + vPrevX * sf - inPt.x\n vTransY = ptPrevShiftY + vPrevY * sf - inPt.y\n const vTransLensq = vTransX * vTransX + vTransY * vTransY\n if (vTransLensq <= 2) return { x: vTransX, y: vTransY }\n shrinkBy = Math.sqrt(vTransLensq / 2)\n } else {\n let directionEq = false\n if (vPrevX > Number.EPSILON) {\n if (vNextX > Number.EPSILON) directionEq = true\n } else if (vPrevX < -Number.EPSILON) {\n if (vNextX < -Number.EPSILON) directionEq = true\n } else if (Math.sign(vPrevY) === Math.sign(vNextY)) {\n directionEq = true\n }\n if (directionEq) {\n vTransX = -vPrevY\n vTransY = vPrevX\n shrinkBy = Math.sqrt(vPrevLensq)\n } else {\n vTransX = vPrevX\n vTransY = vPrevY\n shrinkBy = Math.sqrt(vPrevLensq / 2)\n }\n }\n return { x: vTransX / shrinkBy, y: vTransY / shrinkBy }\n }\n\n const movements = (ring: readonly P[]): P[] => {\n const out: P[] = []\n for (let i = 0, il = ring.length, j = il - 1, k = i + 1; i < il; i++, j++, k++) {\n if (j === il) j = 0\n if (k === il) k = 0\n out[i] = getBevelVec(ring[i] as P, ring[j] as P, ring[k] as P)\n }\n return out\n }\n const contourMovements = movements(contour)\n const holesMovements: P[][] = []\n let verticesMovements = contourMovements.concat()\n for (const ahole of holes) {\n const oneHoleMovements = movements(ahole)\n holesMovements.push(oneHoleMovements)\n verticesMovements = verticesMovements.concat(oneHoleMovements)\n }\n\n const v = (x: number, y: number, z: number): void => {\n placeholder.push(x)\n placeholder.push(y)\n placeholder.push(z)\n }\n const bevelLayer = (b: number, zOf: (z: number) => number): void => {\n const t = b / bevelSegments\n const z = bevelThickness * Math.cos((t * Math.PI) / 2)\n const bs = bevelSize * Math.sin((t * Math.PI) / 2) + bevelOffset\n for (let i = 0; i < contour.length; i++) {\n const vert = scalePt2(contour[i] as P, contourMovements[i] as P, bs)\n v(vert.x, vert.y, zOf(z))\n }\n for (let h = 0; h < holes.length; h++) {\n const ahole = holes[h] as P[]\n const oneHoleMovements = holesMovements[h] as P[]\n for (let i = 0; i < ahole.length; i++) {\n const vert = scalePt2(ahole[i] as P, oneHoleMovements[i] as P, bs)\n v(vert.x, vert.y, zOf(z))\n }\n }\n }\n for (let b = 0; b < bevelSegments; b++) bevelLayer(b, (z) => -z)\n const bs = bevelSize + bevelOffset\n for (let i = 0; i < vlen; i++) {\n const vert = bevelEnabled ? scalePt2(vertices[i] as P, verticesMovements[i] as P, bs) : (vertices[i] as P)\n v(vert.x, vert.y, 0)\n }\n for (let s = 1; s <= steps; s++) {\n for (let i = 0; i < vlen; i++) {\n const vert = bevelEnabled ? scalePt2(vertices[i] as P, verticesMovements[i] as P, bs) : (vertices[i] as P)\n v(vert.x, vert.y, (depth / steps) * s)\n }\n }\n for (let b = bevelSegments - 1; b >= 0; b--) bevelLayer(b, (z) => depth + z)\n\n const addVertex = (index: number): void => {\n verticesArray.push(placeholder[index * 3 + 0] as number)\n verticesArray.push(placeholder[index * 3 + 1] as number)\n verticesArray.push(placeholder[index * 3 + 2] as number)\n }\n const addUV = (x: number, y: number): void => {\n uvArray.push(x)\n uvArray.push(y)\n }\n const at = (index: number, axis: number): number => verticesArray[index * 3 + axis] as number\n const f3 = (a: number, b: number, c: number): void => {\n addVertex(a)\n addVertex(b)\n addVertex(c)\n const nextIndex = verticesArray.length / 3\n for (const index of [nextIndex - 3, nextIndex - 2, nextIndex - 1]) addUV(at(index, 0), at(index, 1))\n }\n const f4 = (a: number, b: number, c: number, d: number): void => {\n addVertex(a)\n addVertex(b)\n addVertex(d)\n addVertex(b)\n addVertex(c)\n addVertex(d)\n const nextIndex = verticesArray.length / 3\n const iA = nextIndex - 6\n const iB = nextIndex - 3\n const iC = nextIndex - 2\n const iD = nextIndex - 1\n const byX = Math.abs(at(iA, 1) - at(iB, 1)) < Math.abs(at(iA, 0) - at(iB, 0))\n const uv = (index: number): [number, number] => [byX ? at(index, 0) : at(index, 1), 1 - at(index, 2)]\n const uvs = [uv(iA), uv(iB), uv(iC), uv(iD)]\n for (const k of [0, 1, 3, 1, 2, 3]) addUV(...(uvs[k] as [number, number]))\n }\n\n // lid faces\n let start = verticesArray.length / 3\n if (bevelEnabled) {\n let offset = 0\n for (let i = 0; i < flen; i++) {\n const face = faces[i] as number[]\n f3((face[2] as number) + offset, (face[1] as number) + offset, (face[0] as number) + offset)\n }\n const layer = steps + bevelSegments * 2\n offset = vlen * layer\n for (let i = 0; i < flen; i++) {\n const face = faces[i] as number[]\n f3((face[0] as number) + offset, (face[1] as number) + offset, (face[2] as number) + offset)\n }\n } else {\n for (let i = 0; i < flen; i++) {\n const face = faces[i] as number[]\n f3(face[2] as number, face[1] as number, face[0] as number)\n }\n for (let i = 0; i < flen; i++) {\n const face = faces[i] as number[]\n f3((face[0] as number) + vlen * steps, (face[1] as number) + vlen * steps, (face[2] as number) + vlen * steps)\n }\n }\n groups.push({ start, count: verticesArray.length / 3 - start, materialIndex: 0 })\n\n // side faces\n start = verticesArray.length / 3\n const sidewalls = (ring: readonly P[], layeroffset: number): void => {\n let i = ring.length\n while (--i >= 0) {\n const j = i\n let k = i - 1\n if (k < 0) k = ring.length - 1\n for (let s = 0, sl = steps + bevelSegments * 2; s < sl; s++) {\n const slen1 = vlen * s\n const slen2 = vlen * (s + 1)\n f4(layeroffset + j + slen1, layeroffset + k + slen1, layeroffset + k + slen2, layeroffset + j + slen2)\n }\n }\n }\n let layeroffset = 0\n sidewalls(contour, layeroffset)\n layeroffset += contour.length\n for (const ahole of holes) {\n sidewalls(ahole, layeroffset)\n layeroffset += ahole.length\n }\n groups.push({ start, count: verticesArray.length / 3 - start, materialIndex: 1 })\n\n const positions = new Float32Array(verticesArray)\n return { type: 'ExtrudeGeometry', parameters, positions, normals: computeVertexNormals(positions), uvs: new Float32Array(uvArray), groups }\n}\n","import { canonicalJson } from '../hash'\nimport type { PrimitiveBuffers, PrimitiveNode } from '../types'\nimport { difference } from './difference'\nimport { computeVertexNormals, extrude } from './extrude'\nimport { box, circle, cone, cylinder, indexArray, lathe, plane, ring, sphere, torus } from './three-generators'\n\nexport { box, circle, cone, cylinder, lathe, plane, ring, sphere, torus } from './three-generators'\nexport { computeVertexNormals, extrude } from './extrude'\nexport { difference } from './difference'\n\n/** How a level of detail changes a primitive. */\nexport interface DetailOptions {\n /** Multiplies the segment counts of round primitives (1 leaves them as given). */\n readonly detail?: number\n /** Floor of the scaled segment counts (default 3). */\n readonly minSegments?: number\n}\n\nconst PARAMETER_KEYS: Readonly<Record<PrimitiveNode['kind'], readonly string[]>> = {\n box: ['size', 'segments'],\n cylinder: ['radiusTop', 'radiusBottom', 'height', 'radialSegments', 'heightSegments', 'openEnded', 'thetaStart', 'thetaLength'],\n cone: ['radius', 'height', 'radialSegments', 'heightSegments', 'openEnded', 'thetaStart', 'thetaLength'],\n sphere: ['radius', 'widthSegments', 'heightSegments', 'phiStart', 'phiLength', 'thetaStart', 'thetaLength'],\n plane: ['width', 'height', 'widthSegments', 'heightSegments'],\n circle: ['radius', 'segments', 'thetaStart', 'thetaLength'],\n ring: ['innerRadius', 'outerRadius', 'thetaSegments', 'phiSegments', 'thetaStart', 'thetaLength'],\n lathe: ['points', 'segments', 'phiStart', 'phiLength'],\n torus: ['radius', 'tube', 'radialSegments', 'tubularSegments', 'arc'],\n extrude: ['shape', 'depth', 'steps', 'bevel'],\n difference: ['size', 'subtract'],\n mesh: ['positions', 'normals', 'uvs', 'indices'],\n}\n\n/** The segment fields `detail` scales, per kind. */\nconst SEGMENT_KEYS: Readonly<Partial<Record<PrimitiveNode['kind'], readonly string[]>>> = {\n cylinder: ['radialSegments'],\n cone: ['radialSegments'],\n sphere: ['widthSegments', 'heightSegments'],\n circle: ['segments'],\n ring: ['thetaSegments'],\n lathe: ['segments'],\n torus: ['radialSegments', 'tubularSegments'],\n}\n/** three's defaults of the segment fields, so a scaled default is scaled from the right number. */\nconst SEGMENT_DEFAULTS: Readonly<Record<string, number>> = { radialSegments: 32, widthSegments: 32, heightSegments: 16, segments: 12, thetaSegments: 32, tubularSegments: 48 }\nconst segmentDefault = (kind: string, key: string): number => (kind === 'circle' && key === 'segments' ? 32 : kind === 'torus' && key === 'radialSegments' ? 12 : (SEGMENT_DEFAULTS[key] as number))\n\n/** The parameters of a primitive node (no transform, colour or name), with the level of detail applied: what its geometry depends on. */\nexport function primitiveParameters(node: PrimitiveNode, options: DetailOptions = {}): Record<string, unknown> {\n const out: Record<string, unknown> = {}\n const source = node as unknown as Record<string, unknown>\n for (const key of PARAMETER_KEYS[node.kind]) if (source[key] !== undefined) out[key] = source[key]\n const detail = options.detail ?? 1\n if (detail !== 1) {\n const floor = options.minSegments ?? 3\n for (const key of SEGMENT_KEYS[node.kind] ?? []) {\n const given = (out[key] as number | undefined) ?? segmentDefault(node.kind, key)\n out[key] = Math.max(floor, Math.round(given * detail))\n }\n }\n return out\n}\n\nfunction mesh(p: Record<string, unknown>): PrimitiveBuffers {\n const positions = new Float32Array(p.positions as number[])\n const indices = p.indices ? indexArray(p.indices as number[]) : undefined\n return {\n type: 'BufferGeometry',\n parameters: {},\n positions,\n normals: p.normals ? new Float32Array(p.normals as number[]) : computeVertexNormals(positions, indices),\n uvs: p.uvs ? new Float32Array(p.uvs as number[]) : new Float32Array((positions.length / 3) * 2),\n ...(indices ? { indices } : {}),\n groups: [],\n }\n}\n\nfunction make(kind: PrimitiveNode['kind'], p: Record<string, any>): PrimitiveBuffers {\n switch (kind) {\n case 'box': {\n const size = (p.size ?? [1, 1, 1]) as number[]\n const segments = (p.segments ?? [1, 1, 1]) as number[]\n return box(size[0], size[1], size[2], segments[0], segments[1], segments[2])\n }\n case 'cylinder':\n return cylinder(p.radiusTop, p.radiusBottom, p.height, p.radialSegments, p.heightSegments, p.openEnded, p.thetaStart, p.thetaLength)\n case 'cone':\n return cone(p.radius, p.height, p.radialSegments, p.heightSegments, p.openEnded, p.thetaStart, p.thetaLength)\n case 'sphere':\n return sphere(p.radius, p.widthSegments, p.heightSegments, p.phiStart, p.phiLength, p.thetaStart, p.thetaLength)\n case 'plane':\n return plane(p.width, p.height, p.widthSegments, p.heightSegments)\n case 'circle':\n return circle(p.radius, p.segments, p.thetaStart, p.thetaLength)\n case 'ring':\n return ring(p.innerRadius, p.outerRadius, p.thetaSegments, p.phiSegments, p.thetaStart, p.thetaLength)\n case 'lathe':\n return lathe(p.points, p.segments, p.phiStart, p.phiLength)\n case 'torus':\n return torus(p.radius, p.tube, p.radialSegments, p.tubularSegments, p.arc)\n case 'extrude':\n return extrude(p.shape, p.depth, p.steps, p.bevel)\n case 'difference':\n return difference(p.size, p.subtract ?? [])\n case 'mesh':\n return mesh(p)\n default:\n throw new Error(`game-shapes: unknown primitive kind \"${String(kind)}\"`)\n }\n}\n\n/** Templates by their parameter text: the same cylinder is generated once per process. Read-only by contract. */\nconst templates = new Map<string, PrimitiveBuffers>()\nlet templateLimit = 4096\nconst stats = { hits: 0, misses: 0 }\n\n/** Sets how many primitive templates are kept (least recently used out; 0 turns the cache off). */\nexport function setTemplateCacheSize(size: number): void {\n templateLimit = Math.max(0, Math.floor(size))\n while (templates.size > templateLimit) templates.delete(templates.keys().next().value as string)\n}\nexport function clearTemplateCache(): void {\n templates.clear()\n stats.hits = 0\n stats.misses = 0\n}\nexport const templateCacheStats = (): { size: number; hits: number; misses: number } => ({ size: templates.size, ...stats })\n\n/**\n * The geometry of one primitive on its own, not baked: the arrays three's generator of the same kind builds, bit for bit (meshes and differences\n * are `BufferGeometry`). The result comes from a shared template cache and must not be written to (copy it with `clonePrimitive`).\n */\nexport function buildPrimitive(node: PrimitiveNode, options: DetailOptions = {}): PrimitiveBuffers {\n const parameters = primitiveParameters(node, options)\n // raw meshes are not worth a key of their whole arrays; they are cheap to wrap\n if (node.kind === 'mesh' || templateLimit === 0) return make(node.kind, parameters)\n const key = `${node.kind}:${canonicalJson(parameters)}`\n const cached = templates.get(key)\n if (cached) {\n stats.hits++\n templates.delete(key)\n templates.set(key, cached)\n return cached\n }\n stats.misses++\n const built = make(node.kind, parameters)\n templates.set(key, built)\n if (templates.size > templateLimit) templates.delete(templates.keys().next().value as string)\n return built\n}\n\n/** A copy that owns its arrays. */\nexport function clonePrimitive(p: PrimitiveBuffers): PrimitiveBuffers {\n return {\n type: p.type,\n parameters: p.parameters,\n positions: p.positions.slice(),\n normals: p.normals.slice(),\n uvs: p.uvs.slice(),\n ...(p.indices ? { indices: p.indices.slice() } : {}),\n groups: p.groups.map((group) => ({ ...group })),\n }\n}\n","import { hash64 } from './hash'\n\n/** mulberry32: a small, fast 32-bit seeded stream in [0, 1). */\nexport function mulberry32(seed: number): () => number {\n let state = seed >>> 0\n return () => {\n state = (state + 0x6d2b79f5) >>> 0\n let t = 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\n/** The stream of one node: its own per (seed, generator, path), so adding a node never shifts another node's draws. */\nexport const streamFor = (seed: number | string, generator: string, path: string): (() => number) =>\n mulberry32(parseInt(hash64(`${String(seed)}\\u0000${generator}\\u0000${path}`).slice(0, 8), 16))\n","import type { ShapeGenerator } from './types'\n\nconst generators = new Map<string, ShapeGenerator>()\n\n/**\n * Registers a generator for `{ kind: 'custom', generator: name, params }` nodes: a pure function of its params and a seeded stream that returns a\n * node. A worker that generates shapes with custom nodes must register the same generators (import the same module in the worker script).\n */\nexport function registerGenerator(name: string, generator: ShapeGenerator): void {\n if (!/^[a-zA-Z][\\w.:-]*$/.test(name)) throw new Error(`game-shapes: generator name \"${name}\" must start with a letter and use letters, digits, \".\", \":\", \"-\" or \"_\"`)\n generators.set(name, generator)\n}\nexport const unregisterGenerator = (name: string): boolean => generators.delete(name)\nexport const getGenerator = (name: string): ShapeGenerator | undefined => generators.get(name)\nexport const listGenerators = (): string[] => [...generators.keys()].sort()\n","{\n \"$schema\": \"https://json-schema.org/draft/2020-12/schema\",\n \"$id\": \"https://github.com/Andersonfrfilho/adatechnology-game-kit/packages/game-shapes/schema/shape.schema.json\",\n \"title\": \"game-shapes shape\",\n \"type\": \"object\",\n \"required\": [\n \"version\",\n \"root\"\n ],\n \"additionalProperties\": false,\n \"properties\": {\n \"version\": {\n \"const\": 1\n },\n \"name\": {\n \"type\": \"string\"\n },\n \"materials\": {\n \"type\": \"object\",\n \"additionalProperties\": {\n \"$ref\": \"#/$defs/material\"\n }\n },\n \"root\": {\n \"$ref\": \"#/$defs/node\"\n },\n \"lod\": {\n \"type\": \"array\",\n \"items\": {\n \"$ref\": \"#/$defs/lodLevel\"\n }\n },\n \"cullDistance\": {\n \"type\": \"number\",\n \"exclusiveMinimum\": 0\n }\n },\n \"$defs\": {\n \"number\": {\n \"type\": \"number\"\n },\n \"count\": {\n \"type\": \"integer\",\n \"minimum\": 0\n },\n \"vec2\": {\n \"type\": \"array\",\n \"items\": {\n \"type\": \"number\"\n },\n \"minItems\": 2,\n \"maxItems\": 2\n },\n \"vec3\": {\n \"type\": \"array\",\n \"items\": {\n \"type\": \"number\"\n },\n \"minItems\": 3,\n \"maxItems\": 3\n },\n \"mat4\": {\n \"type\": \"array\",\n \"items\": {\n \"type\": \"number\"\n },\n \"minItems\": 16,\n \"maxItems\": 16\n },\n \"color\": {\n \"oneOf\": [\n {\n \"type\": \"integer\",\n \"minimum\": 0,\n \"maximum\": 16777215\n },\n {\n \"type\": \"string\",\n \"pattern\": \"^#[0-9a-fA-F]{6}$\"\n }\n ]\n },\n \"uvRect\": {\n \"type\": \"object\",\n \"additionalProperties\": false,\n \"required\": [\n \"u0\",\n \"v0\",\n \"u1\",\n \"v1\"\n ],\n \"properties\": {\n \"u0\": {\n \"type\": \"number\"\n },\n \"v0\": {\n \"type\": \"number\"\n },\n \"u1\": {\n \"type\": \"number\"\n },\n \"v1\": {\n \"type\": \"number\"\n }\n }\n },\n \"rotationOrder\": {\n \"enum\": [\n \"XYZ\",\n \"YXZ\",\n \"ZXY\",\n \"ZYX\",\n \"YZX\",\n \"XZY\"\n ]\n },\n \"transform\": {\n \"type\": \"object\",\n \"properties\": {\n \"position\": {\n \"$ref\": \"#/$defs/vec3\"\n },\n \"rotation\": {\n \"$ref\": \"#/$defs/vec3\"\n },\n \"rotationOrder\": {\n \"$ref\": \"#/$defs/rotationOrder\"\n },\n \"scale\": {\n \"oneOf\": [\n {\n \"type\": \"number\"\n },\n {\n \"$ref\": \"#/$defs/vec3\"\n }\n ]\n },\n \"heading\": {\n \"type\": \"number\"\n },\n \"matrix\": {\n \"$ref\": \"#/$defs/mat4\"\n }\n }\n },\n \"instance\": {\n \"allOf\": [\n {\n \"$ref\": \"#/$defs/transform\"\n }\n ],\n \"properties\": {\n \"position\": true,\n \"rotation\": true,\n \"rotationOrder\": true,\n \"scale\": true,\n \"heading\": true,\n \"matrix\": true,\n \"color\": {\n \"$ref\": \"#/$defs/color\"\n }\n },\n \"unevaluatedProperties\": false\n },\n \"material\": {\n \"type\": \"object\",\n \"additionalProperties\": false,\n \"properties\": {\n \"color\": {\n \"$ref\": \"#/$defs/color\"\n },\n \"roughness\": {\n \"type\": \"number\",\n \"minimum\": 0,\n \"maximum\": 1\n },\n \"metalness\": {\n \"type\": \"number\",\n \"minimum\": 0,\n \"maximum\": 1\n },\n \"opacity\": {\n \"type\": \"number\",\n \"minimum\": 0,\n \"maximum\": 1\n },\n \"transparent\": {\n \"type\": \"boolean\"\n },\n \"emissive\": {\n \"$ref\": \"#/$defs/color\"\n },\n \"emissiveIntensity\": {\n \"type\": \"number\",\n \"minimum\": 0\n },\n \"side\": {\n \"enum\": [\n \"front\",\n \"back\",\n \"double\"\n ]\n },\n \"flatShading\": {\n \"type\": \"boolean\"\n },\n \"vertexColors\": {\n \"type\": \"boolean\"\n },\n \"depthWrite\": {\n \"type\": \"boolean\"\n }\n }\n },\n \"lodLevel\": {\n \"type\": \"object\",\n \"additionalProperties\": false,\n \"required\": [\n \"distance\",\n \"detail\"\n ],\n \"properties\": {\n \"distance\": {\n \"type\": \"number\",\n \"minimum\": 0\n },\n \"detail\": {\n \"type\": \"number\",\n \"exclusiveMinimum\": 0,\n \"maximum\": 1\n },\n \"minSize\": {\n \"type\": \"number\",\n \"minimum\": 0\n },\n \"minSegments\": {\n \"type\": \"integer\",\n \"minimum\": 3\n }\n }\n },\n \"common\": {\n \"allOf\": [\n {\n \"$ref\": \"#/$defs/transform\"\n }\n ],\n \"properties\": {\n \"kind\": {\n \"type\": \"string\"\n },\n \"name\": {\n \"type\": \"string\"\n },\n \"part\": {\n \"type\": \"string\"\n },\n \"material\": {\n \"type\": \"string\"\n },\n \"color\": {\n \"$ref\": \"#/$defs/color\"\n },\n \"uv\": {\n \"$ref\": \"#/$defs/uvRect\"\n },\n \"instances\": {\n \"type\": \"array\",\n \"items\": {\n \"$ref\": \"#/$defs/instance\"\n }\n },\n \"minDetail\": {\n \"type\": \"number\",\n \"exclusiveMinimum\": 0,\n \"maximum\": 1\n },\n \"tags\": {\n \"type\": \"array\",\n \"items\": {\n \"type\": \"string\"\n }\n }\n }\n },\n \"node\": {\n \"type\": \"object\",\n \"required\": [\n \"kind\"\n ],\n \"allOf\": [\n {\n \"$ref\": \"#/$defs/common\"\n }\n ],\n \"oneOf\": [\n {\n \"properties\": {\n \"kind\": {\n \"const\": \"group\"\n },\n \"children\": {\n \"type\": \"array\",\n \"items\": {\n \"$ref\": \"#/$defs/node\"\n }\n }\n }\n },\n {\n \"properties\": {\n \"kind\": {\n \"const\": \"box\"\n },\n \"size\": {\n \"$ref\": \"#/$defs/vec3\"\n },\n \"segments\": {\n \"type\": \"array\",\n \"items\": {\n \"type\": \"integer\",\n \"minimum\": 1\n },\n \"minItems\": 3,\n \"maxItems\": 3\n }\n }\n },\n {\n \"properties\": {\n \"kind\": {\n \"const\": \"cylinder\"\n },\n \"radiusTop\": {\n \"type\": \"number\"\n },\n \"radiusBottom\": {\n \"type\": \"number\"\n },\n \"height\": {\n \"type\": \"number\"\n },\n \"radialSegments\": {\n \"type\": \"integer\",\n \"minimum\": 1\n },\n \"heightSegments\": {\n \"type\": \"integer\",\n \"minimum\": 1\n },\n \"openEnded\": {\n \"type\": \"boolean\"\n },\n \"thetaStart\": {\n \"type\": \"number\"\n },\n \"thetaLength\": {\n \"type\": \"number\"\n }\n }\n },\n {\n \"properties\": {\n \"kind\": {\n \"const\": \"cone\"\n },\n \"radius\": {\n \"type\": \"number\"\n },\n \"height\": {\n \"type\": \"number\"\n },\n \"radialSegments\": {\n \"type\": \"integer\",\n \"minimum\": 1\n },\n \"heightSegments\": {\n \"type\": \"integer\",\n \"minimum\": 1\n },\n \"openEnded\": {\n \"type\": \"boolean\"\n },\n \"thetaStart\": {\n \"type\": \"number\"\n },\n \"thetaLength\": {\n \"type\": \"number\"\n }\n }\n },\n {\n \"properties\": {\n \"kind\": {\n \"const\": \"sphere\"\n },\n \"radius\": {\n \"type\": \"number\"\n },\n \"widthSegments\": {\n \"type\": \"integer\",\n \"minimum\": 3\n },\n \"heightSegments\": {\n \"type\": \"integer\",\n \"minimum\": 2\n },\n \"phiStart\": {\n \"type\": \"number\"\n },\n \"phiLength\": {\n \"type\": \"number\"\n },\n \"thetaStart\": {\n \"type\": \"number\"\n },\n \"thetaLength\": {\n \"type\": \"number\"\n }\n }\n },\n {\n \"properties\": {\n \"kind\": {\n \"const\": \"plane\"\n },\n \"width\": {\n \"type\": \"number\"\n },\n \"height\": {\n \"type\": \"number\"\n },\n \"widthSegments\": {\n \"type\": \"integer\",\n \"minimum\": 1\n },\n \"heightSegments\": {\n \"type\": \"integer\",\n \"minimum\": 1\n }\n }\n },\n {\n \"properties\": {\n \"kind\": {\n \"const\": \"circle\"\n },\n \"radius\": {\n \"type\": \"number\"\n },\n \"segments\": {\n \"type\": \"integer\",\n \"minimum\": 3\n },\n \"thetaStart\": {\n \"type\": \"number\"\n },\n \"thetaLength\": {\n \"type\": \"number\"\n }\n }\n },\n {\n \"properties\": {\n \"kind\": {\n \"const\": \"ring\"\n },\n \"innerRadius\": {\n \"type\": \"number\"\n },\n \"outerRadius\": {\n \"type\": \"number\"\n },\n \"thetaSegments\": {\n \"type\": \"integer\",\n \"minimum\": 3\n },\n \"phiSegments\": {\n \"type\": \"integer\",\n \"minimum\": 1\n },\n \"thetaStart\": {\n \"type\": \"number\"\n },\n \"thetaLength\": {\n \"type\": \"number\"\n }\n }\n },\n {\n \"required\": [\n \"points\"\n ],\n \"properties\": {\n \"kind\": {\n \"const\": \"lathe\"\n },\n \"points\": {\n \"type\": \"array\",\n \"items\": {\n \"$ref\": \"#/$defs/vec2\"\n },\n \"minItems\": 2\n },\n \"segments\": {\n \"type\": \"integer\",\n \"minimum\": 1\n },\n \"phiStart\": {\n \"type\": \"number\"\n },\n \"phiLength\": {\n \"type\": \"number\"\n }\n }\n },\n {\n \"properties\": {\n \"kind\": {\n \"const\": \"torus\"\n },\n \"radius\": {\n \"type\": \"number\"\n },\n \"tube\": {\n \"type\": \"number\"\n },\n \"radialSegments\": {\n \"type\": \"integer\",\n \"minimum\": 1\n },\n \"tubularSegments\": {\n \"type\": \"integer\",\n \"minimum\": 1\n },\n \"arc\": {\n \"type\": \"number\"\n }\n }\n },\n {\n \"required\": [\n \"shape\"\n ],\n \"properties\": {\n \"kind\": {\n \"const\": \"extrude\"\n },\n \"shape\": {\n \"type\": \"object\",\n \"required\": [\n \"outer\"\n ],\n \"additionalProperties\": false,\n \"properties\": {\n \"outer\": {\n \"type\": \"array\",\n \"items\": {\n \"$ref\": \"#/$defs/vec2\"\n },\n \"minItems\": 3\n },\n \"holes\": {\n \"type\": \"array\",\n \"items\": {\n \"type\": \"array\",\n \"items\": {\n \"$ref\": \"#/$defs/vec2\"\n },\n \"minItems\": 3\n }\n }\n }\n },\n \"depth\": {\n \"type\": \"number\"\n },\n \"steps\": {\n \"type\": \"integer\",\n \"minimum\": 1\n },\n \"bevel\": {\n \"oneOf\": [\n {\n \"const\": false\n },\n {\n \"type\": \"object\",\n \"additionalProperties\": false,\n \"properties\": {\n \"thickness\": {\n \"type\": \"number\"\n },\n \"size\": {\n \"type\": \"number\"\n },\n \"offset\": {\n \"type\": \"number\"\n },\n \"segments\": {\n \"type\": \"integer\",\n \"minimum\": 1\n }\n }\n }\n ]\n }\n }\n },\n {\n \"required\": [\n \"size\",\n \"subtract\"\n ],\n \"properties\": {\n \"kind\": {\n \"const\": \"difference\"\n },\n \"size\": {\n \"$ref\": \"#/$defs/vec3\"\n },\n \"subtract\": {\n \"type\": \"array\",\n \"items\": {\n \"type\": \"object\",\n \"required\": [\n \"min\",\n \"max\"\n ],\n \"additionalProperties\": false,\n \"properties\": {\n \"min\": {\n \"$ref\": \"#/$defs/vec2\"\n },\n \"max\": {\n \"$ref\": \"#/$defs/vec2\"\n }\n }\n }\n }\n }\n },\n {\n \"required\": [\n \"positions\"\n ],\n \"properties\": {\n \"kind\": {\n \"const\": \"mesh\"\n },\n \"positions\": {\n \"type\": \"array\",\n \"items\": {\n \"type\": \"number\"\n }\n },\n \"normals\": {\n \"type\": \"array\",\n \"items\": {\n \"type\": \"number\"\n }\n },\n \"uvs\": {\n \"type\": \"array\",\n \"items\": {\n \"type\": \"number\"\n }\n },\n \"indices\": {\n \"type\": \"array\",\n \"items\": {\n \"$ref\": \"#/$defs/count\"\n }\n }\n }\n },\n {\n \"properties\": {\n \"kind\": {\n \"const\": \"point\"\n },\n \"data\": {}\n }\n },\n {\n \"required\": [\n \"generator\"\n ],\n \"properties\": {\n \"kind\": {\n \"const\": \"custom\"\n },\n \"generator\": {\n \"type\": \"string\"\n },\n \"params\": {}\n }\n }\n ]\n }\n }\n}\n","import schemaJson from '../schema/shape.schema.json'\nimport type { ShapeSchema } from './types'\n\n/** The JSON Schema (draft 2020-12) of a shape document; the same file ships as `@adatechnology/game-shapes/schema.json`. */\nexport const SHAPE_SCHEMA: Readonly<Record<string, unknown>> = schemaJson\n\ntype Check = (value: unknown) => string | null\n\nconst num: Check = (v) => (typeof v === 'number' && Number.isFinite(v) ? null : 'expected a finite number')\nconst bool: Check = (v) => (typeof v === 'boolean' ? null : 'expected a boolean')\nconst str: Check = (v) => (typeof v === 'string' ? null : 'expected a string')\nconst int = (min: number): Check => (v) => (typeof v === 'number' && Number.isInteger(v) && v >= min ? null : `expected an integer >= ${min}`)\nconst range = (lo: number, hi: number, loOpen = false): Check => (v) =>\n typeof v === 'number' && (loOpen ? v > lo : v >= lo) && v <= hi ? null : `expected a number in ${loOpen ? '(' : '['}${lo}, ${hi}]`\nconst tuple = (n: number, item: Check = num): Check => (v) => {\n if (!Array.isArray(v) || v.length !== n) return `expected an array of ${n}`\n for (const x of v) if (item(x)) return `expected an array of ${n} numbers`\n return null\n}\nconst list = (item: Check, min = 0): Check => (v) => {\n if (!Array.isArray(v)) return 'expected an array'\n if (v.length < min) return `expected at least ${min} items`\n for (let i = 0; i < v.length; i++) {\n const e = item(v[i])\n if (e) return `[${i}]: ${e}`\n }\n return null\n}\nconst color: Check = (v) =>\n (typeof v === 'number' && Number.isInteger(v) && v >= 0 && v <= 0xffffff) || (typeof v === 'string' && /^#[0-9a-fA-F]{6}$/.test(v)) ? null : 'expected 0xRRGGBB or \"#rrggbb\"'\nconst oneOf = (values: readonly unknown[]): Check => (v) => (values.includes(v) ? null : `expected one of ${values.map((x) => JSON.stringify(x)).join(', ')}`)\nconst object = (fields: Readonly<Record<string, Check>>, required: readonly string[] = []): Check => (v) => {\n if (!v || typeof v !== 'object' || Array.isArray(v)) return 'expected an object'\n const record = v as Record<string, unknown>\n for (const key of required) if (record[key] === undefined) return `${key}: required`\n for (const key of Object.keys(record)) {\n if (record[key] === undefined) continue\n const check = fields[key]\n if (!check) return `${key}: unknown field`\n const e = check(record[key])\n if (e) return `${key}: ${e}`\n }\n return null\n}\n\nconst ORDERS = ['XYZ', 'YXZ', 'ZXY', 'ZYX', 'YZX', 'XZY'] as const\nconst TRANSFORM: Record<string, Check> = {\n position: tuple(3),\n rotation: tuple(3),\n rotationOrder: oneOf(ORDERS),\n scale: (v) => (typeof v === 'number' ? num(v) : tuple(3)(v)),\n heading: num,\n matrix: tuple(16),\n}\nconst UV = object({ u0: num, v0: num, u1: num, v1: num }, ['u0', 'v0', 'u1', 'v1'])\nconst INSTANCE = object({ ...TRANSFORM, color })\nconst COMMON: Record<string, Check> = {\n ...TRANSFORM,\n kind: str,\n name: str,\n part: str,\n material: str,\n color,\n uv: UV,\n instances: list(INSTANCE),\n minDetail: range(0, 1, true),\n tags: list(str),\n}\nconst vec2 = tuple(2)\nconst BEVEL: Check = (v) => (v === false ? null : object({ thickness: num, size: num, offset: num, segments: int(1) })(v))\nconst KINDS: Readonly<Record<string, { fields: Record<string, Check>; required?: string[] }>> = {\n group: { fields: {} },\n box: { fields: { size: tuple(3), segments: tuple(3, int(1)) } },\n cylinder: { fields: { radiusTop: num, radiusBottom: num, height: num, radialSegments: int(1), heightSegments: int(1), openEnded: bool, thetaStart: num, thetaLength: num } },\n cone: { fields: { radius: num, height: num, radialSegments: int(1), heightSegments: int(1), openEnded: bool, thetaStart: num, thetaLength: num } },\n sphere: { fields: { radius: num, widthSegments: int(3), heightSegments: int(2), phiStart: num, phiLength: num, thetaStart: num, thetaLength: num } },\n plane: { fields: { width: num, height: num, widthSegments: int(1), heightSegments: int(1) } },\n circle: { fields: { radius: num, segments: int(3), thetaStart: num, thetaLength: num } },\n ring: { fields: { innerRadius: num, outerRadius: num, thetaSegments: int(3), phiSegments: int(1), thetaStart: num, thetaLength: num } },\n lathe: { fields: { points: list(vec2, 2), segments: int(1), phiStart: num, phiLength: num }, required: ['points'] },\n torus: { fields: { radius: num, tube: num, radialSegments: int(1), tubularSegments: int(1), arc: num } },\n extrude: {\n fields: { shape: object({ outer: list(vec2, 3), holes: list(list(vec2, 3)) }, ['outer']), depth: num, steps: int(1), bevel: BEVEL },\n required: ['shape'],\n },\n difference: { fields: { size: tuple(3), subtract: list(object({ min: vec2, max: vec2 }, ['min', 'max'])) }, required: ['size', 'subtract'] },\n mesh: {\n fields: {\n positions: (v) => list(num)(v) ?? ((v as unknown[]).length % 3 === 0 ? null : 'expected a multiple of 3 numbers'),\n normals: list(num),\n uvs: list(num),\n indices: list(int(0)),\n },\n required: ['positions'],\n },\n point: { fields: { data: () => null } },\n custom: { fields: { generator: str, params: () => null }, required: ['generator'] },\n}\n\nfunction validateNode(node: unknown, path: string, errors: string[]): void {\n if (!node || typeof node !== 'object' || Array.isArray(node)) {\n errors.push(`${path}: expected a node object`)\n return\n }\n const record = node as Record<string, unknown>\n const spec = typeof record.kind === 'string' ? KINDS[record.kind] : undefined\n if (!spec) {\n errors.push(`${path}.kind: expected one of ${Object.keys(KINDS).join(', ')}`)\n return\n }\n for (const key of spec.required ?? []) if (record[key] === undefined) errors.push(`${path}.${key}: required`)\n for (const key of Object.keys(record)) {\n if (record[key] === undefined || key === 'children') continue\n const check = spec.fields[key] ?? COMMON[key]\n if (!check) {\n errors.push(`${path}.${key}: unknown field for a ${String(record.kind)}`)\n continue\n }\n const e = check(record[key])\n if (e) errors.push(`${path}.${key}: ${e}`)\n }\n const exclusive = ['matrix', 'heading'].filter((key) => record[key] !== undefined)\n if (record.matrix !== undefined && (record.position !== undefined || record.rotation !== undefined || record.scale !== undefined || record.heading !== undefined))\n errors.push(`${path}.matrix: cannot be combined with position, rotation, scale or heading`)\n else if (exclusive.includes('heading') && (record.rotation !== undefined || record.scale !== undefined)) errors.push(`${path}.heading: cannot be combined with rotation or scale`)\n if (record.children !== undefined) {\n if (record.kind !== 'group') errors.push(`${path}.children: only a group has children`)\n else if (!Array.isArray(record.children)) errors.push(`${path}.children: expected an array`)\n else record.children.forEach((child, index) => validateNode(child, `${path}.children[${index}]`, errors))\n }\n}\n\n/** Every rule of the JSON Schema, checked without a schema engine: one message per problem, with its path (`root.children[3].radialSegments: ...`). */\nexport function validateShape(schema: unknown): string[] {\n const errors: string[] = []\n if (!schema || typeof schema !== 'object' || Array.isArray(schema)) return ['expected a shape object']\n const record = schema as Record<string, unknown>\n for (const key of Object.keys(record)) if (!['version', 'name', 'materials', 'root', 'lod', 'cullDistance'].includes(key) && record[key] !== undefined) errors.push(`${key}: unknown field`)\n if (record.version !== 1) errors.push('version: expected 1')\n if (record.name !== undefined && typeof record.name !== 'string') errors.push('name: expected a string')\n if (record.materials !== undefined) {\n if (!record.materials || typeof record.materials !== 'object' || Array.isArray(record.materials)) errors.push('materials: expected an object')\n else {\n const material = object({\n color,\n roughness: range(0, 1),\n metalness: range(0, 1),\n opacity: range(0, 1),\n transparent: bool,\n emissive: color,\n emissiveIntensity: (v) => (typeof v === 'number' && v >= 0 ? null : 'expected a number >= 0'),\n side: oneOf(['front', 'back', 'double']),\n flatShading: bool,\n vertexColors: bool,\n depthWrite: bool,\n })\n for (const [id, hint] of Object.entries(record.materials)) {\n const e = material(hint)\n if (e) errors.push(`materials.${id}: ${e}`)\n }\n }\n }\n if (record.lod !== undefined) {\n const e = list(object({ distance: (v) => (typeof v === 'number' && v >= 0 ? null : 'expected a number >= 0'), detail: range(0, 1, true), minSize: (v) => (typeof v === 'number' && v >= 0 ? null : 'expected a number >= 0'), minSegments: int(3) }, ['distance', 'detail']))(record.lod)\n if (e) errors.push(`lod${e.startsWith('[') ? '' : ': '}${e}`)\n }\n if (record.cullDistance !== undefined && !(typeof record.cullDistance === 'number' && record.cullDistance > 0)) errors.push('cullDistance: expected a number > 0')\n if (record.root === undefined) errors.push('root: required')\n else validateNode(record.root, 'root', errors)\n return errors\n}\n\n/** Throws with every problem when the schema is not valid. */\nexport function assertValidShape(schema: unknown): asserts schema is ShapeSchema {\n const errors = validateShape(schema)\n if (errors.length) throw new Error(`game-shapes: invalid shape\\n ${errors.slice(0, 20).join('\\n ')}${errors.length > 20 ? `\\n ... ${errors.length - 20} more` : ''}`)\n}\n","import { colorChannels, colorHex } from './color'\nimport { hashValue } from './hash'\nimport { asMat4, identity4, isAffine, matrixOf, multiply, normalMatrix, transformPoint } from './math'\nimport type { Matrix4 } from './math'\nimport { buildPrimitive, primitiveParameters } from './primitives'\nimport { canonicalJson } from './hash'\nimport { streamFor } from './random'\nimport { getGenerator } from './registry'\nimport { assertValidShape } from './schema'\nimport type {\n Bounds,\n GenerateOptions,\n InstancedBatch,\n NamedRange,\n PrimitiveBuffers,\n PrimitiveNode,\n ShapeBatch,\n ShapeBuffers,\n ShapeLevel,\n ShapeNode,\n ShapePart,\n ShapePoint,\n ShapeSchema,\n UvRect,\n} from './types'\n\nconst PRIMITIVE_KINDS = new Set(['box', 'cylinder', 'cone', 'sphere', 'plane', 'circle', 'ring', 'lathe', 'torus', 'extrude', 'difference', 'mesh'])\nexport const isPrimitiveNode = (node: ShapeNode): node is PrimitiveNode => PRIMITIVE_KINDS.has(node.kind)\n\n/** The options that change the output, as they enter the cache key. */\nexport function keyOptions(options: GenerateOptions = {}): Record<string, unknown> {\n return {\n seed: options.seed ?? 0,\n colors: options.colors ?? 'linear',\n indexed: options.indexed ?? true,\n materials: options.materials,\n fallbackMaterial: options.fallbackMaterial,\n materialAlias: options.materialAlias,\n instancing: options.instancing,\n levels: options.levels,\n }\n}\n\n/** The cache key of a shape under some options: 64-bit FNV-1a of the canonical schema text and the options that change the output. */\nexport const shapeKey = (schema: ShapeSchema, options: GenerateOptions = {}): string => hashValue({ schema, options: keyOptions(options) })\n\nconst IDENTITY_UV: UvRect = { u0: 0, v0: 0, u1: 1, v1: 1 }\n\nclass FloatList {\n array: Float32Array\n length = 0\n constructor(capacity = 256) {\n this.array = new Float32Array(capacity)\n }\n reserve(extra: number): void {\n if (this.length + extra <= this.array.length) return\n let capacity = this.array.length * 2\n while (capacity < this.length + extra) capacity *= 2\n const next = new Float32Array(capacity)\n next.set(this.array.subarray(0, this.length))\n this.array = next\n }\n done(): Float32Array {\n return this.array.slice(0, this.length)\n }\n}\nclass IndexList {\n array: Uint32Array\n length = 0\n constructor(capacity = 256) {\n this.array = new Uint32Array(capacity)\n }\n reserve(extra: number): void {\n if (this.length + extra <= this.array.length) return\n let capacity = this.array.length * 2\n while (capacity < this.length + extra) capacity *= 2\n const next = new Uint32Array(capacity)\n next.set(this.array.subarray(0, this.length))\n this.array = next\n }\n}\n\n/** Growing buffers of one (target, material). */\nclass Accumulator {\n readonly positions = new FloatList()\n readonly normals = new FloatList()\n readonly uvs = new FloatList(170)\n readonly colors = new FloatList()\n readonly indices = new IndexList()\n readonly ranges: NamedRange[] = []\n vertices = 0\n constructor(\n readonly material: string,\n readonly part: string | null,\n ) {}\n}\n\ninterface Target {\n readonly part: string | null\n readonly accs: Map<string, Accumulator>\n}\n\ninterface Settings {\n readonly colors: 'linear' | 'srgb' | 'none'\n readonly indexed: boolean\n readonly materials?: ReadonlySet<string>\n readonly fallback?: string\n readonly alias?: Readonly<Record<string, string>>\n readonly seed: number | string\n readonly generators?: GenerateOptions['generators']\n readonly autoMin?: number\n}\n\ninterface LevelSpec {\n readonly distance: number\n readonly detail: number\n readonly minSize?: number\n readonly minSegments?: number\n readonly index: number\n}\n\ninterface Inherited {\n readonly material: string\n readonly color: number\n readonly uv: UvRect\n readonly target: Target\n}\n\n/**\n * Bakes a template into an accumulator: positions by the world matrix, normals by its normal matrix and normalised, uvs into the atlas cell,\n * one colour for all, indices offset. The arithmetic is three's (`createMeshApi`, `BufferGeometry.applyMatrix4`), so the bits match.\n */\nfunction bake(acc: Accumulator, t: PrimitiveBuffers, world: readonly number[], rgb: readonly number[] | null, u: UvRect, indexed: boolean): void {\n const e = world\n const nm = normalMatrix(world)\n const affine = isAffine(world)\n const source = t.positions\n const count = source.length / 3\n const order: ArrayLike<number> | null = indexed ? null : t.indices ?? null\n const emitted = order ? order.length : count\n acc.positions.reserve(emitted * 3)\n acc.normals.reserve(emitted * 3)\n acc.uvs.reserve(emitted * 2)\n if (rgb) acc.colors.reserve(emitted * 3)\n const P = acc.positions.array\n const N = acc.normals.array\n const U = acc.uvs.array\n const C = acc.colors.array\n let pi = acc.positions.length\n let ni = acc.normals.length\n let ui = acc.uvs.length\n let ci = acc.colors.length\n const du = u.u1 - u.u0\n const dv = u.v1 - u.v0\n const tn = t.normals\n const tu = t.uvs\n for (let k = 0; k < emitted; k++) {\n const i = order ? (order[k] as number) : k\n const x = source[i * 3] as number\n const y = source[i * 3 + 1] as number\n const z = source[i * 3 + 2] as number\n if (affine) {\n P[pi++] = e[0]! * x + e[4]! * y + e[8]! * z + e[12]!\n P[pi++] = e[1]! * x + e[5]! * y + e[9]! * z + e[13]!\n P[pi++] = e[2]! * x + e[6]! * y + e[10]! * z + e[14]!\n } else {\n const p = transformPoint(e, x, y, z)\n P[pi++] = p[0]\n P[pi++] = p[1]\n P[pi++] = p[2]\n }\n const nx = tn[i * 3] as number\n const ny = tn[i * 3 + 1] as number\n const nz = tn[i * 3 + 2] as number\n const vx = nm[0]! * nx + nm[3]! * ny + nm[6]! * nz\n const vy = nm[1]! * nx + nm[4]! * ny + nm[7]! * nz\n const vz = nm[2]! * nx + nm[5]! * ny + nm[8]! * nz\n const s = 1 / (Math.sqrt(vx * vx + vy * vy + vz * vz) || 1)\n N[ni++] = vx * s\n N[ni++] = vy * s\n N[ni++] = vz * s\n U[ui++] = u.u0 + (tu[i * 2] as number) * du\n U[ui++] = u.v0 + (tu[i * 2 + 1] as number) * dv\n if (rgb) {\n C[ci++] = rgb[0]!\n C[ci++] = rgb[1]!\n C[ci++] = rgb[2]!\n }\n }\n acc.positions.length = pi\n acc.normals.length = ni\n acc.uvs.length = ui\n acc.colors.length = ci\n if (indexed) {\n const base = acc.vertices\n const idx = t.indices\n const n = idx ? idx.length : count\n acc.indices.reserve(n)\n const I = acc.indices.array\n let ii = acc.indices.length\n for (let k = 0; k < n; k++) I[ii++] = base + (idx ? (idx[k] as number) : k)\n acc.indices.length = ii\n }\n acc.vertices += emitted\n}\n\nfunction boundsOf(positions: Float32Array): Bounds {\n const min: [number, number, number] = [Infinity, Infinity, Infinity]\n const max: [number, number, number] = [-Infinity, -Infinity, -Infinity]\n for (let i = 0; i < positions.length; i += 3) {\n for (let axis = 0; axis < 3; axis++) {\n const v = positions[i + axis] as number\n if (v < min[axis]!) min[axis] = v\n if (v > max[axis]!) max[axis] = v\n }\n }\n return { min, max }\n}\n\nfunction finish(acc: Accumulator, indexed: boolean, withColors: boolean): ShapeBatch {\n const positions = acc.positions.done()\n const indices = indexed ? (acc.vertices > 65535 ? acc.indices.array.slice(0, acc.indices.length) : Uint16Array.from(acc.indices.array.subarray(0, acc.indices.length))) : undefined\n return {\n material: acc.material,\n part: acc.part,\n positions,\n normals: acc.normals.done(),\n uvs: acc.uvs.done(),\n ...(withColors ? { colors: acc.colors.done() } : {}),\n ...(indices ? { indices } : {}),\n ranges: acc.ranges,\n bounds: boundsOf(positions),\n }\n}\n\nconst radiusOf = (t: PrimitiveBuffers, world: readonly number[]): number => {\n let r = 0\n const p = t.positions\n for (let i = 0; i < p.length; i += 3) r = Math.max(r, Math.hypot(p[i] as number, p[i + 1] as number, p[i + 2] as number))\n const sx = Math.hypot(world[0]!, world[1]!, world[2]!)\n const sy = Math.hypot(world[4]!, world[5]!, world[6]!)\n const sz = Math.hypot(world[8]!, world[9]!, world[10]!)\n return r * Math.max(sx, sy, sz)\n}\n\ninterface LevelResult {\n readonly level: ShapeLevel\n readonly parts: ShapePart[]\n readonly points: ShapePoint[]\n readonly primitives: number\n}\n\n/** Expands a custom node into the node its generator returns (wrapped so that the custom node's own fields still apply). */\nfunction expandCustom(node: Extract<ShapeNode, { kind: 'custom' }>, settings: Settings, detail: number, path: string): ShapeNode {\n const generator = settings.generators?.[node.generator] ?? getGenerator(node.generator)\n if (!generator) throw new Error(`game-shapes: no generator \"${node.generator}\" (register it with registerGenerator, in the worker too) at ${path}`)\n const generated = generator(node.params, { random: streamFor(settings.seed, node.generator, path), seed: settings.seed, detail, path })\n const { kind: _kind, generator: _generator, params: _params, ...common } = node\n return { ...common, kind: 'group', children: [generated] }\n}\n\n/** The key two leaf primitives share when one can stand for the other as an instance. */\nconst leafKey = (node: PrimitiveNode, material: string, color: number, uv: UvRect, level: LevelSpec): string =>\n `${node.kind}|${canonicalJson(primitiveParameters(node, level))}|${material}|${color}|${uv.u0},${uv.v0},${uv.u1},${uv.v1}`\n\nfunction runLevel(schema: ShapeSchema, settings: Settings, level: LevelSpec): LevelResult {\n const bakeParts = level.index > 0\n const root: Target = { part: null, accs: new Map() }\n const targets: Target[] = [root]\n const partTargets = new Map<string, Target>()\n const parts: ShapePart[] = []\n const points: ShapePoint[] = []\n const instanced: InstancedBatch[] = []\n let primitives = 0\n const space = settings.colors === 'none' ? null : settings.colors\n const channels = new Map<number, readonly number[]>()\n const rgbOf = (hex: number): readonly number[] | null => {\n if (!space) return null\n let c = channels.get(hex)\n if (!c) {\n c = colorChannels(hex, space)\n channels.set(hex, c)\n }\n return c\n }\n const resolveMaterial = (id: string): string => {\n let out = id\n if (settings.materials && !settings.materials.has(out)) out = settings.fallback ?? out\n return settings.alias?.[out] ?? out\n }\n const accOf = (target: Target, material: string): Accumulator => {\n let acc = target.accs.get(material)\n if (!acc) {\n acc = new Accumulator(material, target.part)\n target.accs.set(material, acc)\n }\n return acc\n }\n\n // automatic instancing: count the leaves first\n const autoCounts = new Map<string, number>()\n const autoGroups = new Map<string, { node: PrimitiveNode; material: string; color: number; part: string | null; matrices: number[] }>()\n\n const count = (node: ShapeNode, inherited: { material: string; color: number; uv: UvRect; inPart: boolean }, path: string): void => {\n if (node.minDetail !== undefined && level.detail < node.minDetail) return\n if (node.kind === 'custom') return count(expandCustom(node, settings, level.detail, path), inherited, path)\n const next = {\n material: node.material !== undefined ? resolveMaterial(node.material) : inherited.material,\n color: node.color !== undefined ? colorHex(node.color) : inherited.color,\n uv: node.uv ?? inherited.uv,\n inPart: inherited.inPart || (node.part !== undefined && !bakeParts),\n }\n if (node.instances) return\n if (node.kind === 'group') {\n node.children?.forEach((child, index) => count(child, next, `${path}/${index}`))\n return\n }\n if (isPrimitiveNode(node) && node.name === undefined && !next.inPart) {\n const key = leafKey(node, next.material, next.color, next.uv, level)\n autoCounts.set(key, (autoCounts.get(key) ?? 0) + 1)\n }\n }\n const rootMaterial = resolveMaterial('default')\n if (settings.autoMin !== undefined) count(schema.root, { material: rootMaterial, color: 0xffffff, uv: IDENTITY_UV, inPart: false }, 'root')\n\n /** Draws a subtree into `collector` (a target) under `parent` (null: identity). */\n const visit = (node: ShapeNode, parent: Matrix4 | null, inherited: Inherited, path: string): void => {\n if (node.minDetail !== undefined && level.detail < node.minDetail) return\n if (node.kind === 'custom') return visit(expandCustom(node, settings, level.detail, path), parent, inherited, path)\n let target = inherited.target\n let parentWorld = parent\n if (node.part !== undefined) {\n if (bakeParts) {\n // far levels freeze the parts at rest: the part's pivot is relative to the root\n parentWorld = null\n } else {\n let partTarget = partTargets.get(node.part)\n if (!partTarget) {\n partTarget = { part: node.part, accs: new Map() }\n partTargets.set(node.part, partTarget)\n targets.push(partTarget)\n const { position, rotation, rotationOrder, scale, heading, matrix } = node\n parts.push({\n id: node.part,\n ...(position ? { position } : {}),\n ...(rotation ? { rotation } : {}),\n ...(rotationOrder ? { rotationOrder } : {}),\n ...(scale !== undefined ? { scale } : {}),\n ...(heading !== undefined ? { heading } : {}),\n ...(matrix ? { matrix } : { matrix: asMat4(matrixOf(node)) }),\n })\n }\n target = partTarget\n }\n }\n const isPart = node.part !== undefined && !bakeParts\n const local = isPart ? null : matrixOf(node)\n const world = isPart ? null : local ? (parentWorld ? multiply(parentWorld, local) : local) : parentWorld\n const next: Inherited = {\n material: node.material !== undefined ? resolveMaterial(node.material) : inherited.material,\n color: node.color !== undefined ? colorHex(node.color) : inherited.color,\n uv: node.uv ?? inherited.uv,\n target,\n }\n\n if (node.instances) {\n drawInstanced(node, parentWorld, next, path)\n return\n }\n\n const snapshot = node.name !== undefined ? new Map([...target.accs].map(([m, a]) => [m, { v: a.vertices, i: a.indices.length }])) : null\n\n if (node.kind === 'group') {\n node.children?.forEach((child, index) => visit(child, world, next, `${path}/${index}`))\n } else if (node.kind === 'point') {\n const p = node.position ?? [0, 0, 0]\n points.push({\n ...(node.name !== undefined ? { name: node.name } : {}),\n part: target.part,\n position: parent ? transformPoint(parent, p[0], p[1], p[2]) : [p[0], p[1], p[2]],\n ...(node.data !== undefined ? { data: node.data } : {}),\n ...(node.tags ? { tags: node.tags } : {}),\n })\n } else if (isPrimitiveNode(node)) {\n const template = buildPrimitive(node, level)\n const m = world ?? identity4()\n if (level.minSize !== undefined && radiusOf(template, m) < level.minSize) return\n primitives++\n if (settings.autoMin !== undefined && node.name === undefined && target.part === null) {\n const key = leafKey(node, next.material, next.color, next.uv, level)\n if ((autoCounts.get(key) ?? 0) >= settings.autoMin) {\n let group = autoGroups.get(key)\n if (!group) {\n group = { node, material: next.material, color: next.color, part: null, matrices: [] }\n autoGroups.set(key, group)\n }\n group.matrices.push(...m)\n return\n }\n }\n bake(accOf(target, next.material), template, m, rgbOf(next.color), next.uv, settings.indexed)\n }\n\n if (snapshot) {\n for (const [material, acc] of target.accs) {\n const before = snapshot.get(material) ?? { v: 0, i: 0 }\n if (acc.vertices === before.v) continue\n acc.ranges.push({\n name: node.name as string,\n ...(node.tags ? { tags: node.tags } : {}),\n vertexStart: before.v,\n vertexCount: acc.vertices - before.v,\n indexStart: before.i,\n indexCount: acc.indices.length - before.i,\n })\n }\n }\n }\n\n const drawInstanced = (node: ShapeNode, parentWorld: Matrix4 | null, inherited: Inherited, path: string): void => {\n const collector: Target = { part: inherited.target.part, accs: new Map() }\n const { instances, ...single } = node as ShapeNode & { instances: NonNullable<ShapeNode['instances']> }\n const before = parts.length\n visit(single as ShapeNode, null, { ...inherited, target: collector }, path)\n if (parts.length !== before) throw new Error(`game-shapes: an instanced node cannot hold parts (${path})`)\n const matrices = new Float32Array(instances.length * 16)\n const hasColors = instances.some((instance) => instance.color !== undefined)\n const colors = hasColors ? new Float32Array(instances.length * 3) : undefined\n instances.forEach((instance, index) => {\n const local = matrixOf(instance)\n const m = local ? (parentWorld ? multiply(parentWorld, local) : local) : parentWorld ?? identity4()\n matrices.set(m, index * 16)\n if (colors) colors.set(colorChannels(colorHex(instance.color), space ?? 'srgb'), index * 3)\n })\n for (const acc of collector.accs.values()) {\n const batch = finish(acc, settings.indexed, false)\n instanced.push({\n material: acc.material,\n part: collector.part,\n ...(node.name !== undefined ? { name: node.name } : {}),\n geometry: { type: 'BufferGeometry', parameters: {}, positions: batch.positions, normals: batch.normals, uvs: batch.uvs, ...(batch.indices ? { indices: batch.indices } : {}), groups: [] },\n matrices: matrices.slice(),\n ...(colors ? { colors: colors.slice() } : {}),\n count: instances.length,\n })\n }\n }\n\n visit(schema.root, null, { material: rootMaterial, color: 0xffffff, uv: IDENTITY_UV, target: root }, 'root')\n\n for (const group of autoGroups.values()) {\n const template = buildPrimitive(group.node, level)\n const n = group.matrices.length / 16\n const rgb = colorChannels(group.color, space ?? 'srgb')\n const colors = new Float32Array(n * 3)\n for (let i = 0; i < n; i++) colors.set(rgb, i * 3)\n instanced.push({\n material: group.material,\n part: null,\n geometry: { type: template.type, parameters: template.parameters, positions: template.positions.slice(), normals: template.normals.slice(), uvs: template.uvs.slice(), ...(template.indices ? { indices: template.indices.slice() } : {}), groups: template.groups.map((g) => ({ ...g })) },\n matrices: new Float32Array(group.matrices),\n ...(space ? { colors } : {}),\n count: n,\n })\n }\n\n const batches: ShapeBatch[] = []\n for (const target of targets) for (const acc of target.accs.values()) if (acc.vertices > 0 && (!settings.indexed || acc.indices.length > 0)) batches.push(finish(acc, settings.indexed, space !== null))\n return { level: { distance: level.distance, detail: level.detail, batches, instanced }, parts, points, primitives }\n}\n\n/**\n * Turns a shape into buffers: one batch per (part, material) per level, baked; instanced nodes as instance batches; parts with their pivots;\n * points. Pure: the same schema and options give the same bytes, here or in a worker.\n */\nexport function generate(schema: ShapeSchema, options: GenerateOptions = {}): ShapeBuffers {\n if (options.validate !== false) assertValidShape(schema)\n const settings: Settings = {\n colors: options.colors ?? 'linear',\n indexed: options.indexed ?? true,\n ...(options.materials ? { materials: new Set(options.materials) } : {}),\n ...(options.fallbackMaterial !== undefined ? { fallback: options.fallbackMaterial } : {}),\n ...(options.materialAlias ? { alias: options.materialAlias } : {}),\n seed: options.seed ?? 0,\n ...(options.generators ? { generators: options.generators } : {}),\n ...(options.instancing ? { autoMin: Math.max(2, options.instancing.minCount) } : {}),\n }\n const specs: LevelSpec[] = [{ distance: 0, detail: 1, index: 0 }, ...(schema.lod ?? []).map((rule, index) => ({ ...rule, index: index + 1 }))]\n const wanted = options.levels ? specs.filter((spec) => options.levels!.includes(spec.index)) : specs\n let parts: ShapePart[] = []\n let points: ShapePoint[] = []\n let primitives = 0\n const levels: ShapeLevel[] = []\n for (const spec of wanted) {\n const result = runLevel(schema, settings, spec)\n if (spec.index === 0 || levels.length === 0) {\n parts = result.parts\n points = result.points\n primitives = result.primitives\n }\n levels.push(result.level)\n }\n const first = levels[0]\n const vertices = first ? first.batches.reduce((sum, batch) => sum + batch.positions.length / 3, 0) : 0\n const triangles = first\n ? first.batches.reduce((sum, batch) => sum + (batch.indices ? batch.indices.length : batch.positions.length / 3) / 3, 0) +\n first.instanced.reduce((sum, batch) => sum + ((batch.geometry.indices ? batch.geometry.indices.length : batch.geometry.positions.length / 3) / 3) * batch.count, 0)\n : 0\n return {\n key: options.key === false ? '' : options.key ?? shapeKey(schema, options),\n ...(schema.name !== undefined ? { name: schema.name } : {}),\n levels,\n parts,\n points,\n ...(schema.materials ? { materials: schema.materials } : {}),\n ...(schema.cullDistance !== undefined ? { cullDistance: schema.cullDistance } : {}),\n stats: { vertices, triangles, batches: first ? first.batches.length : 0, instances: first ? first.instanced.reduce((sum, batch) => sum + batch.count, 0) : 0, primitives },\n }\n}\n","import { normalMatrix, transformPoint } from './math'\nimport type { InstancedBatch, PrimitiveBuffers, ShapeBatch, ShapeBuffers } from './types'\n\n/** One piece for `mergeTransformed`: arrays (any may be missing) and the matrix that takes them into the merged space. */\nexport interface TransformedPiece {\n readonly positions: ArrayLike<number>\n readonly normals?: ArrayLike<number>\n readonly uvs?: ArrayLike<number>\n readonly indices?: ArrayLike<number> | null\n /** Column-major 4 x 4. */\n readonly matrix: readonly number[]\n}\n\nexport interface MergedArrays {\n readonly positions: Float32Array\n readonly normals: Float32Array\n readonly uvs: Float32Array\n}\n\n/**\n * Joins pieces into one non-indexed set of arrays, each piece de-indexed, its missing normals and uvs zero-filled, its positions by\n * `Vector3.applyMatrix4` and its normals by the normal matrix and normalised: what three's `toNonIndexed` + `applyMatrix4` + a join do,\n * bit for bit (the port of `mergeByMaterial`).\n */\nexport function mergeTransformed(pieces: readonly TransformedPiece[]): MergedArrays {\n let total = 0\n for (const piece of pieces) total += piece.indices ? piece.indices.length : piece.positions.length / 3\n const positions = new Float32Array(total * 3)\n const normals = new Float32Array(total * 3)\n const uvs = new Float32Array(total * 2)\n let at = 0\n for (const piece of pieces) {\n const e = piece.matrix\n const nm = normalMatrix(e)\n const count = piece.indices ? piece.indices.length : piece.positions.length / 3\n // de-index into Float32 first, as toNonIndexed does, then transform the stored values\n const p = new Float32Array(count * 3)\n const n = new Float32Array(count * 3)\n for (let k = 0; k < count; k++) {\n const i = piece.indices ? (piece.indices[k] as number) : k\n for (let c = 0; c < 3; c++) {\n p[k * 3 + c] = piece.positions[i * 3 + c] as number\n if (piece.normals) n[k * 3 + c] = piece.normals[i * 3 + c] as number\n }\n if (piece.uvs) {\n uvs[(at + k) * 2] = piece.uvs[i * 2] as number\n uvs[(at + k) * 2 + 1] = piece.uvs[i * 2 + 1] as number\n }\n }\n for (let k = 0; k < count; k++) {\n const q = transformPoint(e, p[k * 3] as number, p[k * 3 + 1] as number, p[k * 3 + 2] as number)\n positions[(at + k) * 3] = q[0]\n positions[(at + k) * 3 + 1] = q[1]\n positions[(at + k) * 3 + 2] = q[2]\n const x = n[k * 3] as number\n const y = n[k * 3 + 1] as number\n const z = n[k * 3 + 2] as number\n const vx = nm[0]! * x + nm[3]! * y + nm[6]! * z\n const vy = nm[1]! * x + nm[4]! * y + nm[7]! * z\n const vz = nm[2]! * x + nm[5]! * y + nm[8]! * z\n const s = 1 / (Math.sqrt(vx * vx + vy * vy + vz * vz) || 1)\n normals[(at + k) * 3] = vx * s\n normals[(at + k) * 3 + 1] = vy * s\n normals[(at + k) * 3 + 2] = vz * s\n }\n at += count\n }\n return { positions, normals, uvs }\n}\n\nconst primitiveArrays = (p: PrimitiveBuffers): ArrayBuffer[] => [p.positions, p.normals, p.uvs, ...(p.indices ? [p.indices] : [])].map((a) => a.buffer as ArrayBuffer)\nconst batchArrays = (b: ShapeBatch): ArrayBuffer[] => [b.positions, b.normals, b.uvs, ...(b.colors ? [b.colors] : []), ...(b.indices ? [b.indices] : [])].map((a) => a.buffer as ArrayBuffer)\nconst instancedArrays = (b: InstancedBatch): ArrayBuffer[] => [...primitiveArrays(b.geometry), b.matrices.buffer as ArrayBuffer, ...(b.colors ? [b.colors.buffer as ArrayBuffer] : [])]\n\n/** Every `ArrayBuffer` of a result, for `postMessage(buffers, transferablesOf(buffers))`. */\nexport function transferablesOf(buffers: ShapeBuffers): ArrayBuffer[] {\n const out = new Set<ArrayBuffer>()\n for (const level of buffers.levels) {\n for (const batch of level.batches) for (const a of batchArrays(batch)) out.add(a)\n for (const batch of level.instanced) for (const a of instancedArrays(batch)) out.add(a)\n }\n return [...out]\n}\n\nconst copyPrimitive = (p: PrimitiveBuffers): PrimitiveBuffers => ({\n ...p,\n positions: p.positions.slice(),\n normals: p.normals.slice(),\n uvs: p.uvs.slice(),\n ...(p.indices ? { indices: p.indices.slice() } : {}),\n groups: p.groups.map((g) => ({ ...g })),\n})\n\n/** A deep copy whose arrays are its own (cached results are shared and read-only; copy before deforming). */\nexport function cloneBuffers(buffers: ShapeBuffers): ShapeBuffers {\n return {\n ...buffers,\n levels: buffers.levels.map((level) => ({\n ...level,\n batches: level.batches.map((b) => ({\n ...b,\n positions: b.positions.slice(),\n normals: b.normals.slice(),\n uvs: b.uvs.slice(),\n ...(b.colors ? { colors: b.colors.slice() } : {}),\n ...(b.indices ? { indices: b.indices.slice() } : {}),\n ranges: b.ranges.map((r) => ({ ...r })),\n bounds: { min: [...b.bounds.min], max: [...b.bounds.max] },\n })),\n instanced: level.instanced.map((b) => ({ ...b, geometry: copyPrimitive(b.geometry), matrices: b.matrices.slice(), ...(b.colors ? { colors: b.colors.slice() } : {}) })),\n })),\n }\n}\n\n/** Bytes held by the arrays of a result (what the cache counts). */\nexport function byteSizeOf(buffers: ShapeBuffers): number {\n return transferablesOf(buffers).reduce((sum, buffer) => sum + buffer.byteLength, 0)\n}\n","import { generate } from './generate'\nimport { transferablesOf } from './merge'\nimport type { GenerateOptions, ShapeBuffers, ShapeGenerator, ShapeSchema } from './types'\n\n/** A job the pool posts: `options` without `generators` (functions do not cross threads; register them in the worker script). */\nexport interface ShapeJob {\n readonly id: number\n readonly schema: ShapeSchema\n readonly options?: Omit<GenerateOptions, 'generators'>\n}\n\nexport type ShapeReply = { readonly id: number; readonly ok: true; readonly buffers: ShapeBuffers } | { readonly id: number; readonly ok: false; readonly error: string }\n\n/** What a worker scope looks like: `self` in a browser worker, a `worker_threads` `parentPort` wrapper in Node, or an in-thread fake. */\nexport interface WorkerScopeLike {\n onmessage: ((event: { data: unknown }) => void) | null\n postMessage(message: unknown, transfer?: ArrayBuffer[]): void\n}\n\nexport interface ShapeWorkerOptions {\n /** Generators of the `custom` nodes, the same ones the main thread registers. */\n readonly generators?: Readonly<Record<string, ShapeGenerator>>\n /** Transfer the arrays back (default true: zero copy, the worker keeps nothing). */\n readonly transfer?: boolean\n}\n\n/**\n * The worker side of `createShapePool`: answers each job with `generate(schema, options)`, transferring every array.\n *\n * ```ts\n * // shape-worker.ts\n * import { installShapeWorker } from '@adatechnology/game-shapes/worker'\n * installShapeWorker(self as never, { generators: myGenerators })\n * ```\n */\nexport function installShapeWorker(scope: WorkerScopeLike, options: ShapeWorkerOptions = {}): void {\n const transfer = options.transfer !== false\n scope.onmessage = (event) => {\n const job = event.data as ShapeJob\n try {\n const buffers = generate(job.schema, { ...(job.options ?? {}), ...(options.generators ? { generators: options.generators } : {}) })\n const reply: ShapeReply = { id: job.id, ok: true, buffers }\n scope.postMessage(reply, transfer ? transferablesOf(buffers) : [])\n } catch (error) {\n const reply: ShapeReply = { id: job.id, ok: false, error: error instanceof Error ? error.message : String(error) }\n scope.postMessage(reply)\n }\n }\n}\n","import type { PrimitiveBuffers, ShapeBatch } from '@adatechnology/game-shapes'\nimport type * as THREE_NS from 'three'\n\nexport type Three = typeof THREE_NS\n\nexport interface ToGeometryOptions {\n /** Copy the arrays into the attributes (default true). Without a copy the geometry shares the buffers (a cached result is read-only: do not deform it). */\n readonly copy?: boolean\n}\n\n/** The order in which three's generator of each type sets its attributes (toJSON and attribute iteration keep it). */\nconst UV_BEFORE_NORMAL = new Set(['LatheGeometry', 'ExtrudeGeometry'])\n/** Types whose constructor sets the index before the attributes. */\nconst INDEX_FIRST = new Set(['BoxGeometry', 'CylinderGeometry', 'ConeGeometry', 'SphereGeometry', 'PlaneGeometry', 'CircleGeometry', 'RingGeometry', 'LatheGeometry', 'TorusGeometry'])\n\nconst isPrimitive = (value: PrimitiveBuffers | ShapeBatch): value is PrimitiveBuffers => typeof (value as PrimitiveBuffers).type === 'string'\n\n/** Three's own parameters object for a type (lathe points as `Vector2`). */\nfunction threeParameters(THREE: Three, p: PrimitiveBuffers): Record<string, unknown> {\n if (p.type === 'LatheGeometry') {\n const points = (p.parameters.points as Array<{ x: number; y: number }>).map(({ x, y }) => new THREE.Vector2(x, y))\n return { ...p.parameters, points }\n }\n return { ...p.parameters }\n}\n\n/**\n * A `BufferGeometry` from game-shapes buffers. A primitive becomes an instance of the three class it reproduces (`type`, `parameters`, prototype:\n * `instanceof THREE.CylinderGeometry`, `clone()` and `toJSON()` behave as three's), with the same attributes, index and groups. A batch gets\n * `position`, `normal`, `uv`, `color` (when present) and its index.\n */\nexport function toGeometry(THREE: Three, source: PrimitiveBuffers | ShapeBatch, options: ToGeometryOptions = {}): THREE_NS.BufferGeometry {\n const copy = options.copy !== false\n const primitive = isPrimitive(source) ? source : null\n const ThreeClass = primitive && primitive.type !== 'BufferGeometry' ? ((THREE as unknown as Record<string, unknown>)[primitive.type] as (new () => THREE_NS.BufferGeometry) | undefined) : undefined\n // the BufferGeometry constructor only, with the prototype of the class it stands for\n const geometry = (ThreeClass ? Reflect.construct(THREE.BufferGeometry, [], ThreeClass) : new THREE.BufferGeometry()) as THREE_NS.BufferGeometry & { parameters?: Record<string, unknown> }\n if (primitive && ThreeClass) {\n Object.assign(geometry, { type: primitive.type, parameters: threeParameters(THREE, primitive) })\n }\n const attribute = (array: Float32Array, size: number): THREE_NS.BufferAttribute => (copy ? new THREE.Float32BufferAttribute(array, size) : new THREE.BufferAttribute(array, size))\n const index = source.indices\n const setIndex = (): void => {\n if (!index) return\n geometry.setIndex(copy ? (index instanceof Uint32Array ? new THREE.Uint32BufferAttribute(index, 1) : new THREE.Uint16BufferAttribute(index, 1)) : new THREE.BufferAttribute(index, 1))\n }\n const type = primitive?.type ?? 'BufferGeometry'\n if (INDEX_FIRST.has(type)) setIndex()\n geometry.setAttribute('position', attribute(source.positions, 3))\n if (UV_BEFORE_NORMAL.has(type)) {\n geometry.setAttribute('uv', attribute(source.uvs, 2))\n geometry.setAttribute('normal', attribute(source.normals, 3))\n } else {\n geometry.setAttribute('normal', attribute(source.normals, 3))\n geometry.setAttribute('uv', attribute(source.uvs, 2))\n }\n if (!primitive && (source as ShapeBatch).colors) geometry.setAttribute('color', attribute((source as ShapeBatch).colors as Float32Array, 3))\n if (!INDEX_FIRST.has(type)) setIndex()\n if (primitive) for (const group of primitive.groups) geometry.addGroup(group.start, group.count, group.materialIndex)\n return geometry\n}\n","import { box, circle, cone, cylinder, extrude, lathe, plane, ring, sphere, torus } from '@adatechnology/game-shapes'\nimport type { BevelSpec, PrimitiveBuffers, PrimitiveNode, ShapeOutline, Vec2 } from '@adatechnology/game-shapes'\nimport { buildPrimitive } from '@adatechnology/game-shapes'\nimport type * as THREE_NS from 'three'\n\nimport { toGeometry } from './geometry'\nimport type { Three } from './geometry'\n\n/** The geometry constructors `shapeGeometries` replaces. */\nexport const SHAPE_GEOMETRY_TYPES = ['BoxGeometry', 'CylinderGeometry', 'ConeGeometry', 'SphereGeometry', 'PlaneGeometry', 'CircleGeometry', 'RingGeometry', 'LatheGeometry', 'TorusGeometry', 'ExtrudeGeometry'] as const\n\ntype Curve = { isLineCurve?: boolean; v1?: { x: number; y: number }; v2?: { x: number; y: number } }\ntype PathLike = { curves: Curve[]; autoClose?: boolean; holes?: PathLike[] }\n\n/** The point list of a path made only of contiguous `LineCurve`s (what `moveTo` + `lineTo` builds), or null. */\nfunction linePoints(path: PathLike): Vec2[] | null {\n if (path.autoClose || path.curves.length === 0) return null\n const points: Vec2[] = []\n for (const [index, curve] of path.curves.entries()) {\n if (!curve.isLineCurve || !curve.v1 || !curve.v2) return null\n if (index === 0) points.push([curve.v1.x, curve.v1.y])\n else {\n const last = points[points.length - 1] as Vec2\n if (last[0] !== curve.v1.x || last[1] !== curve.v1.y) return null\n }\n points.push([curve.v2.x, curve.v2.y])\n }\n return points\n}\n\ntype ExtrudeOptions = { depth?: number; steps?: number; bevelEnabled?: boolean; bevelThickness?: number; bevelSize?: number; bevelOffset?: number; bevelSegments?: number; extrudePath?: unknown; UVGenerator?: unknown; curveSegments?: number }\n\n/** An extrusion game-shapes can make exactly: one straight-edged shape, no path, the world uvs. */\nfunction extrudeOf(shapes: unknown, options: ExtrudeOptions = {}): PrimitiveBuffers | null {\n if (Array.isArray(shapes) || !shapes || options.extrudePath !== undefined || options.UVGenerator !== undefined) return null\n const shape = shapes as PathLike\n const outer = linePoints(shape)\n if (!outer) return null\n const holes: Vec2[][] = []\n for (const hole of shape.holes ?? []) {\n const points = linePoints(hole)\n if (!points) return null\n holes.push(points)\n }\n const outline: ShapeOutline = holes.length ? { outer, holes } : { outer }\n const bevel: false | BevelSpec =\n options.bevelEnabled === false\n ? false\n : {\n ...(options.bevelThickness !== undefined ? { thickness: options.bevelThickness } : {}),\n ...(options.bevelSize !== undefined ? { size: options.bevelSize } : {}),\n ...(options.bevelOffset !== undefined ? { offset: options.bevelOffset } : {}),\n ...(options.bevelSegments !== undefined ? { segments: options.bevelSegments } : {}),\n }\n return extrude(outline, options.depth, options.steps, bevel)\n}\n\nexport interface ShapeGeometriesOptions {\n /** Go through the template cache of game-shapes (default true): the same primitive is generated once per process. */\n readonly cache?: boolean\n}\n\nconst namespaces = new WeakMap<object, Map<string, Three>>()\n/** The namespaces this module made: wrapping one again gives it back (a package handing its `T` to another). */\nconst shims = new WeakSet<object>()\n\n/**\n * A three namespace whose `BoxGeometry`, `CylinderGeometry`, `ConeGeometry`, `SphereGeometry`, `PlaneGeometry`, `CircleGeometry`, `RingGeometry`,\n * `LatheGeometry`, `TorusGeometry` and (straight-edged) `ExtrudeGeometry` are made by game-shapes, bit-identical to three's and instances of three's\n * classes; everything else is three's own. Hand it to code ported from the teams as `T`, so it keeps reading `new T.CylinderGeometry(...)`.\n * An extrusion with curves, several shapes, a path or a custom uv generator falls back to three.\n */\nexport function shapeGeometries(THREE: Three, options: ShapeGeometriesOptions = {}): Three {\n if (shims.has(THREE)) return THREE\n const cache = options.cache !== false\n const key = cache ? 'cache' : 'nocache'\n let byKey = namespaces.get(THREE)\n if (!byKey) {\n byKey = new Map()\n namespaces.set(THREE, byKey)\n }\n const existing = byKey.get(key)\n if (existing) return existing\n const made = (p: PrimitiveBuffers): THREE_NS.BufferGeometry => toGeometry(THREE, p)\n const viaCache = (node: PrimitiveNode, direct: () => PrimitiveBuffers): PrimitiveBuffers => (cache ? buildPrimitive(node) : direct())\n const defined = <T extends object>(o: T): T => Object.fromEntries(Object.entries(o).filter(([, v]) => v !== undefined)) as T\n const constructors: Record<(typeof SHAPE_GEOMETRY_TYPES)[number], (...args: any[]) => THREE_NS.BufferGeometry> = {\n BoxGeometry: (width?: number, height?: number, depth?: number, ws = 1, hs = 1, ds = 1) =>\n made(viaCache({ kind: 'box', size: [width ?? 1, height ?? 1, depth ?? 1], segments: [ws, hs, ds] }, () => box(width, height, depth, ws, hs, ds))),\n CylinderGeometry: (radiusTop?: number, radiusBottom?: number, height?: number, radialSegments?: number, heightSegments?: number, openEnded?: boolean, thetaStart?: number, thetaLength?: number) =>\n made(viaCache({ kind: 'cylinder', ...defined({ radiusTop, radiusBottom, height, radialSegments, heightSegments, openEnded, thetaStart, thetaLength }) }, () => cylinder(radiusTop, radiusBottom, height, radialSegments, heightSegments, openEnded, thetaStart, thetaLength))),\n ConeGeometry: (radius?: number, height?: number, radialSegments?: number, heightSegments?: number, openEnded?: boolean, thetaStart?: number, thetaLength?: number) =>\n made(viaCache({ kind: 'cone', ...defined({ radius, height, radialSegments, heightSegments, openEnded, thetaStart, thetaLength }) }, () => cone(radius, height, radialSegments, heightSegments, openEnded, thetaStart, thetaLength))),\n SphereGeometry: (radius?: number, widthSegments?: number, heightSegments?: number, phiStart?: number, phiLength?: number, thetaStart?: number, thetaLength?: number) =>\n made(viaCache({ kind: 'sphere', ...defined({ radius, widthSegments, heightSegments, phiStart, phiLength, thetaStart, thetaLength }) }, () => sphere(radius, widthSegments, heightSegments, phiStart, phiLength, thetaStart, thetaLength))),\n PlaneGeometry: (width?: number, height?: number, widthSegments?: number, heightSegments?: number) =>\n made(viaCache({ kind: 'plane', ...defined({ width, height, widthSegments, heightSegments }) }, () => plane(width, height, widthSegments, heightSegments))),\n CircleGeometry: (radius?: number, segments?: number, thetaStart?: number, thetaLength?: number) =>\n made(viaCache({ kind: 'circle', ...defined({ radius, segments, thetaStart, thetaLength }) }, () => circle(radius, segments, thetaStart, thetaLength))),\n RingGeometry: (innerRadius?: number, outerRadius?: number, thetaSegments?: number, phiSegments?: number, thetaStart?: number, thetaLength?: number) =>\n made(viaCache({ kind: 'ring', ...defined({ innerRadius, outerRadius, thetaSegments, phiSegments, thetaStart, thetaLength }) }, () => ring(innerRadius, outerRadius, thetaSegments, phiSegments, thetaStart, thetaLength))),\n LatheGeometry: (points?: Array<{ x: number; y: number }>, segments?: number, phiStart?: number, phiLength?: number) => {\n if (!points) return new THREE.LatheGeometry(undefined, segments, phiStart, phiLength)\n const profile = points.map((p) => [p.x, p.y] as const)\n return made(viaCache({ kind: 'lathe', points: profile, ...defined({ segments, phiStart, phiLength }) }, () => lathe(profile, segments, phiStart, phiLength)))\n },\n TorusGeometry: (radius?: number, tube?: number, radialSegments?: number, tubularSegments?: number, arc?: number) =>\n made(viaCache({ kind: 'torus', ...defined({ radius, tube, radialSegments, tubularSegments, arc }) }, () => torus(radius, tube, radialSegments, tubularSegments, arc))),\n ExtrudeGeometry: (shapes?: unknown, extrudeOptions?: ExtrudeOptions) => {\n const buffers = shapes === undefined ? null : extrudeOf(shapes, extrudeOptions)\n if (!buffers) return new THREE.ExtrudeGeometry(shapes as THREE_NS.Shape, extrudeOptions as THREE_NS.ExtrudeGeometryOptions)\n const geometry = toGeometry(THREE, buffers) as THREE_NS.BufferGeometry & { parameters: unknown }\n geometry.parameters = { shapes, options: extrudeOptions ?? {} }\n return geometry\n },\n }\n const namespace: Record<string, unknown> = { ...(THREE as unknown as Record<string, unknown>) }\n for (const type of SHAPE_GEOMETRY_TYPES) {\n const make = constructors[type]\n // callable with `new` (the returned object wins), and `instanceof` checks three's prototype\n const Constructor = function (this: unknown, ...args: unknown[]) {\n return make(...args)\n } as unknown as { prototype: unknown }\n Constructor.prototype = (THREE as unknown as Record<string, { prototype: unknown }>)[type]!.prototype\n Object.defineProperty(Constructor, 'name', { value: type })\n namespace[type] = Constructor\n }\n const result = namespace as unknown as Three\n byKey.set(key, result)\n shims.add(result)\n return result\n}\n","import { colorHex } from '@adatechnology/game-shapes'\nimport type { MaterialHint, ShapeBuffers, ShapeLevel, ShapePart, ShapePoint } from '@adatechnology/game-shapes'\nimport type * as THREE_NS from 'three'\n\nimport { toGeometry } from './geometry'\nimport type { Three } from './geometry'\n\n/** A `MeshStandardMaterial` per material id from the schema's hints (vertex colours on unless the hint says otherwise). */\nexport function createMaterials(THREE: Three, hints: Readonly<Record<string, MaterialHint>> = {}, ids: Iterable<string> = []): Record<string, THREE_NS.Material> {\n const out: Record<string, THREE_NS.Material> = {}\n const all = new Set([...Object.keys(hints), ...ids])\n for (const id of all) {\n const hint = hints[id] ?? {}\n const parameters: THREE_NS.MeshStandardMaterialParameters = { vertexColors: hint.vertexColors ?? true }\n if (hint.color !== undefined) parameters.color = colorHex(hint.color)\n if (hint.roughness !== undefined) parameters.roughness = hint.roughness\n if (hint.metalness !== undefined) parameters.metalness = hint.metalness\n if (hint.opacity !== undefined) parameters.opacity = hint.opacity\n if (hint.transparent !== undefined) parameters.transparent = hint.transparent\n if (hint.emissive !== undefined) parameters.emissive = colorHex(hint.emissive)\n if (hint.emissiveIntensity !== undefined) parameters.emissiveIntensity = hint.emissiveIntensity\n if (hint.flatShading !== undefined) parameters.flatShading = hint.flatShading\n if (hint.depthWrite !== undefined) parameters.depthWrite = hint.depthWrite\n if (hint.side !== undefined) parameters.side = hint.side === 'double' ? THREE.DoubleSide : hint.side === 'back' ? THREE.BackSide : THREE.FrontSide\n const material = new THREE.MeshStandardMaterial(parameters)\n material.name = id\n out[id] = material\n }\n return out\n}\n\nexport interface ToObjectOptions {\n /** Materials by id; missing ids get one from the schema hints (`createMaterials`). */\n readonly materials?: Readonly<Record<string, THREE_NS.Material>>\n /** The material of one draw (wins over `materials`): per material id and part (`null` for the static body). */\n readonly materialFor?: (material: string, part: string | null) => THREE_NS.Material | undefined\n /** Cast and receive shadows (default true). */\n readonly shadows?: boolean\n /** Copy the arrays into the attributes (default true; false shares them, read-only). */\n readonly copy?: boolean\n /** Name of the root. */\n readonly name?: string\n}\n\nexport interface ShapeObject {\n /** A `Group`, or a `LOD` when the shape has levels or a cull distance. */\n readonly object: THREE_NS.Object3D\n /** The level 0 group (the root itself without LOD). */\n readonly near: THREE_NS.Group\n /** Part groups of level 0 by id, at their pivots; animate these. */\n readonly parts: Record<string, THREE_NS.Group>\n readonly meshes: THREE_NS.Mesh[]\n readonly instanced: THREE_NS.InstancedMesh[]\n readonly points: readonly ShapePoint[]\n readonly materials: Record<string, THREE_NS.Material>\n}\n\nfunction placePart(THREE: Three, group: THREE_NS.Group, part: ShapePart): void {\n if (part.matrix && part.position === undefined && part.rotation === undefined && part.scale === undefined && part.heading === undefined) {\n new THREE.Matrix4().fromArray(part.matrix as number[]).decompose(group.position, group.quaternion, group.scale)\n return\n }\n if (part.position) group.position.set(part.position[0], part.position[1], part.position[2])\n if (part.heading !== undefined) group.rotation.y = part.heading\n else if (part.rotation) group.rotation.set(part.rotation[0], part.rotation[1], part.rotation[2], part.rotationOrder ?? 'XYZ')\n if (part.scale !== undefined) {\n if (typeof part.scale === 'number') group.scale.setScalar(part.scale)\n else group.scale.set(part.scale[0], part.scale[1], part.scale[2])\n }\n group.updateMatrix()\n}\n\n/**\n * The three objects of a shape: one mesh per batch (`static:<material>` or `part:<id>`, `userData.material`, `userData.part`), part groups at their\n * pivots, an `InstancedMesh` per instanced batch, and a `LOD` (levels at their distances, nothing from `cullDistance`) when there are levels.\n */\nexport function toObject3D(THREE: Three, buffers: ShapeBuffers, options: ToObjectOptions = {}): ShapeObject {\n const shadows = options.shadows !== false\n const ids = new Set<string>()\n for (const level of buffers.levels) {\n for (const b of level.batches) ids.add(b.material)\n for (const b of level.instanced) ids.add(b.material)\n }\n const made = createMaterials(THREE, buffers.materials, [...ids].filter((id) => !options.materials?.[id]))\n const materials: Record<string, THREE_NS.Material> = { ...made, ...(options.materials ?? {}) }\n const materialOf = (id: string, part: string | null): THREE_NS.Material => options.materialFor?.(id, part) ?? (materials[id] as THREE_NS.Material)\n const meshes: THREE_NS.Mesh[] = []\n const instanced: THREE_NS.InstancedMesh[] = []\n\n const build = (level: ShapeLevel, withParts: boolean): { group: THREE_NS.Group; parts: Record<string, THREE_NS.Group> } => {\n const group = new THREE.Group()\n group.name = options.name ?? buffers.name ?? 'shape'\n const parts: Record<string, THREE_NS.Group> = {}\n if (withParts) {\n for (const part of buffers.parts) {\n const g = new THREE.Group()\n g.name = `part:${part.id}`\n g.userData.part = part.id\n placePart(THREE, g, part)\n parts[part.id] = g\n }\n }\n const into = (part: string | null): THREE_NS.Object3D => (part !== null && parts[part]) || group\n for (const batch of level.batches) {\n const mesh = new THREE.Mesh(toGeometry(THREE, batch, { copy: options.copy !== false }), materialOf(batch.material, batch.part))\n mesh.geometry.computeBoundingSphere()\n mesh.geometry.computeBoundingBox()\n mesh.name = batch.part === null ? `static:${batch.material}` : `part:${batch.part}`\n if (batch.part !== null) mesh.userData.part = batch.part\n mesh.userData.material = batch.material\n if (batch.ranges.length) mesh.userData.ranges = batch.ranges\n mesh.castShadow = shadows\n mesh.receiveShadow = shadows\n into(batch.part).add(mesh)\n meshes.push(mesh)\n }\n for (const batch of level.instanced) {\n const mesh = new THREE.InstancedMesh(toGeometry(THREE, batch.geometry, { copy: options.copy !== false }), materialOf(batch.material, batch.part), batch.count)\n mesh.instanceMatrix.array.set(batch.matrices)\n mesh.instanceMatrix.needsUpdate = true\n if (batch.colors) mesh.instanceColor = new THREE.InstancedBufferAttribute(batch.colors.slice(), 3)\n mesh.name = `instanced:${batch.name ?? batch.material}`\n mesh.userData.material = batch.material\n if (batch.part !== null) mesh.userData.part = batch.part\n mesh.castShadow = shadows\n mesh.receiveShadow = shadows\n mesh.computeBoundingSphere()\n into(batch.part).add(mesh)\n instanced.push(mesh)\n }\n for (const part of Object.values(parts)) group.add(part)\n return { group, parts }\n }\n\n const levels = buffers.levels\n const first = build(levels[0] ?? { distance: 0, detail: 1, batches: [], instanced: [] }, true)\n let object: THREE_NS.Object3D = first.group\n if (levels.length > 1 || buffers.cullDistance !== undefined) {\n const lod = new THREE.LOD()\n lod.name = first.group.name\n lod.addLevel(first.group, 0)\n for (const level of levels.slice(1)) lod.addLevel(build(level, false).group, level.distance)\n if (buffers.cullDistance !== undefined) lod.addLevel(new THREE.Group(), buffers.cullDistance)\n object = lod\n }\n object.userData.points = buffers.points\n return { object, near: first.group, parts: first.parts, meshes, instanced, points: buffers.points, materials }\n}\n","import { mergeTransformed } from '@adatechnology/game-shapes'\nimport type { TransformedPiece } from '@adatechnology/game-shapes'\nimport type * as THREE_NS from 'three'\n\nimport type { Three } from './geometry'\n\nconst isVisible = (object: THREE_NS.Object3D): boolean => {\n for (let node: THREE_NS.Object3D | null = object; node; node = node.parent) if (!node.visible) return false\n return true\n}\n\n/** A plain, non-interleaved, not normalised Float32 attribute: what the core merge reads directly. */\nconst plain = (attribute: THREE_NS.BufferAttribute | THREE_NS.InterleavedBufferAttribute | undefined): attribute is THREE_NS.BufferAttribute =>\n attribute !== undefined && !(attribute as THREE_NS.InterleavedBufferAttribute).isInterleavedBufferAttribute && attribute.array instanceof Float32Array && !attribute.normalized\n\n/** Arrays of a geometry the core merge can take as they are; for anything else, the arrays three's own `toNonIndexed` makes (then not indexed). */\nfunction piece(geometry: THREE_NS.BufferGeometry, matrix: THREE_NS.Matrix4): TransformedPiece {\n const position = geometry.getAttribute('position')\n const normal = geometry.getAttribute('normal')\n const uv = geometry.getAttribute('uv')\n const ok = plain(position) && (normal === undefined || plain(normal)) && (uv === undefined || plain(uv)) && position.itemSize === 3 && (uv === undefined || uv.itemSize === 2)\n if (ok) {\n return { positions: position.array, ...(normal ? { normals: normal.array } : {}), ...(uv ? { uvs: uv.array } : {}), indices: geometry.index ? geometry.index.array : null, matrix: matrix.elements }\n }\n const flat = geometry.index ? geometry.toNonIndexed() : geometry\n const read = (name: string, size: number): Float32Array | undefined => {\n const attribute = flat.getAttribute(name)\n if (!attribute) return undefined\n const out = new Float32Array(attribute.count * size)\n for (let i = 0; i < attribute.count; i++) for (let c = 0; c < size; c++) out[i * size + c] = c === 0 ? attribute.getX(i) : c === 1 ? attribute.getY(i) : attribute.getZ(i)\n return out\n }\n const positions = read('position', 3) as Float32Array\n const normals = read('normal', 3)\n const uvs = read('uv', 2)\n if (flat !== geometry) flat.dispose()\n return { positions, ...(normals ? { normals } : {}), ...(uvs ? { uvs } : {}), indices: null, matrix: matrix.elements }\n}\n\n/**\n * Every visible mesh under `root` (whose world matrix must be up to date), baked into the space of `space` and joined by material: one non-indexed\n * mesh per material (position, normal, uv), no shadow cast. The bake is game-shapes' `mergeTransformed`, bit-identical to three's\n * `toNonIndexed` + `applyMatrix4` + join, so the result is the one `game-props3d`'s `mergeByMaterial` always gave.\n */\nexport function mergeByMaterial(THREE: Three, root: THREE_NS.Object3D, space: THREE_NS.Object3D): THREE_NS.Mesh[] {\n const toSpace = space.matrixWorld.clone().invert()\n const byMaterial = new Map<THREE_NS.Material, TransformedPiece[]>()\n root.traverse((object) => {\n const mesh = object as THREE_NS.Mesh\n if (!mesh.isMesh || Array.isArray(mesh.material) || !isVisible(mesh)) return\n const list = byMaterial.get(mesh.material) ?? []\n list.push(piece(mesh.geometry, new THREE.Matrix4().multiplyMatrices(toSpace, mesh.matrixWorld)))\n byMaterial.set(mesh.material, list)\n })\n return [...byMaterial].map(([material, pieces]) => {\n const merged = mergeTransformed(pieces)\n const geometry = new THREE.BufferGeometry()\n geometry.setAttribute('position', new THREE.BufferAttribute(merged.positions, 3))\n geometry.setAttribute('normal', new THREE.BufferAttribute(merged.normals, 3))\n geometry.setAttribute('uv', new THREE.BufferAttribute(merged.uvs, 2))\n const mesh = new THREE.Mesh(geometry, material)\n mesh.castShadow = false\n mesh.receiveShadow = true\n return mesh\n })\n}\n","import { shapeGeometries } from '@adatechnology/game-shapes-three'\nimport type * as THREE_NS from 'three'\n\ntype Three = typeof THREE_NS\n\n/** The material tags the team's showcase wears: what `setWear` turns toward its spoiled colour. */\nexport const WEAR_TAGS = ['metal', 'wood', 'cloth', 'plastic', 'paper', 'food', 'glass'] as const\nexport type WearTag = (typeof WEAR_TAGS)[number]\n\n/** What a material of the kit remembers so that `setWear` can go back to new: the colour it was made with (as three read it, and as sRGB floats), its tag and its roughness. */\nexport interface ItemMaterialData {\n base: THREE_NS.Color\n baseRgb: readonly [number, number, number]\n tag: string\n rough: number\n}\n\nexport type Vec3Tuple = readonly [number, number, number]\ntype Triple = [number, number, number]\n\n/**\n * The helpers the showcase page defines before its models (`M`, `mesh`, `cyl`, `bx`, `lathe`, `torus`, `extrude`, `G` and the seven material makers), so that the\n * builders ported from the page read the same as the originals. `T` is the three.js the kit was made with, with its box, cylinder, cone, sphere, plane, lathe, torus and\n * (straight-edged) extrude geometries made by game-shapes (`shapeGeometries`: the same bytes, the same classes, a template cache); `materials` lists every material it made,\n * in order.\n */\nexport interface ItemKit {\n readonly T: Three\n readonly materials: THREE_NS.MeshStandardMaterial[]\n M(color: number, tag: string, options?: THREE_NS.MeshStandardMaterialParameters): THREE_NS.MeshStandardMaterial\n mesh(geometry: THREE_NS.BufferGeometry, material: THREE_NS.Material, position?: Vec3Tuple, rotation?: Vec3Tuple, scale?: Vec3Tuple): THREE_NS.Mesh\n cyl(radiusTop: number, radiusBottom: number, height: number, segments?: number): THREE_NS.CylinderGeometry\n bx(width: number, height: number, depth: number): THREE_NS.BoxGeometry\n lathe(points: ReadonlyArray<readonly [number, number]>, segments?: number): THREE_NS.LatheGeometry\n torus(radius: number, tube: number, arc?: number): THREE_NS.TorusGeometry\n extrude(points: ReadonlyArray<readonly [number, number]>, depth: number, bevel?: number): THREE_NS.ExtrudeGeometry\n G(...children: THREE_NS.Object3D[]): THREE_NS.Group\n metal(color: number): THREE_NS.MeshStandardMaterial\n wood(color: number): THREE_NS.MeshStandardMaterial\n cloth(color: number): THREE_NS.MeshStandardMaterial\n plastic(color: number): THREE_NS.MeshStandardMaterial\n paper(color: number): THREE_NS.MeshStandardMaterial\n food(color: number): THREE_NS.MeshStandardMaterial\n glass(color: number, opacity: number): THREE_NS.MeshStandardMaterial\n}\n\n/** The channels of a hex as r128 (the team's three.js) stores them: each one over 255, as given, with no conversion. */\nconst channelsOf = (hex: number): readonly [number, number, number] => [((hex >> 16) & 255) / 255, ((hex >> 8) & 255) / 255, (hex & 255) / 255]\n\n/** The helpers of the showcase page on a given three.js; every kit has its own list of materials. */\nexport function createItemKit(three: Three): ItemKit {\n const T = shapeGeometries(three)\n const materials: THREE_NS.MeshStandardMaterial[] = []\n const M: ItemKit['M'] = (color, tag, options = {}) => {\n const material = new T.MeshStandardMaterial(Object.assign({ color, roughness: 0.78, metalness: 0 }, options))\n const base = new T.Color(color)\n const data: ItemMaterialData = { base, baseRgb: channelsOf(color), tag, rough: material.roughness }\n material.userData = data\n materials.push(material)\n return material\n }\n const mesh: ItemKit['mesh'] = (geometry, material, position = [0, 0, 0], rotation = [0, 0, 0], scale) => {\n const object = new T.Mesh(geometry, material)\n object.position.set(...(position as Triple))\n object.rotation.set(...(rotation as Triple))\n if (scale) object.scale.set(...(scale as Triple))\n return object\n }\n return {\n T,\n materials,\n M,\n mesh,\n cyl: (radiusTop, radiusBottom, height, segments = 14) => new T.CylinderGeometry(radiusTop, radiusBottom, height, segments),\n bx: (width, height, depth) => new T.BoxGeometry(width, height, depth),\n lathe: (points, segments = 16) => new T.LatheGeometry(points.map(([x, y]) => new T.Vector2(x, y)), segments),\n torus: (radius, tube, arc = Math.PI * 2) => new T.TorusGeometry(radius, tube, 8, 18, arc),\n extrude: (points, depth, bevel = 0.015) => {\n const shape = new T.Shape()\n points.forEach(([x, y], index) => (index ? shape.lineTo(x, y) : shape.moveTo(x, y)))\n return new T.ExtrudeGeometry(shape, { depth, bevelEnabled: true, bevelThickness: bevel, bevelSize: bevel, bevelSegments: 2 })\n },\n G: (...children) => {\n const group = new T.Group()\n children.forEach((child) => group.add(child))\n return group\n },\n metal: (color) => M(color, 'metal', { metalness: 0.55, roughness: 0.45 }),\n wood: (color) => M(color, 'wood'),\n cloth: (color) => M(color, 'cloth', { roughness: 0.95 }),\n plastic: (color) => M(color, 'plastic', { roughness: 0.6 }),\n paper: (color) => M(color, 'paper', { roughness: 0.9 }),\n food: (color) => M(color, 'food', { roughness: 0.85 }),\n glass: (color, opacity) => M(color, 'glass', { roughness: 0.15, metalness: 0.1, transparent: true, opacity }),\n }\n}\n","import type * as THREE_NS from 'three'\n\nimport type { ItemMaterialData } from './kit'\n\n/** 0 new, 1 used, 2 spoiled (the three stages of the showcase). */\nexport type WearStage = 0 | 1 | 2\n\n/** The colour each material tag turns toward as it wears (`STAGE_TARGET` of the showcase). */\nexport const WEAR_TARGET: Readonly<Record<string, number>> = { food: 0x5d6b2e, metal: 0x7a3e1d, wood: 0x3f3326, cloth: 0x4a4033, plastic: 0x6b6556, paper: 0x8a7a52, glass: 0x55503a }\n\n/** How far toward the target colour each stage goes (`AMT`). */\nexport const WEAR_AMOUNT: readonly [number, number, number] = [0, 0.3, 0.62]\n\nconst hexToRgb = (hex: number): readonly [number, number, number] => [((hex >> 16) & 255) / 255, ((hex >> 8) & 255) / 255, (hex & 255) / 255]\n\nconst dataOf = (material: THREE_NS.Material): ItemMaterialData | undefined => {\n const data = material.userData as Partial<ItemMaterialData>\n return data.base && data.baseRgb && data.tag !== undefined && data.rough !== undefined ? (data as ItemMaterialData) : undefined\n}\n\n/** Every material under `root` that the kit made (with a tag), once each. */\nexport function wearableMaterials(root: THREE_NS.Object3D): THREE_NS.MeshStandardMaterial[] {\n const found = new Set<THREE_NS.MeshStandardMaterial>()\n root.traverse((object) => {\n const mesh = object as THREE_NS.Mesh\n if (!mesh.isMesh) return\n for (const material of Array.isArray(mesh.material) ? mesh.material : [mesh.material]) if (dataOf(material)) found.add(material as THREE_NS.MeshStandardMaterial)\n })\n return [...found]\n}\n\n/**\n * Sets the wear of an item (`setStage` of the showcase): each material goes from its own colour toward the target of its tag by `WEAR_AMOUNT[stage]`, gets rougher, and\n * metal loses its shine. The colours are mixed in sRGB, as the page mixes them (three r128 had no colour management), so stage 0 is exactly the colour the material was made with.\n * Takes the object or the list of materials of a kit.\n */\nexport function setWear(target: THREE_NS.Object3D | readonly THREE_NS.MeshStandardMaterial[], stage: WearStage): void {\n const materials = 'traverse' in target ? wearableMaterials(target) : target\n if ('traverse' in target) target.userData.wear = stage\n const amount = WEAR_AMOUNT[stage]\n for (const material of materials) {\n const data = dataOf(material)\n if (!data) continue\n const goal = WEAR_TARGET[data.tag]\n if (goal === undefined) continue\n const [tr, tg, tb] = hexToRgb(goal)\n const [r, g, b] = data.baseRgb\n material.color.setRGB(r + (tr - r) * amount, g + (tg - g) * amount, b + (tb - b) * amount, 'srgb')\n material.roughness = Math.min(1, data.rough + (0.2 * stage) / 2)\n if (data.tag === 'metal') material.metalness = Math.max(0.1, 0.55 - 0.2 * stage)\n }\n}\n","import type * as THREE_NS from 'three'\n\nimport type { ItemKit, Vec3Tuple } from './kit'\n\n/** The simple shapes the kit draws at the real size of an item, by the `shape` hint of its definition. */\nexport const SHAPES = [\n 'can', 'bag', 'box', 'bottle', 'tool', 'roll', 'dish', 'cloth', 'shoe', 'jar', 'paper', 'fruit', 'cup', 'tube',\n 'blade', 'long_tool', 'garment', 'backpack', 'jerrycan', 'tank', 'book', 'key', 'battery', 'plank', 'device',\n] as const\nexport type ShapeId = (typeof SHAPES)[number]\n\n/** What a shape drawer is given: the kit, the size in metres, the colour of the item and the level of detail (1 full, 0.5 half the segments). */\nexport interface ShapeContext {\n k: ItemKit\n w: number\n h: number\n d: number\n color: number\n detail: number\n}\ntype Drawer = (c: ShapeContext) => THREE_NS.Group\n\nconst DEFAULT_COLOR = 0x8a8f94\nconst PI = Math.PI\n\n/** The colour `factor` times lighter (above 1) or darker (below 1), per channel. */\nexport function shade(color: number, factor: number): number {\n const channel = (shift: number): number => Math.max(0, Math.min(255, Math.round(((color >> shift) & 255) * factor)))\n return (channel(16) << 16) | (channel(8) << 8) | channel(0)\n}\n\n/** Segments of a round part at a level of detail: never below 5. */\nconst seg = (c: ShapeContext, n: number): number => Math.max(5, Math.round(n * c.detail))\n\n/** The long axis of a size and the three sides in the frame where that axis is x: `L` long, `a` the next, `b` the shortest of the other two in their own order. */\nexport function canonicalFrame(size: Vec3Tuple): { axis: 0 | 1 | 2; L: number; a: number; b: number } {\n const [w, h, d] = size\n if (h >= w && h >= d) return { axis: 1, L: h, a: w, b: d }\n if (d >= w && d >= h) return { axis: 2, L: d, a: h, b: w }\n return { axis: 0, L: w, a: h, b: d }\n}\n\n/** Turns a group drawn with its long side on x so that the long side lies on the given axis. */\nfunction orient(c: ShapeContext, group: THREE_NS.Group, axis: 0 | 1 | 2): THREE_NS.Group {\n if (axis === 0) return group\n const holder = c.k.G(group)\n if (axis === 1) holder.rotation.z = PI / 2\n else holder.rotation.y = -PI / 2\n return holder\n}\n\n/** A shape drawn along x in the frame `(L, a, b)`, then turned onto the long axis of the size. */\nconst alongLong = (draw: (c: ShapeContext, L: number, a: number, b: number) => THREE_NS.Group): Drawer => (c) => {\n const { axis, L, a, b } = canonicalFrame([c.w, c.h, c.d])\n return orient(c, draw(c, L, a, b), axis)\n}\n\n/** A group drawn with a radius of 0.5 and stretched to the width and depth of the item (an oval can fills its box). */\nconst across = (c: ShapeContext, group: THREE_NS.Group): THREE_NS.Group => {\n group.scale.set(c.w, 1, c.d)\n return c.k.G(group)\n}\n\nconst can: Drawer = (c) => {\n const { k, h } = c\n const body = k.metal(0x8d9096)\n return across(c, k.G(k.mesh(k.cyl(0.5, 0.5, h * 0.94, seg(c, 14)), body), k.mesh(k.cyl(0.5, 0.5, h * 0.5, seg(c, 14)), k.food(c.color), [0, 0, 0], [0, 0, 0], [1.0, 1, 1.0]), k.mesh(k.cyl(0.5, 0.5, h * 0.03, seg(c, 14)), body, [0, h * 0.485, 0]), k.mesh(k.cyl(0.5, 0.5, h * 0.03, seg(c, 14)), body, [0, -h * 0.485, 0])))\n}\n\nconst bottle: Drawer = (c) => {\n const { k, h } = c\n const r = 0.5\n const profile: Array<[number, number]> = [[0, -h / 2], [r, -h / 2], [r, h * 0.12], [r * 0.45, h * 0.3], [r * 0.4, h * 0.4], [0, h * 0.4]]\n return across(c, k.G(k.mesh(k.lathe(profile, seg(c, 14)), k.glass(c.color, 0.6)), k.mesh(k.cyl(r * 0.42, r * 0.42, h * 0.1, seg(c, 10)), k.plastic(shade(c.color, 0.5)), [0, h * 0.45, 0])))\n}\n\nconst jar: Drawer = (c) => {\n const { k, h } = c\n return across(c, k.G(k.mesh(k.cyl(0.5, 0.5, h * 0.82, seg(c, 14)), k.glass(c.color, 0.55), [0, -h * 0.09, 0]), k.mesh(k.cyl(0.5, 0.5, h * 0.18, seg(c, 14)), k.metal(0xb8913a), [0, h * 0.41, 0])))\n}\n\nconst bag: Drawer = (c) => {\n const { k, w, h, d } = c\n return k.G(k.mesh(k.bx(w, h * 0.88, d), k.paper(c.color), [0, -h * 0.06, 0]), k.mesh(k.bx(w * 1.0, h * 0.12, d * 0.5), k.paper(shade(c.color, 0.85)), [0, h * 0.44, 0]), k.mesh(k.bx(w * 0.7, h * 0.3, d * 1.0), k.paper(shade(c.color, 1.2)), [0, 0, 0]))\n}\n\nconst box: Drawer = (c) => {\n const { k, w, h, d } = c\n return k.G(k.mesh(k.bx(w, h, d), k.paper(c.color)), k.mesh(k.bx(w, h * 0.12, d), k.paper(shade(c.color, 0.8)), [0, h * 0.44, 0]), k.mesh(k.bx(w * 0.62, h * 0.4, d), k.paper(shade(c.color, 1.25)), [0, -h * 0.02, 0]))\n}\n\nconst cloth: Drawer = (c) => {\n const { k, w, h, d } = c\n const material = k.cloth(c.color)\n return k.G(k.mesh(k.bx(w, h * 0.55, d), material, [0, -h * 0.225, 0]), k.mesh(k.bx(w * 0.96, h * 0.45, d * 0.96), k.cloth(shade(c.color, 0.9)), [0, h * 0.275, 0]))\n}\n\nconst paper: Drawer = (c) => {\n const { k, w, h, d } = c\n const sheet = k.paper(c.color)\n return k.G(k.mesh(k.bx(w, h / 3, d), sheet, [0, -h / 3, 0]), k.mesh(k.bx(w * 0.98, h / 3, d * 0.98), k.paper(shade(c.color, 0.95)), [0, 0, 0]), k.mesh(k.bx(w, h / 3, d), sheet, [0, h / 3, 0]))\n}\n\nconst fruit: Drawer = (c) => {\n const { k, w, h, d } = c\n const sphere = new k.T.SphereGeometry(0.5, seg(c, 12), seg(c, 8))\n return k.G(k.mesh(sphere, k.food(c.color), [0, -h * 0.04, 0], [0, 0, 0], [w, h * 0.92, d]), k.mesh(k.cyl(h * 0.02, h * 0.02, h * 0.1, 6), k.wood(0x5a3a22), [0, h * 0.45, 0]))\n}\n\nconst dish: Drawer = (c) => {\n const { k, w, h, d } = c\n return k.G(k.mesh(k.cyl(0.5, 0.35, h, seg(c, 16)), k.plastic(c.color), [0, 0, 0], [0, 0, 0], [w, 1, d]))\n}\n\nconst cup: Drawer = (c) => {\n const { k, w, h, d } = c\n const profile: Array<[number, number]> = [[0, -h / 2], [0.38, -h / 2], [0.5, h / 2], [0.44, h / 2], [0.33, -h / 2 + h * 0.06], [0, -h / 2 + h * 0.06]]\n return k.G(k.mesh(k.lathe(profile, seg(c, 14)), k.plastic(c.color), [0, 0, 0], [0, 0, 0], [w, 1, d]))\n}\n\nconst tube: Drawer = (c) => {\n const { k, h } = c\n const material = k.plastic(c.color)\n return across(c, k.G(k.mesh(k.cyl(0.5, 0.42, h * 0.86, seg(c, 12)), material, [0, -h * 0.04, 0]), k.mesh(k.cyl(0.35, 0.35, h * 0.12, seg(c, 12)), k.plastic(shade(c.color, 0.6)), [0, h * 0.44, 0]), k.mesh(k.bx(1, h * 0.06, 0.25), material, [0, -h * 0.47, 0])))\n}\n\nconst roll: Drawer = (c) => {\n const { k, w, h, d } = c\n // the roll lies with its axis along the shortest side; the other two sides are the (oval) section\n const body = k.G(k.mesh(k.cyl(0.5, 0.5, 1, seg(c, 18)), k.paper(c.color)), k.mesh(k.cyl(0.18, 0.18, 0.98, seg(c, 12)), k.paper(0xb59d78)))\n if (h <= w && h <= d) body.scale.set(w, h, d)\n else if (w <= d) {\n body.rotation.z = PI / 2\n body.scale.set(h, w, d)\n } else {\n body.rotation.x = PI / 2\n body.scale.set(w, d, h)\n }\n return k.G(body)\n}\n\nconst shoe: Drawer = (c) => {\n const { k, w, h, d } = c\n const upper = k.cloth(c.color)\n return k.G(k.mesh(k.bx(w, h * 0.22, d), k.plastic(0x22251f), [0, -h * 0.39, 0]), k.mesh(k.bx(w * 0.42, h * 0.78, d * 0.96), upper, [-w * 0.29, h * 0.11, 0]), k.mesh(k.bx(w * 0.5, h * 0.5, d * 0.96), upper, [w * 0.25, -h * 0.03, 0]))\n}\n\nconst tool: Drawer = alongLong((c, L, a, b) => {\n const { k } = c\n const radius = Math.max(0.004, Math.min(a, b) / 2)\n return k.G(k.mesh(k.cyl(radius, radius, L * 0.74, seg(c, 10)), k.wood(0x8a643c), [-L * 0.13, 0, 0], [0, 0, PI / 2]), k.mesh(k.bx(L * 0.26, a, b), k.metal(shade(c.color, 1)), [L * 0.37, 0, 0]))\n})\n\nconst longTool: Drawer = alongLong((c, L, a, b) => {\n const { k } = c\n const radius = Math.max(0.004, Math.min(a, b) / 2) * 0.55\n return k.G(k.mesh(k.cyl(radius, radius, L * 0.94, seg(c, 10)), k.wood(0x9a7448), [0, 0, 0], [0, 0, PI / 2]), k.mesh(k.bx(L * 0.12, a, b), k.metal(c.color), [L * 0.44, 0, 0]))\n})\n\nconst blade: Drawer = alongLong((c, L, a, b) => {\n const { k } = c\n const edge = Math.min(0.0002, b * 0.05)\n const steel = k.extrude([[0, 0], [L * 0.66, 0], [L * 0.68, a * 0.4], [0, a]], Math.max(0.0005, b * 0.4 - 2 * edge), edge)\n return k.G(k.mesh(steel, k.metal(0xa9adb0), [-L * 0.18, -a / 2, -b * 0.2 + edge]), k.mesh(k.bx(L * 0.34, a * 0.6, b), k.wood(0x3b2a20), [-L * 0.33, 0, 0]))\n})\n\nconst garment: Drawer = (c) => {\n const { k, w, h, d } = c\n const material = k.cloth(c.color)\n return k.G(k.mesh(k.bx(w * 0.56, h, d), material), k.mesh(k.bx(w * 0.22, h * 0.42, d * 0.9), material, [-w * 0.39, h * 0.29, 0]), k.mesh(k.bx(w * 0.22, h * 0.42, d * 0.9), material, [w * 0.39, h * 0.29, 0]))\n}\n\nconst backpack: Drawer = (c) => {\n const { k, w, h, d } = c\n const material = k.cloth(c.color)\n const dome = new k.T.SphereGeometry(0.5, seg(c, 12), seg(c, 6), 0, PI * 2, 0, PI / 2)\n const strap = k.cloth(shade(c.color, 0.6))\n return k.G(k.mesh(k.bx(w, h * 0.78, d * 0.68), material, [0, -h * 0.11, -d * 0.14]), k.mesh(dome, material, [0, h * 0.28, -d * 0.14], [0, 0, 0], [w, h * 0.44, d * 0.68]), k.mesh(k.bx(w * 0.7, h * 0.4, d * 0.3), k.cloth(shade(c.color, 0.75)), [0, -h * 0.18, d * 0.35]), k.mesh(k.bx(w * 0.1, h * 0.7, d * 0.04), strap, [-w * 0.25, -h * 0.05, -d * 0.48]), k.mesh(k.bx(w * 0.1, h * 0.7, d * 0.04), strap, [w * 0.25, -h * 0.05, -d * 0.48]))\n}\n\nconst jerrycan: Drawer = (c) => {\n const { k, w, h, d } = c\n const material = k.plastic(c.color)\n return k.G(k.mesh(k.bx(w, h * 0.86, d), material, [0, -h * 0.07, 0]), k.mesh(k.bx(w * 0.4, h * 0.1, d * 0.5), material, [-w * 0.2, h * 0.45, 0]), k.mesh(k.cyl(d * 0.14, d * 0.18, h * 0.12, seg(c, 10)), k.plastic(0xd9a441), [w * 0.3, h * 0.44, 0]))\n}\n\nconst tank: Drawer = (c) => {\n const { k, h } = c\n const r = 0.5\n const profile: Array<[number, number]> = [[0, -h / 2], [r * 0.9, -h / 2], [r, -h * 0.4], [r, h * 0.22], [r * 0.6, h * 0.36], [r * 0.2, h * 0.4], [0, h * 0.4]]\n const metal = k.metal(c.color)\n return across(c, k.G(k.mesh(k.lathe(profile, seg(c, 14)), metal), k.mesh(k.cyl(r * 0.62, r * 0.62, h * 0.05, seg(c, 14)), metal, [0, h * 0.3, 0]), k.mesh(k.cyl(r * 0.18, r * 0.18, h * 0.12, seg(c, 8)), k.metal(0xb8913a), [0, h * 0.44, 0])))\n}\n\nconst book: Drawer = (c) => {\n const { k, w, h, d } = c\n const cover = k.paper(c.color)\n return k.G(k.mesh(k.bx(w, h, d * 0.14), cover, [0, 0, d * 0.43]), k.mesh(k.bx(w, h, d * 0.14), cover, [0, 0, -d * 0.43]), k.mesh(k.bx(w * 0.94, h * 0.96, d * 0.72), k.paper(0xe9e1cc), [w * 0.02, 0, 0]), k.mesh(k.bx(w * 0.08, h, d), k.paper(shade(c.color, 0.8)), [-w * 0.46, 0, 0]))\n}\n\nconst key: Drawer = alongLong((c, L, a, b) => {\n const { k } = c\n const metal = k.metal(0xb8913a)\n const ring = a * 0.5\n const tube = Math.min(b * 0.4, ring * 0.2)\n return k.G(k.mesh(new c.k.T.TorusGeometry(ring * 0.8, tube, 5, seg(c, 10)), k.metal(0x9a9da0), [-L / 2 + ring * 0.8 + tube, 0, 0]), k.mesh(k.bx(L * 0.62, a * 0.28, b), metal, [L * 0.12, 0, 0]), k.mesh(k.bx(L * 0.08, a * 0.22, b), metal, [L * 0.36, -a * 0.2, 0]), k.mesh(k.bx(L * 0.06, a * 0.22, b), metal, [L * 0.2, -a * 0.2, 0]))\n})\n\nconst battery: Drawer = alongLong((c, L, a, b) => {\n const { k } = c\n const r = Math.min(a, b) / 2\n return k.G(k.mesh(k.cyl(r, r, L * 0.94, seg(c, 14)), k.metal(c.color), [0, 0, 0], [0, 0, PI / 2]), k.mesh(k.cyl(r * 0.36, r * 0.36, L * 0.06, seg(c, 8)), k.metal(0xb9bdc0), [L * 0.47, 0, 0], [0, 0, PI / 2]))\n})\n\nconst plank: Drawer = alongLong((c, L, a, b) => {\n const { k } = c\n const nail = k.metal(0x7d8186)\n return k.G(k.mesh(k.bx(L, a, b), k.wood(0xa88459)), k.mesh(k.cyl(Math.min(a, b) * 0.1, Math.min(a, b) * 0.1, b * 0.98, 6), nail, [-L * 0.4, 0, 0], [PI / 2, 0, 0]), k.mesh(k.cyl(Math.min(a, b) * 0.1, Math.min(a, b) * 0.1, b * 0.98, 6), nail, [L * 0.4, 0, 0], [PI / 2, 0, 0]))\n})\n\nconst device: Drawer = (c) => {\n const { k, w, h, d } = c\n const screen = k.M(0x9fbf8a, 'glass', { emissive: 0x2f4a22, emissiveIntensity: 0.6, roughness: 0.2 })\n return k.G(k.mesh(k.bx(w, h, d * 0.96), k.plastic(c.color), [0, 0, -d * 0.02]), k.mesh(k.bx(w * 0.7, h * 0.32, d * 0.06), screen, [0, h * 0.22, d * 0.47]), k.mesh(k.cyl(Math.min(w, h) * 0.08, Math.min(w, h) * 0.08, d * 0.1, seg(c, 8)), k.metal(0xb9bdc0), [w * 0.25, -h * 0.18, d * 0.45], [PI / 2, 0, 0]))\n}\n\nconst DRAWERS: Readonly<Record<ShapeId, Drawer>> = {\n can, bag, box, bottle, tool, roll, dish, cloth, shoe, jar, paper, fruit, cup, tube, blade, long_tool: longTool, garment, backpack, jerrycan, tank, book, key, battery, plank, device,\n}\n\nexport const isShape = (value: string | undefined): value is ShapeId => value !== undefined && value in DRAWERS\n\n/** The item fields the shape choice reads. */\nexport interface ShapeSubject {\n category: string\n size: Vec3Tuple\n shape?: string\n color?: number\n}\n\n/**\n * The shape an item is drawn with: its own `shape` when it names one of the 25, else a box. The hints the household catalog uses (`tool`, `cloth`, `bag`, `box`, `paper`) are\n * refined by the category and the proportions, so that a rake is a long tool, a jacket a garment, a rucksack a backpack, a phone a device and a diary a book.\n */\nexport function shapeOf(subject: ShapeSubject): ShapeId {\n const hint = subject.shape\n if (!isShape(hint)) return 'box'\n const [w, h, d] = subject.size\n const { L, a, b } = canonicalFrame(subject.size)\n const long = L / Math.max(a, b, 1e-6) >= 4\n const flat = Math.min(w, h, d) / Math.max(w, h, d) <= 0.2\n switch (hint) {\n case 'tool':\n if (subject.category === 'keys') return 'key'\n if (subject.category === 'electronics') return 'device'\n if (long) return subject.category === 'melee' && Math.min(a, b) / L <= 0.1 && flat ? 'blade' : 'long_tool'\n return hint\n case 'cloth':\n return subject.category === 'clothing' ? 'garment' : hint\n case 'bag':\n return subject.category === 'bags' ? 'backpack' : hint\n case 'box':\n if (subject.category === 'electronics') return 'device'\n if (subject.category === 'books') return 'book'\n if (subject.category === 'keys') return 'key'\n return hint\n case 'paper':\n return subject.category === 'books' ? 'book' : hint\n default:\n return hint\n }\n}\n\n/** Draws the simple shape of an item at its real size, centred on the origin (the long side of long shapes lies on the long axis of `size`). */\nexport function drawShape(k: ItemKit, shape: ShapeId, size: Vec3Tuple, options: { color?: number; detail?: number } = {}): THREE_NS.Group {\n const [w, h, d] = size\n return DRAWERS[shape]({ k, w, h, d, color: options.color ?? DEFAULT_COLOR, detail: options.detail ?? 1 })\n}\n","[\n {\n \"id\": \"water\",\n \"color\": 11064558,\n \"opacity\": 0.35,\n \"stainColor\": 7309206,\n \"viscosity\": 1,\n \"density\": 1000,\n \"dryTime\": 180,\n \"gloss\": 0.9,\n \"drink\": {\n \"thirst\": 100,\n \"effects\": []\n },\n \"tags\": [\n \"drink\",\n \"clear\"\n ]\n },\n {\n \"id\": \"coffee\",\n \"color\": 3875604,\n \"opacity\": 0.95,\n \"stainColor\": 2824202,\n \"viscosity\": 1.5,\n \"density\": 1005,\n \"dryTime\": 900,\n \"gloss\": 0.8,\n \"leavesMark\": true,\n \"steamC\": 60,\n \"drink\": {\n \"thirst\": 80,\n \"effects\": [\n \"caffeine\"\n ]\n },\n \"tags\": [\n \"drink\",\n \"hot\"\n ]\n },\n {\n \"id\": \"tea\",\n \"color\": 9063188,\n \"opacity\": 0.8,\n \"stainColor\": 6961682,\n \"viscosity\": 1.4,\n \"density\": 1005,\n \"dryTime\": 800,\n \"gloss\": 0.8,\n \"leavesMark\": true,\n \"steamC\": 60,\n \"drink\": {\n \"thirst\": 90,\n \"effects\": []\n },\n \"tags\": [\n \"drink\",\n \"hot\"\n ]\n },\n {\n \"id\": \"milk\",\n \"color\": 16052712,\n \"opacity\": 0.98,\n \"stainColor\": 14473160,\n \"viscosity\": 2,\n \"density\": 1030,\n \"dryTime\": 900,\n \"gloss\": 0.5,\n \"leavesMark\": true,\n \"drink\": {\n \"thirst\": 70,\n \"effects\": []\n },\n \"tags\": [\n \"drink\"\n ]\n },\n {\n \"id\": \"soda\",\n \"color\": 3808530,\n \"opacity\": 0.85,\n \"stainColor\": 2757901,\n \"viscosity\": 1.3,\n \"density\": 1040,\n \"dryTime\": 1200,\n \"gloss\": 0.85,\n \"leavesMark\": true,\n \"drink\": {\n \"thirst\": 60,\n \"effects\": []\n },\n \"tags\": [\n \"drink\",\n \"sticky\"\n ]\n },\n {\n \"id\": \"juice\",\n \"color\": 15239467,\n \"opacity\": 0.9,\n \"stainColor\": 12741916,\n \"viscosity\": 2,\n \"density\": 1045,\n \"dryTime\": 1100,\n \"gloss\": 0.8,\n \"leavesMark\": true,\n \"drink\": {\n \"thirst\": 75,\n \"effects\": []\n },\n \"tags\": [\n \"drink\",\n \"sticky\"\n ]\n },\n {\n \"id\": \"beer\",\n \"color\": 14259740,\n \"opacity\": 0.8,\n \"stainColor\": 11039764,\n \"viscosity\": 1.4,\n \"density\": 1010,\n \"dryTime\": 900,\n \"gloss\": 0.8,\n \"drink\": {\n \"thirst\": 50,\n \"effects\": [\n \"alcohol\"\n ]\n },\n \"tags\": [\n \"drink\",\n \"alcohol\"\n ]\n },\n {\n \"id\": \"wine\",\n \"color\": 7016223,\n \"opacity\": 0.9,\n \"stainColor\": 5048854,\n \"viscosity\": 1.6,\n \"density\": 990,\n \"dryTime\": 800,\n \"gloss\": 0.85,\n \"leavesMark\": true,\n \"drink\": {\n \"thirst\": 40,\n \"effects\": [\n \"alcohol\"\n ]\n },\n \"tags\": [\n \"drink\",\n \"alcohol\"\n ]\n },\n {\n \"id\": \"spirits\",\n \"color\": 13214042,\n \"opacity\": 0.6,\n \"stainColor\": 10320959,\n \"viscosity\": 1.8,\n \"density\": 940,\n \"dryTime\": 200,\n \"gloss\": 0.85,\n \"flammable\": true,\n \"drink\": {\n \"thirst\": 5,\n \"effects\": [\n \"alcohol\"\n ]\n },\n \"tags\": [\n \"drink\",\n \"alcohol\"\n ]\n },\n {\n \"id\": \"fuel\",\n \"color\": 14926682,\n \"opacity\": 0.6,\n \"stainColor\": 7232298,\n \"viscosity\": 0.6,\n \"density\": 740,\n \"dryTime\": 60,\n \"gloss\": 0.95,\n \"leavesMark\": false,\n \"flammable\": true,\n \"drink\": {\n \"thirst\": 0,\n \"effects\": [\n \"poison\"\n ]\n },\n \"tags\": [\n \"fuel\",\n \"gasoline\"\n ]\n },\n {\n \"id\": \"diesel\",\n \"color\": 12098094,\n \"opacity\": 0.8,\n \"stainColor\": 5917208,\n \"viscosity\": 3,\n \"density\": 830,\n \"dryTime\": 3600,\n \"gloss\": 0.95,\n \"leavesMark\": true,\n \"flammable\": true,\n \"drink\": {\n \"thirst\": 0,\n \"effects\": [\n \"poison\"\n ]\n },\n \"tags\": [\n \"fuel\"\n ]\n },\n {\n \"id\": \"motor_oil\",\n \"color\": 3877388,\n \"opacity\": 0.95,\n \"stainColor\": 1840134,\n \"viscosity\": 100,\n \"density\": 880,\n \"dryTime\": 0,\n \"gloss\": 1,\n \"leavesMark\": true,\n \"flammable\": true,\n \"drink\": {\n \"thirst\": 0,\n \"effects\": [\n \"poison\"\n ]\n },\n \"tags\": [\n \"oil\"\n ]\n },\n {\n \"id\": \"cooking_oil\",\n \"color\": 14267708,\n \"opacity\": 0.85,\n \"stainColor\": 11110698,\n \"viscosity\": 60,\n \"density\": 920,\n \"dryTime\": 0,\n \"gloss\": 1,\n \"leavesMark\": true,\n \"flammable\": true,\n \"drink\": {\n \"thirst\": 0,\n \"effects\": [\n \"poison\"\n ]\n },\n \"tags\": [\n \"oil\",\n \"food\"\n ]\n },\n {\n \"id\": \"blood\",\n \"color\": 7997964,\n \"opacity\": 0.92,\n \"stainColor\": 3874068,\n \"viscosity\": 4,\n \"density\": 1060,\n \"dryTime\": 600,\n \"gloss\": 0.75,\n \"leavesMark\": true,\n \"drink\": {\n \"thirst\": 10,\n \"effects\": [\n \"disgust\"\n ]\n },\n \"tags\": [\n \"organic\"\n ]\n },\n {\n \"id\": \"old_blood\",\n \"color\": 7085078,\n \"opacity\": 0.92,\n \"stainColor\": 2758158,\n \"viscosity\": 4,\n \"density\": 1060,\n \"dryTime\": 360,\n \"gloss\": 0.7,\n \"leavesMark\": true,\n \"drink\": {\n \"thirst\": 10,\n \"effects\": [\n \"disgust\"\n ]\n },\n \"tags\": [\n \"organic\"\n ]\n },\n {\n \"id\": \"bile\",\n \"color\": 9083434,\n \"opacity\": 0.9,\n \"stainColor\": 4080160,\n \"viscosity\": 6,\n \"density\": 1020,\n \"dryTime\": 900,\n \"gloss\": 0.75,\n \"leavesMark\": true,\n \"drink\": {\n \"thirst\": 0,\n \"effects\": [\n \"disgust\"\n ]\n },\n \"tags\": [\n \"organic\"\n ]\n },\n {\n \"id\": \"sap\",\n \"color\": 13146940,\n \"opacity\": 0.8,\n \"stainColor\": 10122282,\n \"viscosity\": 200,\n \"density\": 1100,\n \"dryTime\": 3600,\n \"gloss\": 0.8,\n \"leavesMark\": true,\n \"drink\": {\n \"thirst\": 20,\n \"effects\": []\n },\n \"tags\": [\n \"organic\",\n \"sticky\"\n ]\n },\n {\n \"id\": \"acid\",\n \"color\": 10146378,\n \"opacity\": 0.6,\n \"stainColor\": 7313970,\n \"viscosity\": 1.5,\n \"density\": 1200,\n \"dryTime\": 900,\n \"gloss\": 0.9,\n \"leavesMark\": true,\n \"drink\": {\n \"thirst\": 0,\n \"effects\": [\n \"poison\"\n ]\n },\n \"tags\": [\n \"corrosive\"\n ]\n },\n {\n \"id\": \"paint\",\n \"color\": 11740715,\n \"opacity\": 0.98,\n \"stainColor\": 9050655,\n \"viscosity\": 300,\n \"density\": 1300,\n \"dryTime\": 1800,\n \"gloss\": 0.6,\n \"leavesMark\": true,\n \"drink\": {\n \"thirst\": 0,\n \"effects\": [\n \"poison\"\n ]\n },\n \"tags\": [\n \"paint\"\n ]\n },\n {\n \"id\": \"bleach\",\n \"color\": 15134688,\n \"opacity\": 0.7,\n \"stainColor\": 13621446,\n \"viscosity\": 1.2,\n \"density\": 1100,\n \"dryTime\": 900,\n \"gloss\": 0.85,\n \"leavesMark\": true,\n \"drink\": {\n \"thirst\": 0,\n \"effects\": [\n \"poison\"\n ]\n },\n \"tags\": [\n \"corrosive\"\n ]\n },\n {\n \"id\": \"honey\",\n \"color\": 14193162,\n \"opacity\": 0.9,\n \"stainColor\": 12089350,\n \"viscosity\": 3000,\n \"density\": 1420,\n \"dryTime\": 14400,\n \"gloss\": 0.95,\n \"leavesMark\": true,\n \"drink\": {\n \"thirst\": 10,\n \"effects\": []\n },\n \"tags\": [\n \"drink\",\n \"sticky\"\n ]\n }\n]","import liquidsData from './data/liquids.json'\nimport type { LiquidDef } from './types'\n\n/**\n * Built-in liquids (data in `data/liquids.json`; colours are `0xRRGGBB` stored as integers).\n * Viscosity is relative to water, density in kg/m³, `dryTime` in seconds for a thin film at 20 °C (0 = never dries).\n */\nexport const LIQUIDS: LiquidDef[] = liquidsData as unknown as LiquidDef[]\n","import type { Quat, Vec3 } from './types'\n\nexport const GRAVITY = 9.81\nexport const EPS = 1e-7\n\nexport const clamp = (v: number, lo: number, hi: number): number => (v < lo ? lo : v > hi ? hi : v)\nexport const lerp = (a: number, b: number, t: number): number => a + (b - a) * t\n\nexport const add = (a: Vec3, b: Vec3): Vec3 => [a[0] + b[0], a[1] + b[1], a[2] + b[2]]\nexport const sub = (a: Vec3, b: Vec3): Vec3 => [a[0] - b[0], a[1] - b[1], a[2] - b[2]]\nexport const scale = (a: Vec3, s: number): Vec3 => [a[0] * s, a[1] * s, a[2] * s]\nexport const dot = (a: Vec3, b: Vec3): number => a[0] * b[0] + a[1] * b[1] + a[2] * b[2]\nexport const cross = (a: Vec3, b: Vec3): Vec3 => [a[1] * b[2] - a[2] * b[1], a[2] * b[0] - a[0] * b[2], a[0] * b[1] - a[1] * b[0]]\nexport const length = (a: Vec3): number => Math.hypot(a[0], a[1], a[2])\nexport const distance = (a: Vec3, b: Vec3): number => Math.hypot(a[0] - b[0], a[1] - b[1], a[2] - b[2])\nexport const normalize = (a: Vec3, fallback: Vec3 = [0, 1, 0]): Vec3 => {\n const l = length(a)\n return l < 1e-9 ? [fallback[0], fallback[1], fallback[2]] : [a[0] / l, a[1] / l, a[2] / l]\n}\nexport const copy3 = (a: Vec3): Vec3 => [a[0], a[1], a[2]]\nexport const lerp3 = (a: Vec3, b: Vec3, t: number): Vec3 => [lerp(a[0], b[0], t), lerp(a[1], b[1], t), lerp(a[2], b[2], t)]\n\n/** Rotate `v` by the unit quaternion `q` (x, y, z, w). */\nexport const quatRotate = (q: Quat, v: Vec3): Vec3 => {\n const u: Vec3 = [q[0], q[1], q[2]]\n const c1 = cross(u, v)\n const c2 = cross(u, c1)\n return [v[0] + 2 * (q[3] * c1[0] + c2[0]), v[1] + 2 * (q[3] * c1[1] + c2[1]), v[2] + 2 * (q[3] * c1[2] + c2[2])]\n}\nexport const quatConjugate = (q: Quat): Quat => [-q[0], -q[1], -q[2], q[3]]\nexport const quatMultiply = (a: Quat, b: Quat): Quat => [\n a[3] * b[0] + a[0] * b[3] + a[1] * b[2] - a[2] * b[1],\n a[3] * b[1] - a[0] * b[2] + a[1] * b[3] + a[2] * b[0],\n a[3] * b[2] + a[0] * b[1] - a[1] * b[0] + a[2] * b[3],\n a[3] * b[3] - a[0] * b[0] - a[1] * b[1] - a[2] * b[2],\n]\nexport const quatNormalize = (q: Quat): Quat => {\n const l = Math.hypot(q[0], q[1], q[2], q[3])\n return l < 1e-9 ? [0, 0, 0, 1] : [q[0] / l, q[1] / l, q[2] / l, q[3] / l]\n}\n/** Quaternion from Euler angles in XYZ order (the same convention as three.js). */\nexport const quatFromEuler = (x: number, y: number, z: number): Quat => {\n const c1 = Math.cos(x / 2)\n const c2 = Math.cos(y / 2)\n const c3 = Math.cos(z / 2)\n const s1 = Math.sin(x / 2)\n const s2 = Math.sin(y / 2)\n const s3 = Math.sin(z / 2)\n return [s1 * c2 * c3 + c1 * s2 * s3, c1 * s2 * c3 - s1 * c2 * s3, c1 * c2 * s3 + s1 * s2 * c3, c1 * c2 * c3 - s1 * s2 * s3]\n}\n\n/** Small seeded generator (mulberry32). Its whole state is one integer, so it serialises trivially. */\nexport class Rng {\n state: number\n constructor(seed: number) {\n this.state = (Math.imul((seed | 0) ^ 0x9e3779b9, 0x85ebca6b) >>> 0) || 1\n }\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","import type { StreamState, Vec3 } from './types'\nimport { dot, sub } from './math'\nimport type { Basis } from './stains'\n\nexport const GROUND_ID = 'ground'\n/** Longest flight simulated for a stream before it counts as landing nowhere. */\nexport const MAX_FLIGHT = 3\n\n/** Position of a ballistic jet `t` seconds after leaving its origin. */\nexport const ballistic = (origin: Vec3, velocity: Vec3, gravity: number, t: number): Vec3 => [\n origin[0] + velocity[0] * t,\n origin[1] + velocity[1] * t - 0.5 * gravity * t * t,\n origin[2] + velocity[2] * t,\n]\n\n/** Point of a stream's path `t` seconds after its origin (use with `StreamState.flightTime` and the world's `gravity`). */\nexport const sampleStream = (stream: Pick<StreamState, 'origin' | 'velocity'>, gravity: number, t: number): Vec3 =>\n ballistic(stream.origin, stream.velocity, gravity, t)\n\nexport interface LandingSurface extends Basis {\n id: string\n point: Vec3\n half: [number, number]\n}\n\nexport interface Hit {\n t: number\n point: Vec3\n normal: Vec3\n surface: string\n /** Velocity of the jet at impact. */\n velocity: Vec3\n}\n\nconst velocityAt = (velocity: Vec3, gravity: number, t: number): Vec3 => [velocity[0], velocity[1] - gravity * t, velocity[2]]\n\n/** First thing a jet hits: an authored surface (plane with half extents) or else the ground. */\nexport const trace = (\n surfaces: Iterable<LandingSurface>,\n groundAt: (x: number, z: number) => number,\n origin: Vec3,\n velocity: Vec3,\n gravity: number,\n): Hit | null => {\n let best: Hit | null = null\n for (const s of surfaces) {\n const n = s.normal\n const c = dot(n, sub(origin, s.point))\n if (c < -0.005) continue\n const a = -0.5 * gravity * n[1]\n const b = dot(n, velocity)\n let t = Infinity\n if (Math.abs(a) < 1e-9) {\n if (b < -1e-9) t = -c / b\n } else {\n const disc = b * b - 4 * a * c\n if (disc >= 0) {\n const sq = Math.sqrt(disc)\n for (const root of [(-b - sq) / (2 * a), (-b + sq) / (2 * a)]) {\n if (root >= -1e-6 && b + 2 * a * root < 0 && root < t) t = root\n }\n }\n }\n if (!Number.isFinite(t) || t > MAX_FLIGHT) continue\n t = Math.max(0, t)\n if (best && t >= best.t) continue\n const p = ballistic(origin, velocity, gravity, t)\n const rel = sub(p, s.point)\n if (Math.abs(dot(rel, s.t1)) > s.half[0] || Math.abs(dot(rel, s.t2)) > s.half[1]) continue\n best = { t, point: p, normal: n, surface: s.id, velocity: velocityAt(velocity, gravity, t) }\n }\n\n // Ground: march the path and refine the crossing.\n const step = 0.02\n let prevT = 0\n const startOver = origin[1] - groundAt(origin[0], origin[2])\n const limit = best ? best.t : MAX_FLIGHT\n if (startOver <= 0) {\n return best && best.t <= 0 ? best : { t: 0, point: [origin[0], groundAt(origin[0], origin[2]), origin[2]], normal: [0, 1, 0], surface: GROUND_ID, velocity }\n }\n for (let t = step; t <= limit + step; t += step) {\n const tt = Math.min(t, limit)\n const p = ballistic(origin, velocity, gravity, tt)\n const over = p[1] - groundAt(p[0], p[2])\n if (over <= 0) {\n let lo = prevT\n let hi = tt\n for (let i = 0; i < 18; i++) {\n const mid = (lo + hi) / 2\n const q = ballistic(origin, velocity, gravity, mid)\n if (q[1] - groundAt(q[0], q[2]) > 0) lo = mid\n else hi = mid\n }\n if (best && hi >= best.t - 1e-3) return best\n const q = ballistic(origin, velocity, gravity, hi)\n return { t: hi, point: [q[0], groundAt(q[0], q[2]), q[2]], normal: [0, 1, 0], surface: GROUND_ID, velocity: velocityAt(velocity, gravity, hi) }\n }\n prevT = tt\n if (tt >= limit) break\n }\n return best\n}\n","import type { FluidEvent, LiquidId } from './types'\n\n/** Locales shipped with the package. Unknown locales fall back to `en`. */\nexport type FluidLocale = 'en' | 'pt-BR'\n\nexport interface FluidStrings {\n /** Display name per liquid id (unknown ids fall back to the id itself). */\n liquids: Record<LiquidId, string>\n /** Short label per event type. */\n events: Record<FluidEvent['type'], string>\n on: string\n off: string\n}\n\nexport const locales: Record<FluidLocale, FluidStrings> = {\n en: {\n liquids: {\n water: 'water',\n coffee: 'coffee',\n tea: 'tea',\n milk: 'milk',\n soda: 'soda',\n juice: 'juice',\n beer: 'beer',\n wine: 'wine',\n spirits: 'spirits',\n fuel: 'gasoline',\n diesel: 'diesel',\n motor_oil: 'motor oil',\n cooking_oil: 'cooking oil',\n blood: 'blood',\n old_blood: 'old blood',\n bile: 'bile',\n sap: 'sap',\n acid: 'acid',\n paint: 'paint',\n bleach: 'bleach',\n honey: 'honey',\n },\n events: {\n fill: 'filled',\n pour: 'poured',\n spill: 'spilled',\n leak: 'leaking',\n drink: 'drank',\n empty: 'emptied',\n stream_end: 'stream ended',\n splash: 'splash',\n stain: 'stain',\n dried: 'dried',\n steam: 'steam',\n mix: 'mixed',\n tap: 'tap',\n },\n on: 'on',\n off: 'off',\n },\n 'pt-BR': {\n liquids: {\n water: 'água',\n coffee: 'café',\n tea: 'chá',\n milk: 'leite',\n soda: 'refrigerante',\n juice: 'suco',\n beer: 'cerveja',\n wine: 'vinho',\n spirits: 'destilado',\n fuel: 'gasolina',\n diesel: 'diesel',\n motor_oil: 'óleo de motor',\n cooking_oil: 'óleo de cozinha',\n blood: 'sangue',\n old_blood: 'sangue antigo',\n bile: 'bile',\n sap: 'seiva',\n acid: 'ácido',\n paint: 'tinta',\n bleach: 'água sanitária',\n honey: 'mel',\n },\n events: {\n fill: 'encheu',\n pour: 'despejou',\n spill: 'derramou',\n leak: 'vazando',\n drink: 'bebeu',\n empty: 'esvaziou',\n stream_end: 'parou de escorrer',\n splash: 'respingo',\n stain: 'mancha',\n dried: 'secou',\n steam: 'vapor',\n mix: 'misturou',\n tap: 'torneira',\n },\n on: 'ligado',\n off: 'desligado',\n },\n}\n\nexport const resolveStrings = (locale: string | undefined): FluidStrings => locales[(locale as FluidLocale) ?? 'en'] ?? locales.en\n\nconst fmt = (n: number): string => `${(Math.round(n * 1000) / 1000).toString()} l`\nconst pt = (p: [number, number, number]): string => `(${p.map((v) => Math.round(v * 100) / 100).join(', ')})`\n\n/** One-line description of an event for logs and debug panels, e.g. `drank: coffee 0.03 l`. */\nexport const describeEvent = (strings: FluidStrings, event: FluidEvent): string => {\n const label = strings.events[event.type]\n const name = (id: LiquidId) => strings.liquids[id] ?? id\n switch (event.type) {\n case 'fill':\n return `${label}: ${event.container} ${name(event.liquid)} ${fmt(event.liters)}`\n case 'pour':\n case 'spill':\n return `${label}: ${event.container} ${name(event.liquid)} ${fmt(event.rate)}/s`\n case 'leak':\n return `${label}: ${event.container} ${name(event.liquid)} ${fmt(event.rate)}/s ${pt(event.point)}`\n case 'drink':\n return `${label}: ${event.container} ${name(event.liquid)} ${fmt(event.liters)}${event.effects.length ? ` [${event.effects.join(', ')}]` : ''}${event.burn ? ' !' : ''}`\n case 'empty':\n return `${label}: ${event.container}`\n case 'stream_end':\n return `${label}: ${event.stream}`\n case 'splash':\n return `${label}: ${name(event.liquid)} ${pt(event.point)}`\n case 'stain':\n return `${label}: ${event.stain} ${name(event.liquid)} ${event.surface} ${pt(event.point)}`\n case 'dried':\n return `${label}: ${event.stain}${event.mark ? ' (mark)' : ''}`\n case 'steam':\n return `${label}: ${event.container} ${event.on ? strings.on : strings.off}`\n case 'mix':\n return `${label}: ${event.container} ${name(event.from)} -> ${name(event.into)}`\n case 'tap':\n return `${label}: ${event.tap} ${event.on ? strings.on : strings.off}`\n }\n}\n","import type { ContainerSpec, Vec3 } from './types'\nimport { clamp, normalize } from './math'\n\nexport type Shape = ContainerSpec['shape']\n\n/** Sample columns of a container's inner volume: equal-weight (x, z) positions with the full height `h`. */\nexport interface Columns {\n x: Float64Array\n z: Float64Array\n h: number\n /** Radius (cylinder) or half extents (box) used for the extent of a plane. */\n kind: 'cylinder' | 'box'\n r: number\n hx: number\n hz: number\n}\n\nconst RINGS = 8\nconst SEGMENTS = 16\nconst GRID = 12\n\nexport const makeColumns = (shape: Shape): Columns => {\n if (shape.kind === 'cylinder') {\n const x = new Float64Array(RINGS * SEGMENTS)\n const z = new Float64Array(RINGS * SEGMENTS)\n let n = 0\n for (let k = 0; k < RINGS; k++) {\n const rr = shape.radius * Math.sqrt((k + 0.5) / RINGS)\n for (let m = 0; m < SEGMENTS; m++) {\n // Offset every other ring so the samples do not line up radially.\n const a = ((m + (k % 2) * 0.5) / SEGMENTS) * Math.PI * 2\n x[n] = Math.cos(a) * rr\n z[n] = Math.sin(a) * rr\n n++\n }\n }\n return { x, z, h: shape.height, kind: 'cylinder', r: shape.radius, hx: shape.radius, hz: shape.radius }\n }\n const [sx, sy, sz] = shape.size\n const x = new Float64Array(GRID * GRID)\n const z = new Float64Array(GRID * GRID)\n let n = 0\n for (let i = 0; i < GRID; i++) {\n for (let j = 0; j < GRID; j++) {\n x[n] = ((i + 0.5) / GRID - 0.5) * sx\n z[n] = ((j + 0.5) / GRID - 0.5) * sz\n n++\n }\n }\n return { x, z, h: sy, kind: 'box', r: Math.hypot(sx, sz) / 2, hx: sx / 2, hz: sz / 2 }\n}\n\n/** Range of `u · p` over the container: below `lo` it is empty, above `hi` it is full. */\nexport const planeRange = (c: Columns, u: Vec3): [number, number] => {\n const horizontal = c.kind === 'cylinder' ? c.r * Math.hypot(u[0], u[2]) : Math.abs(u[0]) * c.hx + Math.abs(u[2]) * c.hz\n const top = u[1] * c.h\n return [-horizontal + Math.min(0, top), horizontal + Math.max(0, top)]\n}\n\n/** Fraction (0..1) of the inner volume with `u · p <= d` (the liquid for a surface plane with normal `u` at offset `d`). */\nexport const planeFraction = (c: Columns, u: Vec3, d: number): number => {\n const uy = u[1]\n let total = 0\n const n = c.x.length\n for (let i = 0; i < n; i++) {\n const s0 = u[0] * c.x[i] + u[2] * c.z[i]\n let len: number\n if (uy > 1e-6) len = clamp((d - s0) / uy, 0, c.h)\n else if (uy < -1e-6) len = c.h - clamp((d - s0) / uy, 0, c.h)\n else len = s0 <= d ? c.h : 0\n total += len\n }\n return total / (n * c.h)\n}\n\n/** Plane offset `d` along unit normal `u` for which the liquid takes the volume fraction `f`. */\nexport const levelFor = (c: Columns, u: Vec3, f: number): number => {\n const [lo0, hi0] = planeRange(c, u)\n if (f <= 0) return lo0\n if (f >= 1) return hi0\n if (Math.abs(u[0]) + Math.abs(u[2]) < 1e-9) {\n return u[1] > 0 ? f * c.h * u[1] : u[1] * c.h - f * c.h * u[1]\n }\n let lo = lo0\n let hi = hi0\n for (let i = 0; i < 28; i++) {\n const mid = (lo + hi) / 2\n if (planeFraction(c, u, mid) < f) lo = mid\n else hi = mid\n }\n return (lo + hi) / 2\n}\n\n/** Radius of the lip circle (the opening); a closed spec (`opening` 0) uses half the container width once opened. */\nexport const lipRadius = (shape: Shape, opening: number): number => {\n const limit = shape.kind === 'cylinder' ? shape.radius : Math.min(shape.size[0], shape.size[2]) / 2\n return opening > 0 ? Math.min(opening, limit) : limit * 0.5\n}\n\nexport const shapeHeight = (shape: Shape): number => (shape.kind === 'cylinder' ? shape.height : shape.size[1])\n\nexport interface Lip {\n /** Lowest lip point along the surface normal, container space. */\n point: Vec3\n /** Centre of the lip circle, container space. */\n center: Vec3\n /** Outward direction (container space, horizontal in the container frame) the liquid leaves along, or null when upright. */\n outward: Vec3 | null\n /** `u · point`: the surface offset above which the liquid spills. */\n level: number\n}\n\nexport const lipOf = (shape: Shape, opening: number, u: Vec3): Lip => {\n const h = shapeHeight(shape)\n const ro = lipRadius(shape, opening)\n const center: Vec3 = [0, h, 0]\n const uh = Math.hypot(u[0], u[2])\n if (uh < 1e-6) return { point: center, center, outward: null, level: u[1] * h }\n const out: Vec3 = normalize([-u[0], 0, -u[2]])\n const point: Vec3 = [out[0] * ro, h, out[2] * ro]\n return { point, center, outward: out, level: u[0] * point[0] + u[1] * point[1] + u[2] * point[2] }\n}\n","import type { LiquidDef, StainState, Vec3 } from './types'\nimport { Rng, add, clamp, cross, dot, length, normalize, scale, sub } from './math'\n\n/** Number of radial samples of the flow front. */\nexport const SAMPLES = 16\n\nconst COS: number[] = []\nconst SIN: number[] = []\nfor (let i = 0; i < SAMPLES; i++) {\n COS.push(Math.cos((i / SAMPLES) * Math.PI * 2))\n SIN.push(Math.sin((i / SAMPLES) * Math.PI * 2))\n}\n\n/** Orthonormal frame of a surface: `normal`, `t1` (tangent) and `t2 = normal × t1`. */\nexport interface Basis {\n normal: Vec3\n t1: Vec3\n t2: Vec3\n}\n\nexport const makeBasis = (normalIn: Vec3, tangentIn?: Vec3): Basis => {\n const normal = normalize(normalIn)\n const ref: Vec3 = tangentIn && length(tangentIn) > 1e-6 ? tangentIn : Math.abs(normal[1]) > 0.9 ? [1, 0, 0] : [0, 1, 0]\n const t1 = normalize(sub(ref, scale(normal, dot(ref, normal))), [1, 0, 0])\n return { normal, t1, t2: cross(normal, t1) }\n}\n\n/** What a stain needs to know about the surface it lies on. */\nexport interface StainSurface extends Basis {\n point: Vec3\n half: [number, number]\n porosity: number\n}\n\nexport interface StainInt extends StainState {\n normal: Vec3\n tangent: Vec3\n noise: number[]\n /** Seconds since the last inflow. */\n sinceInflow: number\n /** Drying progress 0..1. */\n dry: number\n mark: boolean\n age: number\n}\n\n/** Direction (world space) of radial sample `i` on a surface frame. */\nexport const sampleDir = (b: Basis, i: number): Vec3 => [\n b.t1[0] * COS[i] + b.t2[0] * SIN[i],\n b.t1[1] * COS[i] + b.t2[1] * SIN[i],\n b.t1[2] * COS[i] + b.t2[2] * SIN[i],\n]\n\nexport const stainArea = (front: number[]): number => {\n let a = 0\n for (let i = 0; i < SAMPLES; i++) a += front[i] * front[(i + 1) % SAMPLES]\n return 0.5 * Math.sin((Math.PI * 2) / SAMPLES) * a\n}\n\nexport const meanRadius = (front: number[]): number => front.reduce((s, v) => s + v, 0) / front.length\n\n/** Thickness (m) a puddle of this liquid cannot get thinner than: 1 mm for water, thicker for viscous liquids. */\nexport const minFilm = (def: LiquidDef): number => 0.001 * (1 + 0.8 * Math.log10(Math.max(1, def.viscosity)))\n\n/** Per-direction growth multipliers: low harmonics plus smoothed seeded noise, so the outline is never a disc. */\nexport const makeNoise = (rng: Rng): number[] => {\n const amp = [0.12 + rng.next() * 0.18, 0.08 + rng.next() * 0.14, 0.05 + rng.next() * 0.08]\n const phase = [rng.next() * Math.PI * 2, rng.next() * Math.PI * 2, rng.next() * Math.PI * 2]\n const raw: number[] = []\n for (let i = 0; i < SAMPLES; i++) {\n const a = (i / SAMPLES) * Math.PI * 2\n let v = 1 + (rng.next() - 0.5) * 0.3\n for (let k = 0; k < 3; k++) v += amp[k] * Math.sin((k + 2) * a + phase[k])\n raw.push(v)\n }\n const out = raw.map((v, i) => 0.25 * raw[(i + SAMPLES - 1) % SAMPLES] + 0.5 * v + 0.25 * raw[(i + 1) % SAMPLES])\n return out.map((v) => clamp(v, 0.45, 1.7))\n}\n\n/** Horizontal run direction on a surface (downhill, unit, in the plane) and the slope strength 0..1 (sin of the angle). */\nexport const downhill = (normal: Vec3): { dir: Vec3; slope: number } => {\n const d = add([0, -1, 0], scale(normal, normal[1]))\n const slope = length(d)\n return slope < 1e-6 ? { dir: [0, 0, 0], slope: 0 } : { dir: scale(d, 1 / slope), slope }\n}\n\n/** Creates a stain at `center` (on the surface) with a small starting front. */\nexport const createStain = (\n id: string,\n surfaceId: string,\n def: LiquidDef,\n basis: Basis,\n center: Vec3,\n liters: number,\n rng: Rng,\n): StainInt => {\n const r0 = clamp(Math.sqrt(liters / 1000 / minFilm(def) / Math.PI) * 0.4, 0.012, 0.12)\n return {\n id,\n surface: surfaceId,\n liquid: def.id,\n center: [center[0], center[1], center[2]],\n front: new Array(SAMPLES).fill(r0),\n liters,\n soaked: 0,\n wetness: 1,\n wetRadius: 1,\n normal: basis.normal,\n tangent: basis.t1,\n noise: makeNoise(rng),\n sinceInflow: 0,\n dry: 0,\n mark: false,\n age: 0,\n }\n}\n\n/** Adds liquid to a stain (rewets a dried mark). `velocity` makes the front stretch the way the liquid came in. */\nexport const addInflow = (s: StainInt, liters: number, velocity: Vec3 | null): void => {\n s.liters += liters\n s.sinceInflow = 0\n if (s.dry > 0 || s.mark) {\n s.dry = 0\n s.mark = false\n s.wetness = 1\n s.wetRadius = 1\n }\n if (velocity) {\n const n = s.normal\n const tangential = sub(velocity, scale(n, dot(velocity, n)))\n if (length(tangential) > 0.2) s.flow = normalize(tangential)\n }\n}\n\n/** Moves the centre towards an inflow point without moving the outline. */\nexport const nudgeCenter = (s: StainInt, point: Vec3, weight: number, basis: Basis): void => {\n const delta = scale(sub(point, s.center), weight)\n if (length(delta) < 1e-6) return\n s.center = add(s.center, delta)\n for (let i = 0; i < SAMPLES; i++) s.front[i] = Math.max(0.008, s.front[i] - dot(delta, sampleDir(basis, i)))\n}\n\nexport type StainStatus = 'alive' | 'dried_mark' | 'dried_gone'\n\n/** Largest radius along each sample direction before the centre's surface rectangle ends. */\nconst edgeLimit = (s: StainInt, surface: StainSurface, i: number): number => {\n if (!Number.isFinite(surface.half[0]) && !Number.isFinite(surface.half[1])) return Infinity\n const rel = sub(s.center, surface.point)\n const cx = dot(rel, surface.t1)\n const cy = dot(rel, surface.t2)\n let limit = Infinity\n if (COS[i] > 1e-6) limit = Math.min(limit, (surface.half[0] - cx) / COS[i])\n else if (COS[i] < -1e-6) limit = Math.min(limit, (-surface.half[0] - cx) / COS[i])\n if (SIN[i] > 1e-6) limit = Math.min(limit, (surface.half[1] - cy) / SIN[i])\n else if (SIN[i] < -1e-6) limit = Math.min(limit, (-surface.half[1] - cy) / SIN[i])\n return Math.max(0.01, limit)\n}\n\n/**\n * Advances a stain: the front grows (faster downhill, with seeded noise, tapering as the area approaches what the liquid can cover at its\n * minimum film thickness), porous surfaces soak the pool, and once the inflow stopped the stain dries from the edge in.\n */\nexport const stepStain = (s: StainInt, def: LiquidDef, surface: StainSurface, ambientC: number, dt: number): StainStatus => {\n s.age += dt\n s.sinceInflow += dt\n const basis: Basis = surface\n const { dir: down, slope } = downhill(s.normal)\n\n // Soak into porous surfaces.\n if (s.liters > 0 && surface.porosity > 0) {\n const soak = Math.min(s.liters, surface.porosity * 0.2 * stainArea(s.front) * dt)\n s.liters -= soak\n s.soaked += soak\n }\n\n // Grow the flow front.\n if (s.liters > 1e-7 && s.wetness > 0) {\n const area = stainArea(s.front)\n const cover = s.liters / 1000 / (minFilm(def) * (1 - 0.7 * slope))\n if (area < cover) {\n const taper = clamp(1 - area / cover, 0, 1)\n const v0 = (0.02 + 0.2 * Math.sqrt(s.liters)) / Math.sqrt(Math.max(1, def.viscosity))\n const delta: number[] = []\n for (let i = 0; i < SAMPLES; i++) {\n let m = s.noise[i]\n if (s.flow) m *= 1 + 0.5 * Math.max(0, dot(sampleDir(basis, i), s.flow))\n if (slope > 0.02) {\n const a = dot(sampleDir(basis, i), down)\n m *= a > 0 ? 1 + 14 * slope * a : Math.max(0.1, 1 + 2.5 * slope * a)\n }\n delta.push(Math.max(0, Math.min(s.front[i] + v0 * m * taper * dt, edgeLimit(s, surface, i)) - s.front[i]))\n }\n // Never overshoot the area the liquid can cover: scale the growth (not the outline) down to fit.\n let lambda = 1\n const apply = (k: number) => s.front.map((r, i) => r + delta[i] * k)\n if (stainArea(apply(1)) > cover) {\n let lo = 0\n let hi = 1\n for (let i = 0; i < 14; i++) {\n const mid = (lo + hi) / 2\n if (stainArea(apply(mid)) > cover) hi = mid\n else lo = mid\n }\n lambda = lo\n }\n s.front = apply(lambda)\n }\n }\n\n // Dry from the edge in once the inflow stopped.\n if (s.sinceInflow > 1 && def.dryTime > 0 && s.dry < 1) {\n const warm = Math.pow(2, (ambientC - 20) / 12)\n const ds = (dt * warm * (1 + 0.5 * surface.porosity)) / def.dryTime\n const before = s.dry\n s.dry = Math.min(1, s.dry + ds)\n if (before < 1) s.liters *= 1 - (s.dry - before) / (1 - before)\n s.wetness = 1 - s.dry\n s.wetRadius = Math.sqrt(Math.max(0, 1 - s.dry))\n if (s.dry >= 1) {\n s.liters = 0\n s.wetness = 0\n s.wetRadius = 0\n if (def.leavesMark) {\n s.mark = true\n return 'dried_mark'\n }\n return 'dried_gone'\n }\n }\n return 'alive'\n}\n\n/** Unit direction (world space) of front sample `i` of a stain, from its `normal` and `tangent`. */\nexport const stainDirection = (s: Pick<StainState, 'normal' | 'tangent'>, i: number): Vec3 => sampleDir(makeBasis(s.normal ?? [0, 1, 0], s.tangent), i)\n","import { LIQUIDS } from './liquids'\nimport { GROUND_ID, MAX_FLIGHT, ballistic, trace } from './landing'\nimport type { Hit, LandingSurface } from './landing'\nimport { describeEvent, resolveStrings } from './locale'\nimport { GRAVITY, Rng, add, clamp, copy3, cross, distance, dot, length, normalize, quatConjugate, quatRotate, scale } from './math'\nimport { levelFor, lipOf, lipRadius, makeColumns, planeFraction, planeRange, shapeHeight } from './shapes'\nimport type { Columns } from './shapes'\nimport { addInflow, createStain, makeBasis, meanRadius, nudgeCenter, stepStain } from './stains'\nimport type { Basis, StainInt, StainSurface } from './stains'\nimport type {\n ContainerSpec,\n ContainerState,\n FluidEvent,\n FluidOptions,\n FluidWorld,\n LiquidDef,\n LiquidId,\n Quat,\n StainState,\n StainTint,\n StreamCause,\n StreamState,\n SurfaceSpec,\n Vec3,\n} from './types'\n\ninterface Hole {\n point: Vec3\n normal: Vec3\n diameter: number\n}\n\ninterface ContainerInt {\n id: string\n spec: ContainerSpec\n cols: Columns\n liquid: LiquidId | null\n liters: number\n temperature: number\n closed: boolean\n position: Vec3\n rotation: Quat\n velocity: Vec3\n prevVelocity: Vec3\n hasPrev: boolean\n holes: Hole[]\n /** Slosh of the liquid surface: tilt offsets and their rates (x, z, vx, vz). */\n slosh: [number, number, number, number]\n /** Surface normal in world space (up plus slosh) and in container space, and the surface offset along it. */\n normal: Vec3\n u: Vec3\n d: number\n steaming: boolean\n outflow: number\n /** Stream key (`spill`, `pour`, `leak:<n>`) to stream id. */\n streams: Record<string, string>\n pourRate: number\n pourTTL: number\n pourVisual: boolean\n lastMix: number\n}\n\ninterface TapInt {\n id: string\n position: Vec3\n direction: Vec3\n liquid: LiquidId\n rate: number\n temperature: number\n on: boolean\n stream?: string\n}\n\ninterface StreamInt extends StreamState {\n key: string\n lastSplash: number\n visualOnly: boolean\n temperature: number\n}\n\ninterface SurfaceInt extends SurfaceSpec, StainSurface {}\n\ninterface Snapshot {\n version: 1\n time: number\n rng: number\n counters: { container: number; stream: number; stain: number; tap?: number }\n taps?: TapInt[]\n containers: Array<Omit<ContainerInt, 'cols'>>\n surfaces: SurfaceSpec[]\n streams: StreamInt[]\n stains: StainInt[]\n}\n\nconst GROUND_POROSITY = 0.2\nconst MAX_STEP = 0.1\nconst MAX_SUBSTEPS = 50\nconst MAX_HOLES = 32\n\nconst clone = <T>(v: T): T => JSON.parse(JSON.stringify(v)) as T\n\nexport function createFluids(options: FluidOptions = {}): FluidWorld {\n const strings = resolveStrings(options.locale)\n const liquids = new Map<LiquidId, LiquidDef>()\n for (const def of LIQUIDS) liquids.set(def.id, def)\n for (const def of options.liquids ?? []) liquids.set(def.id, def)\n const ambientC = options.ambientC ?? 20\n const gravity = options.gravity ?? GRAVITY\n const groundAt = options.groundAt ?? (() => 0)\n const mergeDistance = options.mergeDistance ?? 0.15\n const maxStains = options.maxStains ?? 64\n\n let rng = new Rng(options.seed ?? 1)\n let time = 0\n const counters = { container: 0, stream: 0, stain: 0, tap: 0 }\n let containers = new Map<string, ContainerInt>()\n let surfaces = new Map<string, SurfaceInt>()\n let streams = new Map<string, StreamInt>()\n let taps = new Map<string, TapInt>()\n let stains = new Map<string, StainInt>()\n const listeners = new Map<string, Set<(e: FluidEvent) => void>>()\n let queue: FluidEvent[] = []\n /** Only events produced by `update` are queued and returned by it; direct calls just notify the listeners. */\n let updating = false\n\n const groundSurface: StainSurface = {\n normal: [0, 1, 0],\n t1: [1, 0, 0],\n t2: [0, 0, -1],\n point: [0, 0, 0],\n half: [Infinity, Infinity],\n porosity: GROUND_POROSITY,\n }\n\n // ---- events ----\n\n const emit = (e: FluidEvent): void => {\n if (updating) queue.push(e)\n options.onEvent?.(e)\n listeners.get(e.type)?.forEach((fn) => fn(e))\n listeners.get('*')?.forEach((fn) => fn(e))\n }\n\n // ---- helpers ----\n\n const toWorld = (c: ContainerInt, p: Vec3): Vec3 => add(c.position, quatRotate(c.rotation, p))\n const defOf = (c: ContainerInt): LiquidDef | null => (c.liquid ? (liquids.get(c.liquid) ?? null) : null)\n const viscScale = (def: LiquidDef): number => 1 / Math.sqrt(Math.max(1, def.viscosity))\n\n const refreshLevel = (c: ContainerInt): void => {\n c.normal = normalize([c.slosh[0], 1, c.slosh[1]])\n c.u = normalize(quatRotate(quatConjugate(c.rotation), c.normal))\n c.d = levelFor(c.cols, c.u, c.spec.capacity > 0 ? c.liters / c.spec.capacity : 0)\n }\n\n const surfaceFor = (id: string): StainSurface => (id === GROUND_ID ? groundSurface : (surfaces.get(id) ?? groundSurface))\n\n const landingSurfaces = (): LandingSurface[] => {\n const list: LandingSurface[] = []\n for (const [id, s] of surfaces) list.push({ id, normal: s.normal, t1: s.t1, t2: s.t2, point: s.point, half: s.half })\n return list\n }\n\n const stopStream = (id: string): void => {\n const s = streams.get(id)\n if (!s) return\n streams.delete(id)\n const c = s.container ? containers.get(s.container) : undefined\n if (c) delete c.streams[s.key]\n const tap = s.tap ? taps.get(s.tap) : undefined\n if (tap && tap.stream === id) tap.stream = undefined\n emit({ type: 'stream_end', stream: id })\n }\n\n const endStreamKey = (c: ContainerInt, key: string): void => {\n const id = c.streams[key]\n if (id) stopStream(id)\n }\n\n /** Create or update the stream under `key` of a container; creating one emits the matching cause event. */\n const syncStream = (\n c: ContainerInt,\n key: string,\n cause: StreamCause,\n rate: number,\n origin: Vec3,\n velocity: Vec3,\n visualOnly = false,\n ): void => {\n if (rate < 1e-5 || !c.liquid) {\n endStreamKey(c, key)\n return\n }\n const existing = c.streams[key] ? streams.get(c.streams[key]) : undefined\n if (existing) {\n existing.rate = rate\n existing.origin = origin\n existing.velocity = velocity\n existing.thin = rate < 0.04\n existing.visualOnly = visualOnly\n existing.temperature = c.temperature\n return\n }\n const id = `stream_${++counters.stream}`\n const stream: StreamInt = {\n id,\n liquid: c.liquid,\n cause,\n container: c.id,\n origin,\n velocity,\n rate,\n landing: null,\n thin: rate < 0.04,\n flightTime: MAX_FLIGHT,\n key,\n lastSplash: -1,\n visualOnly,\n temperature: c.temperature,\n }\n streams.set(id, stream)\n c.streams[key] = id\n if (cause === 'leak') emit({ type: 'leak', container: c.id, liquid: c.liquid, rate, stream: id, point: copy3(origin) })\n else if (cause === 'spill') emit({ type: 'spill', container: c.id, liquid: c.liquid, rate, stream: id })\n else emit({ type: 'pour', container: c.id, liquid: c.liquid, rate, stream: id })\n }\n\n /** Speed (m/s) at which a tap's liquid leaves the nozzle. */\n const TAP_SPEED = 1.2\n\n /** Create or update the `tap` stream of a tap that is on; end it when it is off. */\n const syncTap = (t: TapInt): void => {\n if (!t.on || t.rate < 1e-5 || !liquids.has(t.liquid)) {\n if (t.stream) stopStream(t.stream)\n return\n }\n const velocity: Vec3 = [t.direction[0] * TAP_SPEED, t.direction[1] * TAP_SPEED, t.direction[2] * TAP_SPEED]\n const existing = t.stream ? streams.get(t.stream) : undefined\n if (existing) {\n existing.rate = t.rate\n existing.thin = t.rate < 0.04\n existing.temperature = t.temperature\n existing.velocity = velocity\n return\n }\n const id = `stream_${++counters.stream}`\n streams.set(id, {\n id,\n liquid: t.liquid,\n cause: 'tap',\n tap: t.id,\n origin: copy3(t.position),\n velocity,\n rate: t.rate,\n landing: null,\n thin: t.rate < 0.04,\n flightTime: MAX_FLIGHT,\n key: `tap:${t.id}`,\n lastSplash: -1,\n visualOnly: false,\n temperature: t.temperature,\n })\n t.stream = id\n }\n\n /** Where and how fast the liquid leaves over the lowest lip point. */\n const lipFlow = (c: ContainerInt, head: number): { origin: Vec3; velocity: Vec3 } => {\n const lip = lipOf(c.spec.shape, c.spec.opening, c.u)\n const origin = toWorld(c, lip.point)\n let dir: Vec3 = [1, 0, 0]\n const horizontal = (v: Vec3): Vec3 | null => (Math.hypot(v[0], v[2]) > 1e-3 ? normalize([v[0], 0, v[2]]) : null)\n if (lip.outward) dir = horizontal(quatRotate(c.rotation, lip.outward)) ?? horizontal(quatRotate(c.rotation, [1, 0, 0])) ?? dir\n else dir = horizontal(quatRotate(c.rotation, [1, 0, 0])) ?? dir\n const speed = clamp(0.3 + 0.5 * Math.sqrt(2 * gravity * Math.max(0, head)), 0.2, 2.5)\n return { origin, velocity: [dir[0] * speed, -0.1, dir[2] * speed] }\n }\n\n const removeLiters = (c: ContainerInt, amount: number): void => {\n c.liters = Math.max(0, c.liters - amount)\n }\n\n /** Clear a container that ran out and emit `empty` once. */\n const settle = (c: ContainerInt): void => {\n if (c.liquid && c.liters <= 1e-6) {\n c.liters = 0\n c.liquid = null\n emit({ type: 'empty', container: c.id })\n }\n }\n\n const fillInternal = (c: ContainerInt, liquid: LiquidId, liters: number, temperature: number | undefined, announce: boolean): number => {\n if (!(liters > 0) || !liquids.has(liquid)) return 0\n const room = c.spec.capacity - c.liters\n const accepted = Math.min(liters, Math.max(0, room))\n if (accepted <= 0) return 0\n const t = temperature ?? ambientC\n if (c.liquid && c.liquid !== liquid && c.liters > 1e-6) {\n const incomingWins = accepted > c.liters\n const into = incomingWins ? liquid : c.liquid\n const from = incomingWins ? c.liquid : liquid\n if (announce || time - c.lastMix > 0.5) {\n c.lastMix = time\n emit({ type: 'mix', container: c.id, from, into })\n }\n c.liquid = into\n } else if (!c.liquid || c.liters <= 1e-6) {\n c.liquid = liquid\n }\n c.temperature = c.liters > 1e-6 ? (c.temperature * c.liters + t * accepted) / (c.liters + accepted) : t\n c.liters += accepted\n if (announce) emit({ type: 'fill', container: c.id, liquid, liters: accepted })\n return accepted\n }\n\n // ---- stains ----\n\n const stainAt = (surfaceId: string, liquid: LiquidId, point: Vec3): StainInt | null => {\n let best: StainInt | null = null\n let bestD = Infinity\n for (const s of stains.values()) {\n if (s.surface !== surfaceId || s.liquid !== liquid) continue\n const d = distance(point, s.center)\n if (d < mergeDistance + 0.5 * meanRadius(s.front) && d < bestD) {\n best = s\n bestD = d\n }\n }\n return best\n }\n\n const evictStain = (): void => {\n let victim: StainInt | null = null\n for (const s of stains.values()) {\n const rank = (x: StainInt) => (x.wetness <= 0 ? 0 : 1) * 1e9 - x.age\n if (!victim || rank(s) < rank(victim)) victim = s\n }\n if (victim) stains.delete(victim.id)\n }\n\n const deposit = (liquid: LiquidId, hit: Pick<Hit, 'point' | 'surface' | 'normal'>, liters: number, velocity: Vec3 | null, tint?: StainTint): void => {\n const def = liquids.get(liquid)\n if (!def || liters <= 0) return\n let s = stainAt(hit.surface, liquid, hit.point)\n if (s) {\n const basis: Basis = { normal: s.normal, t1: s.tangent, t2: cross(s.normal, s.tangent) }\n nudgeCenter(s, hit.point, clamp((liters / (s.liters + liters)) * 0.5, 0, 0.5), basis)\n addInflow(s, liters, velocity)\n if (tint) s.tint = { ...tint }\n return\n }\n while (stains.size >= maxStains) evictStain()\n const surface = surfaceFor(hit.surface)\n const basis: Basis = hit.surface === GROUND_ID ? makeBasis(hit.normal) : surface\n s = createStain(`stain_${++counters.stain}`, hit.surface, def, basis, hit.point, liters, rng)\n if (velocity) addInflow(s, 0, velocity)\n if (tint) s.tint = { ...tint }\n s.sinceInflow = 0\n stains.set(s.id, s)\n emit({ type: 'stain', stain: s.id, surface: hit.surface, liquid, point: copy3(hit.point) })\n }\n\n // ---- streams ----\n\n const lipCenterWorld = (c: ContainerInt): Vec3 => toWorld(c, [0, shapeHeight(c.spec.shape), 0])\n\n /** A container whose opening the jet passes through before it lands (pouring into a cup). */\n const catcher = (s: StreamInt, landingT: number): { container: ContainerInt; t: number; point: Vec3 } | null => {\n let best: { container: ContainerInt; t: number; point: Vec3 } | null = null\n for (const oc of containers.values()) {\n if (oc.id === s.container || oc.closed || oc.liters >= oc.spec.capacity) continue\n const lip = lipCenterWorld(oc)\n const disc = s.velocity[1] * s.velocity[1] - 2 * gravity * (lip[1] - s.origin[1])\n if (disc < 0) continue\n const t = (s.velocity[1] + Math.sqrt(disc)) / gravity\n if (t <= 0 || t >= landingT || (best && t >= best.t)) continue\n const p = ballistic(s.origin, s.velocity, gravity, t)\n if (Math.hypot(p[0] - lip[0], p[2] - lip[2]) <= lipRadius(oc.spec.shape, oc.spec.opening) + 0.01) best = { container: oc, t, point: p }\n }\n return best\n }\n\n const stepStream = (s: StreamInt, dt: number): void => {\n const hit = trace(landingSurfaces(), groundAt, s.origin, s.velocity, gravity)\n const caught = catcher(s, hit ? hit.t : MAX_FLIGHT)\n if (caught) {\n s.landing = caught.point\n s.flightTime = caught.t\n if (!s.visualOnly) fillInternal(caught.container, s.liquid, s.rate * dt, s.temperature, false)\n return\n }\n s.landing = hit ? copy3(hit.point) : null\n s.flightTime = hit ? hit.t : MAX_FLIGHT\n if (!hit || s.visualOnly) return\n const speed = length(hit.velocity)\n if (time - s.lastSplash >= 0.12) {\n s.lastSplash = time\n emit({ type: 'splash', liquid: s.liquid, point: copy3(hit.point), intensity: clamp(0.15 + s.rate * 1.2 + speed * 0.05, 0, 1) })\n }\n deposit(s.liquid, hit, s.rate * dt, hit.velocity)\n }\n\n // ---- containers ----\n\n const spillRate = (c: ContainerInt, def: LiquidDef, h: number): number => {\n const ro = lipRadius(c.spec.shape, c.spec.opening)\n const area = 2 * ro * Math.min(h, ro)\n return Math.max(0.6 * area * Math.sqrt(2 * gravity * h) * 1000 * viscScale(def), 0.004)\n }\n\n const steamThreshold = (def: LiquidDef): number => def.steamC ?? (def.drink && def.drink.thirst > 0 ? 60 : Infinity)\n\n const stepContainer = (c: ContainerInt, dt: number): void => {\n // Slosh: the surface tilts towards the horizontal acceleration and settles with a damped spring.\n if (c.hasPrev && dt > 0) {\n const ax = (c.velocity[0] - c.prevVelocity[0]) / dt\n const az = (c.velocity[2] - c.prevVelocity[2]) / dt\n const tx = clamp(ax / gravity, -0.35, 0.35)\n const tz = clamp(az / gravity, -0.35, 0.35)\n const w = 9\n const z = 0.12\n c.slosh[2] += (w * w * (tx - c.slosh[0]) - 2 * z * w * c.slosh[2]) * dt\n c.slosh[3] += (w * w * (tz - c.slosh[1]) - 2 * z * w * c.slosh[3]) * dt\n } else {\n c.slosh[2] *= 0.5\n c.slosh[3] *= 0.5\n }\n c.slosh[0] += c.slosh[2] * dt\n c.slosh[1] += c.slosh[3] * dt\n if (Math.abs(c.slosh[0]) + Math.abs(c.slosh[1]) + Math.abs(c.slosh[2]) + Math.abs(c.slosh[3]) < 1e-5) c.slosh = [0, 0, 0, 0]\n c.prevVelocity = copy3(c.velocity)\n c.hasPrev = true\n\n // Cooling towards ambient (insulated containers 10× slower).\n if (c.temperature !== ambientC) {\n const tau = (600 + 2400 * c.liters) * (c.spec.insulated ? 10 : 1)\n c.temperature = ambientC + (c.temperature - ambientC) * Math.exp(-dt / tau)\n if (Math.abs(c.temperature - ambientC) < 0.01) c.temperature = ambientC\n }\n\n refreshLevel(c)\n const def = defOf(c)\n\n const steaming = !!def && c.liters > 1e-6 && !c.closed && c.temperature > steamThreshold(def)\n if (steaming !== c.steaming) {\n c.steaming = steaming\n emit({ type: 'steam', container: c.id, on: steaming })\n }\n\n c.outflow = 0\n if (!def || c.liters <= 1e-6) {\n for (const key of Object.keys(c.streams)) endStreamKey(c, key)\n c.pourTTL = 0\n settle(c)\n return\n }\n\n // Pour (driven by `pour()`), else spill over the lip when the tilted surface rises above it.\n if (c.pourTTL > 0) {\n c.pourTTL -= dt\n if (c.pourTTL > 0) {\n const flow = lipFlow(c, 0.05)\n syncStream(c, 'pour', 'pour', c.pourRate, flow.origin, flow.velocity, c.pourVisual)\n c.outflow += c.pourRate\n } else endStreamKey(c, 'pour')\n endStreamKey(c, 'spill')\n } else {\n endStreamKey(c, 'pour')\n const lip = lipOf(c.spec.shape, c.spec.opening, c.u)\n const h = c.d - lip.level\n let handled = false\n if (!c.closed && h > 1e-5) {\n const excess = c.liters - c.spec.capacity * planeFraction(c.cols, c.u, lip.level)\n if (excess > 1e-6) {\n const rate = Math.min(spillRate(c, def, h), excess / Math.max(dt, 1e-6))\n removeLiters(c, Math.min(rate * dt, excess, c.liters))\n const flow = lipFlow(c, h)\n syncStream(c, 'spill', 'spill', rate, flow.origin, flow.velocity)\n c.outflow += rate\n handled = true\n }\n }\n if (!handled) endStreamKey(c, 'spill')\n }\n\n // Holes leak by Torricelli with the head above each hole.\n for (let i = 0; i < c.holes.length; i++) {\n const hole = c.holes[i]\n const key = `leak:${i}`\n const hh = dot(c.u, hole.point)\n const head = c.d - hh\n if (c.liters > 1e-6 && head > 1e-4) {\n const area = Math.PI * (hole.diameter / 2) ** 2\n const natural = 0.6 * area * Math.sqrt(2 * gravity * head) * 1000 * viscScale(def)\n const avail = c.liters - c.spec.capacity * planeFraction(c.cols, c.u, hh)\n if (avail > 1e-7) {\n const rate = Math.min(natural, avail / Math.max(dt, 1e-6))\n removeLiters(c, Math.min(rate * dt, avail))\n const nW = normalize(quatRotate(c.rotation, hole.normal))\n const v = Math.min(3, 0.6 * Math.sqrt(2 * gravity * head))\n syncStream(c, key, 'leak', rate, toWorld(c, hole.point), [nW[0] * v, nW[1] * v - 0.05, nW[2] * v])\n c.outflow += rate\n continue\n }\n }\n endStreamKey(c, key)\n }\n if (c.holes.length > 0 || c.outflow > 0) refreshLevel(c)\n settle(c)\n }\n\n const step = (dt: number): void => {\n time += dt\n for (const c of [...containers.values()]) stepContainer(c, dt)\n for (const s of [...streams.values()]) stepStream(s, dt)\n for (const st of [...stains.values()]) {\n const def = liquids.get(st.liquid)\n if (!def) continue\n const status = stepStain(st, def, surfaceFor(st.surface), ambientC, dt)\n if (status === 'dried_mark') emit({ type: 'dried', stain: st.id, mark: true })\n else if (status === 'dried_gone') {\n stains.delete(st.id)\n emit({ type: 'dried', stain: st.id, mark: false })\n }\n }\n }\n\n // ---- public state views ----\n\n const stateOf = (c: ContainerInt): ContainerState => ({\n id: c.id,\n liquid: c.liquid,\n liters: c.liters,\n capacity: c.spec.capacity,\n temperature: c.temperature,\n closed: c.closed,\n surfaceHeight: c.liters > 0 ? c.d : 0,\n surfacePoint: add(c.position, scale(c.normal, c.liters > 0 ? c.d : 0)),\n surfaceNormal: copy3(c.normal),\n holes: c.holes.map((h) => ({ point: copy3(h.point), normal: copy3(h.normal), diameter: h.diameter })),\n outflow: c.outflow,\n steaming: c.steaming,\n shape: c.spec.shape,\n lipRadius: lipRadius(c.spec.shape, c.spec.opening),\n position: copy3(c.position),\n rotation: [...c.rotation] as Quat,\n })\n\n const streamView = (s: StreamInt): StreamState => ({\n id: s.id,\n liquid: s.liquid,\n cause: s.cause,\n container: s.container,\n tap: s.tap,\n origin: copy3(s.origin),\n velocity: copy3(s.velocity),\n rate: s.rate,\n landing: s.landing ? copy3(s.landing) : null,\n thin: s.thin,\n flightTime: s.flightTime,\n })\n\n const stainView = (s: StainInt): StainState => ({\n id: s.id,\n surface: s.surface,\n liquid: s.liquid,\n center: copy3(s.center),\n front: [...s.front],\n liters: s.liters,\n soaked: s.soaked,\n wetness: s.wetness,\n wetRadius: s.wetRadius,\n normal: copy3(s.normal),\n tangent: copy3(s.tangent),\n flow: s.flow ? copy3(s.flow) : undefined,\n mark: s.mark,\n age: s.age,\n tint: s.tint ? { ...s.tint } : undefined,\n })\n\n // ---- world API ----\n\n const world: FluidWorld = {\n liquids,\n gravity,\n describe: (event) => describeEvent(strings, event),\n\n addContainer(spec, opts = {}) {\n const id = opts.id ?? `container_${++counters.container}`\n if (containers.has(id)) world.removeContainer(id)\n const liquid = spec.liquid && liquids.has(spec.liquid) ? spec.liquid : null\n const liters = liquid ? clamp(spec.liters ?? 0, 0, spec.capacity) : 0\n const c: ContainerInt = {\n id,\n spec: clone(spec),\n cols: makeColumns(spec.shape),\n liquid: liters > 0 ? liquid : null,\n liters,\n temperature: spec.temperature ?? ambientC,\n closed: spec.closed ?? spec.opening <= 0,\n position: copy3(opts.position ?? [0, 0, 0]),\n rotation: opts.rotation ? ([...opts.rotation] as Quat) : [0, 0, 0, 1],\n velocity: [0, 0, 0],\n prevVelocity: [0, 0, 0],\n hasPrev: false,\n holes: [],\n slosh: [0, 0, 0, 0],\n normal: [0, 1, 0],\n u: [0, 1, 0],\n d: 0,\n steaming: false,\n outflow: 0,\n streams: {},\n pourRate: 0,\n pourTTL: 0,\n pourVisual: false,\n lastMix: -10,\n }\n containers.set(id, c)\n refreshLevel(c)\n return id\n },\n\n addTap(spec) {\n const id = spec.id ?? `tap_${++counters.tap}`\n if (taps.has(id)) world.removeTap(id)\n const d = spec.direction ?? [0, -1, 0]\n const len = Math.hypot(d[0], d[1], d[2]) || 1\n const t: TapInt = {\n id,\n position: copy3(spec.position),\n direction: [d[0] / len, d[1] / len, d[2] / len],\n liquid: spec.liquid,\n rate: Math.max(0, spec.rate),\n temperature: spec.temperature ?? ambientC,\n on: false,\n }\n taps.set(id, t)\n if (spec.on ?? true) world.setTap(id, true)\n return id\n },\n\n setTap(id, on, rate) {\n const t = taps.get(id)\n if (!t) return\n if (rate !== undefined) t.rate = Math.max(0, rate)\n const changed = t.on !== on\n t.on = on\n syncTap(t)\n if (changed) emit({ type: 'tap', tap: id, on })\n },\n\n removeTap(id) {\n const t = taps.get(id)\n if (!t) return\n t.on = false\n syncTap(t)\n taps.delete(id)\n },\n\n taps: () => [...taps.values()].map((t) => ({ id: t.id, position: copy3(t.position), direction: copy3(t.direction), liquid: t.liquid, rate: t.rate, temperature: t.temperature, on: t.on, stream: t.stream })),\n\n removeContainer(id) {\n const c = containers.get(id)\n if (!c) return\n for (const key of Object.keys(c.streams)) endStreamKey(c, key)\n containers.delete(id)\n },\n\n setTransform(id, position, rotation, velocity) {\n const c = containers.get(id)\n if (!c) return\n c.position = copy3(position)\n c.rotation = [...rotation] as Quat\n if (velocity) c.velocity = copy3(velocity)\n refreshLevel(c)\n },\n\n open(id) {\n const c = containers.get(id)\n if (c) c.closed = false\n },\n\n close(id) {\n const c = containers.get(id)\n if (!c) return\n c.closed = true\n for (const key of ['pour', 'spill']) endStreamKey(c, key)\n c.pourTTL = 0\n },\n\n fill(id, liquid, liters, temperature) {\n const c = containers.get(id)\n if (!c || c.closed) return 0\n const accepted = fillInternal(c, liquid, liters, temperature, true)\n refreshLevel(c)\n return accepted\n },\n\n pour(id, dt, into) {\n const c = containers.get(id)\n const def = c ? defOf(c) : null\n if (!c || !def || c.closed || c.liters <= 1e-6 || !(dt > 0)) return 0\n refreshLevel(c)\n const lip = lipOf(c.spec.shape, c.spec.opening, c.u)\n const depth = Math.max(0, c.d - planeRange(c.cols, c.u)[0])\n const head = Math.max(c.d - lip.level, 0.02 + 0.5 * depth)\n const ro = lipRadius(c.spec.shape, c.spec.opening)\n const natural = 0.6 * Math.PI * ro * ro * Math.sqrt(2 * gravity * head) * 1000\n const rate = Math.min(natural, 0.15 + 12 * ro) * viscScale(def)\n const out = Math.min(rate * dt, c.liters)\n const target = into ? containers.get(into) : undefined\n let delivered = out\n if (target) {\n delivered = fillInternal(target, c.liquid as LiquidId, out, c.temperature, false)\n refreshLevel(target)\n const overflow = out - delivered\n if (overflow > 1e-6) {\n const flow = lipFlow(c, head)\n const hit = trace(landingSurfaces(), groundAt, flow.origin, flow.velocity, gravity)\n if (hit) deposit(c.liquid as LiquidId, hit, overflow, hit.velocity)\n }\n }\n removeLiters(c, out)\n c.pourRate = out / dt\n c.pourTTL = Math.max(0.12, dt * 1.5)\n c.pourVisual = !!target\n const flow = lipFlow(c, head)\n syncStream(c, 'pour', 'pour', c.pourRate, flow.origin, flow.velocity, c.pourVisual)\n refreshLevel(c)\n settle(c)\n return out\n },\n\n drink(id, liters) {\n const c = containers.get(id)\n const def = c ? defOf(c) : null\n if (!c || !def || c.closed || c.liters <= 1e-6 || !(liters > 0)) return null\n const amount = Math.min(liters, c.liters)\n removeLiters(c, amount)\n const event: Extract<FluidEvent, { type: 'drink' }> = {\n type: 'drink',\n container: c.id,\n liquid: def.id,\n liters: amount,\n temperature: c.temperature,\n thirst: (def.drink?.thirst ?? 0) * amount,\n effects: [...(def.drink?.effects ?? [])],\n burn: c.temperature > 65,\n }\n emit(event)\n refreshLevel(c)\n settle(c)\n return event\n },\n\n puncture(id, point, normal, diameter) {\n const c = containers.get(id)\n if (!c || !(diameter > 0) || c.holes.length >= MAX_HOLES) return\n c.holes.push({ point: copy3(point), normal: normalize(normal), diameter })\n },\n\n heat(id, deltaC) {\n const c = containers.get(id)\n if (c) c.temperature = clamp(c.temperature + deltaC, -50, 1000)\n },\n\n addSurface(spec) {\n const basis = makeBasis(spec.normal, spec.tangent)\n surfaces.set(spec.id, {\n ...clone(spec),\n ...basis,\n point: copy3(spec.point),\n half: [spec.halfSize[0], spec.halfSize[1]],\n })\n },\n\n removeSurface(id) {\n surfaces.delete(id)\n for (const s of [...stains.values()]) if (s.surface === id) stains.delete(s.id)\n },\n\n splash(liquid, point, liters, velocity, options) {\n if (!liquids.has(liquid) || !(liters > 0)) return\n const v: Vec3 = velocity ?? [0, -0.1, 0]\n const origin = add(point, [0, 0.02, 0])\n const hit = trace(landingSurfaces(), groundAt, origin, v, gravity)\n if (!hit) return\n emit({ type: 'splash', liquid, point: copy3(hit.point), intensity: clamp(0.3 + liters * 2, 0, 1) })\n deposit(liquid, hit, liters, length(v) > 0.3 ? hit.velocity : null, options?.tint)\n },\n\n clearStains(point, radius) {\n for (const s of [...stains.values()]) {\n if (distance(point, s.center) <= radius + 0.5 * meanRadius(s.front)) {\n stains.delete(s.id)\n emit({ type: 'dried', stain: s.id, mark: false })\n }\n }\n },\n\n update(dt) {\n if (dt > 0) {\n const n = clamp(Math.ceil(dt / MAX_STEP), 1, MAX_SUBSTEPS)\n updating = true\n try {\n for (let i = 0; i < n; i++) step(dt / n)\n } finally {\n updating = false\n }\n }\n const out = queue\n queue = []\n return out\n },\n\n container: (id) => {\n const c = containers.get(id)\n return c ? stateOf(c) : null\n },\n containers: () => [...containers.values()].map(stateOf),\n streams: () => [...streams.values()].map(streamView),\n stains: () => [...stains.values()].map(stainView),\n\n on(type, fn) {\n let set = listeners.get(type)\n if (!set) listeners.set(type, (set = new Set()))\n set.add(fn)\n return () => {\n set?.delete(fn)\n }\n },\n\n serialize() {\n const snapshot: Snapshot = {\n version: 1,\n time,\n rng: rng.state,\n counters: { ...counters },\n containers: [...containers.values()].map((c) => {\n const { cols: _cols, ...rest } = c\n return clone(rest)\n }),\n surfaces: [...surfaces.values()].map((s) => clone({ id: s.id, point: s.point, normal: s.normal, halfSize: s.half, tangent: s.t1, porosity: s.porosity })),\n streams: [...streams.values()].map((s) => clone(s)),\n taps: [...taps.values()].map((t) => clone(t)),\n stains: [...stains.values()].map((s) => clone(s)),\n }\n return snapshot\n },\n\n load(input) {\n const snap = clone(input) as Snapshot\n if (!snap || snap.version !== 1) throw new Error('game-fluids: unsupported snapshot')\n time = snap.time\n rng = new Rng(0)\n rng.state = snap.rng\n counters.container = snap.counters.container\n counters.stream = snap.counters.stream\n counters.stain = snap.counters.stain\n containers = new Map()\n for (const raw of snap.containers) containers.set(raw.id, { ...raw, cols: makeColumns(raw.spec.shape) })\n surfaces = new Map()\n for (const s of snap.surfaces) world.addSurface(s)\n counters.tap = snap.counters.tap ?? 0\n streams = new Map(snap.streams.map((s) => [s.id, s]))\n taps = new Map((snap.taps ?? []).map((t) => [t.id, t]))\n stains = new Map(snap.stains.map((s) => [s.id, s]))\n queue = []\n },\n }\n\n return world\n}\n","[\n {\n \"id\": \"sip\",\n \"duration\": 1.2,\n \"keys\": [\n {\n \"t\": 0,\n \"position\": [\n 0.22,\n -0.2,\n -0.4\n ],\n \"rotation\": [\n 0,\n 0,\n 0\n ],\n \"action\": \"none\"\n },\n {\n \"t\": 0.35,\n \"position\": [\n 0.0,\n 0.02,\n -0.2\n ],\n \"rotation\": [\n 0,\n 0,\n 0\n ],\n \"action\": \"none\"\n },\n {\n \"t\": 0.45,\n \"position\": [\n 0.0,\n 0.02,\n -0.2\n ],\n \"rotation\": [\n -0.9,\n 0,\n 0\n ],\n \"action\": \"drink\",\n \"rate\": 0.06\n },\n {\n \"t\": 0.95,\n \"position\": [\n 0.0,\n 0.02,\n -0.2\n ],\n \"rotation\": [\n -0.9,\n 0,\n 0\n ],\n \"action\": \"none\"\n },\n {\n \"t\": 1.2,\n \"position\": [\n 0.22,\n -0.2,\n -0.4\n ],\n \"rotation\": [\n 0,\n 0,\n 0\n ],\n \"action\": \"none\"\n }\n ]\n },\n {\n \"id\": \"drink\",\n \"duration\": 2.5,\n \"keys\": [\n {\n \"t\": 0,\n \"position\": [\n 0.22,\n -0.2,\n -0.4\n ],\n \"rotation\": [\n 0,\n 0,\n 0\n ],\n \"action\": \"none\"\n },\n {\n \"t\": 0.5,\n \"position\": [\n 0.0,\n 0.02,\n -0.2\n ],\n \"rotation\": [\n 0,\n 0,\n 0\n ],\n \"action\": \"none\"\n },\n {\n \"t\": 0.8,\n \"position\": [\n 0.0,\n 0.02,\n -0.2\n ],\n \"rotation\": [\n -1.22,\n 0,\n 0\n ],\n \"action\": \"drink\",\n \"rate\": 0.1667\n },\n {\n \"t\": 2.0,\n \"position\": [\n 0.0,\n 0.02,\n -0.2\n ],\n \"rotation\": [\n -1.22,\n 0,\n 0\n ],\n \"action\": \"none\"\n },\n {\n \"t\": 2.5,\n \"position\": [\n 0.22,\n -0.2,\n -0.4\n ],\n \"rotation\": [\n 0,\n 0,\n 0\n ],\n \"action\": \"none\"\n }\n ]\n },\n {\n \"id\": \"chug\",\n \"duration\": 4,\n \"keys\": [\n {\n \"t\": 0,\n \"position\": [\n 0.22,\n -0.2,\n -0.4\n ],\n \"rotation\": [\n 0,\n 0,\n 0\n ],\n \"action\": \"none\"\n },\n {\n \"t\": 0.5,\n \"position\": [\n 0.0,\n 0.02,\n -0.2\n ],\n \"rotation\": [\n 0,\n 0,\n 0\n ],\n \"action\": \"none\"\n },\n {\n \"t\": 0.9,\n \"position\": [\n 0.0,\n 0.02,\n -0.2\n ],\n \"rotation\": [\n -1.45,\n 0,\n 0\n ],\n \"action\": \"drink\",\n \"rate\": 0.2\n },\n {\n \"t\": 3.4,\n \"position\": [\n 0.0,\n 0.02,\n -0.2\n ],\n \"rotation\": [\n -1.45,\n 0,\n 0\n ],\n \"action\": \"none\"\n },\n {\n \"t\": 4,\n \"position\": [\n 0.22,\n -0.2,\n -0.4\n ],\n \"rotation\": [\n 0,\n 0,\n 0\n ],\n \"action\": \"none\"\n }\n ]\n },\n {\n \"id\": \"pour\",\n \"duration\": 3,\n \"keys\": [\n {\n \"t\": 0,\n \"position\": [\n 0.22,\n -0.2,\n -0.4\n ],\n \"rotation\": [\n 0,\n 0,\n 0\n ],\n \"action\": \"none\"\n },\n {\n \"t\": 0.4,\n \"position\": [\n 0.1,\n 0.0,\n -0.35\n ],\n \"rotation\": [\n 0,\n 0,\n 0\n ],\n \"action\": \"none\"\n },\n {\n \"t\": 0.8,\n \"position\": [\n 0.1,\n 0.0,\n -0.35\n ],\n \"rotation\": [\n -1.745,\n 0,\n 0\n ],\n \"action\": \"pour\",\n \"rate\": 1\n },\n {\n \"t\": 2.4,\n \"position\": [\n 0.1,\n 0.0,\n -0.35\n ],\n \"rotation\": [\n -1.745,\n 0,\n 0\n ],\n \"action\": \"none\"\n },\n {\n \"t\": 3,\n \"position\": [\n 0.22,\n -0.2,\n -0.4\n ],\n \"rotation\": [\n 0,\n 0,\n 0\n ],\n \"action\": \"none\"\n }\n ]\n },\n {\n \"id\": \"pour_out\",\n \"duration\": 4,\n \"keys\": [\n {\n \"t\": 0,\n \"position\": [\n 0.22,\n -0.2,\n -0.4\n ],\n \"rotation\": [\n 0,\n 0,\n 0\n ],\n \"action\": \"none\"\n },\n {\n \"t\": 0.5,\n \"position\": [\n 0.1,\n 0.1,\n -0.35\n ],\n \"rotation\": [\n 0,\n 0,\n 0\n ],\n \"action\": \"none\"\n },\n {\n \"t\": 1.0,\n \"position\": [\n 0.1,\n 0.1,\n -0.35\n ],\n \"rotation\": [\n -2.2,\n 0,\n 0\n ],\n \"action\": \"pour\",\n \"rate\": 40\n },\n {\n \"t\": 3.2,\n \"position\": [\n 0.1,\n 0.1,\n -0.35\n ],\n \"rotation\": [\n -2.2,\n 0,\n 0\n ],\n \"action\": \"none\"\n },\n {\n \"t\": 4,\n \"position\": [\n 0.22,\n -0.2,\n -0.4\n ],\n \"rotation\": [\n 0,\n 0,\n 0\n ],\n \"action\": \"none\"\n }\n ]\n },\n {\n \"id\": \"open\",\n \"duration\": 1,\n \"keys\": [\n {\n \"t\": 0,\n \"position\": [\n 0.22,\n -0.2,\n -0.4\n ],\n \"rotation\": [\n 0,\n 0,\n 0\n ],\n \"action\": \"none\"\n },\n {\n \"t\": 0.25,\n \"position\": [\n 0.1,\n 0,\n -0.3\n ],\n \"rotation\": [\n 0,\n 0,\n 0\n ],\n \"action\": \"open\"\n },\n {\n \"t\": 0.7,\n \"position\": [\n 0.1,\n 0,\n -0.3\n ],\n \"rotation\": [\n 0,\n 0,\n 0\n ],\n \"action\": \"none\"\n },\n {\n \"t\": 1,\n \"position\": [\n 0.22,\n -0.2,\n -0.4\n ],\n \"rotation\": [\n 0,\n 0,\n 0\n ],\n \"action\": \"none\"\n }\n ]\n },\n {\n \"id\": \"close\",\n \"duration\": 1,\n \"keys\": [\n {\n \"t\": 0,\n \"position\": [\n 0.22,\n -0.2,\n -0.4\n ],\n \"rotation\": [\n 0,\n 0,\n 0\n ],\n \"action\": \"none\"\n },\n {\n \"t\": 0.25,\n \"position\": [\n 0.1,\n 0,\n -0.3\n ],\n \"rotation\": [\n 0,\n 0,\n 0\n ],\n \"action\": \"close\"\n },\n {\n \"t\": 0.7,\n \"position\": [\n 0.1,\n 0,\n -0.3\n ],\n \"rotation\": [\n 0,\n 0,\n 0\n ],\n \"action\": \"none\"\n },\n {\n \"t\": 1,\n \"position\": [\n 0.22,\n -0.2,\n -0.4\n ],\n \"rotation\": [\n 0,\n 0,\n 0\n ],\n \"action\": \"none\"\n }\n ]\n }\n]","import itemUsesData from './data/item-uses.json'\nimport { lerp3, quatFromEuler, quatMultiply, quatRotate, add } from './math'\nimport type { FluidEvent, FluidWorld, ItemUseDef, ItemUsePlayer, Quat, Vec3 } from './types'\n\n/** Built-in scripted uses of a held item (data in `data/item-uses.json`): `sip`, `drink`, `chug`, `pour`, `pour_out`, `open`, `close`. */\nexport const ITEM_USES: ItemUseDef[] = itemUsesData as unknown as ItemUseDef[]\n\n/** World transform of the hand (or any holder) the item pose is relative to. */\nexport type HandTransform = () => { position: Vec3; rotation: Quat }\n\nconst DEFAULT_DRINK_RATE = 0.1\n\n/**\n * Plays an item use on a container: interpolates the keys, applies `drink` (rate × dt litres) and `pour` (`world.pour`, `rate` multiplies the\n * time) while the current key has that action, and fires `open` / `close` once when their key is reached. When `getHandTransform` is given, the\n * container's world transform follows hand ∘ pose every update; otherwise the host animates the viewmodel from `pose()`.\n */\nexport function createItemUse(world: FluidWorld, containerId: string, def: ItemUseDef, getHandTransform?: HandTransform): ItemUsePlayer {\n const keys = [...def.keys].sort((a, b) => a.t - b.t)\n let time = 0\n let done = keys.length === 0 || def.duration <= 0\n let checked = false\n let lastPos: Vec3 | null = null\n const fired = new Set<number>()\n\n const pose = (): { position: Vec3; rotation: Vec3 } => {\n if (keys.length === 0) return { position: [0, 0, 0], rotation: [0, 0, 0] }\n if (time <= keys[0].t) return { position: [...keys[0].position], rotation: [...keys[0].rotation] }\n for (let i = 0; i < keys.length - 1; i++) {\n const a = keys[i]\n const b = keys[i + 1]\n if (time <= b.t) {\n const k = b.t > a.t ? (time - a.t) / (b.t - a.t) : 1\n return { position: lerp3(a.position, b.position, k), rotation: lerp3(a.rotation, b.rotation, k) }\n }\n }\n const last = keys[keys.length - 1]\n return { position: [...last.position], rotation: [...last.rotation] }\n }\n\n const follow = (dt: number): void => {\n if (!getHandTransform) return\n const hand = getHandTransform()\n const p = pose()\n const position = add(hand.position, quatRotate(hand.rotation, p.position))\n const rotation = quatMultiply(hand.rotation, quatFromEuler(p.rotation[0], p.rotation[1], p.rotation[2]))\n const velocity: Vec3 | undefined =\n lastPos && dt > 0 ? [(position[0] - lastPos[0]) / dt, (position[1] - lastPos[1]) / dt, (position[2] - lastPos[2]) / dt] : undefined\n lastPos = position\n world.setTransform(containerId, position, rotation, velocity)\n }\n\n const player: ItemUsePlayer = {\n def,\n get time() {\n return time\n },\n get done() {\n return done\n },\n pose,\n update(dt) {\n if (done) return []\n const events: FluidEvent[] = []\n const off = world.on('*', (e) => events.push(e))\n try {\n if (!checked) {\n checked = true\n const state = world.container(containerId)\n if (!state || (def.liquids && def.liquids.length > 0 && (!state.liquid || !def.liquids.includes(state.liquid)))) {\n done = true\n return events\n }\n }\n const start = time\n const end = Math.min(def.duration, time + Math.max(0, dt))\n for (let i = 0; i < keys.length && !done; i++) {\n const key = keys[i]\n const spanStart = key.t\n const spanEnd = i + 1 < keys.length ? keys[i + 1].t : def.duration\n if ((key.action === 'open' || key.action === 'close') && !fired.has(i) && end >= spanStart) {\n fired.add(i)\n if (key.action === 'open') world.open(containerId)\n else world.close(containerId)\n }\n const overlap = Math.min(end, spanEnd) - Math.max(start, spanStart)\n if (overlap <= 0) continue\n if (key.action === 'drink') {\n const ev = world.drink(containerId, (key.rate ?? DEFAULT_DRINK_RATE) * overlap)\n const left = world.container(containerId)\n if (!ev || !left || left.liters <= 1e-6) {\n time = def.duration\n done = true\n }\n } else if (key.action === 'pour') {\n world.pour(containerId, overlap * (key.rate ?? 1))\n }\n }\n if (!done) {\n time = end\n done = time >= def.duration\n }\n follow(dt)\n } finally {\n off()\n }\n return events\n },\n cancel() {\n done = true\n },\n }\n return player\n}\n","import type { FilmField, FilmProfile, FilmRandom } from './types'\n\nexport interface DepositContext {\n readonly field: FilmField\n readonly random: FilmRandom\n readonly profile: () => FilmProfile\n}\n\nconst VISIBLE_THICKNESS = 0.035\n\nexport function depositCell(context: DepositContext, rowIn: number, columnIn: number, amount: number): void {\n const { field } = context\n const row = Math.round(rowIn)\n const column = Math.round(columnIn)\n if (row < 0 || column < 0 || row >= field.height || column >= field.width || !(amount > 0)) return\n const index = row * field.width + column\n field.thickness[index]! += amount\n if (amount > 0.02) field.dryness[index]! *= 0.15\n field.dampness[index] = 1\n}\n\nexport function wetCellCount(field: FilmField): number {\n let cells = 0\n for (let index = 0; index < field.thickness.length; index++) if (field.thickness[index]! > VISIBLE_THICKNESS) cells++\n return cells\n}\n\n/** A filled ellipse with a noisy outline; `along` runs along (directionColumn, directionRow) and `across` is the other half axis, `amount` is the thickness at the centre in mm. */\nexport function depositBlob(context: DepositContext, centerRow: number, centerColumn: number, along: number, across: number, directionColumn: number, directionRow: number, amount: number, roughness: number): void {\n const random = context.random\n const phaseA = random() * 6.28\n const phaseB = random() * 6.28\n const phaseC = random() * 6.28\n const phaseD = random() * 6.28\n const reach = Math.ceil(Math.max(along, across) * (1 + roughness) + 1.5)\n for (let row = Math.floor(centerRow - reach); row <= centerRow + reach; row++) {\n for (let column = Math.floor(centerColumn - reach); column <= centerColumn + reach; column++) {\n const dx = column + 0.5 - centerColumn\n const dy = row + 0.5 - centerRow\n const alongDistance = dx * directionColumn + dy * directionRow\n const acrossDistance = -dx * directionRow + dy * directionColumn\n const angle = Math.atan2(acrossDistance / across, alongDistance / along)\n const edge = 1 + roughness * (0.45 * Math.sin(3 * angle + phaseA) + 0.3 * Math.sin(5 * angle + phaseB) + 0.18 * Math.sin(8 * angle + phaseC) + 0.12 * Math.sin(13 * angle + phaseD))\n const squared = ((alongDistance / along) * (alongDistance / along) + (acrossDistance / across) * (acrossDistance / across)) / (edge * edge)\n if (squared < 1) depositCell(context, row, column, amount * Math.sqrt(1 - squared))\n }\n }\n}\n\n/** A tapered stroke from one cell to another. */\nexport function depositStroke(context: DepositContext, fromRow: number, fromColumn: number, toRow: number, toColumn: number, startWidth: number, endWidth: number, amount: number): void {\n const { field } = context\n const length = Math.hypot(toRow - fromRow, toColumn - fromColumn)\n const samples = Math.max(2, Math.ceil(length * 2.5))\n for (let sample = 0; sample <= samples; sample++) {\n const progress = sample / samples\n const row = fromRow + (toRow - fromRow) * progress\n const column = fromColumn + (toColumn - fromColumn) * progress\n const width = startWidth + (endWidth - startWidth) * progress\n const reach = Math.ceil(width + 1)\n for (let cellRow = Math.floor(row - reach); cellRow <= row + reach; cellRow++) {\n for (let cellColumn = Math.floor(column - reach); cellColumn <= column + reach; cellColumn++) {\n if (cellRow < 0 || cellColumn < 0 || cellRow >= field.height || cellColumn >= field.width) continue\n const distance = Math.hypot(cellRow + 0.5 - row, cellColumn + 0.5 - column)\n if (distance >= width) continue\n const index = cellRow * field.width + cellColumn\n const target = amount * (1 - distance / width) * 0.5\n if (field.thickness[index]! < target) depositCell(context, cellRow, cellColumn, target - field.thickness[index]!)\n }\n }\n }\n}\n\n/**\n * The impact: the body is stretched by 1 / sin(angle), with spikes (long only along the travel), satellites and tails.\n * `size` is the radius in cells of the main body; `profile.spikes` below 1 turns the spikes short and the blobs thick.\n */\nexport function depositSplat(context: DepositContext, row: number, column: number, size: number, directionColumn: number, directionRow: number, sinAngleIn: number, amount: number): void {\n const random = context.random\n const spikes = context.profile().spikes\n const sinAngle = Math.max(0.17, Math.min(1, sinAngleIn))\n const stretch = Math.min(5.5, 1 / sinAngle)\n const along = size * Math.pow(stretch, 0.75)\n const across = size / Math.pow(stretch, 0.25)\n const frontRow = row + directionRow * along * 0.25\n const frontColumn = column + directionColumn * along * 0.25\n depositBlob(context, frontRow, frontColumn, along, across, directionColumn, directionRow, amount, 0.1 + 0.12 * (1 - sinAngle) + (size < 1.4 ? 0 : 0.06))\n const sideColumn = -directionRow\n const sideRow = directionColumn\n const spikeCount = Math.round(Math.min(18, (size < 1.2 ? 1 : 4) + size * 1.6 + 5 * (1 - sinAngle)) * spikes)\n for (let spike = 0; spike < spikeCount; spike++) {\n const spread = Math.PI * (0.25 + 0.75 * sinAngle * sinAngle)\n let theta = (random() * 2 - 1) * spread\n if (sinAngle > 0.9) theta = random() * 6.283\n const cosine = Math.cos(theta)\n const sine = Math.sin(theta)\n const dx = cosine * directionColumn + sine * sideColumn\n const dy = cosine * directionRow + sine * sideRow\n const length = size * (0.25 + random() * 0.55) * (1 + 2.6 * (1 - sinAngle) * Math.max(0, cosine)) * (sinAngle > 0.9 ? 0.6 : 1) * (0.5 + 0.5 * spikes)\n const startRow = frontRow + (along * cosine * directionRow + across * sine * sideRow) * 0.75\n const startColumn = frontColumn + (along * cosine * directionColumn + across * sine * sideColumn) * 0.75\n const endRow = startRow + dy * length\n const endColumn = startColumn + dx * length\n depositStroke(context, startRow, startColumn, endRow, endColumn, Math.max(0.55, size * 0.22), 0.42, amount * 0.75)\n if (random() < 0.5) {\n const gap = 1 + random() * 2.2\n depositBlob(context, endRow + dy * gap, endColumn + dx * gap, 0.55 + random() * 0.7, 0.5 + random() * 0.4, dx, dy, amount * 0.55, 0.08)\n }\n }\n const satelliteCount = Math.round((1 + size * 0.9) * (1.4 - sinAngle * 0.6) * (0.5 + 0.5 * spikes))\n for (let satellite = 0; satellite < satelliteCount; satellite++) {\n const cone = sinAngle > 0.9 ? Math.PI : 0.18 + 0.6 * sinAngle\n const theta = (random() * 2 - 1) * cone\n const cosine = Math.cos(theta)\n const sine = Math.sin(theta)\n const dx = cosine * directionColumn + sine * sideColumn\n const dy = cosine * directionRow + sine * sideRow\n const distance = along + size * (0.8 + random() * 3.2)\n const radius = 0.45 + random() * Math.min(1.2, size * 0.22)\n const satelliteRow = frontRow + dy * distance\n const satelliteColumn = frontColumn + dx * distance\n depositBlob(context, satelliteRow, satelliteColumn, radius * Math.sqrt(stretch), radius, dx, dy, amount * 0.6, 0.08)\n if (sinAngle < 0.8) depositStroke(context, satelliteRow + dy * radius * stretch * 0.7, satelliteColumn + dx * radius * stretch * 0.7, satelliteRow + dy * radius * stretch * 1.8, satelliteColumn + dx * radius * stretch * 1.8, 0.5, 0.3, amount * 0.35)\n }\n}\n","import type { Vec3 } from '../types'\nimport { depositBlob, depositSplat } from './deposit'\nimport type { DepositContext } from './deposit'\nimport type { FilmDropState, FilmLayout } from './types'\n\nconst GRAVITY = 9.8\nconst AIR_DRAG = 0.25\nconst MIN_SIZE_CELLS = 0.6\n\nexport interface DropPool {\n readonly state: FilmDropState\n launch(position: Vec3, velocity: Vec3, radius: number): void\n update(dt: number): void\n clear(): void\n}\n\n/** Drops in flight: a ring of slots (the oldest is overwritten), a ballistic flight and a landing that makes an impact shaped by the angle and direction (F250-278). */\nexport function createDropPool(layout: FilmLayout, context: DepositContext): DropPool {\n const capacity = layout.rules.dropCapacity\n let cursor = 0\n const state: FilmDropState = {\n capacity,\n get launched() {\n return cursor\n },\n active: new Uint8Array(capacity),\n position: new Float64Array(capacity * 3),\n velocity: new Float64Array(capacity * 3),\n radius: new Float64Array(capacity),\n }\n const { active, position, velocity, radius } = state\n const cellMillimetres = layout.cellSize * 1000\n const previous: Vec3 = [0, 0, 0]\n const point: Vec3 = [0, 0, 0]\n const speed: Vec3 = [0, 0, 0]\n\n function land(region: number, dropRadius: number): void {\n const profile = context.profile()\n const impact = layout.impact(region, point, speed)\n const [alongColumn, alongRow] = impact.along\n const travel = Math.hypot(alongColumn, alongRow) || 1e-6\n const sinAngle = Math.abs(impact.normalSpeed) / Math.hypot(travel, impact.normalSpeed)\n const volume = ((4 / 3) * Math.PI * dropRadius * dropRadius * dropRadius) / (cellMillimetres * cellMillimetres) * (dropRadius > 3 ? 7 : 4) * profile.volume\n const totalSpeed = Math.sqrt(speed[0] * speed[0] + speed[1] * speed[1] + speed[2] * speed[2])\n const size = Math.max(MIN_SIZE_CELLS, (dropRadius * 2) / cellMillimetres * (1 + 0.2 * totalSpeed))\n const amount = Math.min(profile.maxAmount, Math.max(0.25, volume / ((Math.PI * size * size * 1.6) / (sinAngle < 0.3 ? 0.6 : 1))))\n if (profile.landsAsBlob) {\n depositBlob(context, impact.row, impact.column, size * 1.3, size * 1.1, alongColumn / travel, alongRow / travel, amount, 0.2)\n return\n }\n depositSplat(context, impact.row, impact.column, size, alongColumn / travel, alongRow / travel, sinAngle, amount)\n }\n\n return {\n state,\n launch(origin, direction, dropRadius) {\n const slot = cursor++ % capacity\n const offset = slot * 3\n active[slot] = 1\n position[offset] = origin[0]\n position[offset + 1] = origin[1]\n position[offset + 2] = origin[2]\n velocity[offset] = direction[0]\n velocity[offset + 1] = direction[1]\n velocity[offset + 2] = direction[2]\n radius[slot] = dropRadius\n },\n update(dt) {\n for (let slot = 0; slot < capacity; slot++) {\n if (!active[slot]) continue\n const offset = slot * 3\n previous[0] = position[offset]!\n previous[1] = position[offset + 1]!\n previous[2] = position[offset + 2]!\n velocity[offset + 1]! -= GRAVITY * dt\n const drag = 1 - dt * AIR_DRAG\n velocity[offset]! *= drag\n velocity[offset + 1]! *= drag\n velocity[offset + 2]! *= drag\n point[0] = position[offset]! + velocity[offset]! * dt\n point[1] = position[offset + 1]! + velocity[offset + 1]! * dt\n point[2] = position[offset + 2]! + velocity[offset + 2]! * dt\n const region = layout.collide(previous, point)\n position[offset] = point[0]\n position[offset + 1] = point[1]\n position[offset + 2] = point[2]\n if (region >= 0) {\n if (layout.contains(point)) {\n speed[0] = velocity[offset]!\n speed[1] = velocity[offset + 1]!\n speed[2] = velocity[offset + 2]!\n land(region, radius[slot]!)\n }\n active[slot] = 0\n continue\n }\n if (layout.escaped(point)) active[slot] = 0\n }\n },\n clear() {\n active.fill(0)\n },\n }\n}\n","import type { FilmAdvanceInput, FilmBounds, FilmField, FilmLayout, FilmProfile, FilmSimulator, FilmWeather } from './types'\n\nexport interface CpuSimulatorOptions {\n /** Flow steps per second of real time (the pages use 180). */\n stepRate: number\n /** Most flow steps in one advance (6 in the Fluid Standard, 9 in the Workshop). */\n maxSteps: number\n weather: () => FilmWeather\n}\n\nconst RAIN_SPREAD = 0.5\nconst BOUNDS_MARGIN = 8\n\n/**\n * The thin-film step of the Fluid Standard (F94-114), literal: only film above the pin moves, a dry cell needs the front thickness,\n * walls run sideways at 0.22 and the flow is limited to the wet bounding box. Drying starts from the thin edge.\n */\nexport function createCpuSimulator(field: FilmField, layout: FilmLayout, profileOf: () => FilmProfile, options: CpuSimulatorOptions): FilmSimulator {\n const { width, height, thickness, dryness, dampness } = field\n const { bed, pin: pinning, vertical } = layout\n const delta = new Float32Array(width * height)\n const bounds: FilmBounds = { firstRow: 0, lastRow: -1, firstColumn: 0, lastColumn: -1 }\n let accumulated = 0\n\n function refreshBounds(): void {\n let firstRow = height\n let lastRow = -1\n let firstColumn = width\n let lastColumn = -1\n for (let row = 0; row < height; row++) {\n const offset = row * width\n let isWet = false\n for (let column = 0; column < width; column++) {\n if (thickness[offset + column]! > 0) {\n isWet = true\n if (column < firstColumn) firstColumn = column\n if (column > lastColumn) lastColumn = column\n }\n }\n if (isWet) {\n if (row < firstRow) firstRow = row\n lastRow = row\n }\n }\n if (lastRow < 0) {\n bounds.firstRow = 0\n bounds.lastRow = -1\n bounds.firstColumn = 0\n bounds.lastColumn = -1\n return\n }\n bounds.firstRow = Math.max(0, firstRow - BOUNDS_MARGIN)\n bounds.lastRow = Math.min(height - 1, lastRow + BOUNDS_MARGIN)\n bounds.firstColumn = Math.max(0, firstColumn - BOUNDS_MARGIN)\n bounds.lastColumn = Math.min(width - 1, lastColumn + BOUNDS_MARGIN)\n }\n\n const mobility = (index: number): number => {\n const dry = dryness[index]!\n return dry < 0.25 ? 1 : dry > 0.6 ? 0 : 1 - (dry - 0.25) / 0.35\n }\n\n function flowStep(): void {\n const { firstRow, lastRow, firstColumn, lastColumn } = bounds\n if (lastRow < 0) return\n const profile = profileOf()\n const flow = profile.flow * (1 + RAIN_SPREAD * options.weather().rain)\n const referenceSquared = profile.referenceThickness * profile.referenceThickness\n const slopeCap = profile.slopeCap\n const pinLevel = profile.pin\n const front = profile.front\n for (let row = firstRow; row <= lastRow; row++) {\n const offset = row * width\n for (let column = firstColumn; column <= lastColumn; column++) delta[offset + column] = 0\n }\n for (let row = firstRow; row <= lastRow; row++) {\n const offset = row * width\n for (let column = firstColumn; column <= lastColumn; column++) {\n const index = offset + column\n const own = thickness[index]!\n for (let edge = 0; edge < 2; edge++) {\n let neighbour: number\n if (edge === 0) {\n if (column >= lastColumn) continue\n neighbour = index + 1\n } else {\n if (row >= lastRow) continue\n neighbour = index + width\n }\n const other = thickness[neighbour]!\n if (own < 0.005 && other < 0.005) continue\n let bedDrop = bed[index]! - bed[neighbour]!\n if (bedDrop > slopeCap) bedDrop = slopeCap\n else if (bedDrop < -slopeCap) bedDrop = -slopeCap\n let head = bedDrop + own - other\n let source = index\n let destination = neighbour\n if (head < 0) {\n head = -head\n source = neighbour\n destination = index\n }\n const sourceThickness = thickness[source]!\n const verticalFactor = vertical[source]!\n const pinThreshold = pinLevel * pinning[source]! * (verticalFactor < 1 ? 0.5 : 1)\n if (sourceThickness <= pinThreshold) continue\n if (thickness[destination]! < 0.03 && sourceThickness < front * pinning[source]! * verticalFactor) continue\n const mobile = mobility(source)\n if (mobile <= 0) continue\n let moved = flow * mobile * ((sourceThickness * sourceThickness) / (sourceThickness * sourceThickness + referenceSquared)) * head * (verticalFactor < 1 ? (edge === 0 ? 0.22 : 1) : 4)\n const limit = (sourceThickness - pinThreshold) * 0.24\n if (moved > limit) moved = limit\n delta[source]! -= moved\n delta[destination]! += moved\n }\n }\n }\n for (let row = firstRow; row <= lastRow; row++) {\n const offset = row * width\n for (let column = firstColumn; column <= lastColumn; column++) {\n const index = offset + column\n let next = thickness[index]! + delta[index]!\n if (next < 1e-4) next = 0\n else dampness[index] = 1\n thickness[index] = next\n }\n }\n }\n\n function age(dryingSeconds: number): void {\n const { firstRow, lastRow, firstColumn, lastColumn } = bounds\n if (lastRow < 0) return\n const profile = profileOf()\n const rainScale = 1 - options.weather().rain\n const seconds = dryingSeconds * rainScale * (options.weather().drying ?? 1)\n for (let row = firstRow; row <= lastRow; row++) {\n const offset = row * width\n for (let column = firstColumn; column <= lastColumn; column++) {\n const index = offset + column\n const own = thickness[index]!\n if (own > 0) {\n const thin = 1 - Math.min(1, own / 1.6)\n if (profile.dryTime > 0 && dryness[index]! < 1) dryness[index] = Math.min(1, dryness[index]! + (seconds / profile.dryTime) * (0.45 + 1.7 * thin))\n if (profile.evaporation > 0) {\n const next = own - profile.evaporation * seconds * (0.5 + 1.5 * thin)\n thickness[index] = next > 0.004 ? next : 0\n }\n } else if (dampness[index]! > 0) {\n dampness[index] = Math.max(0, dampness[index]! - seconds / (profile.evaporation > 0 ? 25 : 1e9))\n }\n }\n }\n }\n\n return {\n bounds,\n refreshBounds,\n advance({ dt, dryingSeconds }: FilmAdvanceInput): number {\n accumulated += dt\n let steps = 0\n refreshBounds()\n while (accumulated >= 1 / options.stepRate && steps < options.maxSteps) {\n flowStep()\n accumulated -= 1 / options.stepRate\n steps++\n }\n if (steps === options.maxSteps) accumulated = 0\n age(dryingSeconds)\n return steps\n },\n resetClock() {\n accumulated = 0\n },\n }\n}\n","import type { Vec3 } from '../types'\nimport { depositCell } from './deposit'\nimport type { DepositContext } from './deposit'\nimport type { FilmBead, FilmDrag, FilmDrip, FilmLayout, FilmRandom, FilmSource } from './types'\n\ntype Launch = (position: Vec3, velocity: Vec3, radius: number) => void\n\nconst range = (random: FilmRandom, from: number, to: number): number => from + random() * (to - from)\n\n/** The drip (F282, W-style): a bead swells at the fingertip, detaches and falls. Updates `bead` for the renderer and returns nothing. */\nexport function updateDrip(drip: FilmDrip | undefined, bead: FilmBead, layout: FilmLayout, random: FilmRandom, launch: Launch, dt: number): void {\n if (!drip) {\n bead.visible = false\n return\n }\n drip.elapsed += dt\n const swell = Math.min(1, drip.elapsed / drip.every)\n const radius = drip.radius * (0.35 + 0.65 * swell)\n const isWorkshop = layout.rules.dripStyle === 'workshop'\n bead.visible = true\n bead.swell = swell\n bead.radius = radius\n bead.position[0] = drip.position[0]\n bead.position[1] = drip.position[1] + (isWorkshop ? -radius * 0.0012 * (1 + swell * 0.7) : -radius * 0.0012)\n bead.position[2] = drip.position[2]\n if (drip.elapsed < drip.every) return\n const origin: Vec3 = [bead.position[0], bead.position[1] + -radius * 0.001, bead.position[2]]\n if (isWorkshop) {\n const sideX = range(random, -0.025, 0.025)\n const sideZ = range(random, -0.025, 0.025)\n launch(origin, [sideX, -0.2, sideZ], drip.radius * range(random, 0.85, 1.15))\n drip.elapsed = 0\n drip.every = drip.base * range(random, 0.75, 1.25)\n return\n }\n const sideX = (random() - 0.5) * 0.05\n const sideZ = (random() - 0.5) * 0.05\n launch(origin, [sideX, -0.2, sideZ], drip.radius * (0.85 + random() * 0.3))\n drip.elapsed = 0\n drip.every = drip.base * (0.75 + random() * 0.5)\n}\n\n/** Continuous sources (a wound at the feet, a tipped can): a pulsing thickness added over a small disc (F288). */\nexport function updateSources(sources: readonly FilmSource[], context: DepositContext, dt: number): void {\n const random = context.random\n for (const source of sources) {\n source.elapsed += dt\n if (source.elapsed < 0 || source.elapsed > source.duration) continue\n const pulse = 0.6 + 0.4 * Math.max(0, Math.sin(source.elapsed * 5.2))\n const amount = source.rate * dt * pulse\n for (let part = 0; part < 3; part++) {\n const angle = random() * 6.28\n const distance = random() * source.radius\n depositCell(context, source.row + Math.sin(angle) * distance, source.column + Math.cos(angle) * distance, amount / 3)\n }\n }\n}\n\n/** Drag smears (F291): a striped band that loses load and crumbles at the end, with side drops stretched along the travel. */\nexport function updateDrags(drags: readonly FilmDrag[], context: DepositContext, layout: FilmLayout, launch: Launch, dt: number): void {\n const random = context.random\n for (const drag of drags) {\n if (drag.done) continue\n drag.elapsed += dt\n const progress = Math.min(1, drag.elapsed / drag.duration)\n const here = drag.path(progress)\n const ahead = drag.path(Math.min(1, progress + 0.01))\n let directionColumn = ahead.column - here.column\n let directionRow = ahead.row - here.row\n const length = Math.hypot(directionColumn, directionRow) || 1\n directionColumn /= length\n directionRow /= length\n const sideColumn = -directionRow\n const sideRow = directionColumn\n const load = Math.pow(1 - progress, 1.3)\n for (let offset = -drag.width; offset <= drag.width; offset += 0.5) {\n const across = offset / drag.width\n const stripe = drag.stripes[Math.round((offset + drag.width) * 2)]!\n const edge = 1 - across * across\n const amount = drag.amount * load * (0.25 + 0.75 * stripe) * edge\n if (load < 0.45 && random() > load * 2.2) continue\n depositCell(context, Math.round(here.row + sideRow * offset), Math.round(here.column + sideColumn * offset), amount * dt * 30)\n }\n if (drag.hand && random() < dt * 14 * load + 0.02) {\n const world = layout.cellToWorld(here.row, here.column)\n const origin: Vec3 = [world[0] + (random() - 0.5) * 0.06, drag.hand.height + random() * 0.3, world[2] + (random() - 0.5) * 0.06]\n const velocity: Vec3 = [directionColumn * drag.hand.speed, 0 * drag.hand.speed, directionRow * drag.hand.speed]\n velocity[0] += (random() - 0.5) * 0.3\n velocity[1] += 0.2\n velocity[2] += (random() - 0.5) * 0.3\n launch(origin, velocity, 2 + random() * 2.2)\n }\n if (progress >= 1) drag.done = true\n }\n}\n","import { depositBlob, depositCell, depositSplat, depositStroke, wetCellCount } from './deposit'\nimport type { DepositContext } from './deposit'\nimport { createDropPool } from './drops'\nimport { createCpuSimulator } from './simulate'\nimport { updateDrags, updateDrip, updateSources } from './sources'\nimport type { Film, FilmField, FilmOptions, FilmProfile, FilmWeather } from './types'\n\nconst DEFAULT_STEP_RATE = 180\nconst DEFAULT_MAX_STEPS = 6\n/** The visor's `ZG.wipe`: rain removes only the stain that is less than half dry. */\nconst WASH_BELOW_DRYNESS = 0.5\n\n/**\n * A running film of one liquid over one layout: drops land as impacts, a drip, sources and drag smears add to it, and a 180 Hz\n * thin-film step spreads it limited to the wet box, at most `maxSteps` per frame. It never calls `Math.random`: the host gives the random stream.\n */\nexport function createFilm(options: FilmOptions): Film {\n const { layout, random } = options\n const cellCount = layout.width * layout.height\n const field: FilmField = {\n width: layout.width,\n height: layout.height,\n thickness: new Float32Array(cellCount),\n dryness: new Float32Array(cellCount),\n dampness: new Float32Array(cellCount),\n }\n let weatherState: FilmWeather = { rain: 0, drying: 1 }\n let currentProfile: FilmProfile = options.profile\n const context: DepositContext = { field, random, profile: () => currentProfile }\n const drops = createDropPool(layout, context)\n const createSimulator = options.simulator ?? createCpuSimulator\n const simulator = createSimulator(field, layout, () => currentProfile, {\n stepRate: options.stepRate ?? DEFAULT_STEP_RATE,\n maxSteps: options.maxSteps ?? DEFAULT_MAX_STEPS,\n weather: () => weatherState,\n })\n\n const film: Film = {\n layout,\n field,\n drops: drops.state,\n bead: { visible: false, position: [0, 0, 0], radius: 0, swell: 0 },\n simulator,\n get profile() {\n return currentProfile\n },\n set profile(profile: FilmProfile) {\n currentProfile = profile\n },\n drip: undefined,\n sources: [],\n drags: [],\n launch: (position, velocity, radius) => drops.launch(position, velocity, radius),\n splat: (row, column, size, directionColumn, directionRow, sinAngle, amount) => depositSplat(context, row, column, size, directionColumn, directionRow, sinAngle, amount),\n blob: (row, column, along, across, directionColumn, directionRow, amount, roughness) => depositBlob(context, row, column, along, across, directionColumn, directionRow, amount, roughness),\n stroke: (fromRow, fromColumn, toRow, toColumn, startWidth, endWidth, amount) => depositStroke(context, fromRow, fromColumn, toRow, toColumn, startWidth, endWidth, amount),\n deposit: (row, column, amount) => depositCell(context, row, column, amount),\n update({ dt, dryingSeconds }) {\n drops.update(dt)\n updateDrip(film.drip, film.bead, layout, random, drops.launch, dt)\n updateSources(film.sources, context, dt)\n updateDrags(film.drags, context, layout, drops.launch, dt)\n simulator.advance({ dt, dryingSeconds })\n },\n setWeather(weather) {\n weatherState = {\n rain: Math.min(1, Math.max(0, weather.rain ?? weatherState.rain)),\n drying: Math.max(0, weather.drying ?? weatherState.drying ?? 1),\n }\n },\n weather: () => ({ ...weatherState }),\n wash(maxDryness = WASH_BELOW_DRYNESS) {\n simulator.refreshBounds()\n const { firstRow, lastRow, firstColumn, lastColumn } = simulator.bounds\n let cleared = 0\n for (let row = firstRow; row <= lastRow; row++) {\n for (let column = firstColumn; column <= lastColumn; column++) {\n const index = row * layout.width + column\n if (field.thickness[index]! > 0 && field.dryness[index]! < maxDryness) {\n field.thickness[index] = 0\n field.dryness[index] = 0\n field.dampness[index] = 0\n cleared++\n }\n }\n }\n // the bounds shrink on the next advance, which the grid's upload rectangle (union with the previous one) already covers\n return cleared\n },\n clear() {\n field.thickness.fill(0)\n field.dryness.fill(0)\n field.dampness.fill(0)\n drops.clear()\n film.drip = undefined\n film.bead.visible = false\n film.sources.length = 0\n film.drags.length = 0\n simulator.refreshBounds()\n },\n wetCells: () => wetCellCount(field),\n }\n return film\n}\n","import type { FilmRandom } from './types'\n\nexport type FilmLcg = FilmRandom & { seed: number }\n\n/** The Fluid Standard's generator (LCG 1664525 / 1013904223). `seed` can be read and set, so a scene can be restarted from a number. */\nexport function createFilmLcg(seed: number): FilmLcg {\n const lcg = (() => {\n lcg.seed = (lcg.seed * 1664525 + 1013904223) >>> 0\n return lcg.seed / 4294967296\n }) as FilmLcg\n lcg.seed = seed >>> 0\n return lcg\n}\n","// The product is taken in doubles on purpose (not `Math.imul`): the recorded pages round it the same way, and the grids depend on it.\nexport function hashCell(x: number, y: number): number {\n let value = (x * 374761393 + y * 668265263) | 0\n value = ((value ^ (value >>> 13)) * 1274126177) | 0\n return ((value ^ (value >>> 16)) >>> 0) / 4294967296\n}\n\nexport function valueNoise(x: number, y: number): number {\n const xi = Math.floor(x)\n const yi = Math.floor(y)\n const xf = x - xi\n const yf = y - yi\n const u = xf * xf * (3 - 2 * xf)\n const v = yf * yf * (3 - 2 * yf)\n const a = hashCell(xi, yi)\n const b = hashCell(xi + 1, yi)\n const c = hashCell(xi, yi + 1)\n const d = hashCell(xi + 1, yi + 1)\n return a + (b - a) * u + (c - a) * v + (a - b - c + d) * u * v\n}\n","import type { Vec3 } from '../types'\nimport { hashCell, valueNoise } from './noise'\nimport type { FilmImpact, FilmLayout, FilmRegion, FilmRules } from './types'\n\nexport interface FoldedLayoutParams {\n id: string\n columns: number\n /** Metres per cell. */\n cellSize: number\n /** World x of the left edge. */\n originX: number\n wallRows: number\n sidewalkRows: number\n curbRows: number\n roadRows: number\n /** World y of the top of the wall strip and of the sidewalk and road planes. */\n wallTopY: number\n sidewalkY: number\n roadY: number\n /** World z of the wall plane (the sidewalk starts here and runs towards +z). */\n wallZ: number\n /** Metres the curb face drops per row. Default `(sidewalkY - roadY) / curbRows`. */\n curbStep?: number\n /** x that the road's cross slope is measured from (the road falls `5 mm / m` towards +x from here). */\n roadSlopeAnchorX: number\n rules: FilmRules\n}\n\nconst REGION_NAMES = ['wall', 'sidewalk', 'curb', 'road'] as const\n\nconst dot3 = (a: Vec3, b: Vec3): number => a[0] * b[0] + a[1] * b[1] + a[2] * b[2]\n\nfunction impactOf(region: FilmRegion, position: Vec3, velocity: Vec3, cellSize: number): FilmImpact {\n const local: Vec3 = [position[0] - region.origin[0], position[1] - region.origin[1], position[2] - region.origin[2]]\n return {\n row: region.firstRow + dot3(local, region.rowAxis) / cellSize,\n column: dot3(local, region.columnAxis) / cellSize,\n along: [dot3(velocity, region.columnAxis), dot3(velocity, region.rowAxis)],\n normalSpeed: -dot3(velocity, region.normal),\n }\n}\n\nfunction cellToWorldOf(regions: readonly FilmRegion[], cellSize: number, row: number, column: number): Vec3 {\n let region = regions[regions.length - 1]!\n for (const candidate of regions) {\n if (row < candidate.firstRow + candidate.rowCount) {\n region = candidate\n break\n }\n }\n const across = column * cellSize\n const down = (row - region.firstRow) * cellSize\n return [\n region.origin[0] + region.columnAxis[0] * across + region.rowAxis[0] * down,\n region.origin[1] + region.columnAxis[1] * across + region.rowAxis[1] * down,\n region.origin[2] + region.columnAxis[2] * across + region.rowAxis[2] * down,\n ]\n}\n\n/**\n * One strip folded over a wall, the sidewalk in front of it, the curb face and the road: the Fluid Standard's grid (F12-42) and the\n * Workshop's (W562-582) are two settings of it. Bed height (mm), pinning noise and the vertical flag are filled per cell.\n */\nexport function createFoldedLayout(params: FoldedLayoutParams): FilmLayout {\n const { columns, cellSize, originX, wallRows, sidewalkRows, curbRows, roadRows, wallTopY, sidewalkY, roadY, wallZ, rules } = params\n const curbStep = params.curbStep ?? (sidewalkY - roadY) / curbRows\n const height = wallRows + sidewalkRows + curbRows + roadRows\n const cellCount = columns * height\n const bed = new Float32Array(cellCount)\n const pin = new Float32Array(cellCount)\n const vertical = new Float32Array(cellCount)\n const sidewalkEnd = wallRows + sidewalkRows\n const curbEnd = sidewalkEnd + curbRows\n const regionOfRow = (row: number): number => (row < wallRows ? 0 : row < sidewalkEnd ? 1 : row < curbEnd ? 2 : 3)\n\n for (let row = 0; row < height; row++) {\n for (let column = 0; column < columns; column++) {\n const index = row * columns + column\n const region = regionOfRow(row)\n const x = originX + (column + 0.5) * cellSize\n let bedHeight: number\n let roughness = 0.2\n if (region === 0) {\n bedHeight = (wallTopY - (row + 0.5) * cellSize) * 1000\n roughness = 0.3\n } else if (region === 1) {\n const z = (row - wallRows + 0.5) * cellSize\n bedHeight = sidewalkY * 1000 - z * 6\n const jointX = Math.abs((((x - originX) % 0.5) + 0.5) % 0.5 - 0.25)\n const jointZ = Math.abs(((z % 0.5) + 0.5) % 0.5 - 0.25)\n if (jointX > 0.25 - cellSize * 0.6 || jointZ > 0.25 - cellSize * 0.6) bedHeight -= 0.9\n roughness = 0.18\n } else if (region === 2) {\n bedHeight = sidewalkY * 1000 - (row - sidewalkEnd + 0.5) * curbStep * 1000\n } else {\n const z = (row - curbEnd + 0.5) * cellSize\n bedHeight = roadY * 1000 + z * 14 - (x - params.roadSlopeAnchorX) * 5\n roughness = 0.55\n }\n const noise = valueNoise(column * 0.35, row * 0.35) * 0.6 + valueNoise(column * 1.3, row * 1.3) * 0.4\n bed[index] = bedHeight + (noise - 0.5) * roughness * 2\n vertical[index] = region === 0 || region === 2 ? 0.95 : 1\n pin[index] = 0.62 + 0.76 * (valueNoise(column * 0.21 + 40, row * 0.21) * 0.5 + hashCell(column, row) * 0.5) * (region === 3 ? 1.25 : 1)\n }\n }\n\n const curbZ = wallZ + sidewalkRows * cellSize\n const roadEndZ = curbZ + roadRows * cellSize\n const right = [1, 0, 0] as Vec3\n const regions: FilmRegion[] = [\n { id: REGION_NAMES[0], firstRow: 0, rowCount: wallRows, origin: [originX, wallTopY, wallZ], columnAxis: right, rowAxis: [0, -1, 0], normal: [0, 0, 1], isVertical: true },\n { id: REGION_NAMES[1], firstRow: wallRows, rowCount: sidewalkRows, origin: [originX, sidewalkY, wallZ], columnAxis: right, rowAxis: [0, 0, 1], normal: [0, 1, 0], isVertical: false },\n { id: REGION_NAMES[2], firstRow: sidewalkEnd, rowCount: curbRows, origin: [originX, sidewalkY, curbZ], columnAxis: right, rowAxis: [0, -1, 0], normal: [0, 0, 1], isVertical: true },\n { id: REGION_NAMES[3], firstRow: curbEnd, rowCount: roadRows, origin: [originX, roadY, curbZ], columnAxis: right, rowAxis: [0, 0, 1], normal: [0, 1, 0], isVertical: false },\n ]\n const maxX = originX + columns * cellSize\n\n return {\n id: params.id,\n width: columns,\n height,\n cellSize,\n bed,\n pin,\n vertical,\n regions,\n rules,\n cellToWorld: (row, column) => cellToWorldOf(regions, cellSize, row, column),\n collide(previous, position) {\n if (position[2] <= wallZ && position[1] > sidewalkY) {\n position[2] = wallZ\n return 0\n }\n if (position[2] < curbZ && (!rules.guardBehindWall || position[2] >= wallZ) && position[1] <= sidewalkY) {\n position[1] = sidewalkY\n return 1\n }\n if (rules.curbCatch && position[2] >= curbZ && previous[2] < curbZ && position[1] < sidewalkY) {\n position[2] = curbZ\n return 2\n }\n if (position[2] >= curbZ && position[1] <= roadY) {\n position[1] = roadY\n return 3\n }\n return -1\n },\n impact: (region, position, velocity) => impactOf(regions[region]!, position, velocity, cellSize),\n contains: (position) => position[0] > originX && position[0] < maxX && (!rules.clipRoadEnd || position[2] < roadEndZ),\n escaped(position) {\n if (position[1] < -1) return true\n const box = rules.escapeBox\n return box !== undefined && (position[0] < box.minX || position[0] > box.maxX || position[2] > box.maxZ)\n },\n }\n}\n\nconst PADRAO_CELL = 0.0125\nconst PADRAO_WALL_Z = 0\n\n/** The Fluid Standard's grid: 256 x 396 cells of 1.25 cm over a 1.95 m wall, a 1.6 m sidewalk, a 15 cm curb and a 1.4 m road. */\nexport const PADRAO_LAYOUT: FilmLayout = createFoldedLayout({\n id: 'padrao',\n columns: 256,\n cellSize: PADRAO_CELL,\n originX: -1.6,\n wallRows: 144,\n sidewalkRows: 128,\n curbRows: 12,\n roadRows: 112,\n wallTopY: 1.95,\n sidewalkY: 0.15,\n roadY: 0,\n wallZ: PADRAO_WALL_Z,\n curbStep: PADRAO_CELL,\n roadSlopeAnchorX: 0,\n rules: {\n dropCapacity: 600,\n curbCatch: true,\n guardBehindWall: true,\n clipRoadEnd: true,\n escapeBox: { minX: -3, maxX: 3, maxZ: PADRAO_WALL_Z + 128 * PADRAO_CELL + 112 * PADRAO_CELL + 1 },\n dripStyle: 'padrao',\n },\n})\n\nconst WORKSHOP_CELL = 0.0125\n\n/** The Workshop's grid: 160 x 448 cells (wall 160, sidewalk 128, curb 9, road 151) at the foot of the workshop's wall. */\nexport const WORKSHOP_LAYOUT: FilmLayout = createFoldedLayout({\n id: 'workshop',\n columns: 160,\n cellSize: WORKSHOP_CELL,\n originX: -2.2,\n wallRows: 160,\n sidewalkRows: 128,\n curbRows: 9,\n roadRows: 151,\n wallTopY: 2.12,\n sidewalkY: 0.1235,\n roadY: 0.009,\n wallZ: -4.497,\n roadSlopeAnchorX: -1.2,\n rules: { dropCapacity: 400, curbCatch: false, guardBehindWall: false, clipRoadEnd: false, dripStyle: 'workshop' },\n})\n","import { add, cross, dot, normalize, scale, sub } from '../math'\nimport { makeBasis } from '../stains'\nimport type { SurfaceSpec, Vec3 } from '../types'\nimport { valueNoise } from './noise'\nimport type { FilmLayout, FilmRegion, FilmRules } from './types'\n\nexport interface SurfaceLayoutOptions {\n /** The surface the film lies on (a floor, a table, a ramp). */\n floor: SurfaceSpec\n /** A wall that meets the floor: the film folds up it, so a splash on the wall runs down onto the floor. */\n wall?: SurfaceSpec\n /** The lower surface beyond the floor's far edge: the film folds down a curb face to it. Needs the wall or the floor's tangent to say where the edge is. */\n curb?: SurfaceSpec\n /** World point the grid is centred on (sideways; and along the floor when there is no wall). */\n center: Vec3\n /** Cells across (default 160: 2 m of 1.25 cm cells, the grid of the near-player manager). */\n columns?: number\n /** Cells along all strips together (default 160). */\n rows?: number\n /** Metres per cell (default 0.0125). */\n cellSize?: number\n /** Rows of the wall strip (default 48 with a wall, else 0) and cap of the curb face rows (default 12). */\n wallRows?: number\n curbRows?: number\n}\n\nconst DEFAULT_COLUMNS = 160\nconst DEFAULT_ROWS = 160\nconst DEFAULT_CELL = 0.0125\nconst DEFAULT_WALL_ROWS = 48\nconst DEFAULT_CURB_ROWS = 12\nconst RULES: FilmRules = { dropCapacity: 160, curbCatch: false, guardBehindWall: false, clipRoadEnd: false, dripStyle: 'padrao' }\n\nconst along3 = (origin: Vec3, axis: Vec3, distance: number): Vec3 => add(origin, scale(axis, distance))\n\n/** Removes the part of `vector` along the unit `axis`. */\nconst reject = (vector: Vec3, axis: Vec3): Vec3 => sub(vector, scale(axis, dot(vector, axis)))\n\ninterface Strip {\n id: string\n rows: number\n origin: Vec3\n rowAxis: Vec3\n normal: Vec3\n isVertical: boolean\n roughness: number\n}\n\n/**\n * Builds the folded grid from the host's surfaces: `wall` (optional) hangs above the fold line, `floor` runs away from the wall, and\n * `curb` (optional) is the lower surface the floor drops to over a curb face. Without a wall the grid is a flat patch of the floor around `center`.\n * Bed heights come from world y, so a tilted floor makes the film run downhill.\n */\nexport function layoutFromSurfaces(options: SurfaceLayoutOptions): FilmLayout {\n const columns = options.columns ?? DEFAULT_COLUMNS\n const totalRows = options.rows ?? DEFAULT_ROWS\n const cell = options.cellSize ?? DEFAULT_CELL\n const floorBasis = makeBasis(options.floor.normal, options.floor.tangent)\n const floorNormal = floorBasis.normal\n const projected = sub(options.center, scale(floorNormal, dot(sub(options.center, options.floor.point), floorNormal)))\n const wallNormal = options.wall ? normalize(reject(options.wall.normal, floorNormal), floorBasis.t2) : undefined\n const awayAxis = wallNormal ?? floorBasis.t2\n const columnAxis = wallNormal ? normalize(cross(floorNormal, wallNormal), floorBasis.t1) : floorBasis.t1\n const wallRows = options.wall ? Math.min(totalRows - 1, options.wallRows ?? DEFAULT_WALL_ROWS) : 0\n\n let fold = projected\n if (options.wall && wallNormal) {\n const toWall = dot(sub(projected, options.wall.point), wallNormal) / (dot(awayAxis, wallNormal) || 1)\n fold = sub(projected, scale(awayAxis, toWall))\n } else {\n fold = along3(projected, awayAxis, -(totalRows * cell) / 2)\n }\n const lateral = dot(sub(projected, fold), columnAxis) - (columns * cell) / 2\n const base = along3(fold, columnAxis, lateral)\n\n const strips: Strip[] = []\n const roughness = 0.18 + 0.4 * options.floor.porosity\n if (options.wall && wallNormal) {\n strips.push({ id: 'wall', rows: wallRows, origin: along3(base, floorNormal, wallRows * cell), rowAxis: scale(floorNormal, -1), normal: wallNormal, isVertical: true, roughness: 0.3 })\n }\n const lowerRows = totalRows - wallRows\n const dropMetres = options.curb ? Math.max(0, dot(sub(options.floor.point, options.curb.point), floorNormal)) : 0\n const curbRows = options.curb ? Math.min(options.curbRows ?? DEFAULT_CURB_ROWS, Math.max(1, Math.ceil(dropMetres / cell)), lowerRows - 2) : 0\n const floorRows = options.curb ? Math.max(1, Math.floor((lowerRows - curbRows) / 2)) : lowerRows\n strips.push({ id: 'floor', rows: floorRows, origin: base, rowAxis: awayAxis, normal: floorNormal, isVertical: false, roughness })\n if (options.curb) {\n const edge = along3(base, awayAxis, floorRows * cell)\n strips.push({ id: 'curb', rows: curbRows, origin: edge, rowAxis: scale(floorNormal, -1), normal: awayAxis, isVertical: true, roughness: 0.2 })\n const lowerOrigin = along3(edge, floorNormal, -curbRows * cell)\n strips.push({ id: 'low', rows: lowerRows - floorRows - curbRows, origin: lowerOrigin, rowAxis: awayAxis, normal: floorNormal, isVertical: false, roughness: 0.55 })\n }\n\n const regions: FilmRegion[] = []\n let firstRow = 0\n for (const strip of strips) {\n regions.push({ id: strip.id, firstRow, rowCount: strip.rows, origin: strip.origin, columnAxis, rowAxis: strip.rowAxis, normal: strip.normal, isVertical: strip.isVertical })\n firstRow += strip.rows\n }\n\n const height = firstRow\n const bed = new Float32Array(columns * height)\n const pin = new Float32Array(columns * height)\n const vertical = new Float32Array(columns * height)\n regions.forEach((region, regionIndex) => {\n const strip = strips[regionIndex]!\n for (let row = 0; row < region.rowCount; row++) {\n for (let column = 0; column < columns; column++) {\n const index = (region.firstRow + row) * columns + column\n const centre = add(add(region.origin, scale(columnAxis, (column + 0.5) * cell)), scale(region.rowAxis, (row + 0.5) * cell))\n const noise = valueNoise(column * 0.35, (region.firstRow + row) * 0.35) * 0.6 + valueNoise(column * 1.3, (region.firstRow + row) * 1.3) * 0.4\n bed[index] = centre[1] * 1000 + (noise - 0.5) * strip.roughness * 2\n vertical[index] = region.isVertical ? 0.95 : 1\n pin[index] = 0.62 + 0.76 * (valueNoise(column * 0.21 + 40, (region.firstRow + row) * 0.21) * 0.5 + valueNoise(column * 0.9, row * 0.9) * 0.5)\n }\n }\n })\n\n const lowestY = Math.min(...regions.map((region) => region.origin[1] - (region.rowAxis[1] > 0 ? 0 : region.rowCount * cell * Math.abs(region.rowAxis[1])))) - 1\n const width = columns * cell\n const cellToWorld = (row: number, column: number): Vec3 => {\n const region = regions.find((candidate) => row < candidate.firstRow + candidate.rowCount) ?? regions[regions.length - 1]!\n return add(add(region.origin, scale(region.columnAxis, column * cell)), scale(region.rowAxis, (row - region.firstRow) * cell))\n }\n\n return {\n id: 'surfaces',\n width: columns,\n height,\n cellSize: cell,\n bed,\n pin,\n vertical,\n regions,\n rules: RULES,\n cellToWorld,\n collide(previous, position) {\n for (let index = 0; index < regions.length; index++) {\n const region = regions[index]!\n const before = dot(sub(previous, region.origin), region.normal)\n const after = dot(sub(position, region.origin), region.normal)\n if (before < 0 || after > 0) continue\n const local = sub(position, region.origin)\n const sideways = dot(local, region.columnAxis)\n const downward = dot(local, region.rowAxis)\n if (sideways < 0 || sideways >= width || downward < 0 || downward >= region.rowCount * cell) continue\n position[0] -= region.normal[0] * after\n position[1] -= region.normal[1] * after\n position[2] -= region.normal[2] * after\n return index\n }\n return -1\n },\n impact(regionIndex, position, velocity) {\n const region = regions[regionIndex]!\n const local = sub(position, region.origin)\n return {\n row: region.firstRow + dot(local, region.rowAxis) / cell,\n column: dot(local, region.columnAxis) / cell,\n along: [dot(velocity, region.columnAxis), dot(velocity, region.rowAxis)],\n normalSpeed: -dot(velocity, region.normal),\n }\n },\n contains: () => true,\n escaped: (position) => position[1] < lowestY,\n }\n}\n","[\n {\n \"id\": \"blood\",\n \"look\": \"blood\",\n \"flow\": 0.05,\n \"pin\": 0.33,\n \"front\": 0.58,\n \"referenceThickness\": 0.6,\n \"slopeCap\": 1.1,\n \"dryTime\": 600,\n \"evaporation\": 0,\n \"opacityRate\": 3.2,\n \"reflectance\": 0.045,\n \"normalScale\": 16,\n \"thin\": 7997966,\n \"thick\": 2753028,\n \"dry\": 3874068,\n \"dryThin\": 6960678,\n \"dropColor\": 7997965,\n \"dropOpacity\": 1,\n \"volume\": 1,\n \"spikes\": 1,\n \"landsAsBlob\": false,\n \"maxAmount\": 2.6,\n \"sources\": {\n \"padrao\": \"F46\",\n \"oficina\": \"W583\"\n }\n },\n {\n \"id\": \"old_blood\",\n \"look\": \"blood\",\n \"flow\": 0.032,\n \"pin\": 0.42,\n \"front\": 0.7,\n \"referenceThickness\": 0.7,\n \"slopeCap\": 1,\n \"dryTime\": 360,\n \"evaporation\": 0,\n \"opacityRate\": 3.8,\n \"reflectance\": 0.03,\n \"normalScale\": 14,\n \"thin\": 7085078,\n \"thick\": 2888717,\n \"dry\": 2758158,\n \"dryThin\": 4860444,\n \"dropColor\": 4854286,\n \"dropOpacity\": 1,\n \"volume\": 0.6,\n \"spikes\": 1,\n \"landsAsBlob\": false,\n \"maxAmount\": 2.6,\n \"sources\": {\n \"padrao\": \"F48\"\n }\n },\n {\n \"id\": \"bile\",\n \"look\": \"bile\",\n \"flow\": 0.02,\n \"pin\": 0.8,\n \"front\": 1.2,\n \"referenceThickness\": 1.2,\n \"slopeCap\": 0.9,\n \"dryTime\": 900,\n \"evaporation\": 0,\n \"opacityRate\": 7,\n \"reflectance\": 0.04,\n \"normalScale\": 12,\n \"thin\": 11121724,\n \"thick\": 7174171,\n \"dry\": 4080160,\n \"dryThin\": 5659180,\n \"dropColor\": 9083434,\n \"dropOpacity\": 1,\n \"volume\": 1.3,\n \"spikes\": 0.3,\n \"landsAsBlob\": false,\n \"maxAmount\": 4,\n \"sources\": {\n \"padrao\": \"F50\",\n \"oficina\": \"W584 (spikes 0.3 W578, cap 4 W691)\"\n }\n },\n {\n \"id\": \"motor_oil\",\n \"look\": \"oil\",\n \"flow\": 0.03,\n \"pin\": 0.12,\n \"front\": 0.22,\n \"referenceThickness\": 0.5,\n \"slopeCap\": 1,\n \"dryTime\": 0,\n \"evaporation\": 0,\n \"opacityRate\": 4.5,\n \"reflectance\": 0.06,\n \"normalScale\": 18,\n \"thin\": 1381135,\n \"thick\": 263173,\n \"dry\": 263173,\n \"dryThin\": 1381135,\n \"dropColor\": 657932,\n \"dropOpacity\": 1,\n \"volume\": 1,\n \"spikes\": 1,\n \"landsAsBlob\": true,\n \"maxAmount\": 2.6,\n \"sources\": {\n \"padrao\": \"F52\",\n \"oficina\": \"W585 (blob W691)\"\n }\n },\n {\n \"id\": \"fuel\",\n \"look\": \"fuel\",\n \"flow\": 0.2,\n \"pin\": 0.035,\n \"front\": 0.07,\n \"referenceThickness\": 0.2,\n \"slopeCap\": 1.2,\n \"dryTime\": 0,\n \"evaporation\": 0.02,\n \"opacityRate\": 0.25,\n \"reflectance\": 0.04,\n \"normalScale\": 0,\n \"thin\": 10129520,\n \"thick\": 7234630,\n \"dry\": 0,\n \"dryThin\": 0,\n \"dropColor\": 12103824,\n \"dropOpacity\": 0.45,\n \"volume\": 1.4,\n \"spikes\": 1,\n \"landsAsBlob\": true,\n \"maxAmount\": 2.6,\n \"sources\": {\n \"padrao\": \"F54\",\n \"oficina\": \"W586 (blob W691)\"\n }\n }\n]\n","import profilesData from '../data/film-profiles.json'\nimport type { LiquidId } from '../types'\nimport type { FilmProfile } from './types'\n\n/** Film profiles of the liquids that run as a film (F46-55, plus the Workshop's `spikes` and `landsAsBlob`). Data in `data/film-profiles.json`. */\nexport const FILM_PROFILES: FilmProfile[] = profilesData as unknown as FilmProfile[]\n\n/** The profile of a liquid with the given overrides, or undefined when the liquid has no film. */\nexport function filmProfileOf(id: LiquidId, overrides: Partial<FilmProfile> = {}): FilmProfile | undefined {\n const profile = FILM_PROFILES.find((entry) => entry.id === id)\n return profile ? { ...profile, ...overrides } : undefined\n}\n","{\n \"families\": {\n \"drink_can\": {\n \"models\": [\n \"soda_can\",\n \"beer_can\",\n \"energy_drink\",\n \"empty_can\"\n ],\n \"rule\": {\n \"hollow\": true,\n \"welded\": true,\n \"skinTags\": [\n \"paper\",\n \"food\"\n ],\n \"materials\": {\n \"metal\": \"aluminium\"\n },\n \"tessellate\": {\n \"cylinder\": {\n \"heightSegments\": 6,\n \"radialSegments\": 20\n },\n \"box\": {\n \"widthSegments\": 6,\n \"heightSegments\": 1,\n \"depthSegments\": 4\n }\n }\n }\n },\n \"food_tin\": {\n \"models\": [\n \"canned_beans\",\n \"canned_corn_and_peas\",\n \"canned_sausages\",\n \"canned_sardines\",\n \"condensed_milk\"\n ],\n \"rule\": {\n \"hollow\": true,\n \"welded\": true,\n \"skinTags\": [\n \"paper\",\n \"food\"\n ],\n \"materials\": {\n \"metal\": \"steel\"\n },\n \"tessellate\": {\n \"cylinder\": {\n \"heightSegments\": 6,\n \"radialSegments\": 20\n },\n \"box\": {\n \"widthSegments\": 6,\n \"heightSegments\": 1,\n \"depthSegments\": 4\n }\n }\n }\n }\n },\n \"contents\": {\n \"soda_can\": {\n \"liquid\": \"soda\",\n \"fill\": 0.95\n },\n \"beer_can\": {\n \"liquid\": \"beer\",\n \"fill\": 0.95\n },\n \"energy_drink\": {\n \"liquid\": \"soda\",\n \"fill\": 0.95\n },\n \"canned_beans\": {\n \"liquid\": \"juice\",\n \"fill\": 0.4\n },\n \"canned_corn_and_peas\": {\n \"liquid\": \"water\",\n \"fill\": 0.4\n },\n \"canned_sausages\": {\n \"liquid\": \"water\",\n \"fill\": 0.3\n },\n \"canned_sardines\": {\n \"liquid\": \"cooking_oil\",\n \"fill\": 0.3,\n \"box\": true\n },\n \"condensed_milk\": {\n \"liquid\": \"honey\",\n \"fill\": 0.9\n }\n }\n}\n","import type * as THREE_NS from 'three'\nimport type { ContainerSpec } from '@adatechnology/game-contracts'\nimport { LIQUIDS } from '@adatechnology/game-fluids'\n\nimport data from './data/destruction.json'\n\n/** The destruction material (`game-destruction` id) of each material tag of the kit, for a mesh whose model says nothing else. */\nexport const DESTRUCTION_MATERIAL_BY_TAG: Readonly<Record<string, string>> = {\n metal: 'steel',\n wood: 'wood_soft',\n glass: 'glass',\n paper: 'paper',\n plastic: 'plastic',\n cloth: 'fabric',\n food: 'flesh_fruit',\n}\n\n/** How a model behaves under `game-destruction-three`'s `specFromObject3D`, as `data/destruction.json` keeps it. */\nexport interface ItemDestruction {\n /** The meshes are thin shells, not solid blocks. */\n readonly hollow?: boolean\n /** The parts of the model are welded to its largest mesh, so a hit dents and holes them instead of tearing them off. */\n readonly welded?: boolean\n /** Meshes made of these material tags are skins (labels, coats): drawn on a part, never a part of their own. */\n readonly skinTags?: readonly string[]\n /** Material tag to destruction material id, over `DESTRUCTION_MATERIAL_BY_TAG`. */\n readonly materials?: Readonly<Record<string, string>>\n /** Segments the cylinder and box meshes of the model are rebuilt with, so a bullet dent (a few millimetres wide) finds vertices to push in. */\n readonly tessellate?: {\n readonly cylinder?: { readonly heightSegments: number; readonly radialSegments: number }\n readonly box?: { readonly widthSegments: number; readonly heightSegments: number; readonly depthSegments: number }\n }\n}\n\n/** A family of models that behave alike: one rule for all of them, so adding a model is one id and changing the rule changes them all. */\nexport interface ItemFamily {\n readonly models: readonly string[]\n readonly rule: ItemDestruction\n}\n\n/** What a model holds inside its shell: a liquid (`game-fluids` id) filling `fill` of the inner volume. */\nexport interface ItemContents {\n readonly liquid: string\n readonly fill: number\n /** The shell is a box (a flat tin) and not a cylinder. */\n readonly box?: boolean\n}\n\nconst FAMILIES = data.families as Readonly<Record<string, ItemFamily>>\nconst CONTENTS = data.contents as Readonly<Record<string, ItemContents>>\n\nconst FAMILY_OF_MODEL = new Map<string, string>(Object.entries(FAMILIES).flatMap(([family, entry]) => entry.models.map((model) => [model, family] as const)))\n\n/** Id of the family a model belongs to (`drink_can`), if any. */\nexport const itemFamily = (modelId: string): string | undefined => FAMILY_OF_MODEL.get(modelId)\n\n// One lookup on purpose: the item-category system (contracts per category) can feed it later instead of this file.\nexport const itemDestruction = (modelId: string): ItemDestruction | undefined => {\n const family = FAMILY_OF_MODEL.get(modelId)\n return family === undefined ? undefined : FAMILIES[family]?.rule\n}\n\n/** The family ids and their models, as the data gives them. */\nexport const ITEM_FAMILIES: Readonly<Record<string, ItemFamily>> = FAMILIES\n\n/** The subject of `itemContents`: what `buildItem` draws. */\nexport interface ContentsSubject {\n readonly model?: string\n /** Metres. */\n readonly size: readonly [number, number, number]\n /** Kg, shell included. */\n readonly weight?: number\n}\n\n/** Id of the welded part that is the whole shell of a container. */\nexport const SHELL_PART_ID = 'shell'\n\n/** Share of the inner volume the walls and the seams take away. */\nconst WALL_SHARE = 0.9\n/** Radius of the pull tab opening of a closed can, in metres. */\nconst OPENING_RADIUS = 0.012\n\n/**\n * The container the model holds (`TestableItem.fluid` of the test room and `PartSpec.contains` of the shell), sized from the item: the inner volume of its\n * box times the fill of the model, never more than the item weighs in that liquid. Undefined for a model that holds nothing.\n */\nexport function itemContents(subject: ContentsSubject): { readonly container: ContainerSpec; readonly liquid: string; readonly liters: number } | undefined {\n const contents = subject.model === undefined ? undefined : CONTENTS[subject.model]\n if (!contents) return undefined\n const [width, height, depth] = subject.size\n const radius = Math.min(width, depth) / 2\n const innerLiters = (contents.box ? width * depth : Math.PI * radius * radius) * height * WALL_SHARE * 1000\n const density = LIQUIDS.find((liquid) => liquid.id === contents.liquid)?.density ?? 1000\n const heaviest = subject.weight === undefined ? Infinity : (subject.weight * 1000) / density\n const liters = Math.min(innerLiters * contents.fill, heaviest)\n const container: ContainerSpec = {\n capacity: innerLiters,\n liquid: contents.liquid,\n liters,\n shape: contents.box ? { kind: 'box', size: [width * WALL_SHARE, height * WALL_SHARE, depth * WALL_SHARE] } : { kind: 'cylinder', radius: radius * WALL_SHARE, height: height * WALL_SHARE },\n opening: OPENING_RADIUS,\n closed: true,\n }\n return { container, liquid: contents.liquid, liters }\n}\n\nfunction tagOf(mesh: THREE_NS.Mesh): string | undefined {\n const material = Array.isArray(mesh.material) ? mesh.material[0] : mesh.material\n const tag = (material?.userData as { tag?: unknown } | undefined)?.tag\n return typeof tag === 'string' ? tag : undefined\n}\n\nfunction volumeOf(mesh: THREE_NS.Mesh): number {\n if (!mesh.geometry.boundingBox) mesh.geometry.computeBoundingBox()\n const box = mesh.geometry.boundingBox\n if (!box) return 0\n return (box.max.x - box.min.x) * (box.max.y - box.min.y) * (box.max.z - box.min.z)\n}\n\n/** What `tagForDestruction` needs to know about the item beside its meshes. */\nexport interface DestructionTagOptions {\n readonly modelId?: string\n /** Real weight in kg. */\n readonly weight?: number\n /** Size in metres, for the contents of the shell. */\n readonly size?: readonly [number, number, number]\n}\n\ntype CylinderParameters = { radiusTop: number; radiusBottom: number; height: number; openEnded: boolean; thetaStart: number; thetaLength: number }\ntype BoxParameters = { width: number; height: number; depth: number }\ntype Tessellation = NonNullable<ItemDestruction['tessellate']>\ntype GeometryConstructor = new (...args: readonly (number | boolean)[]) => THREE_NS.BufferGeometry\n\n/** The same shape as `geometry` with the segments of the rule, or undefined when the rule says nothing about its kind. */\nfunction tessellated(geometry: THREE_NS.BufferGeometry, rule: Tessellation): THREE_NS.BufferGeometry | undefined {\n const Shape = geometry.constructor as GeometryConstructor\n if (geometry.type === 'CylinderGeometry' && rule.cylinder) {\n const { radiusTop, radiusBottom, height, openEnded, thetaStart, thetaLength } = (geometry as unknown as { parameters: CylinderParameters }).parameters\n return new Shape(radiusTop, radiusBottom, height, rule.cylinder.radialSegments, rule.cylinder.heightSegments, openEnded, thetaStart, thetaLength)\n }\n if (geometry.type === 'BoxGeometry' && rule.box) {\n const { width, height, depth } = (geometry as unknown as { parameters: BoxParameters }).parameters\n return new Shape(width, height, depth, rule.box.widthSegments, rule.box.heightSegments, rule.box.depthSegments)\n }\n return undefined\n}\n\nconst triangleCount = (geometry: THREE_NS.BufferGeometry): number => (geometry.index ? geometry.index.count : geometry.getAttribute('position').count) / 3\n\n/** Rebuilds the cylinder and box geometries of every mesh under `root` with the segments of the rule; a geometry shared by several meshes is rebuilt once. */\nfunction tessellateShapes(root: THREE_NS.Object3D, rule: Tessellation): void {\n const rebuilt = new Map<THREE_NS.BufferGeometry, THREE_NS.BufferGeometry>()\n root.traverse((object) => {\n const mesh = object as THREE_NS.Mesh\n if (!mesh.isMesh) return\n let fresh = rebuilt.get(mesh.geometry)\n if (!fresh) {\n fresh = tessellated(mesh.geometry, rule)\n if (!fresh) return\n rebuilt.set(mesh.geometry, fresh)\n }\n mesh.geometry = fresh\n })\n let added = 0\n rebuilt.forEach((fresh, old) => {\n added += triangleCount(fresh) - triangleCount(old)\n old.dispose()\n })\n root.userData.tessellationTriangles = added\n}\n\n/**\n * Writes the `userData` that `specFromObject3D` reads onto the meshes of a drawn item: the destruction material of each mesh from its kit material tag,\n * the item's real weight in kg (`destructionMass`, so the world weighs what the thing weighs) and what the model's family in `data/destruction.json` asks for (hollow shells, welded parts, skins),\n * with the liquid the model holds on its shell (`destructionContains`).\n */\nexport function tagForDestruction(root: THREE_NS.Object3D, options: DestructionTagOptions = {}): void {\n const { modelId, weight, size } = options\n if (weight !== undefined && weight > 0) root.userData.destructionMass = weight\n const rule = modelId === undefined ? undefined : itemDestruction(modelId)\n if (rule?.tessellate) tessellateShapes(root, rule.tessellate)\n const solid: THREE_NS.Mesh[] = []\n root.traverse((object) => {\n const mesh = object as THREE_NS.Mesh\n if (!mesh.isMesh) return\n const tag = tagOf(mesh)\n if (tag === undefined) return\n const material = rule?.materials?.[tag] ?? DESTRUCTION_MATERIAL_BY_TAG[tag]\n if (material !== undefined) mesh.userData.destructionMaterial = material\n if (rule?.skinTags?.includes(tag)) {\n mesh.userData.destructionSkin = true\n return\n }\n if (rule?.hollow) mesh.userData.hollow = true\n solid.push(mesh)\n })\n if (!rule?.welded || solid.length < 2) return\n const anchor = solid.reduce((largest, mesh) => (volumeOf(mesh) > volumeOf(largest) ? mesh : largest))\n solid.forEach((mesh, index) => {\n mesh.userData.destructionPart = mesh === anchor ? { id: SHELL_PART_ID } : { id: `shell_${index}`, parent: SHELL_PART_ID, kind: 'weld' }\n })\n const contents = size === undefined ? undefined : itemContents({ ...(modelId === undefined ? {} : { model: modelId }), size, ...(weight === undefined ? {} : { weight }) })\n if (contents) anchor.userData.destructionContains = { fluid: contents.liquid, liters: contents.liters }\n}\n","[\n {\n \"id\": \"canned_beans\",\n \"teamId\": \"feijao_lata\",\n \"teamBox\": [\n 0.67,\n 0.57,\n 0.66\n ],\n \"scale\": 0.119403\n },\n {\n \"id\": \"water_bottle\",\n \"teamId\": \"agua_500\",\n \"teamBox\": [\n 0.452,\n 1.25,\n 0.452\n ],\n \"scale\": 0.146018\n },\n {\n \"id\": \"rice\",\n \"teamId\": \"arroz\",\n \"teamBox\": [\n 0.72,\n 1.055,\n 0.3\n ],\n \"scale\": 0.236967\n },\n {\n \"id\": \"military_ration\",\n \"teamId\": \"racao_militar\",\n \"teamBox\": [\n 0.77,\n 1.03,\n 0.235\n ],\n \"scale\": 0.252427\n },\n {\n \"id\": \"cachaca\",\n \"teamId\": \"cachaca\",\n \"teamBox\": [\n 0.552,\n 1.31,\n 0.552\n ],\n \"scale\": 0.163043\n },\n {\n \"id\": \"first_aid_kit\",\n \"teamId\": \"kit_ps\",\n \"teamBox\": [\n 1.07,\n 0.915,\n 0.41\n ],\n \"scale\": 0.233645\n },\n {\n \"id\": \"bandage\",\n \"teamId\": \"atadura\",\n \"teamBox\": [\n 0.9851,\n 0.7575,\n 0.43\n ],\n \"scale\": 0.102528\n },\n {\n \"id\": \"amoxicillin\",\n \"teamId\": \"amoxicilina\",\n \"teamBox\": [\n 0.8859,\n 0.47,\n 0.607\n ],\n \"scale\": 0.11288\n },\n {\n \"id\": \"crowbar\",\n \"teamId\": \"pe_cabra\",\n \"teamBox\": [\n 0.428,\n 1.7087,\n 0.11\n ],\n \"scale\": 0.43893\n },\n {\n \"id\": \"hammer\",\n \"teamId\": \"martelo\",\n \"teamBox\": [\n 0.6487,\n 1.3477,\n 0.19\n ],\n \"scale\": 0.244862\n },\n {\n \"id\": \"machete\",\n \"teamId\": \"facao\",\n \"teamBox\": [\n 1.8759,\n 0.2906,\n 0.12\n ],\n \"scale\": 0.293193\n },\n {\n \"id\": \"axe\",\n \"teamId\": \"machado\",\n \"teamBox\": [\n 0.5952,\n 1.6693,\n 0.14\n ],\n \"scale\": 0.419337\n },\n {\n \"id\": \"nail_bat\",\n \"teamId\": \"taco_pregos\",\n \"teamBox\": [\n 0.4384,\n 1.69,\n 0.4352\n ],\n \"scale\": 0.508876\n },\n {\n \"id\": \"hiking_backpack_40l\",\n \"teamId\": \"mochila_trilha\",\n \"teamBox\": [\n 0.8,\n 1.07,\n 0.62\n ],\n \"scale\": 0.514019\n },\n {\n \"id\": \"flashlight\",\n \"teamId\": \"lanterna\",\n \"teamBox\": [\n 0.38,\n 1.08,\n 0.38\n ],\n \"scale\": 0.148148\n },\n {\n \"id\": \"portable_radio\",\n \"teamId\": \"radio_portatil\",\n \"teamBox\": [\n 1.1041,\n 1.4821,\n 0.35\n ],\n \"scale\": 0.199257\n },\n {\n \"id\": \"house_key\",\n \"teamId\": \"chave_casa\",\n \"teamBox\": [\n 1.5433,\n 0.8305,\n 0.08\n ],\n \"scale\": 0.055077\n },\n {\n \"id\": \"survivor_diary\",\n \"teamId\": \"diario\",\n \"teamBox\": [\n 0.8,\n 1.04,\n 0.27\n ],\n \"scale\": 0.201923\n },\n {\n \"id\": \"motorcycle_helmet\",\n \"teamId\": \"capacete_moto\",\n \"teamBox\": [\n 1.11,\n 1.0825,\n 1.17\n ],\n \"scale\": 0.234234\n },\n {\n \"id\": \"lpg_cylinder_13kg\",\n \"teamId\": \"botijao\",\n \"teamBox\": [\n 0.9257,\n 1.285,\n 0.94\n ],\n \"scale\": 0.381323\n },\n {\n \"id\": \"fuel_jerrycan\",\n \"teamId\": \"galao\",\n \"teamBox\": [\n 0.8788,\n 1.342,\n 0.44\n ],\n \"scale\": 0.350224\n },\n {\n \"id\": \"walkie_talkies\",\n \"teamId\": \"walkie\",\n \"teamBox\": [\n 0.465,\n 1.47,\n 0.22\n ],\n \"scale\": 0.14966\n },\n {\n \"id\": \"batteries\",\n \"teamId\": \"pilha_aa\",\n \"teamBox\": [\n 0.744,\n 1.005,\n 0.344\n ],\n \"scale\": 0.050249\n },\n {\n \"id\": \"wooden_plank\",\n \"teamId\": \"tabua\",\n \"teamBox\": [\n 1.5203,\n 0.4741,\n 0.5377\n ],\n \"scale\": 0.526212\n },\n {\n \"id\": \"sugar\",\n \"teamId\": \"acucar\",\n \"teamBox\": [\n 1,\n 2,\n 0.601\n ],\n \"scale\": 0.099945\n },\n {\n \"id\": \"chocolate_bar\",\n \"teamId\": \"chocolate\",\n \"teamBox\": [\n 1.5,\n 0.7,\n 0.102\n ],\n \"scale\": 0.099342\n },\n {\n \"id\": \"potatoes\",\n \"teamId\": \"batata\",\n \"teamBox\": [\n 1.9511,\n 0.9,\n 1.3608\n ],\n \"scale\": 0.101787\n },\n {\n \"id\": \"biscuits\",\n \"teamId\": \"biscoito\",\n \"teamBox\": [\n 2,\n 0.5,\n 1\n ],\n \"scale\": 0.1\n },\n {\n \"id\": \"coffee\",\n \"teamId\": \"cafe_po\",\n \"teamBox\": [\n 0.8,\n 1.5,\n 0.61\n ],\n \"scale\": 0.099451\n },\n {\n \"id\": \"raw_beef\",\n \"teamId\": \"carne_bovina\",\n \"teamBox\": [\n 2,\n 0.5,\n 1.5\n ],\n \"scale\": 0.1\n },\n {\n \"id\": \"game_meat\",\n \"teamId\": \"carne_caca\",\n \"teamBox\": [\n 3,\n 0.8,\n 2\n ],\n \"scale\": 0.1\n },\n {\n \"id\": \"jerked_beef\",\n \"teamId\": \"charque\",\n \"teamBox\": [\n 2.5,\n 0.251,\n 1.5\n ],\n \"scale\": 0.099867\n },\n {\n \"id\": \"home_preserves\",\n \"teamId\": \"conserva\",\n \"teamBox\": [\n 0.904,\n 1.3,\n 0.904\n ],\n \"scale\": 0.099705\n },\n {\n \"id\": \"eggs\",\n \"teamId\": \"ovos\",\n \"teamBox\": [\n 2.5,\n 0.7,\n 1\n ],\n \"scale\": 0.1\n },\n {\n \"id\": \"cassava_flour\",\n \"teamId\": \"farinha_mandioca\",\n \"teamBox\": [\n 1.5,\n 2.5,\n 0.601\n ],\n \"scale\": 0.099945\n },\n {\n \"id\": \"beans\",\n \"teamId\": \"feijao_seco\",\n \"teamBox\": [\n 1,\n 2,\n 0.6\n ],\n \"scale\": 0.1\n },\n {\n \"id\": \"frozen_chicken\",\n \"teamId\": \"frango\",\n \"teamBox\": [\n 2.6,\n 1,\n 1.7\n ],\n \"scale\": 0.1\n },\n {\n \"id\": \"orange\",\n \"teamId\": \"laranja\",\n \"teamBox\": [\n 0.75,\n 0.7518,\n 0.75\n ],\n \"scale\": 0.099921\n },\n {\n \"id\": \"condensed_milk\",\n \"teamId\": \"leite_condensado\",\n \"teamBox\": [\n 0.734,\n 1.004,\n 0.734\n ],\n \"scale\": 0.099504\n },\n {\n \"id\": \"pasta\",\n \"teamId\": \"macarrao\",\n \"teamBox\": [\n 1,\n 2.5,\n 0.405\n ],\n \"scale\": 0.099587\n },\n {\n \"id\": \"instant_noodles\",\n \"teamId\": \"macarrao_inst\",\n \"teamBox\": [\n 1.2,\n 1.6,\n 0.308\n ],\n \"scale\": 0.099127\n },\n {\n \"id\": \"cassava_root\",\n \"teamId\": \"mandioca\",\n \"teamBox\": [\n 4.0317,\n 0.7121,\n 0.71\n ],\n \"scale\": 0.098701\n },\n {\n \"id\": \"canned_corn_and_peas\",\n \"teamId\": \"milho_lata\",\n \"teamBox\": [\n 0.734,\n 0.85,\n 0.734\n ],\n \"scale\": 0.099636\n },\n {\n \"id\": \"mortadella\",\n \"teamId\": \"mortadela\",\n \"teamBox\": [\n 1.516,\n 0.6,\n 0.5\n ],\n \"scale\": 0.099647\n },\n {\n \"id\": \"fresh_fish\",\n \"teamId\": \"peixe_fresco\",\n \"teamBox\": [\n 3.0071,\n 0.6,\n 1\n ],\n \"scale\": 0.099921\n },\n {\n \"id\": \"salted_fish\",\n \"teamId\": \"peixe_salgado\",\n \"teamBox\": [\n 2.487,\n 0.291,\n 0.98\n ],\n \"scale\": 0.101878\n },\n {\n \"id\": \"banana_bunch\",\n \"teamId\": \"banana\",\n \"teamBox\": [\n 3.0041,\n 1.2881,\n 1.6943\n ],\n \"scale\": 0.100373\n },\n {\n \"id\": \"honey_jar\",\n \"teamId\": \"mel\",\n \"teamBox\": [\n 0.804,\n 1,\n 0.804\n ],\n \"scale\": 0.099668\n },\n {\n \"id\": \"bread\",\n \"teamId\": \"pao_forma\",\n \"teamBox\": [\n 3,\n 1,\n 1\n ],\n \"scale\": 0.1\n },\n {\n \"id\": \"cheese\",\n \"teamId\": \"queijo\",\n \"teamBox\": [\n 1.4941,\n 0.405,\n 0.981\n ],\n \"scale\": 0.100355\n },\n {\n \"id\": \"rapadura\",\n \"teamId\": \"rapadura\",\n \"teamBox\": [\n 1.9,\n 1,\n 0.602\n ],\n \"scale\": 0.099889\n },\n {\n \"id\": \"dog_food\",\n \"teamId\": \"racao_cao\",\n \"teamBox\": [\n 1.8,\n 2.6,\n 0.711\n ],\n \"scale\": 0.099482\n },\n {\n \"id\": \"salt\",\n \"teamId\": \"sal\",\n \"teamBox\": [\n 0.704,\n 1.61,\n 0.704\n ],\n \"scale\": 0.099414\n },\n {\n \"id\": \"snack_chips\",\n \"teamId\": \"salgadinho\",\n \"teamBox\": [\n 2,\n 2.8,\n 0.601\n ],\n \"scale\": 0.099945\n },\n {\n \"id\": \"canned_sausages\",\n \"teamId\": \"salsicha_lata\",\n \"teamBox\": [\n 0.734,\n 0.85,\n 0.734\n ],\n \"scale\": 0.099636\n },\n {\n \"id\": \"canned_sardines\",\n \"teamId\": \"sardinha\",\n \"teamBox\": [\n 1.12,\n 0.26,\n 0.65\n ],\n \"scale\": 0.1\n },\n {\n \"id\": \"cooking_oil\",\n \"teamId\": \"oleo_cozinha\",\n \"teamBox\": [\n 0.704,\n 2.6,\n 0.704\n ],\n \"scale\": 0.099621\n },\n {\n \"id\": \"beer_can\",\n \"teamId\": \"cerveja\",\n \"teamBox\": [\n 0.664,\n 1.2,\n 0.664\n ],\n \"scale\": 0.099598\n },\n {\n \"id\": \"energy_drink\",\n \"teamId\": \"energetico\",\n \"teamBox\": [\n 0.584,\n 1.35,\n 0.584\n ],\n \"scale\": 0.099543\n },\n {\n \"id\": \"water_jug_5l\",\n \"teamId\": \"galao_agua\",\n \"teamBox\": [\n 1.9,\n 3.3,\n 1.501\n ],\n \"scale\": 0.099978\n },\n {\n \"id\": \"sports_drink\",\n \"teamId\": \"isotonico\",\n \"teamBox\": [\n 0.664,\n 1.83,\n 0.664\n ],\n \"scale\": 0.099598\n },\n {\n \"id\": \"milk_carton\",\n \"teamId\": \"leite\",\n \"teamBox\": [\n 0.7,\n 2,\n 0.704\n ],\n \"scale\": 0.09981\n },\n {\n \"id\": \"soda_can\",\n \"teamId\": \"refri_lata\",\n \"teamBox\": [\n 0.664,\n 1.2,\n 0.664\n ],\n \"scale\": 0.099598\n },\n {\n \"id\": \"juice_box\",\n \"teamId\": \"suco_cx\",\n \"teamBox\": [\n 0.52,\n 1,\n 0.3715\n ],\n \"scale\": 0.099865\n },\n {\n \"id\": \"communion_wine\",\n \"teamId\": \"vinho\",\n \"teamBox\": [\n 0.764,\n 3,\n 0.767\n ],\n \"scale\": 0.099521\n },\n {\n \"id\": \"coconut_water\",\n \"teamId\": \"agua_coco\",\n \"teamBox\": [\n 0.6,\n 1.7,\n 0.6\n ],\n \"scale\": 0.1\n },\n {\n \"id\": \"dirty_water\",\n \"teamId\": \"agua_suja\",\n \"teamBox\": [\n 0.664,\n 1.83,\n 0.664\n ],\n \"scale\": 0.099598\n },\n {\n \"id\": \"painkillers\",\n \"teamId\": \"analgesico\",\n \"teamBox\": [\n 0.6,\n 0.201,\n 0.4\n ],\n \"scale\": 0.099834\n },\n {\n \"id\": \"tramadol\",\n \"teamId\": \"opioide\",\n \"teamBox\": [\n 0.95,\n 0.5,\n 0.1525\n ],\n \"scale\": 0.099451\n },\n {\n \"id\": \"ibuprofen\",\n \"teamId\": \"ibuprofeno\",\n \"teamBox\": [\n 0.95,\n 0.5,\n 0.1525\n ],\n \"scale\": 0.099451\n },\n {\n \"id\": \"antihistamine\",\n \"teamId\": \"antialergico\",\n \"teamBox\": [\n 0.8,\n 0.5,\n 0.1525\n ],\n \"scale\": 0.099451\n },\n {\n \"id\": \"ceftriaxone\",\n \"teamId\": \"ceftriaxona\",\n \"teamBox\": [\n 1,\n 0.6,\n 0.3\n ],\n \"scale\": 0.1\n },\n {\n \"id\": \"clonazepam\",\n \"teamId\": \"calmante\",\n \"teamBox\": [\n 0.9,\n 0.5,\n 0.1525\n ],\n \"scale\": 0.099451\n },\n {\n \"id\": \"activated_charcoal\",\n \"teamId\": \"carvao_ativado\",\n \"teamBox\": [\n 0.6,\n 0.95,\n 0.2515\n ],\n \"scale\": 0.099801\n },\n {\n \"id\": \"adhesive_bandages\",\n \"teamId\": \"curativo\",\n \"teamBox\": [\n 1,\n 0.6,\n 0.1516\n ],\n \"scale\": 0.099647\n },\n {\n \"id\": \"medical_tape\",\n \"teamId\": \"esparadrapo\",\n \"teamBox\": [\n 0.5,\n 0.25,\n 0.5\n ],\n \"scale\": 0.1\n },\n {\n \"id\": \"sterile_gauze\",\n \"teamId\": \"gaze\",\n \"teamBox\": [\n 1,\n 1,\n 0.1526\n ],\n \"scale\": 0.099429\n },\n {\n \"id\": \"povidone_iodine\",\n \"teamId\": \"pvpi\",\n \"teamBox\": [\n 0.451,\n 1.1,\n 0.3563\n ],\n \"scale\": 0.099335\n },\n {\n \"id\": \"suture_kit\",\n \"teamId\": \"kit_sutura\",\n \"teamBox\": [\n 1.5,\n 0.8,\n 0.305\n ],\n \"scale\": 0.099451\n },\n {\n \"id\": \"exam_gloves\",\n \"teamId\": \"luva_proc\",\n \"teamBox\": [\n 1.0104,\n 1.2,\n 0.1005\n ],\n \"scale\": 0.09949\n },\n {\n \"id\": \"n95_mask\",\n \"teamId\": \"n95\",\n \"teamBox\": [\n 1.5,\n 1.1007,\n 0.25\n ],\n \"scale\": 0.099978\n },\n {\n \"id\": \"multivitamin\",\n \"teamId\": \"vitamina\",\n \"teamBox\": [\n 0.5,\n 0.9,\n 0.5\n ],\n \"scale\": 0.1\n },\n {\n \"id\": \"maintenance_medication\",\n \"teamId\": \"remedio_continuo\",\n \"teamBox\": [\n 0.45,\n 0.9,\n 0.45\n ],\n \"scale\": 0.1\n },\n {\n \"id\": \"rehydration_salts\",\n \"teamId\": \"sais_reidrat\",\n \"teamBox\": [\n 0.9,\n 1.2,\n 0.1005\n ],\n \"scale\": 0.099834\n },\n {\n \"id\": \"syringe\",\n \"teamId\": \"seringa\",\n \"teamBox\": [\n 1.5,\n 0.2,\n 0.2\n ],\n \"scale\": 0.1\n },\n {\n \"id\": \"antivenom\",\n \"teamId\": \"antiofidico\",\n \"teamBox\": [\n 1.5,\n 0.9,\n 0.504\n ],\n \"scale\": 0.099735\n },\n {\n \"id\": \"saline_iv_bag\",\n \"teamId\": \"soro\",\n \"teamBox\": [\n 1.2,\n 2.5,\n 0.45\n ],\n \"scale\": 0.1\n },\n {\n \"id\": \"splint\",\n \"teamId\": \"tala\",\n \"teamBox\": [\n 4.6,\n 1.1,\n 0.1005\n ],\n \"scale\": 0.099834\n },\n {\n \"id\": \"thermometer\",\n \"teamId\": \"termometro\",\n \"teamBox\": [\n 1.2,\n 0.198,\n 0.3\n ],\n \"scale\": 0.100336\n },\n {\n \"id\": \"alcohol_70\",\n \"teamId\": \"alcool70\",\n \"teamBox\": [\n 0.702,\n 2,\n 0.5012\n ],\n \"scale\": 0.099823\n },\n {\n \"id\": \"can_opener\",\n \"teamId\": \"abridor\",\n \"teamBox\": [\n 14,\n 4,\n 2.5\n ],\n \"scale\": 0.01\n },\n {\n \"id\": \"pliers\",\n \"teamId\": \"alicate\",\n \"teamBox\": [\n 20,\n 3,\n 7\n ],\n \"scale\": 0.01\n },\n {\n \"id\": \"bolt_cutters\",\n \"teamId\": \"corta_vergalhao\",\n \"teamBox\": [\n 60,\n 6,\n 15\n ],\n \"scale\": 0.01\n },\n {\n \"id\": \"bucket\",\n \"teamId\": \"balde\",\n \"teamBox\": [\n 28,\n 27,\n 28\n ],\n \"scale\": 0.01\n },\n {\n \"id\": \"binoculars\",\n \"teamId\": \"binoculo\",\n \"teamBox\": [\n 18,\n 15,\n 12\n ],\n \"scale\": 0.01\n },\n {\n \"id\": \"matches\",\n \"teamId\": \"fosforo\",\n \"teamBox\": [\n 5,\n 1.5,\n 3.5\n ],\n \"scale\": 0.01\n },\n {\n \"id\": \"pocket_knife\",\n \"teamId\": \"canivete\",\n \"teamBox\": [\n 11,\n 2.2,\n 3.2\n ],\n \"scale\": 0.01\n },\n {\n \"id\": \"screwdriver\",\n \"teamId\": \"chave_fenda\",\n \"teamBox\": [\n 22,\n 4,\n 4\n ],\n \"scale\": 0.01\n },\n {\n \"id\": \"adjustable_wrench\",\n \"teamId\": \"chave_inglesa\",\n \"teamBox\": [\n 25,\n 2,\n 6\n ],\n \"scale\": 0.01\n },\n {\n \"id\": \"hoe\",\n \"teamId\": \"enxada\",\n \"teamBox\": [\n 135,\n 6,\n 17\n ],\n \"scale\": 0.01\n },\n {\n \"id\": \"fire_extinguisher\",\n \"teamId\": \"extintor\",\n \"teamBox\": [\n 16.0794,\n 48,\n 16\n ],\n \"scale\": 0.009984\n },\n {\n \"id\": \"duct_tape\",\n \"teamId\": \"silver_tape\",\n \"teamBox\": [\n 10,\n 5,\n 10\n ],\n \"scale\": 0.01\n },\n {\n \"id\": \"camp_stove\",\n \"teamId\": \"fogareiro\",\n \"teamBox\": [\n 18,\n 10,\n 11\n ],\n \"scale\": 0.01\n },\n {\n \"id\": \"lighter\",\n \"teamId\": \"isqueiro\",\n \"teamBox\": [\n 2.5,\n 8,\n 1.2\n ],\n \"scale\": 0.01\n },\n {\n \"id\": \"lockpick_kit\",\n \"teamId\": \"kit_chaveiro\",\n \"teamBox\": [\n 10,\n 7,\n 2\n ],\n \"scale\": 0.01\n },\n {\n \"id\": \"sewing_kit\",\n \"teamId\": \"kit_costura\",\n \"teamBox\": [\n 9,\n 5,\n 3\n ],\n \"scale\": 0.01\n },\n {\n \"id\": \"car_jack\",\n \"teamId\": \"macaco\",\n \"teamBox\": [\n 30,\n 11,\n 11\n ],\n \"scale\": 0.01\n },\n {\n \"id\": \"mechanic_toolbox\",\n \"teamId\": \"kit_mecanico\",\n \"teamBox\": [\n 40,\n 20,\n 19.8\n ],\n \"scale\": 0.010034\n },\n {\n \"id\": \"gas_torch\",\n \"teamId\": \"macarico\",\n \"teamBox\": [\n 15.1,\n 42,\n 15\n ],\n \"scale\": 0.009978\n },\n {\n \"id\": \"inverter_welder\",\n \"teamId\": \"solda\",\n \"teamBox\": [\n 30,\n 22,\n 12.9\n ],\n \"scale\": 0.010026\n },\n {\n \"id\": \"pot\",\n \"teamId\": \"panela\",\n \"teamBox\": [\n 25,\n 15,\n 25\n ],\n \"scale\": 0.01\n },\n {\n \"id\": \"cordless_drill\",\n \"teamId\": \"parafusadeira\",\n \"teamBox\": [\n 22,\n 20,\n 7\n ],\n \"scale\": 0.01\n },\n {\n \"id\": \"flint_striker\",\n \"teamId\": \"pederneira\",\n \"teamBox\": [\n 11.1,\n 2,\n 1.5\n ],\n \"scale\": 0.00997\n },\n {\n \"id\": \"sharpening_stone\",\n \"teamId\": \"amolador\",\n \"teamBox\": [\n 20,\n 5,\n 2.5\n ],\n \"scale\": 0.01\n },\n {\n \"id\": \"shovel\",\n \"teamId\": \"pa\",\n \"teamBox\": [\n 110.3,\n 7,\n 22\n ],\n \"scale\": 0.009991\n },\n {\n \"id\": \"hacksaw\",\n \"teamId\": \"serra_arco\",\n \"teamBox\": [\n 42,\n 3,\n 12\n ],\n \"scale\": 0.01\n },\n {\n \"id\": \"handsaw\",\n \"teamId\": \"serrote\",\n \"teamBox\": [\n 50.01,\n 3.5,\n 13.021\n ],\n \"scale\": 0.009994\n },\n {\n \"id\": \"scissors\",\n \"teamId\": \"tesoura\",\n \"teamBox\": [\n 18,\n 1.5,\n 7\n ],\n \"scale\": 0.01\n },\n {\n \"id\": \"recurve_bow\",\n \"teamId\": \"arco\",\n \"teamBox\": [\n 12.9812,\n 1.98,\n 0.5\n ],\n \"scale\": 0.100385\n },\n {\n \"id\": \"crossbow\",\n \"teamId\": \"besta\",\n \"teamBox\": [\n 7,\n 1.2,\n 8.0191\n ],\n \"scale\": 0.09992\n },\n {\n \"id\": \"iron_pipe\",\n \"teamId\": \"cano\",\n \"teamBox\": [\n 8.01,\n 0.354,\n 0.354\n ],\n \"scale\": 0.099204\n },\n {\n \"id\": \"meat_cleaver\",\n \"teamId\": \"cutelo\",\n \"teamBox\": [\n 3.3,\n 0.3,\n 1.2\n ],\n \"scale\": 0.1\n },\n {\n \"id\": \"slingshot\",\n \"teamId\": \"estilingue\",\n \"teamBox\": [\n 1.3013,\n 1.5055,\n 0.252\n ],\n \"scale\": 0.099578\n },\n {\n \"id\": \"knife\",\n \"teamId\": \"faca_cozinha\",\n \"teamBox\": [\n 2.5028,\n 0.3,\n 0.404\n ],\n \"scale\": 0.099632\n },\n {\n \"id\": \"tactical_knife\",\n \"teamId\": \"faca_tatica\",\n \"teamBox\": [\n 2.6028,\n 0.282,\n 0.454\n ],\n \"scale\": 0.099433\n },\n {\n \"id\": \"arrows_and_bolts\",\n \"teamId\": \"flecha\",\n \"teamBox\": [\n 7,\n 0.25,\n 0.4\n ],\n \"scale\": 0.1\n },\n {\n \"id\": \"sickle\",\n \"teamId\": \"foice\",\n \"teamBox\": [\n 4.0085,\n 0.352,\n 3.4971\n ],\n \"scale\": 0.099767\n },\n {\n \"id\": \"cast_iron_skillet\",\n \"teamId\": \"frigideira\",\n \"teamBox\": [\n 4.3,\n 0.5,\n 2.5\n ],\n \"scale\": 0.1\n },\n {\n \"id\": \"improvised_spear\",\n \"teamId\": \"lanca\",\n \"teamBox\": [\n 16,\n 0.35,\n 0.35\n ],\n \"scale\": 0.1\n },\n {\n \"id\": \"hatchet\",\n \"teamId\": \"machadinha\",\n \"teamBox\": [\n 3.5016,\n 0.5,\n 1.3047\n ],\n \"scale\": 0.099866\n },\n {\n \"id\": \"sledgehammer\",\n \"teamId\": \"marreta\",\n \"teamBox\": [\n 9,\n 1.2,\n 2.5\n ],\n \"scale\": 0.1\n },\n {\n \"id\": \"chainsaw\",\n \"teamId\": \"motosserra\",\n \"teamBox\": [\n 4.5,\n 2.6,\n 2.3\n ],\n \"scale\": 0.1\n },\n {\n \"id\": \"pickaxe\",\n \"teamId\": \"picareta\",\n \"teamBox\": [\n 9,\n 0.4,\n 3.5352\n ],\n \"scale\": 0.099667\n },\n {\n \"id\": \"baseball_bat\",\n \"teamId\": \"taco\",\n \"teamBox\": [\n 8.6,\n 0.704,\n 0.704\n ],\n \"scale\": 0.099621\n },\n {\n \"id\": \"police_baton\",\n \"teamId\": \"tonfa\",\n \"teamBox\": [\n 5,\n 1,\n 0.45\n ],\n \"scale\": 0.1\n },\n {\n \"id\": \"wire_roll\",\n \"teamId\": \"arame\",\n \"teamBox\": [\n 1.404,\n 0.5,\n 1.404\n ],\n \"scale\": 0.09981\n },\n {\n \"id\": \"barbed_wire\",\n \"teamId\": \"arame_farpado\",\n \"teamBox\": [\n 3,\n 1.2,\n 3\n ],\n \"scale\": 0.1\n },\n {\n \"id\": \"glass_shards\",\n \"teamId\": \"cacos\",\n \"teamBox\": [\n 1.205,\n 0.5149,\n 1.0049\n ],\n \"scale\": 0.098729\n },\n {\n \"id\": \"sheet_metal\",\n \"teamId\": \"chapa\",\n \"teamBox\": [\n 6,\n 0.03,\n 4.5\n ],\n \"scale\": 0.1\n },\n {\n \"id\": \"cement_bag\",\n \"teamId\": \"cimento\",\n \"teamBox\": [\n 5,\n 1.011,\n 3\n ],\n \"scale\": 0.099636\n },\n {\n \"id\": \"epoxy_glue\",\n \"teamId\": \"cola\",\n \"teamBox\": [\n 1,\n 0.6,\n 0.3\n ],\n \"scale\": 0.1\n },\n {\n \"id\": \"electronic_components\",\n \"teamId\": \"componentes\",\n \"teamBox\": [\n 1,\n 0.2,\n 0.8\n ],\n \"scale\": 0.1\n },\n {\n \"id\": \"rope\",\n \"teamId\": \"corda\",\n \"teamBox\": [\n 1.5,\n 0.8,\n 1.5\n ],\n \"scale\": 0.1\n },\n {\n \"id\": \"copper_wire\",\n \"teamId\": \"fio_cobre\",\n \"teamBox\": [\n 0.8,\n 0.302,\n 0.8\n ],\n \"scale\": 0.099779\n },\n {\n \"id\": \"pet_bottle\",\n \"teamId\": \"garrafa_pet\",\n \"teamBox\": [\n 1.06,\n 3.3,\n 1.06\n ],\n \"scale\": 0.09937\n },\n {\n \"id\": \"glass_bottle\",\n \"teamId\": \"garrafa_vidro\",\n \"teamBox\": [\n 0.75,\n 2.6,\n 0.75\n ],\n \"scale\": 0.1\n },\n {\n \"id\": \"empty_can\",\n \"teamId\": \"lata_vazia\",\n \"teamBox\": [\n 0.664,\n 1.207,\n 0.664\n ],\n \"scale\": 0.099405\n },\n {\n \"id\": \"firewood\",\n \"teamId\": \"lenha\",\n \"teamBox\": [\n 4,\n 1.2,\n 1.6\n ],\n \"scale\": 0.1\n },\n {\n \"id\": \"tarp\",\n \"teamId\": \"lona\",\n \"teamBox\": [\n 3.5,\n 1.002,\n 2.502\n ],\n \"scale\": 0.099907\n },\n {\n \"id\": \"screws\",\n \"teamId\": \"parafusos\",\n \"teamBox\": [\n 0.9,\n 0.5,\n 0.5\n ],\n \"scale\": 0.1\n },\n {\n \"id\": \"nails\",\n \"teamId\": \"pregos\",\n \"teamBox\": [\n 1.3,\n 0.6,\n 0.5\n ],\n \"scale\": 0.1\n },\n {\n \"id\": \"raffia_sack\",\n \"teamId\": \"saco_areia\",\n \"teamBox\": [\n 4,\n 0.2,\n 3\n ],\n \"scale\": 0.1\n },\n {\n \"id\": \"scrap_metal\",\n \"teamId\": \"sucata\",\n \"teamBox\": [\n 2,\n 0.805,\n 1.5\n ],\n \"scale\": 0.099793\n },\n {\n \"id\": \"bricks\",\n \"teamId\": \"tijolo\",\n \"teamBox\": [\n 1.911,\n 1.8,\n 2.9\n ],\n \"scale\": 0.099808\n },\n {\n \"id\": \"rag\",\n \"teamId\": \"trapo\",\n \"teamBox\": [\n 2.2,\n 0.252,\n 1.8\n ],\n \"scale\": 0.099735\n },\n {\n \"id\": \"rebar\",\n \"teamId\": \"vergalhao\",\n \"teamBox\": [\n 12.7,\n 0.16,\n 0.16\n ],\n \"scale\": 0.1\n },\n {\n \"id\": \"lubricant_spray\",\n \"teamId\": \"lubrificante\",\n \"teamBox\": [\n 0.504,\n 1.7,\n 0.504\n ],\n \"scale\": 0.09947\n },\n {\n \"id\": \"army_camouflage_uniform\",\n \"teamId\": \"farda_eb\",\n \"teamBox\": [\n 0.4,\n 0.1005,\n 0.32\n ],\n \"scale\": 1\n },\n {\n \"id\": \"backpack\",\n \"teamId\": \"mochila_escolar\",\n \"teamBox\": [\n 0.3,\n 0.3,\n 0.2\n ],\n \"scale\": 1\n },\n {\n \"id\": \"ballistic_vest\",\n \"teamId\": \"colete\",\n \"teamBox\": [\n 0.4,\n 0.07,\n 0.45\n ],\n \"scale\": 1\n },\n {\n \"id\": \"battery_9v\",\n \"teamId\": \"bateria_9v\",\n \"teamBox\": [\n 0.0262,\n 0.049,\n 0.0182\n ],\n \"scale\": 1\n },\n {\n \"id\": \"bean_seeds\",\n \"teamId\": \"sem_feijao\",\n \"teamBox\": [\n 0.1,\n 0.15,\n 0.02\n ],\n \"scale\": 1\n },\n {\n \"id\": \"beekeeper_suit\",\n \"teamId\": \"apicultor\",\n \"teamBox\": [\n 0.4,\n 0.1,\n 0.33\n ],\n \"scale\": 1\n },\n {\n \"id\": \"candles\",\n \"teamId\": \"vela\",\n \"teamBox\": [\n 0.06,\n 0.12,\n 0.06\n ],\n \"scale\": 1\n },\n {\n \"id\": \"car_alarm_remote\",\n \"teamId\": \"controle_alarme\",\n \"teamBox\": [\n 0.04,\n 0.07011,\n 0.012\n ],\n \"scale\": 1\n },\n {\n \"id\": \"car_battery_12v\",\n \"teamId\": \"bateria_12v\",\n \"teamBox\": [\n 0.24,\n 0.19,\n 0.1725\n ],\n \"scale\": 1\n },\n {\n \"id\": \"car_key\",\n \"teamId\": \"chave_carro\",\n \"teamBox\": [\n 0.06,\n 0.045,\n 0.015\n ],\n \"scale\": 1\n },\n {\n \"id\": \"cash\",\n \"teamId\": \"dinheiro\",\n \"teamBox\": [\n 0.155,\n 0.01,\n 0.065\n ],\n \"scale\": 1\n },\n {\n \"id\": \"cassava_cuttings\",\n \"teamId\": \"maniva\",\n \"teamBox\": [\n 0.7,\n 0.12,\n 0.12\n ],\n \"scale\": 1\n },\n {\n \"id\": \"cb_radio\",\n \"teamId\": \"radio_px\",\n \"teamBox\": [\n 0.25,\n 0.08,\n 0.2\n ],\n \"scale\": 1\n },\n {\n \"id\": \"cell_key\",\n \"teamId\": \"chave_cela\",\n \"teamBox\": [\n 0.12,\n 0.03,\n 0.008\n ],\n \"scale\": 1\n },\n {\n \"id\": \"charcoal_bag\",\n \"teamId\": \"carvao\",\n \"teamBox\": [\n 0.3,\n 0.12,\n 0.4\n ],\n \"scale\": 1\n },\n {\n \"id\": \"cigarettes\",\n \"teamId\": \"cigarro\",\n \"teamBox\": [\n 0.055,\n 0.088,\n 0.022\n ],\n \"scale\": 1\n },\n {\n \"id\": \"city_map\",\n \"teamId\": \"mapa_cidade\",\n \"teamBox\": [\n 0.11,\n 0.01,\n 0.25\n ],\n \"scale\": 1\n },\n {\n \"id\": \"combat_boots\",\n \"teamId\": \"coturno\",\n \"teamBox\": [\n 0.3,\n 0.2,\n 0.22\n ],\n \"scale\": 1\n },\n {\n \"id\": \"cooler_box\",\n \"teamId\": \"caixa_termica\",\n \"teamBox\": [\n 0.32,\n 0.25,\n 0.23\n ],\n \"scale\": 1\n },\n {\n \"id\": \"corn_seeds\",\n \"teamId\": \"sem_milho\",\n \"teamBox\": [\n 0.1,\n 0.15,\n 0.02\n ],\n \"scale\": 1\n },\n {\n \"id\": \"crossbody_bag\",\n \"teamId\": \"bolsa\",\n \"teamBox\": [\n 0.25,\n 0.2,\n 0.08\n ],\n \"scale\": 1\n },\n {\n \"id\": \"delivery_bag\",\n \"teamId\": \"bag_entregador\",\n \"teamBox\": [\n 0.48,\n 0.45,\n 0.42\n ],\n \"scale\": 1\n },\n {\n \"id\": \"denim_jacket\",\n \"teamId\": \"jaqueta_jeans\",\n \"teamBox\": [\n 0.4,\n 0.08,\n 0.3025\n ],\n \"scale\": 1\n },\n {\n \"id\": \"diesel\",\n \"teamId\": \"diesel\",\n \"teamBox\": [\n 0.091,\n 0.26,\n 0.091\n ],\n \"scale\": 1\n },\n {\n \"id\": \"diy_magazine\",\n \"teamId\": \"revista_receita\",\n \"teamBox\": [\n 0.21,\n 0.28,\n 0.00805\n ],\n \"scale\": 1\n },\n {\n \"id\": \"dog_tag\",\n \"teamId\": \"plaqueta\",\n \"teamBox\": [\n 0.03,\n 0.003,\n 0.05038\n ],\n \"scale\": 1\n },\n {\n \"id\": \"electric_fence_energizer\",\n \"teamId\": \"eletrificador\",\n \"teamBox\": [\n 0.25,\n 0.2,\n 0.1502\n ],\n \"scale\": 1\n },\n {\n \"id\": \"extension_cord\",\n \"teamId\": \"extensao\",\n \"teamBox\": [\n 0.228,\n 0.08,\n 0.23\n ],\n \"scale\": 1\n },\n {\n \"id\": \"fanny_pack\",\n \"teamId\": \"pochete\",\n \"teamBox\": [\n 0.25,\n 0.1,\n 0.12\n ],\n \"scale\": 1\n },\n {\n \"id\": \"farmers_almanac\",\n \"teamId\": \"almanaque\",\n \"teamBox\": [\n 0.15,\n 0.21,\n 0.0151\n ],\n \"scale\": 1\n },\n {\n \"id\": \"fertilizer_bag\",\n \"teamId\": \"adubo\",\n \"teamBox\": [\n 0.45,\n 0.13,\n 0.3\n ],\n \"scale\": 1\n },\n {\n \"id\": \"firefighter_suit\",\n \"teamId\": \"bombeiro\",\n \"teamBox\": [\n 0.55,\n 0.2,\n 0.4\n ],\n \"scale\": 1\n },\n {\n \"id\": \"fishing_net\",\n \"teamId\": \"rede_pesca\",\n \"teamBox\": [\n 0.35,\n 0.15,\n 0.3\n ],\n \"scale\": 1\n },\n {\n \"id\": \"fishing_rod\",\n \"teamId\": \"vara_pesca\",\n \"teamBox\": [\n 1.8,\n 0.04,\n 0.04\n ],\n \"scale\": 1\n },\n {\n \"id\": \"fishing_tackle_box\",\n \"teamId\": \"kit_pesca\",\n \"teamBox\": [\n 0.3,\n 0.1,\n 0.18\n ],\n \"scale\": 1\n },\n {\n \"id\": \"flip_flops\",\n \"teamId\": \"chinelo\",\n \"teamBox\": [\n 0.29,\n 0.03,\n 0.23\n ],\n \"scale\": 1\n },\n {\n \"id\": \"folding_solar_panel\",\n \"teamId\": \"painel_solar\",\n \"teamBox\": [\n 0.396,\n 0.296,\n 0.0506\n ],\n \"scale\": 1\n },\n {\n \"id\": \"gas_cartridge\",\n \"teamId\": \"cartucho_gas\",\n \"teamBox\": [\n 0.111,\n 0.165,\n 0.111\n ],\n \"scale\": 1\n },\n {\n \"id\": \"gasoline\",\n \"teamId\": \"gasolina\",\n \"teamBox\": [\n 0.091,\n 0.26,\n 0.091\n ],\n \"scale\": 1\n },\n {\n \"id\": \"generator_key\",\n \"teamId\": \"chave_gerador\",\n \"teamBox\": [\n 0.08,\n 0.03,\n 0.006\n ],\n \"scale\": 1\n },\n {\n \"id\": \"hard_hat\",\n \"teamId\": \"capacete_obra\",\n \"teamBox\": [\n 0.24958,\n 0.15,\n 0.3\n ],\n \"scale\": 1\n },\n {\n \"id\": \"headlamp\",\n \"teamId\": \"lanterna_cabeca\",\n \"teamBox\": [\n 0.09,\n 0.06,\n 0.05\n ],\n \"scale\": 1\n },\n {\n \"id\": \"hoodie\",\n \"teamId\": \"moletom\",\n \"teamBox\": [\n 0.38,\n 0.08,\n 0.28\n ],\n \"scale\": 1\n },\n {\n \"id\": \"janitor_keys\",\n \"teamId\": \"molho_zelador\",\n \"teamBox\": [\n 0.12125,\n 0.10081,\n 0.02\n ],\n \"scale\": 1\n },\n {\n \"id\": \"jeans\",\n \"teamId\": \"calca_jeans\",\n \"teamBox\": [\n 0.35,\n 0.06,\n 0.22\n ],\n \"scale\": 1\n },\n {\n \"id\": \"kale_and_lettuce_seeds\",\n \"teamId\": \"sem_couve\",\n \"teamBox\": [\n 0.09,\n 0.13,\n 0.015\n ],\n \"scale\": 1\n },\n {\n \"id\": \"kerosene\",\n \"teamId\": \"querosene\",\n \"teamBox\": [\n 0.091,\n 0.26,\n 0.091\n ],\n \"scale\": 1\n },\n {\n \"id\": \"laptop\",\n \"teamId\": \"notebook\",\n \"teamBox\": [\n 0.36,\n 0.0252,\n 0.251\n ],\n \"scale\": 1\n },\n {\n \"id\": \"leather_motorcycle_jacket\",\n \"teamId\": \"jaqueta_couro\",\n \"teamBox\": [\n 0.45,\n 0.1,\n 0.355\n ],\n \"scale\": 1\n },\n {\n \"id\": \"leather_motorcycle_pants\",\n \"teamId\": \"calca_couro\",\n \"teamBox\": [\n 0.4,\n 0.0902,\n 0.3\n ],\n \"scale\": 1\n },\n {\n \"id\": \"leather_work_gloves\",\n \"teamId\": \"luva_couro\",\n \"teamBox\": [\n 0.25,\n 0.03,\n 0.12\n ],\n \"scale\": 1\n },\n {\n \"id\": \"led_camp_lantern\",\n \"teamId\": \"lampiao_led\",\n \"teamBox\": [\n 0.11,\n 0.2,\n 0.11\n ],\n \"scale\": 1\n },\n {\n \"id\": \"magazine_arm_guard\",\n \"teamId\": \"braco_revista\",\n \"teamBox\": [\n 0.3,\n 0.05899,\n 0.15022\n ],\n \"scale\": 1\n },\n {\n \"id\": \"magazines_and_comics\",\n \"teamId\": \"revista_passa\",\n \"teamBox\": [\n 0.17,\n 0.26,\n 0.0101\n ],\n \"scale\": 1\n },\n {\n \"id\": \"master_key\",\n \"teamId\": \"chave_mestra\",\n \"teamBox\": [\n 0.09,\n 0.035,\n 0.006\n ],\n \"scale\": 1\n },\n {\n \"id\": \"mechanic_coveralls\",\n \"teamId\": \"macacao\",\n \"teamBox\": [\n 0.4,\n 0.09,\n 0.3\n ],\n \"scale\": 1\n },\n {\n \"id\": \"military_backpack\",\n \"teamId\": \"mochila_militar\",\n \"teamBox\": [\n 0.35,\n 0.6,\n 0.3\n ],\n \"scale\": 1\n },\n {\n \"id\": \"military_radio\",\n \"teamId\": \"radio_militar\",\n \"teamBox\": [\n 0.3,\n 0.2,\n 0.25\n ],\n \"scale\": 1\n },\n {\n \"id\": \"mobile_phone\",\n \"teamId\": \"celular\",\n \"teamBox\": [\n 0.077,\n 0.16,\n 0.009\n ],\n \"scale\": 1\n },\n {\n \"id\": \"motor_oil\",\n \"teamId\": \"oleo_motor\",\n \"teamBox\": [\n 0.1,\n 0.26,\n 0.07\n ],\n \"scale\": 1\n },\n {\n \"id\": \"night_vision_goggles\",\n \"teamId\": \"nvg\",\n \"teamBox\": [\n 0.15,\n 0.1,\n 0.11\n ],\n \"scale\": 1\n },\n {\n \"id\": \"note\",\n \"teamId\": \"bilhete\",\n \"teamBox\": [\n 0.15,\n 0.002,\n 0.1\n ],\n \"scale\": 1\n },\n {\n \"id\": \"padded_coat\",\n \"teamId\": \"casaco_frio\",\n \"teamBox\": [\n 0.45,\n 0.15,\n 0.35\n ],\n \"scale\": 1\n },\n {\n \"id\": \"padlock_key\",\n \"teamId\": \"cadeado_chave\",\n \"teamBox\": [\n 0.05,\n 0.08078,\n 0.025\n ],\n \"scale\": 1\n },\n {\n \"id\": \"photo\",\n \"teamId\": \"foto\",\n \"teamBox\": [\n 0.102,\n 0.002,\n 0.152\n ],\n \"scale\": 1\n },\n {\n \"id\": \"portable_generator\",\n \"teamId\": \"gerador\",\n \"teamBox\": [\n 0.5,\n 0.42,\n 0.43345\n ],\n \"scale\": 1\n },\n {\n \"id\": \"power_bank\",\n \"teamId\": \"power_bank\",\n \"teamBox\": [\n 0.15,\n 0.07,\n 0.0158\n ],\n \"scale\": 1\n },\n {\n \"id\": \"pumpkin_seeds\",\n \"teamId\": \"sem_abobora\",\n \"teamBox\": [\n 0.09,\n 0.13,\n 0.015\n ],\n \"scale\": 1\n },\n {\n \"id\": \"raincoat\",\n \"teamId\": \"capa_chuva\",\n \"teamBox\": [\n 0.3,\n 0.04,\n 0.25\n ],\n \"scale\": 1\n },\n {\n \"id\": \"road_map\",\n \"teamId\": \"mapa_rodoviario\",\n \"teamBox\": [\n 0.11,\n 0.01,\n 0.25\n ],\n \"scale\": 1\n },\n {\n \"id\": \"rolling_suitcase\",\n \"teamId\": \"mala\",\n \"teamBox\": [\n 0.4,\n 0.65,\n 0.25\n ],\n \"scale\": 1\n },\n {\n \"id\": \"rubber_boots\",\n \"teamId\": \"bota_borracha\",\n \"teamBox\": [\n 0.3,\n 0.35,\n 0.223\n ],\n \"scale\": 1\n },\n {\n \"id\": \"safe_key\",\n \"teamId\": \"chave_cofre\",\n \"teamBox\": [\n 0.06995,\n 0.0249,\n 0.005\n ],\n \"scale\": 1\n },\n {\n \"id\": \"safety_goggles\",\n \"teamId\": \"oculos\",\n \"teamBox\": [\n 0.16,\n 0.06,\n 0.08\n ],\n \"scale\": 1\n },\n {\n \"id\": \"sheet_metal_forearm_guard\",\n \"teamId\": \"braco_chapa\",\n \"teamBox\": [\n 0.3,\n 0.0981,\n 0.11995\n ],\n \"scale\": 1\n },\n {\n \"id\": \"shopping_bag\",\n \"teamId\": \"sacola\",\n \"teamBox\": [\n 0.3,\n 0.02,\n 0.2\n ],\n \"scale\": 1\n },\n {\n \"id\": \"shopping_cart\",\n \"teamId\": \"carrinho_merc\",\n \"teamBox\": [\n 0.55,\n 0.98,\n 0.95\n ],\n \"scale\": 1\n },\n {\n \"id\": \"skill_book\",\n \"teamId\": \"livro_hab\",\n \"teamBox\": [\n 0.1615,\n 0.23,\n 0.0402\n ],\n \"scale\": 1\n },\n {\n \"id\": \"snare_trap\",\n \"teamId\": \"armadilha_laco\",\n \"teamBox\": [\n 0.15,\n 0.03,\n 0.15\n ],\n \"scale\": 1\n },\n {\n \"id\": \"sneakers\",\n \"teamId\": \"tenis\",\n \"teamBox\": [\n 0.29731,\n 0.12,\n 0.12\n ],\n \"scale\": 1\n },\n {\n \"id\": \"tactical_vest\",\n \"teamId\": \"colete_tatico\",\n \"teamBox\": [\n 0.35,\n 0.1,\n 0.4\n ],\n \"scale\": 1\n },\n {\n \"id\": \"technical_manual\",\n \"teamId\": \"livro_tecnico\",\n \"teamBox\": [\n 0.21,\n 0.3,\n 0.0404\n ],\n \"scale\": 1\n },\n {\n \"id\": \"tool_belt\",\n \"teamId\": \"cinto_ferramentas\",\n \"teamBox\": [\n 0.35,\n 0.1,\n 0.25\n ],\n \"scale\": 1\n },\n {\n \"id\": \"trash_bag\",\n \"teamId\": \"saco_lixo\",\n \"teamBox\": [\n 0.25,\n 0.025,\n 0.2\n ],\n \"scale\": 1\n },\n {\n \"id\": \"trekking_backpack_70l\",\n \"teamId\": \"cargueira\",\n \"teamBox\": [\n 0.38,\n 0.75,\n 0.3\n ],\n \"scale\": 1\n },\n {\n \"id\": \"tshirt\",\n \"teamId\": \"camiseta\",\n \"teamBox\": [\n 0.3,\n 0.04,\n 0.22\n ],\n \"scale\": 1\n },\n {\n \"id\": \"watering_can\",\n \"teamId\": \"regador\",\n \"teamBox\": [\n 0.40001,\n 0.25789,\n 0.18\n ],\n \"scale\": 1\n },\n {\n \"id\": \"wheelbarrow\",\n \"teamId\": \"carrinho_mao\",\n \"teamBox\": [\n 0.64651,\n 0.65148,\n 1.5\n ],\n \"scale\": 1\n },\n {\n \"id\": \"windup_alarm_clock\",\n \"teamId\": \"despertador\",\n \"teamBox\": [\n 0.1089,\n 0.125,\n 0.05525\n ],\n \"scale\": 1\n }\n]\n","import type { ItemModelBuilder } from './registry'\n\n/**\n * `MODELS[\"feijao_lata\"]` of the Itens do Vale Cinzento showcase (`armas-itens__itens-vale-cinzento.js` L145), ported as it is: same units, same parts, same order, same materials by tag.\n * It draws in the units of the page; `data/models.json` gives the scale to metres of the item `canned_beans`.\n */\nexport const cannedBeans: ItemModelBuilder = ({ mesh, cyl, torus, G, metal, paper, food }) => { const m = metal(0x8d9096); return G(mesh(cyl(.32, .32, .52), m), mesh(cyl(.326, .326, .34, 14), food(0x9b3a24)), mesh(cyl(.33, .33, .06), paper(0xe2c36a), [0, .02, 0]), mesh(torus(.31, .025), m, [0, .26, 0], [Math.PI / 2, 0, 0]), mesh(torus(.31, .025), m, [0, -.26, 0], [Math.PI / 2, 0, 0])); }\n","import type { ItemModelBuilder } from './registry'\n\n/**\n * `MODELS[\"agua_500\"]` of the Itens do Vale Cinzento showcase (`armas-itens__itens-vale-cinzento.js` L146), ported as it is: same units, same parts, same order, same materials by tag.\n * It draws in the units of the page; `data/models.json` gives the scale to metres of the item `water_bottle`.\n */\nexport const waterBottle: ItemModelBuilder = ({ mesh, cyl, lathe, G, plastic, paper, glass }) => G(mesh(lathe([[0, -.6], [.2, -.6], [.22, -.5], [.22, .2], [.19, .32], [.09, .45], [.08, .55], [0, .55]]), glass(0x8fc3dc, .55)), mesh(cyl(.085, .085, .1, 12), plastic(0x2c5d8a), [0, .6, 0]), mesh(cyl(.225, .225, .22, 16), paper(0xe9ecef), [0, -.15, 0]), mesh(cyl(.226, .226, .05, 16), plastic(0x3a78a8), [0, -.12, 0]))\n","import type { ItemModelBuilder } from './registry'\n\n/**\n * `MODELS[\"arroz\"]` of the Itens do Vale Cinzento showcase (`armas-itens__itens-vale-cinzento.js` L147), ported as it is: same units, same parts, same order, same materials by tag.\n * It draws in the units of the page; `data/models.json` gives the scale to metres of the item `rice`.\n */\nexport const rice: ItemModelBuilder = ({ mesh, bx, G, paper, food }) => G(mesh(bx(.7, .95, .28), paper(0xe6dcc0)), mesh(bx(.72, .12, .1), paper(0xd5c9a8), [0, .52, 0]), mesh(bx(.5, .3, .02), food(0xb5521f), [0, .05, .15]), mesh(bx(.3, .1, .02), paper(0x3f7a45), [0, -.25, .15]))\n","import type { ItemModelBuilder } from './registry'\n\n/**\n * `MODELS[\"racao_militar\"]` of the Itens do Vale Cinzento showcase (`armas-itens__itens-vale-cinzento.js` L148), ported as it is: same units, same parts, same order, same materials by tag.\n * It draws in the units of the page; `data/models.json` gives the scale to metres of the item `military_ration`.\n */\nexport const militaryRation: ItemModelBuilder = ({ mesh, bx, G, plastic, paper }) => G(mesh(bx(.75, 1, .22), plastic(0x5a6146)), mesh(bx(.77, .1, .23), plastic(0x474d37), [0, .48, 0]), mesh(bx(.5, .14, .01), paper(0x22251f), [0, .18, .115]), mesh(bx(.36, .06, .01), paper(0x22251f), [0, -.02, .115]))\n","import type { ItemModelBuilder } from './registry'\n\n/**\n * `MODELS[\"cachaca\"]` of the Itens do Vale Cinzento showcase (`armas-itens__itens-vale-cinzento.js` L149), ported as it is: same units, same parts, same order, same materials by tag.\n * It draws in the units of the page; `data/models.json` gives the scale to metres of the item `cachaca`.\n */\nexport const cachaca: ItemModelBuilder = ({ mesh, cyl, lathe, G, wood, paper, food, glass }) => G(mesh(lathe([[0, -.6], [.25, -.6], [.27, -.52], [.27, .1], [.2, .25], [.09, .35], [.09, .58], [0, .58]]), glass(0xc28a2a, .78)), mesh(cyl(.08, .07, .14, 10), wood(0x8a6a44), [0, .64, 0]), mesh(cyl(.275, .275, .34, 16), paper(0xe9e1cc), [0, -.25, 0]), mesh(cyl(.276, .276, .06, 16), food(0x7a2f1f), [0, -.15, 0]))\n","import type { ItemModelBuilder } from './registry'\n\n/**\n * `MODELS[\"kit_ps\"]` of the Itens do Vale Cinzento showcase (`armas-itens__itens-vale-cinzento.js` L150), ported as it is: same units, same parts, same order, same materials by tag.\n * It draws in the units of the page; `data/models.json` gives the scale to metres of the item `first_aid_kit`.\n */\nexport const firstAidKit: ItemModelBuilder = ({ mesh, bx, torus, G, plastic }) => { const r = plastic(0xb23a2c); return G(mesh(bx(1.05, .72, .38), plastic(0xe6e3d8)), mesh(bx(1.07, .06, .4), plastic(0xbdb8aa), [0, 0, 0]), mesh(bx(.36, .1, .02), r, [0, .1, .2]), mesh(bx(.1, .36, .02), r, [0, .1, .2]), mesh(torus(.16, .035, Math.PI), plastic(0x55534c), [0, .36, 0])); }\n","import type { ItemModelBuilder } from './registry'\n\n/**\n * `MODELS[\"atadura\"]` of the Itens do Vale Cinzento showcase (`armas-itens__itens-vale-cinzento.js` L151), ported as it is: same units, same parts, same order, same materials by tag.\n * It draws in the units of the page; `data/models.json` gives the scale to metres of the item `bandage`.\n */\nexport const bandage: ItemModelBuilder = ({ mesh, cyl, bx, G, cloth }) => { const c = cloth(0xece5d2); return G(mesh(cyl(.34, .34, .38, 18), c, [0, 0, 0], [Math.PI / 2, 0, 0]), mesh(cyl(.1, .1, .4, 12), cloth(0x8a8577), [0, 0, 0], [Math.PI / 2, 0, 0]), mesh(bx(.36, .02, .36), c, [.2, -.33, .05], [0, 0, -.25]), mesh(bx(.3, .02, .36), c, [.5, -.4, .05], [0, 0, -.05])); }\n","import type { ItemModelBuilder } from './registry'\n\n/**\n * `MODELS[\"amoxicilina\"]` of the Itens do Vale Cinzento showcase (`armas-itens__itens-vale-cinzento.js` L152), ported as it is: same units, same parts, same order, same materials by tag.\n * It draws in the units of the page; `data/models.json` gives the scale to metres of the item `amoxicillin`.\n */\nexport const amoxicillin: ItemModelBuilder = ({ T, mesh, bx, G, metal, plastic, paper }) => G(mesh(bx(.8, .42, .24), paper(0xf0eee6)), mesh(bx(.81, .1, .25), plastic(0x4e7287), [0, .1, 0]), mesh(bx(.6, .04, .3), metal(0xb9bdc0), [.15, -.24, .25], [0, .3, 0]), ...[0, 1, 2, 3].map(k => mesh(new T.SphereGeometry(.05, 10, 8), plastic(0xd9a441), [-.05 + k * .14, -.21, .3], [0, 0, 0], [1, .6, 1])))\n","import type { ItemModelBuilder } from './registry'\n\n/**\n * `MODELS[\"pe_cabra\"]` of the Itens do Vale Cinzento showcase (`armas-itens__itens-vale-cinzento.js` L153), ported as it is: same units, same parts, same order, same materials by tag.\n * It draws in the units of the page; `data/models.json` gives the scale to metres of the item `crowbar`.\n */\nexport const crowbar: ItemModelBuilder = ({ T, mesh, cyl, G, metal }) => { const c = new T.CatmullRomCurve3([[0, -.8, 0], [0, .45, 0], [.02, .62, 0], [.12, .72, 0], [.26, .7, 0], [.32, .6, 0]].map(p => new T.Vector3(...p))); return G(mesh(new T.TubeGeometry(c, 30, .055, 8), metal(0x9b2a1f)), mesh(cyl(.02, .055, .14, 8), metal(0x3a3c3e), [0, -.86, 0])); }\n","import type { ItemModelBuilder } from './registry'\n\n/**\n * `MODELS[\"martelo\"]` of the Itens do Vale Cinzento showcase (`armas-itens__itens-vale-cinzento.js` L154), ported as it is: same units, same parts, same order, same materials by tag.\n * It draws in the units of the page; `data/models.json` gives the scale to metres of the item `hammer`.\n */\nexport const hammer: ItemModelBuilder = ({ T, mesh, cyl, bx, G, metal, wood, plastic }) => G(mesh(cyl(.05, .065, 1.1, 10), wood(0x8a643c), [0, -.15, 0]), mesh(cyl(.07, .07, .3, 10), plastic(0x22251f), [0, -.6, 0]), mesh(bx(.28, .15, .15), metal(0x55595d), [.05, .45, 0]), mesh(cyl(.08, .08, .1, 12), metal(0x55595d), [.22, .45, 0], [0, 0, Math.PI / 2]), mesh(new T.ConeGeometry(.06, .3, 6), metal(0x55595d), [-.22, .5, .035], [0, 0, 1.9]), mesh(new T.ConeGeometry(.06, .3, 6), metal(0x55595d), [-.22, .5, -.035], [0, 0, 1.9]))\n","import type { ItemModelBuilder } from './registry'\n\n/**\n * `MODELS[\"facao\"]` of the Itens do Vale Cinzento showcase (`armas-itens__itens-vale-cinzento.js` L155), ported as it is: same units, same parts, same order, same materials by tag.\n * It draws in the units of the page; `data/models.json` gives the scale to metres of the item `machete`.\n */\nexport const machete: ItemModelBuilder = ({ mesh, cyl, bx, extrude, G, metal, wood }) => G(mesh(extrude([[0, 0], [1.25, .05], [1.4, .14], [1.3, .26], [0, .2]], .03), metal(0xa9adb0), [-.55, 0, 0]), mesh(bx(.45, .2, .1), wood(0x3b2a20), [-.78, .1, .015]), ...[-.9, -.68].map(x => mesh(cyl(.025, .025, .12, 8), metal(0xb8913a), [x, .1, .015], [Math.PI / 2, 0, 0])))\n","import type { ItemModelBuilder } from './registry'\n\n/**\n * `MODELS[\"machado\"]` of the Itens do Vale Cinzento showcase (`armas-itens__itens-vale-cinzento.js` L156), ported as it is: same units, same parts, same order, same materials by tag.\n * It draws in the units of the page; `data/models.json` gives the scale to metres of the item `axe`.\n */\nexport const axe: ItemModelBuilder = ({ M, mesh, cyl, bx, extrude, G, metal, wood }) => G(mesh(cyl(.05, .06, 1.5, 10), wood(0x9a7448), [0, -.1, 0]), mesh(extrude([[0, 0], [.42, -.16], [.5, .05], [.48, .3], [.4, .42], [0, .22]], .07), metal(0x6c7075), [.02, .38, -.05]), mesh(bx(.12, .26, .14), metal(0x4a4d50), [0, .5, 0]), mesh(bx(.1, .2, .08), M(0x9b2a1f, \"plastic\"), [0, .55, 0]))\n","import type { ItemModelBuilder } from './registry'\n\n/**\n * `MODELS[\"taco_pregos\"]` of the Itens do Vale Cinzento showcase (`armas-itens__itens-vale-cinzento.js` L157), ported as it is: same units, same parts, same order, same materials by tag.\n * It draws in the units of the page; `data/models.json` gives the scale to metres of the item `nail_bat`.\n */\nexport const nailBat: ItemModelBuilder = ({ mesh, cyl, lathe, G, metal, wood }) => { const g = G(mesh(lathe([[0, -.85], [.05, -.85], [.05, -.8], [.035, -.75], [.04, -.2], [.09, .3], [.11, .7], [.09, .82], [0, .84]], 14), wood(0xb08a5a))); const nm = metal(0x7d8186); for (let k = 0; k < 9; k++) { const a = k * 2.4, y = .25 + (k % 5) * .12; const n = mesh(cyl(.012, .012, .2, 6), nm, [Math.cos(a) * .12, y, Math.sin(a) * .12], [0, 0, 0]); n.lookAt(Math.cos(a) * 2, y, Math.sin(a) * 2); n.rotateX(Math.PI / 2); g.add(n); } return g; }\n","import type { ItemModelBuilder } from './registry'\n\n/**\n * `MODELS[\"mochila_trilha\"]` of the Itens do Vale Cinzento showcase (`armas-itens__itens-vale-cinzento.js` L158), ported as it is: same units, same parts, same order, same materials by tag.\n * It draws in the units of the page; `data/models.json` gives the scale to metres of the item `hiking_backpack_40l`.\n */\nexport const hikingBackpack40L: ItemModelBuilder = ({ T, mesh, bx, G, cloth, plastic }) => { const c = cloth(0x4f6b3a), d = cloth(0x36472a); return G(mesh(bx(.78, .9, .42), c), mesh(new T.SphereGeometry(.4, 14, 8, 0, Math.PI * 2, 0, Math.PI / 2), c, [0, .44, 0], [0, 0, 0], [.98, .45, .53]), mesh(bx(.56, .4, .16), d, [0, -.15, .27]), mesh(bx(.8, .12, .46), d, [0, .2, 0]), mesh(bx(.06, .9, .06), cloth(0x22251f), [-.22, 0, -.24]), mesh(bx(.06, .9, .06), cloth(0x22251f), [.22, 0, -.24]), mesh(bx(.1, .08, .04), plastic(0xd9a441), [0, .2, .24])); }\n","import type { ItemModelBuilder } from './registry'\n\n/**\n * `MODELS[\"lanterna\"]` of the Itens do Vale Cinzento showcase (`armas-itens__itens-vale-cinzento.js` L159), ported as it is: same units, same parts, same order, same materials by tag.\n * It draws in the units of the page; `data/models.json` gives the scale to metres of the item `flashlight`.\n */\nexport const flashlight: ItemModelBuilder = ({ M, mesh, cyl, bx, torus, G, metal, plastic }) => G(mesh(cyl(.11, .11, .8, 14), metal(0x2a2c2e), [0, -.15, 0]), mesh(cyl(.19, .12, .28, 16), metal(0x3a3d40), [0, .37, 0]), mesh(cyl(.17, .17, .02, 16), M(0xfff1c0, \"glass\", { emissive: 0xffe08a, emissiveIntensity: .9 }), [0, .52, 0]), mesh(bx(.06, .1, .05), plastic(0xb5521f), [0, .05, .11]), ...[-.4, -.3, -.2].map(y => mesh(torus(.112, .012), plastic(0x1b1c1d), [0, y, 0], [Math.PI / 2, 0, 0])))\n","import type { ItemModelBuilder } from './registry'\n\n/**\n * `MODELS[\"radio_portatil\"]` of the Itens do Vale Cinzento showcase (`armas-itens__itens-vale-cinzento.js` L160), ported as it is: same units, same parts, same order, same materials by tag.\n * It draws in the units of the page; `data/models.json` gives the scale to metres of the item `portable_radio`.\n */\nexport const portableRadio: ItemModelBuilder = ({ M, mesh, cyl, bx, torus, G, metal, plastic }) => { const g = G(mesh(bx(1.05, .62, .3), plastic(0x3a3d35)), mesh(cyl(.2, .2, .02, 18), plastic(0x1e1f1b), [-.24, -.04, .16], [Math.PI / 2, 0, 0]), mesh(bx(.36, .14, .02), M(0xd9a441, \"glass\", { emissive: 0x6a4a10, emissiveIntensity: .6 }), [.26, .1, .16]), mesh(cyl(.06, .06, .06, 12), plastic(0x8d8a80), [.18, -.15, .17], [Math.PI / 2, 0, 0]), mesh(cyl(.06, .06, .06, 12), plastic(0x8d8a80), [.36, -.15, .17], [Math.PI / 2, 0, 0]), mesh(torus(.24, .03, Math.PI), plastic(0x22251f), [0, .3, 0])); const a = mesh(cyl(.012, .02, .95, 6), metal(0xb9bdc0), [.4, .72, 0], [0, 0, -.35]); g.add(a); return g; }\n","import type { ItemModelBuilder } from './registry'\n\n/**\n * `MODELS[\"chave_casa\"]` of the Itens do Vale Cinzento showcase (`armas-itens__itens-vale-cinzento.js` L161), ported as it is: same units, same parts, same order, same materials by tag.\n * It draws in the units of the page; `data/models.json` gives the scale to metres of the item `house_key`.\n */\nexport const houseKey: ItemModelBuilder = ({ mesh, bx, torus, extrude, G, metal, plastic }) => { const b = metal(0xb8913a); return G(mesh(torus(.22, .04), metal(0x9a9da0), [-.55, .1, 0]), mesh(extrude([[0, -.2], [.25, -.22], [.3, -.1], [.3, .1], [.25, .22], [0, .2]], .05), b, [-.38, .02, -.025]), mesh(extrude([[0, 0], [.75, 0], [.75, -.08], [.66, -.08], [.66, -.14], [.56, -.08], [.46, -.14], [.4, -.08], [0, -.08]], .035), b, [-.1, .06, -.017]), mesh(bx(.24, .34, .03), plastic(0xb5521f), [-.72, -.28, 0], [0, 0, .25])); }\n","import type { ItemModelBuilder } from './registry'\n\n/**\n * `MODELS[\"diario\"]` of the Itens do Vale Cinzento showcase (`armas-itens__itens-vale-cinzento.js` L162), ported as it is: same units, same parts, same order, same materials by tag.\n * It draws in the units of the page; `data/models.json` gives the scale to metres of the item `survivor_diary`.\n */\nexport const survivorDiary: ItemModelBuilder = ({ mesh, bx, G, cloth, paper }) => G(mesh(bx(.78, 1.02, .05), paper(0x6b3f2a), [0, 0, .1]), mesh(bx(.78, 1.02, .05), paper(0x6b3f2a), [0, 0, -.1]), mesh(bx(.74, .98, .16), paper(0xe9e1cc), [.01, 0, 0]), mesh(bx(.06, 1.02, .25), paper(0x5a3322), [-.38, 0, 0]), mesh(bx(.03, 1.04, .27), cloth(0x22251f), [.25, 0, 0]), mesh(bx(.18, .3, .002), paper(0xd5c9a8), [.05, .2, .126], [0, 0, .08]))\n","import type { ItemModelBuilder } from './registry'\n\n/**\n * `MODELS[\"capacete_moto\"]` of the Itens do Vale Cinzento showcase (`armas-itens__itens-vale-cinzento.js` L163), ported as it is: same units, same parts, same order, same materials by tag.\n * It draws in the units of the page; `data/models.json` gives the scale to metres of the item `motorcycle_helmet`.\n */\nexport const motorcycleHelmet: ItemModelBuilder = ({ T, M, mesh, cyl, bx, G, plastic }) => G(mesh(new T.SphereGeometry(.55, 18, 12), plastic(0x2b2f3a), [0, 0, 0], [0, 0, 0], [1, .95, 1.08]), mesh(new T.SphereGeometry(.56, 18, 10, -0.9, 1.8, 1.05, .75), M(0x14171c, \"glass\", { roughness: .15, metalness: .4 }), [0, .02, .02], [0, 0, 0], [1, .95, 1.08]), mesh(bx(.2, .12, .02), plastic(0xe0773f), [.42, .2, .22], [0, .95, 0]), mesh(cyl(.5, .55, .12, 18), plastic(0x1d2028), [0, -.5, 0]))\n","import type { ItemModelBuilder } from './registry'\n\n/**\n * `MODELS[\"botijao\"]` of the Itens do Vale Cinzento showcase (`armas-itens__itens-vale-cinzento.js` L164), ported as it is: same units, same parts, same order, same materials by tag.\n * It draws in the units of the page; `data/models.json` gives the scale to metres of the item `lpg_cylinder_13kg`.\n */\nexport const lpgCylinder13Kg: ItemModelBuilder = ({ mesh, cyl, bx, lathe, torus, G, metal }) => G(mesh(lathe([[0, -.6], [.38, -.6], [.42, -.55], [.45, -.3], [.45, .15], [.4, .32], [.28, .42], [.12, .46], [0, .46]], 18), metal(0x355f86)), mesh(cyl(.47, .47, .1, 18), metal(0x29486a), [0, -.62, 0]), mesh(torus(.24, .035), metal(0x29486a), [0, .58, 0], [Math.PI / 2, 0, 0]), mesh(cyl(.07, .07, .14, 10), metal(0xb8913a), [0, .5, 0]), mesh(bx(.04, .2, .04), metal(0x29486a), [.22, .5, 0]), mesh(bx(.04, .2, .04), metal(0x29486a), [-.22, .5, 0]))\n","import type { ItemModelBuilder } from './registry'\n\n/**\n * `MODELS[\"galao\"]` of the Itens do Vale Cinzento showcase (`armas-itens__itens-vale-cinzento.js` L165), ported as it is: same units, same parts, same order, same materials by tag.\n * It draws in the units of the page; `data/models.json` gives the scale to metres of the item `fuel_jerrycan`.\n */\nexport const fuelJerrycan: ItemModelBuilder = ({ mesh, cyl, bx, G, plastic }) => G(mesh(bx(.85, 1, .42), plastic(0xa3322a)), mesh(bx(.6, .1, .3), plastic(0x7e2620), [0, .45, 0]), mesh(bx(.36, .2, .1), plastic(0xa3322a), [-.12, .62, 0]), mesh(cyl(.05, .07, .35, 10), plastic(0xd9a441), [.3, .66, 0], [0, 0, -.6]), mesh(bx(.6, .5, .02), plastic(0x8a2a22), [0, -.1, .22]))\n","import type { ItemModelBuilder } from './registry'\n\n/**\n * `MODELS[\"walkie\"]` of the Itens do Vale Cinzento showcase (`armas-itens__itens-vale-cinzento.js` L166), ported as it is: same units, same parts, same order, same materials by tag.\n * It draws in the units of the page; `data/models.json` gives the scale to metres of the item `walkie_talkies`.\n */\nexport const walkieTalkies: ItemModelBuilder = ({ M, mesh, cyl, bx, G, plastic }) => G(mesh(bx(.42, .9, .2), plastic(0x2a2d27)), mesh(bx(.34, .3, .02), plastic(0x161814), [0, -.12, .11]), mesh(bx(.24, .12, .02), M(0x9fbf8a, \"glass\", { emissive: 0x2f4a22, emissiveIntensity: .7 }), [0, .22, .11]), mesh(cyl(.035, .045, .6, 8), plastic(0x1b1c1a), [.12, .72, 0]), mesh(cyl(.04, .04, .08, 10), plastic(0xb5521f), [-.12, .48, 0]), mesh(bx(.05, .2, .1), plastic(0x3a3d35), [-.23, .05, 0]))\n","import type { ItemModelBuilder } from './registry'\n\n/**\n * `MODELS[\"pilha_aa\"]` of the Itens do Vale Cinzento showcase (`armas-itens__itens-vale-cinzento.js` L167), ported as it is: same units, same parts, same order, same materials by tag.\n * It draws in the units of the page; `data/models.json` gives the scale to metres of the item `batteries`.\n */\nexport const batteries: ItemModelBuilder = ({ mesh, cyl, G, metal }) => { const g = G(); [-.2, .2].forEach((x, k) => g.add(mesh(cyl(.17, .17, .95, 16), metal(k ? 0xb5521f : 0x2a2c2e), [x, 0, 0]), mesh(cyl(.172, .172, .3, 16), metal(0xc9a227), [x, .33, 0]), mesh(cyl(.06, .06, .06, 10), metal(0xb9bdc0), [x, .5, 0]))); return g; }\n","import type { ItemModelBuilder } from './registry'\n\n/**\n * `MODELS[\"tabua\"]` of the Itens do Vale Cinzento showcase (`armas-itens__itens-vale-cinzento.js` L168), ported as it is: same units, same parts, same order, same materials by tag.\n * It draws in the units of the page; `data/models.json` gives the scale to metres of the item `wooden_plank`.\n */\nexport const woodenPlank: ItemModelBuilder = ({ mesh, cyl, bx, G, metal, wood }) => { const g = G(); [0xa88459, 0x8e6c45, 0xb49268].forEach((c, k) => g.add(mesh(bx(1.5, .07, .26), wood(c), [0, -.15 + k * .12, (k - 1) * .05], [0, (k - 1) * .12, 0]))); const nm = metal(0x7d8186); [-.5, -.3, .4].forEach((x, k) => g.add(mesh(cyl(.012, .012, .18, 6), nm, [x, .18 + k * .01, .2], [0, 0, (k - 1) * .3]))); return g; }\n","import type { ItemModelBuilder } from './registry'\n\n/**\n * Authored in the kit (no team model delivered); replace when the items team delivers one.\n * It draws in the units of the builder; `data/models.json` gives the scale to metres of the item `sugar`.\n */\nexport const sugar: ItemModelBuilder = ({ mesh, bx, G, paper }) => G(\n mesh(bx(1.0, 1.7, 0.58), paper(0xf4f1ea), [0, -0.15, 0]),\n mesh(bx(1.0, 0.3, 0.34), paper(0xe4dfd0), [0, 0.85, 0]),\n mesh(bx(1.0, 0.05, 0.12), paper(0xc9c3b0), [0, 0.975, 0]),\n mesh(bx(0.7, 0.8, 0.02), paper(0x3f6f94), [0, -0.1, 0.3]),\n mesh(bx(0.5, 0.14, 0.022), paper(0xf4f1ea), [0, 0.1, 0.3]),\n mesh(bx(0.5, 0.14, 0.022), paper(0xf4f1ea), [0, -0.3, 0.3]),\n)\n","import type { ItemModelBuilder } from './registry'\n\n/**\n * Authored in the kit (no team model delivered); replace when the items team delivers one.\n * It draws in the units of the builder; `data/models.json` gives the scale to metres of the item `chocolate_bar`.\n */\nexport const chocolateBar: ItemModelBuilder = ({ mesh, bx, G, paper, food }) => {\n const chocolate = food(0x4a2a1a)\n const pieces = [-0.5, 0, 0.5].flatMap((x) => [0.18, -0.07].map((y) => mesh(bx(0.46, 0.22, 0.04), chocolate, [x, y, 0.03])))\n return G(\n mesh(bx(1.5, 0.7, 0.06), paper(0xb9bcc0), [0, 0, -0.02]),\n ...pieces,\n mesh(bx(1.5, 0.2, 0.1), paper(0x9b2f2f), [0, -0.25, 0]),\n mesh(bx(0.9, 0.05, 0.102), paper(0xe8d9a8), [0, -0.25, 0]),\n )\n}\n","import type { ItemModelBuilder } from './registry'\n\n/**\n * Authored in the kit (no team model delivered); replace when the items team delivers one.\n * It draws in the units of the builder; `data/models.json` gives the scale to metres of the item `potatoes`.\n */\nexport const potatoes: ItemModelBuilder = ({ T, mesh, bx, G, food }) => {\n const skin = food(0xb08a55)\n const ball = new T.SphereGeometry(0.5, 8, 5)\n const eye = food(0x6b4f2a)\n return G(\n mesh(ball, skin, [-0.5, 0, -0.3], [0, 0, 0], [1.0, 0.9, 0.8]),\n mesh(ball, food(0xa57e4a), [0.5, -0.03, -0.3], [0, 0, 0], [1.0, 0.8, 0.8]),\n mesh(ball, food(0xbf9a63), [0, -0.03, 0.3], [0, 0, 0], [1.0, 0.8, 0.8]),\n mesh(bx(0.08, 0.05, 0.08), eye, [-0.6, 0.4, -0.3]),\n mesh(bx(0.08, 0.05, 0.08), eye, [0.4, 0.34, -0.3]),\n mesh(bx(0.08, 0.05, 0.08), eye, [0.1, 0.34, 0.3]),\n )\n}\n","import type { ItemModelBuilder } from './registry'\n\n/**\n * Authored in the kit (no team model delivered); replace when the items team delivers one.\n * It draws in the units of the builder; `data/models.json` gives the scale to metres of the item `biscuits`.\n */\nexport const biscuits: ItemModelBuilder = ({ mesh, bx, cyl, G, paper, food }) => {\n const biscuit = food(0xc98f4e)\n const cream = food(0xe6d2a2)\n return G(\n mesh(bx(2.0, 0.24, 1.0), paper(0x2f5d8c), [0, -0.13, 0]),\n mesh(bx(0.1, 0.3, 1.0), paper(0x244a70), [-0.95, -0.1, 0]),\n mesh(bx(0.1, 0.3, 1.0), paper(0x244a70), [0.95, -0.1, 0]),\n mesh(cyl(0.38, 0.38, 0.1, 12), biscuit, [-0.45, 0.04, 0]),\n mesh(cyl(0.38, 0.38, 0.05, 12), cream, [-0.45, 0.11, 0]),\n mesh(cyl(0.38, 0.38, 0.11, 12), biscuit, [-0.45, 0.195, 0]),\n mesh(cyl(0.38, 0.38, 0.1, 12), biscuit, [0.45, 0.04, 0]),\n mesh(cyl(0.38, 0.38, 0.05, 12), cream, [0.45, 0.11, 0]),\n mesh(cyl(0.38, 0.38, 0.11, 12), biscuit, [0.45, 0.195, 0]),\n )\n}\n","import type { ItemModelBuilder } from './registry'\n\n/**\n * Authored in the kit (no team model delivered); replace when the items team delivers one.\n * It draws in the units of the builder; `data/models.json` gives the scale to metres of the item `coffee`.\n */\nexport const coffee: ItemModelBuilder = ({ T, mesh, bx, G, paper, food }) => G(\n mesh(bx(0.8, 1.3, 0.58), paper(0x5a3a22), [0, -0.1, 0]),\n mesh(bx(0.8, 0.2, 0.12), paper(0x3f2a18), [0, 0.65, 0]),\n mesh(bx(0.6, 0.55, 0.02), paper(0xe8d7b0), [0, -0.05, 0.3]),\n mesh(bx(0.6, 0.12, 0.022), paper(0x8a5a2e), [0, -0.4, 0.3]),\n mesh(new T.SphereGeometry(0.5, 8, 4), food(0x3b2414), [0, 0.0, 0.29], [0, 0, 0.5], [0.3, 0.42, 0.06]),\n)\n","import type { ItemModelBuilder } from './registry'\n\n/**\n * Authored in the kit (no team model delivered); replace when the items team delivers one.\n * It draws in the units of the builder; `data/models.json` gives the scale to metres of the item `raw_beef`.\n */\nexport const rawBeef: ItemModelBuilder = ({ T, mesh, bx, G, plastic, food }) => {\n const ball = new T.SphereGeometry(0.5, 8, 6)\n return G(\n mesh(bx(2.0, 0.1, 1.5), plastic(0xf1f0eb), [0, -0.2, 0]),\n mesh(bx(2.0, 0.16, 0.08), plastic(0xf1f0eb), [0, -0.13, 0.71]),\n mesh(bx(2.0, 0.16, 0.08), plastic(0xf1f0eb), [0, -0.13, -0.71]),\n mesh(bx(0.08, 0.16, 1.34), plastic(0xf1f0eb), [0.96, -0.13, 0]),\n mesh(bx(0.08, 0.16, 1.34), plastic(0xf1f0eb), [-0.96, -0.13, 0]),\n mesh(ball, food(0xa3262a), [0, 0, 0], [0, 0.2, 0], [1.6, 0.5, 1.05]),\n mesh(ball, food(0xe9d6c1), [-0.35, 0.08, 0.3], [0, 0.4, 0], [0.7, 0.3, 0.3]),\n mesh(ball, food(0x7d1b20), [0.4, 0.09, -0.1], [0, 0.2, 0], [0.6, 0.3, 0.5]),\n )\n}\n","import type { ItemModelBuilder } from './registry'\n\n/**\n * Authored in the kit (no team model delivered); replace when the items team delivers one.\n * It draws in the units of the builder; `data/models.json` gives the scale to metres of the item `game_meat`.\n */\nexport const gameMeat: ItemModelBuilder = ({ T, mesh, cyl, G, food }) => {\n const ball = new T.SphereGeometry(0.5, 8, 6)\n const knob = new T.SphereGeometry(0.5, 6, 4)\n const bone = food(0xe6dcc3)\n return G(\n mesh(ball, food(0x7a2a24), [-0.4, 0, 0], [0, 0, 0], [2.2, 0.8, 2.0]),\n mesh(ball, food(0xc9a37a), [-0.5, 0.1, -0.3], [0, 0, 0], [1.4, 0.6, 1.0]),\n mesh(ball, food(0x5c1d1a), [-0.2, -0.05, 0.5], [0, 0, 0], [1.0, 0.6, 0.6]),\n mesh(cyl(0.11, 0.14, 0.9, 8), bone, [1.05, 0, 0], [0, 0, Math.PI / 2]),\n mesh(knob, bone, [1.35, 0.1, 0], [0, 0, 0], [0.3, 0.4, 0.4]),\n mesh(knob, bone, [1.35, -0.1, 0], [0, 0, 0], [0.3, 0.4, 0.4]),\n mesh(cyl(0.25, 0.25, 0.06, 8), food(0x3a2a22), [0.62, 0, 0], [0, 0, Math.PI / 2]),\n )\n}\n","import type { ItemModelBuilder } from './registry'\n\n/**\n * Authored in the kit (no team model delivered); replace when the items team delivers one.\n * It draws in the units of the builder; `data/models.json` gives the scale to metres of the item `jerked_beef`.\n */\nexport const jerkedBeef: ItemModelBuilder = ({ mesh, bx, cyl, G, food, wood }) => {\n const dark = food(0x5b2e22)\n const mid = food(0x70392a)\n const fat = food(0xb98a6a)\n return G(\n mesh(bx(2.5, 0.08, 0.4), dark, [0, -0.085, -0.55]),\n mesh(bx(2.2, 0.08, 0.4), mid, [0.1, 0.08, -0.18]),\n mesh(bx(2.4, 0.08, 0.4), dark, [-0.05, -0.085, 0.2]),\n mesh(bx(2.1, 0.08, 0.4), mid, [0.15, 0.085, 0.55]),\n mesh(bx(1.1, 0.012, 0.06), fat, [0.2, 0.12, -0.18]),\n mesh(bx(0.9, 0.012, 0.06), fat, [-0.3, 0.12, 0.55]),\n mesh(cyl(0.04, 0.04, 1.5, 6), wood(0x9b7a4a), [-0.95, 0.085, 0], [Math.PI / 2, 0, 0]),\n )\n}\n","import type { ItemModelBuilder } from './registry'\n\n/**\n * Authored in the kit (no team model delivered); replace when the items team delivers one.\n * It draws in the units of the builder; `data/models.json` gives the scale to metres of the item `home_preserves`.\n */\nexport const homePreserves: ItemModelBuilder = ({ mesh, cyl, G, glass, metal, paper, food, cloth }) => G(\n mesh(cyl(0.445, 0.445, 0.98, 12), glass(0xcfe6ee, 0.5), [0, -0.16, 0]),\n mesh(cyl(0.41, 0.41, 0.86, 12), food(0x8e1f3a), [0, -0.2, 0]),\n mesh(cyl(0.34, 0.445, 0.12, 12), glass(0xcfe6ee, 0.5), [0, 0.39, 0]),\n mesh(cyl(0.34, 0.34, 0.05, 12), glass(0xcfe6ee, 0.5), [0, 0.475, 0]),\n mesh(cyl(0.38, 0.38, 0.15, 12), metal(0xb99a3c), [0, 0.575, 0]),\n mesh(cyl(0.45, 0.45, 0.4, 12), paper(0xe9dfc4), [0, -0.2, 0]),\n mesh(cyl(0.452, 0.452, 0.08, 12), cloth(0x9b3a3a), [0, -0.2, 0]),\n)\n","import type { ItemModelBuilder } from './registry'\n\n/**\n * Authored in the kit (no team model delivered); replace when the items team delivers one.\n * It draws in the units of the builder; `data/models.json` gives the scale to metres of the item `eggs`.\n */\nexport const eggs: ItemModelBuilder = ({ T, mesh, bx, G, paper, food }) => {\n const egg = new T.SphereGeometry(0.5, 8, 4)\n const carton = paper(0xb8a98f)\n const eggs = [-0.8, 0, 0.8].flatMap((x) => [-0.25, 0.25].map((z, row) => mesh(egg, food(row ? 0xd9bd8d : 0xe6d3b0), [x, 0.05, z], [0, 0, 0], [0.5, 0.6, 0.5])))\n return G(\n mesh(bx(2.5, 0.2, 1.0), carton, [0, -0.25, 0]),\n ...eggs,\n mesh(bx(0.05, 0.18, 1.0), carton, [-0.4, -0.06, 0]),\n mesh(bx(0.05, 0.18, 1.0), carton, [0.4, -0.06, 0]),\n mesh(bx(2.5, 0.12, 0.04), carton, [0, -0.1, 0.48]),\n )\n}\n","import type { ItemModelBuilder } from './registry'\n\n/**\n * Authored in the kit (no team model delivered); replace when the items team delivers one.\n * It draws in the units of the builder; `data/models.json` gives the scale to metres of the item `cassava_flour`.\n */\nexport const cassavaFlour: ItemModelBuilder = ({ T, mesh, bx, G, paper, food }) => G(\n mesh(bx(1.5, 2.2, 0.58), paper(0xf1e9d2), [0, -0.15, 0]),\n mesh(bx(1.5, 0.3, 0.34), paper(0xdcd1b3), [0, 1.1, 0]),\n mesh(bx(1.5, 0.05, 0.12), paper(0xc4b890), [0, 1.225, 0]),\n mesh(bx(1.1, 1.0, 0.02), paper(0xd48a2a), [0, -0.1, 0.3]),\n mesh(bx(1.1, 0.16, 0.022), paper(0x5b7a3a), [0, -0.78, 0.3]),\n mesh(new T.SphereGeometry(0.5, 8, 4), food(0x7a5230), [0, 0.0, 0.29], [0, 0, 0.5], [0.8, 0.28, 0.04]),\n)\n","import type { ItemModelBuilder } from './registry'\n\n/**\n * Authored in the kit (no team model delivered); replace when the items team delivers one.\n * It draws in the units of the builder; `data/models.json` gives the scale to metres of the item `beans`.\n */\nexport const beans: ItemModelBuilder = ({ T, mesh, bx, G, cloth, paper, food }) => {\n const bean = new T.SphereGeometry(0.5, 6, 4)\n const dark = food(0x4a2418)\n return G(\n mesh(bx(1.0, 1.7, 0.58), cloth(0x8a5a2e), [0, -0.15, 0]),\n mesh(bx(1.0, 0.3, 0.34), cloth(0x70461f), [0, 0.85, 0]),\n mesh(bx(1.0, 0.05, 0.12), cloth(0x5a3716), [0, 0.975, 0]),\n mesh(bx(0.7, 0.8, 0.02), paper(0xe8d7b0), [0, -0.1, 0.3]),\n mesh(bean, dark, [-0.1, 0.0, 0.29], [0, 0, 0.6], [0.22, 0.14, 0.04]),\n mesh(bean, dark, [0.12, -0.1, 0.29], [0, 0, -0.5], [0.22, 0.14, 0.04]),\n mesh(bean, dark, [-0.05, -0.25, 0.29], [0, 0, 0.2], [0.22, 0.14, 0.04]),\n )\n}\n","import type { ItemModelBuilder } from './registry'\n\n/**\n * Authored in the kit (no team model delivered); replace when the items team delivers one.\n * It draws in the units of the builder; `data/models.json` gives the scale to metres of the item `frozen_chicken`.\n */\nexport const frozenChicken: ItemModelBuilder = ({ T, mesh, bx, cyl, G, plastic, glass, food }) => {\n const ball = new T.SphereGeometry(0.5, 8, 5)\n const small = new T.SphereGeometry(0.5, 6, 4)\n const skin = food(0xe6c7a0)\n const leg = (z: number) => [\n mesh(cyl(0.1, 0.17, 0.7, 8), skin, [0.8, -0.02, z], [0, 0, -1.37]),\n mesh(small, food(0xefe0c8), [1.18, 0.02, z], [0, 0, 0], [0.22, 0.2, 0.22]),\n ]\n return G(\n mesh(bx(2.6, 1.0, 1.7), glass(0xcfe3ee, 0.3)),\n mesh(ball, skin, [-0.25, -0.05, 0], [0, 0, 0], [1.7, 0.7, 1.1]),\n mesh(small, food(0xd6a97f), [-0.1, 0.18, 0], [0, 0, 0], [1.0, 0.3, 0.7]),\n ...leg(0.45),\n ...leg(-0.45),\n mesh(small, skin, [-0.55, 0.05, 0.62], [0, 0, 0], [0.8, 0.3, 0.35]),\n mesh(small, skin, [-0.55, 0.05, -0.62], [0, 0, 0], [0.8, 0.3, 0.35]),\n mesh(bx(2.6, 0.14, 0.05), plastic(0x7fa7c4), [0, 0.43, 0.8]),\n )\n}\n","import type { ItemModelBuilder } from './registry'\n\n/**\n * Authored in the kit (no team model delivered); replace when the items team delivers one.\n * It draws in the units of the builder; `data/models.json` gives the scale to metres of the item `orange`.\n */\nexport const orange: ItemModelBuilder = ({ T, mesh, cyl, bx, G, food }) => G(\n mesh(new T.SphereGeometry(0.375, 12, 8), food(0xe8871e)),\n mesh(cyl(0.07, 0.07, 0.02, 8), food(0x4f7a2a), [0, 0.365, 0]),\n mesh(bx(0.16, 0.012, 0.07), food(0x4f7a2a), [0.1, 0.355, 0.02], [0, 0.5, 0.2]),\n mesh(cyl(0.03, 0.03, 0.02, 6), food(0xc06a12), [0, -0.365, 0]),\n)\n","import type { ItemModelBuilder } from './registry'\n\n/**\n * Authored in the kit (no team model delivered); replace when the items team delivers one.\n * It draws in the units of the builder; `data/models.json` gives the scale to metres of the item `condensed_milk`.\n */\nexport const condensedMilk: ItemModelBuilder = ({ mesh, cyl, G, metal, paper }) => G(\n mesh(cyl(0.36, 0.36, 0.96, 12), metal(0xb8bcc2)),\n mesh(cyl(0.365, 0.365, 0.04, 12), metal(0x8d9096), [0, 0.48, 0]),\n mesh(cyl(0.365, 0.365, 0.04, 12), metal(0x8d9096), [0, -0.48, 0]),\n mesh(cyl(0.365, 0.365, 0.52, 12), paper(0xf1f1ec), [0, -0.02, 0]),\n mesh(cyl(0.367, 0.367, 0.16, 12), paper(0x2f6aa8), [0, 0.1, 0]),\n mesh(cyl(0.367, 0.367, 0.06, 12), paper(0x2f6aa8), [0, -0.2, 0]),\n mesh(cyl(0.12, 0.12, 0.008, 8), metal(0x8d9096), [0, 0.5, 0.0]),\n)\n","import type { ItemModelBuilder } from './registry'\n\n/**\n * Authored in the kit (no team model delivered); replace when the items team delivers one.\n * It draws in the units of the builder; `data/models.json` gives the scale to metres of the item `pasta`.\n */\nexport const pasta: ItemModelBuilder = ({ mesh, bx, G, paper, glass, food }) => {\n const strand = food(0xe8cf86)\n return G(\n mesh(bx(1.0, 2.5, 0.38), paper(0xb23a2c)),\n mesh(bx(0.7, 1.7, 0.02), glass(0xf2f2ee, 0.35), [0, -0.1, 0.195]),\n ...[-0.24, -0.12, 0, 0.12, 0.24].map((x) => mesh(bx(0.05, 1.6, 0.03), strand, [x, -0.1, 0.18])),\n mesh(bx(1.0, 0.16, 0.4), paper(0xf1e3b8), [0, 1.0, 0]),\n mesh(bx(1.0, 0.16, 0.4), paper(0xf1e3b8), [0, -1.1, 0]),\n )\n}\n","import type { ItemModelBuilder } from './registry'\n\n/**\n * Authored in the kit (no team model delivered); replace when the items team delivers one.\n * It draws in the units of the builder; `data/models.json` gives the scale to metres of the item `instant_noodles`.\n */\nexport const instantNoodles: ItemModelBuilder = ({ mesh, bx, cyl, G, plastic, paper, food }) => {\n const wrap = plastic(0xd9742a)\n return G(\n mesh(bx(1.2, 1.3, 0.28), wrap),\n mesh(bx(1.2, 0.15, 0.1), plastic(0xb85a1a), [0, 0.725, 0]),\n mesh(bx(1.2, 0.15, 0.1), plastic(0xb85a1a), [0, -0.725, 0]),\n mesh(cyl(0.38, 0.38, 0.02, 12), paper(0xf3e2a8), [0, 0.05, 0.15], [Math.PI / 2, 0, 0]),\n mesh(cyl(0.3, 0.3, 0.012, 12), food(0xe6c866), [0, 0.1, 0.162], [Math.PI / 2, 0, 0]),\n mesh(bx(0.9, 0.16, 0.02), paper(0x8a2a1a), [0, -0.5, 0.15]),\n )\n}\n","import type { ItemModelBuilder } from './registry'\n\n/**\n * Authored in the kit (no team model delivered); replace when the items team delivers one.\n * It draws in the units of the builder; `data/models.json` gives the scale to metres of the item `cassava_root`.\n */\nexport const cassavaRoot: ItemModelBuilder = ({ mesh, cyl, G, food }) => {\n const skin = food(0x7a5230)\n return G(\n mesh(cyl(0.35, 0.3, 1.2, 8), skin, [-1.38, 0, 0], [0, 0, Math.PI / 2]),\n mesh(cyl(0.3, 0.2, 1.5, 8), food(0x6b4528), [-0.05, 0.02, 0], [0, 0, Math.PI / 2 + 0.05]),\n mesh(cyl(0.2, 0.05, 1.3, 8), skin, [1.35, 0.02, 0], [0, 0, Math.PI / 2 + 0.1]),\n mesh(cyl(0.34, 0.34, 0.04, 8), food(0xf1ead6), [-1.98, 0, 0], [0, 0, Math.PI / 2]),\n mesh(cyl(0.05, 0.05, 0.05, 6), food(0x4a3018), [-1.99, 0, 0], [0, 0, Math.PI / 2]),\n mesh(cyl(0.355, 0.355, 0.06, 8), food(0x5c3c20), [-0.95, 0, 0], [0, 0, Math.PI / 2]),\n )\n}\n","import type { ItemModelBuilder } from './registry'\n\n/**\n * Authored in the kit (no team model delivered); replace when the items team delivers one.\n * It draws in the units of the builder; `data/models.json` gives the scale to metres of the item `canned_corn_and_peas`.\n */\nexport const cannedCornAndPeas: ItemModelBuilder = ({ mesh, cyl, G, metal, paper }) => G(\n mesh(cyl(0.36, 0.36, 0.81, 12), metal(0xb8bcc2)),\n mesh(cyl(0.365, 0.365, 0.04, 12), metal(0x8d9096), [0, 0.405, 0]),\n mesh(cyl(0.365, 0.365, 0.04, 12), metal(0x8d9096), [0, -0.405, 0]),\n mesh(cyl(0.365, 0.365, 0.5, 12), paper(0x4f8a3a), [0, 0, 0]),\n mesh(cyl(0.367, 0.367, 0.14, 12), paper(0xe9c43a), [0, 0.09, 0]),\n mesh(cyl(0.12, 0.12, 0.01, 10), paper(0xf3e08a), [-0.13, 0.0, 0.36], [Math.PI / 2, 0, 0]),\n mesh(cyl(0.1, 0.1, 0.01, 10), paper(0x7ab648), [0.12, -0.08, 0.36], [Math.PI / 2, 0, 0]),\n)\n","import type { ItemModelBuilder } from './registry'\n\n/**\n * Authored in the kit (no team model delivered); replace when the items team delivers one.\n * It draws in the units of the builder; `data/models.json` gives the scale to metres of the item `mortadella`.\n */\nexport const mortadella: ItemModelBuilder = ({ mesh, cyl, bx, G, food }) => {\n const pink = food(0xd98a8a)\n const fat = food(0xf1e4d4)\n const nut = food(0x7a9a4a)\n return G(\n mesh(cyl(0.25, 0.25, 1.2, 12), food(0xc27a74), [-0.15, 0, 0], [0, 0, Math.PI / 2], [1.2, 1, 1]),\n mesh(cyl(0.25, 0.25, 0.05, 12), pink, [0.48, 0, 0.0], [0, 0, Math.PI / 2], [1.2, 1, 1]),\n mesh(cyl(0.25, 0.25, 0.05, 12), pink, [0.62, 0.0, 0], [0, 0, Math.PI / 2], [1.2, 1, 1]),\n mesh(cyl(0.25, 0.25, 0.05, 12), pink, [0.73, 0.0, 0], [0, 0, Math.PI / 2], [1.2, 1, 1]),\n mesh(bx(0.012, 0.07, 0.07), fat, [0.76, 0.1, 0.05]),\n mesh(bx(0.012, 0.07, 0.07), fat, [0.76, -0.1, -0.06]),\n mesh(bx(0.012, 0.05, 0.05), nut, [0.76, 0.0, 0.0]),\n )\n}\n","import type { ItemModelBuilder } from './registry'\n\n/**\n * Authored in the kit (no team model delivered); replace when the items team delivers one.\n * It draws in the units of the builder; `data/models.json` gives the scale to metres of the item `fresh_fish`.\n */\nexport const freshFish: ItemModelBuilder = ({ T, mesh, bx, G, food, extrude }) => {\n const silver = food(0x9fb0b8)\n const eye = food(0x1c1c1c)\n return G(\n mesh(new T.SphereGeometry(0.5, 12, 6), silver, [0.0, 0, 0], [0, 0, 0], [3.0, 0.6, 1.0]),\n mesh(extrude([[0, 0], [-0.7, 0.4], [-0.7, -0.4]], 0.05, 0.01), food(0x7f939c), [-1.5 + 0.7, 0.025, 0], [Math.PI / 2, 0, 0]),\n mesh(bx(0.8, 0.2, 0.08), food(0xe9eef0), [0.1, -0.12, 0.4]),\n mesh(bx(0.04, 0.2, 0.5), food(0x6c7f88), [0.75, 0.0, 0.0]),\n mesh(new T.SphereGeometry(0.06, 6, 4), eye, [1.2, 0.16, 0.12]),\n )\n}\n","import type { ItemModelBuilder } from './registry'\n\n/**\n * Authored in the kit (no team model delivered); replace when the items team delivers one.\n * It draws in the units of the builder; `data/models.json` gives the scale to metres of the item `salted_fish`.\n */\nexport const saltedFish: ItemModelBuilder = ({ mesh, bx, G, food, extrude }) => {\n const outline: [number, number][] = [[-1.22, 0.34], [-0.88, 0.0], [-1.22, -0.34], [-0.6, -0.46], [0.5, -0.47], [1.22, -0.3], [1.22, 0.3], [0.5, 0.47], [-0.6, 0.46]]\n const salt = food(0xf1ede2)\n return G(\n mesh(extrude(outline, 0.24, 0.02), food(0xc9b48a), [0, 0.12, 0], [Math.PI / 2, 0, 0]),\n mesh(bx(2.0, 0.01, 0.1), food(0x9a8458), [0.1, 0.145, 0]),\n mesh(bx(0.4, 0.012, 0.25), salt, [-0.3, 0.145, 0.2]),\n mesh(bx(0.5, 0.012, 0.2), salt, [0.5, 0.145, -0.22]),\n mesh(bx(0.3, 0.012, 0.18), salt, [0.7, 0.145, 0.25]),\n )\n}\n","import type { ItemModelBuilder } from './registry'\n\n/**\n * Authored in the kit (no team model delivered); replace when the items team delivers one.\n * It draws in the units of the builder; `data/models.json` gives the scale to metres of the item `banana_bunch`.\n */\nexport const bananaBunch: ItemModelBuilder = ({ mesh, bx, cyl, G, food }) => {\n const yellow = food(0xe5c336)\n const stem = food(0x7d8a3a)\n const tip = food(0x4a3a1a)\n const point = (spread: number, lift: number, u: number): [number, number, number] => [-1.2 + u * 2.62, lift + 0.84 * (u - 0.2) * (u - 0.2), spread * 0.69 * u]\n const banana = (spread: number, lift: number) => [0, 1, 2].map((index) => {\n const from = point(spread, lift, index / 3)\n const to = point(spread, lift, (index + 1) / 3)\n const [dx, dy, dz] = [to[0] - from[0], to[1] - from[1], to[2] - from[2]]\n const elevation = Math.atan2(dy, Math.hypot(dx, dz))\n const mid: [number, number, number] = [(from[0] + to[0]) / 2, (from[1] + to[1]) / 2, (from[2] + to[2]) / 2]\n const material = index === 0 ? stem : yellow\n return mesh(cyl(index === 2 ? 0.08 : 0.15, index === 0 ? 0.1 : 0.15, Math.hypot(dx, dy, dz), 6), material, mid, [0, Math.atan2(-dz, dx), -(Math.PI / 2 - elevation)])\n })\n return G(\n mesh(bx(0.3, 0.3, 0.3), tip, [-1.35, -0.2, 0]),\n ...banana(-1, 0).flat(),\n ...banana(0, 0).flat(),\n ...banana(1, 0).flat(),\n ...banana(-0.5, 0.28).flat(),\n ...banana(0.5, 0.28).flat(),\n )\n}\n","import type { ItemModelBuilder } from './registry'\n\n/**\n * Authored in the kit (no team model delivered); replace when the items team delivers one.\n * It draws in the units of the builder; `data/models.json` gives the scale to metres of the item `honey_jar`.\n */\nexport const honeyJar: ItemModelBuilder = ({ mesh, cyl, G, glass, metal, paper, food }) => G(\n mesh(cyl(0.395, 0.395, 0.68, 12), glass(0xe3c070, 0.55), [0, -0.16, 0]),\n mesh(cyl(0.37, 0.37, 0.6, 12), food(0xd99a1c), [0, -0.2, 0]),\n mesh(cyl(0.3, 0.395, 0.14, 12), glass(0xe3c070, 0.55), [0, 0.25, 0]),\n mesh(cyl(0.3, 0.3, 0.18, 12), metal(0x6b4a1c), [0, 0.41, 0]),\n mesh(cyl(0.4, 0.4, 0.34, 12), paper(0xf1e7c8), [0, -0.2, 0]),\n mesh(cyl(0.402, 0.402, 0.05, 12), paper(0x8a5a14), [0, -0.1, 0]),\n mesh(cyl(0.402, 0.402, 0.05, 12), paper(0x8a5a14), [0, -0.3, 0]),\n)\n","import type { ItemModelBuilder } from './registry'\n\n/**\n * Authored in the kit (no team model delivered); replace when the items team delivers one.\n * It draws in the units of the builder; `data/models.json` gives the scale to metres of the item `bread`.\n */\nexport const bread: ItemModelBuilder = ({ T, mesh, bx, G, food }) => {\n const score = food(0xe0b070)\n return G(\n mesh(new T.SphereGeometry(0.5, 12, 6), food(0xa86a2c), [0, 0, 0], [0, 0, 0], [3.0, 1.0, 1.0]),\n mesh(bx(0.6, 0.03, 0.09), score, [-0.7, 0.4, 0], [0, 0.7, 0]),\n mesh(bx(0.6, 0.03, 0.09), score, [0, 0.485, 0], [0, 0.7, 0]),\n mesh(bx(0.6, 0.03, 0.09), score, [0.7, 0.4, 0], [0, 0.7, 0]),\n )\n}\n","import type { ItemModelBuilder } from './registry'\n\n/**\n * Authored in the kit (no team model delivered); replace when the items team delivers one.\n * It draws in the units of the builder; `data/models.json` gives the scale to metres of the item `cheese`.\n */\nexport const cheese: ItemModelBuilder = ({ mesh, bx, cyl, G, food, extrude }) => {\n const outline: [number, number][] = [[-0.73, 0.0], [0.2, 0.44], [0.55, 0.48], [0.71, 0.3], [0.71, -0.3], [0.55, -0.48], [0.2, -0.44]]\n const hole = food(0xc99a1c)\n return G(\n mesh(extrude(outline, 0.38, 0.01), food(0xf0c64a), [0, 0.19, 0], [Math.PI / 2, 0, 0]),\n mesh(bx(0.04, 0.4, 0.6), food(0xb5482e), [0.73, 0, 0]),\n mesh(cyl(0.07, 0.07, 0.02, 8), hole, [0.1, 0.195, 0.1]),\n mesh(cyl(0.05, 0.05, 0.02, 8), hole, [0.35, 0.195, -0.15]),\n mesh(cyl(0.06, 0.06, 0.02, 8), hole, [-0.2, 0.195, -0.02]),\n )\n}\n","import type { ItemModelBuilder } from './registry'\n\n/**\n * Authored in the kit (no team model delivered); replace when the items team delivers one.\n * It draws in the units of the builder; `data/models.json` gives the scale to metres of the item `rapadura`.\n */\nexport const rapadura: ItemModelBuilder = ({ mesh, bx, G, food, paper }) => G(\n mesh(bx(1.9, 0.46, 0.58), food(0x8a5a2b), [0, -0.25, 0]),\n mesh(bx(1.78, 0.04, 0.5), food(0x9b6a36), [0, -0.01, 0]),\n mesh(bx(1.9, 0.46, 0.58), food(0x7d4f25), [0, 0.25, 0]),\n mesh(bx(1.78, 0.04, 0.5), food(0x9b6a36), [0, 0.5, 0]),\n mesh(bx(0.4, 0.96, 0.6), paper(0xc9a26a), [0, 0, 0]),\n mesh(bx(0.42, 0.2, 0.602), paper(0x6b3a1a), [0, 0, 0]),\n)\n","import type { ItemModelBuilder } from './registry'\n\n/**\n * Authored in the kit (no team model delivered); replace when the items team delivers one.\n * It draws in the units of the builder; `data/models.json` gives the scale to metres of the item `dog_food`.\n */\nexport const dogFood: ItemModelBuilder = ({ mesh, bx, cyl, G, paper }) => {\n const brown = paper(0x6b3f22)\n return G(\n mesh(bx(1.8, 2.3, 0.69), paper(0xb5461f), [0, -0.15, 0]),\n mesh(bx(1.8, 0.3, 0.4), paper(0x9a3a18), [0, 1.15, 0]),\n mesh(bx(1.8, 0.05, 0.14), paper(0x7a2a10), [0, 1.275, 0]),\n mesh(bx(1.3, 1.3, 0.02), paper(0xf1e7c8), [0, -0.05, 0.35]),\n mesh(cyl(0.3, 0.3, 0.012, 10), brown, [0, -0.25, 0.36], [Math.PI / 2, 0, 0]),\n ...[-0.4, -0.14, 0.14, 0.4].map((x, index) => mesh(cyl(0.09, 0.09, 0.012, 8), brown, [x, 0.2 + (index % 3 === 0 ? 0 : 0.14), 0.36], [Math.PI / 2, 0, 0])),\n mesh(bx(1.3, 0.2, 0.022), paper(0x2f5d3a), [0, -1.0, 0.35]),\n )\n}\n","import type { ItemModelBuilder } from './registry'\n\n/**\n * Authored in the kit (no team model delivered); replace when the items team delivers one.\n * It draws in the units of the builder; `data/models.json` gives the scale to metres of the item `salt`.\n */\nexport const salt: ItemModelBuilder = ({ mesh, cyl, G, paper, plastic }) => G(\n mesh(cyl(0.345, 0.345, 1.3, 12), paper(0xeeeeea), [0, -0.15, 0]),\n mesh(cyl(0.25, 0.345, 0.15, 12), paper(0xd6d6d0), [0, 0.575, 0]),\n mesh(cyl(0.12, 0.12, 0.15, 12), plastic(0x2f6aa8), [0, 0.725, 0]),\n mesh(cyl(0.35, 0.35, 0.7, 12), paper(0x2f6aa8), [0, -0.3, 0]),\n mesh(cyl(0.352, 0.352, 0.3, 12), paper(0xeeeeea), [0, -0.3, 0]),\n mesh(cyl(0.35, 0.35, 0.06, 12), paper(0x244a70), [0, -0.78, 0]),\n)\n","import type { ItemModelBuilder } from './registry'\n\n/**\n * Authored in the kit (no team model delivered); replace when the items team delivers one.\n * It draws in the units of the builder; `data/models.json` gives the scale to metres of the item `snack_chips`.\n */\nexport const snackChips: ItemModelBuilder = ({ T, mesh, bx, G, paper, plastic, food }) => G(\n mesh(bx(2.0, 2.4, 0.58), plastic(0xd0402a)),\n mesh(bx(2.0, 0.2, 0.12), plastic(0xa8301c), [0, 1.3, 0]),\n mesh(bx(2.0, 0.2, 0.12), plastic(0xa8301c), [0, -1.3, 0]),\n mesh(bx(1.4, 1.2, 0.02), paper(0xf1c230), [0, 0.1, 0.3]),\n mesh(new T.SphereGeometry(0.5, 8, 4), food(0xe3b04a), [0, 0.1, 0.29], [0, 0, 0.4], [0.9, 0.6, 0.04]),\n mesh(bx(1.4, 0.2, 0.022), paper(0x7a1a10), [0, -0.8, 0.3]),\n)\n","import type { ItemModelBuilder } from './registry'\n\n/**\n * Authored in the kit (no team model delivered); replace when the items team delivers one.\n * It draws in the units of the builder; `data/models.json` gives the scale to metres of the item `canned_sausages`.\n */\nexport const cannedSausages: ItemModelBuilder = ({ mesh, cyl, bx, G, metal, paper, food }) => G(\n mesh(cyl(0.36, 0.36, 0.81, 12), metal(0xb8bcc2)),\n mesh(cyl(0.365, 0.365, 0.04, 12), metal(0x8d9096), [0, 0.405, 0]),\n mesh(cyl(0.365, 0.365, 0.04, 12), metal(0x8d9096), [0, -0.405, 0]),\n mesh(cyl(0.365, 0.365, 0.5, 12), paper(0xa8322a), [0, 0, 0]),\n mesh(cyl(0.367, 0.367, 0.06, 12), paper(0xf1e7c8), [0, 0.2, 0]),\n mesh(cyl(0.367, 0.367, 0.06, 12), paper(0xf1e7c8), [0, -0.2, 0]),\n mesh(bx(0.4, 0.08, 0.01), food(0xd9a07a), [0, 0.05, 0.36]),\n mesh(bx(0.4, 0.08, 0.01), food(0xc78c66), [0, -0.07, 0.36]),\n)\n","import type { ItemModelBuilder } from './registry'\n\n/**\n * Authored in the kit (no team model delivered); replace when the items team delivers one.\n * It draws in the units of the builder; `data/models.json` gives the scale to metres of the item `canned_sardines`.\n */\nexport const cannedSardines: ItemModelBuilder = ({ T, mesh, bx, cyl, G, metal, paper, food }) => {\n const tin = metal(0xb8bcc2)\n return G(\n mesh(bx(1.12, 0.22, 0.65), tin, [0, -0.02, 0]),\n mesh(bx(1.0, 0.04, 0.54), metal(0x9a9ea5), [0, 0.11, 0]),\n mesh(bx(0.7, 0.01, 0.34), paper(0x2f6aa8), [0, 0.125, 0]),\n mesh(new T.SphereGeometry(0.5, 8, 4), food(0xcfd6da), [-0.05, 0.125, 0], [0, 0.2, 0], [0.45, 0.01, 0.12]),\n mesh(cyl(0.08, 0.08, 0.01, 8), metal(0x8d9096), [0.42, 0.125, 0.0]),\n mesh(bx(0.5, 0.02, 0.65), metal(0x8d9096), [0, -0.12, 0]),\n )\n}\n","import type { ItemModelBuilder } from './registry'\n\n/**\n * Authored in the kit (no team model delivered); replace when the items team delivers one.\n * It draws in the units of the builder; `data/models.json` gives the scale to metres of the item `cooking_oil`.\n */\nexport const cookingOil: ItemModelBuilder = ({ mesh, cyl, G, glass, plastic, paper }) => G(\n mesh(cyl(0.345, 0.345, 1.7, 12), glass(0xe3b830, 0.65), [0, -0.45, 0]),\n mesh(cyl(0.12, 0.345, 0.5, 12), glass(0xe3b830, 0.65), [0, 0.65, 0]),\n mesh(cyl(0.12, 0.12, 0.25, 12), glass(0xe3b830, 0.65), [0, 1.025, 0]),\n mesh(cyl(0.14, 0.14, 0.15, 12), plastic(0x3f7a2a), [0, 1.225, 0]),\n mesh(cyl(0.35, 0.35, 0.8, 12), paper(0xf1e7c8), [0, -0.5, 0]),\n mesh(cyl(0.352, 0.352, 0.2, 12), paper(0x3f7a2a), [0, -0.5, 0]),\n)\n","import type { ItemModelBuilder } from './registry'\n\n/**\n * Authored in the kit (no team model delivered); replace when the items team delivers one.\n * It draws in the units of the builder; `data/models.json` gives the scale to metres of the item `beer_can`.\n */\nexport const beerCan: ItemModelBuilder = ({ mesh, cyl, bx, G, metal, paper }) => {\n const shell = metal(0x235789)\n const foot = mesh(cyl(0.33, 0.29, 0.12, 16), shell, [0, -0.54, 0])\n const body = mesh(cyl(0.33, 0.33, 0.88, 16), shell, [0, -0.04, 0])\n const label = mesh(cyl(0.332, 0.332, 0.56, 16), paper(0xd4af37), [0, -0.02, 0])\n const stripe = mesh(cyl(0.332, 0.332, 0.06, 16), paper(0xf2efe4), [0, 0.3, 0])\n const neck = mesh(cyl(0.27, 0.33, 0.12, 16), shell, [0, 0.46, 0])\n const lid = mesh(cyl(0.285, 0.285, 0.08, 16), metal(0xb0b8bf), [0, 0.552, 0])\n const tab = mesh(bx(0.1, 0.008, 0.18), metal(0x8d949a), [0, 0.596, 0.04])\n return G(foot, body, label, stripe, neck, lid, tab)\n}\n","import type { ItemModelBuilder } from './registry'\n\n/**\n * Authored in the kit (no team model delivered); replace when the items team delivers one.\n * It draws in the units of the builder; `data/models.json` gives the scale to metres of the item `energy_drink`.\n */\nexport const energyDrink: ItemModelBuilder = ({ mesh, cyl, bx, G, metal, paper }) => {\n const shell = metal(0x1a1a1a)\n const foot = mesh(cyl(0.29, 0.25, 0.12, 12), shell, [0, -0.615, 0])\n const body = mesh(cyl(0.29, 0.29, 1.0, 12), shell, [0, -0.055, 0])\n const label = mesh(cyl(0.292, 0.292, 0.8, 12), paper(0x00c853), [0, -0.055, 0])\n const upperBand = mesh(cyl(0.292, 0.292, 0.05, 12), paper(0xf0f0f0), [0, 0.37, 0])\n const lowerBand = mesh(cyl(0.292, 0.292, 0.05, 12), paper(0xf0f0f0), [0, -0.48, 0])\n const neck = mesh(cyl(0.235, 0.29, 0.12, 12), shell, [0, 0.505, 0])\n const lid = mesh(cyl(0.24, 0.24, 0.12, 12), metal(0x999999), [0, 0.615, 0])\n const tab = mesh(bx(0.08, 0.008, 0.14), metal(0x777777), [0, 0.671, 0.05])\n return G(foot, body, label, upperBand, lowerBand, neck, lid, tab)\n}\n","import type { ItemModelBuilder } from './registry'\n\n/**\n * Authored in the kit (no team model delivered); replace when the items team delivers one.\n * It draws in the units of the builder; `data/models.json` gives the scale to metres of the item `water_jug_5l`.\n */\nexport const waterJug5l: ItemModelBuilder = ({ mesh, bx, cyl, G, plastic, paper, glass }) => {\n const dark = plastic(0x1565c0)\n const body = mesh(bx(1.5, 2.3, 1.5), glass(0x9fd0ee, 0.75), [0, -0.5, 0])\n const shoulder = mesh(bx(1.2, 0.45, 1.2), glass(0x9fd0ee, 0.75), [0, 0.875, 0])\n const neck = mesh(cyl(0.34, 0.34, 0.3, 12), dark, [0, 1.25, 0])\n const cap = mesh(cyl(0.4, 0.4, 0.25, 12), dark, [0, 1.525, 0])\n const grip = mesh(bx(0.16, 0.9, 0.3), dark, [1.07, 0.6, 0])\n const upperBar = mesh(bx(0.45, 0.16, 0.3), dark, [0.925, 0.97, 0])\n const lowerBar = mesh(bx(0.45, 0.16, 0.3), dark, [0.925, 0.23, 0])\n const label = mesh(bx(1.0, 0.9, 0.02), paper(0xf4f6f8), [0, -0.5, 0.74])\n const band = mesh(bx(1.0, 0.2, 0.02), paper(0x2f80c8), [0, -0.3, 0.741])\n return G(body, shoulder, neck, cap, grip, upperBar, lowerBar, label, band)\n}\n","import type { ItemModelBuilder } from './registry'\n\n/**\n * Authored in the kit (no team model delivered); replace when the items team delivers one.\n * It draws in the units of the builder; `data/models.json` gives the scale to metres of the item `sports_drink`.\n */\nexport const sportsDrink: ItemModelBuilder = ({ mesh, cyl, lathe, G, plastic, paper }) => {\n const bottle = mesh(lathe([[0, -0.915], [0.28, -0.915], [0.33, -0.86], [0.33, 0.28], [0.28, 0.5], [0.18, 0.64], [0.17, 0.72], [0, 0.72]], 12), plastic(0x2080d0))\n const label = mesh(cyl(0.332, 0.332, 0.7, 12), paper(0x161b22), [0, -0.12, 0])\n const stripe = mesh(cyl(0.332, 0.332, 0.1, 12), paper(0xf06010), [0, 0.28, 0])\n const collar = mesh(cyl(0.2, 0.2, 0.04, 12), plastic(0xe8e8e8), [0, 0.705, 0])\n const cap = mesh(cyl(0.19, 0.19, 0.2, 12), plastic(0xf06010), [0, 0.815, 0])\n return G(bottle, label, stripe, collar, cap)\n}\n","import type { ItemModelBuilder } from './registry'\n\n/**\n * Authored in the kit (no team model delivered); replace when the items team delivers one.\n * It draws in the units of the builder; `data/models.json` gives the scale to metres of the item `milk_carton`.\n */\nexport const milkCarton: ItemModelBuilder = ({ mesh, bx, cyl, extrude, G, paper, plastic }) => {\n const white = paper(0xf3f2ec)\n const body = mesh(bx(0.7, 1.3, 0.7), white, [0, -0.35, 0])\n const gable = mesh(extrude([[-0.35, 0], [0.35, 0], [0.025, 0.5], [-0.025, 0.5]], 0.7, 0), white, [0, 0.3, -0.35])\n const fin = mesh(bx(0.05, 0.2, 0.7), paper(0xd9d8d0), [0, 0.9, 0])\n const frontPanel = mesh(bx(0.5, 0.6, 0.012), paper(0x2f6fc0), [0, -0.3, 0.345])\n const backPanel = mesh(bx(0.5, 0.6, 0.012), paper(0x2f6fc0), [0, -0.3, -0.345])\n const baseStripe = mesh(bx(0.5, 0.08, 0.012), paper(0xf3f2ec), [0, -0.55, 0.347])\n const spout = mesh(cyl(0.07, 0.07, 0.04, 8), plastic(0xd23b3b), [0.2, 0.558, 0], [0, 0, -0.995])\n return G(body, gable, fin, frontPanel, backPanel, baseStripe, spout)\n}\n","import type { ItemModelBuilder } from './registry'\n\n/**\n * Authored in the kit (no team model delivered); replace when the items team delivers one.\n * It draws in the units of the builder; `data/models.json` gives the scale to metres of the item `soda_can`.\n */\nexport const sodaCan: ItemModelBuilder = ({ mesh, cyl, bx, G, metal, paper }) => {\n const shell = metal(0xb8262b)\n const foot = mesh(cyl(0.33, 0.29, 0.12, 16), shell, [0, -0.54, 0])\n const body = mesh(cyl(0.33, 0.33, 0.88, 16), shell, [0, -0.04, 0])\n const wave = mesh(cyl(0.332, 0.332, 0.22, 16), paper(0xf4f1ea), [0, 0.02, 0])\n const neck = mesh(cyl(0.27, 0.33, 0.12, 16), shell, [0, 0.46, 0])\n const lid = mesh(cyl(0.285, 0.285, 0.08, 16), metal(0xb0b8bf), [0, 0.552, 0])\n const tab = mesh(bx(0.1, 0.008, 0.18), metal(0x8d949a), [0, 0.596, 0.04])\n return G(foot, body, wave, neck, lid, tab)\n}\n","import type { ItemModelBuilder } from './registry'\n\n/**\n * Authored in the kit (no team model delivered); replace when the items team delivers one.\n * It draws in the units of the builder; `data/models.json` gives the scale to metres of the item `juice_box`.\n */\nexport const juiceBox: ItemModelBuilder = ({ mesh, bx, cyl, G, paper, plastic }) => {\n const body = mesh(bx(0.52, 0.88, 0.37), paper(0xe08a20), [0, -0.06, 0])\n const fin = mesh(bx(0.52, 0.12, 0.12), paper(0xc9741a), [0, 0.44, 0])\n const label = mesh(bx(0.4, 0.5, 0.02), paper(0xf6f1e4), [0, -0.05, 0.176])\n const fruit = mesh(cyl(0.1, 0.1, 0.02, 10), paper(0xd64a1a), [0, -0.02, 0.175], [Math.PI / 2, 0, 0])\n const stripe = mesh(bx(0.52, 0.08, 0.371), paper(0x6aa84f), [0, -0.38, 0])\n const straw = mesh(cyl(0.012, 0.012, 0.3, 6), plastic(0xf2f2f2), [0, 0.485, 0.06], [0, 0, Math.PI / 2])\n return G(body, fin, label, fruit, stripe, straw)\n}\n","import type { ItemModelBuilder } from './registry'\n\n/**\n * Authored in the kit (no team model delivered); replace when the items team delivers one.\n * It draws in the units of the builder; `data/models.json` gives the scale to metres of the item `communion_wine`.\n */\nexport const communionWine: ItemModelBuilder = ({ mesh, bx, cyl, lathe, G, glass, paper, metal }) => {\n const bottle = mesh(lathe([[0, -1.5], [0.33, -1.5], [0.38, -1.42], [0.38, 0.4], [0.37, 0.55], [0.2, 0.9], [0.135, 1.05], [0.135, 1.12], [0, 1.12]], 12), glass(0x3a1015, 0.85))\n const label = mesh(cyl(0.382, 0.382, 0.9, 12), paper(0xe3d8b0), [0, -0.4, 0])\n const goldBand = mesh(cyl(0.382, 0.382, 0.05, 12), metal(0xb58830), [0, 0.075, 0])\n const crossUpright = mesh(bx(0.06, 0.26, 0.02), paper(0x7a1f2b), [0, -0.35, 0.375])\n const crossArm = mesh(bx(0.18, 0.06, 0.02), paper(0x7a1f2b), [0, -0.3, 0.375])\n const foil = mesh(cyl(0.15, 0.15, 0.46, 12), metal(0xb58830), [0, 1.27, 0])\n return G(bottle, label, goldBand, crossUpright, crossArm, foil)\n}\n","import type { ItemModelBuilder } from './registry'\n\n/**\n * Authored in the kit (no team model delivered); replace when the items team delivers one.\n * It draws in the units of the builder; `data/models.json` gives the scale to metres of the item `coconut_water`.\n */\nexport const coconutWater: ItemModelBuilder = ({ mesh, bx, cyl, lathe, G, plastic, paper }) => {\n const bottle = mesh(lathe([[0, -0.85], [0.25, -0.85], [0.298, -0.8], [0.298, 0.3], [0.24, 0.52], [0.13, 0.66], [0.12, 0.72], [0, 0.72]], 12), plastic(0xe8efe4))\n const label = mesh(cyl(0.3, 0.3, 0.7, 12), paper(0x3f8f4a), [0, -0.15, 0])\n const nut = mesh(cyl(0.11, 0.11, 0.03, 10), paper(0x6b4a2b), [0, -0.12, 0.285], [Math.PI / 2, 0, 0])\n const leafLeft = mesh(bx(0.2, 0.05, 0.01), paper(0xe6f2d8), [-0.12, 0.08, 0.292], [0, 0, 0.5])\n const leafRight = mesh(bx(0.2, 0.05, 0.01), paper(0xe6f2d8), [0.12, 0.08, 0.292], [0, 0, -0.5])\n const cap = mesh(cyl(0.14, 0.14, 0.2, 12), plastic(0x3f8f4a), [0, 0.75, 0])\n return G(bottle, label, nut, leafLeft, leafRight, cap)\n}\n","import type { ItemModelBuilder } from './registry'\n\n/**\n * Authored in the kit (no team model delivered); replace when the items team delivers one.\n * It draws in the units of the builder; `data/models.json` gives the scale to metres of the item `dirty_water`.\n */\nexport const dirtyWater: ItemModelBuilder = ({ mesh, cyl, lathe, G, plastic, paper, glass, food }) => {\n const bottle = mesh(lathe([[0, -0.915], [0.28, -0.915], [0.33, -0.86], [0.33, 0.28], [0.28, 0.5], [0.18, 0.64], [0.17, 0.72], [0, 0.72]], 12), glass(0xb9c4b8, 0.45))\n const murk = mesh(lathe([[0, -0.89], [0.27, -0.89], [0.315, -0.84], [0.315, 0.1], [0, 0.1]], 12), food(0x6b5a34))\n const sediment = mesh(cyl(0.31, 0.27, 0.12, 8), food(0x4a3d22), [0, -0.82, 0])\n const label = mesh(cyl(0.332, 0.332, 0.22, 12), paper(0xcfc9b4), [0, 0.38, 0])\n const cap = mesh(cyl(0.19, 0.19, 0.2, 8), plastic(0x5a6068), [0, 0.815, 0])\n return G(bottle, murk, sediment, label, cap)\n}\n","import type { ItemModelBuilder } from './registry'\n\n/**\n * Authored in the kit (no team model delivered); replace when the items team delivers one.\n * It draws in the units of the builder; `data/models.json` gives the scale to metres of the item `painkillers`.\n */\nexport const painkillers: ItemModelBuilder = ({ mesh, bx, cyl, G, paper, metal, glass }) => {\n const card = mesh(bx(0.6, 0.03, 0.4), metal(0xd0d0d0), [0, -0.085, 0])\n const strip = mesh(bx(0.12, 0.032, 0.4), paper(0xcc2222), [0.24, -0.085, 0])\n const blisterShell = glass(0xeef3f5, 0.7)\n const bumps = [-0.16, 0, 0.16].flatMap((x) => [-0.1, 0.1].map((z) => mesh(cyl(0.06, 0.07, 0.18, 8), blisterShell, [x - 0.06, 0.01, z])))\n return G(card, strip, ...bumps)\n}\n","import type { ItemModelBuilder } from './registry'\n\n/**\n * Authored in the kit (no team model delivered); replace when the items team delivers one.\n * It draws in the units of the builder; `data/models.json` gives the scale to metres of the item `tramadol`.\n */\nexport const tramadol: ItemModelBuilder = ({ mesh, bx, cyl, G, paper, plastic }) => {\n const carton = mesh(bx(0.95, 0.5, 0.15), paper(0xf4f1e8))\n const band = mesh(bx(0.948, 0.12, 0.152), paper(0x1f4f8f), [0, -0.19, 0])\n const label = mesh(bx(0.55, 0.24, 0.01), paper(0xffffff), [-0.12, 0.06, 0.0705])\n const title = mesh(bx(0.4, 0.04, 0.01), paper(0x1f4f8f), [-0.12, 0.1, 0.0715])\n const pill = mesh(cyl(0.07, 0.07, 0.01, 10), plastic(0xe6e0d0), [0.3, 0.06, 0.0705], [Math.PI / 2, 0, 0])\n return G(carton, band, label, title, pill)\n}\n","import type { ItemModelBuilder } from './registry'\n\n/**\n * Authored in the kit (no team model delivered); replace when the items team delivers one.\n * It draws in the units of the builder; `data/models.json` gives the scale to metres of the item `ibuprofen`.\n */\nexport const ibuprofen: ItemModelBuilder = ({ mesh, bx, cyl, G, paper, plastic }) => {\n const carton = mesh(bx(0.95, 0.5, 0.15), paper(0xe9772e))\n const band = mesh(bx(0.948, 0.1, 0.152), paper(0xf6f0e2), [0, 0.2, 0])\n const label = mesh(bx(0.6, 0.24, 0.01), paper(0xfdf8ee), [-0.1, -0.05, 0.0705])\n const title = mesh(bx(0.44, 0.05, 0.01), paper(0xc3541a), [-0.1, -0.0, 0.0715])\n const pill = mesh(cyl(0.07, 0.07, 0.012, 10), plastic(0xf3d9a0), [0.3, -0.05, 0.0705], [Math.PI / 2, 0, 0])\n return G(carton, band, label, title, pill)\n}\n","import type { ItemModelBuilder } from './registry'\n\n/**\n * Authored in the kit (no team model delivered); replace when the items team delivers one.\n * It draws in the units of the builder; `data/models.json` gives the scale to metres of the item `antihistamine`.\n */\nexport const antihistamine: ItemModelBuilder = ({ mesh, bx, cyl, G, paper, plastic }) => {\n const carton = mesh(bx(0.8, 0.5, 0.15), paper(0x7b5ea7))\n const band = mesh(bx(0.798, 0.1, 0.152), paper(0xf0eef6), [0, -0.2, 0])\n const label = mesh(bx(0.5, 0.26, 0.01), paper(0xf7f4fb), [-0.1, 0.05, 0.0705])\n const title = mesh(bx(0.36, 0.05, 0.01), paper(0x7b5ea7), [-0.1, 0.1, 0.0715])\n const pill = mesh(cyl(0.065, 0.065, 0.012, 10), plastic(0xf5f5f5), [0.28, 0.05, 0.0705], [Math.PI / 2, 0, 0])\n return G(carton, band, label, title, pill)\n}\n","import type { ItemModelBuilder } from './registry'\n\n/**\n * Authored in the kit (no team model delivered); replace when the items team delivers one.\n * It draws in the units of the builder; `data/models.json` gives the scale to metres of the item `ceftriaxone`.\n */\nexport const ceftriaxone: ItemModelBuilder = ({ mesh, bx, cyl, G, plastic, glass, metal, paper }) => {\n const tray = mesh(bx(1.0, 0.06, 0.3), plastic(0xdfe6ea), [0, -0.27, 0])\n const vials = [-0.35, 0, 0.35].flatMap((x) => [\n mesh(cyl(0.148, 0.148, 0.3, 8), glass(0xd8ecf2, 0.6), [x, -0.09, 0]),\n mesh(cyl(0.09, 0.148, 0.08, 8), glass(0xd8ecf2, 0.6), [x, 0.1, 0]),\n mesh(cyl(0.09, 0.09, 0.16, 8), metal(0xb9bec4), [x, 0.22, 0]),\n mesh(cyl(0.15, 0.15, 0.14, 8), paper(0xf2f0e6), [x, -0.1, 0]),\n ])\n return G(tray, ...vials)\n}\n","import type { ItemModelBuilder } from './registry'\n\n/**\n * Authored in the kit (no team model delivered); replace when the items team delivers one.\n * It draws in the units of the builder; `data/models.json` gives the scale to metres of the item `clonazepam`.\n */\nexport const clonazepam: ItemModelBuilder = ({ mesh, bx, cyl, G, paper, plastic }) => {\n const carton = mesh(bx(0.9, 0.5, 0.15), paper(0xf2f2f0))\n const band = mesh(bx(0.898, 0.14, 0.152), paper(0x2b8a6e), [0, 0.18, 0])\n const label = mesh(bx(0.55, 0.22, 0.01), paper(0xffffff), [-0.1, -0.07, 0.0705])\n const title = mesh(bx(0.4, 0.04, 0.01), paper(0x2b8a6e), [-0.1, -0.02, 0.0715])\n const pill = mesh(cyl(0.065, 0.065, 0.012, 10), plastic(0x6fb6e8), [0.3, -0.07, 0.0705], [Math.PI / 2, 0, 0])\n return G(carton, band, label, title, pill)\n}\n","import type { ItemModelBuilder } from './registry'\n\n/**\n * Authored in the kit (no team model delivered); replace when the items team delivers one.\n * It draws in the units of the builder; `data/models.json` gives the scale to metres of the item `activated_charcoal`.\n */\nexport const activatedCharcoal: ItemModelBuilder = ({ mesh, bx, cyl, G, plastic, paper }) => {\n const black = plastic(0x1c1c1c)\n const body = mesh(bx(0.6, 0.65, 0.25), black, [0, -0.15, 0])\n const shoulder = mesh(bx(0.44, 0.1, 0.2), black, [0, 0.225, 0])\n const neck = mesh(cyl(0.1, 0.1, 0.1, 10), black, [0, 0.325, 0])\n const cap = mesh(cyl(0.12, 0.12, 0.1, 10), plastic(0xe8e8e8), [0, 0.425, 0])\n const label = mesh(bx(0.5, 0.36, 0.01), paper(0xf2f2ee), [0, -0.15, 0.1205])\n const title = mesh(bx(0.36, 0.06, 0.01), paper(0x1c1c1c), [0, -0.05, 0.1215])\n return G(body, shoulder, neck, cap, label, title)\n}\n","import type { ItemModelBuilder } from './registry'\n\n/**\n * Authored in the kit (no team model delivered); replace when the items team delivers one.\n * It draws in the units of the builder; `data/models.json` gives the scale to metres of the item `adhesive_bandages`.\n */\nexport const adhesiveBandages: ItemModelBuilder = ({ mesh, bx, G, metal, paper }) => {\n const body = mesh(bx(1.0, 0.54, 0.15), metal(0xd9dde0), [0, -0.03, 0])\n const lid = mesh(bx(1.0, 0.06, 0.15), metal(0x2a8ad6), [0, 0.27, 0])\n const label = mesh(bx(0.7, 0.34, 0.01), paper(0xf6f6f2), [0, -0.05, 0.0705])\n const crossUpright = mesh(bx(0.08, 0.24, 0.01), paper(0xd2312d), [0, -0.05, 0.0715])\n const crossArm = mesh(bx(0.24, 0.08, 0.01), paper(0xd2312d), [0, -0.05, 0.0716])\n return G(body, lid, label, crossUpright, crossArm)\n}\n","import type { ItemModelBuilder } from './registry'\n\n/**\n * Authored in the kit (no team model delivered); replace when the items team delivers one.\n * It draws in the units of the builder; `data/models.json` gives the scale to metres of the item `medical_tape`.\n */\nexport const medicalTape: ItemModelBuilder = ({ mesh, cyl, lathe, G, cloth, plastic }) => {\n const roll = mesh(lathe([[0.12, -0.125], [0.248, -0.125], [0.248, 0.125], [0.12, 0.125]], 16), cloth(0xe9e6dc))\n const stripe = mesh(cyl(0.25, 0.25, 0.08, 16), cloth(0x3a78a8), [0, 0, 0])\n const core = mesh(lathe([[0.1, -0.125], [0.12, -0.125], [0.12, 0.125], [0.1, 0.125]], 16), plastic(0xffffff))\n const coreWall = mesh(lathe([[0.1, -0.125], [0.1, 0.125]], 16), plastic(0xf2f2f2))\n return G(roll, stripe, core, coreWall)\n}\n","import type { ItemModelBuilder } from './registry'\n\n/**\n * Authored in the kit (no team model delivered); replace when the items team delivers one.\n * It draws in the units of the builder; `data/models.json` gives the scale to metres of the item `sterile_gauze`.\n */\nexport const sterileGauze: ItemModelBuilder = ({ mesh, bx, G, paper }) => {\n const packet = mesh(bx(1.0, 1.0, 0.15), paper(0xeef3f5))\n const topSeal = mesh(bx(0.96, 0.08, 0.152), paper(0xc6d4da), [0, 0.46, 0])\n const bottomSeal = mesh(bx(0.96, 0.08, 0.152), paper(0xc6d4da), [0, -0.46, 0])\n const label = mesh(bx(0.6, 0.4, 0.01), paper(0x2f7fc1), [0, -0.05, 0.0705])\n const crossUpright = mesh(bx(0.07, 0.26, 0.01), paper(0xffffff), [0, -0.05, 0.0715])\n const crossArm = mesh(bx(0.26, 0.07, 0.01), paper(0xffffff), [0, -0.05, 0.0716])\n return G(packet, topSeal, bottomSeal, label, crossUpright, crossArm)\n}\n","import type { ItemModelBuilder } from './registry'\n\n/**\n * Authored in the kit (no team model delivered); replace when the items team delivers one.\n * It draws in the units of the builder; `data/models.json` gives the scale to metres of the item `povidone_iodine`.\n */\nexport const povidoneIodine: ItemModelBuilder = ({ mesh, cyl, lathe, G, glass, plastic, paper }) => {\n const bottle = mesh(lathe([[0, -0.55], [0.2, -0.55], [0.225, -0.5], [0.225, 0.15], [0.15, 0.28], [0.1, 0.33], [0.1, 0.34], [0, 0.34]], 12), glass(0x6b3a14, 0.85), [0, 0, 0], [0, 0, 0], [1, 1, 0.79])\n const label = mesh(cyl(0.2255, 0.2255, 0.4, 12), paper(0xf0e6cc), [0, -0.18, 0], [0, 0, 0], [1, 1, 0.79])\n const stripe = mesh(cyl(0.2255, 0.2255, 0.07, 12), paper(0xb5651d), [0, 0.0, 0], [0, 0, 0], [1, 1, 0.79])\n const cap = mesh(cyl(0.11, 0.11, 0.16, 10), plastic(0xf2f2f2), [0, 0.4, 0])\n const nozzle = mesh(cyl(0.03, 0.07, 0.07, 8), plastic(0xd8d8d8), [0, 0.515, 0])\n return G(bottle, label, stripe, cap, nozzle)\n}\n","import type { ItemModelBuilder } from './registry'\n\n/**\n * Authored in the kit (no team model delivered); replace when the items team delivers one.\n * It draws in the units of the builder; `data/models.json` gives the scale to metres of the item `suture_kit`.\n */\nexport const sutureKit: ItemModelBuilder = ({ mesh, bx, torus, G, plastic, metal, paper }) => {\n const lower = mesh(bx(1.5, 0.8, 0.15), plastic(0x2d5a7b), [0, 0, -0.075])\n const lid = mesh(bx(1.5, 0.8, 0.15), plastic(0x3d7aa3), [0, 0, 0.075])\n const latch = mesh(bx(0.2, 0.14, 0.304), metal(0xc2c7cc), [0.62, 0.0, 0])\n const label = mesh(bx(0.7, 0.34, 0.01), paper(0xf4f4f0), [-0.2, -0.1, 0.1455])\n const needle = mesh(torus(0.12, 0.018, 4.2), metal(0xd7dbe0), [-0.2, 0.1, 0.135])\n const thread = mesh(bx(0.5, 0.02, 0.01), paper(0x1c1c1c), [-0.2, -0.1, 0.1465])\n return G(lower, lid, latch, label, needle, thread)\n}\n","import type { ItemModelBuilder } from './registry'\n\n/**\n * Authored in the kit (no team model delivered); replace when the items team delivers one.\n * It draws in the units of the builder; `data/models.json` gives the scale to metres of the item `exam_gloves`.\n */\nexport const examGloves: ItemModelBuilder = ({ mesh, bx, G, plastic, paper }) => {\n const nitrile = plastic(0x3a6ea5)\n const cuff = mesh(bx(0.6, 0.22, 0.1), plastic(0x2c557f), [0, -0.49, 0])\n const palm = mesh(bx(0.7, 0.5, 0.1), nitrile, [0, -0.15, 0])\n const pinky = mesh(bx(0.16, 0.34, 0.1), nitrile, [-0.2625, 0.27, 0])\n const ring = mesh(bx(0.16, 0.44, 0.1), nitrile, [-0.0875, 0.32, 0])\n const middle = mesh(bx(0.16, 0.5, 0.1), nitrile, [0.0875, 0.35, 0])\n const index = mesh(bx(0.16, 0.46, 0.1), nitrile, [0.2625, 0.33, 0])\n const thumb = mesh(bx(0.15, 0.38, 0.1), nitrile, [0.46, 0.0, 0], [0, 0, -1.0])\n const tag = mesh(bx(0.4, 0.1, 0.01), paper(0xf4f4f0), [0, -0.49, 0.0455])\n return G(cuff, palm, pinky, ring, middle, index, thumb, tag)\n}\n","import type { ItemModelBuilder } from './registry'\n\n/**\n * Authored in the kit (no team model delivered); replace when the items team delivers one.\n * It draws in the units of the builder; `data/models.json` gives the scale to metres of the item `n95_mask`.\n */\nexport const n95Mask: ItemModelBuilder = ({ mesh, bx, extrude, G, cloth, metal, paper }) => {\n const white = cloth(0xf1f1ee)\n const strapMaterial = cloth(0xdcdcd6)\n const cup = mesh(extrude([[-0.5, 0.2], [-0.38, 0.53], [0.38, 0.53], [0.5, 0.2], [0.4, -0.42], [0, -0.53], [-0.4, -0.42]], 0.21, 0.02), white, [0, 0, -0.105])\n const fold = mesh(bx(0.9, 0.03, 0.01), paper(0xc9c9c2), [0, 0, 0.12])\n const noseClip = mesh(bx(0.5, 0.03, 0.01), metal(0x8e949a), [0, 0.5, 0.12])\n const strapTopLeft = mesh(bx(0.3, 0.04, 0.03), strapMaterial, [-0.6, 0.15, 0])\n const strapTopRight = mesh(bx(0.3, 0.04, 0.03), strapMaterial, [0.6, 0.15, 0])\n const strapLowLeft = mesh(bx(0.3, 0.04, 0.03), strapMaterial, [-0.6, -0.25, 0])\n const strapLowRight = mesh(bx(0.3, 0.04, 0.03), strapMaterial, [0.6, -0.25, 0])\n return G(cup, fold, noseClip, strapTopLeft, strapTopRight, strapLowLeft, strapLowRight)\n}\n","import type { ItemModelBuilder } from './registry'\n\n/**\n * Authored in the kit (no team model delivered); replace when the items team delivers one.\n * It draws in the units of the builder; `data/models.json` gives the scale to metres of the item `multivitamin`.\n */\nexport const multivitamin: ItemModelBuilder = ({ mesh, cyl, lathe, G, plastic, paper }) => {\n const bottle = mesh(lathe([[0, -0.45], [0.22, -0.45], [0.248, -0.41], [0.248, 0.15], [0.2, 0.24], [0.17, 0.26], [0, 0.26]], 12), plastic(0xc9791a))\n const label = mesh(cyl(0.25, 0.25, 0.42, 12), paper(0xf6f1e2), [0, -0.14, 0])\n const stripe = mesh(cyl(0.25, 0.25, 0.06, 12), paper(0x3f9e55), [0, 0.11, 0])\n const collar = mesh(cyl(0.2, 0.2, 0.03, 12), plastic(0xe8e8e8), [0, 0.265, 0])\n const cap = mesh(cyl(0.19, 0.19, 0.19, 12), plastic(0x3f9e55), [0, 0.355, 0])\n return G(bottle, label, stripe, collar, cap)\n}\n","import type { ItemModelBuilder } from './registry'\n\n/**\n * Authored in the kit (no team model delivered); replace when the items team delivers one.\n * It draws in the units of the builder; `data/models.json` gives the scale to metres of the item `maintenance_medication`.\n */\nexport const maintenanceMedication: ItemModelBuilder = ({ mesh, bx, cyl, lathe, G, plastic, paper }) => {\n const bottle = mesh(lathe([[0, -0.45], [0.19, -0.45], [0.21, -0.42], [0.21, 0.25], [0, 0.25]], 12), plastic(0xd9892b))\n const label = mesh(cyl(0.212, 0.212, 0.45, 12), paper(0xf6f4ee), [0, -0.1, 0])\n const stripe = mesh(cyl(0.212, 0.212, 0.07, 12), paper(0xc23b32), [0, 0.155, 0])\n const dosageBar = mesh(bx(0.04, 0.16, 0.01), paper(0x2a2a2a), [0, -0.1, 0.207])\n const dosageNotch = mesh(bx(0.16, 0.03, 0.01), paper(0x2a2a2a), [0, -0.02, 0.207])\n const cap = mesh(cyl(0.225, 0.225, 0.2, 12), plastic(0xf2f2f2), [0, 0.35, 0])\n return G(bottle, label, stripe, dosageBar, dosageNotch, cap)\n}\n","import type { ItemModelBuilder } from './registry'\n\n/**\n * Authored in the kit (no team model delivered); replace when the items team delivers one.\n * It draws in the units of the builder; `data/models.json` gives the scale to metres of the item `rehydration_salts`.\n */\nexport const rehydrationSalts: ItemModelBuilder = ({ mesh, bx, cyl, G, paper, metal }) => {\n const foil = metal(0xe6eef2)\n const lower = mesh(bx(0.9, 0.5, 0.1), foil, [0, -0.23, 0])\n const stripe = mesh(bx(0.9, 0.14, 0.1), paper(0x2f9fd0), [0, 0.09, 0])\n const upper = mesh(bx(0.9, 0.32, 0.1), foil, [0, 0.32, 0])\n const topCrimp = mesh(bx(0.9, 0.12, 0.05), metal(0xc9d4da), [0, 0.54, 0])\n const bottomCrimp = mesh(bx(0.9, 0.12, 0.05), metal(0xc9d4da), [0, -0.54, 0])\n const label = mesh(bx(0.6, 0.3, 0.01), paper(0xffffff), [0, -0.23, 0.0455])\n const drop = mesh(cyl(0.06, 0.06, 0.01, 8), paper(0xffffff), [0, 0.09, 0.0455], [Math.PI / 2, 0, 0])\n return G(lower, stripe, upper, topCrimp, bottomCrimp, label, drop)\n}\n","import type { ItemModelBuilder } from './registry'\n\n/**\n * Authored in the kit (no team model delivered); replace when the items team delivers one.\n * It draws in the units of the builder; `data/models.json` gives the scale to metres of the item `syringe`.\n */\nexport const syringe: ItemModelBuilder = ({ mesh, bx, cyl, G, plastic, metal, glass }) => {\n const along = [0, 0, Math.PI / 2] as const\n const alongTip = [0, 0, -Math.PI / 2] as const\n const barrel = mesh(cyl(0.075, 0.075, 0.7, 10), glass(0xcfe8f0, 0.55), [-0.1, 0, 0], along)\n const flange = mesh(cyl(0.1, 0.1, 0.025, 12), plastic(0xe8eef0), [-0.45, 0, 0], along)\n const stopper = mesh(cyl(0.07, 0.07, 0.07, 8), plastic(0x2b2b2b), [-0.3, 0, 0], along)\n const rod = mesh(cyl(0.022, 0.022, 0.5, 6), plastic(0xe8eef0), [-0.475, 0, 0], along)\n const thumbRest = mesh(cyl(0.09, 0.09, 0.025, 10), plastic(0xe8eef0), [-0.7375, 0, 0], along)\n const hub = mesh(cyl(0.025, 0.06, 0.1, 8), plastic(0xf0f0f0), [0.3, 0, 0], alongTip)\n const needle = mesh(cyl(0.012, 0.012, 0.4, 6), metal(0xc9ced3), [0.55, 0, 0], along)\n const marks = [-0.3, -0.1, 0.1].map((x) => mesh(bx(0.012, 0.15, 0.15), plastic(0x2a6fb5), [x, 0, 0]))\n return G(barrel, flange, stopper, rod, thumbRest, hub, needle, ...marks)\n}\n","import type { ItemModelBuilder } from './registry'\n\n/**\n * Authored in the kit (no team model delivered); replace when the items team delivers one.\n * It draws in the units of the builder; `data/models.json` gives the scale to metres of the item `antivenom`.\n */\nexport const antivenom: ItemModelBuilder = ({ mesh, bx, G, plastic, metal, paper }) => {\n const body = mesh(bx(1.5, 0.5, 0.5), plastic(0xe8ecef), [0, -0.2, 0])\n const lid = mesh(bx(1.5, 0.25, 0.5), plastic(0xc8352b), [0, 0.175, 0])\n const postLeft = mesh(bx(0.06, 0.15, 0.08), plastic(0x8f2620), [-0.25, 0.375, 0])\n const postRight = mesh(bx(0.06, 0.15, 0.08), plastic(0x8f2620), [0.25, 0.375, 0])\n const handle = mesh(bx(0.56, 0.05, 0.08), plastic(0x8f2620), [0, 0.425, 0])\n const latchLeft = mesh(bx(0.12, 0.22, 0.504), metal(0xb7bcc2), [-0.5, 0.05, 0])\n const latchRight = mesh(bx(0.12, 0.22, 0.504), metal(0xb7bcc2), [0.5, 0.05, 0])\n const label = mesh(bx(0.34, 0.3, 0.01), paper(0xfdfdfb), [0, -0.2, 0.2455])\n const crossUpright = mesh(bx(0.07, 0.22, 0.01), paper(0xc8352b), [0, -0.2, 0.2465])\n const crossArm = mesh(bx(0.22, 0.07, 0.01), paper(0xc8352b), [0, -0.2, 0.2466])\n return G(body, lid, postLeft, postRight, handle, latchLeft, latchRight, label, crossUpright, crossArm)\n}\n","import type { ItemModelBuilder } from './registry'\n\n/**\n * Authored in the kit (no team model delivered); replace when the items team delivers one.\n * It draws in the units of the builder; `data/models.json` gives the scale to metres of the item `saline_iv_bag`.\n */\nexport const salineIvBag: ItemModelBuilder = ({ mesh, bx, cyl, extrude, G, plastic, paper, glass, metal }) => {\n const bag = mesh(extrude([[-0.58, -0.8], [-0.5, -0.98], [0.5, -0.98], [0.58, -0.8], [0.58, 0.8], [0.5, 0.98], [-0.5, 0.98], [-0.58, 0.8]], 0.41, 0.02), glass(0xd7eef4, 0.5), [0, 0, -0.205])\n const header = mesh(bx(1.0, 0.25, 0.08), plastic(0xe4eef1), [0, 1.125, 0])\n const hangHole = mesh(bx(0.3, 0.1, 0.084), plastic(0x3a4a52), [0, 1.14, 0])\n const label = mesh(bx(0.8, 0.6, 0.02), paper(0xf6f9fa), [0, 0.1, 0.2135])\n const band = mesh(bx(0.82, 0.12, 0.02), paper(0x2f80c8), [0, 0.25, 0.2145])\n const adminPort = mesh(cyl(0.12, 0.09, 0.25, 8), plastic(0x2f80c8), [-0.25, -1.125, 0])\n const injectionPort = mesh(cyl(0.1, 0.07, 0.25, 8), metal(0x3a3a3a), [0.25, -1.125, 0])\n return G(bag, header, hangHole, label, band, adminPort, injectionPort)\n}\n","import type { ItemModelBuilder } from './registry'\n\n/**\n * Authored in the kit (no team model delivered); replace when the items team delivers one.\n * It draws in the units of the builder; `data/models.json` gives the scale to metres of the item `splint`.\n */\nexport const splint: ItemModelBuilder = ({ mesh, bx, extrude, G, plastic, metal }) => {\n const foam = mesh(extrude([[-2.28, -0.53], [2.28, -0.53], [2.28, 0.53], [-2.28, 0.53]], 0.05, 0.02), plastic(0xee6611), [0, 0, -0.025])\n const core = mesh(bx(4.2, 0.5, 0.01), metal(0x2070b0), [0, 0, 0.0455])\n const strapLeft = mesh(bx(0.35, 1.1, 0.1), plastic(0x3a3f45), [-1.4, 0, 0])\n const strapRight = mesh(bx(0.35, 1.1, 0.1), plastic(0x3a3f45), [1.4, 0, 0])\n return G(foam, core, strapLeft, strapRight)\n}\n","import type { ItemModelBuilder } from './registry'\n\n/**\n * Authored in the kit (no team model delivered); replace when the items team delivers one.\n * It draws in the units of the builder; `data/models.json` gives the scale to metres of the item `thermometer`.\n */\nexport const thermometer: ItemModelBuilder = ({ mesh, bx, cyl, G, plastic, metal, glass }) => {\n const along = [0, 0, -Math.PI / 2] as const\n const body = mesh(bx(0.8, 0.19, 0.3), plastic(0xf2f4f5), [-0.2, 0, 0])\n const screen = mesh(bx(0.34, 0.01, 0.16), glass(0x9fc7a4, 0.9), [-0.3, 0.098, 0])\n const button = mesh(cyl(0.05, 0.05, 0.01, 10), plastic(0x2a8ad6), [0.0, 0.098, 0])\n const collar = mesh(cyl(0.07, 0.07, 0.04, 10), plastic(0xd4d9dc), [0.22, 0, 0], along)\n const probe = mesh(cyl(0.04, 0.06, 0.36, 10), metal(0xb7bcc2), [0.42, 0, 0], along)\n return G(body, screen, button, collar, probe)\n}\n","import type { ItemModelBuilder } from './registry'\n\n/**\n * Authored in the kit (no team model delivered); replace when the items team delivers one.\n * It draws in the units of the builder; `data/models.json` gives the scale to metres of the item `alcohol_70`.\n */\nexport const alcohol70: ItemModelBuilder = ({ mesh, cyl, lathe, G, glass, plastic, paper }) => {\n const slim = [1, 1, 0.714] as const\n const bottle = mesh(lathe([[0, -1], [0.31, -1], [0.35, -0.94], [0.35, 0.2], [0.25, 0.55], [0.12, 0.68], [0.12, 0.78], [0, 0.78]], 12), glass(0xe8f2f5, 0.6), [0, 0, 0], [0, 0, 0], slim)\n const label = mesh(cyl(0.351, 0.351, 0.8, 12), paper(0xf4f4f0), [0, -0.35, 0], [0, 0, 0], slim)\n const stripe = mesh(cyl(0.351, 0.351, 0.2, 12), paper(0xc23b32), [0, -0.1, 0], [0, 0, 0], slim)\n const cap = mesh(cyl(0.15, 0.15, 0.14, 10), plastic(0xf2f2f2), [0, 0.85, 0])\n const nozzle = mesh(cyl(0.04, 0.07, 0.08, 8), plastic(0xd8d8d8), [0, 0.96, 0])\n return G(bottle, label, stripe, cap, nozzle)\n}\n","import type { ItemModelBuilder } from './registry'\n\n/**\n * Authored in the kit (no team model delivered); replace when the items team delivers one.\n * It draws in the units of the builder; `data/models.json` gives the scale to metres of the item `can_opener`.\n */\nexport const canOpener: ItemModelBuilder = ({ mesh, bx, cyl, G, metal, plastic }) => {\n const steel = metal(0xa9adb2)\n const grip = plastic(0x2f5d8a)\n const rotateAcross = [Math.PI / 2, 0, 0] as const\n return G(\n mesh(bx(9, 1, 2.2), steel, [1.5, -1.5, 0]),\n mesh(bx(5, 1.6, 2.5), grip, [-4.5, -1.2, 0]),\n mesh(bx(8, 1, 2.2), steel, [-3, 1.5, 0]),\n mesh(bx(5, 1, 2.5), grip, [-4.5, 1.5, 0]),\n mesh(bx(3, 2.4, 1.5), steel, [5.5, 0, 0]),\n mesh(cyl(1.2, 1.2, 0.4, 8), steel, [5.5, -0.8, 0.85], rotateAcross),\n mesh(cyl(0.4, 0.4, 2.4, 8), metal(0x6b6f74), [2.6, 0, 0], rotateAcross),\n )\n}\n","import type { ItemModelBuilder } from './registry'\n\n/**\n * Authored in the kit (no team model delivered); replace when the items team delivers one.\n * It draws in the units of the builder; `data/models.json` gives the scale to metres of the item `pliers`.\n */\nexport const pliers: ItemModelBuilder = ({ mesh, bx, cyl, G, metal, plastic }) => {\n const steel = metal(0x7b7f84)\n const grip = plastic(0xc8541c)\n return G(\n mesh(bx(9, 3, 2), grip, [-5.5, 0, 2.5]),\n mesh(bx(9, 3, 2), grip, [-5.5, 0, -2.5]),\n mesh(bx(2, 1.2, 1.4), steel, [0, 0, 1.2]),\n mesh(bx(2, 1.2, 1.4), steel, [0, 0, -1.2]),\n mesh(bx(3, 1.6, 5), steel, [2.5, 0, 0]),\n mesh(cyl(0.9, 0.9, 3, 8), metal(0x4d5054), [2.5, 0, 0]),\n mesh(bx(6, 1.2, 2.2), steel, [7, 0, 1.4]),\n mesh(bx(6, 1.2, 2.2), steel, [7, 0, -1.4]),\n )\n}\n","import type { ItemModelBuilder } from './registry'\n\n/**\n * Authored in the kit (no team model delivered); replace when the items team delivers one.\n * It draws in the units of the builder; `data/models.json` gives the scale to metres of the item `bolt_cutters`.\n */\nexport const boltCutters: ItemModelBuilder = ({ mesh, bx, cyl, G, metal, plastic }) => {\n const steel = metal(0x4a4e53)\n const grip = plastic(0xb82a1f)\n const alongX = [0, 0, Math.PI / 2] as const\n return G(\n mesh(cyl(1.2, 1.2, 36, 8), steel, [-12, 0, 3], alongX),\n mesh(cyl(1.2, 1.2, 36, 8), steel, [-12, 0, -3], alongX),\n mesh(cyl(1.5, 1.5, 14, 8), grip, [-23, 0, 3], alongX),\n mesh(cyl(1.5, 1.5, 14, 8), grip, [-23, 0, -3], alongX),\n mesh(bx(8, 3, 8), steel, [8, 0, 0]),\n mesh(bx(4, 6, 15), steel, [14, 0, 0]),\n mesh(cyl(1.5, 1.5, 6, 8), metal(0x8d9196), [14, 0, 0]),\n mesh(bx(14, 5.5, 3), metal(0x6f7378), [23, 0, 6]),\n mesh(bx(14, 5.5, 3), metal(0x6f7378), [23, 0, -6]),\n )\n}\n","import type { ItemModelBuilder } from './registry'\n\n/**\n * Authored in the kit (no team model delivered); replace when the items team delivers one.\n * It draws in the units of the builder; `data/models.json` gives the scale to metres of the item `bucket`.\n */\nexport const bucket: ItemModelBuilder = ({ mesh, bx, cyl, G, plastic, metal }) => {\n const body = plastic(0x2c5f9e)\n const wire = metal(0x8a8d91)\n return G(\n mesh(cyl(13.6, 11.6, 23, 16), body, [0, -2, 0]),\n mesh(cyl(14, 14, 1.6, 16), plastic(0x234d82), [0, 8.7, 0]),\n mesh(cyl(11.8, 11.8, 1, 16), plastic(0x234d82), [0, -13, 0]),\n mesh(bx(0.6, 4, 0.6), wire, [13, 11.5, 0]),\n mesh(bx(0.6, 4, 0.6), wire, [-13, 11.5, 0]),\n mesh(bx(26.6, 0.5, 0.6), wire, [0, 13.25, 0]),\n )\n}\n","import type { ItemModelBuilder } from './registry'\n\n/**\n * Authored in the kit (no team model delivered); replace when the items team delivers one.\n * It draws in the units of the builder; `data/models.json` gives the scale to metres of the item `binoculars`.\n */\nexport const binoculars: ItemModelBuilder = ({ mesh, bx, cyl, G, M, plastic, metal }) => {\n const shell = plastic(0x2a2d30)\n const trim = metal(0x6a6e73)\n const lens = M(0x6a8fa3, 'glass', { metalness: 0.2, roughness: 0.2 })\n const barrel = (x: number) => [\n mesh(cyl(3.8, 3.8, 8, 12), shell, [x, -0.5, 0]),\n mesh(cyl(3, 3, 3.5, 12), trim, [x, -5.75, 0]),\n mesh(cyl(6, 4.6, 4, 12), shell, [x, 5.5, 0], [0, 0, 0], [0.8, 1, 1]),\n mesh(cyl(5.4, 5.4, 0.2, 8), lens, [x, 7.4, 0], [0, 0, 0], [0.8, 1, 1]),\n ]\n return G(...barrel(-4.2), ...barrel(4.2), mesh(bx(2.4, 6, 3), trim), mesh(cyl(1.3, 1.3, 3, 8), metal(0x3c3f43), [0, 0.5, 0]))\n}\n","import type { ItemModelBuilder } from './registry'\n\n/**\n * Authored in the kit (no team model delivered); replace when the items team delivers one.\n * It draws in the units of the builder; `data/models.json` gives the scale to metres of the item `matches`.\n */\nexport const matches: ItemModelBuilder = ({ mesh, bx, cyl, G, paper, wood, food }) => {\n const stick = wood(0xd9bb84)\n const head = food(0xb03a2a)\n const matchAt = (x: number) => [mesh(cyl(0.12, 0.12, 3.2, 6), stick, [x, 0.6, 0], [Math.PI / 2, 0, 0]), mesh(bx(0.3, 0.3, 0.4), head, [x, 0.6, 1.5])]\n return G(\n mesh(bx(5, 1.2, 3.4), paper(0xcdb07a)),\n mesh(bx(2.8, 1.5, 3.5), paper(0x9c3b2e), [1.1, 0, 0]),\n mesh(bx(2.4, 0.1, 1.2), paper(0x4a3f38), [1.1, 0.7, 0]),\n ...matchAt(-2.1),\n ...matchAt(-1.7),\n ...matchAt(-1.3),\n )\n}\n","import type { ItemModelBuilder } from './registry'\n\n/**\n * Authored in the kit (no team model delivered); replace when the items team delivers one.\n * It draws in the units of the builder; `data/models.json` gives the scale to metres of the item `pocket_knife`.\n */\nexport const pocketKnife: ItemModelBuilder = ({ mesh, bx, cyl, G, metal, plastic }) => {\n const steel = metal(0xb5b9be)\n return G(\n mesh(bx(7.5, 2.2, 3.2), plastic(0xb02a22), [-1.75, 0, 0]),\n mesh(bx(0.5, 2, 3), steel, [1.75, 0, 0]),\n mesh(bx(0.5, 2.1, 3.1), steel, [-5.25, 0, 0]),\n mesh(cyl(0.45, 0.45, 3.2, 8), metal(0x6b6f74), [1.2, 0, 0], [Math.PI / 2, 0, 0]),\n mesh(bx(3.6, 0.3, 1.5), steel, [3.7, 0, 0]),\n mesh(bx(3.6, 0.15, 0.4), metal(0x8c9096), [3.7, 0.2, -0.55]),\n )\n}\n","import type { ItemModelBuilder } from './registry'\n\n/**\n * Authored in the kit (no team model delivered); replace when the items team delivers one.\n * It draws in the units of the builder; `data/models.json` gives the scale to metres of the item `screwdriver`.\n */\nexport const screwdriver: ItemModelBuilder = ({ mesh, bx, cyl, G, metal, plastic }) => {\n const alongX = [0, 0, Math.PI / 2] as const\n const ring = plastic(0x1f2022)\n return G(\n mesh(cyl(1.9, 1.9, 8, 8), plastic(0xd4601c), [-7, 0, 0], alongX),\n mesh(cyl(2, 2, 0.5, 8), ring, [-10, 0, 0], alongX),\n mesh(cyl(2, 2, 0.5, 8), ring, [-8, 0, 0], alongX),\n mesh(cyl(2, 2, 0.5, 8), ring, [-6, 0, 0], alongX),\n mesh(cyl(1.2, 1.2, 2, 8), metal(0x9a9ea3), [-2, 0, 0], alongX),\n mesh(cyl(0.45, 0.45, 11, 8), metal(0x8d9196), [4.5, 0, 0], alongX),\n mesh(bx(1, 0.7, 0.12), metal(0x6f7378), [10.5, 0, 0]),\n )\n}\n","import type { ItemModelBuilder } from './registry'\n\n/**\n * Authored in the kit (no team model delivered); replace when the items team delivers one.\n * It draws in the units of the builder; `data/models.json` gives the scale to metres of the item `adjustable_wrench`.\n */\nexport const adjustableWrench: ItemModelBuilder = ({ mesh, bx, cyl, G, metal, plastic }) => {\n const steel = metal(0x8a8e93)\n return G(\n mesh(bx(17, 1.6, 2.2), steel, [-4, 0, 0]),\n mesh(cyl(0.55, 0.55, 1.65, 8), plastic(0x2a2c2e), [-11, 0, 0]),\n mesh(bx(4, 2, 6), steel, [6.5, 0, 0]),\n mesh(bx(4, 2, 2), steel, [10.5, 0, -2]),\n mesh(bx(4, 2, 1.8), steel, [10.5, 0, 2.1]),\n mesh(cyl(0.8, 0.8, 6, 8), metal(0x55595d), [6.5, 0, 0], [Math.PI / 2, 0, 0]),\n )\n}\n","import type { ItemModelBuilder } from './registry'\n\n/**\n * Authored in the kit (no team model delivered); replace when the items team delivers one.\n * It draws in the units of the builder; `data/models.json` gives the scale to metres of the item `hoe`.\n */\nexport const hoe: ItemModelBuilder = ({ mesh, bx, cyl, G, metal, wood }) => {\n const steel = metal(0x7d8186)\n return G(\n mesh(cyl(1.3, 1.3, 122, 8), wood(0x9a7448), [-6.5, 1.7, 0], [0, 0, Math.PI / 2]),\n mesh(bx(8, 2.6, 3), steel, [58.5, 1.7, 0]),\n mesh(bx(5, 2.2, 2.6), steel, [65, 0.4, 0]),\n mesh(bx(0.8, 6, 17), steel, [67.1, 0, 0]),\n mesh(bx(1.6, 1, 17), metal(0xa4a8ad), [66.7, -2.5, 0]),\n mesh(bx(1.6, 1, 10), metal(0x5d6166), [65.9, 0.5, 0]),\n )\n}\n","import type { ItemModelBuilder } from './registry'\n\n/**\n * Authored in the kit (no team model delivered); replace when the items team delivers one.\n * It draws in the units of the builder; `data/models.json` gives the scale to metres of the item `fire_extinguisher`.\n */\nexport const fireExtinguisher: ItemModelBuilder = ({ mesh, bx, cyl, G, M, metal, plastic, paper }) => {\n const red = metal(0xb3261e)\n const brass = metal(0x9a8a4a)\n const hose = plastic(0x1f2022)\n return G(\n mesh(cyl(7, 7, 34, 12), red, [0, -7, 0]),\n mesh(cyl(8, 8, 2, 12), hose, [0, -23, 0]),\n mesh(cyl(7.1, 7.1, 10, 12), paper(0xe8e4d8), [0, -8, 0]),\n mesh(cyl(2.8, 7, 5, 12), red, [0, 12.5, 0]),\n mesh(cyl(2.2, 2.2, 4, 8), brass, [0, 17, 0]),\n mesh(bx(6, 4, 4), brass, [0, 21, 0]),\n mesh(bx(8, 1, 2.4), red, [0, 23.5, 0]),\n mesh(cyl(0.7, 0.7, 5, 8), hose, [5.5, 20, 0], [0, 0, Math.PI / 2]),\n mesh(cyl(0.7, 0.7, 16, 8), hose, [7.3, 12, 0]),\n mesh(cyl(0.9, 0.9, 1.5, 6), metal(0x3c3f43), [7.3, 3.2, 0]),\n mesh(cyl(1.4, 1.4, 0.8, 8), M(0xe8e4d8, 'metal', { metalness: 0.3, roughness: 0.4 }), [-1.5, 21, 2.2], [Math.PI / 2, 0, 0]),\n )\n}\n","import type { ItemModelBuilder } from './registry'\n\n/**\n * Authored in the kit (no team model delivered); replace when the items team delivers one.\n * It draws in the units of the builder; `data/models.json` gives the scale to metres of the item `duct_tape`.\n */\nexport const ductTape: ItemModelBuilder = ({ mesh, bx, lathe, G, metal, paper }) => {\n const ring = (inner: number, outer: number, half: number) => lathe([[inner, -half], [outer, -half], [outer, half], [inner, half], [inner, -half]], 16)\n return G(\n mesh(ring(2.8, 5, 2.5), metal(0x8b8f93)),\n mesh(ring(2.4, 2.8, 2.3), paper(0xa88a5c)),\n mesh(bx(0.2, 4.6, 2.4), metal(0xa4a8ac), [4.9, 0, 0]),\n )\n}\n","import type { ItemModelBuilder } from './registry'\n\n/**\n * Authored in the kit (no team model delivered); replace when the items team delivers one.\n * It draws in the units of the builder; `data/models.json` gives the scale to metres of the item `camp_stove`.\n */\nexport const campStove: ItemModelBuilder = ({ mesh, bx, cyl, G, metal, plastic }) => {\n const steel = metal(0x4f5358)\n const grate = metal(0x2c2e30)\n const post = (x: number, z: number) => mesh(bx(0.8, 3, 0.8), grate, [x, 2.8, z])\n return G(\n mesh(bx(18, 3.6, 11), steel, [0, -3.2, 0]),\n mesh(cyl(3.6, 3.6, 1.8, 12), metal(0x8a8e93), [0, -0.5, 0]),\n mesh(cyl(2.4, 3, 1, 12), metal(0x2c2e30), [0, 0.9, 0]),\n mesh(cyl(1.1, 1.1, 1, 8), plastic(0xb5321f), [6, -3.2, 5], [Math.PI / 2, 0, 0]),\n post(6.8, 4), post(-6.8, 4), post(6.8, -4), post(-6.8, -4),\n mesh(bx(14, 0.8, 0.8), grate, [0, 4.6, 4]),\n mesh(bx(14, 0.8, 0.8), grate, [0, 4.6, -4]),\n mesh(bx(0.8, 0.8, 9), grate, [6.8, 4.6, 0]),\n mesh(bx(0.8, 0.8, 9), grate, [-6.8, 4.6, 0]),\n )\n}\n","import type { ItemModelBuilder } from './registry'\n\n/**\n * Authored in the kit (no team model delivered); replace when the items team delivers one.\n * It draws in the units of the builder; `data/models.json` gives the scale to metres of the item `lighter`.\n */\nexport const lighter: ItemModelBuilder = ({ mesh, bx, cyl, G, metal, plastic }) => G(\n mesh(bx(2.46, 5.4, 1.16), plastic(0x2f6f4e), [0, -1.3, 0]),\n mesh(bx(2.5, 1.4, 1.2), plastic(0xe6e0d0), [0, -2.5, 0]),\n mesh(bx(2.4, 2.2, 1.1), metal(0xb0b4b9), [0, 2.5, 0]),\n mesh(cyl(0.6, 0.6, 0.9, 8), metal(0x55595d), [-0.5, 3.3, 0], [Math.PI / 2, 0, 0]),\n mesh(bx(0.5, 0.4, 0.4), metal(0x8d9196), [0.5, 3.8, 0]),\n)\n","import type { ItemModelBuilder } from './registry'\n\n/**\n * Authored in the kit (no team model delivered); replace when the items team delivers one.\n * It draws in the units of the builder; `data/models.json` gives the scale to metres of the item `lockpick_kit`.\n */\nexport const lockpickKit: ItemModelBuilder = ({ mesh, bx, cyl, G, metal, cloth }) => {\n const leather = cloth(0x5b3d28)\n const pick = metal(0xaeb2b7)\n return G(\n mesh(bx(10, 6, 1.7), leather, [0, -0.5, 0]),\n mesh(bx(10, 3.2, 2), cloth(0x6b4830), [0, 0.9, 0]),\n mesh(cyl(0.45, 0.45, 0.2, 8), metal(0xb08a3c), [0, -0.7, 0.9], [Math.PI / 2, 0, 0]),\n mesh(bx(0.3, 2.2, 0.3), pick, [-2.5, 2.4, 0]),\n mesh(bx(0.3, 2.2, 0.3), pick, [0, 2.4, 0]),\n mesh(bx(0.3, 2.2, 0.3), pick, [2.5, 2.4, 0]),\n )\n}\n","import type { ItemModelBuilder } from './registry'\n\n/**\n * Authored in the kit (no team model delivered); replace when the items team delivers one.\n * It draws in the units of the builder; `data/models.json` gives the scale to metres of the item `sewing_kit`.\n */\nexport const sewingKit: ItemModelBuilder = ({ mesh, bx, cyl, G, plastic, cloth, wood }) => {\n const spool = (x: number, color: number) => [mesh(cyl(0.75, 0.75, 3, 8), cloth(color), [x, 1, 0.4]), mesh(cyl(0.95, 0.95, 0.3, 8), wood(0xc9a46a), [x, 2.35, 0.4])]\n return G(\n mesh(bx(9, 2, 3), plastic(0x3a5a78), [0, -1.5, 0]),\n mesh(bx(8.4, 0.3, 2.4), cloth(0xa83a3a), [0, -0.4, 0.1]),\n mesh(bx(9, 5, 0.4), plastic(0x2f4a63), [0, 0, -1.3]),\n ...spool(-3, 0xc93a3a),\n ...spool(0, 0x3a6fc9),\n ...spool(3, 0xd8b43a),\n )\n}\n","import type { ItemModelBuilder } from './registry'\n\n/**\n * Authored in the kit (no team model delivered); replace when the items team delivers one.\n * It draws in the units of the builder; `data/models.json` gives the scale to metres of the item `car_jack`.\n */\nexport const carJack: ItemModelBuilder = ({ mesh, bx, cyl, G, metal }) => {\n const steel = metal(0x5f6469)\n const dark = metal(0x3e4247)\n const arm = (x: number, y: number, angle: number, z: number) => mesh(bx(12.65, 1.2, 1.6), steel, [x, y, z], [0, 0, angle])\n const arms = [3.8, -3.8].flatMap((z) => [arm(-5.9, 2, 0.3217, z), arm(-5.9, -2, -0.3217, z), arm(5.9, 2, -0.3217, z), arm(5.9, -2, 0.3217, z)])\n return G(\n mesh(bx(8, 1, 11), dark, [0, -5, 0]),\n mesh(bx(8, 1, 11), dark, [0, 5, 0]),\n ...arms,\n mesh(cyl(0.6, 0.6, 30, 8), metal(0x8d9196), [0, 0, 0], [0, 0, Math.PI / 2]),\n mesh(bx(1.6, 2.4, 3), dark, [-11.8, 0, 0]),\n mesh(bx(1.6, 2.4, 3), dark, [11.8, 0, 0]),\n mesh(bx(1, 0.8, 5), metal(0xb5321f), [14.5, 0, 0]),\n )\n}\n","import type { ItemModelBuilder } from './registry'\n\n/**\n * Authored in the kit (no team model delivered); replace when the items team delivers one.\n * It draws in the units of the builder; `data/models.json` gives the scale to metres of the item `mechanic_toolbox`.\n */\nexport const mechanicToolbox: ItemModelBuilder = ({ mesh, bx, G, metal, plastic }) => {\n const red = metal(0xa8281f)\n const steel = metal(0x8d9196)\n const latch = (x: number) => mesh(bx(2.6, 6, 0.3), steel, [x, 2, 9.85])\n return G(\n mesh(bx(40, 12, 19.4), red, [0, -4, 0]),\n mesh(bx(40, 1.2, 19.6), metal(0x2c2e30), [0, -9.4, 0]),\n mesh(bx(40, 5, 19.4), red, [0, 4.5, 0]),\n mesh(bx(40, 0.5, 19.6), metal(0x2c2e30), [0, 2, 0]),\n mesh(bx(1.2, 2, 1.8), plastic(0x1f2022), [-7.5, 8, 0]),\n mesh(bx(1.2, 2, 1.8), plastic(0x1f2022), [7.5, 8, 0]),\n mesh(bx(16.2, 1, 1.8), plastic(0x1f2022), [0, 9.5, 0]),\n latch(-11), latch(11),\n )\n}\n","import type { ItemModelBuilder } from './registry'\n\n/**\n * Authored in the kit (no team model delivered); replace when the items team delivers one.\n * It draws in the units of the builder; `data/models.json` gives the scale to metres of the item `gas_torch`.\n */\nexport const gasTorch: ItemModelBuilder = ({ mesh, cyl, G, metal, plastic }) => {\n const brass = metal(0xa88a3c)\n const alongX = [0, 0, Math.PI / 2] as const\n return G(\n mesh(cyl(5, 5, 22, 12), metal(0xe3b82a), [0, -10, 0]),\n mesh(cyl(7.5, 7.5, 1.5, 16), metal(0x3c3f43), [0, -20.25, 0]),\n mesh(cyl(2.2, 5, 2.5, 12), metal(0xe3b82a), [0, 2.25, 0]),\n mesh(cyl(2.4, 2.4, 3, 8), brass, [0, 5, 0]),\n mesh(cyl(1, 1, 5, 8), plastic(0x1f2022), [4.5, 5, 0], alongX),\n mesh(cyl(1.6, 1.6, 1.2, 8), plastic(0xb5321f), [7, 5, 0], alongX),\n mesh(cyl(1.4, 1.4, 12, 8), brass, [0, 12.5, 0]),\n mesh(cyl(2.8, 1.4, 2.5, 8), metal(0x55595d), [0, 19.75, 0]),\n )\n}\n","import type { ItemModelBuilder } from './registry'\n\n/**\n * Authored in the kit (no team model delivered); replace when the items team delivers one.\n * It draws in the units of the builder; `data/models.json` gives the scale to metres of the item `inverter_welder`.\n */\nexport const inverterWelder: ItemModelBuilder = ({ mesh, bx, cyl, G, M, metal, plastic }) => {\n const front = [Math.PI / 2, 0, 0] as const\n const dark = plastic(0x1f2022)\n return G(\n mesh(bx(30, 19, 12.8), metal(0xc2561c), [0, -1.5, 0]),\n mesh(bx(27, 15, 0.15), dark, [0, -1.5, 6.375]),\n mesh(bx(1.8, 2, 1.8), dark, [-8, 9, 0]),\n mesh(bx(1.8, 2, 1.8), dark, [8, 9, 0]),\n mesh(bx(18, 1, 1.8), dark, [0, 10.5, 0]),\n mesh(bx(6, 2.6, 0.12), M(0x2e5d3a, 'glass', { emissive: 0x1a6b3a, emissiveIntensity: 0.5 }), [-7, 3.5, 6.44]),\n mesh(cyl(1.4, 1.4, 1.2, 8), metal(0xb8bcc1), [-8, -2.5, 5.9], front),\n mesh(cyl(1.4, 1.4, 1.2, 8), metal(0xb8bcc1), [-3, -2.5, 5.9], front),\n mesh(cyl(1.2, 1.2, 1.2, 8), plastic(0xb5321f), [8.5, -7, 5.9], front),\n mesh(cyl(1.2, 1.2, 1.2, 8), plastic(0x15161a), [11.5, -7, 5.9], front),\n )\n}\n","import type { ItemModelBuilder } from './registry'\n\n/**\n * Authored in the kit (no team model delivered); replace when the items team delivers one.\n * It draws in the units of the builder; `data/models.json` gives the scale to metres of the item `pot`.\n */\nexport const pot: ItemModelBuilder = ({ mesh, bx, cyl, G, metal, plastic }) => {\n const steel = metal(0x9fa3a8)\n return G(\n mesh(cyl(12.2, 11.4, 12.5, 16), steel, [0, -1.25, 0]),\n mesh(cyl(12.5, 12.5, 0.8, 16), metal(0x8a8e93), [0, 4.6, 0]),\n mesh(cyl(12.2, 12.2, 0.7, 16), steel, [0, 5.35, 0]),\n mesh(cyl(4, 11, 1.1, 16), metal(0x8a8e93), [0, 6.25, 0]),\n mesh(cyl(1.3, 1, 0.7, 8), plastic(0x1f2022), [0, 7.15, 0]),\n mesh(bx(3.4, 1.2, 2.4), plastic(0x1f2022), [10.8, 3, 0]),\n mesh(bx(3.4, 1.2, 2.4), plastic(0x1f2022), [-10.8, 3, 0]),\n )\n}\n","import type { ItemModelBuilder } from './registry'\n\n/**\n * Authored in the kit (no team model delivered); replace when the items team delivers one.\n * It draws in the units of the builder; `data/models.json` gives the scale to metres of the item `cordless_drill`.\n */\nexport const cordlessDrill: ItemModelBuilder = ({ mesh, bx, cyl, G, metal, plastic }) => {\n const body = plastic(0x2f7a45)\n const alongX = [0, 0, Math.PI / 2] as const\n const dark = plastic(0x1f2022)\n return G(\n mesh(cyl(3.2, 3.5, 2, 12), dark, [-10, 6.5, 0], alongX),\n mesh(cyl(3.5, 3.5, 10, 12), body, [-4, 6.5, 0], alongX),\n mesh(cyl(2.8, 3.3, 3, 12), dark, [2.5, 6.5, 0], alongX),\n mesh(cyl(2.3, 2, 4, 12), metal(0x9a9ea3), [6, 6.5, 0], alongX),\n mesh(cyl(0.5, 0.5, 3, 8), metal(0x6f7378), [9.5, 6.5, 0], alongX),\n mesh(bx(4, 8, 5), dark, [-3.5, -0.5, 0]),\n mesh(bx(0.8, 2.2, 1.4), plastic(0xb5321f), [-1.1, 1, 0]),\n mesh(bx(9, 5.5, 6), body, [-5.5, -7.25, 0]),\n )\n}\n","import type { ItemModelBuilder } from './registry'\n\n/**\n * Authored in the kit (no team model delivered); replace when the items team delivers one.\n * It draws in the units of the builder; `data/models.json` gives the scale to metres of the item `flint_striker`.\n */\nexport const flintStriker: ItemModelBuilder = ({ mesh, bx, cyl, G, metal, wood }) => {\n const alongX = [0, 0, Math.PI / 2] as const\n return G(\n mesh(cyl(1, 1, 5, 8), wood(0x6b4a2c), [-3, 0, 0], alongX, [1, 1, 0.75]),\n mesh(cyl(0.8, 0.8, 0.5, 8), metal(0x9a9ea3), [-5.25, 0, 0], alongX, [1, 1, 0.75]),\n mesh(cyl(0.9, 0.9, 0.6, 8), metal(0x9a9ea3), [-0.2, 0, 0], alongX, [1, 1, 0.75]),\n mesh(cyl(0.5, 0.5, 5.6, 8), metal(0x4a4d51), [2.8, 0.1, 0], alongX),\n mesh(bx(4, 0.2, 1.1), metal(0xb3b7bc), [3.4, -0.6, 0]),\n )\n}\n","import type { ItemModelBuilder } from './registry'\n\n/**\n * Authored in the kit (no team model delivered); replace when the items team delivers one.\n * It draws in the units of the builder; `data/models.json` gives the scale to metres of the item `sharpening_stone`.\n */\nexport const sharpeningStone: ItemModelBuilder = ({ mesh, bx, G, wood, plastic, paper }) => G(\n mesh(bx(19.2, 2, 2.5), wood(0x7a5632), [0, -1.5, 0]),\n mesh(bx(0.4, 2, 2.5), plastic(0x1f2022), [-9.8, -1.5, 0]),\n mesh(bx(0.4, 2, 2.5), plastic(0x1f2022), [9.8, -1.5, 0]),\n mesh(bx(9.4, 3, 2.3), paper(0x8c8f8a), [-4.7, 1, 0]),\n mesh(bx(9.4, 3, 2.3), paper(0xc9c3b0), [4.7, 1, 0]),\n)\n","import type { ItemModelBuilder } from './registry'\n\n/**\n * Authored in the kit (no team model delivered); replace when the items team delivers one.\n * It draws in the units of the builder; `data/models.json` gives the scale to metres of the item `shovel`.\n */\nexport const shovel: ItemModelBuilder = ({ mesh, bx, cyl, G, metal, wood }) => {\n const steel = metal(0x7d8186)\n return G(\n mesh(cyl(1.7, 1.7, 86, 8), wood(0x9a7448), [-12, 1.8, 0], [0, 0, Math.PI / 2]),\n mesh(cyl(1.5, 1.5, 12, 8), wood(0x8a643c), [-53.8, 1.8, 0], [Math.PI / 2, 0, 0]),\n mesh(bx(10, 3.6, 3.6), steel, [30, -0.6, 0]),\n mesh(bx(32, 0.9, 3.6), steel, [39, -2.35, 0]),\n mesh(bx(27, 0.7, 22), steel, [41.5, -3.15, 0]),\n mesh(bx(3, 0.8, 22), metal(0xa4a8ad), [53.5, -3.1, 0]),\n )\n}\n","import type { ItemModelBuilder } from './registry'\n\n/**\n * Authored in the kit (no team model delivered); replace when the items team delivers one.\n * It draws in the units of the builder; `data/models.json` gives the scale to metres of the item `hacksaw`.\n */\nexport const hacksaw: ItemModelBuilder = ({ mesh, bx, cyl, G, metal, plastic }) => {\n const frame = metal(0x3f4348)\n return G(\n mesh(bx(10, 3, 4), plastic(0xc4521b), [-16, 0, 0]),\n mesh(bx(1.2, 1.4, 12), frame, [-11.4, 0, 0]),\n mesh(bx(1.2, 1.4, 12), frame, [19.8, 0, 0]),\n mesh(bx(33, 1.4, 1.2), frame, [4.5, 0, 5.4]),\n mesh(bx(31, 0.4, 0.8), metal(0xb5b9be), [4.5, 0, -5.4]),\n mesh(cyl(0.8, 0.8, 1.8, 8), metal(0x8d9196), [20.1, 0, 0], [0, 0, Math.PI / 2]),\n )\n}\n","import type { ItemModelBuilder } from './registry'\n\n/**\n * Authored in the kit (no team model delivered); replace when the items team delivers one.\n * It draws in the units of the builder; `data/models.json` gives the scale to metres of the item `handsaw`.\n */\nexport const handsaw: ItemModelBuilder = ({ mesh, bx, extrude, G, metal, wood }) => {\n const grip = wood(0x7a4f2c)\n return G(\n mesh(bx(11, 3.5, 2.2), grip, [-19.5, 0, 5.4]),\n mesh(bx(11, 3.5, 2.2), grip, [-19.5, 0, -5.4]),\n mesh(bx(2.2, 3.5, 13), grip, [-23.9, 0, 0]),\n mesh(bx(2.4, 3.5, 13), grip, [-15.2, 0, 0]),\n mesh(extrude([[-14, 6.5], [25, 6.5], [25, 2], [-14, -6.5]], 0.3, 0.01), metal(0xaeb2b7), [0, 0.15, 0], [Math.PI / 2, 0, 0]),\n )\n}\n","import type { ItemModelBuilder } from './registry'\n\n/**\n * Authored in the kit (no team model delivered); replace when the items team delivers one.\n * It draws in the units of the builder; `data/models.json` gives the scale to metres of the item `scissors`.\n */\nexport const scissors: ItemModelBuilder = ({ mesh, bx, cyl, lathe, G, metal, plastic }) => {\n const steel = metal(0xb5b9be)\n const grip = plastic(0xb5321f)\n const ring = lathe([[1.1, -0.75], [1.9, -0.75], [1.9, 0.75], [1.1, 0.75], [1.1, -0.75]], 8)\n return G(\n mesh(ring, grip, [-7.1, 0, 1.6]),\n mesh(ring, grip, [-7.1, 0, -1.6]),\n mesh(bx(4.4, 0.6, 0.9), steel, [-3.4, 0.35, -0.8]),\n mesh(bx(4.4, 0.6, 0.9), steel, [-3.4, -0.35, 0.8]),\n mesh(bx(6, 0.6, 1.6), steel, [1.8, 0.35, 0.3]),\n mesh(bx(6, 0.6, 1.6), steel, [1.8, -0.35, -0.3]),\n mesh(bx(3, 0.6, 0.8), steel, [7.5, 0.35, 0.2]),\n mesh(bx(3, 0.6, 0.8), steel, [7.5, -0.35, -0.2]),\n mesh(cyl(0.5, 0.5, 1.5, 8), metal(0x6f7378), [-1, 0, 0]),\n )\n}\n","import type { ItemModelBuilder } from './registry'\n\n/**\n * Authored in the kit (no team model delivered); replace when the items team delivers one.\n * It draws in the units of the builder; `data/models.json` gives the scale to metres of the item `recurve_bow`.\n */\nexport const recurveBow: ItemModelBuilder = ({ mesh, bx, G, wood, cloth }) => {\n const bar = (x1: number, y1: number, x2: number, y2: number, thick: number, depth: number) =>\n [bx(Math.hypot(x2 - x1, y2 - y1), thick, depth), [(x1 + x2) / 2, (y1 + y2) / 2, 0], [0, 0, Math.atan2(y2 - y1, x2 - x1)]] as const\n const limbMaterial = wood(0x6b4a2c)\n const stringMaterial = cloth(0xe3ddc8)\n const limbs = [-1, 1].flatMap((side) => [\n bar(side * 0.4, 0.6, side * 2.4, 0.35, 0.3, 0.36),\n bar(side * 2.4, 0.35, side * 4.4, -0.2, 0.26, 0.34),\n bar(side * 4.4, -0.2, side * 6.0, -0.8, 0.22, 0.32),\n bar(side * 6.0, -0.8, side * 6.45, -0.6, 0.2, 0.3),\n ])\n const strings = [bar(-6.4, -0.6, 0, -0.95, 0.06, 0.06), bar(0, -0.95, 6.4, -0.6, 0.06, 0.06)]\n return G(\n mesh(bx(0.9, 1.3, 0.46), wood(0x4a301b), [0, 0.35, 0]),\n mesh(bx(0.92, 0.5, 0.5), cloth(0x2b2b2b), [0, 0.1, 0]),\n ...limbs.map(([geometry, position, rotation]) => mesh(geometry, limbMaterial, [...position], [...rotation])),\n ...strings.map(([geometry, position, rotation]) => mesh(geometry, stringMaterial, [...position], [...rotation])),\n )\n}\n","import type { ItemModelBuilder } from './registry'\n\n/**\n * Authored in the kit (no team model delivered); replace when the items team delivers one.\n * It draws in the units of the builder; `data/models.json` gives the scale to metres of the item `crossbow`.\n */\nexport const crossbow: ItemModelBuilder = ({ mesh, bx, G, wood, metal, cloth }) => {\n const stock = wood(0x4a2f1a)\n const prod = metal(0x2f3236)\n const stringMaterial = cloth(0xe3ddc8)\n return G(\n mesh(bx(7, 0.5, 0.5), stock, [0, -0.35, 0]),\n mesh(bx(1.4, 0.9, 0.5), stock, [-2.8, -0.15, 0]),\n mesh(bx(5.4, 0.16, 0.3), wood(0x5d3d22), [0.3, -0.02, 0]),\n mesh(bx(0.8, 0.7, 0.6), metal(0x3a3d40), [2.9, 0, 0]),\n mesh(bx(0.4, 0.5, 4.0), prod, [2.8, 0.35, 2.0], [0, -0.12, 0]),\n mesh(bx(0.4, 0.5, 4.0), prod, [2.8, 0.35, -2.0], [0, 0.12, 0]),\n mesh(bx(0.05, 0.05, 4.07), stringMaterial, [1.98, 0.35, 1.95], [0, 0.289, 0]),\n mesh(bx(0.05, 0.05, 4.07), stringMaterial, [1.98, 0.35, -1.95], [0, -0.289, 0]),\n mesh(bx(3.6, 0.08, 0.08), wood(0xcdb68a), [1.2, 0.1, 0]),\n )\n}\n","import type { ItemModelBuilder } from './registry'\n\n/**\n * Authored in the kit (no team model delivered); replace when the items team delivers one.\n * It draws in the units of the builder; `data/models.json` gives the scale to metres of the item `iron_pipe`.\n */\nexport const ironPipe: ItemModelBuilder = ({ mesh, cyl, G, metal }) => {\n const R = Math.PI / 2\n const rust = metal(0x7a4a2c)\n const collar = metal(0x4a4e53)\n const bore = metal(0x1c1d1f)\n return G(\n mesh(cyl(0.155, 0.155, 7.4, 8), metal(0x5b6066), [0, 0, 0], [0, 0, R]),\n mesh(cyl(0.177, 0.177, 0.6, 8), collar, [3.7, 0, 0], [0, 0, R]),\n mesh(cyl(0.177, 0.177, 0.6, 8), collar, [-3.7, 0, 0], [0, 0, R]),\n mesh(cyl(0.165, 0.165, 0.35, 8), rust, [-1.1, 0, 0], [0, 0, R]),\n mesh(cyl(0.165, 0.165, 0.35, 8), rust, [1.9, 0, 0], [0, 0, R]),\n mesh(cyl(0.11, 0.11, 0.02, 8), bore, [3.995, 0, 0], [0, 0, R]),\n mesh(cyl(0.11, 0.11, 0.02, 8), bore, [-3.995, 0, 0], [0, 0, R]),\n )\n}\n","import type { ItemModelBuilder } from './registry'\n\n/**\n * Authored in the kit (no team model delivered); replace when the items team delivers one.\n * It draws in the units of the builder; `data/models.json` gives the scale to metres of the item `meat_cleaver`.\n */\nexport const meatCleaver: ItemModelBuilder = ({ mesh, bx, cyl, G, metal, wood }) => {\n const steel = metal(0xa9adb0)\n const rivet = metal(0xb8913a)\n return G(\n mesh(bx(2.15, 0.07, 1.2), steel, [-0.575, 0, 0]),\n mesh(bx(2.15, 0.14, 0.2), metal(0x8c9094), [-0.575, 0, -0.5]),\n mesh(bx(2.15, 0.03, 0.14), metal(0xd4d7da), [-0.575, 0, 0.53]),\n mesh(cyl(0.1, 0.1, 0.08, 8), metal(0x2a2c2e), [-1.25, 0, -0.1]),\n mesh(bx(1.2, 0.3, 0.28), wood(0x3b2a20), [1.05, 0, -0.3]),\n mesh(bx(0.12, 0.2, 0.4), metal(0x6f7377), [0.5, 0, -0.3]),\n mesh(cyl(0.04, 0.04, 0.3, 8), rivet, [0.8, 0, -0.3]),\n mesh(cyl(0.04, 0.04, 0.3, 8), rivet, [1.3, 0, -0.3]),\n )\n}\n","import type { ItemModelBuilder } from './registry'\n\n/**\n * Authored in the kit (no team model delivered); replace when the items team delivers one.\n * It draws in the units of the builder; `data/models.json` gives the scale to metres of the item `slingshot`.\n */\nexport const slingshot: ItemModelBuilder = ({ mesh, cyl, bx, G, wood, cloth }) => {\n const rod = (x1: number, y1: number, x2: number, y2: number, radius: number) =>\n [cyl(radius, radius, Math.hypot(x2 - x1, y2 - y1), 8), [(x1 + x2) / 2, (y1 + y2) / 2, 0], [0, 0, Math.atan2(-(x2 - x1), y2 - y1)]] as const\n const frame = wood(0x6b4a2c)\n const band = cloth(0x1f1f1f)\n const arms = [-1, 1].map((side) => rod(0, -0.15, side * 0.5675, 0.70, 0.1))\n const bands = [-1, 1].map((side) => rod(side * 0.5675, 0.70, side * 0.12, 0.25, 0.03))\n return G(\n mesh(cyl(0.12, 0.1, 0.65, 8), frame, [0, -0.425, 0]),\n mesh(cyl(0.126, 0.126, 0.3, 8), cloth(0x7a2f1f), [0, -0.5, 0]),\n ...arms.map(([geometry, position, rotation]) => mesh(geometry, frame, [...position], [...rotation])),\n ...bands.map(([geometry, position, rotation]) => mesh(geometry, band, [...position], [...rotation])),\n mesh(bx(0.26, 0.2, 0.05), cloth(0x8a5a35), [0, 0.2, 0]),\n )\n}\n","import type { ItemModelBuilder } from './registry'\n\n/**\n * Authored in the kit (no team model delivered); replace when the items team delivers one.\n * It draws in the units of the builder; `data/models.json` gives the scale to metres of the item `knife`.\n */\nexport const knife: ItemModelBuilder = ({ mesh, bx, cyl, extrude, G, metal, wood }) => {\n const R = Math.PI / 2\n const blade = extrude([[-1.25, 0.1], [-0.75, -0.2], [0.2, -0.2], [0.2, 0.2], [-0.9, 0.2]], 0.06, 0.002)\n const rivet = metal(0xb8913a)\n return G(\n mesh(blade, metal(0xb4b8bb), [0, 0.03, 0], [R, 0, 0]),\n mesh(bx(0.1, 0.24, 0.38), metal(0x6f7377), [0.2, 0, 0]),\n mesh(bx(0.94, 0.294, 0.3), wood(0x5a3a22), [0.72, 0, 0]),\n mesh(bx(0.06, 0.28, 0.28), metal(0x6f7377), [1.22, 0, 0]),\n mesh(cyl(0.035, 0.035, 0.3, 8), rivet, [0.55, 0, 0]),\n mesh(cyl(0.035, 0.035, 0.3, 8), rivet, [0.95, 0, 0]),\n )\n}\n","import type { ItemModelBuilder } from './registry'\n\n/**\n * Authored in the kit (no team model delivered); replace when the items team delivers one.\n * It draws in the units of the builder; `data/models.json` gives the scale to metres of the item `tactical_knife`.\n */\nexport const tacticalKnife: ItemModelBuilder = ({ mesh, bx, cyl, extrude, G, metal, plastic }) => {\n const R = Math.PI / 2\n const blade = extrude([[-1.3, 0.05], [-0.9, -0.225], [0.15, -0.225], [0.15, 0.225], [-0.7, 0.225], [-1.05, 0.15]], 0.05, 0.002)\n const grip = plastic(0x1b1c1d)\n const bolt = metal(0x8d9095)\n return G(\n mesh(blade, metal(0x3a3d40), [0, 0.025, 0], [R, 0, 0]),\n mesh(bx(0.1, 0.26, 0.42), metal(0x55595d), [0.2, 0, 0]),\n mesh(bx(0.4, 0.27, 0.32), grip, [0.45, 0, 0]),\n mesh(bx(0.4, 0.23, 0.3), plastic(0x2a2c2e), [0.85, 0, 0]),\n mesh(bx(0.25, 0.27, 0.34), grip, [1.175, 0, 0]),\n mesh(cyl(0.04, 0.04, 0.282, 8), bolt, [0.4, 0, 0]),\n mesh(cyl(0.04, 0.04, 0.282, 8), bolt, [1.15, 0, 0]),\n )\n}\n","import type { ItemModelBuilder } from './registry'\n\n/**\n * Authored in the kit (no team model delivered); replace when the items team delivers one.\n * It draws in the units of the builder; `data/models.json` gives the scale to metres of the item `arrows_and_bolts`.\n */\nexport const arrowsAndBolts: ItemModelBuilder = ({ T, mesh, bx, cyl, G, metal, wood, cloth, plastic }) => {\n const R = Math.PI / 2\n const vane = cloth(0xb03a2e)\n const binding = cloth(0x2b2b2b)\n return G(\n mesh(cyl(0.04, 0.04, 6.45, 8), wood(0xc9ab74), [-0.225, 0, 0], [0, 0, R]),\n mesh(new T.ConeGeometry(0.125, 0.55, 4), metal(0x8d9095), [3.225, 0, 0], [0, 0, -R], [1, 1, 0.35]),\n mesh(bx(0.9, 0.02, 0.4), vane, [-2.9, 0, 0]),\n mesh(bx(0.9, 0.25, 0.02), cloth(0xe6e0d0), [-2.9, 0, 0]),\n mesh(cyl(0.05, 0.05, 0.1, 8), plastic(0xe6a23a), [-3.45, 0, 0], [0, 0, R]),\n mesh(cyl(0.055, 0.055, 0.25, 8), binding, [-2.2, 0, 0], [0, 0, R]),\n mesh(cyl(0.055, 0.055, 0.25, 8), binding, [2.85, 0, 0], [0, 0, R]),\n )\n}\n","import type { ItemModelBuilder } from './registry'\n\n/**\n * Authored in the kit (no team model delivered); replace when the items team delivers one.\n * It draws in the units of the builder; `data/models.json` gives the scale to metres of the item `sickle`.\n */\nexport const sickle: ItemModelBuilder = ({ mesh, bx, cyl, G, metal, wood, cloth }) => {\n const R = Math.PI / 2\n const steel = metal(0xa5a9ad)\n const blade = (x1: number, z1: number, x2: number, z2: number, width: number) =>\n mesh(bx(Math.hypot(x2 - x1, z2 - z1), 0.06, width), steel, [(x1 + x2) / 2, 0, (z1 + z2) / 2], [0, Math.atan2(-(z2 - z1), x2 - x1), 0])\n return G(\n mesh(cyl(0.15, 0.17, 1.5, 8), wood(0x7a5a38), [-1.25, 0, -1.575], [0, 0, R]),\n mesh(cyl(0.176, 0.176, 0.5, 8), cloth(0x3b2a20), [-1.7, 0, -1.575], [0, 0, R]),\n mesh(cyl(0.176, 0.176, 0.2, 8), metal(0x6f7377), [-0.6, 0, -1.575], [0, 0, R]),\n blade(-0.5, -1.575, 0.3, -1.5, 0.18),\n blade(0.3, -1.5, 1.2, -1.1, 0.24),\n blade(1.2, -1.1, 1.75, -0.35, 0.28),\n blade(1.75, -0.35, 1.88, 0.5, 0.26),\n blade(1.88, 0.5, 1.5, 1.2, 0.2),\n blade(1.5, 1.2, 0.9, 1.7, 0.12),\n )\n}\n","import type { ItemModelBuilder } from './registry'\n\n/**\n * Authored in the kit (no team model delivered); replace when the items team delivers one.\n * It draws in the units of the builder; `data/models.json` gives the scale to metres of the item `cast_iron_skillet`.\n */\nexport const castIronSkillet: ItemModelBuilder = ({ mesh, lathe, cyl, G, metal }) => {\n const R = Math.PI / 2\n const iron = metal(0x2b2c2e)\n const pan = lathe([[0, -0.25], [0.95, -0.25], [1.25, 0.25], [1.1, 0.25], [0.92, -0.1], [0, -0.1]], 16)\n return G(\n mesh(pan, iron, [-0.9, 0, 0]),\n mesh(cyl(0.9, 0.9, 0.01, 16), metal(0x1c1d1f), [-0.9, -0.095, 0]),\n mesh(cyl(0.14, 0.1, 1.95, 8), iron, [1.175, 0.1, 0], [0, 0, R]),\n mesh(cyl(0.06, 0.06, 0.22, 8), metal(0x111213), [2.0, 0.1, 0]),\n mesh(cyl(0.1, 0.1, 0.16, 8), iron, [-2.0, 0.12, 0], [0, 0, R]),\n )\n}\n","import type { ItemModelBuilder } from './registry'\n\n/**\n * Authored in the kit (no team model delivered); replace when the items team delivers one.\n * It draws in the units of the builder; `data/models.json` gives the scale to metres of the item `improvised_spear`.\n */\nexport const improvisedSpear: ItemModelBuilder = ({ T, mesh, cyl, G, metal, wood, cloth }) => {\n const R = Math.PI / 2\n const wrap = cloth(0x4a3b2a)\n return G(\n mesh(cyl(0.1, 0.1, 13.6, 8), wood(0x7a5a38), [-1.2, 0, 0], [0, 0, R]),\n mesh(new T.ConeGeometry(0.175, 2.4, 4), metal(0x8d9095), [6.8, 0, 0], [0, 0, -R], [1, 1, 0.4]),\n mesh(cyl(0.175, 0.175, 0.8, 8), cloth(0x6b5a3e), [5.4, 0, 0], [0, 0, R]),\n mesh(cyl(0.14, 0.14, 0.7, 8), wrap, [-4.5, 0, 0], [0, 0, R]),\n mesh(cyl(0.14, 0.14, 0.7, 8), wrap, [-3.5, 0, 0], [0, 0, R]),\n mesh(cyl(0.12, 0.12, 0.3, 8), metal(0x6f7377), [4.4, 0, 0], [0, 0, R]),\n )\n}\n","import type { ItemModelBuilder } from './registry'\n\n/**\n * Authored in the kit (no team model delivered); replace when the items team delivers one.\n * It draws in the units of the builder; `data/models.json` gives the scale to metres of the item `hatchet`.\n */\nexport const hatchet: ItemModelBuilder = ({ mesh, cyl, bx, extrude, G, metal, wood, cloth }) => {\n const R = Math.PI / 2\n const head = metal(0x5c6065)\n const blade = extrude([[0.7, -0.25], [1.75, -0.65], [1.75, 0.65], [0.7, 0.25]], 0.28, 0.002)\n return G(\n mesh(cyl(0.14, 0.09, 3.0, 8), wood(0x8a643c), [-0.25, 0, 0], [0, 0, R]),\n mesh(cyl(0.16, 0.16, 0.2, 8), wood(0x6f4f2e), [-1.65, 0, 0], [0, 0, R]),\n mesh(cyl(0.145, 0.145, 1.0, 8), cloth(0x2b2b2b), [-1.15, 0, 0], [0, 0, R]),\n mesh(bx(0.5, 0.5, 0.45), head, [1.0, 0, 0]),\n mesh(blade, head, [0, 0.14, 0], [R, 0, 0]),\n mesh(bx(0.08, 0.12, 1.3), metal(0xc4c8cb), [1.71, 0, 0]),\n )\n}\n","import type { ItemModelBuilder } from './registry'\n\n/**\n * Authored in the kit (no team model delivered); replace when the items team delivers one.\n * It draws in the units of the builder; `data/models.json` gives the scale to metres of the item `sledgehammer`.\n */\nexport const sledgehammer: ItemModelBuilder = ({ mesh, cyl, bx, G, metal, wood, cloth }) => {\n const R = Math.PI / 2\n const steel = metal(0x55595d)\n return G(\n mesh(cyl(0.2, 0.13, 8.7, 8), wood(0x8a643c), [-0.15, 0, 0], [0, 0, R]),\n mesh(cyl(0.205, 0.205, 2.0, 8), cloth(0x22251f), [-3.2, 0, 0], [0, 0, R]),\n mesh(cyl(0.21, 0.21, 0.3, 8), wood(0x6f4f2e), [-4.35, 0, 0], [0, 0, R]),\n mesh(bx(0.9, 1.2, 1.4), steel, [4.0, 0, 0]),\n mesh(cyl(0.5, 0.5, 0.56, 8), metal(0x3a3d40), [4.0, 0, 0.97], [R, 0, 0]),\n mesh(cyl(0.5, 0.5, 0.56, 8), metal(0x3a3d40), [4.0, 0, -0.97], [R, 0, 0]),\n )\n}\n","import type { ItemModelBuilder } from './registry'\n\n/**\n * Authored in the kit (no team model delivered); replace when the items team delivers one.\n * It draws in the units of the builder; `data/models.json` gives the scale to metres of the item `chainsaw`.\n */\nexport const chainsaw: ItemModelBuilder = ({ mesh, bx, cyl, G, metal, plastic }) => {\n const orange = plastic(0xd9731c)\n const dark = plastic(0x2f3133)\n return G(\n mesh(bx(2.1, 1.2, 1.5), orange, [-1.2, -0.4, 0]),\n mesh(bx(1.3, 0.3, 1.1), dark, [-1.4, -1.15, 0]),\n mesh(bx(0.28, 0.85, 0.3), dark, [-2.1, 0.625, 0]),\n mesh(bx(0.28, 0.85, 0.3), dark, [-0.5, 0.625, 0]),\n mesh(bx(1.9, 0.25, 0.3), dark, [-1.3, 1.175, 0]),\n mesh(bx(0.2, 0.45, 2.3), dark, [-0.1, 0.45, 0]),\n mesh(cyl(0.38, 0.38, 0.12, 8), dark, [-1.2, 0.26, 0]),\n mesh(bx(0.8, 0.5, 0.3), metal(0x6f7377), [-1.5, -0.35, 0.9]),\n mesh(bx(2.2, 0.46, 0.14), metal(0xa9adb0), [1.0, -0.45, 0]),\n mesh(bx(2.35, 0.6, 0.2), metal(0x2a2c2e), [1.075, -0.45, 0]),\n )\n}\n","import type { ItemModelBuilder } from './registry'\n\n/**\n * Authored in the kit (no team model delivered); replace when the items team delivers one.\n * It draws in the units of the builder; `data/models.json` gives the scale to metres of the item `pickaxe`.\n */\nexport const pickaxe: ItemModelBuilder = ({ T, mesh, cyl, bx, G, metal, wood, cloth }) => {\n const R = Math.PI / 2\n const iron = metal(0x55595d)\n const arm = (side: number) => [\n mesh(cyl(0.13, 0.2, 0.8, 8), iron, [4.1, 0, side * 0.65], [side * R, 0, 0]),\n mesh(new T.ConeGeometry(0.13, 0.7, 8), metal(0x6a6e72), [4.08, 0, side * 1.4], [side * R, 0, 0.18]),\n ]\n return G(\n mesh(cyl(0.17, 0.15, 8.6, 8), wood(0x8a643c), [-0.2, 0, 0], [0, 0, R]),\n mesh(cyl(0.19, 0.19, 2.0, 8), cloth(0x2b2b2b), [-3.4, 0, 0], [0, 0, R]),\n mesh(cyl(0.2, 0.2, 0.3, 8), wood(0x6f4f2e), [-4.35, 0, 0], [0, 0, R]),\n mesh(bx(0.8, 0.4, 0.5), iron, [4.1, 0, 0]),\n mesh(cyl(0.2, 0.2, 0.3, 8), metal(0x3a3d40), [3.45, 0, 0], [0, 0, R]),\n ...arm(1),\n ...arm(-1),\n )\n}\n","import type { ItemModelBuilder } from './registry'\n\n/**\n * Authored in the kit (no team model delivered); replace when the items team delivers one.\n * It draws in the units of the builder; `data/models.json` gives the scale to metres of the item `baseball_bat`.\n */\nexport const baseballBat: ItemModelBuilder = ({ mesh, lathe, cyl, G, wood, cloth }) => {\n const R = Math.PI / 2\n const profile: Array<[number, number]> = [[0, -4.3], [0.19, -4.3], [0.25, -4.2], [0.22, -4.05], [0.14, -3.95], [0.14, -3.0], [0.17, -1.6], [0.25, 0.2], [0.3, 1.8], [0.345, 3.0], [0.345, 4.0], [0.31, 4.25], [0, 4.3]]\n const band = cloth(0x8f1f1f)\n return G(\n mesh(lathe(profile, 16), wood(0xc9a56b), [0, 0, 0], [0, 0, -R]),\n mesh(cyl(0.185, 0.185, 2.2, 8), cloth(0x1b1c1d), [-2.8, 0, 0], [0, 0, R]),\n mesh(cyl(0.352, 0.352, 0.12, 16), band, [3.2, 0, 0], [0, 0, R]),\n mesh(cyl(0.352, 0.352, 0.12, 16), band, [3.55, 0, 0], [0, 0, R]),\n )\n}\n","import type { ItemModelBuilder } from './registry'\n\n/**\n * Authored in the kit (no team model delivered); replace when the items team delivers one.\n * It draws in the units of the builder; `data/models.json` gives the scale to metres of the item `police_baton`.\n */\nexport const policeBaton: ItemModelBuilder = ({ mesh, cyl, G, plastic, metal }) => {\n const R = Math.PI / 2\n const black = plastic(0x1b1c1d)\n return G(\n mesh(cyl(0.22, 0.22, 5, 8), black, [0, 0, 0], [0, 0, R]),\n mesh(cyl(0.225, 0.225, 0.3, 8), metal(0x3a3d40), [2.35, 0, 0], [0, 0, R]),\n mesh(cyl(0.225, 0.225, 0.3, 8), metal(0x3a3d40), [-2.35, 0, 0], [0, 0, R]),\n mesh(cyl(0.12, 0.12, 0.6, 8), black, [-1.35, -0.36, 0]),\n mesh(cyl(0.16, 0.16, 0.115, 8), plastic(0x2a2c2e), [-1.35, -0.7175, 0]),\n mesh(cyl(0.13, 0.13, 0.06, 8), plastic(0x3a3d40), [-1.35, -0.2, 0]),\n mesh(cyl(0.13, 0.13, 0.06, 8), plastic(0x3a3d40), [-1.35, -0.32, 0]),\n mesh(cyl(0.13, 0.13, 0.06, 8), plastic(0x3a3d40), [-1.35, -0.44, 0]),\n )\n}\n","import type { ItemModelBuilder } from './registry'\n\n/**\n * Authored in the kit (no team model delivered); replace when the items team delivers one.\n * It draws in the units of the builder; `data/models.json` gives the scale to metres of the item `wire_roll`.\n */\nexport const wireRoll: ItemModelBuilder = ({ mesh, lathe, cyl, G, metal, paper }) => {\n const coil = lathe([[0.32, -0.25], [0.66, -0.25], [0.7, -0.2], [0.7, 0.2], [0.66, 0.25], [0.32, 0.25], [0.32, -0.25]], 12)\n const tube = lathe([[0.26, -0.25], [0.32, -0.25], [0.32, 0.25], [0.26, 0.25], [0.26, -0.25]], 12)\n return G(\n mesh(coil, metal(0x8d9096)),\n mesh(tube, paper(0x9a7b4f)),\n mesh(cyl(0.702, 0.702, 0.05, 12), metal(0x5c6065), [0, -0.1, 0]),\n mesh(cyl(0.702, 0.702, 0.05, 12), metal(0x5c6065), [0, 0.1, 0]),\n )\n}\n","import type { ItemModelBuilder } from './registry'\n\n/**\n * Authored in the kit (no team model delivered); replace when the items team delivers one.\n * It draws in the units of the builder; `data/models.json` gives the scale to metres of the item `barbed_wire`.\n */\nexport const barbedWire: ItemModelBuilder = ({ mesh, bx, lathe, G, metal }) => {\n const ring = (outer: number, y0: number, y1: number) => lathe([[1.25, y0], [outer, y0], [outer, y1], [1.25, y1], [1.25, y0]], 8)\n const wire = metal(0x6b6f73)\n const barb = metal(0x9a9ea3)\n return G(\n mesh(ring(1.5, -0.6, -0.2), wire),\n mesh(ring(1.46, -0.2, 0.2), metal(0x585c62)),\n mesh(ring(1.5, 0.2, 0.6), wire),\n mesh(bx(0.06, 1.2, 0.2), metal(0x3a3d40), [1.47, 0, 0]),\n mesh(bx(0.06, 1.2, 0.2), metal(0x3a3d40), [-1.47, 0, 0]),\n mesh(bx(0.08, 0.08, 0.18), barb, [1.42, 0.4, 0.5]),\n mesh(bx(0.08, 0.08, 0.18), barb, [-1.42, 0.4, -0.5]),\n mesh(bx(0.18, 0.08, 0.08), barb, [0.5, -0.4, 1.42]),\n mesh(bx(0.18, 0.08, 0.08), barb, [-0.5, -0.4, -1.42]),\n )\n}\n","import type { ItemModelBuilder } from './registry'\n\n/**\n * Authored in the kit (no team model delivered); replace when the items team delivers one.\n * It draws in the units of the builder; `data/models.json` gives the scale to metres of the item `glass_shards`.\n */\nexport const glassShards: ItemModelBuilder = ({ T, mesh, extrude, G, glass }) => {\n const R = Math.PI / 2\n const pane = glass(0xbfe3df, 0.55)\n const deep = glass(0x7fb5b0, 0.7)\n const base = extrude([[-0.6, -0.1], [0.45, -0.5], [0.6, 0.2], [-0.1, 0.5]], 0.04, 0.002)\n const chip = extrude([[0, 0], [0.25, 0.05], [0.1, 0.22]], 0.03, 0.002)\n return G(\n mesh(base, pane, [0, 0, 0], [R, 0, 0]),\n mesh(chip, deep, [0.2, 0, -0.35], [R, 0, 0.4]),\n mesh(new T.ConeGeometry(0.14, 0.46, 3), pane, [-0.2, 0.23, 0.1], [0, 0.3, 0.12]),\n mesh(new T.ConeGeometry(0.1, 0.34, 3), deep, [0.25, 0.17, -0.1], [0.15, 0, -0.2]),\n mesh(new T.ConeGeometry(0.08, 0.26, 3), pane, [0.05, 0.13, 0.3], [-0.2, 0.5, 0.15]),\n )\n}\n","import type { ItemModelBuilder } from './registry'\n\n/**\n * Authored in the kit (no team model delivered); replace when the items team delivers one.\n * It draws in the units of the builder; `data/models.json` gives the scale to metres of the item `sheet_metal`.\n */\nexport const sheetMetal: ItemModelBuilder = ({ mesh, bx, cyl, G, metal }) => {\n const zinc = metal(0x9aa0a6)\n const edge = metal(0x7d838a)\n const hole = metal(0x1c1d1f)\n const corners: Array<[number, number]> = [[2.5, 1.8], [-2.5, 1.8], [2.5, -1.8], [-2.5, -1.8]]\n return G(\n mesh(bx(6, 0.02, 4.5), zinc, [0, -0.005, 0]),\n mesh(bx(6, 0.01, 0.16), edge, [0, 0.01, 2.17]),\n mesh(bx(6, 0.01, 0.16), edge, [0, 0.01, -2.17]),\n mesh(bx(0.16, 0.01, 4.18), edge, [2.92, 0.01, 0]),\n mesh(bx(0.16, 0.01, 4.18), edge, [-2.92, 0.01, 0]),\n mesh(bx(1.2, 0.01, 0.8), metal(0x7a4a2c), [-0.8, 0.01, -0.4]),\n ...corners.map(([x, z]) => mesh(cyl(0.12, 0.12, 0.01, 8), hole, [x, 0.01, z])),\n )\n}\n","import type { ItemModelBuilder } from './registry'\n\n/**\n * Authored in the kit (no team model delivered); replace when the items team delivers one.\n * It draws in the units of the builder; `data/models.json` gives the scale to metres of the item `cement_bag`.\n */\nexport const cementBag: ItemModelBuilder = ({ mesh, bx, G, paper, cloth }) => {\n return G(\n mesh(bx(5.0, 0.7, 3.0), paper(0xb9b4a3)),\n mesh(bx(4.5, 1.0, 2.6), paper(0xc9c4b3)),\n mesh(bx(2.4, 0.01, 1.5), paper(0xe8e2d0), [0, 0.505, 0]),\n mesh(bx(2.4, 0.011, 0.25), paper(0x2f5d8a), [0, 0.5055, 0]),\n mesh(bx(0.12, 0.5, 2.8), cloth(0x8c8672), [2.44, 0, 0]),\n mesh(bx(0.12, 0.5, 2.8), cloth(0x8c8672), [-2.44, 0, 0]),\n )\n}\n","import type { ItemModelBuilder } from './registry'\n\n/**\n * Authored in the kit (no team model delivered); replace when the items team delivers one.\n * It draws in the units of the builder; `data/models.json` gives the scale to metres of the item `epoxy_glue`.\n */\nexport const epoxyGlue: ItemModelBuilder = ({ T, mesh, cyl, bx, G, glass, plastic }) => {\n const R = Math.PI / 2\n const barrel = glass(0xdfe8ec, 0.5)\n const orange = plastic(0xe07a1f)\n const blue = plastic(0x2f6bb5)\n return G(\n mesh(cyl(0.15, 0.15, 0.6, 8), barrel, [0, 0.15, 0], [0, 0, R]),\n mesh(cyl(0.15, 0.15, 0.6, 8), barrel, [0, -0.15, 0], [0, 0, R]),\n mesh(cyl(0.11, 0.11, 0.5, 8), plastic(0xf2d27a), [0, 0.15, 0], [0, 0, R]),\n mesh(cyl(0.11, 0.11, 0.5, 8), plastic(0xb9c6d4), [0, -0.15, 0], [0, 0, R]),\n mesh(cyl(0.05, 0.05, 0.16, 8), orange, [-0.38, 0.15, 0], [0, 0, R]),\n mesh(cyl(0.05, 0.05, 0.16, 8), blue, [-0.38, -0.15, 0], [0, 0, R]),\n mesh(bx(0.04, 0.58, 0.28), plastic(0xe8e8e8), [-0.48, 0, 0]),\n mesh(bx(0.03, 0.58, 0.3), plastic(0xe8e8e8), [-0.285, 0, 0]),\n mesh(new T.ConeGeometry(0.15, 0.2, 8), plastic(0xc9ccd0), [0.4, 0, 0], [0, 0, -R]),\n )\n}\n","import type { ItemModelBuilder } from './registry'\n\n/**\n * Authored in the kit (no team model delivered); replace when the items team delivers one.\n * It draws in the units of the builder; `data/models.json` gives the scale to metres of the item `electronic_components`.\n */\nexport const electronicComponents: ItemModelBuilder = ({ mesh, bx, cyl, G, plastic, metal }) => {\n const R = Math.PI / 2\n const chip = plastic(0x18191b)\n const gold = metal(0xb8913a)\n const silver = metal(0xb4b8bb)\n return G(\n mesh(bx(1.0, 0.04, 0.8), plastic(0x2c6b3a), [0, -0.08, 0]),\n mesh(bx(0.22, 0.06, 0.14), chip, [-0.1, -0.03, -0.1]),\n mesh(bx(0.2, 0.02, 0.19), silver, [-0.1, -0.05, -0.1]),\n mesh(bx(0.3, 0.06, 0.18), chip, [0.2, -0.03, 0.2]),\n mesh(bx(0.28, 0.02, 0.27), silver, [0.2, -0.05, 0.2]),\n mesh(cyl(0.05, 0.05, 0.16, 8), plastic(0x2f4f8f), [0.35, 0.02, -0.25]),\n mesh(cyl(0.04, 0.04, 0.14, 8), plastic(0x8f3a2f), [0.2, 0.01, -0.3]),\n mesh(cyl(0.025, 0.025, 0.14, 8), plastic(0xc9a56b), [-0.3, -0.035, 0.2], [0, 0, R]),\n mesh(cyl(0.027, 0.027, 0.02, 6), plastic(0x8f3a2f), [-0.34, -0.035, 0.2], [0, 0, R]),\n mesh(cyl(0.027, 0.027, 0.02, 6), plastic(0x2f4f8f), [-0.26, -0.035, 0.2], [0, 0, R]),\n mesh(bx(0.3, 0.05, 0.06), chip, [-0.3, -0.035, 0.33]),\n ...[-0.4, -0.35, -0.3, -0.25, -0.2].map((x) => mesh(bx(0.03, 0.12, 0.03), gold, [x, 0, 0.33])),\n mesh(bx(0.14, 0.1, 0.16), silver, [0.43, -0.01, 0]),\n )\n}\n","import type { ItemModelBuilder } from './registry'\n\n/**\n * Authored in the kit (no team model delivered); replace when the items team delivers one.\n * It draws in the units of the builder; `data/models.json` gives the scale to metres of the item `rope`.\n */\nexport const rope: ItemModelBuilder = ({ mesh, lathe, bx, G, cloth }) => {\n const ring = (innerRadius: number, outerRadius: number, y0: number, y1: number, color: number) =>\n mesh(lathe([[innerRadius, y0], [outerRadius, y0], [outerRadius, y1], [innerRadius, y1], [innerRadius, y0]], 12), cloth(color))\n const tie = cloth(0x6b5a3e)\n return G(\n ring(0.42, 0.75, -0.4, -0.14, 0xb59b63),\n ring(0.46, 0.72, -0.14, 0.12, 0xa68c55),\n ring(0.42, 0.75, 0.12, 0.4, 0xb59b63),\n mesh(bx(0.2, 0.8, 0.06), tie, [0, 0, 0.72]),\n mesh(bx(0.2, 0.8, 0.06), tie, [0, 0, -0.72]),\n mesh(bx(0.06, 0.8, 0.2), tie, [0.72, 0, 0]),\n mesh(bx(0.06, 0.8, 0.2), tie, [-0.72, 0, 0]),\n )\n}\n","import type { ItemModelBuilder } from './registry'\n\n/**\n * Authored in the kit (no team model delivered); replace when the items team delivers one.\n * It draws in the units of the builder; `data/models.json` gives the scale to metres of the item `copper_wire`.\n */\nexport const copperWire: ItemModelBuilder = ({ mesh, lathe, cyl, G, metal, plastic }) => {\n const R = Math.PI / 2\n const copper = metal(0xb8693a)\n return G(\n mesh(lathe([[0.18, -0.11], [0.38, -0.11], [0.38, 0.11], [0.18, 0.11], [0.18, -0.11]], 16), copper),\n mesh(cyl(0.4, 0.4, 0.04, 16), plastic(0x2a2c2e), [0, 0.131, 0]),\n mesh(cyl(0.4, 0.4, 0.04, 16), plastic(0x2a2c2e), [0, -0.131, 0]),\n mesh(cyl(0.015, 0.015, 0.35, 6), metal(0xd08a55), [0, 0, 0.385], [0, 0, R]),\n )\n}\n","import type { ItemModelBuilder } from './registry'\n\n/**\n * Authored in the kit (no team model delivered); replace when the items team delivers one.\n * It draws in the units of the builder; `data/models.json` gives the scale to metres of the item `pet_bottle`.\n */\nexport const petBottle: ItemModelBuilder = ({ M, mesh, lathe, cyl, G, plastic, paper }) => {\n const body = lathe([[0, -1.65], [0.46, -1.65], [0.527, -1.5], [0.527, 0.55], [0.45, 0.85], [0.2, 1.2], [0.19, 1.37]], 12)\n return G(\n mesh(body, M(0xcfeaf2, 'plastic', { roughness: 0.3, transparent: true, opacity: 0.65 })),\n mesh(cyl(0.53, 0.53, 1.2, 12), paper(0xcc2222), [0, -0.5, 0]),\n mesh(cyl(0.215, 0.215, 0.3, 12), plastic(0x1565c0), [0, 1.5, 0]),\n mesh(cyl(0.22, 0.22, 0.04, 12), plastic(0xcfeaf2), [0, 1.33, 0]),\n )\n}\n","import type { ItemModelBuilder } from './registry'\n\n/**\n * Authored in the kit (no team model delivered); replace when the items team delivers one.\n * It draws in the units of the builder; `data/models.json` gives the scale to metres of the item `glass_bottle`.\n */\nexport const glassBottle: ItemModelBuilder = ({ mesh, lathe, cyl, G, glass, paper, metal }) => {\n const body = lathe([[0, -1.3], [0.3, -1.3], [0.372, -1.2], [0.372, 0.1], [0.33, 0.45], [0.15, 0.8], [0.12, 1.1], [0.13, 1.25]], 12)\n return G(\n mesh(body, glass(0x2f6b3f, 0.8)),\n mesh(cyl(0.375, 0.375, 0.8, 12), paper(0xe3d9b8), [0, -0.5, 0]),\n mesh(cyl(0.15, 0.15, 0.1, 8), glass(0x2f6b3f, 0.85), [0, 1.2, 0]),\n mesh(cyl(0.145, 0.145, 0.06, 12), metal(0xb8913a), [0, 1.27, 0]),\n )\n}\n","import type { ItemModelBuilder } from './registry'\n\n/**\n * Authored in the kit (no team model delivered); replace when the items team delivers one.\n * It draws in the units of the builder; `data/models.json` gives the scale to metres of the item `empty_can`.\n */\nexport const emptyCan: ItemModelBuilder = ({ mesh, lathe, cyl, bx, G, metal, paper }) => {\n const body = lathe([[0, -0.6], [0.27, -0.6], [0.3, -0.55], [0.33, -0.45], [0.33, 0.42], [0.29, 0.55], [0.285, 0.6]], 12)\n return G(\n mesh(body, metal(0xc9ccd0)),\n mesh(cyl(0.332, 0.332, 0.5, 12), paper(0xb5342a), [0, -0.05, 0]),\n mesh(cyl(0.25, 0.25, 0.01, 12), metal(0x222222), [0, 0.55, 0]),\n mesh(bx(0.14, 0.01, 0.24), metal(0x9a9ea3), [0, 0.602, 0.05]),\n )\n}\n","import type { ItemModelBuilder } from './registry'\n\n/**\n * Authored in the kit (no team model delivered); replace when the items team delivers one.\n * It draws in the units of the builder; `data/models.json` gives the scale to metres of the item `firewood`.\n */\nexport const firewood: ItemModelBuilder = ({ mesh, cyl, G, wood }) => {\n const R = Math.PI / 2\n const log = (radius: number, y: number, z: number, bark: number) => [\n mesh(cyl(radius, radius, 3.98, 8), wood(bark), [0, y, z], [0, 0, R]),\n mesh(cyl(radius * 0.92, radius * 0.92, 0.02, 8), wood(0xd2b07a), [1.99, y, z], [0, 0, R]),\n mesh(cyl(radius * 0.92, radius * 0.92, 0.02, 8), wood(0xd2b07a), [-1.99, y, z], [0, 0, R]),\n ]\n return G(...log(0.4, -0.2, 0.4, 0x5a3d24), ...log(0.4, -0.2, -0.4, 0x6b4a2c), ...log(0.3, 0.3, 0, 0x4f3520))\n}\n","import type { ItemModelBuilder } from './registry'\n\n/**\n * Authored in the kit (no team model delivered); replace when the items team delivers one.\n * It draws in the units of the builder; `data/models.json` gives the scale to metres of the item `tarp`.\n */\nexport const tarp: ItemModelBuilder = ({ mesh, bx, cyl, G, cloth, metal }) => {\n const blue = cloth(0x2f5f8f)\n const deep = cloth(0x2a557f)\n const rope = cloth(0xcbb98a)\n const corners: Array<[number, number]> = [[1.55, 1.05], [-1.55, 1.05], [1.55, -1.05], [-1.55, -1.05]]\n return G(\n mesh(bx(3.5, 0.24, 2.5), blue, [0, -0.38, 0]),\n mesh(bx(3.4, 0.25, 2.44), deep, [0, -0.135, 0]),\n mesh(bx(3.46, 0.25, 2.4), blue, [0, 0.115, 0]),\n mesh(bx(3.38, 0.24, 2.46), deep, [0, 0.37, 0]),\n mesh(bx(0.12, 1.002, 2.502), rope, [0.9, 0, 0]),\n mesh(bx(0.12, 1.002, 2.502), rope, [-0.9, 0, 0]),\n ...corners.map(([x, z]) => mesh(cyl(0.09, 0.09, 0.02, 8), metal(0xb4b8bb), [x, 0.49, z])),\n )\n}\n","import type { ItemModelBuilder } from './registry'\n\n/**\n * Authored in the kit (no team model delivered); replace when the items team delivers one.\n * It draws in the units of the builder; `data/models.json` gives the scale to metres of the item `screws`.\n */\nexport const screws: ItemModelBuilder = ({ T, mesh, cyl, bx, G, metal }) => {\n const R = Math.PI / 2\n const steel = metal(0xa9adb0)\n const dark = metal(0x2a2c2e)\n return G(\n mesh(cyl(0.25, 0.25, 0.12, 8), steel, [0.39, 0, 0], [0, 0, R]),\n mesh(bx(0.01, 0.3, 0.05), dark, [0.445, 0, 0]),\n mesh(bx(0.01, 0.05, 0.3), dark, [0.445, 0, 0]),\n mesh(cyl(0.08, 0.08, 0.58, 8), steel, [0.04, 0, 0], [0, 0, R]),\n mesh(new T.ConeGeometry(0.08, 0.2, 8), steel, [-0.35, 0, 0], [0, 0, R]),\n ...[-0.15, 0.05, 0.2].map((x) => mesh(cyl(0.1, 0.1, 0.04, 8), metal(0x8d9096), [x, 0, 0], [0, 0, R])),\n )\n}\n","import type { ItemModelBuilder } from './registry'\n\n/**\n * Authored in the kit (no team model delivered); replace when the items team delivers one.\n * It draws in the units of the builder; `data/models.json` gives the scale to metres of the item `nails`.\n */\nexport const nails: ItemModelBuilder = ({ T, mesh, cyl, G, metal }) => {\n const R = Math.PI / 2\n const steel = metal(0x8d9096)\n const nail = (y: number, z: number, direction: number) => [\n mesh(cyl(0.1, 0.1, 0.04, 8), steel, [direction * 0.63, y, z], [0, 0, R]),\n mesh(cyl(0.035, 0.035, 1.1, 6), steel, [direction * 0.06, y, z], [0, 0, R]),\n mesh(new T.ConeGeometry(0.035, 0.16, 6), steel, [-direction * 0.57, y, z], [0, 0, direction * R]),\n ]\n return G(...nail(-0.2, -0.15, 1), ...nail(-0.2, 0.15, -1), ...nail(0.2, -0.15, -1), ...nail(0.2, 0.15, 1))\n}\n","import type { ItemModelBuilder } from './registry'\n\n/**\n * Authored in the kit (no team model delivered); replace when the items team delivers one.\n * It draws in the units of the builder; `data/models.json` gives the scale to metres of the item `raffia_sack`.\n */\nexport const raffiaSack: ItemModelBuilder = ({ mesh, bx, G, cloth }) => {\n return G(\n mesh(bx(3.98, 0.18, 2.94), cloth(0xd9cfa8)),\n mesh(bx(4.0, 0.2, 0.14), cloth(0xb8ad84), [0, 0, 1.43]),\n mesh(bx(4.0, 0.2, 0.14), cloth(0xb8ad84), [0, 0, -1.43]),\n mesh(bx(0.12, 0.2, 2.7), cloth(0x3b6ea5), [1.0, 0, 0]),\n mesh(bx(0.12, 0.2, 2.7), cloth(0x3b6ea5), [-1.0, 0, 0]),\n )\n}\n","import type { ItemModelBuilder } from './registry'\n\n/**\n * Authored in the kit (no team model delivered); replace when the items team delivers one.\n * It draws in the units of the builder; `data/models.json` gives the scale to metres of the item `scrap_metal`.\n */\nexport const scrapMetal: ItemModelBuilder = ({ mesh, bx, cyl, G, metal }) => {\n const R = Math.PI / 2\n return G(\n mesh(bx(2.0, 0.08, 1.1), metal(0x6e5a4a), [0, -0.36, -0.15]),\n mesh(bx(0.9, 0.5, 0.7), metal(0x7a4a2c), [0.55, -0.07, 0.15]),\n mesh(cyl(0.17, 0.17, 1.5, 8), metal(0x7a7f84), [-0.5, -0.15, 0], [R, 0, 0]),\n mesh(bx(1.2, 0.07, 0.9), metal(0x8a8f94), [0.1, 0.2, 0.05], [0, 0.4, 0.15]),\n mesh(cyl(0.32, 0.32, 0.1, 10), metal(0x4b4f54), [-0.4, 0.35, 0.15]),\n mesh(cyl(0.1, 0.1, 0.11, 6), metal(0x1c1d1f), [-0.4, 0.35, 0.15]),\n )\n}\n","import type { ItemModelBuilder } from './registry'\n\n/**\n * Authored in the kit (no team model delivered); replace when the items team delivers one.\n * It draws in the units of the builder; `data/models.json` gives the scale to metres of the item `bricks`.\n */\nexport const bricks: ItemModelBuilder = ({ mesh, bx, G, M }) => {\n const clay = M(0xa5532f, 'wood', { roughness: 0.95 })\n const clayDark = M(0x974a2b, 'wood', { roughness: 0.95 })\n const mortar = M(0xb9b2a4, 'wood', { roughness: 0.95 })\n return G(\n mesh(bx(1.4, 0.9, 2.9), clay, [-0.25, -0.45, 0]),\n mesh(bx(1.4, 0.9, 2.9), clayDark, [0.25, 0.45, 0]),\n mesh(bx(0.35, 0.02, 1.4), M(0x6e3320, 'wood', { roughness: 0.95 }), [-0.7, 0.005, 0]),\n mesh(bx(0.02, 0.5, 1.2), mortar, [0.951, 0.45, 0.2]),\n )\n}\n","import type { ItemModelBuilder } from './registry'\n\n/**\n * Authored in the kit (no team model delivered); replace when the items team delivers one.\n * It draws in the units of the builder; `data/models.json` gives the scale to metres of the item `rag`.\n */\nexport const rag: ItemModelBuilder = ({ mesh, bx, G, cloth }) => {\n const base = cloth(0xa8473a)\n const fringe = cloth(0xc47d6f)\n return G(\n mesh(bx(2.0, 0.1, 1.8), base, [0, -0.076, 0]),\n mesh(bx(1.7, 0.09, 1.5), cloth(0x9a3f33), [0.1, 0.02, 0], [0, 0.1, 0]),\n mesh(bx(1.5, 0.056, 1.2), cloth(0xb4574a), [0, 0.093, 0]),\n mesh(bx(0.2, 0.02, 1.7), fringe, [1.0, -0.076, 0]),\n mesh(bx(0.2, 0.02, 1.7), fringe, [-1.0, -0.076, 0]),\n mesh(bx(0.3, 0.006, 1.1), cloth(0x6b2a22), [0, 0.123, 0]),\n )\n}\n","import type { ItemModelBuilder } from './registry'\n\n/**\n * Authored in the kit (no team model delivered); replace when the items team delivers one.\n * It draws in the units of the builder; `data/models.json` gives the scale to metres of the item `rebar`.\n */\nexport const rebar: ItemModelBuilder = ({ mesh, lathe, cyl, bx, G, metal }) => {\n const R = Math.PI / 2\n const profile: Array<[number, number]> = [\n [0, -6.33], [0.065, -6.33], [0.065, -5.57], [0.08, -5.55], [0.08, -5.45], [0.065, -5.43], [0.065, -4.57], [0.08, -4.55], [0.08, -4.45], [0.065, -4.43], [0.065, -3.57], [0.08, -3.55], [0.08, -3.45], [0.065, -3.43], [0.065, -2.57], [0.08, -2.55], [0.08, -2.45], [0.065, -2.43], [0.065, -1.57], [0.08, -1.55], [0.08, -1.45], [0.065, -1.43], [0.065, -0.57], [0.08, -0.55], [0.08, -0.45], [0.065, -0.43], [0.065, 0.43], [0.08, 0.45], [0.08, 0.55], [0.065, 0.57], [0.065, 1.43], [0.08, 1.45], [0.08, 1.55], [0.065, 1.57], [0.065, 2.43], [0.08, 2.45], [0.08, 2.55], [0.065, 2.57], [0.065, 3.43], [0.08, 3.45], [0.08, 3.55], [0.065, 3.57], [0.065, 4.43], [0.08, 4.45], [0.08, 4.55], [0.065, 4.57], [0.065, 5.43], [0.08, 5.45], [0.08, 5.55], [0.065, 5.57], [0.065, 6.33], [0, 6.33],\n ]\n return G(\n mesh(lathe(profile, 8), metal(0x585c62), [0, 0, 0], [0, 0, R]),\n mesh(bx(12.4, 0.03, 0.03), metal(0x484c52), [0, 0, 0.065]),\n mesh(cyl(0.062, 0.062, 0.04, 8), metal(0x9a9ea3), [6.33, 0, 0], [0, 0, R]),\n mesh(cyl(0.062, 0.062, 0.04, 8), metal(0x9a9ea3), [-6.33, 0, 0], [0, 0, R]),\n )\n}\n","import type { ItemModelBuilder } from './registry'\n\n/**\n * Authored in the kit (no team model delivered); replace when the items team delivers one.\n * It draws in the units of the builder; `data/models.json` gives the scale to metres of the item `lubricant_spray`.\n */\nexport const lubricantSpray: ItemModelBuilder = ({ mesh, lathe, cyl, bx, G, metal, plastic, paper }) => {\n const body = lathe([[0, -0.85], [0.22, -0.85], [0.25, -0.8], [0.25, 0.35], [0.2, 0.55], [0.12, 0.65]], 12)\n const black = plastic(0x1b1c1d)\n return G(\n mesh(body, metal(0xb4b8bb)),\n mesh(cyl(0.252, 0.252, 0.6, 12), paper(0xd9a21f), [0, -0.2, 0]),\n mesh(cyl(0.08, 0.08, 0.12, 8), metal(0x6f7377), [0, 0.7, 0]),\n mesh(cyl(0.12, 0.12, 0.1, 12), black, [0, 0.8, 0]),\n mesh(bx(0.06, 0.05, 0.12), black, [0, 0.8, 0.14]),\n mesh(cyl(0.1, 0.1, 0.1, 12), plastic(0xd0342c), [0, 0.54, 0]),\n )\n}\n","import type { ItemModelBuilder } from './registry'\n\n/**\n * Authored in the kit (no team model delivered); replace when the items team delivers one.\n */\nexport const armyCamouflageUniform: ItemModelBuilder = ({ mesh, bx, G, cloth }) => {\n const base = cloth(0x59623f)\n const dark = cloth(0x363d28)\n const tan = cloth(0x8a7f55)\n return G(\n mesh(bx(0.24, 0.08, 0.32), base, [0, 0.04, 0]),\n mesh(bx(0.08, 0.07, 0.2), base, [-0.16, 0.035, -0.06]),\n mesh(bx(0.08, 0.07, 0.2), base, [0.16, 0.035, -0.06]),\n mesh(bx(0.08, 0.074, 0.024), dark, [-0.16, 0.037, 0.05]),\n mesh(bx(0.08, 0.074, 0.024), dark, [0.16, 0.037, 0.05]),\n mesh(bx(0.08, 0.01, 0.045), dark, [-0.04, 0.09, -0.135]),\n mesh(bx(0.08, 0.01, 0.045), dark, [0.04, 0.09, -0.135]),\n mesh(bx(0.09, 0.081, 0.09), dark, [-0.06, 0.04, -0.03]),\n mesh(bx(0.1, 0.081, 0.07), tan, [0.07, 0.04, 0.05]),\n mesh(bx(0.07, 0.081, 0.08), dark, [0.04, 0.04, -0.09]),\n mesh(bx(0.1, 0.081, 0.06), tan, [-0.05, 0.04, 0.11]),\n mesh(bx(0.06, 0.1, 0.06), tan, [-0.07, 0.05, -0.1]),\n mesh(bx(0.05, 0.1, 0.07), dark, [0.08, 0.05, -0.12]),\n mesh(bx(0.05, 0.085, 0.05), tan, [0.0, 0.0425, 0.13]),\n )\n}\n","import type { ItemModelBuilder } from './registry'\n\n/**\n * Authored in the kit (no team model delivered); replace when the items team delivers one.\n */\nexport const backpack: ItemModelBuilder = ({ mesh, bx, G, cloth, plastic }) => {\n const main = cloth(0x2f4a6b)\n const trim = cloth(0x1e2a3a)\n return G(\n mesh(bx(0.3, 0.28, 0.12), main, [0, 0.14, -0.02]),\n mesh(bx(0.24, 0.14, 0.06), trim, [0, 0.1, 0.07]),\n mesh(bx(0.05, 0.22, 0.02), trim, [-0.08, 0.13, -0.09]),\n mesh(bx(0.05, 0.22, 0.02), trim, [0.08, 0.13, -0.09]),\n mesh(bx(0.07, 0.02, 0.02), trim, [0, 0.29, -0.02]),\n mesh(bx(0.2, 0.012, 0.125), plastic(0x15181c), [0, 0.2, -0.02]),\n )\n}\n","import type { ItemModelBuilder } from './registry'\n\n/**\n * Authored in the kit (no team model delivered); replace when the items team delivers one.\n */\nexport const ballisticVest: ItemModelBuilder = ({ mesh, bx, G, cloth, metal, plastic }) => {\n const shell = cloth(0x4b5439)\n const strap = cloth(0x3a4130)\n const plate = plastic(0x2a2d2a)\n const buckle = metal(0x8a8d90)\n return G(\n mesh(bx(0.34, 0.045, 0.34), shell, [0, 0.0225, 0.055]),\n mesh(bx(0.08, 0.022, 0.1), strap, [-0.1, 0.011, -0.175]),\n mesh(bx(0.08, 0.022, 0.1), strap, [0.1, 0.011, -0.175]),\n mesh(bx(0.03, 0.04, 0.22), strap, [-0.185, 0.02, 0.1]),\n mesh(bx(0.03, 0.04, 0.22), strap, [0.185, 0.02, 0.1]),\n mesh(bx(0.24, 0.025, 0.24), plate, [0, 0.0575, 0.03]),\n mesh(bx(0.07, 0.02, 0.05), strap, [-0.1, 0.055, 0.19]),\n mesh(bx(0.07, 0.02, 0.05), strap, [0, 0.055, 0.19]),\n mesh(bx(0.07, 0.02, 0.05), strap, [0.1, 0.055, 0.19]),\n mesh(bx(0.03, 0.01, 0.02), buckle, [-0.1, 0.027, -0.215]),\n mesh(bx(0.03, 0.01, 0.02), buckle, [0.1, 0.027, -0.215]),\n )\n}\n","import type { ItemModelBuilder } from './registry'\n\n/**\n * Authored in the kit (no team model delivered); replace when the items team delivers one.\n */\nexport const battery9V: ItemModelBuilder = ({ mesh, cyl, bx, G, metal, plastic }) =>\n G(\n mesh(bx(0.026, 0.043, 0.018), plastic(0x1f2124), [0, 0.0215, 0]),\n mesh(bx(0.0262, 0.012, 0.0182), metal(0xb4b7ba), [0, 0.037, 0]),\n mesh(cyl(0.0045, 0.0045, 0.006, 8), metal(0xc8cacc), [0.006, 0.046, 0]),\n mesh(cyl(0.0035, 0.0035, 0.006, 8), metal(0xc8cacc), [-0.006, 0.046, 0]),\n )\n","import type { ItemModelBuilder } from './registry'\n\n/**\n * Authored in the kit (no team model delivered); replace when the items team delivers one.\n */\nexport const beanSeeds: ItemModelBuilder = ({ mesh, bx, G, paper }) => {\n const width = 0.1\n const height = 0.15\n const depth = 0.02\n const group = G()\n group.add(mesh(bx(width, height, depth * 0.5), paper(0xe8dfc8)))\n group.add(mesh(bx(width * 0.9, height * 0.85, depth * 0.9), paper(0xefe7d3), [0, -height * 0.03, 0]))\n group.add(mesh(bx(width, height * 0.08, depth * 0.3), paper(0xcfc4a8), [0, height * 0.46, 0]))\n ;[1, -1].forEach((side) => group.add(mesh(bx(width * 0.7, height * 0.4, depth * 0.1), paper(0x8a5a3a), [0, -height * 0.05, side * depth * 0.45])))\n return group\n}\n","import type { ItemModelBuilder } from './registry'\n\n/**\n * Authored in the kit (no team model delivered); replace when the items team delivers one.\n */\nexport const beekeeperSuit: ItemModelBuilder = ({ mesh, bx, cyl, G, cloth, metal }) => {\n const white = cloth(0xe3e1d6)\n const grey = cloth(0xb9b7ac)\n const straw = cloth(0xc9b27a)\n const veil = cloth(0x2e2f2c)\n return G(\n mesh(bx(0.2, 0.07, 0.33), white, [0, 0.035, 0]),\n mesh(bx(0.1, 0.06, 0.22), white, [-0.15, 0.03, -0.055]),\n mesh(bx(0.1, 0.06, 0.22), white, [0.15, 0.03, -0.055]),\n mesh(bx(0.1, 0.064, 0.025), grey, [-0.15, 0.032, 0.0675]),\n mesh(bx(0.1, 0.064, 0.025), grey, [0.15, 0.032, 0.0675]),\n mesh(bx(0.2, 0.072, 0.02), grey, [0, 0.036, 0.04]),\n mesh(bx(0.2, 0.072, 0.025), grey, [0, 0.036, 0.1525]),\n mesh(bx(0.012, 0.0702, 0.3), metal(0x9a9da0), [0, 0.0351, 0.01]),\n mesh(cyl(0.078, 0.078, 0.01, 14), straw, [0, 0.075, -0.085]),\n mesh(cyl(0.04, 0.045, 0.02, 12), straw, [0, 0.09, -0.085]),\n mesh(cyl(0.062, 0.062, 0.006, 12), veil, [0, 0.067, -0.085]),\n )\n}\n","import type { ItemModelBuilder } from './registry'\n\n/**\n * Authored in the kit (no team model delivered); replace when the items team delivers one.\n */\nexport const candles: ItemModelBuilder = ({ mesh, cyl, G, cloth, plastic }) =>\n G(\n mesh(cyl(0.03, 0.03, 0.11, 16), plastic(0xe9e2cc), [0, 0.055, 0]),\n mesh(cyl(0.023, 0.023, 0.002, 16), plastic(0xcfc7ad), [0, 0.109, 0]),\n mesh(cyl(0.0015, 0.0015, 0.011, 4), cloth(0x2a2420), [0, 0.1145, 0]),\n )\n","import type { ItemModelBuilder } from './registry'\n\n/**\n * Authored in the kit (no team model delivered); replace when the items team delivers one.\n */\nexport const carAlarmRemote: ItemModelBuilder = ({ mesh, bx, torus, G, plastic, metal }) => {\n const button = plastic(0x6f747a)\n return G(\n mesh(bx(0.04, 0.062, 0.01), plastic(0x1c1e21), [0, 0.031, -0.0005]),\n mesh(bx(0.014, 0.012, 0.002), button, [0, 0.048, 0.0055]),\n mesh(bx(0.014, 0.012, 0.002), button, [-0.01, 0.028, 0.0055]),\n mesh(bx(0.014, 0.012, 0.002), plastic(0xa3322a), [0.01, 0.028, 0.0055]),\n mesh(torus(0.0045, 0.0012), metal(0xb4b7ba), [0, 0.0645, 0]),\n )\n}\n","import type { ItemModelBuilder } from './registry'\n\n/**\n * Authored in the kit (no team model delivered); replace when the items team delivers one.\n */\nexport const carBattery12V: ItemModelBuilder = ({ mesh, cyl, bx, G, metal, plastic, paper }) => {\n const shell = plastic(0x23262a)\n return G(\n mesh(bx(0.24, 0.15, 0.17), shell, [0, 0.075, 0]),\n mesh(bx(0.2, 0.01, 0.04), plastic(0x3a3e44), [0, 0.155, -0.04]),\n mesh(bx(0.18, 0.07, 0.005), paper(0xcfc9b4), [0, 0.07, 0.085]),\n mesh(cyl(0.014, 0.014, 0.04, 8), metal(0x8d9096), [-0.08, 0.17, 0.05]),\n mesh(cyl(0.014, 0.014, 0.04, 8), metal(0x8d9096), [0.08, 0.17, 0.05]),\n mesh(bx(0.1, 0.025, 0.02), shell, [0, 0.1625, -0.07]),\n )\n}\n","import type { ItemModelBuilder } from './registry'\n\n/**\n * Authored in the kit (no team model delivered); replace when the items team delivers one.\n */\nexport const carKey: ItemModelBuilder = ({ mesh, bx, G, metal, plastic }) => {\n const fob = plastic(0x1f2124)\n const button = plastic(0x8a8d90)\n const blade = metal(0xb5b8bb)\n const eyelet = metal(0x6f7275)\n return G(\n mesh(bx(0.038, 0.045, 0.0136), fob, [-0.011, 0.0225, 0]),\n mesh(bx(0.014, 0.008, 0.015), button, [-0.011, 0.034, 0]),\n mesh(bx(0.014, 0.008, 0.015), button, [-0.011, 0.0225, 0]),\n mesh(bx(0.014, 0.008, 0.015), button, [-0.011, 0.011, 0]),\n mesh(bx(0.006, 0.012, 0.0146), eyelet, [-0.027, 0.0385, 0]),\n mesh(bx(0.004, 0.016, 0.006), eyelet, [0.0095, 0.0225, 0]),\n mesh(bx(0.02, 0.012, 0.003), blade, [0.02, 0.0225, 0]),\n mesh(bx(0.004, 0.004, 0.003), blade, [0.016, 0.0145, 0]),\n mesh(bx(0.004, 0.004, 0.003), blade, [0.024, 0.0145, 0]),\n )\n}\n","import type { ItemModelBuilder } from './registry'\n\n/**\n * Authored in the kit (no team model delivered); replace when the items team delivers one.\n */\nexport const cash: ItemModelBuilder = ({ mesh, bx, G, paper }) => {\n const bills = paper(0x6f8f62)\n const group = G()\n group.add(mesh(bx(0.0625, 0.01, 0.065), bills, [-0.04625, 0.005, 0]))\n group.add(mesh(bx(0.03, 0.01, 0.065), paper(0xd8cfa8), [0, 0.005, 0]))\n group.add(mesh(bx(0.0625, 0.01, 0.065), bills, [0.04625, 0.005, 0]))\n return group\n}\n","import type { ItemModelBuilder } from './registry'\n\n/**\n * Authored in the kit (no team model delivered); replace when the items team delivers one.\n */\nexport const cassavaCuttings: ItemModelBuilder = ({ mesh, cyl, G, wood }) => {\n const stick = wood(0x9b7b55)\n const group = G()\n const rows: ReadonlyArray<readonly [number, readonly number[]]> = [[0.02, [-0.04, 0, 0.04]], [0.06, [-0.02, 0.02]], [0.1, [-0.04, 0, 0.04]]]\n rows.forEach(([y, zs]) => zs.forEach((z) => group.add(mesh(cyl(0.02, 0.02, 0.7, 8), stick, [0, y, z], [0, 0, Math.PI / 2]))))\n return group\n}\n","import type { ItemModelBuilder } from './registry'\n\n/**\n * Authored in the kit (no team model delivered); replace when the items team delivers one.\n */\nexport const cbRadio: ItemModelBuilder = ({ M, mesh, cyl, bx, G, metal, plastic }) => {\n const quarter = Math.PI / 2\n const group = G(\n mesh(bx(0.22, 0.006, 0.194), metal(0x1f2124), [0, 0.003, -0.003]),\n mesh(bx(0.25, 0.068, 0.194), metal(0x35383b), [0, 0.04, -0.003]),\n mesh(bx(0.06, 0.02, 0.002), M(0xd9a441, 'glass', { emissive: 0x6a4a10, emissiveIntensity: 0.6 }), [0.06, 0.052, 0.095]),\n mesh(cyl(0.016, 0.016, 0.006, 10), plastic(0x15171a), [-0.08, 0.04, 0.097], [quarter, 0, 0]),\n mesh(cyl(0.016, 0.016, 0.006, 10), plastic(0x15171a), [-0.03, 0.04, 0.097], [quarter, 0, 0]),\n mesh(cyl(0.008, 0.008, 0.006, 8), metal(0x8d9094), [0.09, 0.025, 0.097], [quarter, 0, 0]),\n )\n for (const z of [-0.07, -0.045, -0.02]) group.add(mesh(bx(0.2, 0.006, 0.01), metal(0x1f2124), [0, 0.077, z]))\n return group\n}\n","import type { ItemModelBuilder } from './registry'\n\n/**\n * Authored in the kit (no team model delivered); replace when the items team delivers one.\n */\nexport const cellKey: ItemModelBuilder = ({ mesh, bx, cyl, G, metal }) => {\n const iron = metal(0x3b3b3d)\n const parts = [\n mesh(cyl(0.0035, 0.0035, 0.075, 8), iron, [0.0075, 0.015, 0], [0, 0, Math.PI / 2]),\n mesh(cyl(0.006, 0.006, 0.008, 8), iron, [-0.03, 0.015, 0], [Math.PI / 2, 0, 0]),\n mesh(bx(0.014, 0.012, 0.007), iron, [0.053, 0.009, 0]),\n mesh(bx(0.004, 0.005, 0.007), iron, [0.0485, 0.0025, 0]),\n mesh(bx(0.004, 0.005, 0.007), iron, [0.0575, 0.0025, 0]),\n ]\n const segments = 8\n for (let index = 0; index < segments; index++) {\n const angle = (2 * Math.PI * index) / segments\n parts.push(mesh(bx(0.0105, 0.005, 0.008), iron, [-0.045 + 0.0125 * Math.cos(angle), 0.015 + 0.0125 * Math.sin(angle), 0], [0, 0, angle + Math.PI / 2]))\n }\n return G(...parts)\n}\n","import type { ItemModelBuilder } from './registry'\n\n/**\n * Authored in the kit (no team model delivered); replace when the items team delivers one.\n */\nexport const charcoalBag: ItemModelBuilder = ({ mesh, bx, G, paper, plastic }) => {\n const sack = paper(0x6b5a45)\n return G(\n mesh(bx(0.3, 0.1, 0.34), sack, [0, 0.05, 0]),\n mesh(bx(0.26, 0.12, 0.03), sack, [0, 0.06, 0.185]),\n mesh(bx(0.26, 0.12, 0.03), sack, [0, 0.06, -0.185]),\n mesh(bx(0.24, 0.02, 0.3), sack, [0, 0.11, 0]),\n mesh(bx(0.2, 0.004, 0.16), plastic(0x24262a), [0, 0.118, 0]),\n )\n}\n","import type { ItemModelBuilder } from './registry'\n\n/**\n * Authored in the kit (no team model delivered); replace when the items team delivers one.\n */\nexport const cigarettes: ItemModelBuilder = ({ mesh, bx, G, paper }) => {\n const group = G()\n group.add(mesh(bx(0.055, 0.045, 0.022), paper(0xe8e4da), [0, 0.0225, 0]))\n group.add(mesh(bx(0.055, 0.012, 0.022), paper(0xb08a3a), [0, 0.051, 0]))\n group.add(mesh(bx(0.055, 0.031, 0.022), paper(0xa23b2e), [0, 0.0725, 0]))\n return group\n}\n","import type { ItemModelBuilder } from './registry'\n\n/**\n * Authored in the kit (no team model delivered); replace when the items team delivers one.\n */\nexport const cityMap: ItemModelBuilder = ({ mesh, bx, G, paper }) => {\n const group = G()\n group.add(mesh(bx(0.11, 0.003, 0.25), paper(0xc9b98f), [0, 0.0015, 0]))\n group.add(mesh(bx(0.108, 0.004, 0.24), paper(0xe4dcc2), [0, 0.005, 0]))\n group.add(mesh(bx(0.11, 0.003, 0.18), paper(0xc9b98f), [0, 0.0085, 0.035]))\n group.add(mesh(bx(0.11, 0.003, 0.07), paper(0xa23b2e), [0, 0.0085, -0.09]))\n return group\n}\n","import type { ItemModelBuilder } from './registry'\n\n/**\n * Authored in the kit (no team model delivered); replace when the items team delivers one.\n */\nexport const combatBoots: ItemModelBuilder = ({ mesh, bx, cyl, G, cloth, plastic }) => {\n const leather = cloth(0x1f1e1c)\n const sole = plastic(0x111111)\n const lace = cloth(0x3a3835)\n const boot = (z: number) => [\n mesh(bx(0.3, 0.02, 0.105), sole, [0, 0.01, z]),\n mesh(bx(0.07, 0.016, 0.105), sole, [-0.105, 0.028, z]),\n mesh(bx(0.2, 0.06, 0.095), leather, [0.04, 0.05, z]),\n mesh(cyl(0.0475, 0.0475, 0.06, 8), leather, [0.1025, 0.05, z]),\n mesh(cyl(0.045, 0.05, 0.18, 8), leather, [-0.085, 0.11, z]),\n mesh(bx(0.012, 0.004, 0.07), lace, [0.0, 0.082, z]),\n mesh(bx(0.012, 0.004, 0.07), lace, [0.035, 0.082, z]),\n ]\n return G(...boot(-0.0575), ...boot(0.0575))\n}\n","import type { ItemModelBuilder } from './registry'\n\n/**\n * Authored in the kit (no team model delivered); replace when the items team delivers one.\n */\nexport const coolerBox: ItemModelBuilder = ({ mesh, bx, G, plastic }) => {\n const body = plastic(0x2f5d8a)\n const lid = plastic(0xe6e6e0)\n return G(\n mesh(bx(0.32, 0.19, 0.23), body, [0, 0.095, 0]),\n mesh(bx(0.32, 0.05, 0.23), lid, [0, 0.215, 0]),\n mesh(bx(0.14, 0.01, 0.04), lid, [0, 0.245, 0]),\n mesh(bx(0.06, 0.05, 0.01), lid, [-0.1, 0.18, 0.11]),\n mesh(bx(0.06, 0.05, 0.01), lid, [0.1, 0.18, 0.11]),\n )\n}\n","import type { ItemModelBuilder } from './registry'\n\n/**\n * Authored in the kit (no team model delivered); replace when the items team delivers one.\n */\nexport const cornSeeds: ItemModelBuilder = ({ mesh, bx, G, paper }) => {\n const width = 0.1\n const height = 0.15\n const depth = 0.02\n const group = G()\n group.add(mesh(bx(width, height, depth * 0.5), paper(0xe8dfc8)))\n group.add(mesh(bx(width * 0.9, height * 0.85, depth * 0.9), paper(0xefe7d3), [0, -height * 0.03, 0]))\n group.add(mesh(bx(width, height * 0.08, depth * 0.3), paper(0xcfc4a8), [0, height * 0.46, 0]))\n ;[1, -1].forEach((side) => group.add(mesh(bx(width * 0.7, height * 0.4, depth * 0.1), paper(0xe0b830), [0, -height * 0.05, side * depth * 0.45])))\n return group\n}\n","import type { ItemModelBuilder } from './registry'\n\n/**\n * Authored in the kit (no team model delivered); replace when the items team delivers one.\n */\nexport const crossbodyBag: ItemModelBuilder = ({ mesh, bx, G, cloth, metal }) => {\n const body = cloth(0x3b3f45)\n const strap = cloth(0x25272b)\n return G(\n mesh(bx(0.25, 0.17, 0.07), body, [0, 0.085, -0.005]),\n mesh(bx(0.25, 0.1, 0.01), strap, [0, 0.12, 0.035]),\n mesh(bx(0.03, 0.03, 0.01), metal(0xb0b2b5), [0, 0.085, 0.035]),\n mesh(bx(0.012, 0.03, 0.012), strap, [-0.11, 0.185, 0]),\n mesh(bx(0.012, 0.03, 0.012), strap, [0.11, 0.185, 0]),\n mesh(bx(0.22, 0.012, 0.012), strap, [0, 0.194, 0]),\n )\n}\n","import type { ItemModelBuilder } from './registry'\n\n/**\n * Authored in the kit (no team model delivered); replace when the items team delivers one.\n */\nexport const deliveryBag: ItemModelBuilder = ({ mesh, bx, G, cloth, plastic }) => {\n const shell = cloth(0x8f3b2a)\n const trim = cloth(0x2b2b2d)\n return G(\n mesh(bx(0.48, 0.38, 0.4), shell, [0, 0.19, -0.01]),\n mesh(bx(0.48, 0.04, 0.4), trim, [0, 0.4, -0.01]),\n mesh(bx(0.36, 0.2, 0.02), trim, [0, 0.14, 0.2]),\n mesh(bx(0.24, 0.03, 0.06), trim, [0, 0.435, -0.01]),\n mesh(bx(0.05, 0.03, 0.01), plastic(0xbdbdb5), [0, 0.37, 0.2]),\n mesh(bx(0.02, 0.38, 0.4), trim, [-0.1, 0.19, -0.01]),\n mesh(bx(0.02, 0.38, 0.4), trim, [0.1, 0.19, -0.01]),\n )\n}\n","import type { ItemModelBuilder } from './registry'\n\n/**\n * Authored in the kit (no team model delivered); replace when the items team delivers one.\n */\nexport const denimJacket: ItemModelBuilder = ({ mesh, bx, G, cloth, metal }) => {\n const denim = cloth(0x3f5a85)\n const dark = cloth(0x33496d)\n const stitch = cloth(0xc9a45c)\n const button = metal(0xa9a49a)\n return G(\n mesh(bx(0.26, 0.07, 0.3), denim, [0, 0.035, 0]),\n mesh(bx(0.07, 0.06, 0.18), dark, [-0.165, 0.03, -0.06]),\n mesh(bx(0.07, 0.06, 0.18), dark, [0.165, 0.03, -0.06]),\n mesh(bx(0.07, 0.066, 0.02), denim, [-0.165, 0.033, 0.04]),\n mesh(bx(0.07, 0.066, 0.02), denim, [0.165, 0.033, 0.04]),\n mesh(bx(0.075, 0.01, 0.045), dark, [-0.04, 0.075, -0.13]),\n mesh(bx(0.075, 0.01, 0.045), dark, [0.04, 0.075, -0.13]),\n mesh(bx(0.012, 0.0702, 0.26), stitch, [0, 0.0351, 0.02]),\n mesh(bx(0.05, 0.005, 0.045), dark, [-0.075, 0.0725, -0.04]),\n mesh(bx(0.05, 0.005, 0.045), dark, [0.075, 0.0725, -0.04]),\n mesh(bx(0.008, 0.0745, 0.008), button, [0, 0.03725, -0.04]),\n mesh(bx(0.008, 0.0745, 0.008), button, [0, 0.03725, 0.03]),\n mesh(bx(0.008, 0.0745, 0.008), button, [0, 0.03725, 0.1]),\n )\n}\n","import type { ItemModelBuilder } from './registry'\n\n/**\n * Authored in the kit (no team model delivered); replace when the items team delivers one.\n */\nexport const diesel: ItemModelBuilder = ({ mesh, cyl, G, plastic, paper }) => {\n const bottle = plastic(0xb89a3c)\n const cap = plastic(0x1c1d1f)\n return G(\n mesh(cyl(0.045, 0.045, 0.19, 12), bottle, [0, 0.095, 0]),\n mesh(cyl(0.0455, 0.0455, 0.07, 12), paper(0xd9d4c4), [0, 0.095, 0]),\n mesh(cyl(0.014, 0.045, 0.04, 12), bottle, [0, 0.21, 0]),\n mesh(cyl(0.014, 0.014, 0.01, 8), bottle, [0, 0.235, 0]),\n mesh(cyl(0.018, 0.018, 0.02, 8), cap, [0, 0.25, 0]),\n )\n}\n","import type { ItemModelBuilder } from './registry'\n\n/**\n * Authored in the kit (no team model delivered); replace when the items team delivers one.\n */\nexport const diyMagazine: ItemModelBuilder = ({ mesh, bx, G, paper }) =>\n G(\n mesh(bx(0.21, 0.28, 0.0078), paper(0xe9e6dc), [0, 0.14, 0]),\n mesh(bx(0.21, 0.28, 0.0001), paper(0xd9a441), [0, 0.14, 0.0039]),\n mesh(bx(0.21, 0.28, 0.0001), paper(0xd9a441), [0, 0.14, -0.0039]),\n mesh(bx(0.19, 0.04, 0.0002), paper(0x2f3f52), [0, 0.255, 0.004]),\n mesh(bx(0.15, 0.13, 0.0002), paper(0x8a6a45), [0, 0.13, 0.004]),\n mesh(bx(0.19, 0.012, 0.0002), paper(0xa3322a), [0, 0.04, 0.004]),\n mesh(bx(0.003, 0.28, 0.0008), paper(0x1f2124), [-0.0975, 0.14, 0]),\n )\n","import type { ItemModelBuilder } from './registry'\n\n/**\n * Authored in the kit (no team model delivered); replace when the items team delivers one.\n */\nexport const dogTag: ItemModelBuilder = ({ mesh, cyl, bx, torus, G, metal }) => {\n const steel = metal(0xa7abb0)\n const group = G()\n group.add(mesh(bx(0.03, 0.003, 0.02), steel, [0, 0.0015, 0]))\n group.add(mesh(cyl(0.015, 0.015, 0.003, 8), steel, [0, 0.0015, 0.01]))\n group.add(mesh(cyl(0.015, 0.015, 0.003, 8), steel, [0, 0.0015, -0.01]))\n group.add(mesh(torus(0.0065, 0.0015), metal(0x6c6f75), [0, 0.0015, 0.0175], [Math.PI / 2, 0, 0]))\n return group\n}\n","import type { ItemModelBuilder } from './registry'\n\n/**\n * Authored in the kit (no team model delivered); replace when the items team delivers one.\n */\nexport const electricFenceEnergizer: ItemModelBuilder = ({ M, mesh, cyl, bx, G, metal, plastic }) => {\n const quarter = Math.PI / 2\n const shell = plastic(0x34523b)\n const dark = plastic(0x1f2421)\n return G(\n mesh(bx(0.25, 0.17, 0.146), shell, [0, 0.1, 0]),\n mesh(bx(0.09, 0.06, 0.004), dark, [-0.04, 0.11, 0.075]),\n mesh(bx(0.06, 0.03, 0.004), M(0x9fd18b, 'glass', { emissive: 0x2f5a2a, emissiveIntensity: 0.5 }), [-0.04, 0.12, 0.0752]),\n mesh(cyl(0.016, 0.016, 0.004, 12), dark, [0.07, 0.115, 0.075], [quarter, 0, 0]),\n mesh(cyl(0.006, 0.006, 0.004, 8), M(0xb3261e, 'plastic', { emissive: 0x5a0f0c, emissiveIntensity: 0.6 }), [0.07, 0.07, 0.075], [quarter, 0, 0]),\n mesh(bx(0.13, 0.01, 0.016), metal(0x6d7073), [0, 0.195, 0]),\n mesh(bx(0.01, 0.005, 0.01), metal(0x6d7073), [-0.06, 0.1875, 0]),\n mesh(bx(0.01, 0.005, 0.01), metal(0x6d7073), [0.06, 0.1875, 0]),\n mesh(cyl(0.008, 0.008, 0.015, 8), metal(0xb4b7ba), [-0.07, 0.0075, 0]),\n mesh(cyl(0.008, 0.008, 0.015, 8), metal(0xb4b7ba), [0, 0.0075, 0]),\n mesh(cyl(0.008, 0.008, 0.015, 8), metal(0xb4b7ba), [0.07, 0.0075, 0]),\n )\n}\n","import type { ItemModelBuilder } from './registry'\n\n/**\n * Authored in the kit (no team model delivered); replace when the items team delivers one.\n */\nexport const extensionCord: ItemModelBuilder = ({ mesh, cyl, bx, G, plastic }) => {\n const flange = plastic(0x3a3b3c)\n const plugBody = plastic(0xd8d4c8)\n return G(\n mesh(cyl(0.115, 0.115, 0.008, 14), flange, [0, 0.004, 0]),\n mesh(cyl(0.115, 0.115, 0.008, 14), flange, [0, 0.076, 0]),\n mesh(cyl(0.1, 0.1, 0.064, 14), plastic(0xc7691a), [0, 0.04, 0]),\n mesh(bx(0.012, 0.03, 0.025), plugBody, [0.108, 0.04, 0.02]),\n mesh(bx(0.012, 0.03, 0.04), plugBody, [-0.108, 0.04, -0.02]),\n )\n}\n","import type { ItemModelBuilder } from './registry'\n\n/**\n * Authored in the kit (no team model delivered); replace when the items team delivers one.\n */\nexport const fannyPack: ItemModelBuilder = ({ mesh, bx, G, cloth, plastic }) => {\n const main = cloth(0x3a3d42)\n const trim = cloth(0x25272b)\n return G(\n mesh(bx(0.17, 0.1, 0.1), main, [0, 0.05, -0.01]),\n mesh(bx(0.15, 0.06, 0.02), trim, [0, 0.05, 0.05]),\n mesh(bx(0.04, 0.03, 0.012), trim, [-0.105, 0.05, -0.054]),\n mesh(bx(0.04, 0.03, 0.012), trim, [0.105, 0.05, -0.054]),\n mesh(bx(0.03, 0.03, 0.015), plastic(0x15181c), [0.0, 0.07, 0.05]),\n )\n}\n","import type { ItemModelBuilder } from './registry'\n\n/**\n * Authored in the kit (no team model delivered); replace when the items team delivers one.\n */\nexport const farmersAlmanac: ItemModelBuilder = ({ mesh, bx, G, paper }) => {\n const cover = paper(0x3f5a3a)\n return G(\n mesh(bx(0.1445, 0.206, 0.0116), paper(0xe4dcc6), [0.00025, 0.105, 0]),\n mesh(bx(0.15, 0.21, 0.0014), cover, [0, 0.105, 0.0065]),\n mesh(bx(0.15, 0.21, 0.0014), cover, [0, 0.105, -0.0065]),\n mesh(bx(0.003, 0.21, 0.015), cover, [-0.0735, 0.105, 0]),\n mesh(bx(0.09, 0.04, 0.0004), paper(0xe4dcc6), [0.005, 0.16, 0.0074]),\n mesh(bx(0.1, 0.004, 0.0004), paper(0xc9b36a), [0.005, 0.1, 0.0074]),\n )\n}\n","import type { ItemModelBuilder } from './registry'\n\n/**\n * Authored in the kit (no team model delivered); replace when the items team delivers one.\n */\nexport const fertilizerBag: ItemModelBuilder = ({ mesh, bx, G, cloth, paper }) => {\n const sack = cloth(0xb5a47a)\n const group = G()\n group.add(mesh(bx(0.45, 0.11, 0.3), sack, [0, 0.055, 0]))\n group.add(mesh(bx(0.4, 0.01, 0.26), sack, [0, 0.115, 0]))\n group.add(mesh(bx(0.018, 0.11, 0.3), cloth(0x8f8161), [-0.216, 0.055, 0]))\n group.add(mesh(bx(0.018, 0.11, 0.3), cloth(0x8f8161), [0.216, 0.055, 0]))\n group.add(mesh(bx(0.2, 0.01, 0.12), paper(0x4f7a45), [0, 0.125, 0]))\n return group\n}\n","import type { ItemModelBuilder } from './registry'\n\n/**\n * Authored in the kit (no team model delivered); replace when the items team delivers one.\n */\nexport const firefighterSuit: ItemModelBuilder = ({ mesh, bx, G, cloth, plastic }) => {\n const shell = cloth(0x6b5a34)\n const dark = cloth(0x4d4025)\n const reflective = plastic(0xcfd2c8)\n return G(\n mesh(bx(0.26, 0.09, 0.4), shell, [-0.14, 0.045, 0]),\n mesh(bx(0.26, 0.09, 0.4), shell, [0.14, 0.045, 0]),\n mesh(bx(0.24, 0.092, 0.03), reflective, [-0.14, 0.046, 0.12]),\n mesh(bx(0.24, 0.092, 0.03), reflective, [0.14, 0.046, 0.12]),\n mesh(bx(0.1, 0.092, 0.1), dark, [-0.14, 0.046, -0.04]),\n mesh(bx(0.1, 0.092, 0.1), dark, [0.14, 0.046, -0.04]),\n mesh(bx(0.34, 0.09, 0.38), shell, [0, 0.135, 0]),\n mesh(bx(0.1, 0.08, 0.3), shell, [-0.225, 0.13, -0.04]),\n mesh(bx(0.1, 0.08, 0.3), shell, [0.225, 0.13, -0.04]),\n mesh(bx(0.1, 0.084, 0.03), dark, [-0.225, 0.132, 0.095]),\n mesh(bx(0.1, 0.084, 0.03), dark, [0.225, 0.132, 0.095]),\n mesh(bx(0.342, 0.092, 0.03), reflective, [0, 0.135, 0.12]),\n mesh(bx(0.342, 0.092, 0.03), reflective, [0, 0.135, 0.04]),\n mesh(bx(0.1, 0.084, 0.03), reflective, [-0.225, 0.132, 0.03]),\n mesh(bx(0.1, 0.084, 0.03), reflective, [0.225, 0.132, 0.03]),\n mesh(bx(0.1, 0.02, 0.05), dark, [-0.045, 0.19, -0.16]),\n mesh(bx(0.1, 0.02, 0.05), dark, [0.045, 0.19, -0.16]),\n )\n}\n","import type { ItemModelBuilder } from './registry'\n\n/**\n * Authored in the kit (no team model delivered); replace when the items team delivers one.\n */\nexport const fishingNet: ItemModelBuilder = ({ mesh, bx, G, cloth }) => {\n const cord = cloth(0x6f7a5a)\n const group = G()\n ;[0.003, 0.147].forEach((y) => {\n ;[-0.147, -0.05, 0.05, 0.147].forEach((z) => group.add(mesh(bx(0.35, 0.006, 0.006), cord, [0, y, z])))\n ;[-0.172, -0.086, 0, 0.086, 0.172].forEach((x) => group.add(mesh(bx(0.006, 0.006, 0.3), cord, [x, y, 0])))\n })\n ;[-0.172, 0.172].forEach((x) => [-0.147, 0.147].forEach((z) => group.add(mesh(bx(0.006, 0.15, 0.006), cord, [x, 0.075, z]))))\n return group\n}\n","import type { ItemModelBuilder } from './registry'\n\n/**\n * Authored in the kit (no team model delivered); replace when the items team delivers one.\n */\nexport const fishingRod: ItemModelBuilder = ({ mesh, cyl, bx, G, plastic, wood, metal }) => {\n const group = G()\n group.add(mesh(cyl(0.02, 0.02, 0.25, 8), wood(0xc2a06a), [-0.775, 0, 0], [0, 0, Math.PI / 2]))\n group.add(mesh(cyl(0.004, 0.009, 1.55, 8), plastic(0x2f3a35), [0.125, 0, 0], [0, 0, -Math.PI / 2]))\n group.add(mesh(cyl(0.017, 0.017, 0.012, 12), metal(0x8d9096), [-0.62, 0, 0], [Math.PI / 2, 0, 0]))\n ;[-0.2, 0.2, 0.55, 0.78].forEach((x) => group.add(mesh(bx(0.004, 0.014, 0.004), metal(0x8d9096), [x, 0.01, 0])))\n group.add(mesh(bx(0.012, 0.012, 0.012), metal(0x8d9096), [0.894, 0, 0]))\n return group\n}\n","import type { ItemModelBuilder } from './registry'\n\n/**\n * Authored in the kit (no team model delivered); replace when the items team delivers one.\n */\nexport const fishingTackleBox: ItemModelBuilder = ({ mesh, bx, G, plastic, metal }) => {\n const group = G()\n group.add(mesh(bx(0.3, 0.07, 0.18), plastic(0x3f6b4a), [0, 0.035, 0]))\n group.add(mesh(bx(0.3, 0.025, 0.18), plastic(0x4d7f5a), [0, 0.0825, 0]))\n group.add(mesh(bx(0.12, 0.005, 0.02), plastic(0x2c2c2c), [0, 0.0975, 0]))\n group.add(mesh(bx(0.03, 0.04, 0.004), metal(0x9a9da2), [-0.08, 0.07, 0.088]))\n group.add(mesh(bx(0.03, 0.04, 0.004), metal(0x9a9da2), [0.08, 0.07, 0.088]))\n return group\n}\n","import type { ItemModelBuilder } from './registry'\n\n/**\n * Authored in the kit (no team model delivered); replace when the items team delivers one.\n */\nexport const flipFlops: ItemModelBuilder = ({ mesh, bx, cyl, G, plastic }) => {\n const sole = plastic(0x365d73)\n const strap = plastic(0x1f2326)\n const sandal = (z: number) => [\n mesh(cyl(0.5, 0.5, 0.02, 12), sole, [0.06, 0.01, z], [0, 0, 0], [0.17, 1, 0.105]),\n mesh(cyl(0.5, 0.5, 0.02, 12), sole, [-0.075, 0.01, z], [0, 0, 0], [0.14, 1, 0.09]),\n mesh(bx(0.06, 0.02, 0.07), sole, [-0.01, 0.01, z]),\n mesh(cyl(0.006, 0.006, 0.02, 6), strap, [0.1, 0.02, z]),\n mesh(bx(0.1, 0.008, 0.012), strap, [0.055, 0.024, z + 0.0225], [0, 0.4636, 0]),\n mesh(bx(0.1, 0.008, 0.012), strap, [0.055, 0.024, z - 0.0225], [0, -0.4636, 0]),\n ]\n return G(...sandal(-0.0625), ...sandal(0.0625))\n}\n","import type { ItemModelBuilder } from './registry'\n\n/**\n * Authored in the kit (no team model delivered); replace when the items team delivers one.\n */\nexport const foldingSolarPanel: ItemModelBuilder = ({ mesh, cyl, bx, G, cloth, glass, metal, plastic }) => {\n const group = G(\n mesh(bx(0.396, 0.296, 0.04), cloth(0x30343a), [0, 0.15, 0]),\n mesh(bx(0.38, 0.28, 0.004), glass(0x1d3557, 0.95), [0, 0.15, 0.023]),\n mesh(bx(0.15, 0.1, 0.01), cloth(0x252a2f), [0, 0.12, -0.02]),\n mesh(bx(0.002, 0.28, 0.0006), plastic(0x8d9aa8), [0, 0.15, 0.0253]),\n mesh(bx(0.002, 0.28, 0.0006), plastic(0x8d9aa8), [-0.095, 0.15, 0.0253]),\n mesh(bx(0.002, 0.28, 0.0006), plastic(0x8d9aa8), [0.095, 0.15, 0.0253]),\n )\n for (const [x, y] of [[-0.18, 0.03], [0.18, 0.03], [-0.18, 0.27], [0.18, 0.27]] as const) group.add(mesh(cyl(0.008, 0.008, 0.002, 6), metal(0xb4b7ba), [x, y, 0.024], [Math.PI / 2, 0, 0]))\n return group\n}\n","import type { ItemModelBuilder } from './registry'\n\n/**\n * Authored in the kit (no team model delivered); replace when the items team delivers one.\n */\nexport const gasCartridge: ItemModelBuilder = ({ mesh, cyl, G, metal, paper }) => {\n const can = metal(0x3b5f8a)\n return G(\n mesh(cyl(0.055, 0.055, 0.12, 12), can, [0, 0.06, 0]),\n mesh(cyl(0.0555, 0.0555, 0.04, 12), paper(0xd8d2c0), [0, 0.06, 0]),\n mesh(cyl(0.025, 0.055, 0.03, 12), can, [0, 0.135, 0]),\n mesh(cyl(0.02, 0.02, 0.015, 8), metal(0x8d9096), [0, 0.1575, 0]),\n )\n}\n","import type { ItemModelBuilder } from './registry'\n\n/**\n * Authored in the kit (no team model delivered); replace when the items team delivers one.\n */\nexport const gasoline: ItemModelBuilder = ({ mesh, cyl, G, plastic, paper }) => {\n const bottle = plastic(0xc9c6b8)\n const cap = plastic(0xa3322a)\n return G(\n mesh(cyl(0.045, 0.045, 0.19, 12), bottle, [0, 0.095, 0]),\n mesh(cyl(0.0455, 0.0455, 0.07, 12), paper(0xa3322a), [0, 0.095, 0]),\n mesh(cyl(0.014, 0.045, 0.04, 12), bottle, [0, 0.21, 0]),\n mesh(cyl(0.014, 0.014, 0.01, 8), bottle, [0, 0.235, 0]),\n mesh(cyl(0.018, 0.018, 0.02, 8), cap, [0, 0.25, 0]),\n )\n}\n","import type { ItemModelBuilder } from './registry'\n\n/**\n * Authored in the kit (no team model delivered); replace when the items team delivers one.\n */\nexport const generatorKey: ItemModelBuilder = ({ mesh, bx, G, metal, plastic }) => {\n const steel = metal(0x9a9da0)\n const groove = metal(0x55585b)\n const cover = plastic(0xa8322a)\n const parts = [\n mesh(bx(0.05, 0.012, 0.006), steel, [0.015, 0.016, 0]),\n mesh(bx(0.044, 0.002, 0.006), groove, [0.017, 0.016, 0]),\n mesh(bx(0.005, 0.006, 0.006), steel, [0.0, 0.0075, 0]),\n mesh(bx(0.005, 0.006, 0.006), steel, [0.009, 0.0075, 0]),\n mesh(bx(0.005, 0.006, 0.006), steel, [0.018, 0.0075, 0]),\n mesh(bx(0.005, 0.006, 0.006), steel, [0.033, 0.0075, 0]),\n mesh(bx(0.014, 0.01, 0.006), cover, [-0.008, 0.016, 0]),\n ]\n const segments = 8\n for (let index = 0; index < segments; index++) {\n const angle = (2 * Math.PI * index) / segments\n parts.push(mesh(bx(0.0092, 0.005, 0.006), cover, [-0.025 + 0.0125 * Math.cos(angle), 0.015 + 0.0125 * Math.sin(angle), 0], [0, 0, angle + Math.PI / 2]))\n }\n return G(...parts)\n}\n","import type { ItemModelBuilder } from './registry'\n\n/**\n * Authored in the kit (no team model delivered); replace when the items team delivers one.\n */\nexport const hardHat: ItemModelBuilder = ({ mesh, bx, cyl, lathe, G, plastic, cloth }) => {\n const shell = plastic(0xf2b705)\n const strap = cloth(0x2b2b2b)\n return G(\n mesh(lathe([[0, 0], [0.128, 0], [0.128, 0.04], [0.118, 0.085], [0.087, 0.12], [0.041, 0.138], [0, 0.14]], 14), shell, [0, 0, -0.022]),\n mesh(cyl(0.128, 0.128, 0.012, 14), shell, [0, 0.006, -0.022]),\n mesh(bx(0.22, 0.012, 0.062), shell, [0, 0.006, 0.119]),\n mesh(bx(0.032, 0.012, 0.19), shell, [0, 0.144, -0.022]),\n mesh(bx(0.08, 0.03, 0.02), strap, [0, 0.015, -0.14]),\n )\n}\n","import type { ItemModelBuilder } from './registry'\n\n/**\n * Authored in the kit (no team model delivered); replace when the items team delivers one.\n */\nexport const headlamp: ItemModelBuilder = ({ M, mesh, cyl, bx, G, cloth, plastic }) => {\n const quarter = Math.PI / 2\n const strap = cloth(0x1d2a35)\n return G(\n mesh(bx(0.05, 0.045, 0.024), plastic(0x2b2f33), [0, 0.0225, 0.002]),\n mesh(cyl(0.017, 0.017, 0.011, 12), M(0xfff1c0, 'glass', { emissive: 0xffe08a, emissiveIntensity: 0.6 }), [0, 0.0225, 0.0195], [quarter, 0, 0]),\n mesh(bx(0.012, 0.015, 0.04), strap, [0, 0.0525, -0.005]),\n mesh(bx(0.02, 0.014, 0.004), strap, [-0.035, 0.0225, -0.005]),\n mesh(bx(0.02, 0.014, 0.004), strap, [0.035, 0.0225, -0.005]),\n mesh(bx(0.004, 0.014, 0.02), strap, [-0.043, 0.0225, -0.015]),\n mesh(bx(0.004, 0.014, 0.02), strap, [0.043, 0.0225, -0.015]),\n )\n}\n","import type { ItemModelBuilder } from './registry'\n\n/**\n * Authored in the kit (no team model delivered); replace when the items team delivers one.\n */\nexport const hoodie: ItemModelBuilder = ({ mesh, bx, cyl, G, cloth }) => {\n const fabric = cloth(0x5b6068)\n const rib = cloth(0x484c53)\n const cord = cloth(0xd8d8d0)\n return G(\n mesh(bx(0.25, 0.06, 0.28), fabric, [0, 0.03, 0]),\n mesh(bx(0.065, 0.05, 0.19), fabric, [-0.1575, 0.025, -0.045]),\n mesh(bx(0.065, 0.05, 0.19), fabric, [0.1575, 0.025, -0.045]),\n mesh(bx(0.06, 0.054, 0.025), rib, [-0.1575, 0.027, 0.0675]),\n mesh(bx(0.06, 0.054, 0.025), rib, [0.1575, 0.027, 0.0675]),\n mesh(bx(0.25, 0.062, 0.03), rib, [0, 0.031, 0.125]),\n mesh(cyl(0.062, 0.062, 0.02, 12), fabric, [0, 0.07, -0.075]),\n mesh(bx(0.15, 0.02, 0.055), rib, [0, 0.07, 0.06]),\n mesh(bx(0.006, 0.02, 0.05), cord, [-0.02, 0.07, -0.01]),\n mesh(bx(0.006, 0.02, 0.05), cord, [0.02, 0.07, -0.01]),\n )\n}\n","import type { ItemModelBuilder } from './registry'\n\n/**\n * Authored in the kit (no team model delivered); replace when the items team delivers one.\n */\nexport const janitorKeys: ItemModelBuilder = ({ mesh, bx, G, metal }) => {\n const steel = metal(0xa0a3a6)\n const brass = metal(0xb08a2e)\n const iron = metal(0x6a6d70)\n const parts = []\n const ringSegments = 10\n for (let index = 0; index < ringSegments; index++) {\n const angle = (2 * Math.PI * index) / ringSegments\n parts.push(mesh(bx(0.0105, 0.004, 0.004), steel, [0.0145 * Math.cos(angle), 0.0835 + 0.0145 * Math.sin(angle), 0], [0, 0, angle + Math.PI / 2]))\n }\n const keys = [\n { angle: -0.75, depth: -0.008, material: iron },\n { angle: -0.37, depth: -0.004, material: brass },\n { angle: 0, depth: 0, material: steel },\n { angle: 0.37, depth: 0.004, material: brass },\n { angle: 0.75, depth: 0.008, material: iron },\n ]\n for (const { angle, depth, material } of keys) {\n const key = G(\n mesh(bx(0.014, 0.014, 0.004), material, [0, 0, 0]),\n mesh(bx(0.006, 0.06, 0.004), material, [0, -0.037, 0]),\n mesh(bx(0.01, 0.006, 0.004), material, [0.004, -0.062, 0]),\n mesh(bx(0.01, 0.004, 0.004), material, [0.004, -0.052, 0]),\n )\n key.position.set(0.0165 * Math.sin(angle), 0.0835 - 0.0165 * Math.cos(angle), depth)\n key.rotation.z = angle\n parts.push(key)\n }\n return G(...parts)\n}\n","import type { ItemModelBuilder } from './registry'\n\n/**\n * Authored in the kit (no team model delivered); replace when the items team delivers one.\n */\nexport const jeans: ItemModelBuilder = ({ mesh, bx, G, cloth, metal }) => {\n const denim = cloth(0x3d5683)\n const band = cloth(0x2f4469)\n const stitch = cloth(0xc9a45c)\n return G(\n mesh(bx(0.31, 0.054, 0.105), denim, [0.025, 0.027, -0.0575]),\n mesh(bx(0.31, 0.054, 0.105), denim, [0.025, 0.027, 0.0575]),\n mesh(bx(0.04, 0.06, 0.22), band, [-0.15, 0.03, 0]),\n mesh(bx(0.05, 0.006, 0.06), band, [-0.03, 0.057, -0.0575]),\n mesh(bx(0.05, 0.006, 0.06), band, [-0.03, 0.057, 0.0575]),\n mesh(bx(0.3, 0.0545, 0.003), stitch, [0.03, 0.02725, 0]),\n mesh(bx(0.012, 0.06, 0.012), metal(0xb0b3b6), [-0.15, 0.03, 0]),\n )\n}\n","import type { ItemModelBuilder } from './registry'\n\n/**\n * Authored in the kit (no team model delivered); replace when the items team delivers one.\n */\nexport const kaleAndLettuceSeeds: ItemModelBuilder = ({ mesh, bx, G, paper }) => {\n const width = 0.09\n const height = 0.13\n const depth = 0.015\n const group = G()\n group.add(mesh(bx(width, height, depth * 0.5), paper(0xe8dfc8)))\n group.add(mesh(bx(width * 0.9, height * 0.85, depth * 0.9), paper(0xefe7d3), [0, -height * 0.03, 0]))\n group.add(mesh(bx(width, height * 0.08, depth * 0.3), paper(0xcfc4a8), [0, height * 0.46, 0]))\n ;[1, -1].forEach((side) => group.add(mesh(bx(width * 0.7, height * 0.4, depth * 0.1), paper(0x5f9a4a), [0, -height * 0.05, side * depth * 0.45])))\n return group\n}\n","import type { ItemModelBuilder } from './registry'\n\n/**\n * Authored in the kit (no team model delivered); replace when the items team delivers one.\n */\nexport const kerosene: ItemModelBuilder = ({ mesh, cyl, G, plastic, paper }) => {\n const bottle = plastic(0xc9c6b8)\n const cap = plastic(0x2f5d8a)\n return G(\n mesh(cyl(0.045, 0.045, 0.19, 12), bottle, [0, 0.095, 0]),\n mesh(cyl(0.0455, 0.0455, 0.07, 12), paper(0x2f5d8a), [0, 0.095, 0]),\n mesh(cyl(0.014, 0.045, 0.04, 12), bottle, [0, 0.21, 0]),\n mesh(cyl(0.014, 0.014, 0.01, 8), bottle, [0, 0.235, 0]),\n mesh(cyl(0.018, 0.018, 0.02, 8), cap, [0, 0.25, 0]),\n )\n}\n","import type { ItemModelBuilder } from './registry'\n\n/**\n * Authored in the kit (no team model delivered); replace when the items team delivers one.\n */\nexport const laptop: ItemModelBuilder = ({ mesh, cyl, bx, G, metal, plastic }) =>\n G(\n mesh(bx(0.36, 0.012, 0.25), metal(0x8d9094), [0, 0.006, 0]),\n mesh(bx(0.358, 0.012, 0.248), metal(0x2c2f33), [0, 0.019, 0]),\n mesh(cyl(0.006, 0.006, 0.2, 8), plastic(0x1c1c1c), [0, 0.0125, -0.12], [0, 0, Math.PI / 2]),\n mesh(bx(0.05, 0.0002, 0.03), metal(0xb4b7ba), [0, 0.0251, 0]),\n )\n","import type { ItemModelBuilder } from './registry'\n\n/**\n * Authored in the kit (no team model delivered); replace when the items team delivers one.\n */\nexport const leatherMotorcycleJacket: ItemModelBuilder = ({ mesh, bx, G, cloth, metal }) => {\n const leather = cloth(0x1f1d1c)\n const worn = cloth(0x2c2927)\n const zip = metal(0x9a9da0)\n const pad = cloth(0x3a3633)\n return G(\n mesh(bx(0.29, 0.08, 0.35), leather, [0, 0.04, 0]),\n mesh(bx(0.08, 0.07, 0.24), leather, [-0.185, 0.035, -0.055]),\n mesh(bx(0.08, 0.07, 0.24), leather, [0.185, 0.035, -0.055]),\n mesh(bx(0.08, 0.074, 0.03), worn, [-0.185, 0.037, 0.075]),\n mesh(bx(0.08, 0.074, 0.03), worn, [0.185, 0.037, 0.075]),\n mesh(bx(0.08, 0.09, 0.07), pad, [-0.185, 0.045, -0.12]),\n mesh(bx(0.08, 0.09, 0.07), pad, [0.185, 0.045, -0.12]),\n mesh(bx(0.09, 0.012, 0.06), worn, [-0.05, 0.086, -0.15]),\n mesh(bx(0.09, 0.012, 0.06), worn, [0.05, 0.086, -0.15]),\n mesh(bx(0.012, 0.0802, 0.3), zip, [0.015, 0.0401, 0.025]),\n mesh(bx(0.06, 0.006, 0.01), zip, [-0.07, 0.083, 0.0]),\n mesh(bx(0.06, 0.006, 0.01), zip, [0.07, 0.083, 0.0]),\n mesh(bx(0.1, 0.1, 0.03), worn, [0, 0.05, 0.16]),\n )\n}\n","import type { ItemModelBuilder } from './registry'\n\n/**\n * Authored in the kit (no team model delivered); replace when the items team delivers one.\n */\nexport const leatherMotorcyclePants: ItemModelBuilder = ({ mesh, bx, G, cloth, metal }) => {\n const leather = cloth(0x1f1d1c)\n const pad = cloth(0x302d2b)\n const zip = metal(0x9a9da0)\n return G(\n mesh(bx(0.36, 0.08, 0.145), leather, [0.02, 0.04, -0.0775]),\n mesh(bx(0.36, 0.08, 0.145), leather, [0.02, 0.04, 0.0775]),\n mesh(bx(0.04, 0.09, 0.3), pad, [-0.18, 0.045, 0]),\n mesh(bx(0.07, 0.01, 0.1), pad, [0.0, 0.085, -0.0775]),\n mesh(bx(0.07, 0.01, 0.1), pad, [0.0, 0.085, 0.0775]),\n mesh(bx(0.012, 0.0902, 0.012), zip, [-0.18, 0.0451, 0]),\n mesh(bx(0.04, 0.0802, 0.14), pad, [0.17, 0.0401, -0.0775]),\n mesh(bx(0.04, 0.0802, 0.14), pad, [0.17, 0.0401, 0.0775]),\n mesh(bx(0.2, 0.0825, 0.004), zip, [0.07, 0.04125, -0.0035]),\n )\n}\n","import type { ItemModelBuilder } from './registry'\n\n/**\n * Authored in the kit (no team model delivered); replace when the items team delivers one.\n */\nexport const leatherWorkGloves: ItemModelBuilder = ({ mesh, bx, G, cloth }) => {\n const leather = cloth(0xb08a52)\n const cuff = cloth(0x8a6a3c)\n const finger = (x: number, length: number, z: number) => mesh(bx(length, 0.02, 0.022), leather, [x + length / 2, 0.01, z])\n return G(\n mesh(bx(0.055, 0.03, 0.12), cuff, [-0.0975, 0.015, 0]),\n mesh(bx(0.1, 0.022, 0.1), leather, [-0.02, 0.011, 0]),\n finger(0.03, 0.09, -0.039),\n finger(0.03, 0.095, -0.013),\n finger(0.03, 0.09, 0.013),\n finger(0.03, 0.075, 0.039),\n mesh(bx(0.05, 0.02, 0.026), leather, [-0.01, 0.01, 0.036], [0, -0.5, 0]),\n mesh(bx(0.03, 0.024, 0.1), cuff, [-0.0575, 0.012, 0]),\n )\n}\n","import type { ItemModelBuilder } from './registry'\n\n/**\n * Authored in the kit (no team model delivered); replace when the items team delivers one.\n */\nexport const ledCampLantern: ItemModelBuilder = ({ M, mesh, cyl, bx, G, metal, plastic }) => {\n const body = plastic(0x3b4a3a)\n return G(\n mesh(cyl(0.055, 0.055, 0.03, 16), body, [0, 0.015, 0]),\n mesh(cyl(0.045, 0.045, 0.12, 16), M(0xfff1c0, 'glass', { emissive: 0xffe08a, emissiveIntensity: 0.5, transparent: true, opacity: 0.85 }), [0, 0.09, 0]),\n mesh(cyl(0.05, 0.055, 0.025, 16), body, [0, 0.1625, 0]),\n mesh(bx(0.008, 0.025, 0.008), metal(0x8d9094), [-0.045, 0.1875, 0]),\n mesh(bx(0.008, 0.025, 0.008), metal(0x8d9094), [0.045, 0.1875, 0]),\n mesh(bx(0.098, 0.008, 0.008), metal(0x8d9094), [0, 0.196, 0]),\n )\n}\n","import type { ItemModelBuilder } from './registry'\n\n/**\n * Authored in the kit (no team model delivered); replace when the items team delivers one.\n */\nexport const magazineArmGuard: ItemModelBuilder = ({ mesh, bx, G, paper, cloth }) => {\n const covers = [paper(0xb8b2a2), paper(0x8c9aa6), paper(0xa88a6e), paper(0x8c9aa6), paper(0xb8b2a2)]\n const tape = cloth(0x3a4130)\n const parts = []\n const count = covers.length\n for (let index = 0; index < count; index++) {\n const phi = -1.0 + (2.0 * index) / (count - 1)\n const radiusZ = 0.0657\n const radiusY = 0.05\n const y = 0.0295 + radiusY * Math.cos(phi) - radiusY * Math.cos(1.0)\n const z = radiusZ * Math.sin(phi)\n const angle = Math.atan2(radiusY * Math.sin(phi), radiusZ * Math.cos(phi))\n parts.push(mesh(bx(0.3, 0.008, 0.052), covers[index]!, [0, y, z], [angle, 0, 0]))\n for (const x of [-0.075, 0.075]) parts.push(mesh(bx(0.025, 0.008, 0.052), tape, [x, y + 0.006, z], [angle, 0, 0]))\n }\n return G(...parts)\n}\n","import type { ItemModelBuilder } from './registry'\n\n/**\n * Authored in the kit (no team model delivered); replace when the items team delivers one.\n */\nexport const magazinesAndComics: ItemModelBuilder = ({ mesh, bx, G, paper }) =>\n G(\n mesh(bx(0.17, 0.26, 0.0092), paper(0xe4dcc6), [0, 0.13, 0]),\n mesh(bx(0.17, 0.26, 0.0002), paper(0xb23a2e), [0, 0.13, 0.0048]),\n mesh(bx(0.17, 0.26, 0.0002), paper(0xb23a2e), [0, 0.13, -0.0048]),\n mesh(bx(0.15, 0.04, 0.0002), paper(0xf0d36a), [0, 0.235, 0.005]),\n mesh(bx(0.14, 0.14, 0.0002), paper(0x3b6ea0), [0, 0.12, 0.005]),\n mesh(bx(0.07, 0.07, 0.0002), paper(0xf0d36a), [-0.03, 0.12, 0.0051]),\n )\n","import type { ItemModelBuilder } from './registry'\n\n/**\n * Authored in the kit (no team model delivered); replace when the items team delivers one.\n */\nexport const masterKey: ItemModelBuilder = ({ mesh, bx, G, metal }) => {\n const nickel = metal(0xc7c9cc)\n const parts = [\n mesh(bx(0.057, 0.014, 0.006), nickel, [0.0165, 0.0175, 0]),\n mesh(bx(0.005, 0.02, 0.006), nickel, [-0.011, 0.0175, 0]),\n ]\n for (let tooth = 0; tooth < 6; tooth++) parts.push(mesh(bx(0.004, 0.007, 0.006), nickel, [0.0 + tooth * 0.0085, 0.0075 + (tooth % 2) * 0.002, 0]))\n const segments = 8\n for (let index = 0; index < segments; index++) {\n const angle = (2 * Math.PI * index) / segments\n parts.push(mesh(bx(0.0115, 0.006, 0.006), nickel, [-0.0275 + 0.0145 * Math.cos(angle), 0.0175 + 0.0145 * Math.sin(angle), 0], [0, 0, angle + Math.PI / 2]))\n }\n return G(...parts)\n}\n","import type { ItemModelBuilder } from './registry'\n\n/**\n * Authored in the kit (no team model delivered); replace when the items team delivers one.\n */\nexport const mechanicCoveralls: ItemModelBuilder = ({ mesh, bx, G, cloth, metal }) => {\n const fabric = cloth(0x3c5a78)\n const dark = cloth(0x2f4760)\n const zip = metal(0x9a9da0)\n return G(\n mesh(bx(0.18, 0.07, 0.14), fabric, [0, 0.035, -0.08]),\n mesh(bx(0.09, 0.07, 0.15), fabric, [-0.0465, 0.035, 0.075]),\n mesh(bx(0.09, 0.07, 0.15), fabric, [0.0465, 0.035, 0.075]),\n mesh(bx(0.11, 0.06, 0.1), fabric, [-0.145, 0.03, -0.1]),\n mesh(bx(0.11, 0.06, 0.1), fabric, [0.145, 0.03, -0.1]),\n mesh(bx(0.03, 0.064, 0.1), dark, [-0.185, 0.032, -0.1]),\n mesh(bx(0.03, 0.064, 0.1), dark, [0.185, 0.032, -0.1]),\n mesh(bx(0.18, 0.074, 0.025), dark, [0, 0.037, 0.1375]),\n mesh(bx(0.07, 0.08, 0.04), dark, [0, 0.04, -0.13]),\n mesh(bx(0.012, 0.0802, 0.2), zip, [0, 0.0401, -0.05]),\n mesh(bx(0.05, 0.08, 0.04), dark, [-0.05, 0.04, -0.07]),\n mesh(bx(0.05, 0.09, 0.03), dark, [0.05, 0.045, -0.02]),\n mesh(bx(0.14, 0.071, 0.012), dark, [0, 0.0355, 0.0]),\n )\n}\n","import type { ItemModelBuilder } from './registry'\n\n/**\n * Authored in the kit (no team model delivered); replace when the items team delivers one.\n */\nexport const militaryBackpack: ItemModelBuilder = ({ mesh, cyl, bx, G, cloth, plastic }) => {\n const main = cloth(0x4a4f35)\n const dark = cloth(0x33372a)\n return G(\n mesh(bx(0.33, 0.5, 0.18), main, [0, 0.25, -0.04]),\n mesh(bx(0.35, 0.1, 0.25), dark, [0, 0.55, -0.025]),\n mesh(bx(0.12, 0.2, 0.08), dark, [-0.11, 0.3, 0.09]),\n mesh(bx(0.12, 0.2, 0.08), dark, [0.11, 0.3, 0.09]),\n mesh(cyl(0.07, 0.07, 0.3, 8), cloth(0x5a5d40), [0, 0.07, 0.08], [0, 0, Math.PI / 2]),\n mesh(bx(0.06, 0.4, 0.02), dark, [-0.09, 0.28, -0.14]),\n mesh(bx(0.06, 0.4, 0.02), dark, [0.09, 0.28, -0.14]),\n mesh(bx(0.04, 0.03, 0.02), plastic(0x1c1d1f), [0, 0.52, 0.1]),\n )\n}\n","import type { ItemModelBuilder } from './registry'\n\n/**\n * Authored in the kit (no team model delivered); replace when the items team delivers one.\n */\nexport const militaryRadio: ItemModelBuilder = ({ M, mesh, cyl, bx, G, metal, plastic }) => {\n const quarter = Math.PI / 2\n const dark = plastic(0x1c1e1a)\n const group = G(\n mesh(bx(0.3, 0.14, 0.238), metal(0x4b5230), [0, 0.07, -0.006]),\n mesh(bx(0.08, 0.03, 0.002), M(0xa8d88f, 'glass', { emissive: 0x2f5a2a, emissiveIntensity: 0.5 }), [0.05, 0.1, 0.114]),\n mesh(cyl(0.02, 0.02, 0.016, 10), dark, [-0.08, 0.148, 0.04]),\n mesh(cyl(0.02, 0.02, 0.016, 10), dark, [-0.02, 0.148, 0.04]),\n mesh(cyl(0.018, 0.018, 0.018, 10), metal(0x2a2c2e), [0.1, 0.149, -0.08]),\n mesh(cyl(0.005, 0.008, 0.042, 6), metal(0x2a2c2e), [0.1, 0.179, -0.08]),\n mesh(bx(0.008, 0.015, 0.01), metal(0x2a2c2e), [-0.05, 0.1475, -0.06]),\n mesh(bx(0.008, 0.015, 0.01), metal(0x2a2c2e), [0.05, 0.1475, -0.06]),\n mesh(bx(0.108, 0.008, 0.01), metal(0x2a2c2e), [0, 0.155, -0.06]),\n )\n for (const x of [-0.08, 0, 0.08]) group.add(mesh(cyl(0.015, 0.015, 0.012, 8), metal(0x2a2c2e), [x, 0.045, 0.119], [quarter, 0, 0]))\n return group\n}\n","import type { ItemModelBuilder } from './registry'\n\n/**\n * Authored in the kit (no team model delivered); replace when the items team delivers one.\n */\nexport const mobilePhone: ItemModelBuilder = ({ M, mesh, bx, G, plastic, glass }) =>\n G(\n mesh(bx(0.077, 0.16, 0.0082), plastic(0x23262b), [0, 0.08, 0]),\n mesh(bx(0.07, 0.15, 0.0004), glass(0x0c1118, 0.95), [0, 0.08, 0.0043]),\n mesh(bx(0.026, 0.026, 0.0004), plastic(0x15171a), [-0.02, 0.14, -0.0043]),\n mesh(bx(0.016, 0.002, 0.0004), M(0x3b4048, 'plastic'), [0, 0.153, 0.0043]),\n )\n","import type { ItemModelBuilder } from './registry'\n\n/**\n * Authored in the kit (no team model delivered); replace when the items team delivers one.\n */\nexport const motorOil: ItemModelBuilder = ({ mesh, cyl, bx, G, plastic, paper }) => {\n const bottle = plastic(0x2a2d31)\n return G(\n mesh(bx(0.09, 0.19, 0.068), bottle, [-0.005, 0.095, 0]),\n mesh(bx(0.07, 0.08, 0.002), paper(0xd9a441), [-0.005, 0.09, 0.035]),\n mesh(cyl(0.02, 0.033, 0.04, 8), bottle, [-0.005, 0.21, 0]),\n mesh(cyl(0.02, 0.02, 0.03, 8), plastic(0xd9a441), [-0.005, 0.245, 0]),\n mesh(bx(0.01, 0.12, 0.03), bottle, [0.045, 0.11, 0]),\n )\n}\n","import type { ItemModelBuilder } from './registry'\n\n/**\n * Authored in the kit (no team model delivered); replace when the items team delivers one.\n */\nexport const nightVisionGoggles: ItemModelBuilder = ({ M, mesh, cyl, bx, G, metal, plastic }) => {\n const quarter = Math.PI / 2\n const shell = plastic(0x2e332b)\n const lens = M(0x1f3a24, 'glass', { emissive: 0x2f7a45, emissiveIntensity: 0.5 })\n const group = G(\n mesh(bx(0.12, 0.045, 0.05), shell, [0, 0.05, -0.005]),\n mesh(bx(0.08, 0.014, 0.06), shell, [0, 0.007, -0.005]),\n mesh(bx(0.04, 0.016, 0.05), metal(0x2a2c2e), [0, 0.092, -0.005]),\n )\n for (const x of [-0.039, 0.039]) {\n group.add(mesh(cyl(0.036, 0.036, 0.05, 12), shell, [x, 0.05, 0.03], [quarter, 0, 0]))\n group.add(mesh(cyl(0.028, 0.028, 0.002, 10), lens, [x, 0.05, 0.054], [quarter, 0, 0]))\n group.add(mesh(cyl(0.03, 0.03, 0.03, 10), plastic(0x15171a), [x, 0.05, -0.04], [quarter, 0, 0]))\n }\n return group\n}\n","import type { ItemModelBuilder } from './registry'\n\n/**\n * Authored in the kit (no team model delivered); replace when the items team delivers one.\n */\nexport const note: ItemModelBuilder = ({ mesh, bx, G, paper }) => {\n const group = G()\n group.add(mesh(bx(0.15, 0.001, 0.1), paper(0xe9e2cf), [0, 0.0005, 0]))\n group.add(mesh(bx(0.14, 0.001, 0.09), paper(0xf3eedd), [0, 0.0015, 0.002]))\n return group\n}\n","import type { ItemModelBuilder } from './registry'\n\n/**\n * Authored in the kit (no team model delivered); replace when the items team delivers one.\n */\nexport const paddedCoat: ItemModelBuilder = ({ mesh, bx, cyl, G, cloth, metal }) => {\n const shell = cloth(0x3a4a3e)\n const rib = cloth(0x2b362f)\n const zip = metal(0x9a9da0)\n const parts = [\n mesh(bx(0.3, 0.12, 0.35), shell, [0, 0.06, 0]),\n mesh(bx(0.075, 0.1, 0.24), shell, [-0.1875, 0.05, -0.055]),\n mesh(bx(0.075, 0.1, 0.24), shell, [0.1875, 0.05, -0.055]),\n mesh(bx(0.075, 0.104, 0.03), rib, [-0.1875, 0.052, 0.075]),\n mesh(bx(0.075, 0.104, 0.03), rib, [0.1875, 0.052, 0.075]),\n mesh(cyl(0.07, 0.07, 0.03, 12), shell, [0, 0.135, -0.1]),\n mesh(bx(0.012, 0.1202, 0.34), zip, [0, 0.0601, 0.005]),\n ]\n for (const z of [-0.12, -0.04, 0.04, 0.12]) parts.push(mesh(bx(0.29, 0.03, 0.014), rib, [0, 0.135, z]))\n return G(...parts)\n}\n","import type { ItemModelBuilder } from './registry'\n\n/**\n * Authored in the kit (no team model delivered); replace when the items team delivers one.\n */\nexport const padlockKey: ItemModelBuilder = ({ mesh, bx, G, metal }) => {\n const body = metal(0x8a8d90)\n const shackle = metal(0xc0c3c6)\n const slot = metal(0x1f2022)\n const parts = [\n mesh(bx(0.05, 0.05, 0.0225), body, [0, 0.025, 0]),\n mesh(bx(0.05, 0.006, 0.0225), body, [0, 0.003, 0]),\n mesh(bx(0.006, 0.014, 0.025), slot, [0, 0.022, 0]),\n mesh(bx(0.006, 0.026, 0.008), shackle, [-0.014, 0.063, 0]),\n mesh(bx(0.006, 0.026, 0.008), shackle, [0.014, 0.063, 0]),\n ]\n const segments = 6\n for (let index = 0; index < segments; index++) {\n const angle = (Math.PI * (index + 0.5)) / segments\n parts.push(mesh(bx(0.0105, 0.006, 0.008), shackle, [0.014 * Math.cos(angle), 0.063 + 0.014 * Math.sin(angle), 0], [0, 0, angle + Math.PI / 2]))\n }\n return G(...parts)\n}\n","import type { ItemModelBuilder } from './registry'\n\n/**\n * Authored in the kit (no team model delivered); replace when the items team delivers one.\n */\nexport const photo: ItemModelBuilder = ({ mesh, bx, G, paper }) => {\n const group = G()\n group.add(mesh(bx(0.102, 0.001, 0.152), paper(0xf1eee4), [0, 0.0005, 0]))\n group.add(mesh(bx(0.088, 0.001, 0.115), paper(0x7a8a8c), [0, 0.0015, -0.01]))\n return group\n}\n","import type { ItemModelBuilder } from './registry'\n\n/**\n * Authored in the kit (no team model delivered); replace when the items team delivers one.\n */\nexport const portableGenerator: ItemModelBuilder = ({ M, mesh, cyl, bx, G, metal, plastic }) => {\n const quarter = Math.PI / 2\n const frame = metal(0x3a3c3e)\n const group = G(\n mesh(bx(0.5, 0.02, 0.02), frame, [0, 0.01, 0.205]),\n mesh(bx(0.5, 0.02, 0.02), frame, [0, 0.01, -0.205]),\n mesh(bx(0.02, 0.02, 0.43), frame, [0.24, 0.01, 0]),\n mesh(bx(0.02, 0.02, 0.43), frame, [-0.24, 0.01, 0]),\n mesh(bx(0.5, 0.02, 0.02), frame, [0, 0.41, 0.205]),\n mesh(bx(0.5, 0.02, 0.02), frame, [0, 0.41, -0.205]),\n mesh(bx(0.02, 0.02, 0.43), frame, [0.24, 0.41, 0]),\n mesh(bx(0.02, 0.02, 0.43), frame, [-0.24, 0.41, 0]),\n mesh(bx(0.2, 0.2, 0.26), metal(0x6e7173), [-0.12, 0.13, 0]),\n mesh(cyl(0.11, 0.11, 0.18, 14), metal(0x3f5a73), [0.14, 0.15, 0], [0, 0, quarter]),\n mesh(bx(0.34, 0.1, 0.28), plastic(0x9c2f23), [0, 0.35, 0]),\n mesh(cyl(0.025, 0.025, 0.02, 8), plastic(0x1c1c1c), [-0.1, 0.41, 0]),\n mesh(bx(0.2, 0.12, 0.01), plastic(0x222426), [0.13, 0.2, 0.21]),\n mesh(bx(0.04, 0.04, 0.0045), M(0x777a7d, 'plastic'), [0.09, 0.2, 0.2162]),\n mesh(bx(0.04, 0.04, 0.0045), M(0x777a7d, 'plastic'), [0.17, 0.2, 0.2162]),\n mesh(cyl(0.035, 0.035, 0.16, 10), metal(0x5b4a3c), [-0.12, 0.1, -0.17], [0, 0, quarter]),\n )\n for (const [x, z] of [[-0.24, -0.205], [0.24, -0.205], [-0.24, 0.205], [0.24, 0.205]] as const) group.add(mesh(bx(0.02, 0.4, 0.02), frame, [x, 0.21, z]))\n return group\n}\n","import type { ItemModelBuilder } from './registry'\n\n/**\n * Authored in the kit (no team model delivered); replace when the items team delivers one.\n */\nexport const powerBank: ItemModelBuilder = ({ M, mesh, bx, G, plastic }) => {\n const led = M(0x8be3a0, 'plastic', { emissive: 0x2f7a45, emissiveIntensity: 0.6 })\n return G(\n mesh(bx(0.15, 0.07, 0.015), plastic(0x2d3138), [0, 0.035, 0]),\n mesh(bx(0.07, 0.024, 0.001), plastic(0x4a5058), [-0.025, 0.035, 0.0078]),\n mesh(bx(0.02, 0.008, 0.001), plastic(0x0f1012), [0.058, 0.058, 0.0078]),\n mesh(bx(0.012, 0.004, 0.001), led, [0.028, 0.02, 0.0078]),\n mesh(bx(0.012, 0.004, 0.001), led, [0.044, 0.02, 0.0078]),\n mesh(bx(0.012, 0.004, 0.001), led, [0.06, 0.02, 0.0078]),\n )\n}\n","import type { ItemModelBuilder } from './registry'\n\n/**\n * Authored in the kit (no team model delivered); replace when the items team delivers one.\n */\nexport const pumpkinSeeds: ItemModelBuilder = ({ mesh, bx, G, paper }) => {\n const width = 0.09\n const height = 0.13\n const depth = 0.015\n const group = G()\n group.add(mesh(bx(width, height, depth * 0.5), paper(0xe8dfc8)))\n group.add(mesh(bx(width * 0.9, height * 0.85, depth * 0.9), paper(0xefe7d3), [0, -height * 0.03, 0]))\n group.add(mesh(bx(width, height * 0.08, depth * 0.3), paper(0xcfc4a8), [0, height * 0.46, 0]))\n ;[1, -1].forEach((side) => group.add(mesh(bx(width * 0.7, height * 0.4, depth * 0.1), paper(0xd9822b), [0, -height * 0.05, side * depth * 0.45])))\n return group\n}\n","import type { ItemModelBuilder } from './registry'\n\n/**\n * Authored in the kit (no team model delivered); replace when the items team delivers one.\n */\nexport const raincoat: ItemModelBuilder = ({ mesh, bx, cyl, G, plastic, metal }) => {\n const sheet = plastic(0xd2a91c)\n const trim = plastic(0xa8851a)\n return G(\n mesh(bx(0.2, 0.03, 0.25), sheet, [0, 0.015, 0]),\n mesh(bx(0.05, 0.026, 0.17), sheet, [-0.125, 0.013, -0.04]),\n mesh(bx(0.05, 0.026, 0.17), sheet, [0.125, 0.013, -0.04]),\n mesh(bx(0.05, 0.03, 0.012), trim, [-0.125, 0.015, 0.05]),\n mesh(bx(0.05, 0.03, 0.012), trim, [0.125, 0.015, 0.05]),\n mesh(cyl(0.055, 0.055, 0.01, 12), trim, [0, 0.035, -0.07]),\n mesh(bx(0.014, 0.01, 0.17), trim, [0, 0.035, 0.04]),\n mesh(cyl(0.006, 0.006, 0.012, 6), metal(0x8a8d90), [0, 0.034, 0.0]),\n mesh(cyl(0.006, 0.006, 0.012, 6), metal(0x8a8d90), [0, 0.034, 0.06]),\n )\n}\n","import type { ItemModelBuilder } from './registry'\n\n/**\n * Authored in the kit (no team model delivered); replace when the items team delivers one.\n */\nexport const roadMap: ItemModelBuilder = ({ mesh, bx, G, paper }) => {\n const group = G()\n group.add(mesh(bx(0.11, 0.003, 0.25), paper(0x4f7a8a), [0, 0.0015, 0]))\n group.add(mesh(bx(0.108, 0.004, 0.24), paper(0xe4dcc2), [0, 0.005, 0]))\n group.add(mesh(bx(0.11, 0.003, 0.18), paper(0x4f7a8a), [0, 0.0085, 0.035]))\n group.add(mesh(bx(0.11, 0.003, 0.07), paper(0xe0b830), [0, 0.0085, -0.09]))\n return group\n}\n","import type { ItemModelBuilder } from './registry'\n\n/**\n * Authored in the kit (no team model delivered); replace when the items team delivers one.\n */\nexport const rollingSuitcase: ItemModelBuilder = ({ mesh, cyl, bx, G, plastic }) => {\n const shell = plastic(0x3d4a5c)\n const trim = plastic(0x1f2226)\n const parts = [\n mesh(bx(0.4, 0.55, 0.25), shell, [0, 0.325, 0]),\n mesh(bx(0.012, 0.5, 0.25), trim, [-0.1, 0.325, 0]),\n mesh(bx(0.012, 0.5, 0.25), trim, [0.1, 0.325, 0]),\n mesh(bx(0.012, 0.04, 0.012), trim, [-0.06, 0.62, 0]),\n mesh(bx(0.012, 0.04, 0.012), trim, [0.06, 0.62, 0]),\n mesh(bx(0.15, 0.02, 0.03), trim, [0, 0.64, 0]),\n mesh(bx(0.12, 0.03, 0.04), trim, [0, 0.55, -0.1]),\n ]\n for (const x of [-0.15, 0.15]) for (const z of [-0.09, 0.09]) parts.push(mesh(cyl(0.025, 0.025, 0.02, 8), trim, [x, 0.025, z], [0, 0, Math.PI / 2]))\n return G(...parts)\n}\n","import type { ItemModelBuilder } from './registry'\n\n/**\n * Authored in the kit (no team model delivered); replace when the items team delivers one.\n */\nexport const rubberBoots: ItemModelBuilder = ({ mesh, bx, cyl, G, plastic }) => {\n const rubber = plastic(0x3d5a3a)\n const sole = plastic(0x1d1d1d)\n const rim = plastic(0x2f4a2e)\n const boot = (z: number) => [\n mesh(bx(0.3, 0.025, 0.105), sole, [0, 0.0125, z]),\n mesh(bx(0.07, 0.03, 0.105), sole, [-0.115, 0.04, z]),\n mesh(bx(0.2, 0.06, 0.1), rubber, [0.04, 0.055, z]),\n mesh(cyl(0.05, 0.05, 0.06, 8), rubber, [0.1, 0.055, z]),\n mesh(cyl(0.05, 0.052, 0.325, 10), rubber, [-0.085, 0.1875, z]),\n mesh(cyl(0.054, 0.054, 0.015, 10), rim, [-0.085, 0.3425, z]),\n ]\n return G(...boot(-0.0575), ...boot(0.0575))\n}\n","import type { ItemModelBuilder } from './registry'\n\n/**\n * Authored in the kit (no team model delivered); replace when the items team delivers one.\n */\nexport const safeKey: ItemModelBuilder = ({ mesh, bx, G, metal }) => {\n const brass = metal(0xb08a2e)\n const parts = [\n mesh(bx(0.046, 0.01, 0.005), brass, [0.012, 0.0125, 0]),\n mesh(bx(0.004, 0.016, 0.005), brass, [-0.01, 0.0125, 0]),\n mesh(bx(0.006, 0.004, 0.005), brass, [0.0, 0.0055, 0]),\n mesh(bx(0.006, 0.004, 0.005), brass, [0.01, 0.0055, 0]),\n mesh(bx(0.006, 0.004, 0.005), brass, [0.02, 0.0055, 0]),\n mesh(bx(0.006, 0.004, 0.005), brass, [0.0315, 0.0055, 0]),\n mesh(bx(0.006, 0.004, 0.005), brass, [0.0, 0.0195, 0]),\n mesh(bx(0.006, 0.004, 0.005), brass, [0.015, 0.0195, 0]),\n ]\n const segments = 8\n for (let index = 0; index < segments; index++) {\n const angle = (2 * Math.PI * index) / segments\n parts.push(mesh(bx(0.0066, 0.0045, 0.005), brass, [-0.0225 + 0.0102 * Math.cos(angle), 0.0125 + 0.0102 * Math.sin(angle), 0], [0, 0, angle + Math.PI / 2]))\n }\n return G(...parts)\n}\n","import type { ItemModelBuilder } from './registry'\n\n/**\n * Authored in the kit (no team model delivered); replace when the items team delivers one.\n */\nexport const safetyGoggles: ItemModelBuilder = ({ mesh, bx, cyl, G, plastic, glass, cloth }) => {\n const frame = plastic(0x2f4f6f)\n const lens = glass(0xcfe6f0, 0.45)\n const band = cloth(0x1f2326)\n const cup = (x: number) => [\n mesh(cyl(0.03, 0.03, 0.02, 10), frame, [x, 0.03, 0.027], [Math.PI / 2, 0, 0]),\n mesh(cyl(0.024, 0.024, 0.006, 10), lens, [x, 0.03, 0.037], [Math.PI / 2, 0, 0]),\n ]\n return G(\n ...cup(-0.04),\n ...cup(0.04),\n mesh(bx(0.03, 0.012, 0.02), frame, [0, 0.036, 0.027]),\n mesh(bx(0.006, 0.03, 0.05), band, [-0.077, 0.03, 0.0]),\n mesh(bx(0.006, 0.03, 0.05), band, [0.077, 0.03, 0.0]),\n mesh(bx(0.16, 0.03, 0.006), band, [0, 0.03, -0.037]),\n )\n}\n","import type { ItemModelBuilder } from './registry'\n\n/**\n * Authored in the kit (no team model delivered); replace when the items team delivers one.\n */\nexport const sheetMetalForearmGuard: ItemModelBuilder = ({ mesh, bx, G, metal, cloth }) => {\n const sheet = metal(0x7d8186)\n const strap = cloth(0x4a3a2a)\n const rivet = metal(0xb5b8bb)\n const parts = []\n const count = 7\n const radiusZ = 0.0555\n const radiusY = 0.092\n const phiMax = 1.3\n for (let index = 0; index < count; index++) {\n const phi = -phiMax + (2 * phiMax * index) / (count - 1)\n const y = 0.0455 + radiusY * (Math.cos(phi) - Math.cos(phiMax))\n const z = radiusZ * Math.sin(phi)\n const speed = Math.hypot(radiusY * Math.sin(phi), radiusZ * Math.cos(phi))\n const angle = Math.atan2(radiusY * Math.sin(phi), radiusZ * Math.cos(phi))\n const length = (speed * (2 * phiMax)) / (count - 1) * 1.1\n parts.push(mesh(bx(0.3, 0.006, length), sheet, [0, y, z], [angle, 0, 0]))\n for (const x of [-0.09, 0.09]) parts.push(mesh(bx(0.03, 0.006, length), strap, [x, y + 0.006, z], [angle, 0, 0]))\n }\n parts.push(mesh(bx(0.012, 0.012, 0.012), rivet, [0.09, 0.0985, 0]), mesh(bx(0.012, 0.012, 0.012), rivet, [-0.09, 0.0985, 0]))\n return G(...parts)\n}\n","import type { ItemModelBuilder } from './registry'\n\n/**\n * Authored in the kit (no team model delivered); replace when the items team delivers one.\n */\nexport const shoppingBag: ItemModelBuilder = ({ mesh, bx, G, cloth }) => {\n const body = cloth(0x4b6a5a)\n const trim = cloth(0x2f4a3c)\n return G(\n mesh(bx(0.3, 0.008, 0.2), body, [0, 0.004, 0]),\n mesh(bx(0.2, 0.008, 0.12), trim, [0, 0.012, 0]),\n mesh(bx(0.1, 0.004, 0.012), trim, [0, 0.018, -0.05]),\n mesh(bx(0.1, 0.004, 0.012), trim, [0, 0.018, 0.05]),\n )\n}\n","import type { ItemModelBuilder } from './registry'\n\n/**\n * Authored in the kit (no team model delivered); replace when the items team delivers one.\n */\nexport const shoppingCart: ItemModelBuilder = ({ mesh, cyl, bx, G, metal, plastic }) => {\n const wire = metal(0xb4b7ba)\n const grip = plastic(0x2a2c2e)\n const group = G()\n const add = (...parts: Parameters<typeof G>) => parts.forEach((part) => group.add(part))\n add(mesh(bx(0.5, 0.012, 0.8), wire, [0, 0.38, 0]), mesh(bx(0.55, 0.03, 0.03), grip, [0, 0.965, -0.46]))\n for (const side of [-1, 1]) {\n add(mesh(bx(0.012, 0.012, 0.8), wire, [side * 0.25, 0.75, 0]), mesh(bx(0.012, 0.012, 0.8), wire, [side * 0.25, 0.56, 0]))\n add(mesh(bx(0.012, 0.012, 0.95), wire, [side * 0.22, 0.14, 0]), mesh(bx(0.02, 0.62, 0.02), wire, [side * 0.26, 0.67, -0.46]))\n for (const z of [-0.4, 0.4]) add(mesh(bx(0.012, 0.37, 0.012), wire, [side * 0.25, 0.565, z]))\n add(mesh(bx(0.012, 0.25, 0.012), wire, [side * 0.22, 0.26, -0.3]), mesh(bx(0.012, 0.25, 0.012), wire, [side * 0.22, 0.26, 0.3]))\n for (const z of [-0.3, 0.4]) add(mesh(cyl(0.06, 0.06, 0.03, 8), grip, [side * 0.25, 0.06, z], [0, 0, Math.PI / 2]))\n }\n add(mesh(bx(0.5, 0.012, 0.012), wire, [0, 0.75, 0.4]), mesh(bx(0.5, 0.012, 0.012), wire, [0, 0.56, 0.4]))\n add(mesh(bx(0.5, 0.012, 0.012), wire, [0, 0.75, -0.4]), mesh(bx(0.5, 0.012, 0.012), wire, [0, 0.56, -0.4]))\n for (const x of [-0.125, 0.125]) add(mesh(bx(0.012, 0.012, 0.8), wire, [x, 0.38, 0]))\n add(mesh(bx(0.44, 0.012, 0.012), wire, [0, 0.14, -0.3]), mesh(bx(0.44, 0.012, 0.012), wire, [0, 0.14, 0.3]))\n return group\n}\n","import type { ItemModelBuilder } from './registry'\n\n/**\n * Authored in the kit (no team model delivered); replace when the items team delivers one.\n */\nexport const skillBook: ItemModelBuilder = ({ mesh, bx, G, paper, cloth }) => {\n const cover = cloth(0x6b3f26)\n const trim = paper(0xc9a45a)\n return G(\n mesh(bx(0.154, 0.224, 0.033), paper(0xe4dcc6), [0.0005, 0.115, 0]),\n mesh(bx(0.16, 0.23, 0.0034), cover, [0, 0.115, 0.0183]),\n mesh(bx(0.16, 0.23, 0.0034), cover, [0, 0.115, -0.0183]),\n mesh(bx(0.006, 0.23, 0.04), cover, [-0.077, 0.115, 0]),\n mesh(bx(0.008, 0.01, 0.04), trim, [-0.0775, 0.2, 0]),\n mesh(bx(0.008, 0.01, 0.04), trim, [-0.0775, 0.03, 0]),\n mesh(bx(0.09, 0.05, 0.0002), trim, [0.005, 0.17, 0.0201]),\n mesh(bx(0.06, 0.006, 0.0002), trim, [0.005, 0.06, 0.0201]),\n )\n}\n","import type { ItemModelBuilder } from './registry'\n\n/**\n * Authored in the kit (no team model delivered); replace when the items team delivers one.\n */\nexport const snareTrap: ItemModelBuilder = ({ mesh, torus, bx, G, metal, wood }) => {\n const group = G()\n group.add(mesh(torus(0.067, 0.008), metal(0x8d9096), [0, 0.015, 0], [Math.PI / 2, 0, 0]))\n group.add(mesh(bx(0.02, 0.03, 0.02), wood(0x7a5a3a), [0.065, 0.015, 0]))\n group.add(mesh(bx(0.02, 0.02, 0.02), metal(0x6c6f75), [0, 0.015, 0.065]))\n group.add(mesh(bx(0.006, 0.006, 0.03), wood(0xa08560), [0, 0.01, -0.06]))\n return group\n}\n","import type { ItemModelBuilder } from './registry'\n\n/**\n * Authored in the kit (no team model delivered); replace when the items team delivers one.\n */\nexport const sneakers: ItemModelBuilder = ({ mesh, bx, cyl, G, cloth, plastic }) => {\n const upper = cloth(0x5a6068)\n const sole = plastic(0xe8e8e4)\n const accent = cloth(0x2e6f78)\n const lace = cloth(0xf0f0ea)\n return G(\n mesh(bx(0.25, 0.022, 0.12), sole, [-0.025, 0.011, 0]),\n mesh(cyl(0.06, 0.06, 0.022, 10), sole, [0.09, 0.011, 0]),\n mesh(bx(0.11, 0.09, 0.11), upper, [-0.095, 0.067, 0]),\n mesh(bx(0.12, 0.05, 0.11), upper, [0.0, 0.047, 0]),\n mesh(cyl(0.055, 0.055, 0.042, 10), upper, [0.095, 0.043, 0]),\n mesh(bx(0.03, 0.05, 0.08), accent, [-0.03, 0.095, 0]),\n mesh(bx(0.1, 0.03, 0.004), accent, [-0.05, 0.05, 0.057]),\n mesh(bx(0.1, 0.03, 0.004), accent, [-0.05, 0.05, -0.057]),\n mesh(bx(0.008, 0.004, 0.09), lace, [0.0, 0.074, 0]),\n mesh(bx(0.008, 0.004, 0.09), lace, [0.03, 0.074, 0]),\n mesh(bx(0.008, 0.004, 0.08), lace, [0.06, 0.066, 0]),\n )\n}\n","import type { ItemModelBuilder } from './registry'\n\n/**\n * Authored in the kit (no team model delivered); replace when the items team delivers one.\n */\nexport const tacticalVest: ItemModelBuilder = ({ mesh, bx, G, cloth, plastic }) => {\n const shell = cloth(0x4a5236)\n const pouch = cloth(0x3b4229)\n const buckle = plastic(0x1e2020)\n return G(\n mesh(bx(0.35, 0.03, 0.28), shell, [0, 0.015, 0.06]),\n mesh(bx(0.09, 0.03, 0.12), shell, [-0.13, 0.015, -0.14]),\n mesh(bx(0.09, 0.03, 0.12), shell, [0.13, 0.015, -0.14]),\n mesh(bx(0.09, 0.07, 0.05), pouch, [-0.11, 0.065, 0.165]),\n mesh(bx(0.09, 0.07, 0.05), pouch, [0, 0.065, 0.165]),\n mesh(bx(0.09, 0.07, 0.05), pouch, [0.11, 0.065, 0.165]),\n mesh(bx(0.07, 0.05, 0.07), pouch, [-0.13, 0.055, 0.07]),\n mesh(bx(0.07, 0.05, 0.07), pouch, [0.13, 0.055, 0.07]),\n mesh(bx(0.03, 0.02, 0.02), buckle, [0, 0.04, 0.0]),\n )\n}\n","import type { ItemModelBuilder } from './registry'\n\n/**\n * Authored in the kit (no team model delivered); replace when the items team delivers one.\n */\nexport const technicalManual: ItemModelBuilder = ({ mesh, bx, G, paper, plastic }) => {\n const binder = plastic(0x2f3f52)\n const label = paper(0xe4dcc6)\n return G(\n mesh(bx(0.2, 0.292, 0.034), paper(0xe4dcc6), [0.004, 0.15, 0]),\n mesh(bx(0.21, 0.3, 0.003), binder, [0, 0.15, 0.0185]),\n mesh(bx(0.21, 0.3, 0.003), binder, [0, 0.15, -0.0185]),\n mesh(bx(0.012, 0.3, 0.04), binder, [-0.099, 0.15, 0]),\n mesh(bx(0.006, 0.18, 0.0004), label, [-0.0995, 0.15, 0.0202]),\n mesh(bx(0.12, 0.05, 0.0004), label, [0.01, 0.23, 0.0202]),\n mesh(bx(0.12, 0.004, 0.0004), plastic(0xb4b7ba), [0.01, 0.17, 0.0202]),\n )\n}\n","import type { ItemModelBuilder } from './registry'\n\n/**\n * Authored in the kit (no team model delivered); replace when the items team delivers one.\n */\nexport const toolBelt: ItemModelBuilder = ({ mesh, bx, G, cloth, metal }) => {\n const leather = cloth(0x6b4a2f)\n const pouch = cloth(0x4f3822)\n return G(\n mesh(bx(0.35, 0.04, 0.02), leather, [0, 0.05, 0.115]),\n mesh(bx(0.35, 0.04, 0.02), leather, [0, 0.05, -0.115]),\n mesh(bx(0.02, 0.04, 0.25), leather, [-0.165, 0.05, 0]),\n mesh(bx(0.02, 0.04, 0.25), leather, [0.165, 0.05, 0]),\n mesh(bx(0.08, 0.1, 0.04), pouch, [-0.1, 0.05, 0.105]),\n mesh(bx(0.08, 0.08, 0.04), pouch, [0.1, 0.04, 0.105]),\n mesh(bx(0.04, 0.09, 0.08), pouch, [-0.155, 0.045, -0.02]),\n mesh(bx(0.02, 0.08, 0.02), pouch, [0.145, 0.04, -0.09]),\n mesh(bx(0.04, 0.035, 0.012), metal(0xb0b2b5), [0, 0.05, 0.119]),\n )\n}\n","import type { ItemModelBuilder } from './registry'\n\n/**\n * Authored in the kit (no team model delivered); replace when the items team delivers one.\n */\nexport const trashBag: ItemModelBuilder = ({ mesh, bx, G, plastic }) => {\n const film = plastic(0x1c1d1f)\n return G(\n mesh(bx(0.2, 0.02, 0.2), film, [-0.025, 0.01, 0]),\n mesh(bx(0.2, 0.005, 0.02), film, [-0.025, 0.0225, 0]),\n mesh(bx(0.05, 0.012, 0.08), film, [0.1, 0.006, 0]),\n mesh(bx(0.03, 0.025, 0.04), film, [0.11, 0.0125, 0]),\n )\n}\n","import type { ItemModelBuilder } from './registry'\n\n/**\n * Authored in the kit (no team model delivered); replace when the items team delivers one.\n */\nexport const trekkingBackpack70L: ItemModelBuilder = ({ mesh, bx, G, cloth, plastic }) => {\n const main = cloth(0x5d5640)\n const dark = cloth(0x2f2b22)\n return G(\n mesh(bx(0.34, 0.2, 0.2), dark, [0, 0.1, -0.03]),\n mesh(bx(0.36, 0.49, 0.2), main, [0, 0.445, -0.03]),\n mesh(bx(0.38, 0.06, 0.26), dark, [0, 0.72, -0.02]),\n mesh(bx(0.28, 0.3, 0.08), main, [0, 0.35, 0.11]),\n mesh(bx(0.06, 0.45, 0.02), dark, [-0.1, 0.45, -0.14]),\n mesh(bx(0.06, 0.45, 0.02), dark, [0.1, 0.45, -0.14]),\n mesh(bx(0.38, 0.03, 0.02), dark, [0, 0.3, 0.14]),\n mesh(bx(0.05, 0.03, 0.02), plastic(0x1c1d1f), [0, 0.3, 0.14]),\n )\n}\n","import type { ItemModelBuilder } from './registry'\n\n/**\n * Authored in the kit (no team model delivered); replace when the items team delivers one.\n */\nexport const tshirt: ItemModelBuilder = ({ mesh, bx, G, cloth }) => {\n const fabric = cloth(0x8a8f94)\n const rib = cloth(0x6f7378)\n const inside = cloth(0x2b2d30)\n return G(\n mesh(bx(0.21, 0.0392, 0.22), fabric, [0, 0.0196, 0]),\n mesh(bx(0.045, 0.03, 0.08), fabric, [-0.1275, 0.015, -0.07]),\n mesh(bx(0.045, 0.03, 0.08), fabric, [0.1275, 0.015, -0.07]),\n mesh(bx(0.045, 0.034, 0.012), rib, [-0.1275, 0.017, -0.024]),\n mesh(bx(0.045, 0.034, 0.012), rib, [0.1275, 0.017, -0.024]),\n mesh(bx(0.07, 0.04, 0.024), inside, [0, 0.02, -0.098]),\n mesh(bx(0.09, 0.0394, 0.012), rib, [0, 0.0197, -0.1]),\n )\n}\n","import type { ItemModelBuilder } from './registry'\n\n/**\n * Authored in the kit (no team model delivered); replace when the items team delivers one.\n */\nexport const wateringCan: ItemModelBuilder = ({ mesh, cyl, bx, G, metal }) => {\n const zinc = metal(0x7f8b8f)\n const group = G()\n group.add(mesh(cyl(0.09, 0.09, 0.2, 16), zinc, [-0.06, 0.1, 0]))\n group.add(mesh(cyl(0.07, 0.07, 0.004, 16), metal(0x4b5256), [-0.06, 0.2, 0]))\n group.add(mesh(cyl(0.012, 0.02, 0.22, 8), zinc, [0.1194, 0.115, 0], [0, 0, -0.85]))\n group.add(mesh(cyl(0.035, 0.022, 0.02, 12), zinc, [0.2094, 0.225, 0], [0, 0, -0.85]))\n group.add(mesh(bx(0.01, 0.16, 0.02), zinc, [-0.155, 0.12, 0]))\n group.add(mesh(bx(0.05, 0.01, 0.02), zinc, [-0.135, 0.2, 0]))\n group.add(mesh(bx(0.05, 0.01, 0.02), zinc, [-0.135, 0.04, 0]))\n return group\n}\n","import type { ItemModelBuilder } from './registry'\n\n/**\n * Authored in the kit (no team model delivered); replace when the items team delivers one.\n */\nexport const wheelbarrow: ItemModelBuilder = ({ mesh, cyl, bx, G, metal, plastic }) => {\n const tub = metal(0x2f5d3a)\n const frame = metal(0x3a3d40)\n const tire = plastic(0x1d1e20)\n const tilt = 0.42\n return G(\n mesh(bx(0.4, 0.02, 0.5), tub, [0, 0.38, 0.2]),\n mesh(bx(0.02, 0.29, 0.62), tub, [-0.255, 0.515, 0.2], [0, 0, tilt]),\n mesh(bx(0.02, 0.29, 0.62), tub, [0.255, 0.515, 0.2], [0, 0, -tilt]),\n mesh(bx(0.5, 0.29, 0.02), tub, [0, 0.515, 0.5], [0.5, 0, 0]),\n mesh(bx(0.5, 0.29, 0.02), tub, [0, 0.515, -0.1], [-0.5, 0, 0]),\n mesh(bx(0.03, 0.03, 1.3), frame, [-0.2, 0.33, -0.1]),\n mesh(bx(0.03, 0.03, 1.3), frame, [0.2, 0.33, -0.1]),\n mesh(cyl(0.02, 0.02, 0.3, 6), plastic(0x6b4a2f), [-0.2, 0.33, -0.6], [Math.PI / 2, 0, 0]),\n mesh(cyl(0.02, 0.02, 0.3, 6), plastic(0x6b4a2f), [0.2, 0.33, -0.6], [Math.PI / 2, 0, 0]),\n mesh(bx(0.03, 0.31, 0.03), frame, [-0.2, 0.155, -0.35]),\n mesh(bx(0.03, 0.31, 0.03), frame, [0.2, 0.155, -0.35]),\n mesh(bx(0.02, 0.15, 0.02), frame, [-0.05, 0.27, 0.55]),\n mesh(bx(0.02, 0.15, 0.02), frame, [0.05, 0.27, 0.55]),\n mesh(cyl(0.2, 0.2, 0.06, 12), tire, [0, 0.2, 0.55], [0, 0, Math.PI / 2]),\n )\n}\n","import type { ItemModelBuilder } from './registry'\n\n/**\n * Authored in the kit (no team model delivered); replace when the items team delivers one.\n */\nexport const windupAlarmClock: ItemModelBuilder = ({ M, mesh, cyl, bx, G, metal, plastic }) => {\n const steel = metal(0xa7a9ab)\n const bell = metal(0x7e8083)\n const quarter = Math.PI / 2\n return G(\n mesh(cyl(0.0475, 0.0475, 0.048, 18), steel, [0, 0.0575, 0], [quarter, 0, 0]),\n mesh(cyl(0.04, 0.04, 0.002, 18), plastic(0xe8e2cf), [0, 0.0575, 0.025], [quarter, 0, 0]),\n mesh(bx(0.003, 0.026, 0.0015), plastic(0x1c1c1c), [0, 0.07, 0.0255]),\n mesh(bx(0.003, 0.018, 0.0015), plastic(0x1c1c1c), [0.008, 0.0575, 0.0255], [0, 0, -quarter]),\n mesh(cyl(0.005, 0.008, 0.014, 6), steel, [-0.03, 0.007, 0]),\n mesh(cyl(0.005, 0.008, 0.014, 6), steel, [0.03, 0.007, 0]),\n mesh(cyl(0.008, 0.0215, 0.016, 10), bell, [-0.034, 0.105, 0]),\n mesh(cyl(0.008, 0.0215, 0.016, 10), bell, [0.034, 0.105, 0]),\n mesh(cyl(0.002, 0.002, 0.01, 6), steel, [-0.026, 0.118, 0]),\n mesh(cyl(0.002, 0.002, 0.01, 6), steel, [0.026, 0.118, 0]),\n mesh(bx(0.052, 0.004, 0.004), steel, [0, 0.123, 0]),\n mesh(cyl(0.003, 0.003, 0.007, 6), steel, [0, 0.0575, -0.0255], [quarter, 0, 0]),\n mesh(bx(0.022, 0.008, 0.003), M(0xa7a9ab, 'metal', { metalness: 0.55, roughness: 0.45 }), [0, 0.0575, -0.0275]),\n )\n}\n","import data from '../data/models.json'\n\nimport { cannedBeans } from './canned-beans'\nimport { waterBottle } from './water-bottle'\nimport { rice } from './rice'\nimport { militaryRation } from './military-ration'\nimport { cachaca } from './cachaca'\nimport { firstAidKit } from './first-aid-kit'\nimport { bandage } from './bandage'\nimport { amoxicillin } from './amoxicillin'\nimport { crowbar } from './crowbar'\nimport { hammer } from './hammer'\nimport { machete } from './machete'\nimport { axe } from './axe'\nimport { nailBat } from './nail-bat'\nimport { hikingBackpack40L } from './hiking-backpack-40l'\nimport { flashlight } from './flashlight'\nimport { portableRadio } from './portable-radio'\nimport { houseKey } from './house-key'\nimport { survivorDiary } from './survivor-diary'\nimport { motorcycleHelmet } from './motorcycle-helmet'\nimport { lpgCylinder13Kg } from './lpg-cylinder-13kg'\nimport { fuelJerrycan } from './fuel-jerrycan'\nimport { walkieTalkies } from './walkie-talkies'\nimport { batteries } from './batteries'\nimport { woodenPlank } from './wooden-plank'\nimport { sugar } from './sugar'\nimport { chocolateBar } from './chocolate-bar'\nimport { potatoes } from './potatoes'\nimport { biscuits } from './biscuits'\nimport { coffee } from './coffee'\nimport { rawBeef } from './raw-beef'\nimport { gameMeat } from './game-meat'\nimport { jerkedBeef } from './jerked-beef'\nimport { homePreserves } from './home-preserves'\nimport { eggs } from './eggs'\nimport { cassavaFlour } from './cassava-flour'\nimport { beans } from './beans'\nimport { frozenChicken } from './frozen-chicken'\nimport { orange } from './orange'\nimport { condensedMilk } from './condensed-milk'\nimport { pasta } from './pasta'\nimport { instantNoodles } from './instant-noodles'\nimport { cassavaRoot } from './cassava-root'\nimport { cannedCornAndPeas } from './canned-corn-and-peas'\nimport { mortadella } from './mortadella'\nimport { freshFish } from './fresh-fish'\nimport { saltedFish } from './salted-fish'\nimport { bananaBunch } from './banana-bunch'\nimport { honeyJar } from './honey-jar'\nimport { bread } from './bread'\nimport { cheese } from './cheese'\nimport { rapadura } from './rapadura'\nimport { dogFood } from './dog-food'\nimport { salt } from './salt'\nimport { snackChips } from './snack-chips'\nimport { cannedSausages } from './canned-sausages'\nimport { cannedSardines } from './canned-sardines'\nimport { cookingOil } from './cooking-oil'\nimport { beerCan } from './beer-can'\nimport { energyDrink } from './energy-drink'\nimport { waterJug5l } from './water-jug-5l'\nimport { sportsDrink } from './sports-drink'\nimport { milkCarton } from './milk-carton'\nimport { sodaCan } from './soda-can'\nimport { juiceBox } from './juice-box'\nimport { communionWine } from './communion-wine'\nimport { coconutWater } from './coconut-water'\nimport { dirtyWater } from './dirty-water'\nimport { painkillers } from './painkillers'\nimport { tramadol } from './tramadol'\nimport { ibuprofen } from './ibuprofen'\nimport { antihistamine } from './antihistamine'\nimport { ceftriaxone } from './ceftriaxone'\nimport { clonazepam } from './clonazepam'\nimport { activatedCharcoal } from './activated-charcoal'\nimport { adhesiveBandages } from './adhesive-bandages'\nimport { medicalTape } from './medical-tape'\nimport { sterileGauze } from './sterile-gauze'\nimport { povidoneIodine } from './povidone-iodine'\nimport { sutureKit } from './suture-kit'\nimport { examGloves } from './exam-gloves'\nimport { n95Mask } from './n95-mask'\nimport { multivitamin } from './multivitamin'\nimport { maintenanceMedication } from './maintenance-medication'\nimport { rehydrationSalts } from './rehydration-salts'\nimport { syringe } from './syringe'\nimport { antivenom } from './antivenom'\nimport { salineIvBag } from './saline-iv-bag'\nimport { splint } from './splint'\nimport { thermometer } from './thermometer'\nimport { alcohol70 } from './alcohol-70'\nimport { canOpener } from './can-opener'\nimport { pliers } from './pliers'\nimport { boltCutters } from './bolt-cutters'\nimport { bucket } from './bucket'\nimport { binoculars } from './binoculars'\nimport { matches } from './matches'\nimport { pocketKnife } from './pocket-knife'\nimport { screwdriver } from './screwdriver'\nimport { adjustableWrench } from './adjustable-wrench'\nimport { hoe } from './hoe'\nimport { fireExtinguisher } from './fire-extinguisher'\nimport { ductTape } from './duct-tape'\nimport { campStove } from './camp-stove'\nimport { lighter } from './lighter'\nimport { lockpickKit } from './lockpick-kit'\nimport { sewingKit } from './sewing-kit'\nimport { carJack } from './car-jack'\nimport { mechanicToolbox } from './mechanic-toolbox'\nimport { gasTorch } from './gas-torch'\nimport { inverterWelder } from './inverter-welder'\nimport { pot } from './pot'\nimport { cordlessDrill } from './cordless-drill'\nimport { flintStriker } from './flint-striker'\nimport { sharpeningStone } from './sharpening-stone'\nimport { shovel } from './shovel'\nimport { hacksaw } from './hacksaw'\nimport { handsaw } from './handsaw'\nimport { scissors } from './scissors'\nimport { recurveBow } from './recurve-bow'\nimport { crossbow } from './crossbow'\nimport { ironPipe } from './iron-pipe'\nimport { meatCleaver } from './meat-cleaver'\nimport { slingshot } from './slingshot'\nimport { knife } from './knife'\nimport { tacticalKnife } from './tactical-knife'\nimport { arrowsAndBolts } from './arrows-and-bolts'\nimport { sickle } from './sickle'\nimport { castIronSkillet } from './cast-iron-skillet'\nimport { improvisedSpear } from './improvised-spear'\nimport { hatchet } from './hatchet'\nimport { sledgehammer } from './sledgehammer'\nimport { chainsaw } from './chainsaw'\nimport { pickaxe } from './pickaxe'\nimport { baseballBat } from './baseball-bat'\nimport { policeBaton } from './police-baton'\nimport { wireRoll } from './wire-roll'\nimport { barbedWire } from './barbed-wire'\nimport { glassShards } from './glass-shards'\nimport { sheetMetal } from './sheet-metal'\nimport { cementBag } from './cement-bag'\nimport { epoxyGlue } from './epoxy-glue'\nimport { electronicComponents } from './electronic-components'\nimport { rope } from './rope'\nimport { copperWire } from './copper-wire'\nimport { petBottle } from './pet-bottle'\nimport { glassBottle } from './glass-bottle'\nimport { emptyCan } from './empty-can'\nimport { firewood } from './firewood'\nimport { tarp } from './tarp'\nimport { screws } from './screws'\nimport { nails } from './nails'\nimport { raffiaSack } from './raffia-sack'\nimport { scrapMetal } from './scrap-metal'\nimport { bricks } from './bricks'\nimport { rag } from './rag'\nimport { rebar } from './rebar'\nimport { lubricantSpray } from './lubricant-spray'\nimport { armyCamouflageUniform } from './army-camouflage-uniform'\nimport { backpack } from './backpack'\nimport { ballisticVest } from './ballistic-vest'\nimport { battery9V } from './battery-9v'\nimport { beanSeeds } from './bean-seeds'\nimport { beekeeperSuit } from './beekeeper-suit'\nimport { candles } from './candles'\nimport { carAlarmRemote } from './car-alarm-remote'\nimport { carBattery12V } from './car-battery-12v'\nimport { carKey } from './car-key'\nimport { cash } from './cash'\nimport { cassavaCuttings } from './cassava-cuttings'\nimport { cbRadio } from './cb-radio'\nimport { cellKey } from './cell-key'\nimport { charcoalBag } from './charcoal-bag'\nimport { cigarettes } from './cigarettes'\nimport { cityMap } from './city-map'\nimport { combatBoots } from './combat-boots'\nimport { coolerBox } from './cooler-box'\nimport { cornSeeds } from './corn-seeds'\nimport { crossbodyBag } from './crossbody-bag'\nimport { deliveryBag } from './delivery-bag'\nimport { denimJacket } from './denim-jacket'\nimport { diesel } from './diesel'\nimport { diyMagazine } from './diy-magazine'\nimport { dogTag } from './dog-tag'\nimport { electricFenceEnergizer } from './electric-fence-energizer'\nimport { extensionCord } from './extension-cord'\nimport { fannyPack } from './fanny-pack'\nimport { farmersAlmanac } from './farmers-almanac'\nimport { fertilizerBag } from './fertilizer-bag'\nimport { firefighterSuit } from './firefighter-suit'\nimport { fishingNet } from './fishing-net'\nimport { fishingRod } from './fishing-rod'\nimport { fishingTackleBox } from './fishing-tackle-box'\nimport { flipFlops } from './flip-flops'\nimport { foldingSolarPanel } from './folding-solar-panel'\nimport { gasCartridge } from './gas-cartridge'\nimport { gasoline } from './gasoline'\nimport { generatorKey } from './generator-key'\nimport { hardHat } from './hard-hat'\nimport { headlamp } from './headlamp'\nimport { hoodie } from './hoodie'\nimport { janitorKeys } from './janitor-keys'\nimport { jeans } from './jeans'\nimport { kaleAndLettuceSeeds } from './kale-and-lettuce-seeds'\nimport { kerosene } from './kerosene'\nimport { laptop } from './laptop'\nimport { leatherMotorcycleJacket } from './leather-motorcycle-jacket'\nimport { leatherMotorcyclePants } from './leather-motorcycle-pants'\nimport { leatherWorkGloves } from './leather-work-gloves'\nimport { ledCampLantern } from './led-camp-lantern'\nimport { magazineArmGuard } from './magazine-arm-guard'\nimport { magazinesAndComics } from './magazines-and-comics'\nimport { masterKey } from './master-key'\nimport { mechanicCoveralls } from './mechanic-coveralls'\nimport { militaryBackpack } from './military-backpack'\nimport { militaryRadio } from './military-radio'\nimport { mobilePhone } from './mobile-phone'\nimport { motorOil } from './motor-oil'\nimport { nightVisionGoggles } from './night-vision-goggles'\nimport { note } from './note'\nimport { paddedCoat } from './padded-coat'\nimport { padlockKey } from './padlock-key'\nimport { photo } from './photo'\nimport { portableGenerator } from './portable-generator'\nimport { powerBank } from './power-bank'\nimport { pumpkinSeeds } from './pumpkin-seeds'\nimport { raincoat } from './raincoat'\nimport { roadMap } from './road-map'\nimport { rollingSuitcase } from './rolling-suitcase'\nimport { rubberBoots } from './rubber-boots'\nimport { safeKey } from './safe-key'\nimport { safetyGoggles } from './safety-goggles'\nimport { sheetMetalForearmGuard } from './sheet-metal-forearm-guard'\nimport { shoppingBag } from './shopping-bag'\nimport { shoppingCart } from './shopping-cart'\nimport { skillBook } from './skill-book'\nimport { snareTrap } from './snare-trap'\nimport { sneakers } from './sneakers'\nimport { tacticalVest } from './tactical-vest'\nimport { technicalManual } from './technical-manual'\nimport { toolBelt } from './tool-belt'\nimport { trashBag } from './trash-bag'\nimport { trekkingBackpack70L } from './trekking-backpack-70l'\nimport { tshirt } from './tshirt'\nimport { wateringCan } from './watering-can'\nimport { wheelbarrow } from './wheelbarrow'\nimport { windupAlarmClock } from './windup-alarm-clock'\nimport type { ItemModelBuilder, ItemModelEntry } from './registry'\n\n/** The builder of each model of the showcase, by catalog id. */\nconst BUILDERS: Readonly<Record<string, ItemModelBuilder>> = {\n canned_beans: cannedBeans,\n water_bottle: waterBottle,\n rice: rice,\n military_ration: militaryRation,\n cachaca: cachaca,\n first_aid_kit: firstAidKit,\n bandage: bandage,\n amoxicillin: amoxicillin,\n crowbar: crowbar,\n hammer: hammer,\n machete: machete,\n axe: axe,\n nail_bat: nailBat,\n hiking_backpack_40l: hikingBackpack40L,\n flashlight: flashlight,\n portable_radio: portableRadio,\n house_key: houseKey,\n survivor_diary: survivorDiary,\n motorcycle_helmet: motorcycleHelmet,\n lpg_cylinder_13kg: lpgCylinder13Kg,\n fuel_jerrycan: fuelJerrycan,\n walkie_talkies: walkieTalkies,\n batteries: batteries,\n wooden_plank: woodenPlank,\n sugar: sugar,\n chocolate_bar: chocolateBar,\n potatoes: potatoes,\n biscuits: biscuits,\n coffee: coffee,\n raw_beef: rawBeef,\n game_meat: gameMeat,\n jerked_beef: jerkedBeef,\n home_preserves: homePreserves,\n eggs: eggs,\n cassava_flour: cassavaFlour,\n beans: beans,\n frozen_chicken: frozenChicken,\n orange: orange,\n condensed_milk: condensedMilk,\n pasta: pasta,\n instant_noodles: instantNoodles,\n cassava_root: cassavaRoot,\n canned_corn_and_peas: cannedCornAndPeas,\n mortadella: mortadella,\n fresh_fish: freshFish,\n salted_fish: saltedFish,\n banana_bunch: bananaBunch,\n honey_jar: honeyJar,\n bread: bread,\n cheese: cheese,\n rapadura: rapadura,\n dog_food: dogFood,\n salt: salt,\n snack_chips: snackChips,\n canned_sausages: cannedSausages,\n canned_sardines: cannedSardines,\n cooking_oil: cookingOil,\n beer_can: beerCan,\n energy_drink: energyDrink,\n water_jug_5l: waterJug5l,\n sports_drink: sportsDrink,\n milk_carton: milkCarton,\n soda_can: sodaCan,\n juice_box: juiceBox,\n communion_wine: communionWine,\n coconut_water: coconutWater,\n dirty_water: dirtyWater,\n painkillers: painkillers,\n tramadol: tramadol,\n ibuprofen: ibuprofen,\n antihistamine: antihistamine,\n ceftriaxone: ceftriaxone,\n clonazepam: clonazepam,\n activated_charcoal: activatedCharcoal,\n adhesive_bandages: adhesiveBandages,\n medical_tape: medicalTape,\n sterile_gauze: sterileGauze,\n povidone_iodine: povidoneIodine,\n suture_kit: sutureKit,\n exam_gloves: examGloves,\n n95_mask: n95Mask,\n multivitamin: multivitamin,\n maintenance_medication: maintenanceMedication,\n rehydration_salts: rehydrationSalts,\n syringe: syringe,\n antivenom: antivenom,\n saline_iv_bag: salineIvBag,\n splint: splint,\n thermometer: thermometer,\n alcohol_70: alcohol70,\n can_opener: canOpener,\n pliers: pliers,\n bolt_cutters: boltCutters,\n bucket: bucket,\n binoculars: binoculars,\n matches: matches,\n pocket_knife: pocketKnife,\n screwdriver: screwdriver,\n adjustable_wrench: adjustableWrench,\n hoe: hoe,\n fire_extinguisher: fireExtinguisher,\n duct_tape: ductTape,\n camp_stove: campStove,\n lighter: lighter,\n lockpick_kit: lockpickKit,\n sewing_kit: sewingKit,\n car_jack: carJack,\n mechanic_toolbox: mechanicToolbox,\n gas_torch: gasTorch,\n inverter_welder: inverterWelder,\n pot: pot,\n cordless_drill: cordlessDrill,\n flint_striker: flintStriker,\n sharpening_stone: sharpeningStone,\n shovel: shovel,\n hacksaw: hacksaw,\n handsaw: handsaw,\n scissors: scissors,\n recurve_bow: recurveBow,\n crossbow: crossbow,\n iron_pipe: ironPipe,\n meat_cleaver: meatCleaver,\n slingshot: slingshot,\n knife: knife,\n tactical_knife: tacticalKnife,\n arrows_and_bolts: arrowsAndBolts,\n sickle: sickle,\n cast_iron_skillet: castIronSkillet,\n improvised_spear: improvisedSpear,\n hatchet: hatchet,\n sledgehammer: sledgehammer,\n chainsaw: chainsaw,\n pickaxe: pickaxe,\n baseball_bat: baseballBat,\n police_baton: policeBaton,\n wire_roll: wireRoll,\n barbed_wire: barbedWire,\n glass_shards: glassShards,\n sheet_metal: sheetMetal,\n cement_bag: cementBag,\n epoxy_glue: epoxyGlue,\n electronic_components: electronicComponents,\n rope: rope,\n copper_wire: copperWire,\n pet_bottle: petBottle,\n glass_bottle: glassBottle,\n empty_can: emptyCan,\n firewood: firewood,\n tarp: tarp,\n screws: screws,\n nails: nails,\n raffia_sack: raffiaSack,\n scrap_metal: scrapMetal,\n bricks: bricks,\n rag: rag,\n rebar: rebar,\n lubricant_spray: lubricantSpray,\n army_camouflage_uniform: armyCamouflageUniform,\n backpack: backpack,\n ballistic_vest: ballisticVest,\n battery_9v: battery9V,\n bean_seeds: beanSeeds,\n beekeeper_suit: beekeeperSuit,\n candles: candles,\n car_alarm_remote: carAlarmRemote,\n car_battery_12v: carBattery12V,\n car_key: carKey,\n cash: cash,\n cassava_cuttings: cassavaCuttings,\n cb_radio: cbRadio,\n cell_key: cellKey,\n charcoal_bag: charcoalBag,\n cigarettes: cigarettes,\n city_map: cityMap,\n combat_boots: combatBoots,\n cooler_box: coolerBox,\n corn_seeds: cornSeeds,\n crossbody_bag: crossbodyBag,\n delivery_bag: deliveryBag,\n denim_jacket: denimJacket,\n diesel: diesel,\n diy_magazine: diyMagazine,\n dog_tag: dogTag,\n electric_fence_energizer: electricFenceEnergizer,\n extension_cord: extensionCord,\n fanny_pack: fannyPack,\n farmers_almanac: farmersAlmanac,\n fertilizer_bag: fertilizerBag,\n firefighter_suit: firefighterSuit,\n fishing_net: fishingNet,\n fishing_rod: fishingRod,\n fishing_tackle_box: fishingTackleBox,\n flip_flops: flipFlops,\n folding_solar_panel: foldingSolarPanel,\n gas_cartridge: gasCartridge,\n gasoline: gasoline,\n generator_key: generatorKey,\n hard_hat: hardHat,\n headlamp: headlamp,\n hoodie: hoodie,\n janitor_keys: janitorKeys,\n jeans: jeans,\n kale_and_lettuce_seeds: kaleAndLettuceSeeds,\n kerosene: kerosene,\n laptop: laptop,\n leather_motorcycle_jacket: leatherMotorcycleJacket,\n leather_motorcycle_pants: leatherMotorcyclePants,\n leather_work_gloves: leatherWorkGloves,\n led_camp_lantern: ledCampLantern,\n magazine_arm_guard: magazineArmGuard,\n magazines_and_comics: magazinesAndComics,\n master_key: masterKey,\n mechanic_coveralls: mechanicCoveralls,\n military_backpack: militaryBackpack,\n military_radio: militaryRadio,\n mobile_phone: mobilePhone,\n motor_oil: motorOil,\n night_vision_goggles: nightVisionGoggles,\n note: note,\n padded_coat: paddedCoat,\n padlock_key: padlockKey,\n photo: photo,\n portable_generator: portableGenerator,\n power_bank: powerBank,\n pumpkin_seeds: pumpkinSeeds,\n raincoat: raincoat,\n road_map: roadMap,\n rolling_suitcase: rollingSuitcase,\n rubber_boots: rubberBoots,\n safe_key: safeKey,\n safety_goggles: safetyGoggles,\n sheet_metal_forearm_guard: sheetMetalForearmGuard,\n shopping_bag: shoppingBag,\n shopping_cart: shoppingCart,\n skill_book: skillBook,\n snare_trap: snareTrap,\n sneakers: sneakers,\n tactical_vest: tacticalVest,\n technical_manual: technicalManual,\n tool_belt: toolBelt,\n trash_bag: trashBag,\n trekking_backpack_70l: trekkingBackpack70L,\n tshirt: tshirt,\n watering_can: wateringCan,\n wheelbarrow: wheelbarrow,\n windup_alarm_clock: windupAlarmClock,\n}\n\n/** The 24 models of the showcase in the page's order: the entry of `data/models.json` (generated by `tools/items-catalog`) and the builder ported from the page. */\nexport const SHIPPED_MODELS: ReadonlyArray<{ readonly entry: ItemModelEntry; readonly builder: ItemModelBuilder }> = (data as unknown as ItemModelEntry[]).map((entry) => {\n const builder = BUILDERS[entry.id]\n if (!builder) throw new Error(`game-items-three: no builder for the model \"${entry.id}\"`)\n return { entry, builder }\n})\n","import type * as THREE_NS from 'three'\n\nimport type { ItemKit } from '../kit'\nimport { SHIPPED_MODELS } from './shipped'\n\n/** One model of the showcase as `data/models.json` keeps it: the item it draws, the id the team gave it, the box it has in the units of the page and the scale to metres. */\nexport interface ItemModelEntry {\n /** Catalog id of the item (`canned_beans`). */\n readonly id: string\n /** The id in the team's `MODELS` (`feijao_lata`). */\n readonly teamId: string\n /** Box of the builder's group in the page's units (`Box3.setFromObject`), x y z. */\n readonly teamBox: readonly [number, number, number]\n /** Metres per unit of the page, from one real measure of the object. */\n readonly scale: number\n}\n\n/** A builder of the showcase, ported as it is: it draws in the page's units and returns the group. */\nexport type ItemModelBuilder = (kit: ItemKit) => THREE_NS.Group\n\nconst entries = new Map<string, ItemModelEntry>(SHIPPED_MODELS.map(({ entry }) => [entry.id, entry]))\nconst builders = new Map<string, ItemModelBuilder>(SHIPPED_MODELS.map(({ entry, builder }) => [entry.id, builder]))\n\n/** Adds (or replaces) the model of an item: `entry.id` is the catalog id the item's `model` field names. */\nexport function registerItemModel(entry: ItemModelEntry, builder: ItemModelBuilder): void {\n entries.set(entry.id, entry)\n builders.set(entry.id, builder)\n}\n\n/** Takes a model out (a game that wants the simple shape instead). */\nexport function unregisterItemModel(id: string): void {\n entries.delete(id)\n builders.delete(id)\n}\n\nexport const itemModelEntry = (id: string): ItemModelEntry | undefined => entries.get(id)\nexport const itemModelBuilder = (id: string): ItemModelBuilder | undefined => builders.get(id)\nexport const hasItemModel = (id: string): boolean => builders.has(id)\n/** The ids of the models registered, in the order of registration (the order of the showcase for the ones the kit ships). */\nexport const listItemModels = (): string[] => [...entries.keys()]\n","import type * as THREE_NS from 'three'\n\nimport { tagForDestruction } from './destruction'\nimport { createItemKit } from './kit'\nimport type { ItemKit, Vec3Tuple } from './kit'\nimport { itemModelBuilder, itemModelEntry } from './models/registry'\nimport { drawShape, shapeOf } from './shapes'\nimport type { ShapeId, ShapeSubject } from './shapes'\nimport { setWear } from './wear'\nimport type { WearStage } from './wear'\n\n/** The fields of an item the drawing reads (an `ItemDef` of `game-items` has them all). */\nexport interface DrawableItem extends ShapeSubject {\n id: string\n size: Vec3Tuple\n /** Key of a showcase model; without one (or when the model is not registered) the simple shape is drawn. */\n model?: string\n /** Real weight in kg; with `destructible` it becomes the mass of the destruction body. */\n weight?: number\n}\n\nexport interface BuildItemOptions {\n /** Wear of the materials, 0 new (default), 1 used, 2 spoiled. */\n wear?: WearStage\n /** Draw the simple shape even when the item has a model (the second level of detail). */\n simple?: boolean\n /** Level of detail of the simple shape, 1 (default) or 0.5 for half the segments. */\n detail?: number\n /** Write the `userData` that `game-destruction-three`'s `specFromObject3D` reads (material of each mesh, hollow shells, welded parts, skins; see `tagForDestruction`). Default off. */\n destructible?: boolean\n /** A kit to draw with (and to collect the materials in); default a new one. */\n kit?: ItemKit\n}\n\n/** What `buildItem` returns. */\nexport interface ItemModel {\n /** The object to add to a scene: origin at the bottom centre of the item, y up, in metres. */\n readonly root: THREE_NS.Group\n /** `model` when the showcase builder drew it, `shape` otherwise. */\n readonly kind: 'model' | 'shape'\n readonly shape?: ShapeId\n /** Size in metres the drawing was fitted to (the item's `size`). */\n readonly size: Vec3Tuple\n /** The materials made for this item. */\n readonly materials: readonly THREE_NS.MeshStandardMaterial[]\n}\n\n/** Moves a group so that its box has the centre of its base at the origin. */\nfunction restOnBase(T: typeof THREE_NS, inner: THREE_NS.Object3D): void {\n const box = new T.Box3().setFromObject(inner)\n const centre = box.getCenter(new T.Vector3())\n inner.position.set(-centre.x, -box.min.y, -centre.z)\n}\n\n/**\n * Draws an item at its real size. An item whose `model` is registered gets the showcase builder, ported as it is (page units, scaled to metres by the scale of\n * `models.json` on the root, so that the group inside is still the team's); every other item gets the simple shape of its `shape` hint (refined by category and\n * proportions) at its `size`. Either way the origin is the bottom centre and y is up.\n */\nexport function buildItem(T: typeof THREE_NS, item: DrawableItem, options: BuildItemOptions = {}): ItemModel {\n const kit = options.kit ?? createItemKit(T)\n const first = kit.materials.length\n const root = new T.Group()\n root.name = item.id\n const entry = item.model === undefined ? undefined : itemModelEntry(item.model)\n const builder = item.model === undefined ? undefined : itemModelBuilder(item.model)\n let kind: ItemModel['kind'] = 'shape'\n let shape: ShapeId | undefined\n if (entry && builder && !options.simple) {\n kind = 'model'\n const inner = builder(kit)\n inner.name = entry.teamId\n root.scale.setScalar(entry.scale)\n root.add(inner)\n restOnBase(T, inner)\n } else {\n shape = shapeOf(item)\n const inner = drawShape(kit, shape, item.size, { ...(item.color === undefined ? {} : { color: item.color }), ...(options.detail === undefined ? {} : { detail: options.detail }) })\n inner.name = shape\n root.add(inner)\n restOnBase(T, inner)\n }\n const materials = kit.materials.slice(first)\n if (options.wear) setWear(materials, options.wear)\n root.userData.wear = options.wear ?? 0\n if (options.destructible) tagForDestruction(root, { ...(kind === 'model' && item.model !== undefined ? { modelId: item.model } : {}), ...(item.weight === undefined ? {} : { weight: item.weight }), size: item.size })\n return { root, kind, ...(shape ? { shape } : {}), size: item.size, materials }\n}\n","import { mergeByMaterial } from '@adatechnology/game-shapes-three'\nimport type * as THREE_NS from 'three'\n\nimport type { ItemModel } from './build-item'\n\n/**\n * The same item with its meshes joined by material: one mesh and one draw call per material instead of one per part (the \"one material for all the items\" of the page's\n * budget, as far as the materials of the kit allow). The materials are the same objects, so `setWear` still reaches them. The model's scale stays on the root.\n */\nexport function mergeItem(T: typeof THREE_NS, model: ItemModel): ItemModel {\n model.root.updateMatrixWorld(true)\n const merged = new T.Group()\n merged.name = model.root.name\n merged.scale.copy(model.root.scale)\n merged.userData = { ...model.root.userData }\n // baked into the space of the root, which leaves the root's own scale out of the geometry\n merged.add(...mergeByMaterial(T, model.root, model.root))\n return { ...model, root: merged }\n}\n","import type * as THREE_NS from 'three'\n\nexport type Vec3Like = readonly [number, number, number]\n\n/** The draw budgets of the Itens do Vale Cinzento page (section \"Desempenho com hordas\"). */\nexport interface ItemBudgets {\n /** Draw calls of all the items in a frame. */\n drawCalls: number\n /** A small item: at most this many triangles, and it disappears at `cullDistance`. */\n small: { triangles: number; cullDistance: number }\n /** A large item. */\n large: { triangles: number; cullDistance: number }\n /** The second level of detail has this share of the triangles of the first. */\n lod1Ratio: number\n /** Longest side (m) from which an item counts as large: the page does not say where small ends, so this is the kit's reading and a game can change it. */\n largeFrom: number\n}\n\nexport const ITEM_BUDGETS: ItemBudgets = {\n drawCalls: 30,\n small: { triangles: 400, cullDistance: 30 },\n large: { triangles: 1200, cullDistance: 60 },\n lod1Ratio: 0.5,\n largeFrom: 0.6,\n}\n\nexport type ItemSizeClass = 'small' | 'large'\n\nexport const sizeClassOf = (size: Vec3Like, budgets: ItemBudgets = ITEM_BUDGETS): ItemSizeClass => (Math.max(...size) >= budgets.largeFrom ? 'large' : 'small')\n\nexport const triangleBudgetOf = (size: Vec3Like, budgets: ItemBudgets = ITEM_BUDGETS): number => budgets[sizeClassOf(size, budgets)].triangles\n\nexport const cullDistanceOf = (size: Vec3Like, budgets: ItemBudgets = ITEM_BUDGETS): number => budgets[sizeClassOf(size, budgets)].cullDistance\n\n/** Triangles under `root`: visible meshes only, indexed or not. */\nexport function countTriangles(root: THREE_NS.Object3D): number {\n let total = 0\n root.traverse((object) => {\n const mesh = object as THREE_NS.Mesh\n if (!mesh.isMesh || !mesh.visible) return\n const geometry = mesh.geometry\n total += geometry.index ? geometry.index.count / 3 : geometry.getAttribute('position').count / 3\n })\n return Math.round(total)\n}\n\n/** Draw calls under `root`: one per visible mesh (a mesh with a material list counts once per group). */\nexport function countDrawCalls(root: THREE_NS.Object3D): number {\n let total = 0\n root.traverse((object) => {\n const mesh = object as THREE_NS.Mesh\n if (!mesh.isMesh || !mesh.visible) return\n total += Array.isArray(mesh.material) ? Math.max(1, mesh.geometry.groups.length) : 1\n })\n return total\n}\n\nexport interface BudgetReport {\n triangles: number\n limit: number\n drawCalls: number\n sizeClass: ItemSizeClass\n ok: boolean\n}\n\n/** How an item's model measures against its triangle budget (a model of the team above it is a known deviation, not an error). */\nexport function checkBudget(root: THREE_NS.Object3D, size: Vec3Like, budgets: ItemBudgets = ITEM_BUDGETS): BudgetReport {\n const triangles = countTriangles(root)\n const limit = triangleBudgetOf(size, budgets)\n return { triangles, limit, drawCalls: countDrawCalls(root), sizeClass: sizeClassOf(size, budgets), ok: triangles <= limit }\n}\n","import type * as THREE_NS from 'three'\n\nimport { ITEM_BUDGETS, cullDistanceOf } from './budgets'\nimport type { ItemBudgets } from './budgets'\nimport { buildItem } from './build-item'\nimport type { BuildItemOptions, DrawableItem, ItemModel } from './build-item'\nimport { createItemKit } from './kit'\nimport { mergeItem } from './merge'\n\nexport interface ItemLodOptions extends Omit<BuildItemOptions, 'simple' | 'detail' | 'kit'> {\n budgets?: ItemBudgets\n /** Join the meshes of each level by material (default true). */\n merge?: boolean\n /** Distance of the second level in metres; default a third of the distance at which the item disappears. */\n lod1Distance?: number\n}\n\nexport interface ItemLod {\n /** Add this to the scene and call `update(camera)` (or let the renderer do it). */\n readonly root: THREE_NS.LOD\n /** Full detail: the showcase model, or the shape at full segments. */\n readonly near: ItemModel\n /** The simple shape at half the segments. */\n readonly far: ItemModel\n /** Metres from the camera at which the item is no longer drawn. */\n readonly cullDistance: number\n readonly lod1Distance: number\n}\n\n/**\n * Three levels of an item: the model (or the shape) up close, the simple shape at half the segments from `lod1Distance`, and nothing from the distance of its class\n * (a small item goes at 30 m, a large one at 60 m).\n */\nexport function buildItemLod(T: typeof THREE_NS, item: DrawableItem, options: ItemLodOptions = {}): ItemLod {\n const budgets = options.budgets ?? ITEM_BUDGETS\n const cullDistance = cullDistanceOf(item.size, budgets)\n const lod1Distance = options.lod1Distance ?? cullDistance / 3\n const joined = (model: ItemModel): ItemModel => (options.merge === false ? model : mergeItem(T, model))\n const wear = options.wear === undefined ? {} : { wear: options.wear }\n const near = joined(buildItem(T, item, { ...wear, kit: createItemKit(T) }))\n const far = joined(buildItem(T, item, { ...wear, simple: true, detail: budgets.lod1Ratio, kit: createItemKit(T) }))\n const root = new T.LOD()\n root.name = item.id\n root.addLevel(near.root, 0)\n root.addLevel(far.root, lod1Distance)\n root.addLevel(new T.Group(), cullDistance)\n root.userData.wear = options.wear ?? 0\n return { root, near, far, cullDistance, lod1Distance }\n}\n","/**\n * Models of the showcase that go over the triangle budget of their class (400 for a small item, 1200 for a large one) as the team drew them, with the count they have.\n * The page set the budget for the game and drew the models for a showcase; the models stay as delivered (the builder is the team's) and a scene at a distance wears the\n * simple shape of the second level of detail (`buildItemLod`), which is inside the budget. A model that changes its count is a drawing that changed: the test flags it.\n */\nexport const MODEL_BUDGET_DEVIATIONS: Readonly<Record<string, number>> = {\n canned_beans: 744,\n amoxicillin: 596,\n flashlight: 1060,\n portable_radio: 504,\n house_key: 472,\n motorcycle_helmet: 840,\n lpg_cylinder_13kg: 712,\n}\n","import type { Thumbnail } from '@adatechnology/game-contracts'\nimport type * as THREE_NS from 'three'\n\nimport { buildItem } from './build-item'\nimport type { DrawableItem } from './build-item'\nimport { hasItemModel } from './models/registry'\nimport { shade, shapeOf } from './shapes'\nimport type { ShapeId } from './shapes'\nimport { setWear } from './wear'\nimport type { WearStage } from './wear'\n\nconst hex = (color: number): string => `#${(color & 0xffffff).toString(16).padStart(6, '0')}`\nconst DEFAULT_COLOR = 0x8a8f94\nconst STEEL = '#9aa0a6'\nconst BRASS = '#b8913a'\nconst WOOD = '#8a643c'\nconst PAPER = '#ece4d0'\n\n/** The SVG art of each shape on a 64 x 64 board, from the colour of the item (`c`), a darker (`d`) and a lighter (`l`) tone of it. */\nconst ART: Readonly<Record<ShapeId, (c: string, d: string, l: string) => string>> = {\n can: (c, d, l) => `<rect x=\"19\" y=\"13\" width=\"26\" height=\"42\" rx=\"3\" fill=\"${c}\"/><rect x=\"19\" y=\"24\" width=\"26\" height=\"18\" fill=\"${l}\"/><rect x=\"18\" y=\"11\" width=\"28\" height=\"5\" rx=\"2\" fill=\"${STEEL}\"/><rect x=\"18\" y=\"52\" width=\"28\" height=\"4\" rx=\"2\" fill=\"${STEEL}\"/>`,\n bag: (c, d, l) => `<path d=\"M16 55 L13 25 Q32 14 51 25 L48 55 Z\" fill=\"${c}\"/><rect x=\"14\" y=\"17\" width=\"36\" height=\"7\" rx=\"2\" fill=\"${d}\"/><rect x=\"22\" y=\"32\" width=\"20\" height=\"14\" rx=\"2\" fill=\"${l}\"/>`,\n box: (c, d, l) => `<rect x=\"11\" y=\"18\" width=\"42\" height=\"37\" fill=\"${c}\"/><rect x=\"11\" y=\"18\" width=\"42\" height=\"8\" fill=\"${d}\"/><rect x=\"22\" y=\"33\" width=\"20\" height=\"13\" fill=\"${l}\"/>`,\n bottle: (c, d) => `<rect x=\"28\" y=\"7\" width=\"8\" height=\"8\" rx=\"2\" fill=\"${d}\"/><path d=\"M23 56 V30 Q23 23 28 18 H36 Q41 23 41 30 V56 Z\" fill=\"${c}\" fill-opacity=\".75\"/><rect x=\"23\" y=\"34\" width=\"18\" height=\"14\" fill=\"${PAPER}\" fill-opacity=\".9\"/>`,\n tool: (c) => `<rect x=\"29\" y=\"20\" width=\"6\" height=\"37\" rx=\"2\" fill=\"${WOOD}\"/><rect x=\"17\" y=\"9\" width=\"30\" height=\"13\" rx=\"2\" fill=\"${c === '#808080' ? STEEL : c}\"/>`,\n roll: (c, d) => `<circle cx=\"32\" cy=\"34\" r=\"22\" fill=\"${c}\"/><circle cx=\"32\" cy=\"34\" r=\"8\" fill=\"${d}\"/>`,\n dish: (c, d, l) => `<ellipse cx=\"32\" cy=\"44\" rx=\"27\" ry=\"9\" fill=\"${c}\"/><ellipse cx=\"32\" cy=\"42\" rx=\"19\" ry=\"5\" fill=\"${l}\"/><ellipse cx=\"32\" cy=\"42\" rx=\"9\" ry=\"2\" fill=\"${d}\"/>`,\n cloth: (c, d) => `<rect x=\"9\" y=\"34\" width=\"46\" height=\"21\" rx=\"3\" fill=\"${c}\"/><rect x=\"13\" y=\"22\" width=\"38\" height=\"14\" rx=\"3\" fill=\"${d}\"/>`,\n shoe: (c) => `<path d=\"M9 48 V27 H26 L30 36 H47 Q56 38 56 48 Z\" fill=\"${c}\"/><rect x=\"7\" y=\"48\" width=\"50\" height=\"7\" rx=\"2\" fill=\"#22251f\"/>`,\n jar: (c) => `<rect x=\"17\" y=\"22\" width=\"30\" height=\"33\" rx=\"6\" fill=\"${c}\" fill-opacity=\".7\"/><rect x=\"16\" y=\"13\" width=\"32\" height=\"10\" rx=\"2\" fill=\"${BRASS}\"/>`,\n paper: (c, d) => `<rect x=\"14\" y=\"10\" width=\"36\" height=\"46\" fill=\"${PAPER}\"/><rect x=\"19\" y=\"18\" width=\"26\" height=\"3\" fill=\"${d}\"/><rect x=\"19\" y=\"26\" width=\"26\" height=\"3\" fill=\"${d}\"/><rect x=\"19\" y=\"34\" width=\"18\" height=\"3\" fill=\"${d}\"/><rect x=\"19\" y=\"42\" width=\"22\" height=\"3\" fill=\"${c}\"/>`,\n fruit: (c) => `<circle cx=\"32\" cy=\"38\" r=\"18\" fill=\"${c}\"/><rect x=\"31\" y=\"13\" width=\"3\" height=\"9\" fill=\"#5a3a22\"/><path d=\"M34 16 Q44 10 48 16 Q40 20 34 16 Z\" fill=\"#4f7a3a\"/>`,\n cup: (c, d) => `<path d=\"M18 16 H46 L41 56 H23 Z\" fill=\"${c}\"/><rect x=\"18\" y=\"14\" width=\"28\" height=\"4\" fill=\"${d}\"/>`,\n tube: (c, d) => `<path d=\"M23 15 H41 V48 L37 56 H27 L23 48 Z\" fill=\"${c}\"/><rect x=\"25\" y=\"7\" width=\"14\" height=\"9\" rx=\"2\" fill=\"${d}\"/>`,\n blade: () => `<rect x=\"5\" y=\"33\" width=\"18\" height=\"8\" rx=\"2\" fill=\"#3b2a20\"/><path d=\"M23 33 H55 L60 38 L23 42 Z\" fill=\"#a9adb0\"/><rect x=\"22\" y=\"31\" width=\"3\" height=\"12\" fill=\"${BRASS}\"/>`,\n long_tool: (c) => `<rect x=\"5\" y=\"30\" width=\"50\" height=\"5\" rx=\"2\" fill=\"${WOOD}\"/><rect x=\"47\" y=\"21\" width=\"12\" height=\"22\" rx=\"2\" fill=\"${c === '#808080' ? STEEL : c}\"/>`,\n garment: (c, d) => `<path d=\"M20 12 L6 24 L13 33 L20 28 V56 H44 V28 L51 33 L58 24 L44 12 Q32 22 20 12 Z\" fill=\"${c}\"/><path d=\"M20 12 Q32 22 44 12 Q32 28 20 12 Z\" fill=\"${d}\"/>`,\n backpack: (c, d) => `<path d=\"M24 18 Q32 4 40 18\" fill=\"none\" stroke=\"${d}\" stroke-width=\"3\"/><rect x=\"15\" y=\"16\" width=\"34\" height=\"40\" rx=\"9\" fill=\"${c}\"/><rect x=\"21\" y=\"35\" width=\"22\" height=\"16\" rx=\"3\" fill=\"${d}\"/>`,\n jerrycan: (c, d) => `<rect x=\"13\" y=\"17\" width=\"38\" height=\"39\" rx=\"3\" fill=\"${c}\"/><rect x=\"17\" y=\"8\" width=\"16\" height=\"10\" rx=\"2\" fill=\"${d}\"/><rect x=\"39\" y=\"9\" width=\"9\" height=\"9\" fill=\"#d9a441\"/>`,\n tank: (c, d) => `<rect x=\"21\" y=\"18\" width=\"22\" height=\"38\" rx=\"10\" fill=\"${c}\"/><rect x=\"28\" y=\"9\" width=\"8\" height=\"10\" fill=\"${BRASS}\"/><rect x=\"20\" y=\"43\" width=\"24\" height=\"3\" fill=\"${d}\"/>`,\n book: (c, d) => `<rect x=\"14\" y=\"9\" width=\"37\" height=\"47\" fill=\"${c}\"/><rect x=\"14\" y=\"9\" width=\"6\" height=\"47\" fill=\"${d}\"/><rect x=\"23\" y=\"13\" width=\"25\" height=\"39\" fill=\"#e9e1cc\"/>`,\n key: () => `<circle cx=\"16\" cy=\"32\" r=\"9\" fill=\"none\" stroke=\"#9a9da0\" stroke-width=\"5\"/><rect x=\"24\" y=\"30\" width=\"33\" height=\"5\" fill=\"${BRASS}\"/><rect x=\"45\" y=\"35\" width=\"4\" height=\"7\" fill=\"${BRASS}\"/><rect x=\"51\" y=\"35\" width=\"3\" height=\"5\" fill=\"${BRASS}\"/>`,\n battery: (c, d, l) => `<rect x=\"23\" y=\"14\" width=\"18\" height=\"42\" rx=\"2\" fill=\"${c}\"/><rect x=\"28\" y=\"9\" width=\"8\" height=\"6\" fill=\"#b9bdc0\"/><rect x=\"23\" y=\"26\" width=\"18\" height=\"16\" fill=\"${l}\"/><rect x=\"23\" y=\"47\" width=\"18\" height=\"9\" fill=\"${d}\"/>`,\n plank: (c) => `<rect x=\"5\" y=\"26\" width=\"54\" height=\"13\" fill=\"${WOOD}\"/><rect x=\"5\" y=\"30\" width=\"54\" height=\"2\" fill=\"${c === '#808080' ? '#6b4a2c' : c}\" fill-opacity=\".5\"/><circle cx=\"12\" cy=\"32\" r=\"2\" fill=\"#7d8186\"/><circle cx=\"52\" cy=\"32\" r=\"2\" fill=\"#7d8186\"/>`,\n device: (c) => `<rect x=\"15\" y=\"7\" width=\"34\" height=\"50\" rx=\"5\" fill=\"${c}\"/><rect x=\"20\" y=\"13\" width=\"24\" height=\"18\" rx=\"2\" fill=\"#9fbf8a\"/><circle cx=\"26\" cy=\"43\" r=\"4\" fill=\"#b9bdc0\"/><rect x=\"35\" y=\"40\" width=\"9\" height=\"6\" rx=\"1\" fill=\"#b9bdc0\"/>`,\n}\n\n/** The SVG picture of a shape in the colour of an item: a 64 x 64 board with plain shapes, no script and no reference. */\nexport function shapeThumbnailSvg(shape: ShapeId, color: number = DEFAULT_COLOR): string {\n const art = ART[shape]\n return `<svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 64 64\">${art(hex(color), hex(shade(color, 0.7)), hex(shade(color, 1.3)))}</svg>`\n}\n\n/**\n * The picture of an item for catalogues and inventories: an item that has a 3D model asks the host to draw it (`render: true`), every other gets the SVG of its shape in\n * its colour.\n */\nexport function itemThumbnail(item: DrawableItem): Thumbnail {\n if (item.model !== undefined && hasItemModel(item.model)) return { render: true }\n return { svg: shapeThumbnailSvg(shapeOf(item), item.color) }\n}\n\n/** The SVG of an item whatever it has: its shape in its colour (what a host with no renderer shows for a modeled item). */\nexport const itemThumbnailSvg = (item: DrawableItem): string => shapeThumbnailSvg(shapeOf(item), item.color)\n\n/** `{ id: { thumbnail } }` for `createItems({ patch })`, so that a catalog carries its pictures. */\nexport function thumbnailPatch(items: Iterable<DrawableItem>): Record<string, { thumbnail: Thumbnail }> {\n const patch: Record<string, { thumbnail: Thumbnail }> = {}\n for (const item of items) patch[item.id] = { thumbnail: itemThumbnail(item) }\n return patch\n}\n\nexport interface ThumbnailRenderOptions {\n /** Side of the picture in pixels (default 128). */\n size?: number\n /** Turn of the item around y and the lift of the camera, radians (default a three-quarter view from above). */\n yaw?: number\n pitch?: number\n /** Multiplies the distance that just fits the item (default 1). */\n distance?: number\n wear?: WearStage\n}\n\nexport interface ThumbnailScene {\n scene: THREE_NS.Scene\n camera: THREE_NS.PerspectiveCamera\n}\n\nconst FIT_MARGIN = 1.15\nconst FIELD_OF_VIEW = 30\n\n/** The scene and camera that frame an item for its picture: the item at the origin, lit like the showcase (hemisphere, sun, rim), the camera far enough to fit all of it. */\nexport function composeThumbnailScene(T: typeof THREE_NS, item: DrawableItem, options: ThumbnailRenderOptions = {}): ThumbnailScene {\n const { yaw = -0.6, pitch = 0.45, distance = 1, wear = 0 } = options\n const scene = new T.Scene()\n const model = buildItem(T, item)\n if (wear) setWear(model.root, wear)\n scene.add(model.root)\n scene.add(new T.HemisphereLight(0xdfe6ee, 0x3a3428, 0.85))\n const sun = new T.DirectionalLight(0xffe2bf, 1.1)\n sun.position.set(2.5, 3.5, 2.5)\n scene.add(sun)\n const rim = new T.DirectionalLight(0x8fb2d6, 0.45)\n rim.position.set(-3, 1, -2.5)\n scene.add(rim)\n const box = new T.Box3().setFromObject(model.root)\n const centre = box.getCenter(new T.Vector3())\n const radius = box.getSize(new T.Vector3()).length() / 2\n const camera = new T.PerspectiveCamera(FIELD_OF_VIEW, 1, radius / 50, radius * 40)\n const fit = (radius * FIT_MARGIN) / Math.sin((FIELD_OF_VIEW * Math.PI) / 360)\n const away = fit * distance\n camera.position.set(centre.x + away * Math.cos(pitch) * Math.sin(yaw), centre.y + away * Math.sin(pitch), centre.z + away * Math.cos(pitch) * Math.cos(yaw))\n camera.lookAt(centre)\n camera.updateMatrixWorld(true)\n return { scene, camera }\n}\n\n/** What `renderItemThumbnail` needs of a renderer (a `WebGLRenderer`, or anything that draws a scene to a canvas). */\nexport interface ThumbnailRenderer {\n setSize(width: number, height: number): void\n setClearColor?(color: number, alpha?: number): void\n render(scene: THREE_NS.Scene, camera: THREE_NS.Camera): void\n domElement: { toDataURL(type?: string): string }\n}\n\n/** Draws the item with the host's renderer and returns the PNG as a data URL (transparent background). */\nexport function renderItemThumbnail(T: typeof THREE_NS, renderer: ThumbnailRenderer, item: DrawableItem, options: ThumbnailRenderOptions = {}): string {\n const { scene, camera } = composeThumbnailScene(T, item, options)\n const size = options.size ?? 128\n renderer.setSize(size, size)\n renderer.setClearColor?.(0x000000, 0)\n renderer.render(scene, camera)\n return renderer.domElement.toDataURL('image/png')\n}\n","import type { ColliderOptions, WorldCollider } from './types'\n\ninterface Box {\n ids: string[]\n object: string\n u0: number\n u1: number\n v0: number\n v1: number\n y0: number\n y1: number\n}\n\nconst volume = (b: Box): number => (b.u1 - b.u0) * (b.v1 - b.v0) * (b.y1 - b.y0)\nconst overlap = (a0: number, a1: number, b0: number, b1: number): number => Math.max(0, Math.min(a1, b1) - Math.max(a0, b0))\n\nfunction tryMerge(a: Box, b: Box, gap: number, slack: number): Box | null {\n if (a.u0 - gap > b.u1 || b.u0 - gap > a.u1) return null\n if (a.v0 - gap > b.v1 || b.v0 - gap > a.v1) return null\n if (a.y0 - gap > b.y1 || b.y0 - gap > a.y1) return null\n const u0 = Math.min(a.u0, b.u0)\n const u1 = Math.max(a.u1, b.u1)\n const v0 = Math.min(a.v0, b.v0)\n const v1 = Math.max(a.v1, b.v1)\n const y0 = Math.min(a.y0, b.y0)\n const y1 = Math.max(a.y1, b.y1)\n const hull = (u1 - u0) * (v1 - v0) * (y1 - y0)\n const common = overlap(a.u0, a.u1, b.u0, b.u1) * overlap(a.v0, a.v1, b.v0, b.v1) * overlap(a.y0, a.y1, b.y0, b.y1)\n const real = volume(a) + volume(b) - common\n if (hull > real * (1 + slack) + 1e-9) return null\n return { ids: [...a.ids, ...b.ids], object: a.object, u0, u1, v0, v1, y0, y1 }\n}\n\n/**\n * Union overlapping or adjacent colliders of the same object (same rotation) into fewer OBBs.\n * A merge happens only when the merged box adds at most `slack` extra volume over the real union, so coverage is never lost\n * and never grows noticeably. Colliders of different objects or rotations are left alone.\n */\nexport function mergeColliders(list: WorldCollider[], options: Pick<ColliderOptions, 'gap' | 'slack'> = {}): WorldCollider[] {\n const gap = options.gap ?? 0.02\n const slack = options.slack ?? 0.1\n const groups = new Map<string, WorldCollider[]>()\n for (const c of list) {\n const key = `${c.object}|${Math.round(c.ry * 1000)}`\n const g = groups.get(key)\n if (g) g.push(c)\n else groups.set(key, [c])\n }\n const out: WorldCollider[] = []\n for (const g of groups.values()) {\n const ry = g[0]?.ry ?? 0\n const cs = Math.cos(ry)\n const sn = Math.sin(ry)\n let boxes: Box[] = g.map((c) => {\n const u = c.cx * cs - c.cz * sn\n const v = c.cx * sn + c.cz * cs\n return { ids: [c.id], object: c.object, u0: u - c.hw, u1: u + c.hw, v0: v - c.hd, v1: v + c.hd, y0: c.y0, y1: c.y1 }\n })\n let changed = boxes.length > 1\n while (changed) {\n changed = false\n outer: for (let i = 0; i < boxes.length; i++) {\n for (let j = i + 1; j < boxes.length; j++) {\n const m = tryMerge(boxes[i] as Box, boxes[j] as Box, gap, slack)\n if (!m) continue\n boxes = boxes.filter((_, k) => k !== i && k !== j)\n boxes.push(m)\n changed = true\n break outer\n }\n }\n }\n for (const b of boxes) {\n const u = (b.u0 + b.u1) / 2\n const v = (b.v0 + b.v1) / 2\n out.push({\n id: b.ids.length === 1 ? (b.ids[0] as string) : `${b.ids[0]}+${b.ids.length - 1}`,\n object: b.object,\n cx: u * cs + v * sn,\n cz: -u * sn + v * cs,\n hw: (b.u1 - b.u0) / 2,\n hd: (b.v1 - b.v0) / 2,\n ry,\n y0: b.y0,\n y1: b.y1,\n })\n }\n }\n return out\n}\n","/** FNV-1a hash of a string to a 32-bit unsigned integer. */\nexport function hashString(text: string): number {\n let h = 2166136261\n for (let i = 0; i < text.length; i++) {\n h ^= text.charCodeAt(i)\n h = Math.imul(h, 16777619)\n }\n return h >>> 0\n}\n\n/** Deterministic random generator (mulberry32). Returns a function producing floats in [0, 1). Numbers and strings are accepted as seeds. */\nexport function rng(seed: number | string = 1): () => number {\n let a = (typeof seed === 'number' ? Math.floor(seed) >>> 0 : hashString(seed)) || 0x9e3779b9\n return () => {\n a = (a + 0x6d2b79f5) >>> 0\n let t = a\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","import { rng } from './rng'\nimport type { ItemCatalog, ItemStack, LootTables, SlotSpec, Vec3 } from './types'\n\n/** True when an item of `size` [w, h, d] fits in a slot of `max`; width and depth may be swapped (the item is turned). */\nexport function fitsSize(size: Vec3, max: Vec3): boolean {\n const eps = 1e-9\n if (size[1] > max[1] + eps) return false\n return (size[0] <= max[0] + eps && size[2] <= max[2] + eps) || (size[2] <= max[0] + eps && size[0] <= max[2] + eps)\n}\n\n/** Does the item type fit the slot. Types missing from the catalog are accepted (the host owns unknown items). */\nexport function fitsSlot(type: string, slot: SlotSpec, items?: ItemCatalog): boolean {\n const def = items?.[type]\n return def ? fitsSize(def.size, slot.max) : true\n}\n\n/**\n * Deterministic contents for a container: one entry per slot. A slot is filled with probability `fill`; the entry is a weighted pick\n * among the table entries whose item fits the slot. Same seed, same table and same slots always give the same result.\n */\nexport function generateLoot(\n tables: LootTables | undefined,\n tableId: string,\n slots: SlotSpec[],\n seed: number | string,\n items?: ItemCatalog,\n): Array<ItemStack | null> {\n const table = tables?.[tableId]\n const out: Array<ItemStack | null> = slots.map(() => null)\n if (!table) return out\n const rand = rng(seed)\n slots.forEach((slot, i) => {\n // Always draw the same number of random values per slot so a change in one slot does not shift the others.\n const roll = rand()\n const pick = rand()\n const q = rand()\n if (roll >= table.fill) return\n const candidates = table.entries.filter((e) => e.weight > 0 && fitsSlot(e.type, slot, items))\n const total = candidates.reduce((s, e) => s + e.weight, 0)\n if (total <= 0) return\n let r = pick * total\n let chosen = candidates[candidates.length - 1]\n for (const e of candidates) {\n r -= e.weight\n if (r < 0) {\n chosen = e\n break\n }\n }\n const [lo, hi] = chosen.qty ?? [1, 1]\n const def = items?.[chosen.type]\n const stackMax = def ? (def.stack ?? 1) : Number.POSITIVE_INFINITY\n const qty = Math.max(1, Math.min(stackMax, lo + Math.floor(q * (hi - lo + 1))))\n out[i] = { type: chosen.type, qty }\n })\n return out\n}\n","import type { InteractablesLocale, Strings } from './types'\n\n/** Engine-level prompts and messages. Content packs add their own keys through `WorldOptions.strings`. */\nexport const locales: Record<InteractablesLocale, Strings> = {\n en: {\n 'prompt.open': 'Open {name}',\n 'prompt.close': 'Close {name}',\n 'prompt.turn_on': 'Turn on {name}',\n 'prompt.turn_off': 'Turn off {name}',\n 'prompt.take': 'Take',\n 'prompt.sit': 'Sit',\n 'prompt.lie_down': 'Lie down',\n 'prompt.get_up': 'Get up',\n 'prompt.light': 'Light',\n 'prompt.change_channel': 'Change channel',\n 'prompt.read': 'Read',\n 'prompt.breaker_on': 'Switch on {circuit}',\n 'prompt.breaker_off': 'Switch off {circuit}',\n 'prompt.open_valve': 'Open valve',\n 'prompt.close_valve': 'Close valve',\n no_power: 'No power',\n no_gas: 'No gas',\n no_water: 'No water',\n locked: 'Locked',\n requires_open: 'Open it first',\n already_lit: 'Already lit',\n needs_ignition: 'Light it first',\n turn_on_first: 'Turn it on first',\n empty: 'Empty',\n full: 'Full',\n },\n 'pt-BR': {\n 'prompt.open': 'Abrir {name}',\n 'prompt.close': 'Fechar {name}',\n 'prompt.turn_on': 'Ligar {name}',\n 'prompt.turn_off': 'Desligar {name}',\n 'prompt.take': 'Pegar',\n 'prompt.sit': 'Sentar',\n 'prompt.lie_down': 'Deitar',\n 'prompt.get_up': 'Levantar',\n 'prompt.light': 'Acender',\n 'prompt.change_channel': 'Trocar de canal',\n 'prompt.read': 'Ler',\n 'prompt.breaker_on': 'Ligar {circuit}',\n 'prompt.breaker_off': 'Desligar {circuit}',\n 'prompt.open_valve': 'Abrir registro',\n 'prompt.close_valve': 'Fechar registro',\n no_power: 'Sem energia',\n no_gas: 'Sem gás',\n no_water: 'Sem água',\n locked: 'Trancado',\n requires_open: 'Abra primeiro',\n already_lit: 'Já está aceso',\n needs_ignition: 'Acenda primeiro',\n turn_on_first: 'Ligue primeiro',\n empty: 'Vazio',\n full: 'Cheio',\n },\n}\n\n/** Pick a built-in locale for an arbitrary tag (`pt`, `pt-br`, `en-GB`...). Unknown tags give `en`. */\nexport function pickLocale(locale: string | undefined): InteractablesLocale {\n if (!locale) return 'en'\n const l = locale.toLowerCase()\n if (l === 'pt-br' || l === 'pt') return 'pt-BR'\n return 'en'\n}\n\n/**\n * Merged table for a locale: built-in `en`, then the built-in table of `locale`, then the extra strings for `en` and for `locale`.\n * Lookup therefore falls back to English, and the caller never gets undefined for engine keys.\n */\nexport function resolveStrings(locale?: string, extra?: Partial<Record<InteractablesLocale, Strings>>): Strings {\n const loc = pickLocale(locale)\n return { ...locales.en, ...locales[loc], ...(extra?.en ?? {}), ...(loc === 'en' ? {} : (extra?.[loc] ?? {})) }\n}\n\n/** Replace `{name}` placeholders. Unknown placeholders are left untouched. */\nexport function format(text: string, vars?: Record<string, string | number>): string {\n if (!vars) return text\n return text.replace(/\\{(\\w+)\\}/g, (m, k: string) => (k in vars ? String(vars[k]) : m))\n}\n","import type { Motion, Transform, Vec3 } from './types'\n\nexport interface Pose {\n /** Translation relative to the pivot. */\n position: Vec3\n /** Rotation around `axis` (in the part frame) by `angle` radians. */\n rotation: { axis: Vec3; angle: number }\n scale: Vec3\n}\n\nconst DEFAULT_AXIS: Vec3 = [0, 1, 0]\n\n/**\n * Pose of a part at animation value `t` (0..1), relative to its pivot, so any renderer can apply it:\n * `position`, then `rotation` around the pivot, then `scale` along the axis.\n */\nexport function poseOf(motion: Motion, t: number): Pose {\n const tt = Math.max(0, Math.min(1, t))\n const axis = motion.axis ?? DEFAULT_AXIS\n const pose: Pose = { position: [0, 0, 0], rotation: { axis: [axis[0], axis[1], axis[2]], angle: 0 }, scale: [1, 1, 1] }\n switch (motion.kind) {\n case 'hinge':\n case 'rocker':\n case 'knob':\n pose.rotation.angle = (motion.angle ?? Math.PI / 2) * tt\n break\n case 'slide': {\n const d = (motion.distance ?? 0.4) * tt\n pose.position = [axis[0] * d, axis[1] * d, axis[2] * d]\n break\n }\n case 'scale': {\n const k = 1 + ((motion.scale ?? 0.2) - 1) * tt\n pose.scale = [axis[0] !== 0 ? k : 1, axis[1] !== 0 ? k : 1, axis[2] !== 0 ? k : 1]\n break\n }\n }\n return pose\n}\n\n/** Rotate a vector around +y by `ry` radians (same convention as three.js `rotation.y`). */\nexport function rotY(v: Vec3, ry: number): Vec3 {\n const c = Math.cos(ry)\n const s = Math.sin(ry)\n return [c * v[0] + s * v[2], v[1], -s * v[0] + c * v[2]]\n}\n\n/** Object-local point to world space. */\nexport function localToWorld(transform: Transform, v: Vec3): Vec3 {\n const r = rotY(v, transform.ry)\n return [transform.x + r[0], transform.y + r[1], transform.z + r[2]]\n}\n\n/** World point to object-local space. */\nexport function worldToLocal(transform: Transform, v: Vec3): Vec3 {\n return rotY([v[0] - transform.x, v[1] - transform.y, v[2] - transform.z], -transform.ry)\n}\n\n/** Rodrigues rotation of `v` around a unit-length-normalised `axis` by `angle`. */\nexport function rotateAxis(v: Vec3, axis: Vec3, angle: number): Vec3 {\n const len = Math.hypot(axis[0], axis[1], axis[2]) || 1\n const k: Vec3 = [axis[0] / len, axis[1] / len, axis[2] / len]\n const c = Math.cos(angle)\n const s = Math.sin(angle)\n const dot = k[0] * v[0] + k[1] * v[1] + k[2] * v[2]\n const cross: Vec3 = [k[1] * v[2] - k[2] * v[1], k[2] * v[0] - k[0] * v[2], k[0] * v[1] - k[1] * v[0]]\n return [v[0] * c + cross[0] * s + k[0] * dot * (1 - c), v[1] * c + cross[1] * s + k[1] * dot * (1 - c), v[2] * c + cross[2] * s + k[2] * dot * (1 - c)]\n}\n\nexport function clamp(v: number, lo: number, hi: number): number {\n return v < lo ? lo : v > hi ? hi : v\n}\n\nexport function dist3(a: Vec3, b: Vec3): number {\n return Math.hypot(a[0] - b[0], a[1] - b[1], a[2] - b[2])\n}\n","import { mergeColliders } from './colliders'\nimport { fitsSlot, generateLoot } from './loot'\nimport { format, resolveStrings } from './locale'\nimport { clamp, dist3, localToWorld, rotateAxis, rotY, worldToLocal } from './math'\nimport type {\n ActiveEmitter,\n BurnerSpec,\n ColliderOptions,\n DeviceSpec,\n FixtureSpec,\n FuelSourceSpec,\n Interactable,\n InteractionSpec,\n ItemStack,\n ObjectSpec,\n PartSpec,\n SeatResult,\n SoftSpec,\n TankSpec,\n TargetOptions,\n Transform,\n Vec3,\n World,\n WorldCollider,\n WorldEvent,\n WorldObject,\n WorldOptions,\n WorldState,\n} from './types'\n\n// ---------------------------------------------------------------------------------------------------------------------------------\n// Constants\n// ---------------------------------------------------------------------------------------------------------------------------------\n\nconst DEFAULT_ACTOR = 'player'\nconst DEFAULT_RADIUS = 1.2\nconst AUTO_RANGE = 2\nconst SMOKE_TAIL = 20\nconst FLUSH_SECONDS = 2\nconst ACTOR_HEIGHT = 1.7\nconst PUSH_GAIN = 1.2\nconst SWEEP_STEPS = 24\nconst FLOW_DEFAULTS: Record<string, number> = { tap: 6, shower: 8, utility_sink: 6, flush: 0, hose: 10, filter: 1 }\n\n// ---------------------------------------------------------------------------------------------------------------------------------\n// Internal state\n// ---------------------------------------------------------------------------------------------------------------------------------\n\ninterface PartState {\n spec: PartSpec\n t: number\n target: number\n maxT: number\n}\n\ninterface DeviceState {\n spec: DeviceSpec\n on: boolean\n channel: number\n}\n\ninterface FuelState {\n spec: FuelSourceSpec\n level: number\n}\n\ninterface BurnerState {\n spec: BurnerSpec\n on: boolean\n lit: boolean\n /** Seconds of smoke left after a solid-fuel fire went out. */\n smoke: number\n}\n\ninterface TankState {\n spec: TankSpec\n level: number\n}\n\ninterface FixtureState {\n spec: FixtureSpec\n on: boolean\n flowing: boolean\n /** Delivered / wanted in the last step, 0..1. */\n frac: number\n /** Seconds left of a flush. */\n timer: number\n}\n\ninterface SoftState {\n spec: SoftSpec\n ax: number\n az: number\n vax: number\n vaz: number\n phase: number\n}\n\ninterface DamageState {\n max: number\n hp: number\n}\n\ninterface ObjState {\n id: string\n public: WorldObject\n spec: ObjectSpec\n parts: Map<string, PartState>\n contents: Map<string, Array<ItemStack | null>>\n devices: Map<string, DeviceState>\n fuels: Map<string, FuelState>\n burners: Map<string, BurnerState>\n tanks: Map<string, TankState>\n fixtures: Map<string, FixtureState>\n soft: Map<string, SoftState>\n hp: Map<string, DamageState>\n interactions: InteractionSpec[]\n}\n\nfunction cloneStack(s: ItemStack | null): ItemStack | null {\n return s ? { type: s.type, qty: s.qty, ...(s.data ? { data: JSON.parse(JSON.stringify(s.data)) as Record<string, unknown> } : {}) } : null\n}\n\nfunction humanize(id: string): string {\n const s = id.replace(/[_-]+/g, ' ').trim()\n return s.charAt(0).toUpperCase() + s.slice(1)\n}\n\n// ---------------------------------------------------------------------------------------------------------------------------------\n// World\n// ---------------------------------------------------------------------------------------------------------------------------------\n\nexport function createWorld(options: WorldOptions = {}): World {\n const seed = options.seed ?? 1\n const objs = new Map<string, ObjState>()\n const breakers = new Map<string, boolean>()\n const seats = new Map<string, { object: string; seat: string }>()\n const plugs = new Map<string, string | null>()\n let locale = options.locale ?? 'en'\n let table = resolveStrings(locale, options.strings)\n let grid = options.grid ?? true\n let rain = options.rain ?? 0\n let wind: [number, number] = options.wind ? [options.wind[0], options.wind[1]] : [0, 0]\n let defaultTank: string | null = null\n let defaultTankExplicit = false\n let time = 0\n\n // ------------------------------------------------------------------ text & events\n function t(key: string, vars?: Record<string, string | number>): string {\n return format(table[key] ?? key, vars)\n }\n\n function emit(e: WorldEvent): void {\n options.onEvent?.(e)\n }\n\n function message(key: string): void {\n emit({ type: 'message', key, text: t(key) })\n }\n\n // ------------------------------------------------------------------ lookup helpers\n function gid(o: ObjState, local: string): string {\n return `${o.id}:${local}`\n }\n\n /** Find the first entity matching a world-wide id `objectId:localId`. */\n function findGlobal<T>(id: string, pick: (o: ObjState, local: string) => T | undefined): { o: ObjState; value: T; local: string } | null {\n for (const o of objs.values()) {\n if (!id.startsWith(o.id + ':')) continue\n const local = id.slice(o.id.length + 1)\n const value = pick(o, local)\n if (value !== undefined) return { o, value, local }\n }\n return null\n }\n\n function objectOrThrow(id: string): ObjState {\n const o = objs.get(id)\n if (!o) throw new Error(`Unknown object \"${id}\"`)\n return o\n }\n\n function originOf(o: ObjState): Vec3 {\n const tr = o.public.transform\n return [tr.x, tr.y, tr.z]\n }\n\n function toWorld(o: ObjState, v: Vec3): Vec3 {\n return localToWorld(o.public.transform, v)\n }\n\n // ------------------------------------------------------------------ parts\n function openThreshold(p: PartState): number {\n return Math.min(0.5, p.maxT * 0.9)\n }\n\n function isOpen(o: ObjState, partId: string | undefined): boolean {\n if (!partId) return true\n const p = o.parts.get(partId)\n if (!p) return true\n return p.maxT >= 0.1 && p.t >= openThreshold(p)\n }\n\n function targetIsOpen(p: PartState): boolean {\n return p.maxT >= 0.1 && p.target >= openThreshold(p)\n }\n\n function writeT(o: ObjState, p: PartState, v: number): void {\n p.t = v\n o.public.parts[p.spec.id] = v\n }\n\n function gated(o: ObjState, p: PartState): boolean {\n return !!p.spec.requires && o.parts.has(p.spec.requires) && !isOpen(o, p.spec.requires)\n }\n\n function setOnePart(o: ObjState, p: PartState, target: number, instant: boolean): void {\n const next = clamp(target, 0, p.maxT)\n const changed = next !== p.target\n p.target = next\n if (instant) writeT(o, p, next)\n if (changed || instant) emit({ type: 'part', object: o.id, part: p.spec.id, t: p.t, target: p.target })\n }\n\n function setPartTarget(o: ObjState, partId: string, target: number, instant = false): void {\n const p = o.parts.get(partId)\n if (!p) return\n const group = p.spec.group\n const members = group ? [...o.parts.values()].filter((q) => q.spec.group === group) : [p]\n for (const q of members) {\n setOne(o, q, target, instant)\n }\n }\n\n function setOne(o: ObjState, p: PartState, target: number, instant: boolean): void {\n setOnePart(o, p, target, instant)\n // a part that other parts require closes them with it (the drawer behind a door closes with the door)\n if (!targetIsOpen(p)) {\n for (const q of o.parts.values()) {\n if (q.spec.requires === p.spec.id && q.target > 0) setPartTarget(o, q.spec.id, 0, instant)\n }\n }\n }\n\n /** Frame of a part right now: rotation (axis in object-local, angle) and translation, both about its pivot. */\n function partFrame(o: ObjState, partId: string | undefined): { pivot: Vec3; axis: Vec3; angle: number; offset: Vec3 } | null {\n if (!partId) return null\n const p = o.parts.get(partId)\n if (!p) return null\n const m = p.spec.motion\n const axis = rotY(m.axis ?? [0, 1, 0], p.spec.ry ?? 0)\n const frame = { pivot: p.spec.pivot, axis, angle: 0, offset: [0, 0, 0] as Vec3 }\n if (m.kind === 'slide') {\n const d = (m.distance ?? 0.4) * p.t\n frame.offset = [axis[0] * d, axis[1] * d, axis[2] * d]\n } else if (m.kind !== 'scale') {\n frame.angle = (m.angle ?? Math.PI / 2) * p.t\n }\n return frame\n }\n\n function applyPart(o: ObjState, partId: string | undefined, local: Vec3): Vec3 {\n const f = partFrame(o, partId)\n if (!f) return local\n const rel: Vec3 = [local[0] - f.pivot[0], local[1] - f.pivot[1], local[2] - f.pivot[2]]\n const r = f.angle !== 0 ? rotateAxis(rel, f.axis, f.angle) : rel\n return [f.pivot[0] + r[0] + f.offset[0], f.pivot[1] + r[1] + f.offset[1], f.pivot[2] + r[2] + f.offset[2]]\n }\n\n /** Moves the full closed-pose slab of a part and returns the largest t whose pose keeps every sampled point clear. */\n function fitBounds(o: ObjState, p: PartState, b: NonNullable<PartSpec['bounds']>, blockedAt: (x: number, z: number) => boolean): number {\n const STEP = 0.05\n const ANGLES = 48\n const m = p.spec.motion\n const axis = rotY(m.axis ?? [0, 1, 0], p.spec.ry ?? 0)\n const lo: Vec3 = [Math.min(b[0], b[3]), Math.min(b[1], b[4]), Math.min(b[2], b[5])]\n const hi: Vec3 = [Math.max(b[0], b[3]), Math.max(b[1], b[4]), Math.max(b[2], b[5])]\n const axisPoints = (i: number): number[] => {\n const n = Math.max(1, Math.ceil((hi[i] - lo[i]) / STEP))\n return Array.from({ length: n + 1 }, (_, k) => lo[i] + ((hi[i] - lo[i]) * k) / n)\n }\n const xs = axisPoints(0)\n const ys = axisPoints(1)\n const zs = axisPoints(2)\n // `blocked` only sees x/z, so only the floor footprint matters. About a vertical axis (and for slides) y never changes\n // the footprint, so the x/z outline is enough; otherwise the footprint boundary is the projection of the box edges.\n const flat = m.kind === 'slide' || Math.abs(axis[1]) > 0.999\n const seen = new Set<string>()\n const pts: Vec3[] = []\n const add = (x: number, y: number, z: number): void => {\n const key = `${x.toFixed(5)},${y.toFixed(5)},${z.toFixed(5)}`\n if (seen.has(key)) return\n seen.add(key)\n pts.push([x, y, z])\n }\n if (flat) {\n for (const x of xs) for (const z of [lo[2], hi[2]]) add(x, lo[1], z)\n for (const z of zs) for (const x of [lo[0], hi[0]]) add(x, lo[1], z)\n } else {\n for (const x of xs) for (const y of [lo[1], hi[1]]) for (const z of [lo[2], hi[2]]) add(x, y, z)\n for (const y of ys) for (const x of [lo[0], hi[0]]) for (const z of [lo[2], hi[2]]) add(x, y, z)\n for (const z of zs) for (const x of [lo[0], hi[0]]) for (const y of [lo[1], hi[1]]) add(x, y, z)\n }\n const tr = o.public.transform\n const pivot = p.spec.pivot\n for (let i = 1; i <= ANGLES; i++) {\n const tt = i / ANGLES\n const angle = m.kind === 'slide' ? 0 : (m.angle ?? Math.PI / 2) * tt\n const d = m.kind === 'slide' ? (m.distance ?? 0.4) * tt : 0\n for (const [x, y, z] of pts) {\n let q: Vec3 = [x, y, z]\n if (angle !== 0) {\n const r = rotateAxis([x - pivot[0], y - pivot[1], z - pivot[2]], axis, angle)\n q = [pivot[0] + r[0], pivot[1] + r[1], pivot[2] + r[2]]\n }\n const w = localToWorld(tr, [q[0] + axis[0] * d, 0, q[2] + axis[2] * d])\n if (blockedAt(w[0], w[2])) return (i - 1) / ANGLES\n }\n }\n return 1\n }\n\n function fitSweep(objectId: string, partId: string, blocked: (x: number, z: number) => boolean): number {\n const o = objectOrThrow(objectId)\n const p = o.parts.get(partId)\n if (!p) throw new Error(`Unknown part \"${partId}\" on \"${objectId}\"`)\n const sweep = p.spec.sweep\n let result = 1\n const bounds = p.spec.bounds\n const mk = p.spec.motion.kind\n if (bounds && (mk === 'hinge' || mk === 'rocker' || mk === 'knob' || mk === 'slide')) {\n result = fitBounds(o, p, bounds, blocked)\n } else if (sweep) {\n const x0 = Math.min(sweep[0], sweep[2])\n const x1 = Math.max(sweep[0], sweep[2])\n const z0 = Math.min(sweep[1], sweep[3])\n const z1 = Math.max(sweep[1], sweep[3])\n const tr = o.public.transform\n const hit = (lx: number, lz: number): boolean => {\n const w = localToWorld(tr, [lx, 0, lz])\n return blocked(w[0], w[2])\n }\n const m = p.spec.motion\n const axis = rotY(m.axis ?? [0, 1, 0], p.spec.ry ?? 0)\n if (m.kind === 'hinge' || m.kind === 'rocker' || m.kind === 'knob') {\n if (Math.abs(axis[1]) >= 0.5) {\n const angle = m.angle ?? Math.PI / 2\n const total = -angle * Math.sign(axis[1])\n const [px, , pz] = p.spec.pivot\n const cx = (x0 + x1) / 2\n const cz = (z0 + z1) / 2\n const w = x1 - x0\n const d = z1 - z0\n const radius = Math.abs(angle) > 1.7 ? Math.min(w, d) : Math.max(w, d)\n const tol = 0.05\n const inRect = (x: number, z: number) => x >= x0 - tol && x <= x1 + tol && z >= z0 - tol && z <= z1 + tol\n const centered = Math.hypot(cx - px, cz - pz) < 1e-6\n const mid = Math.atan2(cz - pz, cx - px)\n for (let i = 1; i <= SWEEP_STEPS && result === 1; i++) {\n const tt = i / SWEEP_STEPS\n let isHit = false\n if (centered) {\n for (let x = x0; x <= x1 + 1e-9 && !isHit; x += 0.1) for (let z = z0; z <= z1 + 1e-9 && !isHit; z += 0.1) isHit = hit(x, z)\n } else {\n const phi = mid - total / 2 + total * tt\n const steps = Math.max(2, Math.ceil(radius / 0.1))\n for (let k = 1; k <= steps && !isHit; k++) {\n const r = (radius * k) / steps\n const x = px + Math.cos(phi) * r\n const z = pz + Math.sin(phi) * r\n if (inRect(x, z)) isHit = hit(x, z)\n }\n }\n if (isHit) result = (i - 1) / SWEEP_STEPS\n }\n }\n } else if (m.kind === 'slide') {\n const len = Math.hypot(axis[0], axis[2])\n if (len > 1e-6) {\n const dx = axis[0] / len\n const dz = axis[2] / len\n const proj = [x0 * dx + z0 * dz, x1 * dx + z0 * dz, x0 * dx + z1 * dz, x1 * dx + z1 * dz]\n const pmin = Math.min(...proj)\n const pmax = Math.max(...proj)\n const nx = Math.max(1, Math.ceil((x1 - x0) / 0.1))\n const nz = Math.max(1, Math.ceil((z1 - z0) / 0.1))\n for (let i = 1; i <= SWEEP_STEPS && result === 1; i++) {\n const limit = pmin + (pmax - pmin) * (i / SWEEP_STEPS)\n let isHit = false\n for (let a = 0; a <= nx && !isHit; a++) {\n for (let b = 0; b <= nz && !isHit; b++) {\n const x = x0 + ((x1 - x0) * a) / nx\n const z = z0 + ((z1 - z0) * b) / nz\n if (x * dx + z * dz <= limit + 1e-9 && hit(x, z)) isHit = true\n }\n }\n if (isHit) result = (i - 1) / SWEEP_STEPS\n }\n }\n }\n }\n p.maxT = result\n if (p.target > result) p.target = result\n if (p.t > result) writeT(o, p, result)\n return result\n }\n\n // ------------------------------------------------------------------ containers\n function containerOf(o: ObjState, id: string) {\n return o.spec.containers?.find((c) => c.id === id)\n }\n\n function accessible(objectId: string, containerId: string): boolean {\n const o = objs.get(objectId)\n if (!o) return false\n const c = containerOf(o, containerId)\n if (!c) return false\n return isOpen(o, c.access)\n }\n\n function contents(objectId: string, containerId: string): Array<ItemStack | null> {\n return (objs.get(objectId)?.contents.get(containerId) ?? []).map(cloneStack)\n }\n\n function take(objectId: string, containerId: string, slot: number, actor: string = DEFAULT_ACTOR): ItemStack | null {\n const o = objs.get(objectId)\n if (!o) return null\n const list = o.contents.get(containerId)\n if (!list || !accessible(objectId, containerId)) return null\n const stack = list[slot]\n if (!stack) return null\n const def = options.items?.[stack.type]\n if (def && def.pickable === false) return null\n list[slot] = null\n emit({ type: 'pickup', object: objectId, container: containerId, slot, stack: cloneStack(stack) as ItemStack, actor })\n return stack\n }\n\n function put(objectId: string, containerId: string, stack: ItemStack): number | null {\n const o = objs.get(objectId)\n if (!o) return null\n const c = containerOf(o, containerId)\n const list = o.contents.get(containerId)\n if (!c || !list || !accessible(objectId, containerId)) return null\n const maxStack = options.items?.[stack.type]?.stack ?? 1\n for (let i = 0; i < list.length; i++) {\n const cur = list[i]\n if (cur && cur.type === stack.type && !cur.data && !stack.data && cur.qty + stack.qty <= maxStack) {\n cur.qty += stack.qty\n return i\n }\n }\n for (let i = 0; i < list.length; i++) {\n if (!list[i] && fitsSlot(stack.type, c.slots[i], options.items)) {\n list[i] = cloneStack(stack)\n return i\n }\n }\n message('full')\n return null\n }\n\n function slotPosition(objectId: string, containerId: string, slot: number): Vec3 {\n const o = objectOrThrow(objectId)\n const c = containerOf(o, containerId)\n const s = c?.slots[slot]\n if (!c || !s) throw new Error(`Unknown slot ${slot} of \"${containerId}\" on \"${objectId}\"`)\n return toWorld(o, applyPart(o, s.part, s.pos))\n }\n\n // ------------------------------------------------------------------ power\n function rebuildPlugs(): void {\n plugs.clear()\n const sockets: Array<{ id: string; pos: Vec3; circuit?: string; local: string }> = []\n for (const o of objs.values()) {\n for (const s of o.spec.sockets ?? []) sockets.push({ id: gid(o, s.id), local: s.id, pos: toWorld(o, s.pos), circuit: s.circuit })\n }\n const used = new Set<string>()\n const autos: Array<{ o: ObjState; d: DeviceState }> = []\n for (const o of objs.values()) {\n for (const d of o.devices.values()) {\n const key = gid(o, d.spec.id)\n const want = d.spec.socket\n if (want === undefined || d.spec.circuit) {\n plugs.set(key, null)\n } else if (want === 'auto') {\n plugs.set(key, null)\n autos.push({ o, d })\n } else {\n const s = sockets.find((x) => x.id === want) ?? sockets.find((x) => x.id === gid(o, want)) ?? sockets.find((x) => x.local === want)\n plugs.set(key, s ? s.id : null)\n if (s) used.add(s.id)\n }\n }\n }\n for (const { o, d } of autos) {\n const from = d.spec.plug ? toWorld(o, d.spec.plug) : originOf(o)\n let best: (typeof sockets)[number] | null = null\n let bestD = AUTO_RANGE\n for (const s of sockets) {\n if (used.has(s.id)) continue\n const dd = dist3(from, s.pos)\n if (dd <= bestD) {\n best = s\n bestD = dd\n }\n }\n if (best) {\n used.add(best.id)\n plugs.set(gid(o, d.spec.id), best.id)\n }\n }\n }\n\n function breaker(circuit: string): boolean {\n return breakers.get(circuit) ?? true\n }\n\n function devicePowered(o: ObjState, d: DeviceState): boolean {\n if (d.spec.electric === false) return true\n if (!grid) return false\n if (d.spec.circuit) return breaker(d.spec.circuit)\n if (d.spec.socket === undefined) return false\n const sid = plugs.get(gid(o, d.spec.id))\n if (!sid) return false\n const found = findGlobal(sid, (oo, local) => oo.spec.sockets?.find((s) => s.id === local))\n if (!found) return false\n return found.value.circuit ? breaker(found.value.circuit) : true\n }\n\n function getDevice(objectId: string, deviceId: string): { o: ObjState; d: DeviceState } | null {\n const o = objs.get(objectId)\n const d = o?.devices.get(deviceId)\n return o && d ? { o, d } : null\n }\n\n function powerSnapshot(): Map<string, boolean> {\n const m = new Map<string, boolean>()\n for (const o of objs.values()) for (const d of o.devices.values()) m.set(gid(o, d.spec.id), d.on && devicePowered(o, d))\n return m\n }\n\n function emitPowerChanges(before: Map<string, boolean>): void {\n for (const o of objs.values()) {\n for (const d of o.devices.values()) {\n const key = gid(o, d.spec.id)\n const now = d.on && devicePowered(o, d)\n if (before.get(key) !== now && d.on) emit({ type: 'device', object: o.id, device: d.spec.id, on: d.on, powered: devicePowered(o, d), channel: d.spec.kind === 'screen' ? d.channel : undefined })\n }\n }\n }\n\n function setDeviceOn(o: ObjState, d: DeviceState, on: boolean): void {\n d.on = on\n if (d.spec.part) setPartTarget(o, d.spec.part, on ? 1 : 0)\n const powered = devicePowered(o, d)\n emit({ type: 'device', object: o.id, device: d.spec.id, on, powered, channel: d.spec.kind === 'screen' ? d.channel : undefined })\n if (on && !powered) message('no_power')\n }\n\n function setDevice(objectId: string, deviceId: string, on: boolean): boolean {\n const f = getDevice(objectId, deviceId)\n if (!f) return false\n if (f.d.on !== on) setDeviceOn(f.o, f.d, on)\n return true\n }\n\n function setFixture(objectId: string, fixtureId: string, on: boolean): boolean {\n const fx = objs.get(objectId)?.fixtures.get(fixtureId)\n if (!fx) return false\n if (fx.on !== on) toggleFixture(objs.get(objectId) as ObjState, fixtureId)\n return fx.on === on\n }\n\n function setBurner(objectId: string, burnerId: string, on: boolean): boolean {\n const o = objs.get(objectId)\n const b = o?.burners.get(burnerId)\n if (!o || !b) return false\n const isOn = b.on || b.lit\n if (on === isOn) return true\n if (!on) return toggleBurner(o, burnerId)\n return b.spec.needsIgnition ? ignite(o, burnerId) : toggleBurner(o, burnerId)\n }\n\n function resolveDevice(o: ObjState, id: string): { o: ObjState; d: DeviceState } | null {\n if (id.includes(':')) {\n const f = findGlobal(id, (oo, local) => oo.devices.get(local))\n return f ? { o: f.o, d: f.value } : null\n }\n const local = o.devices.get(id)\n if (local) return { o, d: local }\n for (const oo of objs.values()) {\n const d = oo.devices.get(id)\n if (d) return { o: oo, d }\n }\n return null\n }\n\n function switchIsOn(o: ObjState, spec: { part?: string; controls: string[] }): boolean {\n if (spec.part && o.parts.has(spec.part)) return targetIsOpen(o.parts.get(spec.part) as PartState)\n return spec.controls.some((id) => resolveDevice(o, id)?.d.on)\n }\n\n function toggleSwitch(o: ObjState, id: string): boolean {\n const sw = o.spec.switches?.find((s) => s.id === id)\n if (!sw) return false\n const on = !switchIsOn(o, sw)\n if (sw.part) setPartTarget(o, sw.part, on ? 1 : 0)\n let unpowered = false\n for (const ref of sw.controls) {\n const r = resolveDevice(o, ref)\n if (!r) continue\n r.d.on = on\n if (r.d.spec.part) setPartTarget(r.o, r.d.spec.part, on ? 1 : 0)\n const powered = devicePowered(r.o, r.d)\n if (on && !powered) unpowered = true\n emit({ type: 'device', object: r.o.id, device: r.d.spec.id, on, powered })\n }\n emit({ type: 'switch', object: o.id, switch: sw.id, on })\n if (unpowered) message('no_power')\n return true\n }\n\n // ------------------------------------------------------------------ fuel\n function resolveFuel(o: ObjState, b: BurnerState): { o: ObjState; f: FuelState } | null {\n const want = b.spec.fuel\n if (want === 'auto') {\n const from = toWorld(o, b.spec.pos)\n let best: { o: ObjState; f: FuelState } | null = null\n let bestD = AUTO_RANGE\n for (const oo of objs.values()) {\n for (const f of oo.fuels.values()) {\n if (f.spec.kind !== 'gas') continue\n const d = dist3(from, originOf(oo))\n if (d <= bestD) {\n best = { o: oo, f }\n bestD = d\n }\n }\n }\n return best\n }\n if (want.includes(':')) {\n const f = findGlobal(want, (oo, local) => oo.fuels.get(local))\n return f ? { o: f.o, f: f.value } : null\n }\n const local = o.fuels.get(want)\n return local ? { o, f: local } : null\n }\n\n function valveOpen(o: ObjState, f: FuelState): boolean {\n const v = f.spec.valve\n if (!v || !o.parts.has(v)) return true\n return targetIsOpen(o.parts.get(v) as PartState)\n }\n\n function canBurn(b: BurnerState, ref: { o: ObjState; f: FuelState } | null): boolean {\n return !!ref && ref.f.level > 0 && valveOpen(ref.o, ref.f)\n }\n\n function isSolid(ref: { f: FuelState } | null): boolean {\n return !!ref && ref.f.spec.kind !== 'gas'\n }\n\n function emitBurner(o: ObjState, b: BurnerState): void {\n emit({ type: 'burner', object: o.id, burner: b.spec.id, on: b.on, lit: b.lit })\n }\n\n function extinguish(o: ObjState, b: BurnerState, turnOff: boolean): void {\n const ref = resolveFuel(o, b)\n const wasLit = b.lit\n b.lit = false\n if (turnOff) b.on = false\n if (b.spec.part) setPartTarget(o, b.spec.part, b.on ? 1 : 0)\n if (wasLit && isSolid(ref)) b.smoke = SMOKE_TAIL\n emitBurner(o, b)\n }\n\n function toggleBurner(o: ObjState, id: string): boolean {\n const b = o.burners.get(id)\n if (!b) return false\n if (b.on || b.lit) {\n extinguish(o, b, true)\n return true\n }\n if (b.spec.needsIgnition) return false\n const ref = resolveFuel(o, b)\n b.on = true\n b.lit = canBurn(b, ref)\n if (b.lit) b.smoke = 0\n if (b.spec.part) setPartTarget(o, b.spec.part, 1)\n emitBurner(o, b)\n if (!b.lit) message(ref && ref.f.level <= 0 ? 'empty' : 'no_gas')\n return true\n }\n\n function ignite(o: ObjState, id: string): boolean {\n const b = o.burners.get(id)\n if (!b || b.lit) return false\n const ref = resolveFuel(o, b)\n if (!canBurn(b, ref)) {\n message(ref && ref.f.level <= 0 ? 'empty' : 'no_gas')\n return false\n }\n b.on = true\n b.lit = true\n b.smoke = 0\n if (b.spec.part) setPartTarget(o, b.spec.part, 1)\n emitBurner(o, b)\n return true\n }\n\n function toggleFuel(o: ObjState, id: string): boolean {\n const f = o.fuels.get(id)\n if (!f || !f.spec.valve || !o.parts.has(f.spec.valve)) return false\n const p = o.parts.get(f.spec.valve) as PartState\n setPartTarget(o, f.spec.valve, targetIsOpen(p) ? 0 : 1)\n return true\n }\n\n // ------------------------------------------------------------------ water\n function resolveTank(o: ObjState, id: string | undefined): { o: ObjState; t: TankState } | null {\n const want = id === undefined || id === 'auto' ? defaultTank : id\n if (!want) return null\n const f = findGlobal(want, (oo, local) => oo.tanks.get(local))\n if (f) return { o: f.o, t: f.value }\n const local = o.tanks.get(want)\n return local ? { o, t: local } : null\n }\n\n function drawWater(o: ObjState, fx: FixtureState, liters: number): number {\n if (liters <= 0) return 0\n if (options.waterSupply) return Math.max(0, Math.min(liters, options.waterSupply.draw(gid(o, fx.spec.id), liters)))\n const tank = resolveTank(o, fx.spec.tank)\n if (!tank) return 0\n const got = Math.min(liters, tank.t.level)\n tank.t.level -= got\n return got\n }\n\n function emitFixture(o: ObjState, fx: FixtureState): void {\n emit({ type: 'fixture', object: o.id, fixture: fx.spec.id, on: fx.on, flowing: fx.flowing })\n }\n\n function flowOf(fx: FixtureState): number {\n return fx.spec.flow ?? FLOW_DEFAULTS[fx.spec.kind] ?? 6\n }\n\n function stepFixture(o: ObjState, fx: FixtureState, dt: number): void {\n if (!fx.on) return\n if (fx.spec.kind === 'flush') {\n fx.timer -= dt\n if (fx.timer <= 0) {\n fx.on = false\n fx.flowing = false\n fx.frac = 0\n if (fx.spec.part) setPartTarget(o, fx.spec.part, 0)\n emitFixture(o, fx)\n }\n return\n }\n if (dt <= 0) return\n const wanted = (flowOf(fx) / 60) * dt\n const got = drawWater(o, fx, wanted)\n const flowing = got > 1e-9\n fx.frac = wanted > 0 ? Math.min(1, got / wanted) : 0\n if (flowing !== fx.flowing) {\n fx.flowing = flowing\n emitFixture(o, fx)\n }\n }\n\n function toggleFixture(o: ObjState, id: string): boolean {\n const fx = o.fixtures.get(id)\n if (!fx) return false\n if (fx.on) {\n fx.on = false\n fx.flowing = false\n fx.frac = 0\n if (fx.spec.part) setPartTarget(o, fx.spec.part, 0)\n emitFixture(o, fx)\n return true\n }\n fx.on = true\n if (fx.spec.part) setPartTarget(o, fx.spec.part, 1)\n if (fx.spec.kind === 'flush') {\n const volume = fx.spec.volume ?? 6\n const got = drawWater(o, fx, volume)\n fx.flowing = got > 1e-9\n fx.frac = fx.flowing ? 1 : 0\n fx.timer = FLUSH_SECONDS\n if (!fx.flowing) {\n fx.on = false\n if (fx.spec.part) setPartTarget(o, fx.spec.part, 0)\n }\n } else {\n fx.flowing = false\n fx.frac = 0\n stepFixture(o, fx, 1 / 60)\n }\n emitFixture(o, fx)\n if (!fx.flowing) message('no_water')\n return true\n }\n\n // ------------------------------------------------------------------ seats\n function seatTaken(objectId: string, seatId: string): string | null {\n for (const [actor, s] of seats) if (s.object === objectId && s.seat === seatId) return actor\n return null\n }\n\n function stand(actor: string = DEFAULT_ACTOR): Vec3 | null {\n const s = seats.get(actor)\n if (!s) return null\n seats.delete(actor)\n const o = objs.get(s.object)\n const spec = o?.spec.seats?.find((x) => x.id === s.seat)\n emit({ type: 'seat', object: s.object, seat: s.seat, actor, seated: false })\n if (!o || !spec) return null\n return toWorld(o, spec.exit)\n }\n\n function sit(objectId: string, seatId: string, actor: string = DEFAULT_ACTOR): SeatResult | null {\n const o = objs.get(objectId)\n const seat = o?.spec.seats?.find((s) => s.id === seatId)\n if (!o || !seat) return null\n const holder = seatTaken(objectId, seatId)\n if (holder && holder !== actor) return null\n if (seats.has(actor) && !holder) stand(actor)\n seats.set(actor, { object: objectId, seat: seatId })\n const eye = seat.eye ?? (seat.pose === 'lie' ? 0.18 : 0.62)\n emit({ type: 'seat', object: objectId, seat: seatId, actor, seated: true })\n return { eye: toWorld(o, [seat.pos[0], seat.pos[1] + eye, seat.pos[2]]), yaw: o.public.transform.ry + seat.ry + Math.PI, pose: seat.pose }\n }\n\n // ------------------------------------------------------------------ soft volumes\n function push(pos: Vec3, radius: number, vel: Vec3): void {\n for (const o of objs.values()) {\n if (!o.soft.size) continue\n const tr = o.public.transform\n const lp = worldToLocal(tr, pos)\n const lv = rotY(vel, -tr.ry)\n for (const s of o.soft.values()) {\n const [w, h, d] = s.spec.size\n const hx = w / 2\n const hz = Math.max(d, 0.1) / 2\n const dx = Math.max(Math.abs(lp[0] - s.spec.anchor[0]) - hx, 0)\n const dz = Math.max(Math.abs(lp[2] - s.spec.anchor[2]) - hz, 0)\n if (Math.hypot(dx, dz) > radius) continue\n const top = tr.y + s.spec.anchor[1]\n if (pos[1] + ACTOR_HEIGHT < top - h || pos[1] > top) continue\n const cap = 8\n s.vax = clamp(s.vax - lv[2] * PUSH_GAIN, -cap, cap)\n s.vaz = clamp(s.vaz + lv[0] * PUSH_GAIN, -cap, cap)\n if (s.spec.kind === 'panel' && s.spec.part && lv[2] < -0.05 && lp[2] > s.spec.anchor[2]) setPartTarget(o, s.spec.part, 1)\n }\n }\n }\n\n function stepSoft(dt: number): void {\n const sub = Math.max(1, Math.ceil(dt / (1 / 120)))\n const h = dt / sub\n for (const o of objs.values()) {\n if (!o.soft.size) continue\n const wl = rotY([wind[0], 0, wind[1]], -o.public.transform.ry)\n for (const s of o.soft.values()) {\n const k = s.spec.stiffness ?? 30\n const c = s.spec.damping ?? 4\n const max = s.spec.maxAngle ?? 0.7\n const gain = s.spec.wind ?? (s.spec.kind === 'panel' ? 0 : 1)\n const gust = gain * (0.6 + 0.4 * Math.sin(time * 1.7 + s.phase)) * 0.1\n const fx = -wl[2] * gust\n const fz = wl[0] * gust\n for (let i = 0; i < sub; i++) {\n s.vax += (-k * s.ax - c * s.vax + fx) * h\n s.vaz += (-k * s.az - c * s.vaz + fz) * h\n s.ax += s.vax * h\n s.az += s.vaz * h\n }\n if (Math.abs(s.ax) > max) {\n s.ax = Math.sign(s.ax) * max\n s.vax = 0\n }\n if (Math.abs(s.az) > max) {\n s.az = Math.sign(s.az) * max\n s.vaz = 0\n }\n }\n }\n }\n\n // ------------------------------------------------------------------ damage\n function damage(objectId: string, target: string, amount: number, _kind?: string): { hp: number; destroyed: boolean } | null {\n const o = objs.get(objectId)\n if (o && options.destruction) {\n const pos = toWorld(o, [0, 0.5, 0])\n const type = _kind === 'gas' ? 'explosive' : _kind === 'fabric' ? 'slash' : 'blunt'\n const result = options.destruction.hitPart(objectId, target, { type, point: pos, energy: Math.max(0, amount), source: 'interactables' }) as { events?: Array<{ type?: string; part?: string }> } | null | undefined\n const destroyed = !!result?.events?.some((e) => e.type === 'fracture' && e.part === target)\n emit({ type: 'damage', object: objectId, target, hp: -1, destroyed })\n return { hp: -1, destroyed }\n }\n const st = o?.hp.get(target)\n if (!o || !st) return null\n if (st.hp <= 0) return { hp: 0, destroyed: true }\n const before = st.hp\n st.hp = Math.max(0, st.hp - Math.max(0, amount))\n const destroyed = st.hp <= 0\n emit({ type: 'damage', object: objectId, target, hp: st.hp, destroyed })\n const pos = toWorld(o, [0, 0.5, 0])\n const fuel = o.fuels.get(target)\n if (fuel && destroyed && fuel.spec.kind === 'gas' && fuel.level > 0) {\n emit({ type: 'explosion', object: objectId, pos, radius: 2 + fuel.level / 5 })\n fuel.level = 0\n }\n const tank = o.tanks.get(target)\n if (tank && before === st.max && st.hp < before) emit({ type: 'leak', object: objectId, target, pos })\n return { hp: st.hp, destroyed }\n }\n\n // ------------------------------------------------------------------ interactions\n function deriveInteractions(spec: ObjectSpec): InteractionSpec[] {\n const out: InteractionSpec[] = []\n const used = new Set<string>()\n const partPos = (id: string | undefined, fallback: Vec3): Vec3 => spec.parts?.find((p) => p.id === id)?.pivot ?? fallback\n const partLabel = (id: string | undefined): string => spec.parts?.find((p) => p.id === id)?.label ?? ''\n const claim = (id: string | undefined) => {\n if (id) used.add(id)\n }\n for (const d of spec.devices ?? []) {\n claim(d.part)\n const pos = d.part ? partPos(d.part, [0, 1, 0]) : (d.plug ?? [0, 1, 0])\n // a hard-wired lamp (circuit, no plug, no part to press) is driven by switches and `setDevice`: it never steals the interact key\n if (d.kind === 'lamp' && !d.part && !d.plug && d.electric !== false) continue\n out.push({ id: `device.${d.id}`, pos, action: { do: 'toggle_device', device: d.id }, label: partLabel(d.part) })\n if (d.kind === 'screen' && (d.channels ?? 1) > 1) out.push({ id: `channel.${d.id}`, pos, action: { do: 'cycle_device', device: d.id }, label: '' })\n }\n for (const s of spec.switches ?? []) {\n claim(s.part)\n out.push({ id: `switch.${s.id}`, pos: partPos(s.part, [0, 1.2, 0]), action: { do: 'toggle_switch', switch: s.id }, label: partLabel(s.part) })\n }\n const driven = new Set((spec.devices ?? []).map((d) => d.fixture))\n for (const f of spec.fixtures ?? []) {\n claim(f.part)\n if (driven.has(f.id)) continue\n out.push({ id: `fixture.${f.id}`, pos: f.part ? partPos(f.part, f.outlet) : f.outlet, action: { do: 'toggle_fixture', fixture: f.id }, label: partLabel(f.part) })\n }\n for (const b of spec.burners ?? []) {\n claim(b.part)\n const pos = b.part ? partPos(b.part, b.pos) : b.pos\n if (b.needsIgnition) out.push({ id: `ignite.${b.id}`, pos, action: { do: 'ignite', burner: b.id }, label: '' })\n out.push({ id: `burner.${b.id}`, pos, action: { do: 'toggle_burner', burner: b.id }, label: partLabel(b.part) })\n }\n for (const f of spec.fuels ?? []) {\n if (!f.valve) continue\n claim(f.valve)\n out.push({ id: `fuel.${f.id}`, pos: partPos(f.valve, [0, 0.5, 0]), action: { do: 'toggle_fuel', fuel: f.id }, label: partLabel(f.valve) })\n }\n for (const c of spec.containers ?? []) {\n if (!c.access) out.push({ id: `open.${c.id}`, pos: c.volume.center, action: { do: 'open_container', container: c.id }, label: '' })\n }\n for (const p of spec.parts ?? []) {\n if (used.has(p.id)) continue\n if (p.label) out.push({ id: `part.${p.id}`, pos: p.pivot, action: { do: 'toggle_part', part: p.id }, label: p.label })\n }\n for (const c of spec.containers ?? []) {\n if (c.access && !spec.parts?.find((p) => p.id === c.access)?.label) {\n out.push({ id: `open.${c.id}`, pos: partPos(c.access, c.volume.center), action: { do: 'open_container', container: c.id }, label: '' })\n }\n }\n for (const s of spec.seats ?? []) out.push({ id: `seat.${s.id}`, pos: s.pos, action: { do: 'sit', seat: s.id }, label: '' })\n return out\n }\n\n function typeName(o: ObjState): string {\n return table[`type.${o.spec.type}`] ?? humanize(o.spec.type)\n }\n\n function promptOf(o: ObjState, i: InteractionSpec): { label: string; verb: string; object: string } {\n const a = i.action\n let state: string | null = null\n let def = ''\n switch (a.do) {\n case 'toggle_part': {\n const p = o.parts.get(a.part)\n const open = !!p && targetIsOpen(p)\n state = open ? 'open' : 'closed'\n def = open ? 'prompt.close' : 'prompt.open'\n break\n }\n case 'open_container': {\n const c = containerOf(o, a.container)\n const p = c?.access ? o.parts.get(c.access) : undefined\n const open = p ? targetIsOpen(p) : false\n state = p ? (open ? 'open' : 'closed') : null\n def = open ? 'prompt.close' : 'prompt.open'\n break\n }\n case 'toggle_device': {\n const on = !!o.devices.get(a.device)?.on\n state = on ? 'on' : 'off'\n def = on ? 'prompt.turn_off' : 'prompt.turn_on'\n break\n }\n case 'toggle_switch': {\n const sw = o.spec.switches?.find((s) => s.id === a.switch)\n const on = !!sw && switchIsOn(o, sw)\n state = on ? 'on' : 'off'\n def = on ? 'prompt.turn_off' : 'prompt.turn_on'\n break\n }\n case 'toggle_breaker': {\n const on = breaker(a.circuit)\n state = on ? 'on' : 'off'\n def = on ? 'prompt.breaker_off' : 'prompt.breaker_on'\n break\n }\n case 'toggle_fixture': {\n const on = !!o.fixtures.get(a.fixture)?.on\n state = on ? 'on' : 'off'\n def = on ? 'prompt.turn_off' : 'prompt.turn_on'\n break\n }\n case 'toggle_burner': {\n const b = o.burners.get(a.burner)\n const on = !!b && (b.on || b.lit)\n state = on ? 'on' : 'off'\n def = on ? 'prompt.turn_off' : 'prompt.turn_on'\n break\n }\n case 'toggle_fuel': {\n const f = o.fuels.get(a.fuel)\n const open = !!f && valveOpen(o, f)\n state = open ? 'open' : 'closed'\n def = open ? 'prompt.close_valve' : 'prompt.open_valve'\n break\n }\n case 'take':\n def = 'prompt.take'\n break\n case 'read':\n def = 'prompt.read'\n break\n case 'ignite':\n def = 'prompt.light'\n break\n case 'cycle_device':\n def = 'prompt.change_channel'\n break\n case 'sit': {\n const seat = o.spec.seats?.find((s) => s.id === a.seat)\n const mine = seats.get(DEFAULT_ACTOR)\n def = mine && mine.object === o.id && mine.seat === a.seat ? 'prompt.get_up' : seat?.pose === 'lie' ? 'prompt.lie_down' : 'prompt.sit'\n break\n }\n }\n let key = def\n if (i.label) {\n if (state && table[`${i.label}.${state}`] !== undefined) key = `${i.label}.${state}`\n else if (table[i.label] !== undefined) key = i.label\n }\n const vars = { name: typeName(o), circuit: a.do === 'toggle_breaker' ? (a.name ?? a.circuit) : '' }\n const label = t(key, vars)\n // structured prompt: explicit `<key>.verb` / `<key>.object` entries win; otherwise the first word is the verb and the rest the object\n let verb: string\n let object: string\n if (table[`${key}.verb`] !== undefined) {\n verb = t(`${key}.verb`, vars)\n object = table[`${key}.object`] ? t(`${key}.object`, vars) : vars.name\n } else {\n const sp = label.indexOf(' ')\n verb = sp < 0 ? label : label.slice(0, sp)\n object = sp < 0 ? vars.name : label.slice(sp + 1)\n }\n return { label, verb, object }\n }\n\n /** Locale key of the reason an interaction cannot be used right now, or null when it can. */\n function unavailableReason(o: ObjState, i: InteractionSpec): string | null {\n const a = i.action\n if (!requirementMet(i)) return 'requires_open'\n switch (a.do) {\n case 'toggle_part': {\n const p = o.parts.get(a.part)\n return p && gated(o, p) ? 'requires_open' : null\n }\n case 'open_container': {\n const c = containerOf(o, a.container)\n const p = c?.access ? o.parts.get(c.access) : undefined\n return p && gated(o, p) ? 'requires_open' : null\n }\n case 'toggle_breaker': {\n const rocker = a.part ? o.parts.get(a.part) : undefined\n return rocker && gated(o, rocker) ? 'requires_open' : null\n }\n case 'take':\n case 'read':\n return accessible(o.id, a.container) ? null : 'requires_open'\n case 'ignite':\n return o.burners.get(a.burner)?.lit ? 'already_lit' : null\n case 'toggle_burner': {\n const b = o.burners.get(a.burner)\n return !b?.spec.needsIgnition || b.lit ? null : 'needs_ignition'\n }\n case 'cycle_device': {\n const d = o.devices.get(a.device)\n if (!d || !d.on) return 'turn_on_first'\n return devicePowered(o, d) ? null : 'no_power'\n }\n default:\n return null\n }\n }\n\n function requirementMet(i: InteractionSpec): boolean {\n if (!i.requires) return true\n const p = objs.get(i.requires.object)?.parts.get(i.requires.part)\n return !!p && targetIsOpen(p)\n }\n\n function interactablesOf(o: ObjState): Array<{ item: Interactable; spec: InteractionSpec; o: ObjState }> {\n return o.interactions.map((i) => {\n const id = gid(o, i.id)\n const p = promptOf(o, i)\n const item: Interactable = {\n id,\n object: o.id,\n kind: i.action.do,\n pos: toWorld(o, i.pos),\n radius: i.radius ?? DEFAULT_RADIUS,\n label: p.label,\n verb: p.verb,\n noun: p.object,\n available: true,\n act: (actor) => act(id, actor),\n }\n const reason = unavailableReason(o, i) ?? (options.canInteract?.(item, DEFAULT_ACTOR) === false ? 'locked' : null)\n if (reason) {\n item.available = false\n item.reason = reason\n }\n return { item, spec: i, o }\n })\n }\n\n function interactables(): Interactable[] {\n const out: Interactable[] = []\n for (const o of objs.values()) for (const e of interactablesOf(o)) out.push(e.item)\n return out\n }\n\n function target(eye: { x: number; y: number; z: number; yaw: number; pitch: number }, opts: TargetOptions = {}): Interactable | null {\n const reach = opts.reach ?? 1.8\n const cone = opts.cone ?? 0.45\n const dir: Vec3 = [-Math.sin(eye.yaw) * Math.cos(eye.pitch), Math.sin(eye.pitch), -Math.cos(eye.yaw) * Math.cos(eye.pitch)]\n let best: Interactable | null = null\n let bestScore = Infinity\n for (const o of objs.values()) {\n for (const e of interactablesOf(o)) {\n if (!e.item.available && !opts.includeUnavailable) continue\n if (opts.kinds && !opts.kinds.includes(e.item.kind)) continue\n if (opts.filter && !opts.filter(e.item)) continue\n const v: Vec3 = [e.item.pos[0] - eye.x, e.item.pos[1] - eye.y, e.item.pos[2] - eye.z]\n const d = Math.hypot(v[0], v[1], v[2])\n if (d > reach) continue\n const cos = d < 1e-6 ? 1 : clamp((v[0] * dir[0] + v[1] * dir[1] + v[2] * dir[2]) / d, -1, 1)\n const angle = Math.acos(cos)\n if (angle > cone) continue\n const score = (angle / cone) * 0.6 + (d / reach) * 0.4\n if (score < bestScore) {\n bestScore = score\n best = e.item\n }\n }\n }\n return best\n }\n\n function act(interactableId: string, actor: string = DEFAULT_ACTOR): boolean {\n let found: { item: Interactable; spec: InteractionSpec; o: ObjState } | null = null\n for (const o of objs.values()) {\n if (!interactableId.startsWith(o.id + ':')) continue\n const local = interactableId.slice(o.id.length + 1)\n if (!o.interactions.some((i) => i.id === local)) continue\n found = interactablesOf(o).find((e) => e.spec.id === local) ?? null\n if (found) break\n }\n if (!found) return false\n if (!requirementMet(found.spec)) return false\n if (options.canInteract?.(found.item, actor) === false) return false\n return execute(found.o, found.spec.action, actor)\n }\n\n function execute(o: ObjState, a: InteractionSpec['action'], actor: string): boolean {\n switch (a.do) {\n case 'toggle_part': {\n const p = o.parts.get(a.part)\n if (!p || gated(o, p)) return false\n setPartTarget(o, a.part, targetIsOpen(p) ? 0 : 1)\n return true\n }\n case 'open_container': {\n const c = containerOf(o, a.container)\n if (!c) return false\n if (c.access) return execute(o, { do: 'toggle_part', part: c.access }, actor)\n emit({ type: 'container', object: o.id, container: c.id, open: true })\n return true\n }\n case 'take': {\n if (!accessible(o.id, a.container)) return false\n const list = o.contents.get(a.container)\n if (!list) return false\n const slot = a.slot ?? list.findIndex((s) => s !== null)\n if (slot < 0 || !list[slot]) {\n message('empty')\n return false\n }\n return take(o.id, a.container, slot, actor) !== null\n }\n case 'read': {\n if (!accessible(o.id, a.container)) return false\n const stack = o.contents.get(a.container)?.[a.slot]\n if (!stack) {\n message('empty')\n return false\n }\n const key = typeof stack.data?.text === 'string' ? stack.data.text : null\n if (!key) return false\n message(key)\n return true\n }\n case 'toggle_device': {\n const d = o.devices.get(a.device)\n if (!d) return false\n setDeviceOn(o, d, !d.on)\n return true\n }\n case 'cycle_device': {\n const d = o.devices.get(a.device)\n if (!d || !d.on) return false\n if (!devicePowered(o, d)) {\n message('no_power')\n return false\n }\n d.channel = (d.channel + 1) % Math.max(1, d.spec.channels ?? 1)\n emit({ type: 'device', object: o.id, device: d.spec.id, on: true, powered: true, channel: d.channel })\n return true\n }\n case 'toggle_switch':\n return toggleSwitch(o, a.switch)\n case 'toggle_breaker': {\n const rocker = a.part ? o.parts.get(a.part) : undefined\n if (rocker && gated(o, rocker)) return false\n const on = !breaker(a.circuit)\n if (a.part) setPartTarget(o, a.part, on ? 1 : 0)\n world.power.setBreaker(a.circuit, on)\n return true\n }\n case 'toggle_fixture':\n return toggleFixture(o, a.fixture)\n case 'toggle_burner':\n return toggleBurner(o, a.burner)\n case 'ignite':\n return ignite(o, a.burner)\n case 'toggle_fuel':\n return toggleFuel(o, a.fuel)\n case 'sit': {\n const mine = seats.get(actor)\n if (mine && mine.object === o.id && mine.seat === a.seat) {\n stand(actor)\n return true\n }\n return sit(o.id, a.seat, actor) !== null\n }\n }\n }\n\n // ------------------------------------------------------------------ emitters, mirrors, colliders\n function emitters(): ActiveEmitter[] {\n const out: ActiveEmitter[] = []\n for (const o of objs.values()) {\n for (const e of o.spec.emitters ?? []) {\n let intensity = 0\n const b = o.burners.get(e.source)\n const fx = o.fixtures.get(e.source)\n const dev = o.devices.get(e.source)\n const fuel = o.fuels.get(e.source)\n if (b) {\n const ref = resolveFuel(o, b)\n const frac = ref ? clamp(ref.f.level / ref.f.spec.capacity, 0, 1) : 0\n if (b.lit) intensity = 0.35 + 0.65 * frac\n else if (e.kind === 'smoke' && b.smoke > 0) intensity = 0.6 * (b.smoke / SMOKE_TAIL)\n } else if (fx) {\n if (fx.on && fx.flowing) intensity = fx.frac\n } else if (dev) {\n if (dev.on && devicePowered(o, dev)) intensity = 1\n } else if (fuel) {\n const lit = [...o.burners.values()].some((bb) => bb.lit && resolveFuel(o, bb)?.f === fuel)\n if (lit) intensity = 0.35 + 0.65 * clamp(fuel.level / fuel.spec.capacity, 0, 1)\n }\n if (intensity <= 0) continue\n const dir = rotY(e.dir ?? [0, 1, 0], o.public.transform.ry)\n out.push({ id: gid(o, e.id), object: o.id, kind: e.kind, pos: toWorld(o, e.pos), dir, size: e.size ?? 0.3, ...(e.reach !== undefined ? { reach: e.reach } : {}), intensity: clamp(intensity, 0, 1) })\n }\n }\n return out\n }\n\n function mirrors(eye: Vec3, maxDistance = 10, count = 4) {\n const out: Array<{ id: string; center: Vec3; normal: Vec3; w: number; h: number; distance: number }> = []\n for (const o of objs.values()) {\n for (const m of o.spec.mirrors ?? []) {\n const center = toWorld(o, applyPart(o, m.part, m.center))\n const f = partFrame(o, m.part)\n const ln = f && f.angle !== 0 ? rotateAxis(m.normal, f.axis, f.angle) : m.normal\n const normal = rotY(ln, o.public.transform.ry)\n const len = Math.hypot(normal[0], normal[1], normal[2]) || 1\n const n: Vec3 = [normal[0] / len, normal[1] / len, normal[2] / len]\n const to: Vec3 = [eye[0] - center[0], eye[1] - center[1], eye[2] - center[2]]\n if (n[0] * to[0] + n[1] * to[1] + n[2] * to[2] <= 0) continue\n const distance = Math.hypot(to[0], to[1], to[2])\n if (distance > maxDistance) continue\n out.push({ id: gid(o, m.id), center, normal: n, w: m.w, h: m.h, distance })\n }\n }\n return out.sort((a, b) => a.distance - b.distance).slice(0, count)\n }\n\n function colliders(opts: ColliderOptions = {}): WorldCollider[] {\n const out: WorldCollider[] = []\n const fixed: WorldCollider[] = []\n for (const o of objs.values()) {\n const tr = o.public.transform\n for (const c of o.spec.colliders ?? []) {\n if (c.part && c.offWhenOpen && (o.parts.get(c.part)?.t ?? 0) > 0.5) continue\n let extra = 0\n if (c.part) {\n const f = partFrame(o, c.part)\n if (f && f.angle !== 0 && Math.abs(f.axis[1]) >= 0.5) extra = f.angle * Math.sign(f.axis[1])\n }\n const center = toWorld(o, applyPart(o, c.part, c.center))\n ;(c.part ? out : fixed).push({\n id: gid(o, c.id),\n object: o.id,\n cx: center[0],\n cz: center[2],\n hw: c.half[0],\n hd: c.half[2],\n ry: tr.ry + (c.ry ?? 0) + extra,\n y0: center[1] - c.half[1],\n y1: center[1] + c.half[1],\n })\n }\n }\n if (opts.merge) return [...mergeColliders(fixed, { gap: opts.gap, slack: opts.slack }), ...out]\n return [...fixed, ...out]\n }\n\n // ------------------------------------------------------------------ update\n function update(dt: number): void {\n if (!(dt > 0)) return\n time += dt\n for (const o of objs.values()) {\n for (const p of o.parts.values()) {\n if (p.t === p.target) continue\n if (gated(o, p) && p.target > p.t) continue // a gated part may still close\n const step = (p.spec.motion.speed ?? 2.5) * dt\n const next = p.t < p.target ? Math.min(p.target, p.t + step) : Math.max(p.target, p.t - step)\n writeT(o, p, next)\n if (next === p.target) emit({ type: 'part', object: o.id, part: p.spec.id, t: next, target: p.target })\n }\n }\n stepSoft(dt)\n for (const o of objs.values()) {\n for (const b of o.burners.values()) {\n if (b.lit) {\n const ref = resolveFuel(o, b)\n if (!ref || !valveOpen(ref.o, ref.f)) {\n extinguish(o, b, !!b.spec.needsIgnition)\n } else {\n ref.f.level = Math.max(0, ref.f.level - b.spec.rate * dt)\n if (ref.f.level <= 0) extinguish(o, b, !!b.spec.needsIgnition)\n }\n } else if (b.on && !b.spec.needsIgnition && canBurn(b, resolveFuel(o, b))) {\n // a gas knob left open without gas lights as soon as the bottle valve opens\n b.lit = true\n b.smoke = 0\n emitBurner(o, b)\n } else if (b.smoke > 0) {\n b.smoke = Math.max(0, b.smoke - dt)\n }\n }\n if (rain > 0) {\n for (const tk of o.tanks.values()) {\n if (tk.spec.rainArea) tk.level = Math.min(tk.spec.capacity, tk.level + ((rain * tk.spec.rainArea) / 3600) * dt)\n }\n }\n for (const tk of o.tanks.values()) {\n const st = o.hp.get(tk.spec.id)\n if (st && st.hp < st.max && tk.level > 0) {\n const rate = 0.5 + 2.5 * (1 - st.hp / st.max)\n tk.level = Math.max(0, tk.level - rate * dt)\n }\n }\n }\n for (const o of objs.values()) {\n for (const d of o.devices.values()) {\n const fx = d.spec.fixture ? o.fixtures.get(d.spec.fixture) : undefined\n if (!fx) continue\n const run = d.on && devicePowered(o, d)\n if (fx.on === run) continue\n fx.on = run\n if (!run) {\n fx.flowing = false\n fx.frac = 0\n emitFixture(o, fx)\n }\n }\n for (const fx of o.fixtures.values()) stepFixture(o, fx, dt)\n }\n }\n\n // ------------------------------------------------------------------ add / remove\n function add(id: string, spec: ObjectSpec, transform: Transform): WorldObject {\n if (objs.has(id)) throw new Error(`Object \"${id}\" already exists`)\n const pub: WorldObject = { id, spec, transform: { ...transform }, parts: {} }\n const o: ObjState = {\n id,\n public: pub,\n spec,\n parts: new Map(),\n contents: new Map(),\n devices: new Map(),\n fuels: new Map(),\n burners: new Map(),\n tanks: new Map(),\n fixtures: new Map(),\n soft: new Map(),\n hp: new Map(),\n interactions: spec.interactions ?? deriveInteractions(spec),\n }\n for (const p of spec.parts ?? []) {\n const t0 = clamp(p.t0 ?? 0, 0, 1)\n o.parts.set(p.id, { spec: p, t: t0, target: t0, maxT: 1 })\n pub.parts[p.id] = t0\n }\n for (const c of spec.containers ?? []) {\n let list: Array<ItemStack | null>\n if (c.contents) list = c.slots.map((_, i) => cloneStack(c.contents?.[i] ?? null))\n else if (c.loot) list = generateLoot(options.loot, c.loot, c.slots, `${seed}|${id}|${c.id}`, options.items)\n else list = c.slots.map(() => null)\n o.contents.set(c.id, list)\n }\n for (const d of spec.devices ?? []) {\n o.devices.set(d.id, { spec: d, on: !!d.on, channel: 0 })\n if (d.on && d.part) {\n const p = o.parts.get(d.part)\n if (p) {\n p.target = p.maxT\n writeT(o, p, p.maxT)\n }\n }\n }\n for (const f of spec.fuels ?? []) o.fuels.set(f.id, { spec: f, level: clamp(f.level ?? f.capacity, 0, f.capacity) })\n for (const b of spec.burners ?? []) o.burners.set(b.id, { spec: b, on: false, lit: false, smoke: 0 })\n for (const tk of spec.tanks ?? []) o.tanks.set(tk.id, { spec: tk, level: clamp(tk.level ?? tk.capacity, 0, tk.capacity) })\n for (const f of spec.fixtures ?? []) o.fixtures.set(f.id, { spec: f, on: false, flowing: false, frac: 0, timer: 0 })\n let n = 0\n for (const s of spec.soft ?? []) {\n o.soft.set(s.id, { spec: s, ax: 0, az: 0, vax: 0, vaz: 0, phase: (n++ * 2.399963) % (Math.PI * 2) })\n }\n for (const d of spec.damage ?? []) o.hp.set(d.target, { max: d.hp, hp: d.hp })\n objs.set(id, o)\n if (!defaultTankExplicit && defaultTank === null && o.tanks.size) defaultTank = gid(o, [...o.tanks.keys()][0])\n rebuildPlugs()\n return pub\n }\n\n function remove(id: string): void {\n const o = objs.get(id)\n if (!o) return\n for (const [actor, s] of [...seats]) if (s.object === id) seats.delete(actor)\n objs.delete(id)\n if (defaultTank && defaultTank.startsWith(id + ':')) defaultTank = null\n rebuildPlugs()\n }\n\n // ------------------------------------------------------------------ save / load\n function serialize(): WorldState {\n const objects: WorldState['objects'] = {}\n for (const o of objs.values()) {\n objects[o.id] = {\n parts: Object.fromEntries([...o.parts].map(([k, p]) => [k, p.t])),\n contents: Object.fromEntries([...o.contents].map(([k, v]) => [k, v.map(cloneStack)])),\n devices: Object.fromEntries([...o.devices].map(([k, d]) => [k, { on: d.on, channel: d.channel }])),\n fuels: Object.fromEntries([...o.fuels].map(([k, f]) => [k, { level: f.level, open: valveOpen(o, f) }])),\n burners: Object.fromEntries([...o.burners].map(([k, b]) => [k, { on: b.on, lit: b.lit }])),\n tanks: Object.fromEntries([...o.tanks].map(([k, tk]) => [k, tk.level])),\n fixtures: Object.fromEntries([...o.fixtures].map(([k, f]) => [k, f.on])),\n hp: Object.fromEntries([...o.hp].map(([k, h]) => [k, h.hp])),\n }\n }\n return {\n version: 1,\n objects,\n grid,\n breakers: Object.fromEntries(breakers),\n seats: Object.fromEntries([...seats].map(([a, s]) => [a, { object: s.object, seat: s.seat }])),\n defaultTank,\n }\n }\n\n function load(state: WorldState): void {\n for (const [id, st] of Object.entries(state.objects)) {\n const o = objs.get(id)\n if (!o) continue\n for (const [k, v] of Object.entries(st.parts)) {\n const p = o.parts.get(k)\n if (p) {\n // keep the limit found by fitSweep: a loaded save must not let a door open through a wall again\n p.target = clamp(v, 0, p.maxT)\n writeT(o, p, p.target)\n }\n }\n for (const [k, v] of Object.entries(st.contents)) {\n const c = containerOf(o, k)\n if (c) o.contents.set(k, c.slots.map((_, i) => cloneStack(v[i] ?? null)))\n }\n for (const [k, v] of Object.entries(st.devices)) {\n const d = o.devices.get(k)\n if (d) {\n d.on = v.on\n d.channel = v.channel\n }\n }\n for (const [k, v] of Object.entries(st.fuels)) {\n const f = o.fuels.get(k)\n if (f) f.level = v.level\n }\n for (const [k, v] of Object.entries(st.burners)) {\n const b = o.burners.get(k)\n if (b) {\n b.on = v.on\n b.lit = v.lit\n b.smoke = 0\n }\n }\n for (const [k, v] of Object.entries(st.tanks)) {\n const tk = o.tanks.get(k)\n if (tk) tk.level = v\n }\n for (const [k, v] of Object.entries(st.fixtures)) {\n const f = o.fixtures.get(k)\n if (f) {\n f.on = v\n f.flowing = false\n f.frac = 0\n f.timer = v && f.spec.kind === 'flush' ? FLUSH_SECONDS : 0\n }\n }\n for (const [k, v] of Object.entries(st.hp)) {\n const h = o.hp.get(k)\n if (h) h.hp = v\n }\n }\n grid = state.grid\n breakers.clear()\n for (const [k, v] of Object.entries(state.breakers)) breakers.set(k, v)\n seats.clear()\n for (const [a, s] of Object.entries(state.seats)) if (objs.has(s.object)) seats.set(a, { object: s.object, seat: s.seat })\n defaultTank = state.defaultTank\n defaultTankExplicit = true\n }\n\n // ------------------------------------------------------------------ public surface\n const world: World = {\n add,\n remove,\n get: (id) => objs.get(id)?.public,\n objects: () => [...objs.values()].map((o) => o.public),\n update,\n interactables,\n target,\n act,\n partT: (objectId, partId) => objs.get(objectId)?.parts.get(partId)?.t ?? 0,\n setDevice,\n setFixture,\n setBurner,\n setPart: (objectId, partId, targetT, instant) => {\n const o = objs.get(objectId)\n if (o) setPartTarget(o, partId, targetT, instant)\n },\n fitSweep,\n contents,\n accessible,\n take,\n put,\n slotPosition,\n power: {\n get grid() {\n return grid\n },\n set grid(on: boolean) {\n world.power.setGrid(on)\n },\n setGrid(on) {\n if (on === grid) return\n const before = powerSnapshot()\n grid = on\n emit({ type: 'power', grid })\n emitPowerChanges(before)\n },\n setBreaker(circuit, on) {\n if (breaker(circuit) === on) {\n breakers.set(circuit, on)\n return\n }\n const before = powerSnapshot()\n breakers.set(circuit, on)\n emitPowerChanges(before)\n },\n breaker,\n isPowered: (objectId, deviceId) => {\n const r = getDevice(objectId, deviceId)\n return r ? devicePowered(r.o, r.d) : false\n },\n isOn: (objectId, deviceId) => getDevice(objectId, deviceId)?.d.on ?? false,\n pluggedInto: (objectId, deviceId) => plugs.get(`${objectId}:${deviceId}`) ?? null,\n channel: (objectId, deviceId) => getDevice(objectId, deviceId)?.d.channel ?? 0,\n },\n fuelLevel: (objectId, fuelId) => objs.get(objectId)?.fuels.get(fuelId)?.level ?? 0,\n isLit: (objectId, burnerId) => objs.get(objectId)?.burners.get(burnerId)?.lit ?? false,\n water: {\n setDefaultTank(tankId) {\n defaultTank = tankId\n defaultTankExplicit = true\n },\n level(tankId) {\n return findGlobal(tankId, (oo, local) => oo.tanks.get(local))?.value.level ?? 0\n },\n refill(tankId, liters) {\n const f = findGlobal(tankId, (oo, local) => oo.tanks.get(local))\n if (!f) return 0\n const added = Math.max(0, Math.min(liters, f.value.spec.capacity - f.value.level))\n f.value.level += added\n return added\n },\n setRain(mm) {\n rain = Math.max(0, mm)\n },\n isFlowing: (objectId, fixtureId) => {\n const fx = objs.get(objectId)?.fixtures.get(fixtureId)\n return !!fx && fx.on && fx.flowing\n },\n },\n sit,\n stand,\n seatOf: (actor = DEFAULT_ACTOR) => {\n const s = seats.get(actor)\n return s ? { object: s.object, seat: s.seat } : null\n },\n push,\n sway: (objectId, softId) => {\n const s = objs.get(objectId)?.soft.get(softId)\n return s ? { ax: s.ax, az: s.az } : { ax: 0, az: 0 }\n },\n setWind: (x, z) => {\n wind = [x, z]\n },\n emitters,\n mirrors,\n colliders,\n damage,\n hp: (objectId, target) => (options.destruction ? null : (objs.get(objectId)?.hp.get(target)?.hp ?? null)),\n t,\n setLocale: (l) => {\n locale = l\n table = resolveStrings(locale, options.strings)\n },\n serialize,\n load,\n }\n return world\n}\n","import type { Vec3 } from './destruction'\n\n/**\n * The numbers of the shove a blast gives to a body that moves (a loose item, a piece of furniture, a person): all of them a game value, with a default that reads well in a room,\n * not a physical table. A host reads them once and lends them to the modules that move their own bodies (`ModuleHost.blastShove`).\n */\nexport interface BlastShoveOptions {\n /**\n * The share of the blast energy that reaches a body as motion: the speed at the centre is `sqrt(2 * energy * coupling / mass)`, before the falloff (default 0.02).\n */\n readonly coupling?: number\n /** Fastest a body is thrown, in m/s, at the centre of the blast (default 20). */\n readonly maxSpeed?: number\n /** How much of the push goes up: the direction is `(away, lift)` normalised from the horizontal outward direction (default 0.3). */\n readonly lift?: number\n /** Below this speed (m/s) nothing moves: a heavy thing far from a small blast stays where it is (default 0.3). */\n readonly minSpeed?: number\n /** Exponent of the falloff `(1 - distance / radius) ^ power`, the same as the damage of the destruction world (default 2). */\n readonly falloffPower?: number\n}\n\n/** The defaults of `BlastShoveOptions`. */\nexport const DEFAULT_BLAST_SHOVE: Readonly<Required<BlastShoveOptions>> = { coupling: 0.02, maxSpeed: 20, lift: 0.3, minSpeed: 0.3, falloffPower: 2 }\n\n/** A blast as the shove reads it: where, how much energy (J) and how far it reaches (m). `reach` (0..1) is the share that got through what stood in the way. */\nexport interface BlastSource {\n readonly point: Vec3\n readonly energy: number\n readonly radius: number\n readonly reach?: number\n}\n\n/** What a blast does to one body: how fast it leaves (m/s), the unit direction it leaves in, and how far from the centre it was. */\nexport interface BlastShove {\n readonly speed: number\n readonly direction: Vec3\n readonly distance: number\n /** The falloff applied, 0..1. */\n readonly falloff: number\n}\n\n/**\n * The shove a blast gives to a body of `mass` kg whose centre is at `position`: away from the centre, lifted a little, with the speed\n * `min(maxSpeed, sqrt(2 * energy * reach * coupling / mass)) * (1 - distance / radius) ^ 2`. Undefined when the body is outside the radius or the speed is under `minSpeed`.\n * The same rule moves the loose items and furniture of the test room and the people of the characters module, so a game that tunes the options tunes all of them.\n */\nexport function blastShove(blast: BlastSource, target: { readonly position: Vec3; readonly mass: number }, options: BlastShoveOptions = {}): BlastShove | undefined {\n const o = { ...DEFAULT_BLAST_SHOVE, ...options }\n const dx = target.position[0] - blast.point[0]\n const dy = target.position[1] - blast.point[1]\n const dz = target.position[2] - blast.point[2]\n const distance = Math.hypot(dx, dy, dz)\n if (!(blast.radius > 0) || distance > blast.radius) return undefined\n const falloff = (1 - distance / blast.radius) ** o.falloffPower\n const mass = Math.max(target.mass, 0.05)\n const speed = Math.min(o.maxSpeed, Math.sqrt((2 * blast.energy * (blast.reach ?? 1) * o.coupling) / mass)) * falloff\n if (!(speed >= o.minSpeed)) return undefined\n // straight above or below the centre there is no \"away\": the push goes up\n const direction: Vec3 = distance > 1e-4 ? [dx / distance, dy / distance + o.lift, dz / distance] : [0, 1, 0]\n const length = Math.hypot(direction[0], direction[1], direction[2])\n return { speed, direction: [direction[0] / length, direction[1] / length, direction[2] / length], distance, falloff }\n}\n","import type { DamageType, DestructibleSpec, DestructionEvent, Hit, JointSpec, ObjectState, ToolKind, Vec3 } from './destruction'\n\n/**\n * What a game module implements for an object whose behaviour it owns (a vehicle with its own panel deformation, a creature, a machine). The\n * world (`DestructionWorld.register`) hosts it next to its own objects: raycast, shoot, explode, hit, disassemble, extinguish, update, state,\n * reset and `on` all route to it.\n *\n * Space: the impl receives hits in WORLD space and returns events in WORLD space (it owns its transform; the transform given to `register` or\n * `setTransform` is only used by the world for raycasts and blast range). Every event must carry `object === id` and name parts listed by\n * `describe()`.\n */\nexport interface DestructibleImpl {\n readonly id: string\n readonly name?: string\n /** Parts, joints and structure in the impl's local space, for raycast, inspector and log. Called often: keep it cheap. */\n describe(): DestructibleSpec\n /** Apply one hit (see `IMPACT_CONTRACT` for the fields per type) and return the events it caused. */\n hit(hit: Hit): DestructionEvent[]\n /** Advance fire, melting, collapse and other timed behaviour. */\n update?(dt: number): DestructionEvent[]\n state(): ObjectState\n reset?(): void\n /** Same contract as `DestructionWorld.disassemble`: progress 0..1, or -1 when the tool cannot undo the joint. */\n disassemble?(jointId: string, tool: ToolKind, dt: number): number\n extinguish?(partId?: string): void\n /** Optional: an animation moved a part; `position` / `rotation` (Euler XYZ, radians) are object-local. Keep raycast and hit shapes in sync. */\n setPartPose?(partId: string, position: Vec3, rotation?: Vec3): void\n /** Plain JSON of the impl's own state, stored in `DestructionSnapshot.impls`. */\n serialize?(): unknown\n load?(data: unknown): void\n}\n\n/** The fields a weapon or hazard must put in a `Hit`, per damage type. THE impact contract. */\nexport interface ImpactContract {\n required: string[]\n optional: string[]\n note: string\n}\n\nexport const IMPACT_CONTRACT: Record<DamageType, ImpactContract> = {\n ballistic: { required: ['type', 'point', 'direction', 'energy', 'caliber'], optional: ['space', 'source'], note: 'bullets and pellets: joules and diameter in millimetres' },\n blunt: { required: ['type', 'point', 'energy'], optional: ['direction', 'radius', 'space', 'source'], note: 'contact radius in metres (default 3 cm)' },\n slash: { required: ['type', 'point', 'energy'], optional: ['direction', 'radius', 'space', 'source'], note: 'axes, knives, machetes' },\n explosive: { required: ['type', 'point', 'energy', 'radius'], optional: ['lethalRadius', 'space', 'source'], note: 'point is the centre of the blast, radius the range in metres' },\n fire: { required: ['type', 'point', 'temperature', 'radius'], optional: ['duration', 'space', 'source'], note: 'flame temperature in °C; duration in seconds (call every frame with `dt`)' },\n heat: { required: ['type', 'point', 'temperature', 'radius'], optional: ['duration', 'space', 'source'], note: 'heat without flame (cutting torch, hot plate)' },\n}\n\n/** Problems with a hit according to the impact contract (empty when it is valid). */\nexport const checkHit = (hit: Hit): string[] => {\n const c = IMPACT_CONTRACT[hit.type]\n if (!c) return [`unknown damage type \"${String(hit.type)}\"`]\n const out: string[] = []\n for (const f of c.required) {\n const v = (hit as unknown as Record<string, unknown>)[f]\n if (v === undefined || (Array.isArray(v) ? v.some((n) => !Number.isFinite(n)) : typeof v === 'number' && !Number.isFinite(v))) out.push(`${hit.type} hit needs \"${f}\"`)\n }\n return out\n}\n\nexport interface CheckOptions {\n /**\n * Ids of every material the impl may use (the contracts package does not know the materials of your world: pass the ids of\n * `world.materials`, or the built-in plus your own). When omitted, the material check is skipped.\n */\n materials?: Iterable<string>\n}\n\nconst finiteJson = (v: unknown, path: string, out: string[]) => {\n if (typeof v === 'number') {\n if (!Number.isFinite(v)) out.push(`${path} is not a finite number`)\n } else if (Array.isArray(v)) v.forEach((x, i) => finiteJson(x, `${path}[${i}]`, out))\n else if (v && typeof v === 'object') for (const [k, x] of Object.entries(v)) finiteJson(x, `${path}.${k}`, out)\n else if (typeof v === 'function' || typeof v === 'symbol' || typeof v === 'bigint') out.push(`${path} is not JSON`)\n}\n\n/**\n * Contract checker for the test room (it needs no world): `describe()` is valid, a 500 J ballistic hit at a part centre returns well-formed events of this impl, `state()`\n * matches `describe()`, hit points never go negative, `update(0.016)` returns an array and every event is JSON-serializable. It hits the impl\n * (and calls `reset()` afterwards when there is one).\n */\nexport const checkDestructible = (impl: DestructibleImpl, options: CheckOptions = {}): { ok: boolean; problems: string[] } => {\n const problems: string[] = []\n const known = options.materials ? new Set(options.materials) : null\n let spec: DestructibleSpec | undefined\n try {\n spec = impl.describe()\n } catch (e) {\n return { ok: false, problems: [`describe() threw: ${String(e)}`] }\n }\n if (!spec || !Array.isArray(spec.parts) || spec.parts.length === 0) return { ok: false, problems: ['describe() must return at least one part'] }\n const ids = new Set<string>()\n for (const p of spec.parts) {\n if (ids.has(p.id)) problems.push(`duplicate part id \"${p.id}\"`)\n ids.add(p.id)\n if (known && !known.has(p.material)) problems.push(`part \"${p.id}\" has unknown material \"${p.material}\"`)\n if (!p.shape || !['box', 'cylinder', 'sphere'].includes(p.shape.kind)) problems.push(`part \"${p.id}\" has no valid shape`)\n if (!Array.isArray(p.position) || p.position.length !== 3) problems.push(`part \"${p.id}\" has no position`)\n }\n const jointIds = new Set<string>()\n for (const j of (spec.joints ?? []) as JointSpec[]) {\n if (!ids.has(j.a) || !ids.has(j.b)) problems.push(`joint \"${j.id ?? `${j.a}~${j.b}`}\" references an unknown part`)\n const jid = j.id ?? `${j.a}~${j.b}`\n if (jointIds.has(jid)) problems.push(`duplicate joint id \"${jid}\"`)\n jointIds.add(jid)\n }\n const checkState = (label: string) => {\n let st: ObjectState\n try {\n st = impl.state()\n } catch (e) {\n problems.push(`state() threw ${label}: ${String(e)}`)\n return\n }\n const sids = st.parts.map((p) => p.id).sort().join(',')\n if (sids !== [...ids].sort().join(',')) problems.push(`state() part ids do not match describe() ${label}`)\n for (const p of st.parts) if (!(p.hp >= 0)) problems.push(`part \"${p.id}\" has negative or invalid hp ${label}`)\n }\n const checkEvents = (events: unknown, label: string) => {\n if (!Array.isArray(events)) {\n problems.push(`${label} must return an array`)\n return\n }\n const evs = events as DestructionEvent[]\n evs.forEach((e, i) => {\n if (e.object !== impl.id) problems.push(`${label} event ${i} (${e.type}) has object \"${String(e.object)}\", expected \"${impl.id}\"`)\n const part = (e as { part?: string }).part\n if (part !== undefined && !ids.has(part)) problems.push(`${label} event ${i} (${e.type}) names unknown part \"${part}\"`)\n })\n const bad: string[] = []\n finiteJson(evs, 'events', bad)\n problems.push(...bad.map((b) => `${label}: ${b}`))\n try {\n const s = JSON.stringify(evs)\n if (JSON.stringify(JSON.parse(s)) !== s) problems.push(`${label} events do not survive a JSON round trip`)\n } catch (e) {\n problems.push(`${label} events are not JSON-serializable: ${String(e)}`)\n }\n }\n checkState('before the hit')\n const target = spec.parts[0]\n try {\n const hit: Hit = { type: 'ballistic', point: [target.position[0], target.position[1], target.position[2]], direction: [0, 0, -1], energy: 500, caliber: 9 }\n checkEvents(impl.hit(hit), 'hit()')\n } catch (e) {\n problems.push(`hit() threw: ${String(e)}`)\n }\n checkState('after the hit')\n if (impl.update) {\n try {\n checkEvents(impl.update(0.016), 'update()')\n } catch (e) {\n problems.push(`update() threw: ${String(e)}`)\n }\n checkState('after update')\n }\n try {\n impl.reset?.()\n } catch (e) {\n problems.push(`reset() threw: ${String(e)}`)\n }\n return { ok: problems.length === 0, problems }\n}\n","/** The slots of a body an item can cover (the item slot vocabulary: game-items imports it from here). */\nexport type BodySlot = 'head' | 'eyes' | 'torso' | 'arms' | 'hands' | 'legs' | 'feet' | 'over'\n\n/** The 11 segments of the detailed body model (the Arsenal ids). */\nexport type SegmentKind = 'head' | 'jaw' | 'neck' | 'torso' | 'pelvis' | 'upperArm' | 'forearm' | 'hand' | 'thigh' | 'shin' | 'foot'\n\n/** The 6 regions of the crowd model (the game regions 0..5). */\nexport type BodyRegion = 'head' | 'torso' | 'armL' | 'armR' | 'legL' | 'legR'\n\n/** Bits of the `missing` mask of a body. The instanced body shader reads them, so the values are part of the contract. */\nexport const MISSING_BITS = {\n head: 1,\n armL: 2,\n armR: 4,\n legL: 8,\n legR: 16,\n armLBroken: 32,\n armRBroken: 64,\n legLBroken: 128,\n legRBroken: 256,\n jaw: 512,\n} as const\n","import type { DestructibleSpec, PartSpec } from './destruction'\n\nexport interface CheckSpecOptions {\n /** Known material ids. When given, every part's material must be one of them. */\n materials?: Iterable<string>\n}\n\nexport interface SpecReport {\n /** False when there is at least one problem (warnings do not count). */\n ok: boolean\n problems: string[]\n /** Things that are legal but probably wrong, e.g. structural parts that cannot reach an anchored part. */\n warnings: string[]\n}\n\nconst STRUCTURE_ROLES = ['foundation', 'column', 'beam', 'slab', 'wall', 'partition', 'roof', 'stair', 'none']\nconst BEARS = [true, false, 'a_on_b', 'b_on_a']\n\nconst finite = (n: unknown): n is number => typeof n === 'number' && Number.isFinite(n)\nconst positive = (n: unknown): boolean => finite(n) && n > 0\nconst vec3 = (v: unknown): boolean => Array.isArray(v) && v.length === 3 && v.every(finite)\nconst nonNegative = (n: unknown): boolean => n === undefined || (finite(n) && n >= 0)\n\nconst FACES = ['both', '+', '-']\nconst BONDS = ['running', 'stack']\n\n/** Layers, reinforcement, units and breach: known materials, finite positive sizes. */\nconst checkStagedFields = (p: PartSpec | undefined, label: string, materials: Set<string> | null, problems: string[]): void => {\n const known = (m: unknown, what: string): void => {\n if (materials && !materials.has(m as string)) problems.push(`${label} ${what} has unknown material \"${String(m)}\"`)\n }\n ;(p?.layers ?? []).forEach((l, i) => {\n known(l?.material, `layer ${i}`)\n if (!positive(l?.thickness)) problems.push(`${label} layer ${i} thickness must be finite and positive`)\n if (!FACES.includes(l?.faces)) problems.push(`${label} layer ${i} has an invalid faces \"${String(l?.faces)}\"`)\n })\n const r = p?.reinforcement\n if (r) {\n known(r.material, 'reinforcement')\n if (!positive(r.spacing) || !positive(r.diameter)) problems.push(`${label} reinforcement spacing and diameter must be finite and positive`)\n if (r.residualCapacity !== undefined && !(finite(r.residualCapacity) && r.residualCapacity >= 0 && r.residualCapacity <= 1)) problems.push(`${label} reinforcement residualCapacity must be between 0 and 1`)\n }\n const u = p?.units\n if (u) {\n known(u.mortar, 'units mortar')\n if (!vec3(u.size) || !u.size.every(positive)) problems.push(`${label} units size must be three finite positive numbers`)\n if (!BONDS.includes(u.bond)) problems.push(`${label} units has an invalid bond \"${String(u.bond)}\"`)\n }\n if (p?.breach && p.breach.area !== undefined && !positive(p.breach.area)) problems.push(`${label} breach area must be finite and positive`)\n}\n\n/**\n * Static checks on a `DestructibleSpec` (no world needed), for items that give a `spec` instead of an `impl`: unique part ids, known materials\n * (when `options.materials` is given), joints that reference existing, different parts, finite positive sizes, non-negative mass / hp / capacity,\n * valid structure roles and `bears` directions. A structural part with no path of joints to an anchored part is a warning, not a problem: it\n * is allowed, it just falls.\n */\nexport const checkSpec = (spec: DestructibleSpec, options: CheckSpecOptions = {}): SpecReport => {\n const problems: string[] = []\n const warnings: string[] = []\n const materials = options.materials ? new Set(options.materials) : null\n const parts = Array.isArray(spec?.parts) ? spec.parts : []\n if (!Array.isArray(spec?.parts) || parts.length === 0) problems.push('the spec needs at least one part')\n const ids = new Set<string>()\n for (const p of parts) {\n const id = String(p?.id ?? '')\n const label = `part \"${id}\"`\n if (id === '') problems.push('a part has no id')\n else if (ids.has(id)) problems.push(`duplicate part id \"${id}\"`)\n ids.add(id)\n if (materials && !materials.has(p?.material)) problems.push(`${label} has unknown material \"${String(p?.material)}\"`)\n else if (typeof p?.material !== 'string' || p.material === '') problems.push(`${label} needs a material`)\n const s = p?.shape\n if (s?.kind === 'box') {\n if (!Array.isArray(s.size) || s.size.length !== 3 || !s.size.every(positive)) problems.push(`${label} box size must be three finite positive numbers`)\n } else if (s?.kind === 'cylinder') {\n if (!positive(s.radius) || !positive(s.height)) problems.push(`${label} cylinder radius and height must be finite and positive`)\n } else if (s?.kind === 'sphere') {\n if (!positive(s.radius)) problems.push(`${label} sphere radius must be finite and positive`)\n } else problems.push(`${label} has an unknown shape`)\n if (!vec3(p?.position)) problems.push(`${label} needs a finite position [x, y, z]`)\n if (p?.rotation !== undefined && !vec3(p.rotation)) problems.push(`${label} has an invalid rotation`)\n for (const f of ['mass', 'hp', 'thickness'] as const) if (!nonNegative(p?.[f])) problems.push(`${label} ${f} must be a finite number >= 0`)\n if (p?.fill !== undefined && !(finite(p.fill) && p.fill >= 0 && p.fill <= 1)) problems.push(`${label} fill must be between 0 and 1`)\n if (p?.structure) {\n if (!STRUCTURE_ROLES.includes(p.structure.role)) problems.push(`${label} has an invalid structure role \"${String(p.structure.role)}\"`)\n if (!nonNegative(p.structure.capacity)) problems.push(`${label} structure capacity must be a finite number >= 0`)\n }\n if (p?.contains && !nonNegative(p.contains.liters)) problems.push(`${label} contains.liters must be a finite number >= 0`)\n checkStagedFields(p, label, materials, problems)\n }\n\n const jointIds = new Set<string>()\n const edges: Array<[string, string]> = []\n for (const j of spec?.joints ?? []) {\n const id = j.id ?? `${j.a}~${j.b}`\n const label = `joint \"${id}\"`\n if (jointIds.has(id)) problems.push(`duplicate joint id \"${id}\"`)\n jointIds.add(id)\n if (!ids.has(j.a)) problems.push(`${label} references unknown part \"${String(j.a)}\"`)\n if (!ids.has(j.b)) problems.push(`${label} references unknown part \"${String(j.b)}\"`)\n if (j.a === j.b) problems.push(`${label} joins part \"${String(j.a)}\" to itself`)\n if (j.bears !== undefined && !BEARS.includes(j.bears)) problems.push(`${label} has an invalid bears \"${String(j.bears)}\"`)\n if (!nonNegative(j.strength)) problems.push(`${label} strength must be a finite number >= 0`)\n if (!nonNegative(j.seconds)) problems.push(`${label} seconds must be a finite number >= 0`)\n if (j.bears !== false && ids.has(j.a) && ids.has(j.b) && j.a !== j.b) edges.push([j.a, j.b])\n }\n\n // structural parts must reach an anchored part over the joints (only when the spec lists its joints: otherwise they are inferred later)\n const structural = parts.filter((p) => p?.structure && p.structure.role !== 'none')\n if (structural.length && spec.joints) {\n const anchored = parts.filter((p) => p.anchored || p.structure?.role === 'foundation').map((p) => p.id)\n const adj = new Map<string, string[]>()\n for (const [a, b] of edges) {\n adj.set(a, [...(adj.get(a) ?? []), b])\n adj.set(b, [...(adj.get(b) ?? []), a])\n }\n const seen = new Set(anchored)\n const queue = [...anchored]\n while (queue.length) {\n for (const n of adj.get(queue.pop()!) ?? []) {\n if (seen.has(n)) continue\n seen.add(n)\n queue.push(n)\n }\n }\n const lost = structural.filter((p) => !seen.has(p.id)).map((p) => p.id)\n if (lost.length) warnings.push(`structural part(s) ${lost.map((i) => `\"${i}\"`).join(', ')} cannot reach an anchored part, so they will fall`)\n }\n return { ok: problems.length === 0, problems, warnings }\n}\n","import type { BallisticExtras, Hit, HitIgnition, Vec3 } from './destruction'\n\n/**\n * A ballistic shot (one per pellet) as a weapon module produces it. Plain data: any damage model can consume it (`shotToHit` makes the `Hit`).\n */\nexport interface Shot {\n origin: Vec3\n /** Unit vector. */\n direction: Vec3\n /** Muzzle energy in joules. */\n energy: number\n /** Bullet diameter in millimetres. */\n caliber: number\n /** snake_case calibre id, e.g. `9x19`. */\n caliberId: string\n /** Muzzle speed in m/s. */\n speed: number\n /** Projectile mass in grams (one pellet for a shotgun load). */\n mass?: number\n /** Energy at a distance in metres, with the calibre's drag. */\n energyAt(distance: number): number\n pellet: number\n /** snake_case weapon id. */\n weapon: string\n source?: string\n /** Kind of the round that was loaded (`fmj`, `hp`, `ap`, `buck`, `slug`, `incendiary`, `tracer`...). */\n ammo?: string\n /** Millimetres of steel, concrete, brick and wood the round goes through at the muzzle (the ammo table of the weapons module). `shotToHit` scales it by the energy left. */\n penetration?: Readonly<Record<string, number>>\n incendiary?: boolean\n tracer?: boolean\n /** Chances that the round lights flammable vapour or fuel. */\n ignition?: HitIgnition\n}\n\n/**\n * The fields of the round that a damage model takes besides the geometry: the penetration by material scaled by the energy that is left at `distance`\n * (linear in the energy: half the energy goes through half as much), the incendiary and tracer flags and the ignition chances. Pass it as the sixth\n * argument of `DestructionWorld.shoot` or spread it in a `Hit`.\n */\nexport const shotExtras = (shot: Shot, distance = 0): BallisticExtras => {\n const out: { -readonly [K in keyof BallisticExtras]: BallisticExtras[K] } = {}\n if (shot.penetration) {\n const k = shot.energy > 0 ? Math.min(1, Math.max(0, shot.energyAt(distance) / shot.energy)) : 1\n const scaled: Record<string, number> = {}\n for (const key of Object.keys(shot.penetration)) scaled[key] = shot.penetration[key]! * k\n out.penetration = scaled\n }\n if (shot.incendiary) out.incendiary = true\n if (shot.tracer) out.tracer = true\n if (shot.ignition) out.ignition = { spark: shot.ignition.spark, flame: shot.ignition.flame }\n return out\n}\n\n/** One use of a non-firearm (melee swing, flame tick, heat tick, throw, tool tick, extinguisher tick). */\nexport type Use =\n | { kind: 'melee'; damage: 'blunt' | 'slash'; energy: number; radius: number; reach: number; origin: Vec3; direction: Vec3 }\n | { kind: 'flame'; temperature: number; radius: number; range: number; cone: boolean; duration: number; origin: Vec3; direction: Vec3 }\n | { kind: 'heat'; temperature: number; radius: number; range: number; duration: number; origin: Vec3; direction: Vec3 }\n | {\n kind: 'throw'\n energy: number\n radius: number\n fuse: number\n velocity: Vec3\n origin: Vec3\n fire?: { temperature: number; radius: number; seconds: number }\n /** Explosive id (`m67`, `molotov`, `pg7v`...): the host looks the numbers up in the arsenal. Absent on a plain thrown object. */\n explosive?: string\n /** What sets it off: `timer` after `fuse` seconds, `impact` on the first hit once armed. */\n trigger?: 'timer' | 'impact'\n /** Metres the projectile must fly before an impact sets it off; closer, it hits without exploding (rocket launchers). */\n armDistance?: number\n /** Radius in metres of the wounding area (`radius` is the lethal one). */\n injuryRadius?: number\n /** Seconds the blast stuns whoever is inside the injury radius (flashbang). */\n stunSeconds?: number\n /** Seconds the thrower held it after pulling the pin: `fuse` is what was left of the full fuse when it left the hand. */\n cooked?: number\n /** Went off in the thrower's hand (held past the fuse): no velocity, `fuse` is 0 and the blast is at `origin`. */\n inHand?: boolean\n }\n /** An explosive set down where the trigger is pulled (mine, C4, charge): it waits for its trigger instead of flying. */\n | {\n kind: 'place'\n explosive: string\n /** `wire`: something trips it; `remote`: the player fires it; `timer`: after `fuse` seconds. */\n triggers: readonly ('timer' | 'wire' | 'remote')[]\n energy: number\n /** Lethal radius in metres. */\n radius: number\n injuryRadius: number\n /** Cone the blast goes through, in front of `direction` (mine); absent for a blast in every direction. */\n cone?: { halfAngleDeg: number; length: number }\n /** The wire a `wire` charge stretches from where it is set down: metres out, degrees from its facing (counter-clockwise from above) and metres above it. */\n tripwire?: { length: number; angleDeg: number; height: number }\n fuse?: number\n origin: Vec3\n direction: Vec3\n }\n /** The blast behind a rocket launcher: dangerous inside `radius` metres, in the cone around `direction` (pointing away from the target). */\n | { kind: 'backblast'; radius: number; halfAngleDeg: number; origin: Vec3; direction: Vec3 }\n | { kind: 'tool'; tool: string; reach: number; duration: number; origin: Vec3; direction: Vec3 }\n | { kind: 'extinguish'; range: number; coolC: number; duration: number; origin: Vec3; direction: Vec3 }\n | { kind: 'hand'; reach: number; origin: Vec3; direction: Vec3 }\n\n/**\n * The `Hit` a ballistic shot makes at `point` (world space): the energy is what is left of the shot at that distance from its origin\n * (`shot.energyAt`), the direction and calibre come from the shot. `normal` (the surface normal at the point, when the caller knows it) does not\n * change the hit; it is accepted so that callers can pass what their raycast returned and so that a stricter implementation could use it.\n */\nexport const shotToHit = (shot: Shot, point: Vec3, normal?: Vec3): Hit => {\n void normal\n const dx = point[0] - shot.origin[0]\n const dy = point[1] - shot.origin[1]\n const dz = point[2] - shot.origin[2]\n const distance = Math.hypot(dx, dy, dz)\n return {\n type: 'ballistic',\n point: [point[0], point[1], point[2]],\n direction: [shot.direction[0], shot.direction[1], shot.direction[2]],\n energy: shot.energyAt(distance),\n caliber: shot.caliber,\n ...(shot.mass === undefined ? {} : { mass: shot.mass }),\n ...shotExtras(shot, distance),\n source: shot.source ?? shot.weapon,\n }\n}\n\n/**\n * The `Hit` a non-firearm `Use` makes at `point` (world space), or `null` for uses that do not damage by themselves.\n *\n * - `melee` -> `blunt` / `slash` with the swing's `energy`, contact `radius` and `direction`;\n * - `flame` -> `fire` and `heat` -> `heat`, with `temperature`, `duration` and a contact radius of at most 0.3 m (one ray of the cone);\n * - `throw` -> the blast (`explosive`, `energy`, `radius`, centred on `point`, the place it detonates). A thrown item with no blast energy but\n * a `fire` patch (a molotov) gives that patch as a `fire` hit (`temperature`, `radius`, `seconds` as `duration`). No energy and no fire -> `null`;\n * - `tool`, `extinguish` and `hand` -> `null` (tools work on joints, the extinguisher cools, the hand only grabs).\n *\n * `normal` does not change the hit (same as `shotToHit`).\n */\nexport const useToHit = (use: Use, point: Vec3, normal?: Vec3): Hit | null => {\n void normal\n const p: Vec3 = [point[0], point[1], point[2]]\n switch (use.kind) {\n case 'melee':\n return { type: use.damage, point: p, direction: [use.direction[0], use.direction[1], use.direction[2]], energy: use.energy, radius: use.radius }\n case 'flame':\n case 'heat':\n return {\n type: use.kind === 'flame' ? 'fire' : 'heat',\n point: p,\n direction: [use.direction[0], use.direction[1], use.direction[2]],\n temperature: use.temperature,\n radius: Math.min(use.radius, 0.3),\n duration: use.duration,\n }\n case 'throw':\n if (use.energy > 0) return { type: 'explosive', point: p, energy: use.energy, radius: use.radius }\n if (use.fire) return { type: 'fire', point: p, temperature: use.fire.temperature, radius: use.fire.radius, duration: use.fire.seconds }\n return null\n default:\n return null\n }\n}\n","import type { Hit } from './destruction'\n\n/**\n * How a container of flammable fluid (a fuel tank, a jerrycan, a gas bottle) is set alight by what hits it. A normal bullet that goes through only\n * makes a leak; the leak lights when something supplies a flame: a spark of a hard round on metal, an incendiary or tracer round, a fire nearby\n * or a blast. These are the numbers of the target side; the numbers of the round (core, jacket, incendiary, tracer) are in the weapons module\n * (`rules.ignition` of `@adatechnology/game-weapons`) and reach the target in `Hit.ignition`. Every number is a default to be changed per game.\n */\nexport interface IgnitionRules {\n /**\n * How much of the spark and of the flame of a round reaches the vapour, by how full the container is: points `[filled, factor]`, `filled` 0..1\n * (litres over capacity), `factor` 0..1, linear between points. A full container holds a mixture too rich to burn (the vapour has no air) and\n * mostly leaks; a nearly empty one holds the vapour/air mixture of a flammable range and lights the easiest; a dry one has little vapour left.\n * Default: 0.6 empty, 1 at 10 percent, 0.6 at 35, 0.3 at 65, 0.15 at 90 and 0.12 full.\n */\n fillCurve: ReadonlyArray<readonly [number, number]>\n /** 0..1: how much of the fill factor also weighs on the flame of an incendiary or tracer (1: as much as on a spark; 0: not at all). Default 0.5. */\n flameFillInfluence: number\n /** Chance of the flame of a round that is flagged `incendiary` or `tracer` but carries no `ignition` numbers (a host that passes only the flags). */\n flameDefaults: { incendiary: number; tracer: number }\n /**\n * What a spark needs to strike: a factor 0..1 by material id of the struck part. A material that is not listed but is metal takes\n * `sparkMetalDefault`; a part that is not metal never sparks. Default: steel and iron 1, aluminium 0.25.\n */\n sparkTarget: Readonly<Record<string, number>>\n sparkMetalDefault: number\n /**\n * Factor 0..1 on the spark by fluid (default 1): diesel has a flash point of 52 degrees C and more, so a spark that lights petrol vapour does\n * not light it (a flame does). Default: diesel 0.15.\n */\n sparkFluid: Readonly<Record<string, number>>\n /** A leaking container of flammable fluid within `radius` metres of a burning part or a burning fuel stain lights at `chancePerSecond`. */\n fireNear: { radius: number; chancePerSecond: number }\n}\n\n/** Defaults of `IgnitionRules`. */\nexport const DEFAULT_IGNITION_RULES: IgnitionRules = {\n fillCurve: [\n [0, 0.6],\n [0.1, 1],\n [0.35, 0.6],\n [0.65, 0.3],\n [0.9, 0.15],\n [1, 0.12],\n ],\n flameFillInfluence: 0.5,\n flameDefaults: { incendiary: 0.7, tracer: 0.2 },\n sparkTarget: { steel: 1, iron: 1, aluminium: 0.25 },\n sparkMetalDefault: 0.5,\n sparkFluid: { diesel: 0.15 },\n fireNear: { radius: 1.5, chancePerSecond: 0.5 },\n}\n\n/** Merges a partial `IgnitionRules` over the defaults (an object is merged one level deep). */\nexport const resolveIgnitionRules = (rules?: Partial<IgnitionRules>): IgnitionRules => ({\n ...DEFAULT_IGNITION_RULES,\n ...rules,\n flameDefaults: { ...DEFAULT_IGNITION_RULES.flameDefaults, ...rules?.flameDefaults },\n sparkTarget: { ...DEFAULT_IGNITION_RULES.sparkTarget, ...rules?.sparkTarget },\n sparkFluid: { ...DEFAULT_IGNITION_RULES.sparkFluid, ...rules?.sparkFluid },\n fireNear: { ...DEFAULT_IGNITION_RULES.fireNear, ...rules?.fireNear },\n})\n\n/** Linear interpolation of the fill curve at `fill` (0..1); outside the points it keeps the first or the last. */\nexport const fillFactor = (fill: number, curve: IgnitionRules['fillCurve'] = DEFAULT_IGNITION_RULES.fillCurve): number => {\n if (curve.length === 0) return 1\n const f = Math.min(1, Math.max(0, fill))\n if (f <= curve[0]![0]) return curve[0]![1]\n for (let i = 1; i < curve.length; i++) {\n const [x1, y1] = curve[i]!\n const [x0, y0] = curve[i - 1]!\n if (f <= x1) return x1 === x0 ? y1 : y0 + ((y1 - y0) * (f - x0)) / (x1 - x0)\n }\n return curve[curve.length - 1]![1]\n}\n\n/** The factor of what a spark strikes: 0 when the struck part is not metal. */\nexport const sparkTargetFactor = (materialId: string, metal: boolean, rules: IgnitionRules = DEFAULT_IGNITION_RULES): number =>\n !metal ? 0 : rules.sparkTarget[materialId] ?? rules.sparkMetalDefault\n\n/**\n * Chance that one round that went through the wall of a container lights the fluid that leaks: the spark (only on metal) and the flame (any\n * wall), each weighed by the fill of the container; the two are independent. 0 when the round carries nothing (`Hit.ignition` absent and not\n * flagged `incendiary` or `tracer`): a plain bullet on a plain wall only leaks.\n */\nexport const ignitionChance = (hit: Pick<Hit, 'incendiary' | 'tracer' | 'ignition'>, target: { sparkTarget: number; fill: number; fluid?: string }, rules: IgnitionRules = DEFAULT_IGNITION_RULES): number => {\n const k = fillFactor(target.fill, rules.fillCurve)\n const spark = (hit.ignition?.spark ?? 0) * target.sparkTarget * (target.fluid === undefined ? 1 : rules.sparkFluid[target.fluid] ?? 1) * k\n const flameBase = hit.ignition?.flame ?? Math.max(hit.incendiary ? rules.flameDefaults.incendiary : 0, hit.tracer ? rules.flameDefaults.tracer : 0)\n const flame = flameBase * (1 - rules.flameFillInfluence * (1 - k))\n return 1 - (1 - Math.min(1, Math.max(0, spark))) * (1 - Math.min(1, Math.max(0, flame)))\n}\n","import type { Vec3 } from './destruction'\n\n/** Pose of one part (or of the whole item) at a key: position offset in metres and Euler XYZ rotation in radians, both relative to the rest pose. */\nexport interface AnimationPose {\n position?: Vec3\n rotation?: Vec3\n}\n\nexport interface AnimationKey {\n /** Seconds from the start of the clip. */\n t: number\n /** Pose of the item's root. */\n position?: Vec3\n rotation?: Vec3\n /** Poses of named parts: the key is a destruction part id (a pistol `reload` moves `mag`; a car door `open` rotates `door_l`). */\n parts?: Record<string, AnimationPose>\n}\n\nexport interface AnimationEventSpec {\n /** Seconds from the start of the clip. */\n t: number\n /** snake_case type the host maps (`sound`, `eject_casing`, `door_latch`...). */\n type: string\n data?: Record<string, unknown>\n}\n\n/** A use animation a module brings with its item. Poses between keys are interpolated by the player (the test room does it linearly). */\nexport interface AnimationClipSpec {\n /** snake_case: `reload`, `open`, `drink`... Unique within the item. */\n id: string\n /** Seconds. */\n duration: number\n keys: AnimationKey[]\n events?: AnimationEventSpec[]\n}\n\n/** What an item exposes when it brings its own animations. */\nexport interface ItemAnimationContract {\n animations: AnimationClipSpec[]\n}\n\nconst finite3 = (v: unknown): boolean => Array.isArray(v) && v.length === 3 && v.every((n) => typeof n === 'number' && Number.isFinite(n))\n\n/**\n * Problems with a clip (empty when it is valid): a snake_case id, a positive finite duration, at least one key, key and event times inside\n * `[0, duration]` and not going backwards, finite vectors, every named part one of `partIds`, event types that are non-empty strings and\n * JSON-serializable event data.\n */\nexport const checkAnimation = (clip: AnimationClipSpec, partIds: Iterable<string>): { ok: boolean; problems: string[] } => {\n const problems: string[] = []\n const parts = new Set(partIds)\n const id = String(clip?.id ?? '')\n if (!/^[a-z][a-z0-9_]*$/.test(id)) problems.push(`clip id \"${id}\" must be snake_case`)\n const label = `clip \"${id}\"`\n if (!(typeof clip?.duration === 'number' && Number.isFinite(clip.duration) && clip.duration > 0)) problems.push(`${label} needs a positive finite duration`)\n const dur = typeof clip?.duration === 'number' && clip.duration > 0 ? clip.duration : Infinity\n if (!Array.isArray(clip?.keys) || clip.keys.length === 0) {\n problems.push(`${label} needs at least one key`)\n return { ok: false, problems }\n }\n let prev = -Infinity\n clip.keys.forEach((k, i) => {\n if (!(typeof k.t === 'number' && Number.isFinite(k.t)) || k.t < 0 || k.t > dur + 1e-9) problems.push(`${label} key ${i} has t=${String(k.t)} outside 0..${dur}`)\n else if (k.t < prev) problems.push(`${label} key ${i} goes back in time (${k.t} < ${prev})`)\n else prev = k.t\n for (const f of ['position', 'rotation'] as const) if (k[f] !== undefined && !finite3(k[f])) problems.push(`${label} key ${i} has an invalid ${f}`)\n for (const [pid, pose] of Object.entries(k.parts ?? {})) {\n if (!parts.has(pid)) problems.push(`${label} key ${i} moves unknown part \"${pid}\"`)\n for (const f of ['position', 'rotation'] as const) if (pose?.[f] !== undefined && !finite3(pose[f])) problems.push(`${label} key ${i} part \"${pid}\" has an invalid ${f}`)\n }\n })\n let prevEv = -Infinity\n ;(clip.events ?? []).forEach((e, i) => {\n if (!(typeof e.t === 'number' && Number.isFinite(e.t)) || e.t < 0 || e.t > dur + 1e-9) problems.push(`${label} event ${i} has t=${String(e.t)} outside 0..${dur}`)\n else if (e.t < prevEv) problems.push(`${label} event ${i} goes back in time`)\n else prevEv = e.t\n if (typeof e.type !== 'string' || e.type === '') problems.push(`${label} event ${i} needs a type`)\n try {\n JSON.stringify(e.data ?? {})\n } catch {\n problems.push(`${label} event ${i} data is not JSON`)\n }\n })\n return { ok: problems.length === 0, problems }\n}\n","import type { AnimationClipSpec, AnimationEventSpec, AnimationPose } from './animation'\nimport { checkAnimation } from './animation'\nimport type { HostEvent } from './module'\n\n/** Clips a tool can bring, one per move of its cycle. A tool brings the ones it has; a missing clip is simply not played. */\nexport const TOOL_CLIP = {\n DRAW: 'draw',\n SHOT: 'shot',\n MISFIRE: 'misfire',\n EMPTY: 'empty',\n CYCLE: 'cycle',\n RELOAD: 'reload',\n FEED: 'feed',\n FAULT: 'fault',\n CLEAR: 'clear',\n SAFETY_ON: 'safety_on',\n SAFETY_OFF: 'safety_off',\n MODE: 'mode',\n /** A throwable with the pin out, held until it is thrown. */\n COOK: 'cook',\n /** The stock folds, unfolds, slides in or out (variants `fold`, `unfold`, `collapse`, `extend`). */\n STOCK: 'stock',\n /** A light or a laser is switched (variants `on`, `off`). */\n TOGGLE: 'toggle',\n} as const\nexport type ToolClipId = (typeof TOOL_CLIP)[keyof typeof TOOL_CLIP]\n\n/** What a renderer does when a rule event arrives. `variant` picks `<clip>_<variant>` when the tool has it, else `<clip>`. */\nexport type ToolAnimationStep =\n | { readonly type: 'play'; readonly clip: ToolClipId; readonly variant?: string; readonly duration?: number; readonly repeat?: number }\n /** Move the clip that is playing to the marker (a clip event `stage` with `data.stage`) the rule just reached. */\n | { readonly type: 'sync'; readonly stage: string }\n /** The rule says the phase is over: the clip jumps to its end if it is still running. */\n | { readonly type: 'finish'; readonly clip: ToolClipId }\n\nconst stockVariant = (event: Extract<HostEvent, { type: 'stock' }>): string => {\n const isFolding = event.kind === undefined ? false : event.kind.includes('fold')\n if (event.state === 'collapsed') return isFolding ? 'fold' : 'collapse'\n return isFolding ? 'unfold' : 'extend'\n}\n\n/** The move a host event asks of the tool in hand, or null when it has no motion. */\nexport const toolAnimationStep = (event: HostEvent): ToolAnimationStep | null => {\n switch (event.type) {\n case 'tool':\n return { type: 'play', clip: TOOL_CLIP.DRAW, ...(event.duration === undefined ? {} : { duration: event.duration }) }\n case 'shot':\n return { type: 'play', clip: TOOL_CLIP.SHOT, repeat: Math.max(1, event.rounds ?? 1) }\n case 'misfire':\n return { type: 'play', clip: TOOL_CLIP.MISFIRE }\n case 'empty':\n return { type: 'play', clip: TOOL_CLIP.EMPTY }\n case 'mode':\n return { type: 'play', clip: TOOL_CLIP.MODE, variant: event.mode }\n case 'fault':\n return { type: 'play', clip: TOOL_CLIP.FAULT, variant: event.fault }\n case 'clear':\n if (event.phase === 'end') return { type: 'finish', clip: TOOL_CLIP.CLEAR }\n return { type: 'play', clip: TOOL_CLIP.CLEAR, variant: event.fault, ...(event.duration === undefined ? {} : { duration: event.duration }) }\n case 'safety':\n return { type: 'play', clip: event.on ? TOOL_CLIP.SAFETY_ON : TOOL_CLIP.SAFETY_OFF }\n case 'cycle':\n if (event.phase === 'end') return { type: 'finish', clip: TOOL_CLIP.CYCLE }\n return { type: 'play', clip: TOOL_CLIP.CYCLE, ...(event.duration === undefined ? {} : { duration: event.duration }) }\n case 'reload':\n if (event.phase === 'end') return { type: 'finish', clip: TOOL_CLIP.RELOAD }\n return { type: 'play', clip: TOOL_CLIP.RELOAD, ...(event.kind === undefined ? {} : { variant: event.kind }), ...(event.duration === undefined ? {} : { duration: event.duration }) }\n case 'stage':\n return { type: 'sync', stage: event.stage }\n case 'feed':\n return { type: 'play', clip: TOOL_CLIP.FEED }\n case 'cook':\n if (event.phase === 'start') return { type: 'play', clip: TOOL_CLIP.COOK, duration: event.fuse }\n return { type: 'finish', clip: TOOL_CLIP.COOK }\n case 'stock':\n return { type: 'play', clip: TOOL_CLIP.STOCK, variant: stockVariant(event), ...(event.duration === undefined ? {} : { duration: event.duration }) }\n case 'toggle':\n return { type: 'play', clip: TOOL_CLIP.TOGGLE, variant: event.on ? 'on' : 'off' }\n default:\n return null\n }\n}\n\n/** Where a renderer puts the poses: every part of the tool by id (the ids the clips move), and the whole tool. Poses are offsets from rest. */\nexport interface ToolRig {\n setPartPose(partId: string, pose: AnimationPose): void\n setRootPose?(pose: AnimationPose): void\n}\n\n/** Clips by id, with the variants as `<clip>_<variant>`. */\nexport type ToolClipSet = Readonly<Record<string, AnimationClipSpec>>\n\n/** A renderer's tool animator: feed it the host events and the frame time. */\nexport interface ToolAnimator {\n handle(event: HostEvent): void\n update(dt: number): void\n /** Ids of the clips playing now. */\n readonly playing: readonly string[]\n dispose(): void\n}\n\nexport const STAGE_EVENT = 'stage'\n\n/** The clip with its times (keys and events) scaled so that it lasts `duration` seconds. */\nexport const scaleClip = (clip: AnimationClipSpec, duration: number): AnimationClipSpec => {\n const factor = clip.duration > 0 ? duration / clip.duration : 1\n return {\n ...clip,\n duration,\n keys: clip.keys.map((key) => ({ ...key, t: key.t * factor })),\n ...(clip.events ? { events: clip.events.map((event) => ({ ...event, t: event.t * factor })) } : {}),\n }\n}\n\nconst ZERO: [number, number, number] = [0, 0, 0]\nconst mix = (from: readonly number[], to: readonly number[], fraction: number): [number, number, number] => [\n (from[0] ?? 0) + ((to[0] ?? 0) - (from[0] ?? 0)) * fraction,\n (from[1] ?? 0) + ((to[1] ?? 0) - (from[1] ?? 0)) * fraction,\n (from[2] ?? 0) + ((to[2] ?? 0) - (from[2] ?? 0)) * fraction,\n]\n\n/** Pose of the whole tool (`partId` undefined) or of one part at `time`, linear between keys; a key that does not name it means rest. */\nexport const sampleClip = (clip: AnimationClipSpec, partId: string | undefined, time: number): { position: [number, number, number]; rotation: [number, number, number] } => {\n const points = clip.keys.map((key) => {\n const pose = partId === undefined ? key : key.parts?.[partId]\n return { t: key.t, position: pose?.position ?? ZERO, rotation: pose?.rotation ?? ZERO }\n })\n const first = points[0]\n if (!first || first.t > 0) points.unshift({ t: 0, position: ZERO, rotation: ZERO })\n const last = points[points.length - 1]\n if (!last) return { position: ZERO, rotation: ZERO }\n if (time >= last.t) return { position: mix(last.position, last.position, 0), rotation: mix(last.rotation, last.rotation, 0) }\n const index = Math.max(0, points.findIndex((point, i) => time >= point.t && time < (points[i + 1]?.t ?? Infinity)))\n const from = points[index]\n const to = points[index + 1]\n if (!from || !to) return { position: ZERO, rotation: ZERO }\n const fraction = to.t > from.t ? (time - from.t) / (to.t - from.t) : 0\n return { position: mix(from.position, to.position, fraction), rotation: mix(from.rotation, to.rotation, fraction) }\n}\n\n/** Problems with a clip set (empty when valid): each key is the clip id (or `<clip>_<variant>`), every clip passes `checkAnimation`, and a `stage` event names its stage. */\nexport const checkToolClips = (clips: ToolClipSet, partIds: Iterable<string>): { ok: boolean; problems: string[] } => {\n const parts = [...partIds]\n const problems: string[] = []\n for (const [key, clip] of Object.entries(clips)) {\n if (clip.id !== key) problems.push(`clip \"${key}\" has the id \"${clip.id}\"`)\n if (!(clip.duration > 0)) problems.push(`clip \"${key}\" has no duration`)\n problems.push(...checkAnimation(clip, parts).problems)\n for (const event of clip.events ?? []) if (event.type === STAGE_EVENT && typeof event.data?.stage !== 'string') problems.push(`clip \"${key}\" has a stage event without data.stage`)\n }\n return { ok: problems.length === 0, problems }\n}\n\ninterface Instance {\n readonly name: string\n readonly clip: AnimationClipSpec\n time: number\n delay: number\n fired: number\n}\n\nexport interface ToolClipPlayerOptions {\n clips: ToolClipSet\n rig: ToolRig\n /** Called for each clip event as its time passes (`eject_casing`, `drop_magazine`, `stage`...). */\n onEvent?(event: AnimationEventSpec, clip: string): void\n /** Seconds between the rounds of a `repeat` (a burst): default 0.1. */\n repeatInterval?(): number\n}\n\n/** The default player of a tool's clips: runs the steps of `toolAnimationStep` against a rig, scaled to the duration the rule gives. */\nexport interface ToolClipPlayer {\n apply(step: ToolAnimationStep): void\n update(dt: number): void\n readonly playing: readonly string[]\n /** The clips being played with the time each has reached and the clip itself (scaled to the duration the rule gave), for a renderer that has to follow what the clip does now (the hands working a part). */\n readonly running: ReadonlyArray<{ readonly name: string; readonly time: number; readonly clip: AnimationClipSpec }>\n}\n\nexport const createToolClipPlayer = (options: ToolClipPlayerOptions): ToolClipPlayer => {\n const { clips, rig, onEvent } = options\n let instances: Instance[] = []\n\n const find = (clip: string, variant?: string): { name: string; clip: AnimationClipSpec } | undefined => {\n const name = variant !== undefined && clips[`${clip}_${variant}`] ? `${clip}_${variant}` : clip\n const found = clips[name]\n return found ? { name, clip: found } : undefined\n }\n\n const render = (instance: Instance): void => {\n const time = Math.min(instance.time, instance.clip.duration)\n const root = sampleClip(instance.clip, undefined, time)\n if (instance.clip.keys.some((key) => key.position || key.rotation)) rig.setRootPose?.(root)\n const touched = new Set(instance.clip.keys.flatMap((key) => Object.keys(key.parts ?? {})))\n for (const id of touched) rig.setPartPose(id, sampleClip(instance.clip, id, time))\n }\n\n const fireEvents = (instance: Instance, upTo: number): void => {\n const events = instance.clip.events ?? []\n while (instance.fired < events.length && (events[instance.fired]?.t ?? Infinity) <= upTo + 1e-9) {\n const event = events[instance.fired]\n instance.fired += 1\n if (event) onEvent?.(event, instance.name)\n }\n }\n\n return {\n apply(step) {\n if (step.type === 'sync') {\n for (const instance of instances) {\n const marker = (instance.clip.events ?? []).find((event) => event.type === STAGE_EVENT && event.data?.stage === step.stage)\n if (marker && instance.time < marker.t) instance.time = marker.t\n }\n return\n }\n if (step.type === 'finish') {\n for (const instance of instances) {\n if (instance.name !== step.clip && !instance.name.startsWith(`${step.clip}_`)) continue\n fireEvents(instance, instance.clip.duration)\n instance.time = instance.clip.duration\n }\n return\n }\n const found = find(step.clip, step.variant)\n if (!found) return\n const clip = step.duration && step.duration > 0 ? scaleClip(found.clip, step.duration) : found.clip\n const interval = options.repeatInterval?.() ?? 0.1\n instances = instances.filter((existing) => existing.name !== found.name || existing.delay > 0)\n for (let round = 0; round < (step.repeat ?? 1); round++) {\n instances.push({ name: found.name, clip, time: 0, delay: round * interval, fired: 0 })\n }\n },\n update(dt) {\n for (const instance of instances) {\n const carried = instance.delay > 0 ? dt - instance.delay : dt\n if (instance.delay > 0) {\n instance.delay = Math.max(0, instance.delay - dt)\n if (instance.delay > 0) continue\n }\n instance.time += carried\n fireEvents(instance, instance.time)\n render(instance)\n }\n instances = instances.filter((instance) => instance.delay > 0 || instance.time < instance.clip.duration)\n },\n get playing() {\n return instances.map((instance) => instance.name)\n },\n get running() {\n return instances.filter((instance) => instance.delay <= 0).map((instance) => ({ name: instance.name, time: instance.time, clip: instance.clip }))\n },\n }\n}\n","type PlainObject = Record<string, unknown>\ntype Entry = { readonly id: string }\n\n/** Keys that would reach the prototype of the result when a patch comes from parsed JSON. */\nconst UNSAFE_KEYS: ReadonlySet<string> = new Set(['__proto__', 'constructor', 'prototype'])\n\nconst isPlainObject = (value: unknown): value is PlainObject =>\n typeof value === 'object' && value !== null && !Array.isArray(value) && Object.getPrototypeOf(value) === Object.prototype\n\n/** Recursively optional; arrays and functions are replaced as a whole, objects are merged. */\nexport type DeepPartial<TValue> = TValue extends (...args: never[]) => unknown\n ? TValue\n : TValue extends readonly unknown[]\n ? TValue\n : TValue extends object\n ? { [TKey in keyof TValue]?: DeepPartial<TValue[TKey]> }\n : TValue\n\n/** Merges `patch` over `base`: plain objects merge field by field, arrays, functions and primitives replace. `undefined` in the patch is ignored. */\nexport const deepMerge = <TBase extends object>(base: TBase, patch: object | undefined): TBase => {\n if (!patch) return base\n const result: PlainObject = { ...(base as PlainObject) }\n for (const [key, value] of Object.entries(patch)) {\n if (value === undefined || UNSAFE_KEYS.has(key)) continue\n const current = result[key]\n result[key] = isPlainObject(current) && isPlainObject(value) ? deepMerge(current, value) : value\n }\n return result as TBase\n}\n\n/** The shipped entries with the ones from `extra` added or, when the id exists, replaced. */\nexport const mergeById = <TEntry extends Entry>(shipped: readonly TEntry[], extra: readonly TEntry[] | undefined): Map<string, TEntry> => {\n const entries = new Map<string, TEntry>()\n for (const entry of [...shipped, ...(extra ?? [])]) entries.set(entry.id, entry)\n return entries\n}\n\n/** Applies `patch` by id; a patch for an id that does not exist is ignored. */\nexport const applyPatches = <TEntry extends Entry>(entries: Map<string, TEntry>, patches: Readonly<Record<string, DeepPartial<TEntry> | Partial<TEntry>>> | undefined): void => {\n for (const [id, patch] of Object.entries(patches ?? {})) {\n const entry = entries.get(id)\n if (entry) entries.set(id, deepMerge(entry, patch))\n }\n}\n\nexport const removeIds = (entries: Map<string, unknown>, ids: readonly string[] | undefined): void => {\n for (const id of ids ?? []) entries.delete(id)\n}\n","import type { Vec3 } from './destruction'\n\n/**\n * The bench of a module: controls, layers and counters it declares as data. The host keeps the values, draws them in a generic way and hands\n * every change back through `ModuleHost.bench`. Nothing here is specific to a kind of module.\n */\nexport type ControlValue = number | boolean | string\n\nexport interface ChoiceOption {\n readonly id: string\n readonly name: string\n /** Heading the host lists the option under (`optgroup`, a grouped row of buttons). Options of a group must sit next to each other. */\n readonly group?: string\n}\n\ninterface ControlBase {\n /** snake_case, unique across the module's controls, layers and metrics. */\n readonly id: string\n /** Display name, already translated for the locale the host asked for. */\n readonly name: string\n readonly hint?: string\n readonly hidden?: boolean\n /**\n * The change (or the press, for an action) takes a noticeable time, a third of a second or more: the host shows its loading indicator while it works, with this text, or the control's name for `true`.\n * Only the host's own controls panel does it; a change made through `TestRoom.bench().set / act` runs at once.\n */\n readonly slow?: boolean | string\n}\n\nexport interface NumberControl extends ControlBase {\n readonly kind: 'number'\n readonly min: number\n readonly max: number\n readonly step?: number\n readonly unit?: string\n readonly default: number\n}\n\nexport interface BooleanControl extends ControlBase {\n readonly kind: 'boolean'\n readonly default: boolean\n}\n\nexport interface ChoiceControl extends ControlBase {\n readonly kind: 'choice'\n readonly options: readonly ChoiceOption[]\n readonly default: string\n}\n\n/** A button: no value, only the press. */\nexport interface ActionControl extends ControlBase {\n readonly kind: 'action'\n}\n\nexport type ModuleControl = NumberControl | BooleanControl | ChoiceControl | ActionControl\n\n/** Something of the module the viewer turns on or off (smoke, flash, casings). */\nexport interface ModuleLayer {\n readonly id: string\n readonly name: string\n /** On unless `false`. */\n readonly default?: boolean\n}\n\n/** Pulled: the room calls read only when it samples (~4 Hz, or on TestRoom.metrics()). */\nexport interface ModuleMetric {\n readonly id: string\n readonly name: string\n readonly unit?: string\n /** Budget: the host shows a bar and warns past it. */\n readonly max?: number\n readonly digits?: number\n read(): number | string\n}\n\nexport type BenchChange =\n | { readonly kind: 'control'; readonly id: string; readonly value: ControlValue }\n | { readonly kind: 'layer'; readonly id: string; readonly on: boolean }\n | { readonly kind: 'action'; readonly id: string }\n\nexport interface ControlPatch {\n readonly hidden?: boolean\n readonly disabled?: boolean\n readonly options?: readonly ChoiceOption[]\n readonly value?: ControlValue\n}\n\n/** What the host lends a module that declares a bench: the current values and the changes. */\nexport interface ModuleBench {\n value(id: string): ControlValue | undefined\n layer(id: string): boolean\n /** Right after attach returns, the host sends one change per control (not actions) and per layer, in declaration order. */\n onChange(listener: (change: BenchChange) => void): () => void\n /** `value` sets without emitting (no echo loops); `options` falls back to the first option if the value is no longer offered. */\n patch(id: string, patch: ControlPatch): void\n /** Move the host camera (a near / middle / far choice). */\n look(eye: Vec3, target: Vec3): void\n /** Shows a sheet on the host's panel, or takes it down with `null`. A host without a sheet area ignores it. */\n sheet?(sheet: BenchSheet | null): void\n}\n\n/**\n * A card of text the module puts on the host's panel (the sheet of an effect, of a weapon): what it is, its numbers, its steps, its colours and,\n * optionally, a strip of segments over time. Names and texts are already translated for the host's locale.\n */\nexport interface BenchSheet {\n readonly kicker?: string\n readonly title: string\n readonly body?: string\n readonly facts?: readonly { readonly label: string; readonly value: string }[]\n readonly steps?: readonly { readonly at: string; readonly text: string }[]\n readonly swatches?: readonly { readonly color: string; readonly name: string }[]\n readonly note?: string\n /** A strip of named segments (seconds), with tick marks and a playhead that follows the module metric `metric`. */\n readonly timeline?: {\n readonly segments: readonly { readonly name: string; readonly start: number; readonly end: number; readonly color: string }[]\n readonly ticks: readonly number[]\n readonly metric: string\n }\n}\n\nexport interface BenchReport {\n readonly ok: boolean\n readonly problems: readonly string[]\n}\n\nexport interface BenchDeclaration {\n readonly controls?: readonly ModuleControl[]\n readonly layers?: readonly ModuleLayer[]\n readonly metrics?: readonly ModuleMetric[]\n}\n\nconst SNAKE_CASE = /^[a-z][a-z0-9_]*$/\nconst finite = (n: unknown): n is number => typeof n === 'number' && Number.isFinite(n)\n\nfunction checkControl(control: ModuleControl, problems: string[]): void {\n const label = `control \"${control.id}\"`\n if (control.kind === 'number') {\n if (!finite(control.min) || !finite(control.max) || control.min >= control.max) problems.push(`${label} needs min < max`)\n if (control.step !== undefined && !(finite(control.step) && control.step > 0)) problems.push(`${label} needs a step > 0`)\n if (!finite(control.default) || control.default < control.min || control.default > control.max) problems.push(`${label} default ${String(control.default)} is outside ${control.min}..${control.max}`)\n return\n }\n if (control.kind !== 'choice') return\n if (control.options.length === 0) {\n problems.push(`${label} needs at least one option`)\n return\n }\n const seen = new Set<string>()\n const groups = new Set<string>()\n let previousGroup: string | undefined\n for (const option of control.options) {\n if (seen.has(option.id)) problems.push(`${label} repeats option \"${option.id}\"`)\n seen.add(option.id)\n if (option.group !== undefined && (typeof option.group !== 'string' || option.group === '')) problems.push(`${label} option \"${option.id}\" has an empty group`)\n else if (option.group !== undefined && option.group !== previousGroup && groups.has(option.group)) problems.push(`${label} group \"${option.group}\" is split: its options must be next to each other`)\n if (typeof option.group === 'string' && option.group !== '') groups.add(option.group)\n previousGroup = option.group\n }\n if (!seen.has(control.default)) problems.push(`${label} default \"${control.default}\" is not among its options`)\n}\n\n/** snake_case ids unique across controls, layers and metrics; min < max; step > 0; default in range; options non-empty, unique, default among them, each group in one run; metric max > 0. */\nexport function checkBench(declared: BenchDeclaration): BenchReport {\n const problems: string[] = []\n const ids = new Set<string>()\n const claim = (kind: string, id: string): void => {\n if (!SNAKE_CASE.test(id)) problems.push(`${kind} id \"${id}\" must be snake_case`)\n if (ids.has(id)) problems.push(`duplicate id \"${id}\" across controls, layers and metrics`)\n ids.add(id)\n }\n for (const control of declared.controls ?? []) {\n claim('control', control.id)\n checkControl(control, problems)\n }\n for (const layer of declared.layers ?? []) claim('layer', layer.id)\n for (const metric of declared.metrics ?? []) {\n claim('metric', metric.id)\n if (metric.max !== undefined && !(finite(metric.max) && metric.max > 0)) problems.push(`metric \"${metric.id}\" needs a max > 0`)\n }\n return { ok: problems.length === 0, problems }\n}\n","/** The weather, light and ground as the world is right now. Written by whoever drives the weather, read by whoever reacts to it. */\nexport interface EnvironmentState {\n /** Rain in mm/h; 0 is dry. */\n readonly rain: number\n /** Wind in m/s along x and z, and its strength (the length of that vector). */\n readonly windX: number\n readonly windZ: number\n readonly windSpeed: number\n /** Strongest gust in m/s. */\n readonly gust: number\n /** Render fog far distance in metres. */\n readonly fogFar: number\n /** How far one can see for gameplay, in metres (not the render fog). */\n readonly visibility: number\n /** 0 is full daylight, 1 is the darkest night. */\n readonly nightFactor: number\n readonly temperatureC: number\n /** Wet ground, 0..1: rises with rain and dries after it stops. */\n readonly wetness: number\n}\n\nexport type EnvironmentKey = keyof EnvironmentState\n\n/** A calm dry day (the normal world, before anything went wrong). */\nexport const DEFAULT_ENVIRONMENT: EnvironmentState = {\n rain: 0,\n windX: 0,\n windZ: 0,\n windSpeed: 0,\n gust: 0,\n fogFar: 220,\n visibility: 220,\n nightFactor: 0,\n temperatureC: 20,\n wetness: 0,\n}\n\n/** The host's environment (`ModuleHost.environment`): a store the weather module writes to and the others read. */\nexport interface EnvironmentBus {\n get(): EnvironmentState\n /** Merges `patch` into the state; listeners hear it only when a value really changed. */\n set(patch: Partial<EnvironmentState>): void\n /** Hears every change with the keys that changed. Returns the unsubscribe function. */\n on(listener: (state: EnvironmentState, changed: readonly EnvironmentKey[]) => void): () => void\n}\n\n/** A plain store that implements the bus; the test room and tests use it, a game may bring its own. */\nexport function createEnvironmentBus(initial: Partial<EnvironmentState> = {}): EnvironmentBus {\n let state: EnvironmentState = { ...DEFAULT_ENVIRONMENT, ...initial }\n const listeners = new Set<(state: EnvironmentState, changed: readonly EnvironmentKey[]) => void>()\n return {\n get: () => state,\n set(patch) {\n const changed = (Object.keys(patch) as EnvironmentKey[]).filter((key) => patch[key] !== undefined && patch[key] !== state[key])\n if (changed.length === 0) return\n const next = { ...state } as { -readonly [Key in EnvironmentKey]: number }\n for (const key of changed) next[key] = patch[key] as number\n state = next\n for (const listener of [...listeners]) listener(state, changed)\n },\n on(listener) {\n listeners.add(listener)\n return () => void listeners.delete(listener)\n },\n }\n}\n","import { applyPatches, deepMerge, mergeById, removeIds } from './registry'\nimport type { DeepPartial } from './registry'\n\n/** One category (kind) of items. Defaults and required contracts are inherited from the `extends` chain. */\nexport interface CategoryDef<TDefaults extends object = Record<string, unknown>> {\n readonly id: string\n /** Parent category id; the child inherits its defaults and its required contracts. */\n readonly extends?: string\n /** Field values every entry of this kind starts with; objects merge down the chain, arrays replace. */\n readonly defaults?: DeepPartial<TDefaults>\n /** Contract ids (`ContractChecker.id`) every entry of this kind, or of a descendant, must satisfy. */\n readonly requires?: readonly string[]\n /** An abstract category only groups: entries cannot declare it directly, only its descendants. */\n readonly abstract?: boolean\n}\n\n/** Where a checker is being run: the entry's kind and the chain of categories root first. */\nexport interface ContractContext {\n readonly kind: string\n readonly chain: readonly string[]\n}\n\n/** A named contract: returns the problems of an entry, each a short phrase like `missing leftover.despawnSeconds`. Empty means it holds. */\nexport interface ContractChecker<TEntry> {\n readonly id: string\n check(entry: TEntry, ctx: ContractContext): string[]\n}\n\nexport interface CategoryOptions {\n /** Categories added to the shipped ones; the same id replaces. */\n readonly extra?: readonly CategoryDef[]\n /** Partial changes by id, applied after `extra`. */\n readonly patches?: Readonly<Record<string, DeepPartial<CategoryDef> | Partial<CategoryDef>>>\n /** Ids taken out of the tree (their children are then reported by `check()`). */\n readonly remove?: readonly string[]\n}\n\nexport interface CategoryRegistry {\n get(id: string): CategoryDef | undefined\n has(id: string): boolean\n ids(): string[]\n /** Root first, ending at `id`. Throws on an unknown id, an unknown parent or a cycle. */\n chain(id: string): string[]\n /** `defaults` merged along the chain, root first, so the closest category wins. */\n defaults(id: string): Record<string, unknown>\n /** Union of `requires` along the chain, order kept, without duplicates. */\n requires(id: string): string[]\n /** True when `id` is `ancestorId` or descends from it. */\n isA(id: string, ancestorId: string): boolean\n /** Problems in the tree itself: duplicate ids, unknown `extends`, cycles. */\n check(): string[]\n}\n\nexport interface CategorizedOptions {\n /** Field of the entry that names its category. Default `kind`. */\n readonly kindField?: string\n /** Known gaps by entry id: problems starting with one of these texts go to `allowed`, so the list can shrink over time. */\n readonly allow?: Readonly<Record<string, readonly string[]>>\n}\n\nexport interface CategorizedReport {\n readonly ok: boolean\n readonly problems: string[]\n readonly allowed: string[]\n}\n\nexport const defineCategories = (defs: readonly CategoryDef[], options: CategoryOptions = {}): CategoryRegistry => {\n const problems: string[] = []\n const duplicates = (list: readonly CategoryDef[]): void => {\n const ids = new Set<string>()\n for (const def of list) {\n if (ids.has(def.id)) problems.push(`duplicate category \"${def.id}\"`)\n ids.add(def.id)\n }\n }\n duplicates(defs)\n duplicates(options.extra ?? [])\n\n const entries = mergeById(defs, options.extra)\n applyPatches(entries, options.patches)\n removeIds(entries, options.remove)\n\n const chain = (id: string): string[] => {\n const path: string[] = []\n let current: string | undefined = id\n while (current !== undefined) {\n const def = entries.get(current)\n if (!def) throw new Error(path.length === 0 ? `unknown category \"${current}\"` : `category \"${path[0]}\" has unknown parent \"${current}\"`)\n if (path.includes(current)) throw new Error(`category cycle: ${[...path, current].reverse().join(' -> ')}`)\n path.push(current)\n current = def.extends\n }\n return path.reverse()\n }\n\n const registry: CategoryRegistry = {\n get: (id) => entries.get(id),\n has: (id) => entries.has(id),\n ids: () => [...entries.keys()],\n chain,\n defaults: (id) => chain(id).reduce<Record<string, unknown>>((acc, ancestor) => deepMerge(acc, entries.get(ancestor)?.defaults), {}),\n requires: (id) => {\n const out: string[] = []\n for (const ancestor of chain(id)) for (const contract of entries.get(ancestor)?.requires ?? []) if (!out.includes(contract)) out.push(contract)\n return out\n },\n isA: (id, ancestorId) => {\n try {\n return chain(id).includes(ancestorId)\n } catch {\n return false\n }\n },\n check: () => {\n const found = [...problems]\n for (const [id, def] of entries) {\n if (def.extends !== undefined && !entries.has(def.extends)) found.push(`category \"${id}\" extends unknown \"${def.extends}\"`)\n else {\n try {\n chain(id)\n } catch (error) {\n const message = (error as Error).message\n // The same cycle is found from each of its members; the dedupe keeps one line per distinct message.\n if (message.startsWith('category cycle') && !found.includes(message)) found.push(message)\n }\n }\n }\n return found\n },\n }\n return registry\n}\n\n/** The entry with the defaults of its category underneath: the entry wins, objects merge, arrays replace. */\nexport const resolveEntry = <TEntry extends object>(registry: CategoryRegistry, entry: TEntry, kindField = 'kind'): TEntry =>\n deepMerge(registry.defaults(String((entry as Record<string, unknown>)[kindField])) as TEntry, entry)\n\n/** Checks that each entry has a known, concrete kind and satisfies every contract its chain requires. */\nexport const checkCategorized = <TEntry extends { readonly id: string }>(\n entries: readonly TEntry[],\n registry: CategoryRegistry,\n checkers: readonly ContractChecker<TEntry>[],\n options: CategorizedOptions = {},\n): CategorizedReport => {\n const kindField = options.kindField ?? 'kind'\n const byId = new Map(checkers.map((checker) => [checker.id, checker]))\n const problems: string[] = [...registry.check()]\n const allowed: string[] = []\n\n for (const entry of entries) {\n const kind = String((entry as Record<string, unknown>)[kindField])\n if (!registry.has(kind)) {\n problems.push(`\"${entry.id}\" has unknown kind \"${kind}\"`)\n continue\n }\n if (registry.get(kind)?.abstract) {\n problems.push(`\"${entry.id}\" has abstract kind \"${kind}\"`)\n continue\n }\n let path: string[]\n try {\n path = registry.chain(kind)\n } catch (error) {\n problems.push(`\"${entry.id}\" (${kind}): ${(error as Error).message}`)\n continue\n }\n const resolved = resolveEntry(registry, entry, kindField)\n for (const contract of registry.requires(kind)) {\n const owner = path.find((ancestor) => registry.get(ancestor)?.requires?.includes(contract)) ?? kind\n const checker = byId.get(contract)\n if (!checker) {\n problems.push(`kind \"${kind}\" requires contract \"${contract}\" but no checker is registered`)\n continue\n }\n const prefix = `\"${entry.id}\" (${kind}): `\n for (const problem of checker.check(resolved, { kind, chain: path })) {\n const text = `${prefix}${problem}, required by ${owner}`\n if ((options.allow?.[entry.id] ?? []).some((start) => problem.startsWith(start))) allowed.push(text)\n else problems.push(text)\n }\n }\n }\n return { ok: problems.length === 0, problems: [...new Set(problems)], allowed }\n}\n","import { applyPatches, deepMerge, mergeById, removeIds } from '@adatechnology/game-contracts'\n\nimport { ITEM_CATEGORIES } from './categories'\nimport type { ItemsCatalog, ItemsOptions } from './catalog-types'\nimport { checkItems, findDuplicateIds } from './check-items'\nimport { DEFAULT_RULES } from './rules'\nimport type { RecipeDef } from './recipe-types'\nimport type { ContainerDef, ItemDef, PlaceDef, PoolEntry } from './types'\nimport type { UseEffectDef } from './use-types'\n\nconst LITRES_PER_CUBIC_METRE = 1000\n\n/** Fills what a pack leaves out: the volume comes from the size. */\nconst withDerivedFields = (item: ItemDef): ItemDef => (item.volume === undefined ? { ...item, volume: item.size[0] * item.size[1] * item.size[2] * LITRES_PER_CUBIC_METRE } : item)\n\nconst buildPools = (options: ItemsOptions, packs: NonNullable<ItemsOptions['packs']>): Map<string, readonly PoolEntry[]> => {\n const pools = new Map<string, readonly PoolEntry[]>()\n for (const source of [...packs, options]) for (const [key, entries] of Object.entries(source.pools ?? {})) pools.set(key, entries)\n const problems: string[] = []\n for (const source of [...packs, options]) {\n for (const [alias, key] of Object.entries(source.poolAliases ?? {})) {\n const entries = pools.get(key)\n if (entries) pools.set(alias, entries)\n else problems.push(`pool alias \"${alias}\" points to unknown pool \"${key}\"`)\n }\n }\n if (problems.length > 0) throw new Error(`game-items: the catalog is not consistent:\\n${problems.map((problem) => ` - ${problem}`).join('\\n')}`)\n return pools\n}\n\nconst groupBy = (items: Iterable<ItemDef>, keysOf: (item: ItemDef) => readonly string[]): Map<string, ItemDef[]> => {\n const groups = new Map<string, ItemDef[]>()\n for (const item of items) for (const key of keysOf(item)) groups.set(key, [...(groups.get(key) ?? []), item])\n return groups\n}\n\n/**\n * Create the catalog. Order: the packs in order (added or replaced by id), then `patch`, then `remove`, then `include`; categories, places and\n * containers are those of the packs plus the options, by id. Every inconsistency found is reported in one error.\n */\nexport const createItems = (options: ItemsOptions = {}): ItemsCatalog => {\n const packs = options.packs ?? []\n const items = mergeById([] as ItemDef[], packs.flatMap((pack) => pack.items))\n applyPatches<ItemDef>(items, options.patch)\n removeIds(items, options.remove)\n if (options.include) for (const [id, item] of items) if (!options.include(item)) items.delete(id)\n for (const [id, item] of items) items.set(id, withDerivedFields(item))\n\n const categories = mergeById(ITEM_CATEGORIES, [...packs.flatMap((pack) => pack.categories ?? []), ...(options.categories ?? [])])\n const places = mergeById<PlaceDef>([], [...packs.flatMap((pack) => pack.places ?? []), ...(options.places ?? [])])\n const containers = mergeById<ContainerDef>([], [...packs.flatMap((pack) => pack.containers ?? []), ...(options.containers ?? [])])\n const useEffects = [...mergeById<UseEffectDef>([], [...packs.flatMap((pack) => pack.useEffects ?? []), ...(options.useEffects ?? [])]).values()]\n const recipes = mergeById<RecipeDef>([], [...packs.flatMap((pack) => pack.recipes ?? []), ...(options.recipes ?? [])])\n const pools = buildPools(options, packs)\n const rules = deepMerge(DEFAULT_RULES, options.rules)\n\n const problems = [\n ...packs.flatMap((pack) => findDuplicateIds(`item in pack \"${pack.id}\"`, pack.items)),\n ...findDuplicateIds('category', options.categories),\n ...findDuplicateIds('place', options.places),\n ...findDuplicateIds('container', options.containers),\n ...findDuplicateIds('use effect', options.useEffects),\n ...findDuplicateIds('recipe', options.recipes),\n ...checkItems({ items, categories, places, containers, rules }),\n ]\n if (problems.length > 0) throw new Error(`game-items: the catalog is not consistent:\\n${problems.map((problem) => ` - ${problem}`).join('\\n')}`)\n\n const byCategory = groupBy(items.values(), (item) => [item.category])\n const byPlace = groupBy(items.values(), (item) => item.finds?.places ?? [])\n const byTag = groupBy(items.values(), (item) => item.tags ?? [])\n\n return {\n items,\n categories,\n places,\n containers,\n pools,\n useEffects,\n recipes,\n rules,\n has: (id) => items.has(id),\n get(id) {\n const item = items.get(id)\n if (!item) throw new Error(`game-items: unknown item \"${id}\"`)\n return item\n },\n list: () => [...items.values()],\n byCategory: (category) => [...(byCategory.get(category) ?? [])],\n byPlace: (place) => [...(byPlace.get(place) ?? [])],\n byTag: (tag) => [...(byTag.get(tag) ?? [])],\n }\n}\n","import type { CategoryDef } from './types'\n\n/** The 14 categories of the team's catalog; always registered. */\nexport const ITEM_CATEGORIES: readonly CategoryDef[] = [\n { id: 'food', name: 'Food' },\n { id: 'drink', name: 'Drink' },\n { id: 'medical', name: 'Medical' },\n { id: 'tools', name: 'Tools' },\n { id: 'melee', name: 'Melee' },\n { id: 'materials', name: 'Materials' },\n { id: 'clothing', name: 'Clothing' },\n { id: 'bags', name: 'Bags' },\n { id: 'electronics', name: 'Electronics' },\n { id: 'fuel', name: 'Fuel' },\n { id: 'outdoors', name: 'Outdoors' },\n { id: 'books', name: 'Books' },\n { id: 'collectibles', name: 'Collectibles' },\n { id: 'keys', name: 'Keys' },\n]\n","/**\n * Public types of @adatechnology/game-items.\n *\n * An `ItemDef` is a real-world thing (a can of beans, a hammer, a jacket) with its true size and weight; the rest of the fields are optional groups that\n * only the categories that need them fill (nutrition for food, protection for clothing, carry for bags). Units: metres, kilograms, litres, days.\n */\nimport type { BodySlot } from '@adatechnology/game-contracts'\nimport type { ItemDef as BaseItemDef } from '@adatechnology/game-interactables'\n\nimport type { RecipeDef } from './recipe-types'\nimport type { UseEffectDef } from './use-types'\n\nexport type { BaseItemDef }\n\nexport const RARITIES = ['common', 'uncommon', 'rare', 'very_rare', 'legendary', 'unique'] as const\nexport type Rarity = (typeof RARITIES)[number]\n\n/** The body slots an item covers: the vocabulary is `BodySlot` of game-contracts (`over` is a layer worn over the others, such as a coat or a vest). */\nexport type { BodySlot } from '@adatechnology/game-contracts'\nexport const BODY_SLOTS: readonly BodySlot[] = ['head', 'eyes', 'torso', 'arms', 'hands', 'legs', 'feet', 'over']\n\nexport const DURABILITY_KINDS = ['uses', 'portions', 'doses', 'hits', 'cuts', 'shots', 'condition', 'charges', 'seconds', 'days', 'infinite', 'container'] as const\nexport type DurabilityKind = (typeof DURABILITY_KINDS)[number]\n\n/** How long an item lasts, read from the source text (\"10 uses\", \"4 portions\", \"300 hits\", \"infinite\"). */\nexport interface Durability {\n kind: DurabilityKind\n amount?: number\n /** Source qualifier when the amount alone is not enough (for example the voltage of a battery). */\n per?: string\n}\n\n/** Id of a place where items turn up (house, hospital, farm...). Places are a registry: a pack or the game declares the ones it uses. */\nexport type PlaceTag = string\n\n/** Id of an item category. The 14 of `ITEM_CATEGORIES` are always present; a game adds its own through `createItems({ categories })`. */\nexport type ItemCategory = string\n\nexport interface CategoryDef {\n id: ItemCategory\n /** Display name in English; games translate by id. */\n name?: string\n}\n\nexport interface PlaceDef {\n id: PlaceTag\n name?: string\n}\n\n/**\n * Where items are found inside a place (a fridge, a drawer, a locker): which categories it draws from and how many stacks. The finds roll reads `count`,\n * `categories` (or `categoriesByPlace`, with `*` for any other place) and `places`; other fields of a pack's container are kept and ignored.\n */\nexport interface ContainerDef {\n id: string\n name?: string\n /** Places the container turns up in (`toLootTables` only); empty or missing means any. */\n places?: readonly PlaceTag[]\n /** Weight of each category when a stack is drawn for this container. */\n categories?: Readonly<Record<ItemCategory, number>>\n /** When `categories` is missing: the weights by place (a shop shelf stocks what the shop sells). */\n categoriesByPlace?: Readonly<Record<PlaceTag, Readonly<Record<ItemCategory, number>>>>\n /** Range of stacks a container holds when it is filled. */\n count?: readonly [number, number]\n}\n\n/** One thing an explicit pool can hold (a fridge: water bottle, milk, eggs...): `item` is the catalog id, `weight` the odds, `qty` the range. */\nexport interface PoolEntry {\n item: string\n weight: number\n qty: readonly [number, number]\n /** Supplies (food, water, medicine, tools) are what a fortified house stocks up on. */\n isSupply?: boolean\n}\n\nexport interface ItemDef extends BaseItemDef {\n category: ItemCategory\n /** The old household category (`kitchen`, `hygiene`, `office`...), `perishable` or `craft_only`. */\n tags?: readonly string[]\n rarity: Rarity\n /** Litres. Derived from `size` when the pack does not give it. */\n volume?: number\n durability?: Durability\n /** Days to spoil at room temperature. */\n shelfLife?: number\n portions?: number\n cookable?: boolean\n nutrition?: { satiety?: number; hydration?: number }\n /** Fractions 0..1 per attack, per body slot covered. */\n protection?: {\n slots: readonly BodySlot[]\n bite?: number\n scratch?: number\n warmth?: number\n /** Against projectiles (read by game-characters): `resistance` in penetration units; a stopped projectile does `blunt` of its damage, one that goes through `pass`. */\n ballistic?: { resistance: number; blunt?: number; pass?: number; consumable?: boolean }\n }\n carry?: { capacityKg: number; weightReduction: number; quickSlots: number; wheels?: boolean }\n /** Id of the weapon in the arsenal when the item is also one. */\n weapon?: string\n /** Id of the liquid (`game-fluids`) when the item holds one. */\n fluid?: { liquid: string; liters: number }\n uses?: readonly string[]\n finds?: { places: readonly PlaceTag[] }\n /** Battery-like items: share of the charge lost per month. */\n charge?: { lossPerMonth: number }\n /** Fuel-like items: after `afterDays` each use fails with probability `chance`. */\n agingFault?: { afterDays: number; chance: number }\n /** Key of the 3D model in `game-items-three`; without it a simple shape from `shape` is drawn. */\n model?: string\n}\n\n/** A bundle of content: items plus the categories, places and containers they rely on. */\nexport interface ItemPack {\n id: string\n items: readonly ItemDef[]\n categories?: readonly CategoryDef[]\n places?: readonly PlaceDef[]\n containers?: readonly ContainerDef[]\n /** What using an item does, in priority order (`resolveUse`). */\n useEffects?: readonly UseEffectDef[]\n recipes?: readonly RecipeDef[]\n /** Explicit pools of what a kind of furniture holds, by key (`fridge`, `sink`...); they win over the category roll of a container. */\n pools?: Readonly<Record<string, readonly PoolEntry[]>>\n /** Keys that share another key's pool (`garage_wardrobe` -> `wardrobe`). */\n poolAliases?: Readonly<Record<string, string>>\n}\n","import type { ItemRules } from './rules-types'\nimport type { CategoryDef, ContainerDef, ItemDef, PlaceDef } from './types'\nimport { BODY_SLOTS, DURABILITY_KINDS, RARITIES } from './types'\n\nexport interface ItemsParts {\n readonly items: ReadonlyMap<string, ItemDef>\n readonly categories: ReadonlyMap<string, CategoryDef>\n readonly places: ReadonlyMap<string, PlaceDef>\n readonly containers: ReadonlyMap<string, ContainerDef>\n readonly rules: ItemRules\n}\n\n/** Ids that appear more than once in a list a game passed in. */\nexport const findDuplicateIds = (kind: string, entries: readonly { readonly id: string }[] | undefined): string[] => {\n const seen = new Set<string>()\n const problems: string[] = []\n for (const { id } of entries ?? []) {\n if (seen.has(id)) problems.push(`${kind} \"${id}\" is listed more than once`)\n seen.add(id)\n }\n return problems\n}\n\nconst isFraction = (value: number | undefined): boolean => value === undefined || (value >= 0 && value <= 1)\nconst isPositive = (value: number): boolean => Number.isFinite(value) && value > 0\n\nconst checkItem = (item: ItemDef, { categories, places }: ItemsParts): string[] => {\n const problems: string[] = []\n const issue = (text: string): number => problems.push(`item \"${item.id}\" ${text}`)\n if (!categories.has(item.category)) issue(`has unknown category \"${item.category}\"`)\n if (!RARITIES.includes(item.rarity)) issue(`has unknown rarity \"${item.rarity}\"`)\n if (item.size.length !== 3 || !item.size.every(isPositive)) issue(`has an invalid size [${item.size.join(', ')}]`)\n if (!(item.weight >= 0) || !Number.isFinite(item.weight)) issue(`has a weight of ${item.weight} kg`)\n if (item.volume !== undefined && !isPositive(item.volume)) issue(`has a volume of ${item.volume} L`)\n if (item.shelfLife !== undefined && !isPositive(item.shelfLife)) issue(`has a shelf life of ${item.shelfLife} days`)\n if (item.portions !== undefined && !(Number.isInteger(item.portions) && item.portions > 0)) issue(`has ${item.portions} portions`)\n if (item.durability && !DURABILITY_KINDS.includes(item.durability.kind)) issue(`has unknown durability kind \"${item.durability.kind}\"`)\n const { protection } = item\n if (protection) {\n for (const slot of protection.slots) if (!BODY_SLOTS.includes(slot)) issue(`protects unknown body slot \"${slot}\"`)\n if (protection.slots.length === 0) issue('has protection but covers no body slot')\n if (![protection.bite, protection.scratch, protection.warmth].every(isFraction)) issue('has a protection value outside 0..1')\n }\n if (item.carry && !(item.carry.capacityKg > 0 && isFraction(item.carry.weightReduction))) issue('has an invalid carry (capacity above 0, reduction within 0..1)')\n if (places.size > 0) for (const place of item.finds?.places ?? []) if (!places.has(place)) issue(`is found in unknown place \"${place}\"`)\n return problems\n}\n\nconst checkContainer = (container: ContainerDef, { categories }: ItemsParts): string[] => {\n const problems: string[] = []\n for (const category of Object.keys(container.categories ?? {})) {\n if (!categories.has(category)) problems.push(`container \"${container.id}\" draws from unknown category \"${category}\"`)\n }\n const [low, high] = container.count ?? [0, 0]\n if (low < 0 || high < low) problems.push(`container \"${container.id}\" has an invalid count [${low}, ${high}]`)\n return problems\n}\n\nconst checkRules = ({ rarity, freshness, storage, carry, protection }: ItemRules): string[] => {\n const problems: string[] = []\n const hasNegativeWeight = RARITIES.some((id) => !(rarity.weights[id] >= 0))\n if (hasNegativeWeight || !RARITIES.some((id) => rarity.weights[id] > 0 && !rarity.fixedOnly.includes(id))) {\n problems.push('rules.rarity.weights must be non-negative with at least one rollable rarity above 0')\n }\n if (!(freshness.stale > 0 && freshness.stale < freshness.spoiled && freshness.spoiled < freshness.rotten)) problems.push('rules.freshness must rise: 0 < stale < spoiled < rotten')\n for (const [id, rule] of Object.entries(storage)) if (!isPositive(rule.multiplier) || (rule.limitDays !== undefined && !isPositive(rule.afterLimit ?? 0))) problems.push(`rules.storage \"${id}\" is invalid`)\n if (!(isPositive(carry.baseKg) && carry.perStrengthKg >= 0 && isPositive(carry.factor) && carry.encumbered > 0 && carry.overloaded > carry.encumbered)) problems.push('rules.carry is invalid')\n if (!(protection.cap > 0 && protection.cap <= 1 && isFraction(protection.tornShare))) problems.push('rules.protection is invalid')\n return problems\n}\n\n/** Every inconsistency of a catalog, one line each; empty when it is sound. */\nexport const checkItems = (parts: ItemsParts): string[] => [\n ...[...parts.items.values()].flatMap((item) => checkItem(item, parts)),\n ...[...parts.containers.values()].flatMap((container) => checkContainer(container, parts)),\n ...checkRules(parts.rules),\n]\n","import type { ItemRules } from './rules-types'\n\n/**\n * The numbers of the rules, from the team's Vale Cinzento delivery. `storage` was read by hand from its table (Validade e apodrecimento) so the\n * skeleton runs; the source test of the catalog tool proves it against the HTML (legendary and unique are never rolled: L276). Every field is an option of `createItems({ rules })`.\n */\nexport const DEFAULT_RULES: ItemRules = {\n rarity: {\n weights: { common: 60, uncommon: 28, rare: 9, very_rare: 2.5, legendary: 0.5, unique: 0 },\n fixedOnly: ['legendary', 'unique'],\n },\n freshness: { stale: 0.5, spoiled: 1, rotten: 1.5 },\n storage: {\n fridge: { multiplier: 0.33, needsPower: true },\n freezer: { multiplier: 0.1, needsPower: true },\n cooler: { multiplier: 0.5, limitDays: 2, afterLimit: 1 },\n delivery_bag: { multiplier: 0.8 },\n cellar: { multiplier: 0.66 },\n ambient: { multiplier: 1 },\n hot: { multiplier: 2 },\n },\n carry: { baseKg: 8, perStrengthKg: 2.5, factor: 1.2, encumbered: 1, overloaded: 1.5 },\n protection: { cap: 0.9, wear: { bite: 8, scratch: 3 }, tornShare: 0.25, repairMargin: 10 },\n aging: { thawShelfDays: { freezer: 2 } },\n inventory: { defaultSlots: 10, encumberedRunFactor: 0.75 },\n use: {\n freshness: {\n stale: { satietyFactor: 0.7, poisonChance: 0.1, morale: 0, isEdible: true },\n spoiled: { satietyFactor: 0.7, poisonChance: 0.5, morale: -20, isEdible: true },\n rotten: { satietyFactor: 0, poisonChance: 0, morale: 0, isEdible: false },\n },\n cookedPoisonFactor: 0.25,\n },\n spawn: {\n retailNew: true,\n retailPlaces: ['supermarket', 'pharmacy', 'mall', 'gas_station', 'gun_shop'],\n retailContainers: ['store_shelf', 'stockroom'],\n condition: { common: [30, 90], uncommon: [40, 90], rare: [50, 100], very_rare: [50, 100], legendary: [50, 100], unique: [50, 100] },\n ageShare: [0, 0.6],\n charge: [0.2, 1],\n fillable: ['fuel_jerrycan'],\n fill: [0, 0.6],\n },\n finds: {\n fallbackContainer: 'zombie_corpse',\n rollExcluded: ['ammo_7_62x39'],\n depletion: [\n { places: ['pharmacy', 'gun_shop', 'police_station'], perDay: 0.05, floor: 0.3 },\n { places: ['supermarket', 'gas_station'], perDay: 0.04, floor: 0.35 },\n { places: ['mall', 'hospital'], perDay: 0.025, floor: 0.5 },\n { places: ['house', 'apartment'], perDay: 0.01, floor: 0.7 },\n { places: ['farm', 'warehouse', 'mine', 'dam', 'lodge', 'church'], perDay: 0.005, floor: 0.85 },\n { places: ['military_base'], perDay: 0, floor: 1 },\n ],\n regionMultiplier: {},\n states: { normal: 'normal', fortified: 'fortified', abandoned: 'abandoned' },\n pool: {\n defaultFootprint: 0.5,\n offset: 1.5,\n perSquareMetre: 3,\n jitter: 1.5,\n min: 2,\n max: 5,\n fortifiedExtra: 2,\n supplyWeight: 2.5,\n supplyExtraQty: 1,\n abandonedEmptyChance: 0.4,\n abandonedKept: 1,\n junkChance: 0.5,\n junkItem: 'food_packaging',\n spoiledFoodItem: 'leftover_meal',\n coldContainers: ['geladeira', 'refrig_exp', 'freezer'],\n },\n },\n}\n","import { DEFAULT_RULES } from './rules'\nimport type { ItemRules, StorageId } from './rules-types'\nimport type { ItemDef } from './types'\n\nexport type Freshness = 'fresh' | 'stale' | 'spoiled' | 'rotten'\n\n/**\n * What an item remembers about its age. Nothing ticks: the account is closed lazily, when the item moves or someone looks at it.\n * Times are in days on the host's clock.\n */\nexport interface AgeState {\n /** Effective age: days at room temperature. */\n ageDays: number\n /** Time at which `ageDays` was last closed. */\n since: number\n storage: StorageId\n /** Time at which the item entered `storage` (a cooler only helps for its first days). */\n storedAt: number\n /** Replaces the item's shelf life (a thawed freezer leaves 2 days). */\n shelfLife?: number\n}\n\nexport interface AgeOptions {\n /** Whether the storage has power right now (fridge, freezer). Default true. */\n powered?: boolean\n rules?: ItemRules\n}\n\nconst storageRuleOf = (rules: ItemRules, storage: StorageId) => {\n const rule = rules.storage[storage]\n if (!rule) throw new Error(`game-items: unknown storage \"${storage}\"`)\n return rule\n}\n\n/** The multiplier of the age at one instant: `heldDays` is how long the item has been in `storage`. */\nexport const storageMultiplier = (storage: StorageId, options: AgeOptions & { heldDays?: number } = {}): number => {\n const { powered = true, rules = DEFAULT_RULES, heldDays = 0 } = options\n const rule = storageRuleOf(rules, storage)\n if (rule.needsPower && !powered) return 1\n if (rule.limitDays !== undefined && heldDays >= rule.limitDays) return rule.afterLimit ?? 1\n return rule.multiplier\n}\n\n/** Days of effective age accrued between `from` and `to` in a storage the item entered at `storedAt`. */\nconst accruedDays = (storage: StorageId, window: { storedAt: number; from: number; to: number }, options: AgeOptions): number => {\n const { powered = true, rules = DEFAULT_RULES } = options\n const rule = storageRuleOf(rules, storage)\n const elapsed = window.to - window.from\n if (elapsed <= 0) return 0\n if (rule.needsPower && !powered) return elapsed\n if (rule.limitDays === undefined) return elapsed * rule.multiplier\n const limitEnd = window.storedAt + rule.limitDays\n const early = Math.max(0, Math.min(window.to, limitEnd) - Math.max(window.from, window.storedAt))\n return early * rule.multiplier + (elapsed - early) * (rule.afterLimit ?? 1)\n}\n\n/** Closes the account up to `now`: `ageDays += (now - since) x multiplier`. Pure: returns the new state. */\nexport const advanceAge = (state: AgeState, now: number, options: AgeOptions = {}): AgeState => {\n const { powered = true, rules = DEFAULT_RULES } = options\n const rule = storageRuleOf(rules, state.storage)\n const thawDays = rules.aging.thawShelfDays[state.storage]\n const isThawing = rule.needsPower === true && !powered && thawDays !== undefined && state.shelfLife === undefined\n const base = isThawing ? { ...state, ageDays: 0, shelfLife: thawDays } : state\n const ageDays = base.ageDays + accruedDays(state.storage, { storedAt: state.storedAt, from: state.since, to: now }, options)\n return { ...base, ageDays, since: Math.max(now, state.since) }\n}\n\n/** Moves the item to another storage: closes the account in the old one, then the new multiplier applies from `now`. */\nexport const moveToStorage = (state: AgeState, now: number, storage: StorageId, options: AgeOptions = {}): AgeState => ({\n ...advanceAge(state, now, options),\n storage,\n storedAt: now,\n})\n\n/** Age as a share of the shelf life; 0 for an item that does not spoil. */\nexport const shelfRatio = (item: ItemDef, state: AgeState): number => {\n const shelfLife = state.shelfLife ?? item.shelfLife\n return shelfLife === undefined ? 0 : state.ageDays / shelfLife\n}\n\n/** `fresh`, `stale`, `spoiled` or `rotten` at 0.5, 1 and 1.5 of the shelf life (the rule's `freshness`). Closes the account up to `now` first. */\nexport const freshness = (item: ItemDef, state: AgeState, now: number, options: AgeOptions = {}): Freshness => {\n const { rules = DEFAULT_RULES } = options\n const ratio = shelfRatio(item, advanceAge(state, now, options))\n if (ratio >= rules.freshness.rotten) return 'rotten'\n if (ratio >= rules.freshness.spoiled) return 'spoiled'\n if (ratio >= rules.freshness.stale) return 'stale'\n return 'fresh'\n}\n\n/** Charge left (0..1) of a battery-like item: it loses `charge.lossPerMonth` of the full charge per 30 days of effective age. */\nexport const chargeLevel = (item: ItemDef, initialCharge: number, ageDays: number): number => {\n if (!item.charge) return initialCharge\n return Math.max(0, initialCharge - item.charge.lossPerMonth * (ageDays / 30))\n}\n\n/** True when one use of an old fuel-like item fails: past `agingFault.afterDays` each use fails with probability `chance`. Draws once, only when it can fail. */\nexport const failsToStart = (item: ItemDef, ageDays: number, random: () => number): boolean => {\n if (!item.agingFault || ageDays <= item.agingFault.afterDays) return false\n return random() < item.agingFault.chance\n}\n","import { DEFAULT_RULES } from './rules'\nimport type { ItemRules } from './rules-types'\nimport type { BodySlot, ItemDef } from './types'\n\nexport type AttackKind = 'bite' | 'scratch'\n\n/** A piece of clothing on a body: the item and its condition, 0 (torn) to 100 (new). */\nexport interface WornPiece {\n item: ItemDef\n condition: number\n}\n\nconst FULL_CONDITION = 100\n\nconst covers = (piece: WornPiece, slot: BodySlot): boolean => piece.item.protection?.slots.includes(slot) ?? false\n\n/** What one piece blocks of an attack: its value times its condition; a torn piece (condition 0) keeps `tornShare` of the value. */\nexport const pieceBlock = (piece: WornPiece, attack: AttackKind, rules: ItemRules = DEFAULT_RULES): number => {\n const value = piece.item.protection?.[attack] ?? 0\n const share = piece.condition <= 0 ? rules.protection.tornShare : piece.condition / FULL_CONDITION\n return value * share\n}\n\n/** Share of an attack on `slot` that clothing blocks: `1 - PROD(1 - value x condition)`, never above the cap (there is always some risk). */\nexport const blockChance = (pieces: readonly WornPiece[], slot: BodySlot, attack: AttackKind, rules: ItemRules = DEFAULT_RULES): number => {\n const unblocked = pieces.filter((piece) => covers(piece, slot)).reduce((product, piece) => product * (1 - pieceBlock(piece, attack, rules)), 1)\n return Math.min(rules.protection.cap, 1 - unblocked)\n}\n\n/** A blocked attack wears every piece that covers the slot and blocks something: bite -8, scratch -3 (never below 0). */\nexport const wearBlocked = (pieces: readonly WornPiece[], slot: BodySlot, attack: AttackKind, rules: ItemRules = DEFAULT_RULES): WornPiece[] =>\n pieces.map((piece) => {\n if (!covers(piece, slot) || pieceBlock(piece, attack, rules) <= 0) return piece\n return { ...piece, condition: Math.max(0, piece.condition - rules.protection.wear[attack]) }\n })\n\n/** A repair kit restores up to the maximum condition minus the margin (10); a piece already better is left alone. */\nexport const repairPiece = (piece: WornPiece, rules: ItemRules = DEFAULT_RULES, maxCondition: number = FULL_CONDITION): WornPiece => ({\n ...piece,\n condition: Math.max(piece.condition, maxCondition - rules.protection.repairMargin),\n})\n","import { DEFAULT_RULES } from './rules'\nimport type { ItemRules } from './rules-types'\nimport type { ItemDef } from './types'\n\nexport interface CarryEntry {\n item: ItemDef\n count: number\n}\n\nexport type LoadLevel = 'normal' | 'encumbered' | 'overloaded'\n\nexport interface LoadState {\n /** Load as a share of the maximum. */\n ratio: number\n level: LoadLevel\n /** Multiplier of running speed and breath. */\n runFactor: number\n canRun: boolean\n}\n\n/** What a character can carry, kg: `(8 + 2.5 x strength) x 1.2` with the default rules. */\nexport const maxLoadKg = (strength: number, rules: ItemRules = DEFAULT_RULES): number => (rules.carry.baseKg + rules.carry.perStrengthKg * strength) * rules.carry.factor\n\nconst sumKg = (entries: readonly CarryEntry[]): number => entries.reduce((total, entry) => total + entry.item.weight * entry.count, 0)\n\n/** Weight carried: what is outside the bag counts in full, what is inside counts times `(1 - weightReduction)`. */\nexport const carriedKg = (parts: { loose: readonly CarryEntry[]; packed?: readonly CarryEntry[]; weightReduction?: number }): number =>\n sumKg(parts.loose) + sumKg(parts.packed ?? []) * (1 - (parts.weightReduction ?? 0))\n\n/** Above 100% of the maximum, running and breath drop 25%; above 150% the character cannot run. */\nexport const loadState = (loadKg: number, maxKg: number, rules: ItemRules = DEFAULT_RULES): LoadState => {\n const ratio = maxKg > 0 ? loadKg / maxKg : Number.POSITIVE_INFINITY\n if (ratio > rules.carry.overloaded) return { ratio, level: 'overloaded', runFactor: 0, canRun: false }\n if (ratio > rules.carry.encumbered) return { ratio, level: 'encumbered', runFactor: rules.inventory.encumberedRunFactor, canRun: true }\n return { ratio, level: 'normal', runFactor: 1, canRun: true }\n}\n\n/** The bag of a character: how many item slots it has and how much it holds. */\nexport interface BagOption {\n slots: number\n capacityKg: number\n}\n\n/** The bag a bag item gives: its `carry.capacityKg` is the slot count the team's game reads from `cap`; the weight limit is the character's. */\nexport const bagOption = (bag: ItemDef | undefined, characterMaxKg: number, rules: ItemRules = DEFAULT_RULES): BagOption => ({\n slots: bag?.carry ? Math.round(bag.carry.capacityKg) : rules.inventory.defaultSlots,\n capacityKg: characterMaxKg,\n})\n\nexport type TakeResult = 'ok' | 'bag_full' | 'too_heavy'\n\n/** Whether `item` can go into the bag now: first the slots, then the weight. */\nexport const canTake = (item: ItemDef, bag: BagOption, used: { slots: number; loadKg: number }): TakeResult => {\n if (used.slots >= bag.slots) return 'bag_full'\n if (used.loadKg + item.weight > bag.capacityKg) return 'too_heavy'\n return 'ok'\n}\n","import type { Freshness } from './decay'\nimport { DEFAULT_RULES } from './rules'\nimport type { ItemRules } from './rules-types'\nimport type { ItemDef } from './types'\nimport type { UseEffectDef } from './use-types'\n\nexport interface UseContext {\n /** State of the food, from `freshness()`. Default `fresh`. */\n freshness?: Freshness\n /** The food was cooked: it keeps only `cookedPoisonFactor` of its poison chance. */\n isCooked?: boolean\n}\n\nexport interface NutritionResult {\n satiety: number\n hydration: number\n morale: number\n poisonChance: number\n isEdible: boolean\n}\n\nexport interface UseResult {\n useId: string\n effect: string\n params: Readonly<Record<string, unknown>>\n /** The item is spent (false for food too rotten to eat). */\n consumes: boolean\n /** Only for `consume_nutrition`. */\n nutrition?: NutritionResult\n}\n\nconst FRESH_NUTRITION = { satietyFactor: 1, poisonChance: 0, morale: 0, isEdible: true }\n\nconst nutritionOf = (item: ItemDef, context: UseContext, rules: ItemRules): NutritionResult => {\n const state = context.freshness ?? 'fresh'\n const effect = state === 'fresh' ? FRESH_NUTRITION : rules.use.freshness[state]\n const poisonShare = context.isCooked ? rules.use.cookedPoisonFactor : 1\n return {\n satiety: (item.nutrition?.satiety ?? 0) * effect.satietyFactor,\n hydration: item.nutrition?.hydration ?? 0,\n morale: effect.morale,\n poisonChance: effect.poisonChance * poisonShare,\n isEdible: effect.isEdible,\n }\n}\n\nconst findEffect = (item: ItemDef, effects: readonly UseEffectDef[]): UseEffectDef | undefined =>\n effects.find((entry) => entry.items?.includes(item.id)) ?? effects.find((entry) => entry.category?.includes(item.category))\n\n/**\n * What using `item` does, as data: the host applies it (the player, the needs, the world). Pure. The first effect that lists the item wins, then the first\n * that lists its category; `undefined` when nothing happens. Food past its best follows `rules.use.freshness`.\n */\nexport const resolveUse = (item: ItemDef, effects: readonly UseEffectDef[], context: UseContext = {}, rules: ItemRules = DEFAULT_RULES): UseResult | undefined => {\n const def = findEffect(item, effects)\n if (!def) return undefined\n const base = { useId: def.id, effect: def.effect, params: def.params ?? {}, consumes: def.consumes }\n if (def.effect !== 'consume_nutrition') return base\n const nutrition = nutritionOf(item, context, rules)\n return { ...base, consumes: def.consumes && nutrition.isEdible, nutrition }\n}\n","import type { ItemsCatalog } from './catalog-types'\nimport type { RecipeDef, RecipeInput, RecipeOutput } from './recipe-types'\n\nexport interface CraftContext {\n catalog: ItemsCatalog\n /** Count of each item the character has, by id. */\n inventory: ReadonlyMap<string, number>\n /** Litres of each fluid at hand, by fluid id. */\n fluids?: Readonly<Record<string, number>>\n /** Stations and things of the world that are near (`fire`, `table`, `soil`). */\n world?: ReadonlySet<string>\n /** Skill levels by id. Without it the skill requirement is ignored. */\n skills?: Readonly<Record<string, number>>\n /** Ids unlocked so far. Without it `unlockedBy` is ignored. */\n unlocked?: ReadonlySet<string>\n}\n\nexport interface CraftCheck {\n isPossible: boolean\n /** One entry per unmet requirement: `item:nails`, `any:salt|sugar`, `match:cookable`, `fluid:water`, `world:fire`, `tool:hammer|axe`, `skill:carpentry:2`, `unlock:magazine`. */\n missing: string[]\n}\n\nexport type Consumption = { item: string; count: number; meters?: number } | { fluid: string; liters: number }\n\nexport type CraftOutcome = { item: string; count: number } | { effect: string; params: Readonly<Record<string, unknown>>; text?: string }\n\nexport type CraftResult = { isCrafted: true; seconds: number; consumed: Consumption[]; output: CraftOutcome } | { isCrafted: false; missing: string[] }\n\nconst countOf = (context: CraftContext, id: string): number => context.inventory.get(id) ?? 0\n\n/** Ids that satisfy an item input, in the order they are used. */\nconst candidatesOf = (input: RecipeInput, context: CraftContext): string[] => {\n if (input.item !== undefined) return [input.item]\n if (input.any) return [...input.any]\n if (!input.match) return []\n const { category, cookable } = input.match\n return context.catalog.list().filter((item) => (category === undefined || item.category === category) && (cookable === undefined || item.cookable === cookable)).map((item) => item.id)\n}\n\nconst describeInput = (input: RecipeInput): string => {\n if (input.item !== undefined) return `item:${input.item}`\n if (input.any) return `any:${input.any.join('|')}`\n if (input.match) return `match:${input.match.category ?? 'cookable'}`\n if (input.fluid !== undefined) return `fluid:${input.fluid}`\n return `world:${(input.world ?? []).join('|')}`\n}\n\n/** Takes `needed` units from the candidates in order; returns what was taken, or undefined when there is not enough. */\nconst takeUnits = (candidates: readonly string[], needed: number, context: CraftContext): Consumption[] | undefined => {\n const taken: Consumption[] = []\n let remaining = needed\n for (const id of candidates) {\n if (remaining <= 0) break\n const count = Math.min(remaining, countOf(context, id))\n if (count > 0) taken.push({ item: id, count })\n remaining -= count\n }\n return remaining > 0 ? undefined : taken\n}\n\nconst consumptionFor = (input: RecipeInput, context: CraftContext): Consumption[] | undefined => {\n if (input.world) return input.world.some((thing) => context.world?.has(thing)) ? [] : undefined\n if (input.fluid !== undefined) {\n const liters = input.liters ?? 1\n return (context.fluids?.[input.fluid] ?? 0) >= liters ? [{ fluid: input.fluid, liters }] : undefined\n }\n const taken = takeUnits(candidatesOf(input, context), input.qty ?? 1, context)\n if (!taken || input.meters === undefined) return taken\n return taken.map((entry) => ('item' in entry ? { ...entry, meters: input.meters as number } : entry))\n}\n\nconst toolMissing = (recipe: RecipeDef, context: CraftContext): string[] =>\n recipe.tools.flatMap((tool) => {\n const missing: string[] = []\n if (tool.anyOf.length > 0 && !tool.anyOf.some((id) => countOf(context, id) > 0)) missing.push(`tool:${tool.anyOf.join('|')}`)\n if (tool.world && !tool.world.some((station) => context.world?.has(station))) missing.push(`world:${tool.world.join('|')}`)\n return missing\n })\n\nconst gateMissing = (recipe: RecipeDef, context: CraftContext): string[] => {\n const missing: string[] = []\n if (context.skills && recipe.skill && (context.skills[recipe.skill.id] ?? 0) < recipe.skill.level) missing.push(`skill:${recipe.skill.id}:${recipe.skill.level}`)\n if (context.unlocked && recipe.unlockedBy !== undefined && !context.unlocked.has(recipe.unlockedBy)) missing.push(`unlock:${recipe.unlockedBy}`)\n return missing\n}\n\n/** Whether the character can make the recipe now, and what is missing when not. Skill and `unlockedBy` are ignored when the host does not pass `skills` or `unlocked`. */\nexport const canCraft = (recipe: RecipeDef, context: CraftContext): CraftCheck => {\n const missing = [\n ...gateMissing(recipe, context),\n ...toolMissing(recipe, context),\n ...recipe.inputs.filter((input) => consumptionFor(input, context) === undefined).map(describeInput),\n ]\n return { isPossible: missing.length === 0, missing }\n}\n\nconst outcomeOf = (output: RecipeOutput, random: () => number): CraftOutcome => {\n if ('effect' in output) return { effect: output.effect, params: output.params, ...(output.text === undefined ? {} : { text: output.text }) }\n const [low, high] = output.qty\n return { item: output.item, count: low + Math.floor(random() * (high - low + 1)) }\n}\n\n/**\n * Makes the recipe: what is consumed and what comes out. Pure: the host takes the consumed things from its inventory and applies the output (an item is\n * added, an effect such as \"window with 200 life\" is the host's to handle). Draws one number only when the output quantity is a range.\n */\nexport const craft = (recipe: RecipeDef, context: CraftContext, random: () => number): CraftResult => {\n const check = canCraft(recipe, context)\n if (!check.isPossible) return { isCrafted: false, missing: check.missing }\n const consumed = recipe.inputs.flatMap((input) => consumptionFor(input, context) ?? [])\n return { isCrafted: true, seconds: recipe.seconds, consumed, output: outcomeOf(recipe.output, random) }\n}\n","import type { DepletionRule } from '../rules-types'\nimport type { ItemRules } from '../rules-types'\nimport type { PlaceTag } from '../types'\n\n/** Share of the normal stock a place still has `day` days into the outbreak: `max(floor, 1 - perDay x day)`; 1 on day 0 and where no rule names the place. */\nexport const depletionFactor = (place: PlaceTag, day: number, rules: ItemRules): number => {\n if (day <= 0) return 1\n const rule: DepletionRule | undefined = rules.finds.depletion.find((entry) => entry.places.includes(place))\n return rule ? Math.max(rule.floor, 1 - rule.perDay * day) : 1\n}\n\n/** The count of stacks after the days of the outbreak and the region: the roll is drawn first, so day 0 and an unknown region leave it as it was. */\nexport const scaleCount = (count: number, scale: { place: PlaceTag; day: number; region?: string }, rules: ItemRules): number => {\n const region = scale.region === undefined ? 1 : (rules.finds.regionMultiplier[scale.region] ?? 1)\n return Math.round(count * depletionFactor(scale.place, scale.day, rules) * region)\n}\n","import type { ItemsCatalog } from '../catalog-types'\nimport type { ItemCategory, ItemDef, PlaceTag } from '../types'\n\n/** The items of `category` a roll can draw in `place`: no fixed-spot rarity, nothing excluded; when none lists the place, every one of the category (the game's recuo). */\nexport const rollableItems = (catalog: ItemsCatalog, category: ItemCategory, place: PlaceTag): ItemDef[] => {\n const { rules } = catalog\n const rollable = catalog.byCategory(category).filter((item) => !rules.rarity.fixedOnly.includes(item.rarity) && !rules.finds.rollExcluded.includes(item.id))\n const here = rollable.filter((item) => item.finds?.places.includes(place))\n return here.length > 0 ? here : rollable\n}\n\nexport const rarityWeight = (catalog: ItemsCatalog, item: ItemDef): number => catalog.rules.rarity.weights[item.rarity]\n","import type { ItemsCatalog } from '../catalog-types'\nimport type { ItemCategory } from '../types'\n\nimport { scaleCount } from './depletion'\nimport { rarityWeight, rollableItems } from './rarity-pool'\nimport type { FindsQuery } from './types'\n\nconst pickCategory = (weights: Readonly<Record<ItemCategory, number>>, random: () => number): ItemCategory | undefined => {\n let remaining = random()\n const categories = Object.keys(weights)\n for (const category of categories) {\n remaining -= weights[category] as number\n if (remaining <= 0) return category\n }\n return categories[0]\n}\n\n/**\n * Port of the team game's `rollItems` (jogo.js L68796-68812) on the container table (`CONT_TAB`) and the rarity weights (`RAR_W`).\n *\n * Order of the random draws, the contract the golden test holds: one for the count; then for each stack one to pick the category, and (unless the category\n * has nothing to draw) one to pick the item among those of the place, by rarity weight. Nothing else draws. The count is scaled by the day and the region\n * after it is drawn, so day 0 gives exactly the game's rolls. Returns the item ids, one per stack.\n */\nexport const rollByCategory = (catalog: ItemsCatalog, query: FindsQuery): string[] => {\n const { rules } = catalog\n const table = catalog.containers.get(query.container) ?? catalog.containers.get(rules.finds.fallbackContainer)\n if (!table) return []\n const [low, high] = table.count ?? [0, 0]\n const drawn = low + Math.floor(query.rng() * (high - low + 1))\n const count = scaleCount(drawn, { place: query.place, day: query.day ?? 0, ...(query.region === undefined ? {} : { region: query.region }) }, rules)\n const weights = table.categories ?? table.categoriesByPlace?.[query.place] ?? table.categoriesByPlace?.['*']\n if (!weights) return []\n\n const picked: string[] = []\n for (let stack = 0; stack < count; stack++) {\n const category = pickCategory(weights, query.rng)\n const pool = category === undefined ? [] : rollableItems(catalog, category, query.place)\n if (pool.length === 0) continue\n const total = pool.reduce((sum, item) => sum + rarityWeight(catalog, item), 0)\n let remaining = query.rng() * total\n for (const item of pool) {\n remaining -= rarityWeight(catalog, item)\n if (remaining <= 0) {\n picked.push(item.id)\n break\n }\n }\n }\n return picked\n}\n","import type { ItemRules } from '../rules-types'\nimport type { FindState } from '../rules-types'\nimport type { PoolEntry } from '../types'\n\nimport type { FindsQuery } from './types'\n\nexport interface PoolPick {\n itemId: string\n count: number\n /** The pool entry it came from; none for the junk an abandoned container leaves. */\n entry?: PoolEntry\n}\n\ninterface Candidate {\n entry: PoolEntry\n weight: number\n}\n\n/** Draws without replacement by weight (the viewer's `ordemPonderada`): one draw per candidate, all of them, before anything is cut. */\nconst weightedOrder = (candidates: readonly Candidate[], random: () => number): Candidate[] => {\n const remaining = [...candidates]\n const ordered: Candidate[] = []\n while (remaining.length > 0) {\n const total = remaining.reduce((sum, candidate) => sum + candidate.weight, 0)\n let x = random() * total\n let index = 0\n for (; index < remaining.length - 1; index++) {\n x -= (remaining[index] as Candidate).weight\n if (x < 0) break\n }\n ordered.push(...remaining.splice(index, 1))\n }\n return ordered\n}\n\nconst countFor = (pool: readonly PoolEntry[], state: FindState, footprint: number, query: FindsQuery, rules: ItemRules): number => {\n const settings = rules.finds.pool\n const base = Math.max(settings.min, Math.min(settings.max, Math.round(settings.offset + footprint * settings.perSquareMetre + query.rng() * settings.jitter)))\n if (state === 'fortified') return Math.min(pool.length, base + settings.fortifiedExtra)\n if (state === 'abandoned') return query.rng() < settings.abandonedEmptyChance ? 0 : settings.abandonedKept\n return base\n}\n\n/**\n * Port of the 3D house viewer's `sorteiaConteudo` (visor-casas-3d.js L10837-10863) over a pool of what a kind of furniture holds.\n *\n * Order of the random draws, the contract the golden test holds: one for the count (`base`); for an abandoned container one more (empty or not); then a full\n * weighted order of the pool (one draw per entry, before the cut to the count); then one per kept entry for its quantity; and only for an abandoned and empty\n * container one last draw for the junk. Fortified: more entries, supplies weigh x2.5 and give +1. Abandoned: 40% empty, otherwise one entry, plus junk and,\n * in a fridge or freezer, spoiled food.\n */\nexport const rollExplicitPool = (pool: readonly PoolEntry[], state: FindState, query: FindsQuery, rules: ItemRules): PoolPick[] => {\n const settings = rules.finds.pool\n const n = countFor(pool, state, query.footprint ?? settings.defaultFootprint, query, rules)\n const isFortified = state === 'fortified'\n const candidates = pool.map((entry) => ({ entry, weight: isFortified && entry.isSupply ? entry.weight * settings.supplyWeight : entry.weight }))\n\n const picks: PoolPick[] = []\n for (const { entry } of weightedOrder(candidates, query.rng).slice(0, n)) {\n const [low, high] = entry.qty\n const bonus = isFortified && entry.isSupply ? settings.supplyExtraQty : 0\n picks.push({ itemId: entry.item, count: low + Math.floor(query.rng() * (high - low + 1)) + bonus, entry })\n }\n if (state === 'abandoned') {\n if (picks.length === 0 && query.rng() < settings.junkChance) picks.push({ itemId: settings.junkItem, count: 1 })\n if (settings.coldContainers.includes(query.container) || (query.key !== undefined && settings.coldContainers.includes(query.key))) picks.push({ itemId: settings.spoiledFoodItem, count: 1 })\n }\n return picks\n}\n","import { deepMerge } from '@adatechnology/game-contracts'\nimport type { DeepPartial } from '@adatechnology/game-contracts'\n\nimport type { ItemsCatalog } from '../catalog-types'\nimport type { ItemRules } from '../rules-types'\n\nimport { rollByCategory } from './category-roll'\nimport { rollExplicitPool } from './explicit-pool'\nimport { spawnData } from './spawn-state'\nimport type { FindStack, FindsProvider, FindsQuery } from './types'\n\nexport interface FindsProviderOptions {\n /** `team` (default): a container with an explicit pool in the catalog uses it; `none`: always the category roll. */\n pools?: 'team' | 'none'\n /** Changes to the `finds` and `spawn` rules for this provider. */\n rules?: DeepPartial<Pick<ItemRules, 'finds' | 'spawn'>>\n /** Names a host uses for a place, mapped to the place tags of the catalog (a floorplan `cabin` is a `lodge`). */\n placeAliases?: Readonly<Record<string, string>>\n /** Places where the explicit pools apply (the viewer's pools describe dwellings); the others use the category roll. Default: every place. */\n poolPlaces?: readonly string[]\n /** A container with neither a pool nor a table: `fallback` (default) uses the table of `rules.finds.fallbackContainer`, like the game; `pass` answers `null` so the host's own default applies. */\n unknownContainers?: 'fallback' | 'pass'\n}\n\n/**\n * What a container holds, as the floorplan's `FindsProvider` asks it. A container with an explicit pool (`query.key` or the container id) draws from it\n * (port of the viewer); otherwise the category roll of the game draws on the container table. Every stack is chosen first, in the order of the sources, and\n * only then each gets its state (age, condition, charge, fill) from the same generator. Items the catalog no longer has (removed by a game) are dropped\n * after the draws, so the others do not change.\n */\nexport function createFindsProvider(catalog: ItemsCatalog, options: FindsProviderOptions & { unknownContainers: 'pass' }): FindsProvider\nexport function createFindsProvider(catalog: ItemsCatalog, options?: FindsProviderOptions): { findsFor(query: FindsQuery): readonly FindStack[] }\nexport function createFindsProvider(catalog: ItemsCatalog, options: FindsProviderOptions = {}): FindsProvider {\n const rules = options.rules ? deepMerge(catalog.rules, options.rules) : catalog.rules\n const scoped: ItemsCatalog = rules === catalog.rules ? catalog : { ...catalog, rules }\n const usesPools = (options.pools ?? 'team') === 'team'\n\n const aliases = options.placeAliases ?? {}\n const poolPlaces = options.poolPlaces\n\n const passes = options.unknownContainers === 'pass'\n\n const choose = (query: FindsQuery): FindStack[] | null => {\n const pool = usesPools && (poolPlaces === undefined || poolPlaces.includes(query.place)) ? (scoped.pools.get(query.key ?? query.container) ?? scoped.pools.get(query.container)) : undefined\n if (!pool && passes && !scoped.containers.has(query.container)) return null\n if (!pool) return rollByCategory(scoped, query).map((itemId) => ({ itemId, count: 1 }))\n return rollExplicitPool(pool, rules.finds.states[query.state] ?? 'normal', query, rules).map(({ itemId, count }) => ({ itemId, count }))\n }\n\n return {\n findsFor(asked) {\n const query = aliases[asked.place] === undefined ? asked : { ...asked, place: aliases[asked.place] as string }\n const chosen = choose(query)\n if (chosen === null) return null\n return chosen\n .filter((stack) => scoped.has(stack.itemId))\n .map((stack) => {\n const data = spawnData(scoped.get(stack.itemId), query, scoped)\n return data ? { ...stack, data } : stack\n })\n },\n }\n}\n","import type { ItemsCatalog } from '../catalog-types'\nimport type { ItemDef } from '../types'\n\nimport type { FindData, FindsQuery } from './types'\n\nconst WEARING_DURABILITY = ['condition', 'hits', 'cuts']\n\nconst hasCondition = (item: ItemDef): boolean => item.protection !== undefined || item.weapon !== undefined || WEARING_DURABILITY.includes(item.durability?.kind ?? '')\n\nconst between = (range: readonly [number, number], random: () => number): number => range[0] + random() * (range[1] - range[0])\n\n/** Age of food when it turns up: the days since the outbreak plus 0 to 60% of the shelf life. On day 0 that is the normal turnover of the shelf. One draw. */\nexport const spawnAgeDays = (item: ItemDef, outbreakDays: number, random: () => number, catalog: ItemsCatalog): number | undefined =>\n item.shelfLife === undefined ? undefined : outbreakDays + between(catalog.rules.spawn.ageShare, random) * item.shelfLife\n\nconst isRetailStock = (query: FindsQuery, catalog: ItemsCatalog): boolean => {\n const { spawn } = catalog.rules\n const isRetail = spawn.retailNew && (query.day ?? 0) <= 0 && spawn.retailPlaces.includes(query.place)\n return isRetail && (spawn.retailContainers.length === 0 || spawn.retailContainers.includes(query.container))\n}\n\n/**\n * The state an item has when it turns up, drawn after all the stacks of a container were chosen (so the choice itself matches the sources): food age, condition\n * by rarity (100 for shop stock on day 0), battery charge and how full a jerrycan is. Draws in that order, only what applies.\n */\nexport const spawnData = (item: ItemDef, query: FindsQuery, catalog: ItemsCatalog): FindData | undefined => {\n const { spawn } = catalog.rules\n const data: { ageDays?: number; condition?: number; charge?: number; fill?: number } = {}\n const ageDays = spawnAgeDays(item, query.day ?? 0, query.rng, catalog)\n if (ageDays !== undefined) data.ageDays = ageDays\n if (hasCondition(item)) data.condition = isRetailStock(query, catalog) ? 100 : Math.round(between(spawn.condition[item.rarity], query.rng))\n if (item.charge) data.charge = between(spawn.charge, query.rng)\n if (spawn.fillable.includes(item.id)) data.fill = between(spawn.fill, query.rng)\n return Object.keys(data).length > 0 ? data : undefined\n}\n","import { fitsSize } from '@adatechnology/game-interactables'\nimport type { ItemStack, SlotSpec } from '@adatechnology/game-interactables'\n\nimport type { ItemsCatalog } from '../catalog-types'\n\nimport type { FindStack } from './types'\n\nexport interface PlacedFinds {\n /** One entry per slot, in the order of `slots`; null is empty. */\n contents: Array<ItemStack | null>\n /** Stacks that fit no free slot. */\n leftover: FindStack[]\n}\n\n/**\n * Puts the stacks in the slots of a container: each in the first free slot its item fits (`fitsSize`, width and depth may swap), a stack larger than the\n * item's `stack` splits over several slots. Pure and in order, so the same finds always land in the same slots. The result is the floorplan's `contents`.\n */\nexport const placeFinds = (stacks: readonly FindStack[], slots: readonly SlotSpec[], catalog: ItemsCatalog): PlacedFinds => {\n const contents: Array<ItemStack | null> = slots.map(() => null)\n const leftover: FindStack[] = []\n for (const stack of stacks) {\n const item = catalog.get(stack.itemId)\n const stackMax = item.stack ?? 1\n let remaining = stack.count\n while (remaining > 0) {\n const index = slots.findIndex((slot, position) => contents[position] === null && fitsSize(item.size, slot.max))\n if (index < 0) break\n const qty = Math.min(remaining, stackMax)\n contents[index] = { type: item.id, qty, ...(stack.data ? { data: { ...stack.data } } : {}) }\n remaining -= qty\n }\n if (remaining > 0) leftover.push({ ...stack, count: remaining })\n }\n return { contents, leftover }\n}\n","import type { LootTable, LootTables } from '@adatechnology/game-interactables'\n\nimport type { ItemsCatalog } from '../catalog-types'\nimport type { ContainerDef } from '../types'\n\nimport { depletionFactor } from './depletion'\nimport { rarityWeight, rollableItems } from './rarity-pool'\n\nexport interface LootTablesQuery {\n place: string\n /** Outbreak days; 0 is the normal world. */\n day?: number\n region?: string\n}\n\nconst weightsOf = (container: ContainerDef, place: string): Readonly<Record<string, number>> | undefined => container.categories ?? container.categoriesByPlace?.[place] ?? container.categoriesByPlace?.['*']\n\nconst tableFor = (catalog: ItemsCatalog, container: ContainerDef, query: LootTablesQuery): LootTable | undefined => {\n const weights = weightsOf(container, query.place)\n if (!weights) return undefined\n const entries = Object.entries(weights).flatMap(([category, categoryWeight]) => {\n const pool = rollableItems(catalog, category, query.place)\n const total = pool.reduce((sum, item) => sum + rarityWeight(catalog, item), 0)\n return total > 0 ? pool.map((item) => ({ type: item.id, weight: (categoryWeight * rarityWeight(catalog, item)) / total })) : []\n })\n const [low, high] = container.count ?? [0, 0]\n const region = query.region === undefined ? 1 : (catalog.rules.finds.regionMultiplier[query.region] ?? 1)\n const expected = ((low + high) / 2) * depletionFactor(query.place, query.day ?? 0, catalog.rules) * region\n return entries.length > 0 && high > 0 ? { fill: Math.min(1, expected / high), entries } : undefined\n}\n\n/**\n * The finds as the loot tables of `game-interactables`, for worlds that have no floorplan: one table per container of the place, named by the container id.\n * A table has one entry per rollable item, weighted by the container's category weight and the rarity (60/28/9/2.5). A slot is filled with probability\n * `fill` = expected count / most stacks, taking the container to have as many slots as its largest count; the day and the region scale the expected count.\n */\nexport const toLootTables = (catalog: ItemsCatalog, query: LootTablesQuery): LootTables => {\n const tables: LootTables = {}\n for (const container of catalog.containers.values()) {\n if (container.places && container.places.length > 0 && !container.places.includes(query.place)) continue\n const table = tableFor(catalog, container, query)\n if (table) tables[container.id] = table\n }\n return tables\n}\n","import type { CategoryDef, ItemDef, ItemPack, Rarity } from './types'\n\n/** The part of a weapon definition the bridge reads; `WeaponDef` of `@adatechnology/game-weapons` fits it without importing the package. */\nexport interface ArsenalWeaponLike {\n readonly id: string\n readonly mass: number\n readonly action: { readonly kind: string; readonly explosive?: string }\n readonly dimensions?: { readonly length: number }\n}\n\n/** The part of a calibre definition the bridge reads; `CaliberDef` fits it. */\nexport interface ArsenalCaliberLike {\n readonly id: string\n readonly bulletGrams: number\n readonly pellets?: number\n readonly caseType?: string\n readonly cartridge?: { readonly caseDiameter: number; readonly overallLength: number }\n}\n\n/** The part of an `Arsenal` the bridge reads. */\nexport interface ArsenalLike {\n readonly weapons: ReadonlyMap<string, ArsenalWeaponLike>\n readonly calibers: ReadonlyMap<string, ArsenalCaliberLike>\n}\n\n/** What the team's game says of a box or an arsenal item (`ammo-boxes.json`, from its `EXTRA` table); it wins over the estimates below. */\nexport interface ArsenalItemRecord {\n /** Id of the item; without it the bridge uses `ammo_<caliber>`, `firearm_<weapon>` or `throwable_<weapon>`. */\n id?: string\n kind: 'ammo_box' | 'firearm' | 'throwable'\n /** Calibre id of a box. */\n caliber?: string\n /** Weapon id of a firearm or throwable; for a throwable also the explosive it uses. */\n weapon?: string\n rounds?: number\n weight: number\n rarity: Rarity\n}\n\nexport interface ArsenalItemsOptions {\n records?: readonly ArsenalItemRecord[]\n}\n\nexport const ARSENAL_CATEGORIES: readonly CategoryDef[] = [\n { id: 'ammo', name: 'Ammo' },\n { id: 'firearms', name: 'Firearms' },\n { id: 'throwables', name: 'Throwables' },\n]\n\nconst MM = 0.001\nconst BOX_TARE_KG = 0.03\nconst BOX_WALL = 6 * MM\nconst ROUNDS_BY_CASE: Readonly<Record<string, number>> = { tiny: 50, pistol: 50, rifle: 20, shell: 25, big: 10 }\nconst DEFAULT_ROUNDS = 12\nconst CARTRIDGE_MASS_FACTOR = 2.3\nconst SHELL_MASS_FACTOR = 1.5\nconst BOX_DENSITY_KG_PER_M3 = 600\nconst THROWABLE_DENSITY_KG_PER_M3 = 1500\n\nconst cubeSide = (mass: number, density: number): number => Math.cbrt(mass / density)\n\n/** Estimates (REF) for a calibre the game has no box for: rounds by case type, mass of the rounds plus a tare, a box that packs them in a near-square tray. */\nconst estimateBox = (caliber: ArsenalCaliberLike): { rounds: number; weight: number; size: [number, number, number] } => {\n const rounds = ROUNDS_BY_CASE[caliber.caseType ?? ''] ?? DEFAULT_ROUNDS\n const factor = caliber.caseType === 'shell' ? SHELL_MASS_FACTOR : CARTRIDGE_MASS_FACTOR\n const weight = Number((rounds * caliber.bulletGrams * (caliber.pellets ?? 1) * factor * 0.001 + BOX_TARE_KG).toFixed(3))\n return { rounds, weight, size: boxSize(caliber, rounds, weight) }\n}\n\nconst boxSize = (caliber: ArsenalCaliberLike, rounds: number, weight: number): [number, number, number] => {\n if (!caliber.cartridge) {\n const side = cubeSide(weight, BOX_DENSITY_KG_PER_M3)\n return [side, side, side]\n }\n const rows = Math.ceil(Math.sqrt(rounds))\n const columns = Math.ceil(rounds / rows)\n const { caseDiameter, overallLength } = caliber.cartridge\n return [rows * caseDiameter * MM + BOX_WALL, overallLength * MM + BOX_WALL, columns * caseDiameter * MM + BOX_WALL]\n}\n\nconst ammoItem = (caliber: ArsenalCaliberLike, record: ArsenalItemRecord | undefined): ItemDef => {\n const estimate = estimateBox(caliber)\n const weight = record?.weight ?? estimate.weight\n return {\n id: record?.id ?? `ammo_${caliber.id}`,\n category: 'ammo',\n size: record?.weight === undefined ? estimate.size : boxSize(caliber, record.rounds ?? estimate.rounds, weight),\n weight,\n stack: 4,\n shape: 'box',\n rarity: record?.rarity ?? 'uncommon',\n }\n}\n\n/** A firearm's size from its length: height and thickness grow with it (a pistol 0.2 m is 0.10 x 0.03, a rifle 1 m is 0.20 x 0.05). Without a length, one from the mass. */\nconst firearmSize = (weapon: ArsenalWeaponLike): [number, number, number] => {\n const length = weapon.dimensions?.length ?? 0.15 + 0.2 * weapon.mass\n return [length, 0.08 + 0.12 * length, 0.02 + 0.03 * length]\n}\n\nconst weaponItem = (weapon: ArsenalWeaponLike, record: ArsenalItemRecord | undefined): ItemDef => {\n const isFirearm = weapon.action.kind === 'firearm'\n const side = cubeSide(weapon.mass, THROWABLE_DENSITY_KG_PER_M3)\n return {\n id: record?.id ?? `${isFirearm ? 'firearm' : 'throwable'}_${weapon.id}`,\n category: isFirearm ? 'firearms' : 'throwables',\n size: isFirearm ? firearmSize(weapon) : [side, side, side],\n weight: record?.weight ?? weapon.mass,\n stack: 1,\n shape: isFirearm ? 'long_tool' : 'jar',\n rarity: record?.rarity ?? 'unique',\n weapon: weapon.id,\n }\n}\n\nconst recordFor = (records: readonly ArsenalItemRecord[], match: (record: ArsenalItemRecord) => boolean): ArsenalItemRecord | undefined => records.find(match)\n\n/**\n * The arsenal as items, so a bag can carry it: a box `ammo_<caliber>` for every calibre, `firearm_<id>` for every firearm and `throwable_<id>` for every\n * throwable, with the mass and the real dimensions of the `WeaponDef` (`mass`, `dimensions.length`). A record from the team's game (`records`) gives the rounds\n * per box, the weight and the rarity of what it listed (9x19: 20 rounds, 0.24 kg); the rest are estimated from the calibre (REF): rounds by case type,\n * weight from the bullet. Returns a pack (with the `ammo`, `firearms` and `throwables` categories) for `createItems({ packs })`.\n */\nexport const itemsFromArsenal = (arsenal: ArsenalLike, options: ArsenalItemsOptions = {}): ItemPack => {\n const records = options.records ?? []\n const items: ItemDef[] = []\n for (const caliber of arsenal.calibers.values()) items.push(ammoItem(caliber, recordFor(records, (record) => record.kind === 'ammo_box' && record.caliber === caliber.id)))\n for (const weapon of arsenal.weapons.values()) {\n const kind = weapon.action.kind\n if (kind !== 'firearm' && kind !== 'throwable') continue\n items.push(weaponItem(weapon, recordFor(records, (record) => record.kind === kind && (record.weapon === weapon.id || record.weapon === weapon.action.explosive))))\n }\n return { id: 'arsenal', items, categories: ARSENAL_CATEGORIES }\n}\n","import type { AreaPlacement, Vec3 } from '@adatechnology/game-contracts'\n\n/** What the layout needs of an item: its id, category and real size [width, height, depth] in metres. */\nexport interface LayoutItem {\n readonly id: string\n readonly category: string\n readonly size: readonly [number, number, number]\n}\n\n/** Height of the top of a shelf, metres. */\nexport const SHELF_HEIGHT = 0.9\n/** Longest row of items on a shelf, metres. */\nexport const ROW_LIMIT = 5\nconst GAP = 0.06\nconst EDGE = 0.12\nconst COLUMNS = 4\nconst COLUMN_PITCH = 6.2\nconst ROW_GAP = 1.5\nconst FIRST_Z = -11\n\n/** One shelf: a category's items laid out in rows at real size, the shelf's footprint and where its items sit on its top. */\nexport interface ShelfPlan {\n category: string\n /** Item id of the shelf in the module (`shelf_<category>`). */\n id: string\n /** Footprint on the floor: length along x, depth along z. */\n length: number\n depth: number\n position: Vec3\n /** Where each item sits, in world coordinates. */\n items: AreaPlacement[]\n}\n\nexport const SHELF_PREFIX = 'shelf_'\nexport const ITEM_PREFIX = 'item_'\nexport const SHOWCASE_PREFIX = 'showcase_'\n\ninterface Row {\n items: LayoutItem[]\n width: number\n depth: number\n}\n\nconst rowsOf = (items: readonly LayoutItem[]): Row[] => {\n const rows: Row[] = []\n for (const item of items) {\n const [w, , d] = item.size\n let row = rows[rows.length - 1]\n if (!row || (row.items.length > 0 && row.width + w + GAP > ROW_LIMIT)) {\n row = { items: [], width: 0, depth: 0 }\n rows.push(row)\n }\n row.items.push(item)\n row.width += w + GAP\n row.depth = Math.max(row.depth, d)\n }\n return rows\n}\n\n/**\n * The shelves of the area: one per category, in the order the categories come, with every item of the category side by side at real size, wrapped in rows of at most\n * `ROW_LIMIT` metres. Shelves stand in a grid of four columns; an item that is longer than the row limit gets a row to itself. Pure: the same items always land in the same spots.\n */\nexport function shelvesLayout(items: readonly LayoutItem[], categories: readonly string[]): ShelfPlan[] {\n const plans = categories.flatMap((category) => {\n const own = items.filter((item) => item.category === category)\n if (own.length === 0) return []\n const rows = rowsOf(own)\n const length = Math.max(...rows.map((row) => row.width - GAP)) + 2 * EDGE\n const depth = rows.reduce((sum, row) => sum + row.depth + GAP, 0) - GAP + 2 * EDGE\n return [{ category, rows, length, depth }]\n })\n const result: ShelfPlan[] = []\n let z = FIRST_Z\n for (let start = 0; start < plans.length; start += COLUMNS) {\n const line = plans.slice(start, start + COLUMNS)\n const lineDepth = Math.max(...line.map((plan) => plan.depth))\n line.forEach((plan, column) => {\n const x = (column - (COLUMNS - 1) / 2) * COLUMN_PITCH\n const centre: Vec3 = [x, 0, z + plan.depth / 2]\n const placed: AreaPlacement[] = []\n let rowZ = -plan.depth / 2 + EDGE\n for (const row of plan.rows) {\n let cursor = -plan.length / 2 + EDGE\n for (const item of row.items) {\n const [w, , d] = item.size\n placed.push({ item: `${ITEM_PREFIX}${item.id}`, position: [centre[0] + cursor + w / 2, SHELF_HEIGHT + 0.01, centre[2] + rowZ + d / 2], asleep: true })\n cursor += w + GAP\n }\n rowZ += row.depth + GAP\n }\n result.push({ category: plan.category, id: `${SHELF_PREFIX}${plan.category}`, length: plan.length, depth: plan.depth, position: centre, items: placed })\n })\n z += lineDepth + ROW_GAP\n }\n return result\n}\n","import type * as THREE_NS from 'three'\nimport type { AreaPlacement, BenchChange, ModuleArea, ModuleControl, ModuleHost, ModuleLayer, ModuleMetric, ModuleScenario, TestableItem, TestableModule, Vec3 } from '@adatechnology/game-contracts'\nimport { rng } from '@adatechnology/game-interactables'\nimport { canCraft, craft, createFindsProvider, freshness, ITEM_CATEGORIES } from '@adatechnology/game-items'\nimport type { FindStack, FindsProvider, FindsQuery, ItemDef, ItemsCatalog, RecipeDef } from '@adatechnology/game-items'\n\nimport { ITEM_PREFIX, SHELF_HEIGHT, SHOWCASE_PREFIX, shelvesLayout } from './area-layout'\nimport type { ShelfPlan } from './area-layout'\nimport { buildItem } from './build-item'\nimport type { DrawableItem } from './build-item'\nimport { itemContents, SHELL_PART_ID } from './destruction'\nimport type { ContentsSubject } from './destruction'\nimport { checkBudget, countDrawCalls, countTriangles, ITEM_BUDGETS } from './budgets'\nimport { MODEL_BUDGET_DEVIATIONS } from './models/deviations'\nimport { itemThumbnailSvg } from './thumbnails'\nimport { hasItemModel, itemModelEntry, listItemModels } from './models/registry'\nimport { SHIPPED_MODELS } from './models/shipped'\nimport { setWear } from './wear'\nimport type { WearStage } from './wear'\n\nexport interface ItemsTestModuleOptions {\n /** The catalog to lay out (for example `createGoodsItems()` of `game-items-goods`). The module knows no content of its own. */\n catalog: ItemsCatalog\n /** `en` or `pt-BR` (default). */\n locale?: string\n /** Text of a key such as `item.canned_beans`, `place.house`, `category.food`, `container.fridge`, `recipe.stew` (the goods package has them in `goodsText`); without it the module falls back to the id. */\n translate?: (key: string, locale: string) => string | undefined\n /** Seed of the finds roll (default 1). */\n seed?: number\n /** Wear the items start with: `new` (default), `used` or `spoiled`. */\n wear?: string\n /** The finds provider; default the one of `game-items` over `catalog`. A game gives its own (floorplan bindings, pools). */\n provider?: FindsProvider\n}\n\nexport const SHOWCASE_STAND_ID = 'stand_models'\nexport const RULER_ID = 'ruler_155'\nexport const HUMAN_ID = 'human_180'\nexport const FINDS_TABLE_ID = 'finds_table'\nexport const RULER_HEIGHT = 1.55\nexport const HUMAN_HEIGHT = 1.8\n\nconst STAND = { at: [0, 0, 9.5] as Vec3, radius: 2.1, height: 0.8, ring: 1.35 }\nconst RULER_AT: Vec3 = [-6.5, 0, 9]\nconst HUMAN_AT: Vec3 = [-5.4, 0, 9]\nconst TABLE = { at: [7, 0, 9.5] as Vec3, length: 3.2, depth: 1, height: 0.8 }\nconst WEARS = ['new', 'used', 'spoiled'] as const\nconst WEAR_STAGE: Readonly<Record<string, WearStage>> = { new: 0, used: 1, spoiled: 2 }\nconst SPIN = 0.6\nconst MAX_COPIES = 5\nconst CATEGORY_ALL = 'all'\nconst BOX_COLOR = 0x4fc3f7\nconst HIGHLIGHT = 0x6a3a00\n\ninterface Text {\n group: string\n name: string\n shelf: string\n stand: string\n ruler: string\n human: string\n table: string\n control: Record<'category' | 'wear' | 'age_days' | 'storage' | 'powered' | 'place' | 'container' | 'state' | 'day' | 'seed' | 'roll_finds' | 'recipe' | 'craft', string>\n hint: Record<'age_days' | 'powered' | 'day' | 'roll_finds' | 'craft', string>\n all: string\n wears: Record<(typeof WEARS)[number], string>\n states: Record<'normal' | 'fortified' | 'abandoned', string>\n storages: Record<string, string>\n layers: Record<'labels' | 'boxes' | 'simple_shapes', string>\n metrics: Record<'items' | 'draw_calls' | 'triangles' | 'modeled' | 'finds', string>\n rolled: string\n rolledNothing: string\n crafted: string\n craftMissing: string\n craftEffect: string\n scenarios: Record<'real_size' | 'models' | 'budgets' | 'ruler' | 'finds' | 'freshness' | 'craft', string>\n}\n\nconst TEXT: Record<string, Text> = {\n en: {\n group: 'Items',\n name: 'Items area',\n shelf: 'Shelf of {category}',\n stand: 'Showcase stand of the 3D models',\n ruler: 'Ruler 1.55 m',\n human: 'Human figure 1.80 m',\n table: 'Finds table',\n control: {\n category: 'Category',\n wear: 'Wear',\n age_days: 'Age',\n storage: 'Storage',\n powered: 'Storage has power',\n place: 'Place',\n container: 'Container',\n state: 'State of the place',\n day: 'Outbreak day',\n seed: 'Seed',\n roll_finds: 'Roll finds',\n recipe: 'Recipe',\n craft: 'Craft',\n },\n hint: {\n age_days: 'Days the food has been kept: it spoils by its shelf life, faster or slower by the storage',\n powered: 'A fridge or freezer only keeps the food while it has power',\n day: 'Days since the outbreak: 0 is the normal world',\n roll_finds: 'Draws what the container holds and lays the stacks on the finds table',\n craft: 'Makes the recipe with exactly what it asks for and lays the result on the finds table',\n },\n all: 'All',\n wears: { new: 'New', used: 'Used', spoiled: 'Spoiled' },\n states: { normal: 'Normal', fortified: 'Fortified', abandoned: 'Abandoned' },\n storages: {},\n layers: { labels: 'Labels', boxes: 'Size boxes', simple_shapes: 'Highlight simple shapes' },\n metrics: { items: 'Items shown', draw_calls: 'Draw calls', triangles: 'Triangles', modeled: 'With a team model', finds: 'Stacks on the table' },\n rolled: 'Finds in {container} of {place} ({state}, day {day}): {stacks} stacks',\n rolledNothing: '{container} of {place} holds nothing',\n crafted: 'Crafted {recipe}: {output} ({seconds} s)',\n craftMissing: 'Cannot craft {recipe}: missing {missing}',\n craftEffect: 'effect {effect}',\n scenarios: {\n real_size: 'Every item is drawn at its real size',\n models: 'The 24 models of the team are shipped and draw their items',\n budgets: 'Models and shapes stay within the triangle and draw call budgets',\n ruler: 'The ruler is 1.55 m and the human figure 1.80 m',\n finds: 'The finds roll is the same for the same seed',\n freshness: 'Food spoils with age and the fridge slows it down',\n craft: 'A recipe made with what it asks for gives its output',\n },\n },\n 'pt-BR': {\n group: 'Itens',\n name: 'Área de itens',\n shelf: 'Prateleira de {category}',\n stand: 'Pedestal dos modelos 3D',\n ruler: 'Régua de 1,55 m',\n human: 'Silhueta humana de 1,80 m',\n table: 'Mesa de achados',\n control: {\n category: 'Categoria',\n wear: 'Desgaste',\n age_days: 'Idade',\n storage: 'Armazenamento',\n powered: 'Armazenamento com energia',\n place: 'Lugar',\n container: 'Recipiente',\n state: 'Estado do lugar',\n day: 'Dia do surto',\n seed: 'Semente',\n roll_finds: 'Sortear achados',\n recipe: 'Receita',\n craft: 'Fabricar',\n },\n hint: {\n age_days: 'Dias que a comida ficou guardada: estraga pela validade, mais rápido ou mais devagar conforme onde está',\n powered: 'Geladeira e freezer só conservam enquanto têm energia',\n day: 'Dias desde o surto: 0 é o mundo normal',\n roll_finds: 'Sorteia o que o recipiente guarda e põe as pilhas na mesa de achados',\n craft: 'Faz a receita com exatamente o que ela pede e põe o resultado na mesa de achados',\n },\n all: 'Todas',\n wears: { new: 'Novo', used: 'Usado', spoiled: 'Estragado' },\n states: { normal: 'Normal', fortified: 'Fortificado', abandoned: 'Abandonado' },\n storages: {},\n layers: { labels: 'Rótulos', boxes: 'Caixas de tamanho', simple_shapes: 'Destacar formas simples' },\n metrics: { items: 'Itens à mostra', draw_calls: 'Chamadas de desenho', triangles: 'Triângulos', modeled: 'Com modelo do time', finds: 'Pilhas na mesa' },\n rolled: 'Achados em {container} de {place} ({state}, dia {day}): {stacks} pilhas',\n rolledNothing: '{container} de {place} não tem nada',\n crafted: 'Fabricou {recipe}: {output} ({seconds} s)',\n craftMissing: 'Não dá para fabricar {recipe}: falta {missing}',\n craftEffect: 'efeito {effect}',\n scenarios: {\n real_size: 'Todo item é desenhado no tamanho real',\n models: 'Os 24 modelos do time vêm no kit e desenham os seus itens',\n budgets: 'Modelos e formas ficam dentro do orçamento de triângulos e de chamadas de desenho',\n ruler: 'A régua tem 1,55 m e a silhueta humana 1,80 m',\n finds: 'O sorteio de achados é o mesmo para a mesma semente',\n freshness: 'A comida estraga com a idade e a geladeira atrasa isso',\n craft: 'Uma receita feita com o que ela pede dá o que promete',\n },\n },\n}\nconst textOf = (locale: string): Text => TEXT[locale] ?? (TEXT.en as Text)\nconst fill = (template: string, vars: Record<string, string | number>): string => template.replace(/\\{(\\w+)\\}/g, (_, key: string) => String(vars[key] ?? ''))\nconst humanize = (id: string): string => id.replace(/_/g, ' ').replace(/^./, (c) => c.toUpperCase())\n\n/** What the scenarios of the area ask of the module (and what a host or a test may read). */\nexport interface ItemsAreaState {\n readonly category: string\n readonly wear: string\n readonly ageDays: number\n readonly storage: string\n readonly powered: boolean\n readonly place: string\n readonly container: string\n readonly state: string\n readonly day: number\n readonly seed: number\n readonly recipe: string\n}\n\nexport interface ItemsTestModule extends TestableModule {\n /** Everything the module has put in the scene so far, with what was measured when it was drawn. */\n placed(): ReadonlyArray<{ id: string; itemId: string; group: 'shelf' | 'showcase'; kind: 'model' | 'shape'; size: readonly [number, number, number]; root: THREE_NS.Object3D }>\n /** The stacks now on the finds table. */\n finds(): readonly FindStack[]\n /** The shelves of the layout. */\n shelves(): readonly ShelfPlan[]\n readonly state: ItemsAreaState\n /** The bench actions, callable without a host (what the buttons do). */\n rollFinds(): readonly FindStack[]\n craftSelected(): { ok: boolean; missing: readonly string[] }\n selectRecipe(id: string): void\n /** The box of a drawn object, metres [x, y, z] (needs the host's three.js namespace: null before the module is attached or an item built). */\n measure(root: THREE_NS.Object3D): [number, number, number] | null\n}\n\n/** Wear stage of an item from the age the bench sets: a food past its best turns spoiled, a food getting old turns used. */\nconst stageOf = (catalog: ItemsCatalog, item: ItemDef, base: WearStage, ageDays: number, storage: string, powered: boolean): WearStage => {\n if (item.shelfLife === undefined || ageDays <= 0) return base\n const state = freshness(item, { ageDays: 0, since: 0, storage, storedAt: 0 }, ageDays, { powered, rules: catalog.rules })\n const aged: WearStage = state === 'fresh' ? 0 : state === 'stale' ? 1 : 2\n return Math.max(base, aged) as WearStage\n}\n\nconst sizeOfModel = (id: string): [number, number, number] | undefined => {\n const entry = itemModelEntry(id)\n return entry ? [entry.teamBox[0] * entry.scale, entry.teamBox[1] * entry.scale, entry.teamBox[2] * entry.scale] : undefined\n}\n\n/**\n * The items test area as a `TestableModule` of @adatechnology/game-contracts: every item of a catalog on shelves by category at real size (the real model of the team where there is\n * one, the simple shape of its category elsewhere), a stand where the 24 models turn, a ruler and a human figure to judge the scale, and a table where the finds of a container\n * and the result of a recipe are laid. The bench sets wear, age and storage, the place, container, state, outbreak day and seed of the finds, and the recipe.\n */\nexport function createItemsTestModule(options: ItemsTestModuleOptions): ItemsTestModule {\n const { catalog } = options\n const locale = options.locale ?? 'pt-BR'\n const text = textOf(locale)\n const label = (key: string, fallback: string): string => {\n const found = options.translate?.(key, locale)\n return found !== undefined && found !== key ? found : fallback\n }\n const nameOf = (item: ItemDef): string => label(item.name ?? `item.${item.id}`, label(`item.${item.id}`, humanize(item.id)))\n const categoryName = (id: string): string => label(`category.${id}`, humanize(id))\n const provider = options.provider ?? createFindsProvider(catalog)\n\n const items = catalog.list()\n const categories = [...ITEM_CATEGORIES.map((c) => c.id), ...[...catalog.categories.keys()].filter((id) => !ITEM_CATEGORIES.some((c) => c.id === id))].filter((id) => items.some((item) => item.category === id))\n const shelves = shelvesLayout(items, categories)\n const showcase = listItemModels().map((id) => ({ id, size: sizeOfModel(id) as [number, number, number], def: catalog.has(id) ? catalog.get(id) : undefined }))\n\n const state: { -readonly [K in keyof ItemsAreaState]: ItemsAreaState[K] } = {\n category: CATEGORY_ALL,\n wear: WEARS.includes(options.wear as (typeof WEARS)[number]) ? (options.wear as string) : 'new',\n ageDays: 0,\n storage: catalog.rules.storage.ambient ? 'ambient' : (Object.keys(catalog.rules.storage)[0] ?? 'ambient'),\n powered: true,\n place: catalog.places.has('house') ? 'house' : ([...catalog.places.keys()][0] ?? 'house'),\n container: catalog.containers.has('fridge') ? 'fridge' : ([...catalog.containers.keys()][0] ?? 'fridge'),\n state: 'normal',\n day: 0,\n seed: options.seed ?? 1,\n recipe: [...catalog.recipes.keys()][0] ?? '',\n }\n\n interface Entry {\n id: string\n itemId: string\n group: 'shelf' | 'showcase'\n category: string\n def: ItemDef | undefined\n kind: 'model' | 'shape'\n size: readonly [number, number, number]\n root: THREE_NS.Group\n triangles: number\n drawCalls: number\n }\n const entries: Entry[] = []\n let host: ModuleHost | null = null\n let latestTHREE: typeof THREE_NS | null = null\n let stack: FindStack[] = []\n let findsGroup: THREE_NS.Group | null = null\n let boxes: THREE_NS.Object3D[] = []\n const layers = { labels: true, boxes: false, simple_shapes: false }\n\n const baseStage = (): WearStage => WEAR_STAGE[state.wear] ?? 0\n const stageFor = (def: ItemDef | undefined): WearStage => (def ? stageOf(catalog, def, baseStage(), state.ageDays, state.storage, state.powered) : baseStage())\n\n const drawable = (def: ItemDef): DrawableItem => def\n const register = (entry: Omit<Entry, 'triangles' | 'drawCalls'>): void => {\n entries.push({ ...entry, triangles: countTriangles(entry.root), drawCalls: countDrawCalls(entry.root) })\n }\n\n const shelfItem = (plan: ShelfPlan): TestableItem => ({\n id: plan.id,\n name: fill(text.shelf, { category: categoryName(plan.category) }),\n movable: false,\n build: (THREE: unknown) => {\n const T = THREE as typeof THREE_NS\n const group = new T.Group()\n const wood = new T.MeshStandardMaterial({ color: 0x8a6a45, roughness: 0.85 })\n const frame = new T.MeshStandardMaterial({ color: 0x4a4d52, roughness: 0.7, metalness: 0.3 })\n const top = new T.Mesh(new T.BoxGeometry(plan.length, 0.04, plan.depth), wood)\n top.position.y = SHELF_HEIGHT - 0.02\n group.add(top)\n for (const sx of [-1, 1]) for (const sz of [-1, 1]) {\n const leg = new T.Mesh(new T.BoxGeometry(0.05, SHELF_HEIGHT - 0.04, 0.05), frame)\n leg.position.set((sx * (plan.length - 0.1)) / 2, (SHELF_HEIGHT - 0.04) / 2, (sz * (plan.depth - 0.1)) / 2)\n group.add(leg)\n }\n group.userData.category = plan.category\n group.userData.shelf = true\n shelfRoots.push(group)\n return group\n },\n })\n const shelfRoots: THREE_NS.Group[] = []\n\n /** The liquid a can holds, as the room's `TestableItem.fluid`: a hole in the shell leaks it. */\n const fluidOf = (subject: ContentsSubject): Pick<TestableItem, 'fluid'> => {\n const contents = itemContents(subject)\n return contents ? { fluid: { container: contents.container, part: SHELL_PART_ID } } : {}\n }\n\n const itemOf = (def: ItemDef): TestableItem => ({\n id: `${ITEM_PREFIX}${def.id}`,\n name: nameOf(def),\n movable: true,\n thumbnail: itemThumbnailSvg(drawable(def)),\n ...fluidOf({ ...(def.model === undefined ? {} : { model: def.model }), size: def.size, weight: def.weight }),\n build: (THREE: unknown) => {\n const T = THREE as typeof THREE_NS\n latestTHREE = T\n const model = buildItem(T, drawable(def), { wear: stageFor(def), destructible: true })\n register({ id: `${ITEM_PREFIX}${def.id}`, itemId: def.id, group: 'shelf', category: def.category, def, kind: model.kind, size: def.size, root: model.root })\n return model.root\n },\n })\n\n const showcaseItem = (model: (typeof showcase)[number]): TestableItem => ({\n id: `${SHOWCASE_PREFIX}${model.id}`,\n name: model.def ? nameOf(model.def) : label(`item.${model.id}`, humanize(model.id)),\n movable: false,\n ...fluidOf({ model: model.id, size: model.size, ...(model.def ? { weight: model.def.weight } : {}) }),\n build: (THREE: unknown) => {\n const T = THREE as typeof THREE_NS\n const subject: DrawableItem = { id: model.id, category: model.def?.category ?? '', size: model.size, model: model.id, ...(model.def ? { weight: model.def.weight } : {}) }\n const built = buildItem(T, subject, { wear: stageFor(model.def), destructible: true })\n register({ id: `${SHOWCASE_PREFIX}${model.id}`, itemId: model.id, group: 'showcase', category: model.def?.category ?? '', def: model.def, kind: built.kind, size: model.size, root: built.root })\n return built.root\n },\n })\n\n const standItem = (): TestableItem => ({\n id: SHOWCASE_STAND_ID,\n name: text.stand,\n movable: false,\n build: (THREE: unknown) => {\n const T = THREE as typeof THREE_NS\n const group = new T.Group()\n const base = new T.Mesh(new T.CylinderGeometry(STAND.radius, STAND.radius + 0.1, STAND.height - 0.04, 40), new T.MeshStandardMaterial({ color: 0x3a3d44, roughness: 0.8 }))\n base.position.y = (STAND.height - 0.04) / 2\n const top = new T.Mesh(new T.CylinderGeometry(STAND.radius, STAND.radius, 0.04, 40), new T.MeshStandardMaterial({ color: 0xcfcab8, roughness: 0.6 }))\n top.position.y = STAND.height - 0.02\n group.add(base, top)\n return group\n },\n })\n\n const rulerItem = (): TestableItem => ({\n id: RULER_ID,\n name: text.ruler,\n movable: false,\n build: (THREE: unknown) => {\n const T = THREE as typeof THREE_NS\n const group = new T.Group()\n const post = new T.Mesh(new T.BoxGeometry(0.06, RULER_HEIGHT, 0.02), new T.MeshStandardMaterial({ color: 0xe8e2c8, roughness: 0.7 }))\n post.position.y = RULER_HEIGHT / 2\n group.add(post)\n const tick = new T.MeshStandardMaterial({ color: 0x1b1b1b })\n for (let cm = 0; cm <= 155; cm += 5) {\n const long = cm % 10 === 0\n const mark = new T.Mesh(new T.BoxGeometry(long ? 0.05 : 0.03, 0.004, 0.024), tick)\n mark.position.set(0.03 + (long ? 0.025 : 0.015), cm / 100, 0)\n group.add(mark)\n }\n const base = new T.Mesh(new T.BoxGeometry(0.3, 0.03, 0.3), new T.MeshStandardMaterial({ color: 0x55585c }))\n base.position.y = 0.015\n group.add(base)\n group.userData.height = RULER_HEIGHT\n return group\n },\n })\n\n const humanItem = (): TestableItem => ({\n id: HUMAN_ID,\n name: text.human,\n movable: false,\n build: (THREE: unknown) => {\n const T = THREE as typeof THREE_NS\n const group = new T.Group()\n const skin = new T.MeshStandardMaterial({ color: 0x9aa3ad, roughness: 0.9 })\n const part = (geometry: THREE_NS.BufferGeometry, x: number, y: number): void => {\n const mesh = new T.Mesh(geometry, skin)\n mesh.position.set(x, y, 0)\n group.add(mesh)\n }\n // 1.80 m: legs to 0.88, torso to 1.50, neck and head to 1.80\n for (const x of [-0.09, 0.09]) part(new T.CylinderGeometry(0.075, 0.06, 0.88, 10), x, 0.44)\n part(new T.BoxGeometry(0.4, 0.62, 0.22), 0, 0.88 + 0.31)\n for (const x of [-0.26, 0.26]) part(new T.CylinderGeometry(0.045, 0.04, 0.6, 8), x, 1.2)\n part(new T.CylinderGeometry(0.05, 0.055, 0.07, 8), 0, 1.535)\n part(new T.SphereGeometry(0.115, 14, 10), 0, 1.685)\n group.userData.height = HUMAN_HEIGHT\n return group\n },\n })\n\n const tableItem = (): TestableItem => ({\n id: FINDS_TABLE_ID,\n name: text.table,\n movable: false,\n build: (THREE: unknown) => {\n const T = THREE as typeof THREE_NS\n const group = new T.Group()\n const top = new T.Mesh(new T.BoxGeometry(TABLE.length, 0.05, TABLE.depth), new T.MeshStandardMaterial({ color: 0x7a6a55, roughness: 0.8 }))\n top.position.y = TABLE.height - 0.025\n group.add(top)\n const frame = new T.MeshStandardMaterial({ color: 0x3d3f44 })\n for (const sx of [-1, 1]) for (const sz of [-1, 1]) {\n const leg = new T.Mesh(new T.BoxGeometry(0.06, TABLE.height - 0.05, 0.06), frame)\n leg.position.set((sx * (TABLE.length - 0.12)) / 2, (TABLE.height - 0.05) / 2, (sz * (TABLE.depth - 0.12)) / 2)\n group.add(leg)\n }\n return group\n },\n })\n\n const liveEntries = (): Entry[] => entries.filter((entry) => entry.root.parent !== null)\n const visibleEntries = (): Entry[] => liveEntries().filter((entry) => entry.root.visible)\n\n const applyCategory = (): void => {\n for (const entry of entries) if (entry.group === 'shelf') entry.root.visible = state.category === CATEGORY_ALL || entry.category === state.category\n for (const shelf of shelfRoots) shelf.visible = state.category === CATEGORY_ALL || shelf.userData.category === state.category\n }\n const applyWear = (): void => {\n for (const entry of entries) setWear(entry.root, stageFor(entry.def))\n }\n const applyHighlight = (): void => {\n for (const entry of entries) {\n entry.root.traverse((object) => {\n const mesh = object as THREE_NS.Mesh\n if (!mesh.isMesh) return\n for (const material of Array.isArray(mesh.material) ? mesh.material : [mesh.material]) {\n const standard = material as THREE_NS.MeshStandardMaterial\n if (standard.emissive) standard.emissive.setHex(layers.simple_shapes && entry.kind === 'shape' ? HIGHLIGHT : 0x000000)\n }\n })\n }\n }\n const clearBoxes = (): void => {\n for (const box of boxes) {\n box.parent?.remove(box)\n }\n boxes = []\n }\n const applyBoxes = (): void => {\n clearBoxes()\n if (!layers.boxes || !host || !latestTHREE) return\n const T = latestTHREE\n const scene = host.scene as THREE_NS.Scene\n for (const entry of liveEntries()) {\n if (!entry.root.visible) continue\n const box = new T.Box3().setFromObject(entry.root)\n if (box.isEmpty()) continue\n const helper = new T.Box3Helper(box, BOX_COLOR)\n scene.add(helper)\n boxes.push(helper)\n }\n }\n\n const clearFinds = (): void => {\n if (findsGroup) {\n findsGroup.parent?.remove(findsGroup)\n findsGroup = null\n }\n }\n const labelSprite = (T: typeof THREE_NS, content: string): THREE_NS.Sprite | null => {\n if (typeof document === 'undefined') return null\n const canvas = document.createElement('canvas')\n const context = canvas.getContext('2d')\n if (!context) return null\n canvas.width = 256\n canvas.height = 64\n context.fillStyle = 'rgba(15,17,20,0.78)'\n context.fillRect(0, 0, 256, 64)\n context.fillStyle = '#ffffff'\n context.font = '24px sans-serif'\n context.textAlign = 'center'\n context.textBaseline = 'middle'\n context.fillText(content.length > 22 ? `${content.slice(0, 21)}…` : content, 128, 32)\n const texture = new T.CanvasTexture(canvas)\n const sprite = new T.Sprite(new T.SpriteMaterial({ map: texture, depthTest: false, transparent: true }))\n sprite.scale.set(0.5, 0.125, 1)\n sprite.renderOrder = 10\n return sprite\n }\n /** Draws the stacks on the finds table: each item once per unit (up to five) side by side at real size, with a label of its name and count. */\n const showFinds = (): void => {\n clearFinds()\n if (!host || !latestTHREE) return\n const T = latestTHREE\n const group = new T.Group()\n group.position.set(TABLE.at[0], TABLE.height + 0.005, TABLE.at[2])\n let cursor = -TABLE.length / 2 + 0.1\n const scale = 1\n for (const found of stack) {\n const def = catalog.get(found.itemId)\n const copies = Math.min(found.count, MAX_COPIES)\n const start = cursor\n for (let i = 0; i < copies; i++) {\n const model = buildItem(T, drawable(def), { wear: stageFor(def) })\n model.root.position.set(cursor + (def.size[0] * scale) / 2, 0, 0)\n group.add(model.root)\n cursor += def.size[0] + 0.03\n }\n const sprite = labelSprite(T, `${nameOf(def)} x${found.count}`)\n if (sprite) {\n sprite.position.set((start + cursor) / 2, Math.max(def.size[1], 0.1) + 0.12, 0)\n sprite.visible = layers.labels\n sprite.userData.label = true\n group.add(sprite)\n }\n cursor += 0.1\n }\n ;(host.scene as THREE_NS.Scene).add(group)\n findsGroup = group\n }\n const applyLabels = (): void => {\n findsGroup?.traverse((object) => {\n if (object.userData.label) object.visible = layers.labels\n })\n }\n\n const rollFinds = (): readonly FindStack[] => {\n const query: FindsQuery = { place: state.place, container: state.container, state: state.state, rng: rng(state.seed), day: state.day }\n stack = [...(provider.findsFor(query) ?? [])]\n showFinds()\n const container = label(`container.${state.container}`, humanize(state.container))\n const place = label(`place.${state.place}`, humanize(state.place))\n host?.log(stack.length > 0 ? fill(text.rolled, { container, place, state: text.states[state.state as keyof Text['states']] ?? state.state, day: state.day, stacks: stack.length }) : fill(text.rolledNothing, { container, place }), { place: state.place, container: state.container, seed: state.seed })\n return stack\n }\n\n /** What the character needs to make `recipe`: the items, the stations and the tools it asks for, once. */\n const kitFor = (recipe: RecipeDef): { inventory: Map<string, number>; world: Set<string> } => {\n const inventory = new Map<string, number>()\n const world = new Set<string>()\n const add = (id: string, count: number): void => void inventory.set(id, (inventory.get(id) ?? 0) + count)\n for (const input of recipe.inputs) {\n if (input.world) for (const w of input.world) world.add(w)\n else if (input.item !== undefined) add(input.item, input.qty ?? 1)\n else if (input.any?.[0] !== undefined) add(input.any[0], input.qty ?? 1)\n else if (input.match) {\n const pick = catalog.list().find((item) => (input.match?.category === undefined || item.category === input.match.category) && (input.match?.cookable === undefined || item.cookable === input.match.cookable))\n if (pick) add(pick.id, input.qty ?? 1)\n }\n }\n for (const tool of recipe.tools) {\n if (tool.anyOf[0] !== undefined) add(tool.anyOf[0], 1)\n for (const w of tool.world ?? []) world.add(w)\n }\n return { inventory, world }\n }\n const craftSelected = (): { ok: boolean; missing: readonly string[] } => {\n const recipe = catalog.recipes.get(state.recipe)\n if (!recipe) return { ok: false, missing: [state.recipe] }\n const { inventory, world } = kitFor(recipe)\n const fluids: Record<string, number> = {}\n for (const input of recipe.inputs) if (input.fluid !== undefined) fluids[input.fluid] = (fluids[input.fluid] ?? 0) + (input.liters ?? 1)\n const context = { catalog, inventory, world, fluids }\n const name = label(`recipe.${recipe.id}`, humanize(recipe.id))\n const check = canCraft(recipe, context)\n if (!check.isPossible) {\n host?.log(fill(text.craftMissing, { recipe: name, missing: check.missing.join(', ') }), { recipe: recipe.id })\n return { ok: false, missing: check.missing }\n }\n const result = craft(recipe, context, rng(state.seed))\n if (!result.isCrafted) return { ok: false, missing: result.missing }\n if ('item' in result.output) {\n stack = [{ itemId: result.output.item, count: result.output.count }]\n showFinds()\n }\n const output = 'item' in result.output ? `${nameOf(catalog.get(result.output.item))} x${result.output.count}` : fill(text.craftEffect, { effect: result.output.effect })\n host?.log(fill(text.crafted, { recipe: name, output, seconds: result.seconds }), { recipe: recipe.id })\n return { ok: true, missing: [] }\n }\n\n const areaPlacements = (): AreaPlacement[] => {\n const placements: AreaPlacement[] = []\n for (const shelf of shelves) {\n placements.push({ item: shelf.id, position: shelf.position, surface: { halfSize: [shelf.length / 2, shelf.depth / 2], height: SHELF_HEIGHT } }, ...shelf.items)\n }\n placements.push({ item: SHOWCASE_STAND_ID, position: STAND.at, surface: { halfSize: [STAND.radius, STAND.radius], height: STAND.height } })\n showcase.forEach((model, index) => {\n const angle = (index / showcase.length) * Math.PI * 2\n placements.push({ item: `${SHOWCASE_PREFIX}${model.id}`, position: [STAND.at[0] + Math.cos(angle) * STAND.ring, STAND.height + 0.01, STAND.at[2] + Math.sin(angle) * STAND.ring], asleep: true })\n })\n placements.push({ item: RULER_ID, position: RULER_AT }, { item: HUMAN_ID, position: HUMAN_AT })\n placements.push({ item: FINDS_TABLE_ID, position: TABLE.at, surface: { halfSize: [TABLE.length / 2, TABLE.depth / 2], height: TABLE.height } })\n return placements\n }\n\n const onChange = (change: BenchChange): void => {\n if (change.kind === 'layer') {\n if (change.id === 'labels' || change.id === 'boxes' || change.id === 'simple_shapes') layers[change.id] = change.on\n if (change.id === 'labels') applyLabels()\n else if (change.id === 'boxes') applyBoxes()\n else if (change.id === 'simple_shapes') applyHighlight()\n return\n }\n if (change.kind === 'action') {\n if (change.id === 'roll_finds') rollFinds()\n else if (change.id === 'craft') craftSelected()\n return\n }\n const value = change.value\n switch (change.id) {\n case 'category':\n state.category = String(value)\n applyCategory()\n if (layers.boxes) applyBoxes()\n break\n case 'wear':\n state.wear = String(value)\n applyWear()\n break\n case 'age_days':\n state.ageDays = Number(value)\n applyWear()\n break\n case 'storage':\n state.storage = String(value)\n applyWear()\n break\n case 'powered':\n state.powered = Boolean(value)\n applyWear()\n break\n case 'place':\n state.place = String(value)\n break\n case 'container':\n state.container = String(value)\n break\n case 'state':\n state.state = String(value)\n break\n case 'day':\n state.day = Number(value)\n break\n case 'seed':\n state.seed = Number(value)\n break\n case 'recipe':\n state.recipe = String(value)\n break\n }\n }\n\n const choice = (id: keyof Text['control'], values: ReadonlyArray<{ id: string; name: string }>, def: string): ModuleControl => ({ kind: 'choice', id, name: text.control[id], options: values, default: def })\n\n const module: ItemsTestModule = {\n id: 'items_area',\n name: text.name,\n group: text.group,\n state,\n placed: () => entries.map((entry) => ({ id: entry.id, itemId: entry.itemId, group: entry.group, kind: entry.kind, size: entry.size, root: entry.root })),\n finds: () => stack,\n shelves: () => shelves,\n rollFinds,\n craftSelected,\n selectRecipe: (id) => {\n state.recipe = id\n },\n measure: (root) => {\n if (!latestTHREE) return null\n // the size of the object itself: a piece that a blast or a throw has turned (it, or the holder the room put around it) is measured upright\n const turned: Array<{ node: THREE_NS.Object3D; rotation: THREE_NS.Euler }> = []\n for (let node: THREE_NS.Object3D | null = root; node; node = node.parent) turned.push({ node, rotation: node.rotation.clone() })\n for (const { node } of turned) node.rotation.set(0, 0, 0)\n root.updateWorldMatrix(true, true)\n const size = new latestTHREE.Box3().setFromObject(root).getSize(new latestTHREE.Vector3())\n for (const { node, rotation } of turned) node.rotation.copy(rotation)\n root.updateWorldMatrix(true, true)\n return [size.x, size.y, size.z]\n },\n items: () => [\n ...items.map(itemOf),\n ...shelves.map(shelfItem),\n standItem(),\n ...showcase.map(showcaseItem),\n rulerItem(),\n humanItem(),\n tableItem(),\n ],\n area: (): ModuleArea => ({ placements: areaPlacements(), view: { eye: [0, 5.5, 16], target: [0, 0.8, 0] } }),\n controls: (): ModuleControl[] => [\n choice('category', [{ id: CATEGORY_ALL, name: text.all }, ...categories.map((id) => ({ id, name: categoryName(id) }))], CATEGORY_ALL),\n choice('wear', WEARS.map((id) => ({ id, name: text.wears[id] })), state.wear),\n { kind: 'number', id: 'age_days', name: text.control.age_days, hint: text.hint.age_days, unit: 'd', min: 0, max: 400, step: 5, default: 0 },\n choice('storage', Object.keys(catalog.rules.storage).map((id) => ({ id, name: label(`storage.${id}`, humanize(id)) })), state.storage),\n { kind: 'boolean', id: 'powered', name: text.control.powered, hint: text.hint.powered, default: true },\n choice('place', [...catalog.places.keys()].map((id) => ({ id, name: label(`place.${id}`, humanize(id)) })), state.place),\n choice('container', [...catalog.containers.keys()].map((id) => ({ id, name: label(`container.${id}`, humanize(id)) })), state.container),\n choice('state', (['normal', 'fortified', 'abandoned'] as const).map((id) => ({ id, name: text.states[id] })), 'normal'),\n { kind: 'number', id: 'day', name: text.control.day, hint: text.hint.day, unit: 'd', min: 0, max: 60, step: 1, default: 0 },\n { kind: 'number', id: 'seed', name: text.control.seed, min: 1, max: 9999, step: 1, default: state.seed },\n { kind: 'action', id: 'roll_finds', name: text.control.roll_finds, hint: text.hint.roll_finds },\n ...(state.recipe ? [choice('recipe', [...catalog.recipes.keys()].map((id) => ({ id, name: label(`recipe.${id}`, humanize(id)) })), state.recipe)] : []),\n ...(state.recipe ? [{ kind: 'action', id: 'craft', name: text.control.craft, hint: text.hint.craft } as ModuleControl] : []),\n ],\n layers: (): ModuleLayer[] => [\n { id: 'labels', name: text.layers.labels },\n { id: 'boxes', name: text.layers.boxes, default: false },\n { id: 'simple_shapes', name: text.layers.simple_shapes, default: false },\n ],\n metrics: (): ModuleMetric[] => [\n { id: 'items', name: text.metrics.items, digits: 0, read: () => visibleEntries().length },\n { id: 'draw_calls', name: text.metrics.draw_calls, digits: 0, read: () => visibleEntries().reduce((sum, entry) => sum + entry.drawCalls, 0) },\n { id: 'triangles', name: text.metrics.triangles, digits: 0, read: () => visibleEntries().reduce((sum, entry) => sum + entry.triangles, 0) },\n {\n id: 'modeled',\n name: text.metrics.modeled,\n read: () => {\n const shown = visibleEntries().filter((entry) => entry.group === 'shelf')\n return `${shown.filter((entry) => entry.kind === 'model').length}/${shown.length}`\n },\n },\n { id: 'finds', name: text.metrics.finds, digits: 0, read: () => stack.length },\n ],\n scenarios: (): Array<ModuleScenario<ScenarioLike>> => scenariosOf(module, catalog, text, provider),\n attach(lent) {\n host = lent\n latestTHREE = lent.THREE as typeof THREE_NS\n const offChange = lent.bench?.onChange(onChange)\n const offFrame = lent.onFrame((dt) => {\n for (const entry of entries) if (entry.group === 'showcase' && entry.root.parent) entry.root.rotation.y += dt * SPIN\n })\n return () => {\n offChange?.()\n offFrame()\n clearBoxes()\n clearFinds()\n host = null\n }\n },\n }\n return module\n}\n\n/** What the scenarios use of the context the test room passes (`ScenarioContext`). */\nexport interface ScenarioLike {\n expect(condition: boolean, label: string, data?: Record<string, unknown>): void\n}\n\n/** A drawing never grows past its item's size, and its longest side is within 8% of it (a bag is a little lower than its box). */\nconst OVER = 0.02\nconst UNDER = 0.08\n\nfunction scenariosOf(module: ItemsTestModule, catalog: ItemsCatalog, text: Text, provider: FindsProvider): Array<ModuleScenario<ScenarioLike>> {\n const names = text.scenarios\n const shelf = (): ReturnType<ItemsTestModule['placed']> => module.placed().filter((entry) => entry.group === 'shelf')\n return [\n {\n id: 'real_size',\n name: names.real_size,\n run: ({ expect }) => {\n const shown = shelf()\n expect(shown.length > 0, 'items are on the shelves', { count: shown.length })\n for (const entry of shown) {\n const measured = module.measure(entry.root)\n if (!measured) continue\n const longest = Math.max(...entry.size)\n const axis = entry.size.indexOf(longest)\n const ok = measured.every((side, a) => side <= (entry.size[a] as number) * (1 + OVER) + 0.002) && Math.abs((measured[axis] as number) - longest) <= longest * UNDER + 0.002\n expect(ok, `${entry.itemId} measures its real size`, { measured, size: entry.size })\n }\n },\n },\n {\n id: 'models',\n name: names.models,\n run: ({ expect }) => {\n const models = listItemModels()\n expect(models.length === SHIPPED_MODELS.length, `${SHIPPED_MODELS.length} models are shipped`, { count: models.length })\n const withModel = catalog.list().filter((item) => item.model !== undefined && hasItemModel(item.model))\n const shippedItems = SHIPPED_MODELS.filter(({ entry }) => catalog.has(entry.id)).length\n expect(withModel.length === shippedItems, `${shippedItems} items of the catalog name a model (every shipped model that is a catalog item)`, { count: withModel.length })\n const stand = module.placed().filter((entry) => entry.group === 'showcase')\n expect(stand.length === 0 || stand.every((entry) => entry.kind === 'model'), 'every piece of the stand is drawn by the model of the team')\n },\n },\n {\n id: 'budgets',\n name: names.budgets,\n run: ({ expect }) => {\n for (const entry of module.placed()) {\n const report = checkBudget(entry.root, entry.size)\n expect(report.drawCalls <= ITEM_BUDGETS.drawCalls, `${entry.itemId} stays within ${ITEM_BUDGETS.drawCalls} draw calls`, { drawCalls: report.drawCalls })\n const deviation = entry.kind === 'model' ? MODEL_BUDGET_DEVIATIONS[entry.itemId] : undefined\n // a destructible can is tessellated on purpose (a dent needs vertices): the triangles that rule added are allowed on top of the budget\n const tessellated = (entry.root.userData.tessellationTriangles as number | undefined) ?? 0\n expect(report.ok || report.triangles <= Math.max(report.limit, deviation ?? 0) + tessellated, `${entry.itemId} stays within its triangle budget`, { triangles: report.triangles, limit: report.limit })\n }\n },\n },\n {\n id: 'ruler',\n name: names.ruler,\n run: ({ expect }) => {\n expect(RULER_HEIGHT === 1.55 && HUMAN_HEIGHT === 1.8, 'the references have the measures of the page')\n },\n },\n {\n id: 'finds',\n name: names.finds,\n run: ({ expect }) => {\n const query = (seed: number): FindsQuery => ({ place: module.state.place, container: module.state.container, state: 'normal', rng: rng(seed), day: 0 })\n const a = JSON.stringify(provider.findsFor(query(7)))\n const b = JSON.stringify(provider.findsFor(query(7)))\n expect(a === b, 'the same seed gives the same finds')\n expect((provider.findsFor(query(7)) ?? []).every((found) => catalog.has(found.itemId)), 'every find is an item of the catalog')\n },\n },\n {\n id: 'freshness',\n name: names.freshness,\n run: ({ expect }) => {\n const food = catalog.list().find((item) => item.shelfLife !== undefined && item.shelfLife > 0)\n if (!food) return expect(false, 'the catalog has a food that spoils')\n const at = (storage: string, days: number): string => freshness(food, { ageDays: 0, since: 0, storage, storedAt: 0 }, days, { rules: catalog.rules })\n const days = (food.shelfLife as number) * 1.2\n expect(at('ambient', days) !== 'fresh', 'at room temperature it is past its best', { food: food.id })\n if ('fridge' in catalog.rules.storage) expect(at('fridge', days) !== at('ambient', days) || at('fridge', days) === 'fresh', 'in the fridge it keeps better', { food: food.id })\n },\n },\n {\n id: 'craft',\n name: names.craft,\n run: ({ expect }) => {\n const before = module.state.recipe\n for (const id of catalog.recipes.keys()) {\n module.selectRecipe(id)\n const result = module.craftSelected()\n expect(result.ok, `recipe ${id} is made with what it asks for`, { missing: result.missing })\n }\n module.selectRecipe(before)\n },\n },\n ]\n}\n"],"mappings":"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,OAAS;MACT,YAAc;MACd,OAAS;QACP,QAAU;QACV,SAAW,CAAC;MACd;MACA,MAAQ;QACN;QACA;MACF;IACF;IACA;MACE,IAAM;MACN,OAAS;MACT,SAAW;MACX,YAAc;MACd,WAAa;MACb,SAAW;MACX,SAAW;MACX,OAAS;MACT,OAAS;QACP,QAAU;QACV,SAAW;UACT;QACF;MACF;MACA,MAAQ;QACN;QACA;MACF;IACF;IACA;MACE,IAAM;MACN,OAAS;MACT,SAAW;MACX,YAAc;MACd,WAAa;MACb,SAAW;MACX,SAAW;MACX,OAAS;MACT,YAAc;MACd,OAAS;QACP,QAAU;QACV,SAAW;UACT;QACF;MACF;MACA,MAAQ;QACN;QACA;MACF;IACF;IACA;MACE,IAAM;MACN,OAAS;MACT,SAAW;MACX,YAAc;MACd,WAAa;MACb,SAAW;MACX,SAAW;MACX,OAAS;MACT,WAAa;MACb,OAAS;QACP,QAAU;QACV,SAAW;UACT;QACF;MACF;MACA,MAAQ;QACN;QACA;MACF;IACF;IACA;MACE,IAAM;MACN,OAAS;MACT,SAAW;MACX,YAAc;MACd,WAAa;MACb,SAAW;MACX,SAAW;MACX,OAAS;MACT,YAAc;MACd,WAAa;MACb,OAAS;QACP,QAAU;QACV,SAAW;UACT;QACF;MACF;MACA,MAAQ;QACN;QACA;MACF;IACF;IACA;MACE,IAAM;MACN,OAAS;MACT,SAAW;MACX,YAAc;MACd,WAAa;MACb,SAAW;MACX,SAAW;MACX,OAAS;MACT,YAAc;MACd,WAAa;MACb,OAAS;QACP,QAAU;QACV,SAAW;UACT;QACF;MACF;MACA,MAAQ;QACN;MACF;IACF;IACA;MACE,IAAM;MACN,OAAS;MACT,SAAW;MACX,YAAc;MACd,WAAa;MACb,SAAW;MACX,SAAW;MACX,OAAS;MACT,YAAc;MACd,WAAa;MACb,OAAS;QACP,QAAU;QACV,SAAW;UACT;QACF;MACF;MACA,MAAQ;QACN;MACF;IACF;IACA;MACE,IAAM;MACN,OAAS;MACT,SAAW;MACX,YAAc;MACd,WAAa;MACb,SAAW;MACX,SAAW;MACX,OAAS;MACT,YAAc;MACd,WAAa;MACb,OAAS;QACP,QAAU;QACV,SAAW;UACT;QACF;MACF;MACA,MAAQ;QACN;QACA;MACF;IACF;IACA;MACE,IAAM;MACN,OAAS;MACT,SAAW;MACX,YAAc;MACd,WAAa;MACb,SAAW;MACX,SAAW;MACX,OAAS;MACT,YAAc;MACd,OAAS;QACP,QAAU;QACV,SAAW;UACT;QACF;MACF;MACA,MAAQ;QACN;MACF;IACF;IACA;MACE,IAAM;MACN,OAAS;MACT,SAAW;MACX,YAAc;MACd,WAAa;MACb,SAAW;MACX,SAAW;MACX,OAAS;MACT,YAAc;MACd,OAAS;QACP,QAAU;QACV,SAAW;UACT;QACF;MACF;MACA,MAAQ;QACN;MACF;IACF;IACA;MACE,IAAM;MACN,OAAS;MACT,SAAW;MACX,YAAc;MACd,WAAa;MACb,SAAW;MACX,SAAW;MACX,OAAS;MACT,YAAc;MACd,OAAS;QACP,QAAU;QACV,SAAW;UACT;QACF;MACF;MACA,MAAQ;QACN;MACF;IACF;IACA;MACE,IAAM;MACN,OAAS;MACT,SAAW;MACX,YAAc;MACd,WAAa;MACb,SAAW;MACX,SAAW;MACX,OAAS;MACT,YAAc;MACd,OAAS;QACP,QAAU;QACV,SAAW,CAAC;MACd;MACA,MAAQ;QACN;QACA;MACF;IACF;IACA;MACE,IAAM;MACN,OAAS;MACT,SAAW;MACX,YAAc;MACd,WAAa;MACb,SAAW;MACX,SAAW;MACX,OAAS;MACT,YAAc;MACd,OAAS;QACP,QAAU;QACV,SAAW;UACT;QACF;MACF;MACA,MAAQ;QACN;MACF;IACF;IACA;MACE,IAAM;MACN,OAAS;MACT,SAAW;MACX,YAAc;MACd,WAAa;MACb,SAAW;MACX,SAAW;MACX,OAAS;MACT,YAAc;MACd,OAAS;QACP,QAAU;QACV,SAAW;UACT;QACF;MACF;MACA,MAAQ;QACN;MACF;IACF;IACA;MACE,IAAM;MACN,OAAS;MACT,SAAW;MACX,YAAc;MACd,WAAa;MACb,SAAW;MACX,SAAW;MACX,OAAS;MACT,YAAc;MACd,OAAS;QACP,QAAU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","names":["key","width","height","depth","indexArray","sign","tube","list","num","equals","area","ring","bs","layeroffset","key","key","key","piece","key","tube","make","object","mesh","list","hex","color","mesh","object","tube","hex","object","mesh","color","box","sphere","ring","tube","across","box","mesh","box","object","mesh","torus","paper","mesh","lathe","paper","mesh","paper","mesh","paper","mesh","lathe","paper","mesh","torus","mesh","cloth","mesh","paper","mesh","mesh","mesh","extrude","mesh","extrude","mesh","lathe","mesh","cloth","mesh","torus","mesh","torus","mesh","torus","extrude","mesh","cloth","paper","mesh","mesh","lathe","torus","mesh","mesh","mesh","mesh","mesh","paper","mesh","paper","mesh","mesh","paper","mesh","paper","mesh","mesh","mesh","mesh","paper","cloth","mesh","paper","eggs","mesh","paper","mesh","cloth","paper","mesh","mesh","mesh","paper","mesh","paper","mesh","paper","mesh","mesh","paper","mesh","mesh","extrude","mesh","extrude","salt","mesh","mesh","paper","mesh","mesh","extrude","mesh","paper","mesh","paper","mesh","paper","mesh","paper","mesh","paper","mesh","paper","mesh","paper","mesh","paper","mesh","paper","mesh","paper","mesh","lathe","paper","bottle","mesh","extrude","paper","mesh","paper","mesh","paper","fruit","mesh","lathe","paper","bottle","mesh","lathe","paper","bottle","mesh","lathe","paper","bottle","mesh","paper","mesh","paper","mesh","paper","mesh","paper","mesh","paper","mesh","paper","mesh","paper","mesh","paper","mesh","lathe","cloth","roll","mesh","paper","mesh","lathe","paper","bottle","mesh","torus","paper","mesh","paper","ring","mesh","extrude","cloth","paper","cup","mesh","lathe","paper","bottle","mesh","lathe","paper","bottle","mesh","paper","mesh","mesh","paper","mesh","extrude","paper","bag","mesh","extrude","mesh","mesh","lathe","paper","bottle","mesh","mesh","mesh","mesh","mesh","mesh","paper","mesh","mesh","ring","mesh","mesh","mesh","paper","mesh","lathe","paper","ring","mesh","mesh","mesh","cloth","mesh","cloth","color","mesh","mesh","mesh","mesh","mesh","mesh","mesh","mesh","paper","mesh","mesh","mesh","extrude","mesh","lathe","ring","mesh","cloth","mesh","cloth","mesh","mesh","mesh","cloth","mesh","extrude","blade","mesh","extrude","blade","mesh","cloth","mesh","cloth","blade","mesh","lathe","mesh","cloth","mesh","extrude","cloth","blade","mesh","cloth","mesh","orange","mesh","cloth","mesh","lathe","cloth","mesh","mesh","lathe","paper","tube","mesh","lathe","ring","mesh","extrude","mesh","mesh","paper","cloth","mesh","orange","mesh","mesh","lathe","cloth","ring","color","mesh","lathe","mesh","lathe","paper","mesh","lathe","paper","mesh","lathe","paper","mesh","mesh","cloth","rope","mesh","mesh","mesh","cloth","mesh","mesh","mesh","cloth","mesh","lathe","mesh","lathe","paper","mesh","cloth","backpack","mesh","cloth","mesh","cloth","mesh","mesh","paper","mesh","cloth","mesh","cloth","mesh","torus","mesh","paper","mesh","blade","mesh","paper","mesh","mesh","mesh","mesh","paper","mesh","paper","mesh","paper","mesh","cloth","mesh","mesh","paper","mesh","cloth","mesh","cloth","mesh","cloth","mesh","paper","bottle","mesh","paper","mesh","torus","mesh","mesh","mesh","cloth","mesh","paper","mesh","cloth","paper","mesh","cloth","mesh","cloth","mesh","mesh","mesh","mesh","cloth","mesh","paper","can","mesh","paper","bottle","mesh","mesh","lathe","cloth","mesh","cloth","mesh","cloth","mesh","key","mesh","cloth","mesh","paper","mesh","paper","bottle","mesh","mesh","cloth","mesh","cloth","mesh","cloth","mesh","mesh","paper","cloth","mesh","paper","mesh","mesh","cloth","mesh","cloth","mesh","mesh","mesh","paper","bottle","mesh","mesh","paper","mesh","cloth","mesh","mesh","paper","mesh","mesh","mesh","paper","mesh","mesh","paper","mesh","mesh","mesh","mesh","cloth","cup","mesh","cloth","mesh","cloth","mesh","mesh","paper","cloth","mesh","torus","mesh","cloth","mesh","cloth","mesh","paper","mesh","cloth","mesh","mesh","cloth","mesh","cloth","mesh","mesh","mesh","backpack","box","object","mesh","color","DEFAULT_COLOR","box","key","tool","range","deepMerge","key","entries","mesh","object","box","tool","tessellated","days"]}