@adatechnology/game-animals-three 0.0.0-stage → 0.1.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.
- package/LICENSE +21 -0
- package/dist/index.d.ts +251 -0
- package/dist/index.global.js +1415 -0
- package/dist/index.global.js.map +1 -0
- package/dist/index.js +1160 -0
- package/dist/index.js.map +1 -0
- package/package.json +63 -3
- package/README.md +0 -3
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/index.ts","../../game-animals/src/data/gaits.json","../../game-animals/src/gaits.ts","../../game-animals/src/layout.ts","../../game-animals/src/registry.ts","../../game-animals/src/kit.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/animate-bird.ts","../src/animate-quadruped.ts","../src/animate-snake.ts","../src/context.ts","../src/bird.ts","../src/extras.ts","../src/textures.ts","../src/profile.ts","../src/quadruped.ts","../src/snake.ts","../src/visual-state.ts","../src/views.ts","../src/line-up.ts","../src/test-area/scenarios.ts","../src/test-area/text.ts","../src/test-area/module.ts"],"sourcesContent":["/**\n * @adatechnology/game-animals-three: the three.js drawing of the animals, a literal port of the Bichos do Vale builders (`quad`, `bird`, `snake`) and\n * their animation, with the alive / infected / dead looks for every species, the joints and split views, and a GPU node skin for crowds.\n */\nimport { GAIT_PHASES } from '@adatechnology/game-animals'\nimport type { AnimalSpecies, AnimalVisualState, GaitPhases } from '@adatechnology/game-animals'\nimport { collectReferencedNodes, createNodeSkin } from '@adatechnology/game-props3d'\nimport type { NodeSkin } from '@adatechnology/game-props3d'\nimport type * as THREE_NS from 'three'\n\nimport { animateBird } from './animate-bird'\nimport { animateQuadruped } from './animate-quadruped'\nimport { animateSnake } from './animate-snake'\nimport type { AnimateParams } from './animate-types'\nimport { buildBird } from './bird'\nimport { createRig, createStream } from './context'\nimport { BIRD_EXTRAS, QUADRUPED_EXTRAS } from './extras'\nimport { buildQuadruped } from './quadruped'\nimport { buildSnake } from './snake'\nimport type { AnimalRig, AnimalsThreeOptions, DocumentLike, Three } from './types'\nimport { applyVisualState } from './visual-state'\nimport { setJointView, setSplit, updateSplit } from './views'\n\nexport type { AnimalLeg, AnimalPivot, AnimalRig, AnimalWing, AnimalsThreeOptions, CanvasLike, DocumentLike, Three } from './types'\nexport type { AnimateParams } from './animate-types'\nexport type { BirdExtra, BirdParts, ExtraContext, QuadrupedExtra, QuadrupedParts } from './extras'\nexport { BIRD_EXTRAS, QUADRUPED_EXTRAS } from './extras'\nexport { lineUpAnimals } from './line-up'\nexport type { LineUpOptions } from './line-up'\nexport { profileGeometry } from './profile'\nexport { createCoatTexture } from './textures'\nexport { applyVisualState } from './visual-state'\nexport { setJointView, setSplit, updateSplit } from './views'\n\nexport type AnimalsThree = {\n /** Builds one animal from its species; consumes one number of the stream for the start phase unless `phase` is given. */\n build(species: AnimalSpecies, buildOptions?: { readonly phase?: number }): AnimalRig\n /** Advances the animation of one animal (steps, flight, wings, head, tail, a dead one lying down). */\n animate(rig: AnimalRig, params: AnimateParams): void\n setVisualState(rig: AnimalRig, state: AnimalVisualState): void\n setJointView(rig: AnimalRig, on: boolean): void\n setSplit(rig: AnimalRig, on: boolean): void\n updateSplit(rig: AnimalRig, delta: number): void\n /** One mesh that stands for the whole tree, for crowds: call `skin.update()` each frame after `animate`. */\n createSkin(rig: AnimalRig): NodeSkin\n readonly jointMaterial: THREE_NS.MeshStandardMaterial\n}\n\nconst countTriangles = (root: THREE_NS.Object3D): number => {\n let triangles = 0\n root.traverse((object) => {\n const mesh = object as THREE_NS.Mesh\n if (!mesh.isMesh) return\n const geometry = mesh.geometry\n triangles += geometry.index ? geometry.index.count / 3 : geometry.attributes.position.count / 3\n })\n return Math.round(triangles)\n}\n\nexport const createAnimalsThree = (THREE: Three, options: AnimalsThreeOptions = {}): AnimalsThree => {\n const random = options.random ?? createStream(options.seed ?? 7)\n const documentOf = (): DocumentLike => {\n const found = options.document ?? (globalThis as { document?: DocumentLike }).document\n if (!found) throw new Error('game-animals-three: a species with a coat texture needs `options.document` (no global document found)')\n return found\n }\n const jointMaterial = new THREE.MeshStandardMaterial({ color: 0xe0a548, emissive: 0xe0a548, emissiveIntensity: 0.8, roughness: 0.4 })\n const gaits: Readonly<Record<'walk' | 'trot' | 'gallop', GaitPhases>> = GAIT_PHASES\n\n return {\n jointMaterial,\n build(species, buildOptions = {}) {\n const rig = createRig(THREE, species, { phase: buildOptions.phase ?? random() * 6 })\n if (species.body.kind === 'snake') buildSnake(THREE, rig)\n else if (species.body.kind === 'bird') buildBird(THREE, rig, { extra: BIRD_EXTRAS[species.id] })\n else buildQuadruped(THREE, rig, { document: species.body.texture ? documentOf() : (undefined as never), extra: QUADRUPED_EXTRAS[species.id] })\n rig.triangles = countTriangles(rig.root)\n rig.root.traverse((object) => {\n if ((object as THREE_NS.Mesh).isMesh) object.userData.speciesId = species.id\n })\n return rig\n },\n animate(rig, params) {\n const kind = rig.species.body.kind\n if (kind === 'snake') animateSnake(THREE, rig, params)\n else if (kind === 'bird') animateBird(rig, params)\n else animateQuadruped(rig, params, gaits)\n },\n setVisualState: (rig, state) => applyVisualState(THREE, rig, state),\n setJointView: (rig, on) => setJointView(rig, on, jointMaterial),\n setSplit,\n updateSplit,\n createSkin: (rig) => createNodeSkin(THREE, rig.root, { nodes: collectReferencedNodes(rig, ['species']) }),\n }\n}\nexport { createAnimalsTestModule, ANIMALS_AREA_ID, ANIMAL_ITEM_PREFIX } from './test-area/module'\nexport type { AnimalsContext } from './test-area/scenarios'\nexport type { AnimalsTestOptions, OutbreakLike } from './test-area/types'\n","{\n \"walk\": [\n 1.570796327,\n 4.71238898,\n 0,\n 3.141592654\n ],\n \"trot\": [\n 0,\n 3.141592654,\n 3.141592654,\n 0\n ],\n \"gallop\": [\n 2.890265241,\n 3.707079331,\n 0,\n 0.879645943\n ]\n}\n","import gaitsData from './data/gaits.json'\nimport type { AnimalGaitName, GaitPhases } from './types'\n\n/** The phase of each leg per gait, in radians, from the Bichos do Vale page (`GAIT`); the leg order is front right, front left, hind right, hind left. */\nexport const GAIT_PHASES = gaitsData as unknown as Readonly<Record<AnimalGaitName, GaitPhases>>\n","import type { BirdSpec, QuadrupedSpec } from './types'\n\nexport type QuadrupedLayout = {\n /** Height of the front and the hind hips above the ground. */\n readonly frontHipHeight: number\n readonly hindHipHeight: number\n readonly footHeight: number\n /** Height of the body centre. */\n readonly bodyHeight: number\n /** Distance between the shoulders and the hips. */\n readonly span: number\n /** Largest dimension, used to scale the offsets of the split view and the blood pool. */\n readonly size: number\n}\n\n/** The rest-pose geometry of a quadruped: leg lengths and angles decide how high the body stands. */\nexport const quadrupedLayout = (spec: QuadrupedSpec): QuadrupedLayout => {\n const leg = spec.leg\n const frontAngle1 = leg.fa1 ?? 0.06\n const frontAngle2 = leg.fa2 ?? -0.08\n const hindAngle1 = leg.ha1 ?? -0.32\n const hindAngle2 = leg.ha2 ?? 0.58\n const footHeight = leg.hoof ? leg.r * 1.1 : leg.r * 0.7\n const frontHipHeight = leg.fu * Math.cos(frontAngle1) + leg.fl * Math.cos(frontAngle1 + frontAngle2) + footHeight\n const hindHipHeight = leg.hu * Math.cos(hindAngle1) + leg.hl * Math.cos(hindAngle1 + hindAngle2) + footHeight\n const bodyHeight = (frontHipHeight + hindHipHeight) / 2 + (spec.up ?? 0) * spec.R\n return { frontHipHeight, hindHipHeight, footHeight, bodyHeight, span: spec.L * spec.span, size: Math.max(spec.L, bodyHeight + spec.R) }\n}\n\n/** The size of a bird: the largest of its body and its standing height. */\nexport const birdSize = (spec: BirdSpec): number => Math.max(spec.r * 3, spec.tars + spec.shank * 0.9 + spec.r * 2)\n\n/** The length a species takes in a line-up: used to space the animals apart. */\nexport const lineUpLength = (body: QuadrupedSpec | BirdSpec | { readonly kind: 'snake' }): number => {\n if (body.kind === 'quadruped') return body.L * 1.3\n if (body.kind === 'snake') return 0.9\n return body.r * 4\n}\n","type Entry = { readonly id: string }\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 shallow merge); 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, 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, { ...entry, ...patch, id })\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 { GAIT_PHASES } from './gaits'\nimport { applyPatches, mergeById, removeIds } from './registry'\nimport type { AnimalGaitName, AnimalOutcome, AnimalSpecies, AnimalVisualState, AnimalsOptions, GaitPhases } from './types'\n\nexport type AnimalKit = {\n readonly species: readonly AnimalSpecies[]\n get(id: string): AnimalSpecies | undefined\n gait(name: AnimalGaitName): GaitPhases\n}\n\n/**\n * What a bite does to the look of an animal: a species that turns shows the infected look, one that dies shows the dead look, and an immune one shows no\n * change. `forceDead` shows the dead look for any species (a carcass, an animal killed by something else).\n */\nexport const visualStateOf = (outcome: AnimalOutcome, isBitten: boolean, forceDead = false): AnimalVisualState => {\n if (forceDead) return 'dead'\n if (!isBitten) return 'alive'\n if (outcome === 'turns') return 'infected'\n return outcome === 'dies' ? 'dead' : 'alive'\n}\n\nexport const createAnimals = (options: AnimalsOptions = {}): AnimalKit => {\n const entries = mergeById([], options.packs?.flatMap((pack) => pack.species ?? []))\n applyPatches(entries, options.patch)\n removeIds(entries, options.remove)\n const species = [...entries.values()].sort((first, second) => first.order - second.order)\n const gaits = { ...GAIT_PHASES, ...options.gaits }\n return { species, get: (id) => entries.get(id), gait: (name) => gaits[name] }\n}\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 type { BirdSpec } from '@adatechnology/game-animals'\n\nimport type { AnimateParams } from './animate-types'\nimport type { AnimalRig } from './types'\n\nconst { PI } = Math\n\n/** Advances a bird's cycle (page: `animBird`): steps, flight for the species that fly, wings, peck, alarm, tail. */\nexport const animateBird = (rig: AnimalRig, params: AnimateParams): void => {\n const { time: t, delta: dt, clip } = params\n const species = rig.species\n const spec = species.body as BirdSpec\n const isVulture = species.id === 'vulture'\n const isChicken = species.id === 'chicken'\n const isLapwing = species.id === 'southern_lapwing'\n const flying = clip === 'run' && !isChicken\n const hz = clip === 'run' && !flying ? species.runHz : clip === 'walk' ? species.walkHz : 0\n rig.phase += dt * (flying ? (isVulture ? 1.1 : 4.5) : hz) * 2 * PI\n const targetHeight = flying ? rig.size * 1.2 : 0\n rig.trunk.position.y += (targetHeight - rig.trunk.position.y) * Math.min(1, dt * 3)\n rig.legs.forEach((leg, index) => {\n if (flying) {\n leg.hip.rotation.x = 1.2\n leg.knee.rotation.x = -1.6\n } else if (clip === 'idle') {\n leg.hip.rotation.x = 0\n leg.knee.rotation.x = 0\n } else {\n const phase = rig.phase + index * PI\n leg.hip.rotation.x = -Math.sin(phase) * 0.45\n leg.knee.rotation.x = -Math.max(0, Math.cos(phase)) * 0.7\n }\n leg.foot.rotation.x = -(leg.hip.rotation.x + leg.knee.rotation.x)\n })\n rig.wings.forEach((wing) => {\n const { side, shoulder, elbow } = wing\n if (flying) {\n const flap = isVulture ? 0.25 + Math.sin(rig.phase) * 0.18 : Math.sin(rig.phase) * 0.9\n shoulder.rotation.y += (0 - shoulder.rotation.y) * Math.min(1, dt * 6)\n shoulder.rotation.z = side * flap\n elbow.rotation.z = side * (isVulture ? 0.08 : Math.sin(rig.phase - 0.6) * 0.4)\n elbow.rotation.y = 0\n shoulder.scale.x += (1 - shoulder.scale.x) * Math.min(1, dt * 6)\n } else {\n const alert = isLapwing && clip === 'idle' ? Math.max(0, Math.sin(t * 1.3)) * 0.9 : 0\n const flutter = isChicken && clip === 'run' ? Math.abs(Math.sin(rig.phase * 1.5)) * 0.8 : 0\n shoulder.rotation.y += ((side * PI) / 2 * 0.97 - alert * side * 0.9 - shoulder.rotation.y) * Math.min(1, dt * 6)\n shoulder.rotation.z = side * (-0.06 + flutter + alert * 0.6)\n elbow.rotation.z = side * 0.04\n elbow.rotation.y = 0\n shoulder.scale.x += ((alert > 0.1 ? 1 : 0.58) - shoulder.scale.x) * Math.min(1, dt * 6)\n }\n })\n const peck = isChicken && clip === 'idle' ? Math.max(0, Math.sin(t * 1.6)) ** 8 * 1.2 : 0\n if (rig.neck) {\n rig.neck.rotation.x = rig.neckAngle + (clip === 'walk' && !isVulture ? Math.max(0, Math.sin(rig.phase * 2)) * 0.35 : 0) + peck + (flying ? 0.6 : 0)\n rig.neck.rotation.y = clip === 'idle' ? Math.sin(t * 0.9) * 0.5 : 0\n }\n if (rig.jaw) rig.jaw.rotation.x = isLapwing && clip === 'idle' ? Math.max(0, Math.sin(t * 1.3)) * Math.abs(Math.sin(t * 14)) * 0.5 : 0\n if (rig.tailRoot) rig.tailRoot.rotation.x = (spec.tailA || 0) + (flying ? 0.6 : 0)\n}\n","import type { GaitPhases, QuadrupedSpec } from '@adatechnology/game-animals'\n\nimport type { AnimateParams } from './animate-types'\nimport type { AnimalRig } from './types'\n\nconst { PI } = Math\n\n/** Advances a quadruped's step cycle (page: `animQuad`): legs by gait phase, trunk bob, neck, head, jaw and tail; a dead one lies down. */\nexport const animateQuadruped = (rig: AnimalRig, params: AnimateParams, gaits: { readonly walk: GaitPhases; readonly trot: GaitPhases; readonly gallop: GaitPhases }): void => {\n const { time: t, delta: dt, clip } = params\n const species = rig.species\n const spec = species.body as QuadrupedSpec\n if (rig.dead) {\n rig.root.rotation.z += (PI / 2 * 0.97 - rig.root.rotation.z) * Math.min(1, dt * 3)\n rig.root.position.y += (spec.R * (spec.sx || 1) * 0.85 - rig.root.position.y) * Math.min(1, dt * 3)\n rig.legs.forEach((leg) => {\n leg.hip.rotation.x = leg.angle1 + (leg.isFront ? -0.5 : 0.4)\n leg.knee.rotation.x = 0.05\n leg.foot.rotation.x = 0\n })\n if (rig.neck) rig.neck.rotation.x = rig.neckAngle + 0.35\n if (rig.jaw) rig.jaw.rotation.x = 0.25\n return\n }\n const hz = (clip === 'run' ? species.runHz : clip === 'walk' ? species.walkHz : 0) * (rig.infected ? 1.2 : 1)\n rig.phase += dt * hz * 2 * PI\n const gait = clip === 'run' ? (species.gallop ? gaits.gallop : gaits.trot) : gaits.walk\n const amplitude = clip === 'run' ? 0.62 : 0.34\n const flex = clip === 'run' ? 1.15 : 0.75\n rig.legs.forEach((leg, index) => {\n if (clip === 'idle') {\n leg.hip.rotation.x = leg.angle1\n leg.knee.rotation.x = leg.angle2\n } else {\n const phase = rig.phase + (gait[index] as number)\n const limit = rig.infected && index === 1 ? 0.35 : 1\n leg.hip.rotation.x = leg.angle1 - Math.sin(phase) * amplitude * limit\n leg.knee.rotation.x = leg.angle2 + Math.max(0, Math.cos(phase)) * flex * limit\n }\n leg.foot.rotation.x = -(leg.hip.rotation.x + leg.knee.rotation.x) * 0.85\n })\n const bob = clip === 'idle' ? 0 : Math.abs(Math.sin(rig.phase)) * (clip === 'run' ? 0.05 : 0.018) * rig.size\n rig.trunk.position.y = bob * 0.6\n const bodyGroup = rig.bodyGroup\n if (bodyGroup) {\n bodyGroup.rotation.x = clip === 'run' && species.gallop ? Math.sin(rig.phase + PI * 0.4) * 0.07 : 0\n bodyGroup.scale.y = 1 + (clip === 'idle' ? Math.sin(t * 2.2) * 0.012 : 0)\n }\n const low = rig.infected ? 0.35 : 0\n if (rig.neck) {\n rig.neck.rotation.x = rig.neckAngle + low + (clip === 'idle' ? Math.sin(t * 0.7) * 0.08 : Math.sin(rig.phase * 2) * 0.04)\n rig.neck.rotation.y = clip === 'idle' ? Math.sin(t * 0.45) * 0.35 : 0\n }\n if (rig.head) rig.head.rotation.z = rig.infected ? Math.sin(t * 11) * Math.sin(t * 1.7) * 0.12 : 0\n if (rig.jaw) rig.jaw.rotation.x = rig.infected ? 0.25 + Math.max(0, Math.sin(t * 6)) * 0.25 : clip === 'run' ? 0.12 : 0\n const wagging = species.id === 'dog' && !rig.infected\n rig.tail.forEach((segment, index) => {\n segment.rotation.z = Math.sin(t * (wagging ? 9 : 2.2) - index * 0.6) * (wagging ? 0.35 : 0.12)\n })\n}\n","import type * as THREE_NS from 'three'\n\nimport type { AnimateParams } from './animate-types'\nimport type { AnimalRig, Three } from './types'\n\nconst { PI } = Math\n\n/** The path of the body for a clip: crawling in a wave, or coiled with the head up in an S (and striking when `strike` rises). */\nconst bodyPath = (THREE: Three, rig: AnimalRig, params: AnimateParams, spacing: number): THREE_NS.Vector3[] => {\n const { time: t, clip } = params\n const points: THREE_NS.Vector3[] = []\n for (let index = 0; index < rig.segmentCount; index++) {\n let x: number\n let z: number\n let y = 0\n if (clip === 'walk') {\n z = 0.6 - index * spacing\n x = Math.sin(rig.phase * 2.2 - index * 0.42) * 0.08 * Math.min(1, index / 6 + 0.3)\n } else {\n const strike = clip === 'run' ? Math.max(0, Math.sin(t * 2.2)) ** 6 : 0\n if (index < 9) {\n const k = index / 9\n z = 0.08 + (1 - k) * 0.12 + strike * (1 - k) * 0.35\n y = (1 - k) * 0.13 * (1 - strike * 0.6)\n x = Math.sin(k * PI * 1.6) * 0.05 * (1 - strike)\n } else {\n const angle = (index - 9) * 0.36\n const radius = 0.16 - (index - 9) * 0.0045\n x = Math.cos(angle) * radius\n z = Math.sin(angle) * radius - 0.05\n y = (index - 9) * 0.0012\n }\n }\n points.push(new THREE.Vector3(x, y, z))\n }\n return points\n}\n\n/** Advances a snake (page: `animSnake`): lays the 34 segments along the path of the clip, then the head, jaw and tongue. */\nexport const animateSnake = (THREE: Three, rig: AnimalRig, params: AnimateParams): void => {\n const { time: t, delta: dt, clip } = params\n const spacing = rig.segmentLength * (params.split ? 1.5 : 1)\n if (clip === 'walk') rig.phase += dt * 2.4\n const points = bodyPath(THREE, rig, params, spacing)\n const at = (index: number): THREE_NS.Vector3 => points[index] as THREE_NS.Vector3\n for (let index = 0; index < rig.segmentCount; index++) {\n const group = (rig.segments[index] as AnimalRig['segments'][number]).group\n group.position.copy(at(index))\n const direction = index === 0 ? at(0).clone().sub(at(1)) : at(index - 1).clone().sub(at(index))\n group.rotation.set(0, Math.atan2(direction.x, direction.z), 0)\n group.rotateX(-Math.atan2(direction.y, Math.hypot(direction.x, direction.z)))\n }\n const head = rig.head as THREE_NS.Group\n const headDirection = at(0).clone().sub(at(1)).normalize()\n head.position.copy(at(0)).addScaledVector(headDirection, 0.02)\n head.rotation.set(0, Math.atan2(headDirection.x, headDirection.z), 0)\n head.rotateX(-Math.atan2(headDirection.y, Math.hypot(headDirection.x, headDirection.z)) * 0.5)\n const jaw = rig.jaw as THREE_NS.Group\n jaw.rotation.x = clip === 'run' ? Math.max(0, Math.sin(t * 2.2)) ** 6 * 0.9 : 0\n const tongue = rig.tongue as THREE_NS.Mesh\n tongue.visible = Math.sin(t * 5) > 0.3\n tongue.scale.z = 1 + Math.sin(t * 20) * 0.3\n}\n","import type * as THREE_NS from 'three'\n\nimport type { AnimalRig, AnimalsThreeOptions, Three } from './types'\n\nexport type MaterialExtras = Partial<THREE_NS.MeshStandardMaterialParameters>\n\n/** The mulberry32 stream of the page (`rng`): the same numbers for the same seed. */\nexport const createStream = (seed: number): (() => number) => {\n let state = seed\n return () => {\n state |= 0\n state = (state + 0x6d2b79f5) | 0\n let t = Math.imul(state ^ (state >>> 15), 1 | state)\n t = (t + Math.imul(t ^ (t >>> 7), 61 | t)) ^ t\n return ((t ^ (t >>> 14)) >>> 0) / 4294967296\n }\n}\n\n/** The page's `add`: a mesh at a position and rotation under a parent, casting and receiving shadows. */\nexport const addMesh = (\n THREE: Three,\n parent: THREE_NS.Object3D,\n geometry: THREE_NS.BufferGeometry,\n material: THREE_NS.Material,\n x?: number,\n y?: number,\n z?: number,\n rx?: number,\n ry?: number,\n rz?: number,\n): THREE_NS.Mesh => {\n const mesh = new THREE.Mesh(geometry, material)\n mesh.position.set(x || 0, y || 0, z || 0)\n if (rx || ry || rz) mesh.rotation.set(rx || 0, ry || 0, rz || 0)\n mesh.castShadow = true\n mesh.receiveShadow = true\n parent.add(mesh)\n return mesh\n}\n\n/** The part builders of the page's `Animal` (`M`, `ball`, `limb`, `joint`, `pivot`), bound to one rig. */\nexport type RigTools = {\n material(color: number, extras?: MaterialExtras): THREE_NS.MeshStandardMaterial\n ball(parent: THREE_NS.Object3D, radius: number, material: THREE_NS.Material, x?: number, y?: number, z?: number, sx?: number, sy?: number, sz?: number): THREE_NS.Mesh\n /** A cylinder hanging from the origin; `radius1` is the one the page calls the top, but the geometry takes it as the bottom (kept as the page has it). */\n limb(parent: THREE_NS.Object3D, radius1: number, radius2: number, length: number, material: THREE_NS.Material): THREE_NS.Mesh\n joint(parent: THREE_NS.Object3D, radius: number, material: THREE_NS.Material, x?: number, y?: number, z?: number): THREE_NS.Mesh\n pivot(parent: THREE_NS.Object3D, x: number, y: number, z: number, offset?: THREE_NS.Vector3): THREE_NS.Group\n eyes(head: THREE_NS.Object3D, radius: number, x: number, y: number, z: number): void\n}\n\nexport const createRigTools = (THREE: Three, rig: AnimalRig): RigTools => {\n const tools: RigTools = {\n material(color, extras) {\n const material = new THREE.MeshStandardMaterial(Object.assign({ color, roughness: 0.8, metalness: 0, flatShading: false }, extras || {}))\n material.userData.base = material.color.clone()\n rig.materials.push(material)\n return material\n },\n ball(parent, radius, material, x, y, z, sx, sy, sz) {\n const mesh = addMesh(THREE, parent, new THREE.SphereGeometry(radius, 16, 12), material, x, y, z)\n if (sx) mesh.scale.set(sx, sy as number, sz as number)\n return mesh\n },\n limb: (parent, radius1, radius2, length, material) => addMesh(THREE, parent, new THREE.CylinderGeometry(radius2, radius1, length, 14, 1).translate(0, -length / 2, 0), material),\n joint(parent, radius, material, x, y, z) {\n const joint = tools.ball(parent, radius, material, x, y, z)\n joint.userData.joint = 1\n rig.joints.push(joint)\n return joint\n },\n pivot(parent, x, y, z, offset) {\n const group = new THREE.Group()\n group.position.set(x, y, z)\n parent.add(group)\n rig.pivots.push({ group, rest: group.position.clone(), offset: offset || new THREE.Vector3() })\n return group\n },\n eyes(head, radius, x, y, z) {\n const eyeMaterial = tools.material(0x111111, { roughness: 0.25 })\n rig.eyeMaterial = eyeMaterial\n for (const side of [-1, 1]) rig.eyes.push(tools.ball(head, radius, eyeMaterial, side * x, y, z))\n },\n }\n return tools\n}\n\nexport const createRig = (THREE: Three, species: AnimalRig['species'], options: AnimalsThreeOptions & { phase: number }): AnimalRig => {\n const rig: AnimalRig = {\n species,\n root: new THREE.Group(),\n trunk: new THREE.Group(),\n materials: [],\n joints: [],\n pivots: [],\n legs: [],\n tail: [],\n ears: [],\n infectionParts: [],\n eyes: [],\n wings: [],\n segments: [],\n phase: options.phase,\n size: 1,\n segmentLength: 0,\n segmentCount: 0,\n home: new THREE.Vector3(),\n infected: false,\n dead: false,\n neckAngle: 0,\n headAngle: 0,\n triangles: 0,\n }\n rig.root.add(rig.trunk)\n return rig\n}\n","import { birdSize } from '@adatechnology/game-animals'\nimport type { BirdSpec } from '@adatechnology/game-animals'\nimport type * as THREE_NS from 'three'\n\nimport { addMesh, createRigTools } from './context'\nimport type { BirdExtra } from './extras'\nimport type { AnimalRig, Three } from './types'\n\nconst buildWings = (THREE: Three, rig: AnimalRig, spec: BirdSpec, parts: { bodyGroup: THREE_NS.Group; main: THREE_NS.MeshStandardMaterial; dark: THREE_NS.MeshStandardMaterial }): void => {\n const tools = createRigTools(THREE, rig)\n const { bodyGroup, main, dark } = parts\n for (const side of [-1, 1]) {\n const shoulder = tools.pivot(bodyGroup, side * spec.r * spec.s[0] * 1.02, spec.r * 0.22, spec.r * 0.3, new THREE.Vector3(side * 0.12, 0.03, 0).multiplyScalar(rig.size))\n tools.joint(shoulder, spec.r * 0.14, main, 0, 0, 0)\n tools.ball(shoulder, 0.5, spec.wingM ? tools.material(spec.wingM) : dark, side * spec.wi * 0.5, 0, -spec.wc * 0.3, spec.wi * 1.05, spec.r * 0.16, spec.wc)\n const elbow = tools.pivot(shoulder, side * spec.wi, 0, 0, new THREE.Vector3(side * 0.06, 0, 0).multiplyScalar(rig.size))\n tools.joint(elbow, spec.r * 0.1, main, 0, 0, 0)\n tools.ball(elbow, 0.5, dark, side * spec.wo * 0.45, 0, -spec.wc * 0.32, spec.wo * 1.05, spec.r * 0.12, spec.wc * 0.75)\n if (spec.fingers) {\n for (let finger = 0; finger < 4; finger++) {\n addMesh(THREE, elbow, new THREE.BoxGeometry(spec.wo * 0.35, spec.r * 0.03, spec.wc * 0.12), dark, side * (spec.wo + spec.wo * 0.12), 0, -spec.wc * 0.05 - finger * spec.wc * 0.18, 0, side * (0.05 + finger * 0.12), 0)\n }\n }\n if (spec.spur) addMesh(THREE, elbow, new THREE.ConeGeometry(spec.r * 0.06, spec.r * 0.25, 5), tools.material(0xc0302a), 0, 0, spec.wc * 0.2, Math.PI / 2, 0, 0)\n rig.wings.push({ shoulder, elbow, side })\n }\n}\n\nconst buildLegs = (THREE: Three, rig: AnimalRig, spec: BirdSpec, parts: { bodyGroup: THREE_NS.Group; main: THREE_NS.MeshStandardMaterial; leg: THREE_NS.MeshStandardMaterial }): void => {\n const tools = createRigTools(THREE, rig)\n const { bodyGroup, main, leg } = parts\n for (const side of [-1, 1]) {\n const hip = tools.pivot(bodyGroup, side * spec.r * 0.38, -spec.r * 0.55, spec.r * 0.05, new THREE.Vector3(side * 0.06, -0.05, 0).multiplyScalar(rig.size))\n tools.joint(hip, spec.r * 0.18, main, 0, 0, 0)\n tools.limb(hip, spec.r * 0.16, spec.r * 0.09, spec.shank, spec.featherLeg ? main : leg)\n const ankle = tools.pivot(hip, 0, -spec.shank, 0, new THREE.Vector3(0, -0.04, 0).multiplyScalar(rig.size))\n tools.joint(ankle, spec.r * 0.06, leg, 0, 0, 0)\n tools.limb(ankle, spec.r * 0.055, spec.r * 0.05, spec.tars, leg)\n const foot = tools.pivot(ankle, 0, -spec.tars, 0)\n for (const angle of [-0.45, 0, 0.45]) addMesh(THREE, foot, new THREE.BoxGeometry(spec.r * 0.05, spec.r * 0.04, spec.r * 0.55).translate(0, 0, spec.r * 0.25), leg, 0, -spec.r * 0.02, 0, 0, angle, 0)\n addMesh(THREE, foot, new THREE.BoxGeometry(spec.r * 0.05, spec.r * 0.04, spec.r * 0.25).translate(0, 0, -spec.r * 0.12), leg, 0, -spec.r * 0.02, 0)\n rig.legs.push({ hip, knee: ankle, foot, isFront: false, angle1: 0.35, angle2: -0.5, side })\n }\n}\n\n/** Builds a bird: body, tail, two wings with shoulder and elbow pivots, neck, head with beak and jaw, eyes, the species' extra parts, and two legs. */\nexport const buildBird = (THREE: Three, rig: AnimalRig, options: { extra?: BirdExtra }): AnimalRig => {\n const spec = rig.species.body as BirdSpec\n const tools = createRigTools(THREE, rig)\n const colors = spec.c\n const main = tools.material(colors.main)\n const dark = tools.material(colors.dark)\n const leg = tools.material(colors.leg)\n const beak = tools.material(colors.beak, { roughness: 0.5 })\n const belly = tools.material(colors.belly || colors.main)\n rig.main = main\n const hipY = spec.tars + spec.shank * 0.9\n rig.size = birdSize(spec)\n const bodyGroup = tools.pivot(rig.trunk, 0, hipY + spec.r * 0.55, 0)\n rig.bodyGroup = bodyGroup\n bodyGroup.rotation.x = spec.pitch || 0\n tools.ball(bodyGroup, spec.r, main, 0, 0, 0, spec.s[0], spec.s[1], spec.s[2])\n tools.ball(bodyGroup, spec.r * 0.9, belly, 0, -spec.r * 0.22, spec.r * 0.15, spec.s[0] * 0.9, spec.s[1] * 0.8, spec.s[2] * 0.85)\n const tail = tools.pivot(bodyGroup, 0, spec.r * 0.15, -spec.r * spec.s[2] * 0.85, new THREE.Vector3(0, 0, -0.08).multiplyScalar(rig.size))\n tail.rotation.x = spec.tailA || -0.3\n rig.tailRoot = tail\n addMesh(THREE, tail, new THREE.BoxGeometry(spec.tailW, spec.r * 0.08, spec.tailL).translate(0, 0, -spec.tailL / 2), spec.tailM ? tools.material(spec.tailM) : dark)\n buildWings(THREE, rig, spec, { bodyGroup, main, dark })\n const neck = tools.pivot(bodyGroup, 0, spec.r * 0.45, spec.r * spec.s[2] * 0.75, new THREE.Vector3(0, 0.05, 0.08).multiplyScalar(rig.size))\n neck.rotation.x = spec.neckA\n rig.neck = neck\n rig.neckAngle = spec.neckA\n tools.joint(neck, spec.nr * 1.1, spec.neckM ? tools.material(spec.neckM) : main, 0, 0, 0)\n addMesh(THREE, neck, new THREE.CylinderGeometry(spec.nr * 0.85, spec.nr, spec.nl, 12).translate(0, spec.nl / 2, 0), spec.neckM ? tools.material(spec.neckM) : main)\n const head = tools.pivot(neck, 0, spec.nl, 0, new THREE.Vector3(0, 0.05, 0.05).multiplyScalar(rig.size))\n head.rotation.x = -spec.neckA + (spec.headA || 0)\n rig.head = head\n rig.headAngle = head.rotation.x\n const headMaterial = spec.headM ? tools.material(spec.headM) : main\n tools.ball(head, spec.hr, headMaterial, 0, 0, 0, spec.hs ? spec.hs[0] : 1, spec.hs ? spec.hs[1] : 1, spec.hs ? spec.hs[2] : 1.1)\n addMesh(THREE, head, new THREE.ConeGeometry(spec.br, spec.bl, 8).rotateX(Math.PI / 2).translate(0, 0, spec.bl / 2), beak, 0, -spec.hr * 0.1, spec.hr * 0.85, spec.hook || 0, 0, 0)\n const jaw = tools.pivot(head, 0, -spec.hr * 0.25, spec.hr * 0.8)\n rig.jaw = jaw\n addMesh(THREE, jaw, new THREE.ConeGeometry(spec.br * 0.7, spec.bl * 0.85, 8).rotateX(Math.PI / 2).translate(0, 0, spec.bl * 0.42), beak).scale.set(1, 0.5, 1)\n tools.eyes(head, spec.hr * 0.17, spec.hr * 0.68, spec.hr * 0.2, spec.hr * 0.35)\n if (spec.eyeC && rig.eyeMaterial) {\n rig.eyeMaterial.color.set(spec.eyeC)\n rig.eyeMaterial.userData.base = rig.eyeMaterial.color.clone()\n }\n options.extra?.({ THREE, rig, tools }, { bodyGroup, head, neck, main, dark })\n buildLegs(THREE, rig, spec, { bodyGroup, main, leg })\n return rig\n}\n","import type * as THREE_NS from 'three'\n\nimport { addMesh } from './context'\nimport type { RigTools } from './context'\nimport type { HeadSpecOf, NeckSpecOf } from './extras-types'\nimport type { AnimalRig, Three } from './types'\n\nexport type ExtraContext = { readonly THREE: Three; readonly rig: AnimalRig; readonly tools: RigTools }\n\nexport type QuadrupedParts = {\n readonly bodyGroup: THREE_NS.Group\n readonly head: THREE_NS.Group\n readonly neck: THREE_NS.Group\n readonly main: THREE_NS.MeshStandardMaterial\n readonly belly: THREE_NS.MeshStandardMaterial\n readonly dark: THREE_NS.MeshStandardMaterial\n readonly L: number\n readonly Rb: number\n readonly bodyY: number\n readonly hd: HeadSpecOf\n readonly nk: NeckSpecOf\n}\n\nexport type BirdParts = {\n readonly bodyGroup: THREE_NS.Group\n readonly head: THREE_NS.Group\n readonly neck: THREE_NS.Group\n readonly main: THREE_NS.MeshStandardMaterial\n readonly dark: THREE_NS.MeshStandardMaterial\n}\n\nexport type QuadrupedExtra = (context: ExtraContext, parts: QuadrupedParts) => void\nexport type BirdExtra = (context: ExtraContext, parts: BirdParts) => void\n\nconst cow: QuadrupedExtra = ({ THREE, tools }, k) => {\n tools.ball(k.bodyGroup, 0.2, k.main, 0, k.Rb * 1.1, k.L * 0.33, 0.95, 1.1, 1.1) // hump\n tools.ball(k.neck, 0.13, k.main, 0, 0.12, 0.08, 0.55, 1.4, 1.05) // dewlap\n for (const side of [-1, 1]) addMesh(THREE, k.head, new THREE.ConeGeometry(0.025, 0.13, 8), tools.material(0xcfc6a8), side * 0.12, k.hd.r * 1.05, k.hd.r * 0.05, 0, 0, side * -0.9)\n}\n\nconst horse: QuadrupedExtra = ({ THREE, rig, tools }, k) => {\n for (let index = 0; index < 9; index++) addMesh(THREE, k.neck, new THREE.BoxGeometry(0.035, 0.16, 0.08), k.dark, 0, 0.06 + index * 0.065, -0.12 + index * 0.004, -0.25, 0, 0) // mane\n addMesh(THREE, k.head, new THREE.BoxGeometry(0.03, 0.12, 0.06), k.dark, 0, k.hd.r * 1.05, k.hd.r * 0.3, 0.6, 0, 0) // forelock\n const last = rig.tail[rig.tail.length - 1] as THREE_NS.Group\n tools.ball(last, 0.08, k.dark, 0, -0.42, 0, 0.7, 4.5, 0.7) // tail hair\n}\n\nconst wildBoar: QuadrupedExtra = ({ THREE, tools }, k) => {\n for (let index = 0; index < 12; index++) addMesh(THREE, k.bodyGroup, new THREE.BoxGeometry(0.03, 0.1, 0.06), k.dark, 0, k.Rb * 1.12 - index * 0.004, k.L * 0.38 - index * 0.06, -0.2, 0, 0) // bristles\n for (const side of [-1, 1])\n addMesh(THREE, k.head, new THREE.ConeGeometry(0.012, 0.09, 6), tools.material(0xe8e0cc), side * 0.07, k.hd.r * -0.25 + 0.03, k.hd.r * 0.25 + k.hd.r * k.hd.s[2] * 0.55 + 0.13, -0.6, 0, side * 0.5) // tusks\n}\n\nconst chicken: BirdExtra = ({ tools }, k) => {\n const red = tools.material(0xc0281e)\n for (let index = 0; index < 4; index++) tools.ball(k.head, 0.014, red, 0, 0.045, -0.012 + index * 0.014, 0.5, 1, 0.8) // comb\n tools.ball(k.head, 0.012, red, 0, -0.04, 0.04, 0.5, 1.3, 0.7) // wattle\n}\n\nconst southernLapwing: BirdExtra = ({ THREE, tools }, k) => {\n const black = tools.material(0x161616)\n tools.ball(k.bodyGroup, 0.05, black, 0, 0.03, 0.08, 1.1, 0.9, 0.6) // breast patch\n addMesh(THREE, k.head, new THREE.BoxGeometry(0.006, 0.006, 0.06).translate(0, 0, -0.03), black, 0, 0.025, -0.01, 0.5, 0, 0) // crest\n tools.ball(k.head, 0.026, black, 0, -0.005, 0.02, 1.05, 0.7, 0.9) // cap\n}\n\n/** The parts the page builds with code for five species (the page's `extra` closures), by species id. */\nexport const QUADRUPED_EXTRAS: Readonly<Record<string, QuadrupedExtra>> = { cow, horse, wild_boar: wildBoar }\nexport const BIRD_EXTRAS: Readonly<Record<string, BirdExtra>> = { chicken, southern_lapwing: southernLapwing }\n","import type { TextureMarker } from '@adatechnology/game-animals'\nimport type * as THREE_NS from 'three'\n\nimport { createStream } from './context'\nimport type { CanvasLike, DocumentLike, Three } from './types'\n\ntype Painter = {\n fillStyle: string\n strokeStyle: string\n lineWidth: number\n fillRect(x: number, y: number, width: number, height: number): void\n beginPath(): void\n arc(x: number, y: number, radius: number, from: number, to: number): void\n stroke(): void\n fill(): void\n}\n\nconst canvasTexture = (THREE: Three, document: DocumentLike, width: number, height: number, draw: (painter: Painter, width: number, height: number) => void): THREE_NS.CanvasTexture => {\n const canvas: CanvasLike = document.createElement('canvas')\n canvas.width = width\n canvas.height = height\n draw(canvas.getContext('2d') as Painter, width, height)\n const texture = new THREE.CanvasTexture(canvas as unknown as HTMLCanvasElement)\n texture.colorSpace = THREE.SRGBColorSpace\n return texture\n}\n\nconst spotsTexture = (THREE: Three, document: DocumentLike, base: string, spot: string): THREE_NS.CanvasTexture =>\n canvasTexture(THREE, document, 256, 256, (painter, width, height) => {\n painter.fillStyle = base\n painter.fillRect(0, 0, width, height)\n const next = createStream(11)\n for (let index = 0; index < 70; index++) {\n const x = next() * width\n const y = next() * height\n const radius = 5 + next() * 7\n painter.strokeStyle = spot\n painter.lineWidth = 3\n painter.beginPath()\n painter.arc(x, y, radius, 0, 7)\n painter.stroke()\n painter.fillStyle = 'rgba(120,70,20,.45)'\n painter.beginPath()\n painter.arc(x, y, radius * 0.6, 0, 7)\n painter.fill()\n }\n for (let index = 0; index < 60; index++) {\n painter.fillStyle = spot\n painter.beginPath()\n painter.arc(next() * width, next() * height, 1.5 + next() * 2.5, 0, 7)\n painter.fill()\n }\n })\n\nconst stripesTexture = (THREE: Three, document: DocumentLike, base: string, stripe: string): THREE_NS.CanvasTexture =>\n canvasTexture(THREE, document, 128, 128, (painter, width) => {\n painter.fillStyle = base\n painter.fillRect(0, 0, width, 128)\n painter.fillStyle = stripe\n for (let index = 0; index < 9; index++) painter.fillRect(0, index * 14 + (index % 2) * 3, width, 4)\n })\n\n/** The coat texture a species spec asks for (cat stripes, jaguar rosettes), painted on a canvas. */\nexport const createCoatTexture = (THREE: Three, document: DocumentLike, marker: TextureMarker): THREE_NS.CanvasTexture =>\n marker.kind === 'stripes' ? stripesTexture(THREE, document, marker.base, marker.stripe) : spotsTexture(THREE, document, marker.base, marker.spot)\n","import type * as THREE_NS from 'three'\n\nimport type { Three } from './types'\n\n/** A body of revolution whose radius follows `profile` along the length, rear to front, closed by a point at each end. */\nexport const profileGeometry = (THREE: Three, length: number, profile: readonly number[], segments?: number): THREE_NS.LatheGeometry => {\n const points = profile.map((radius, index) => new THREE.Vector2(index / (profile.length - 1), radius))\n const curve = new THREE.SplineCurve(points)\n const outline: THREE_NS.Vector2[] = []\n outline.push(new THREE.Vector2(0.001, -length / 2 - 0.0))\n for (let step = 0; step <= 30; step++) {\n const point = curve.getPoint(step / 30)\n outline.push(new THREE.Vector2(Math.max(0.001, point.y), -length / 2 + point.x * length))\n }\n outline.push(new THREE.Vector2(0.001, length / 2))\n return new THREE.LatheGeometry(outline, segments || 22).rotateX(Math.PI / 2)\n}\n","import { quadrupedLayout } from '@adatechnology/game-animals'\nimport type { QuadrupedSpec } from '@adatechnology/game-animals'\nimport type * as THREE_NS from 'three'\n\nimport { addMesh, createRigTools } from './context'\nimport { createCoatTexture } from './textures'\nimport { profileGeometry } from './profile'\nimport type { AnimalRig, DocumentLike, Three } from './types'\nimport type { QuadrupedExtra } from './extras'\n\nconst RIB_COUNT = 4\n\ntype LegDefinition = readonly [number, number, 'F' | 'H']\n\nconst LEG_DEFINITIONS: readonly LegDefinition[] = [\n [1, 1, 'F'],\n [-1, 1, 'F'],\n [1, -1, 'H'],\n [-1, -1, 'H'],\n]\n\n/** The body and the four legs of a quadruped (page: the first half of `quad`). */\nconst buildBodyAndLegs = (THREE: Three, rig: AnimalRig, spec: QuadrupedSpec, main: THREE_NS.MeshStandardMaterial, belly: THREE_NS.MeshStandardMaterial, dark: THREE_NS.MeshStandardMaterial) => {\n const tools = createRigTools(THREE, rig)\n const { L, R: radius } = spec\n const leg = spec.leg\n const layout = quadrupedLayout(spec)\n const { frontHipHeight, hindHipHeight, footHeight, bodyHeight, span } = layout\n const frontAngle1 = leg.fa1 ?? 0.06\n const frontAngle2 = leg.fa2 ?? -0.08\n const hindAngle1 = leg.ha1 ?? -0.32\n const hindAngle2 = leg.ha2 ?? 0.58\n rig.size = layout.size\n const bodyGroup = tools.pivot(rig.trunk, 0, bodyHeight, 0)\n rig.bodyGroup = bodyGroup\n const body = addMesh(THREE, bodyGroup, profileGeometry(THREE, L, spec.prof.map((value) => value * radius)), main)\n body.scale.set(spec.sx || 1, spec.sy || 1, 1)\n body.rotation.x = Math.atan2(hindHipHeight - frontHipHeight, span) * 0.6\n rig.body = body\n const belt = addMesh(THREE, bodyGroup, profileGeometry(THREE, L * 0.8, spec.prof.map((value) => value * 0.8 * radius)), belly)\n belt.scale.set((spec.sx || 1) * 0.92, (spec.sy || 1) * 0.85, 1)\n belt.position.y = -radius * 0.2\n LEG_DEFINITIONS.forEach(([sx, sz, kind]) => {\n const front = kind === 'F'\n const upper = front ? leg.fu : leg.hu\n const lower = front ? leg.fl : leg.hl\n const height = front ? frontHipHeight : hindHipHeight\n const hip = tools.pivot(rig.trunk, sx * radius * (spec.sx || 1) * 0.55, height, (sz * span) / 2, new THREE.Vector3(sx * 0.18, -0.06, sz * 0.12).multiplyScalar(rig.size))\n tools.ball(hip, leg.r * (front ? 1.9 : 2.3), main, 0, -upper * 0.18, front ? 0 : -leg.r * 0.3, 0.75, 1.25, 1)\n tools.joint(hip, leg.r * 1.15, main, 0, 0, 0)\n tools.limb(hip, leg.r * 1.25, leg.r * 0.95, upper, main)\n const knee = tools.pivot(hip, 0, -upper, 0, new THREE.Vector3(0, -0.07 * rig.size, 0))\n tools.joint(knee, leg.r * 0.95, main, 0, 0, 0)\n tools.limb(knee, leg.r * 0.92, leg.r * 0.68, lower, main)\n const foot = tools.pivot(knee, 0, -lower, 0, new THREE.Vector3(0, -0.05 * rig.size, 0))\n if (leg.hoof) {\n tools.joint(foot, leg.r * 0.72, dark, 0, 0, 0)\n addMesh(THREE, foot, new THREE.CylinderGeometry(leg.r * 0.8, leg.r * 1.05, footHeight, 12).translate(0, -footHeight / 2, 0), dark)\n } else {\n tools.joint(foot, leg.r * 0.66, main, 0, 0, 0)\n tools.ball(foot, leg.r * 0.95, leg.dark ? dark : main, 0, -footHeight * 0.55, leg.r * 0.5, 1, 0.62, 1.45)\n }\n rig.legs.push({ hip, knee, foot, isFront: front, angle1: front ? frontAngle1 : hindAngle1, angle2: front ? frontAngle2 : hindAngle2, side: sx })\n })\n return { bodyGroup, bodyHeight }\n}\n\nconst buildHead = (THREE: Three, rig: AnimalRig, spec: QuadrupedSpec, parts: { bodyGroup: THREE_NS.Group; main: THREE_NS.MeshStandardMaterial; belly: THREE_NS.MeshStandardMaterial; nose: THREE_NS.MeshStandardMaterial }) => {\n const tools = createRigTools(THREE, rig)\n const { bodyGroup, main, belly, nose } = parts\n const { L, R: radius } = spec\n const neckSpec = spec.neck\n const headSpec = spec.head\n const neck = tools.pivot(bodyGroup, 0, radius * (spec.sy || 1) * (neckSpec.y ?? 0.35), (L / 2) * (neckSpec.z ?? 0.78), new THREE.Vector3(0, 0.05, 0.12).multiplyScalar(rig.size))\n neck.rotation.x = neckSpec.ang\n rig.neck = neck\n rig.neckAngle = neckSpec.ang\n tools.joint(neck, neckSpec.r * 1.05, main, 0, 0, 0)\n addMesh(THREE, neck, new THREE.CylinderGeometry(neckSpec.r2 || neckSpec.r * 0.85, neckSpec.r, neckSpec.len, 14).translate(0, neckSpec.len / 2, 0), main)\n const head = tools.pivot(neck, 0, neckSpec.len, 0, new THREE.Vector3(0, 0.06, 0.08).multiplyScalar(rig.size))\n head.rotation.x = -neckSpec.ang + (headSpec.down || 0)\n rig.head = head\n rig.headAngle = head.rotation.x\n tools.joint(head, neckSpec.r2 || neckSpec.r * 0.85, main, 0, 0, 0)\n tools.ball(head, headSpec.r, main, 0, headSpec.r * 0.25, headSpec.r * 0.25, headSpec.s[0], headSpec.s[1], headSpec.s[2])\n const snoutZ = headSpec.r * 0.25 + headSpec.r * headSpec.s[2] * 0.55\n const snout = addMesh(THREE, head, new THREE.CylinderGeometry(headSpec.sr2, headSpec.sr1, headSpec.sl, 14).rotateX(Math.PI / 2), headSpec.muzzle ? tools.material(headSpec.muzzle) : main, 0, headSpec.r * (headSpec.sy ?? 0), snoutZ + headSpec.sl / 2)\n snout.scale.set(1, headSpec.sq || 1, 1)\n tools.ball(head, headSpec.sr2 * 1.02, nose, 0, headSpec.r * (headSpec.sy ?? 0) + headSpec.sr2 * 0.1, snoutZ + headSpec.sl, 1, 0.85 * (headSpec.sq || 1), 0.45)\n const jaw = tools.pivot(head, 0, headSpec.r * (headSpec.sy ?? 0) - headSpec.sr1 * 0.55 * (headSpec.sq || 1), snoutZ - headSpec.sr1 * 0.2, new THREE.Vector3(0, -0.04, 0.04).multiplyScalar(rig.size))\n rig.jaw = jaw\n addMesh(THREE, jaw, new THREE.CylinderGeometry(headSpec.sr2 * 0.7, headSpec.sr1 * 0.75, headSpec.sl * 0.92, 12).rotateX(Math.PI / 2).translate(0, 0, headSpec.sl * 0.46), belly).scale.set(1, 0.45, 1)\n const blood = tools.ball(jaw, headSpec.sr2 * 0.9, rig.woundMaterial || (rig.woundMaterial = new THREE.MeshStandardMaterial({ color: 0x6a100c, roughness: 0.3 })), 0, 0.0, headSpec.sl * 0.9, 1.1, 0.6, 0.6)\n tools.eyes(head, headSpec.r * 0.13, headSpec.r * headSpec.s[0] * 0.52, headSpec.r * 0.5, headSpec.r * 0.25 + headSpec.r * headSpec.s[2] * 0.55)\n const ears = spec.ears\n for (const side of [-1, 1]) {\n const earGroup = tools.pivot(head, side * headSpec.r * headSpec.s[0] * 0.55, headSpec.r * (0.25 + headSpec.s[1] * 0.75), headSpec.r * 0.1, new THREE.Vector3(side * 0.04, 0.04, 0).multiplyScalar(rig.size))\n rig.ears.push(earGroup)\n if (ears.t === 'cone') addMesh(THREE, earGroup, new THREE.ConeGeometry(ears.s * 0.45, ears.s, 8).translate(0, ears.s / 2, 0), main, 0, 0, 0, ears.fwd || 0, 0, side * -(ears.tilt ?? 0.3))\n else if (ears.t === 'round') tools.ball(earGroup, ears.s, main, 0, ears.s * 0.4, 0, 1, 1, 0.35)\n else if (ears.t === 'flop') {\n const ear = tools.ball(earGroup, ears.s, main, side * ears.s * 0.9, -ears.s * 0.1, 0, 1.5, 0.45, 0.7)\n ear.rotation.z = side * -0.25\n }\n }\n return { neck, head, blood, neckSpec, headSpec }\n}\n\nconst buildTail = (THREE: Three, rig: AnimalRig, spec: QuadrupedSpec, parts: { bodyGroup: THREE_NS.Group; main: THREE_NS.MeshStandardMaterial; dark: THREE_NS.MeshStandardMaterial }): void => {\n const tools = createRigTools(THREE, rig)\n const tailSpec = spec.tail\n if (!tailSpec || !tailSpec.n) return\n const { bodyGroup, main, dark } = parts\n const { L, R: radius } = spec\n let parent = tools.pivot(bodyGroup, 0, radius * (spec.sy || 1) * (tailSpec.y ?? 0.3), (-L / 2) * 0.95, new THREE.Vector3(0, 0.02, -0.12).multiplyScalar(rig.size))\n parent.rotation.x = tailSpec.ang\n rig.tailRoot = parent\n const segmentLength = tailSpec.len / tailSpec.n\n for (let index = 0; index < tailSpec.n; index++) {\n const radius1 = tailSpec.r * (1 - (index / tailSpec.n) * 0.6)\n const radius2 = tailSpec.r * (1 - ((index + 1) / tailSpec.n) * 0.6)\n tools.limb(parent, radius1, radius2, segmentLength, tailSpec.dark && index === tailSpec.n - 1 ? dark : main)\n tools.joint(parent, radius1, main, 0, 0, 0)\n rig.tail.push(parent)\n if (index < tailSpec.n - 1) {\n const next = tools.pivot(parent, 0, -segmentLength, 0)\n next.rotation.x = tailSpec.curl || 0\n parent = next\n } else if (tailSpec.tuft) tools.ball(parent, tailSpec.r * 2.2, dark, 0, -segmentLength - tailSpec.r, 0, 1, 1.8, 1)\n }\n if (tailSpec.bushy) tools.ball(rig.tail[0] as THREE_NS.Group, tailSpec.r * 2.2, dark, 0, -tailSpec.len * 0.55, 0, 1, (tailSpec.len * 2.2) / tailSpec.r / 6, 1)\n}\n\n/** Wounds, ribs and the blood of the jaw: shown only while the animal is infected (page: the end of `quad`). */\nconst buildInfectionParts = (THREE: Three, rig: AnimalRig, spec: QuadrupedSpec, parts: { bodyGroup: THREE_NS.Group; neck: THREE_NS.Group; blood: THREE_NS.Mesh; neckSpec: QuadrupedSpec['neck'] }): void => {\n const tools = createRigTools(THREE, rig)\n const { bodyGroup, neck, blood, neckSpec } = parts\n const { L, R: radius } = spec\n const sideX = radius * (spec.sx || 1)\n const sideY = radius * (spec.sy || 1)\n const list: THREE_NS.Object3D[] = [blood]\n const wound = (parent: THREE_NS.Object3D, size: number, x: number, y: number, z: number, sx: number, sy: number, sz: number): THREE_NS.Mesh =>\n tools.ball(parent, size, rig.woundMaterial || (rig.woundMaterial = new THREE.MeshStandardMaterial({ color: 0x5a120e, roughness: 0.45 })), x, y, z, sx || 1, sy || 1, sz || 1)\n list.push(wound(bodyGroup, radius * 0.28, sideX * 0.92, sideY * 0.15, L * 0.05, 0.35, 1, 1.3))\n list.push(wound(bodyGroup, radius * 0.2, -sideX * 0.9, sideY * 0.3, -L * 0.2, 0.35, 1, 1.1))\n list.push(wound(neck, neckSpec.r * 0.5, neckSpec.r * 0.85, neckSpec.len * 0.5, 0, 0.4, 1, 1))\n const bone = tools.material(0xd9cfb8, { roughness: 0.6 })\n for (let index = 0; index < RIB_COUNT; index++) {\n const rib = addMesh(THREE, bodyGroup, new THREE.TorusGeometry(radius * 0.95, radius * 0.035, 6, 16, Math.PI * 0.42), bone, sideX * 0.12, sideY * 0.05, L * 0.12 - index * L * 0.07, 0, Math.PI / 2, -0.3)\n rib.scale.set(1, 1.02 * (spec.sy || 1), spec.sx || 1)\n list.push(rib)\n }\n rig.infectionParts.push(...list)\n list.forEach((part) => (part.visible = false))\n}\n\n/** Builds a quadruped: body, four legs on hip-knee-foot pivots, neck, head with jaw and eyes, ears, tail, the species' extra parts, and the infection parts. */\nexport const buildQuadruped = (THREE: Three, rig: AnimalRig, options: { document: DocumentLike; extra?: QuadrupedExtra }): AnimalRig => {\n const spec = rig.species.body as QuadrupedSpec\n const tools = createRigTools(THREE, rig)\n const colors = spec.c\n const texture = spec.texture ? createCoatTexture(THREE, options.document, spec.texture) : undefined\n const main = tools.material(texture ? 0xffffff : colors.main, texture ? { map: texture } : undefined)\n const belly = tools.material(colors.belly)\n const dark = tools.material(colors.dark)\n const nose = tools.material(colors.nose || colors.dark, { roughness: 0.4 })\n rig.main = main\n rig.dark = dark\n const { bodyGroup, bodyHeight } = buildBodyAndLegs(THREE, rig, spec, main, belly, dark)\n const { neck, head, blood, neckSpec, headSpec } = buildHead(THREE, rig, spec, { bodyGroup, main, belly, nose })\n buildTail(THREE, rig, spec, { bodyGroup, main, dark })\n options.extra?.({ THREE, rig, tools }, { bodyGroup, head, neck, main, belly, dark, L: spec.L, Rb: spec.R, bodyY: bodyHeight, hd: headSpec, nk: neckSpec })\n if (rig.species.outcome === 'turns') buildInfectionParts(THREE, rig, spec, { bodyGroup, neck, blood, neckSpec })\n else blood.visible = false\n return rig\n}\n","import { addMesh, createRigTools } from './context'\nimport type { AnimalRig, Three } from './types'\n\nconst SEGMENT_COUNT = 34\nconst SEGMENT_LENGTH = 0.042\n\n/** Builds a snake: 34 spheres on their own groups along the trunk (the animation lays them on a path), a head with a jaw and a tongue. */\nexport const buildSnake = (THREE: Three, rig: AnimalRig): AnimalRig => {\n const tools = createRigTools(THREE, rig)\n rig.size = 0.5\n rig.segmentLength = SEGMENT_LENGTH\n rig.segmentCount = SEGMENT_COUNT\n const primary = tools.material(0x7a6a4a)\n const secondary = tools.material(0x3a2e22)\n const belly = tools.material(0xb8a888)\n rig.main = primary\n for (let index = 0; index < SEGMENT_COUNT; index++) {\n const t = index / (SEGMENT_COUNT - 1)\n const radius = 0.012 + 0.03 * Math.sin(Math.min(1, t * 1.15) * Math.PI) * (t < 0.1 ? 0.75 + t * 2.5 : 1) + (t < 0.05 ? 0.012 : 0)\n const material = index % 4 === 1 || index % 4 === 2 ? secondary : primary\n const group = new THREE.Group()\n rig.trunk.add(group)\n const sphere = tools.ball(group, radius, material, 0, radius, 0, 1, 0.78, 1.5)\n sphere.userData.joint = index % 3 === 0 ? 1 : 0\n if (index % 3 === 0) rig.joints.push(sphere)\n rig.segments.push({ group, radius })\n }\n const head = new THREE.Group()\n rig.trunk.add(head)\n rig.head = head\n tools.ball(head, 0.032, primary, 0, 0.03, 0.025, 1.25, 0.6, 1.45)\n tools.ball(head, 0.024, secondary, 0, 0.04, 0.0, 1.3, 0.4, 0.9)\n tools.ball(head, 0.02, primary, 0, 0.028, 0.06, 0.85, 0.55, 1.1)\n const jaw = new THREE.Group()\n jaw.position.set(0, 0.018, 0.0)\n head.add(jaw)\n rig.jaw = jaw\n tools.ball(jaw, 0.026, belly, 0, 0, 0.035, 1.1, 0.35, 1.5)\n tools.eyes(head, 0.006, 0.03, 0.04, 0.045)\n rig.tongue = addMesh(THREE, head, new THREE.BoxGeometry(0.004, 0.002, 0.05), tools.material(0xb02020), 0, 0.024, 0.1)\n return rig\n}\n","import type { AnimalVisualState } from '@adatechnology/game-animals'\nimport type * as THREE_NS from 'three'\n\nimport type { AnimalRig, Three } from './types'\n\nconst INFECTED_TINT = 0x7d8a66\nconst POOL_COLOR = 0x3a0806\n\n/**\n * Applies a visual state (page: `setInfected`, with the dead look for every species): infected greys the coat, glows the eyes, shows the wounds and hides\n * the first ear; dead lets the animation lay the body down and shows a blood pool at `home`. The pool goes under `rig.root.parent`; with no parent yet,\n * it is created hidden from the scene and `rig.pool` is for the caller to add.\n */\nexport const applyVisualState = (THREE: Three, rig: AnimalRig, state: AnimalVisualState): void => {\n rig.infected = state === 'infected'\n rig.dead = state === 'dead'\n const tint = new THREE.Color(INFECTED_TINT)\n rig.materials.forEach((material) => {\n if (material === rig.eyeMaterial || material === rig.woundMaterial) return\n material.color.copy(material.userData.base as THREE_NS.Color)\n if (rig.infected) material.color.lerp(tint, 0.45).multiplyScalar(0.72)\n })\n const eye = rig.eyeMaterial\n if (eye) {\n if (rig.infected) {\n eye.color.set(0xdcd8b0)\n eye.emissive = new THREE.Color(0x8a8660)\n eye.emissiveIntensity = 0.8\n } else {\n eye.color.copy(eye.userData.base as THREE_NS.Color)\n eye.emissive = new THREE.Color(0)\n }\n }\n rig.infectionParts.forEach((part) => (part.visible = rig.infected))\n const firstEar = rig.ears[0]\n if (firstEar) firstEar.visible = !rig.infected\n if (!rig.dead) {\n rig.root.rotation.z = 0\n rig.root.position.y = 0\n }\n if (rig.pool) {\n rig.pool.visible = rig.dead\n return\n }\n if (!rig.dead) return\n const pool = new THREE.Mesh(new THREE.CircleGeometry(1, 22).rotateX(-Math.PI / 2), new THREE.MeshStandardMaterial({ color: POOL_COLOR, roughness: 0.25 }))\n pool.position.set(rig.home.x, 0.005, rig.home.z + 0.1)\n pool.receiveShadow = true\n pool.scale.setScalar(rig.size * 0.45)\n rig.root.parent?.add(pool)\n rig.pool = pool\n}\n","import type * as THREE_NS from 'three'\n\nimport type { AnimalRig } from './types'\n\n/** The \"joints\" view (page: `setJoint`): the coat turns see-through and every joint ball shows in `jointMaterial`. */\nexport const setJointView = (rig: AnimalRig, on: boolean, jointMaterial: THREE_NS.Material): void => {\n rig.materials.forEach((material) => {\n if (material === rig.eyeMaterial) return\n material.transparent = on\n material.opacity = on ? 0.28 : 1\n material.depthWrite = !on\n material.needsUpdate = true\n })\n rig.joints.forEach((joint) => {\n if (on) joint.userData.restMaterial ??= joint.material\n joint.material = on ? jointMaterial : (joint.userData.restMaterial as THREE_NS.Material)\n joint.renderOrder = on ? 2 : 0\n })\n}\n\n/** The \"split\" view (page: `setSplit`): sets where each pivot should go, the rest position or the rest plus its offset; `updateSplit` moves it there. */\nexport const setSplit = (rig: AnimalRig, on: boolean): void => {\n rig.pivots.forEach((pivot) => {\n pivot.group.userData.target = on ? pivot.rest.clone().add(pivot.offset) : pivot.rest.clone()\n })\n}\n\n/** Moves each pivot toward its split target (the page does it in the frame loop: a lerp of 5 per second). */\nexport const updateSplit = (rig: AnimalRig, delta: number): void => {\n rig.pivots.forEach((pivot) => {\n const target = pivot.group.userData.target as THREE_NS.Vector3 | undefined\n if (target) pivot.group.position.lerp(target, Math.min(1, delta * 5))\n })\n}\n","import { lineUpLength } from '@adatechnology/game-animals'\n\nimport type { AnimalRig } from './types'\n\nexport type LineUpOptions = {\n /** X where the row starts (page: -19). */\n readonly start?: number\n /** Gap between animals (page: 0.85). */\n readonly gap?: number\n /** Heading of the animals, radians (page: 1.1; snakes 2.2). */\n readonly yaw?: number\n readonly snakeYaw?: number\n}\n\n/** Puts the animals in a row on the x axis, each given room by its length, the row centred on the origin, and keeps each place as `home` (page: the line-up). */\nexport const lineUpAnimals = (rigs: readonly AnimalRig[], options: LineUpOptions = {}): void => {\n const start = options.start ?? -19\n const gap = options.gap ?? 0.85\n let cursor = start\n for (const rig of rigs) {\n const length = lineUpLength(rig.species.body)\n cursor += length / 2\n rig.root.position.set(cursor, 0, 0)\n rig.home = rig.root.position.clone()\n rig.root.rotation.y = rig.species.body.kind === 'snake' ? (options.snakeYaw ?? 2.2) : (options.yaw ?? 1.1)\n cursor += length / 2 + gap\n }\n const offset = -(cursor - gap + start) / 2\n for (const rig of rigs) {\n rig.root.position.x += offset\n rig.home.x += offset\n }\n}\n","import { visualStateOf } from '@adatechnology/game-animals'\nimport type { AnimalSpecies } from '@adatechnology/game-animals'\nimport type { ModuleScenario } from '@adatechnology/game-contracts'\n\nimport type { AnimalsThree } from '../index'\nimport type { OutbreakLike } from './types'\n\n/** What a scenario needs of the room: the pass/fail line and time. The test room's `ScenarioContext` has both. */\nexport type AnimalsContext = { expect(condition: boolean, label: string, data?: Record<string, unknown>): void; step(seconds: number): void }\n\nexport type ScenarioDeps = {\n readonly text: Readonly<Record<string, string>>\n species(): readonly AnimalSpecies[]\n ensure(): AnimalsThree\n outbreak(): OutbreakLike | null\n rebuildOutbreak(enabled: boolean): OutbreakLike | null\n skins(): { count: number; meshes: { drawCalls: number; triangles: number }; nodes: number; rich: number }\n clearSkins(): void\n}\n\nconst SKIN_COUNT = 40\n\nexport const createScenarios = (deps: ScenarioDeps): ModuleScenario<AnimalsContext>[] => {\n const scenario = (id: string, run: ModuleScenario<AnimalsContext>['run']): ModuleScenario<AnimalsContext> => ({ id, name: deps.text[id] ?? id, run })\n const rate = () => 0.5\n return [\n scenario('visual_states', ({ expect }) => {\n const animals = deps.ensure()\n for (const species of deps.species()) {\n const rig = animals.build(species)\n animals.setVisualState(rig, 'infected')\n expect(rig.infected && !rig.dead, `${species.id}: infected`)\n animals.setVisualState(rig, 'dead')\n expect(rig.dead && !rig.infected, `${species.id}: dead`)\n animals.setVisualState(rig, 'alive')\n expect(!rig.dead && !rig.infected, `${species.id}: alive again`)\n }\n }),\n scenario('gait_moves_legs', ({ expect }) => {\n const animals = deps.ensure()\n const species = deps.species().find((entry) => entry.body.kind === 'quadruped')\n if (!species) return expect(false, 'no quadruped among the species')\n const rig = animals.build(species)\n animals.animate(rig, { time: 0, delta: 0, clip: 'walk' })\n const before = rig.legs.map((leg) => leg.hip.rotation.x)\n animals.animate(rig, { time: 0.4, delta: 0.4, clip: 'walk' })\n expect(rig.legs.some((leg, index) => leg.hip.rotation.x !== before[index]), `${species.id}: a walk step swings a hip`)\n }),\n scenario('outbreak_rule', ({ expect }) => {\n const turns = deps.species().find((entry) => entry.outcome === 'turns')\n const immune = deps.species().find((entry) => entry.outcome === 'immune')\n const on = deps.rebuildOutbreak(true)\n if (!on || !turns) return expect(false, 'no outbreak rule or no species that turns')\n expect(on.bite(turns.id, rate, 0) !== undefined, `a bite on ${turns.id} starts a fate with the rule on`)\n if (immune) expect(on.bite(immune.id, rate, 0) === undefined, `${immune.id} shrugs the bite off`)\n const off = deps.rebuildOutbreak(false)\n expect(off?.bite(turns.id, rate, 0) === undefined, 'with the rule off a bite does nothing')\n deps.rebuildOutbreak(true)\n }),\n scenario('carcass_lure', ({ expect }) => {\n const outbreak = deps.rebuildOutbreak(true)\n const dies = deps.species().find((entry) => entry.outbreak?.carcass)\n if (!outbreak || !dies) return expect(false, 'no outbreak rule or no species that leaves a carcass')\n const carcass = outbreak.carcass(dies.id, [0, 0, 0], 0)\n expect(carcass !== undefined, `${dies.id} leaves a carcass`)\n if (!carcass) return\n expect(outbreak.lures(carcass, carcass.lureRadiusMetres - 1, 1), 'a zombie inside the radius is drawn')\n expect(!outbreak.lures(carcass, carcass.lureRadiusMetres + 1, 1), 'a zombie outside it is not')\n }),\n scenario('bite_to_turn_timer', ({ expect }) => {\n const outbreak = deps.rebuildOutbreak(true)\n const turns = deps.species().find((entry) => entry.outcome === 'turns')\n if (!outbreak || !turns) return expect(false, 'no outbreak rule or no species that turns')\n const fate = outbreak.bite(turns.id, rate, 0)\n if (!fate) return expect(false, 'the bite took')\n expect(outbreak.stateOf(fate, 0) === 'incubating', 'it incubates at first')\n expect(outbreak.stateOf(fate, fate.dueAt + 1) === 'turned', 'it has turned once the time is up (the bench clock runs it accelerated)')\n expect(visualStateOf(turns.outcome, true) === 'infected', 'and shows the infected look')\n }),\n scenario('skins_40', ({ expect }) => {\n const result = deps.skins()\n expect(result.count === SKIN_COUNT, `${SKIN_COUNT} animals are in the field`, { count: result.count })\n expect(result.meshes.drawCalls <= SKIN_COUNT + 16, 'the skins are about one draw call each', result.meshes)\n expect(result.nodes > 0, 'each skin keeps the nodes the animation moves', { nodes: result.nodes })\n deps.clearSkins()\n }),\n ]\n}\n","export type AnimalsText = {\n group: string\n name: string\n controls: Record<'visual_state' | 'gait' | 'speed' | 'outbreak' | 'time_scale', string>\n hints: Record<'visual_state' | 'gait' | 'outbreak' | 'time_scale', string>\n options: { visual_state: Record<string, string>; gait: Record<string, string> }\n actions: Record<'bite_all' | 'recover' | 'skin_40' | 'clear_skins', string>\n layers: Record<'joints' | 'split' | 'sound_range' | 'carcass_lure', string>\n metrics: Record<'animals' | 'draw_calls' | 'triangles' | 'nodes_per_skin' | 'incubating' | 'turned' | 'dead', string>\n scenarios: Record<string, string>\n}\n\nexport const TEXT: Record<string, AnimalsText> = {\n en: {\n group: 'Animals',\n name: 'Animals area',\n controls: { visual_state: 'Visual state', gait: 'Gait', speed: 'Animation speed', outbreak: 'Outbreak rule', time_scale: 'Bite clock' },\n hints: {\n visual_state: 'The look of every animal: alive, infected (grey coat, glowing eyes, wounds) or dead (lying down, a pool of blood)',\n gait: 'idle, walk or run; the cycle of each species runs at its own rate',\n outbreak: 'Off: a bite does nothing. On: a species that turns incubates and turns, one that dies dies, the rest shrug it off',\n time_scale: 'Game seconds per real second for the bite timers (60: ten minutes pass in ten seconds)',\n },\n options: { visual_state: { alive: 'Alive', infected: 'Infected', dead: 'Dead' }, gait: { idle: 'Idle', walk: 'Walk', run: 'Run' } },\n actions: { bite_all: 'Bite every animal', recover: 'Heal every animal', skin_40: 'Add 40 animals as node skins', clear_skins: 'Remove the skins' },\n layers: { joints: 'Joints', split: 'Split view', sound_range: 'Sound range', carcass_lure: 'Carcass lure radius' },\n metrics: { animals: 'Animals', draw_calls: 'Draw calls', triangles: 'Triangles', nodes_per_skin: 'Nodes per skin', incubating: 'Incubating', turned: 'Turned', dead: 'Dead' },\n scenarios: {\n visual_states: 'Alive, infected and dead for every species',\n gait_moves_legs: 'The gait moves the legs',\n outbreak_rule: 'Outbreak rule on and off',\n carcass_lure: 'A carcass lures zombies within its radius',\n bite_to_turn_timer: 'Bite, incubation, turn (accelerated)',\n skins_40: '40 animals as node skins',\n },\n },\n 'pt-BR': {\n group: 'Animais',\n name: 'Área de animais',\n controls: { visual_state: 'Estado visual', gait: 'Andar', speed: 'Velocidade da animação', outbreak: 'Regra de surto', time_scale: 'Relógio da mordida' },\n hints: {\n visual_state: 'O aspecto de todos os bichos: vivo, infectado (pelo cinza, olhos brilhando, feridas) ou morto (deitado, poça de sangue)',\n gait: 'idle, walk ou run; o ciclo de cada espécie anda no seu ritmo',\n outbreak: 'Desligada: a mordida não faz nada. Ligada: a espécie que vira incuba e vira, a que morre morre, as outras não sentem',\n time_scale: 'Segundos de jogo por segundo real nos prazos da mordida (60: dez minutos passam em dez segundos)',\n },\n options: { visual_state: { alive: 'Vivo', infected: 'Infectado', dead: 'Morto' }, gait: { idle: 'Parado', walk: 'Andando', run: 'Correndo' } },\n actions: { bite_all: 'Morder todos os bichos', recover: 'Curar todos os bichos', skin_40: 'Pôr 40 bichos como pele de nós', clear_skins: 'Tirar as peles' },\n layers: { joints: 'Juntas', split: 'Vista aberta', sound_range: 'Alcance do som', carcass_lure: 'Raio de atração da carcaça' },\n metrics: { animals: 'Bichos', draw_calls: 'Chamadas de desenho', triangles: 'Triângulos', nodes_per_skin: 'Nós por pele', incubating: 'Incubando', turned: 'Viraram', dead: 'Morreram' },\n scenarios: {\n visual_states: 'Vivo, infectado e morto em cada espécie',\n gait_moves_legs: 'O andar mexe as pernas',\n outbreak_rule: 'Regra de surto ligada e desligada',\n carcass_lure: 'A carcaça atrai zumbis dentro do raio',\n bite_to_turn_timer: 'Mordida, incubação, vira (acelerado)',\n skins_40: '40 bichos como pele de nós',\n },\n },\n}\n","import { lineUpLength, visualStateOf } from '@adatechnology/game-animals'\nimport type { AnimalSpecies, AnimalVisualState } from '@adatechnology/game-animals'\nimport type { BenchChange, ModuleArea, ModuleControl, ModuleHost, ModuleLayer, ModuleMetric, ModuleScenario, TestableItem, TestableModule } from '@adatechnology/game-contracts'\nimport type { NodeSkin } from '@adatechnology/game-props3d'\nimport type * as THREE_NS from 'three'\n\nimport { createAnimalsThree } from '../index'\nimport type { AnimalsThree } from '../index'\nimport type { AnimalRig, Three } from '../types'\nimport { createScenarios } from './scenarios'\nimport type { AnimalsContext, ScenarioDeps } from './scenarios'\nimport { TEXT } from './text'\nimport type { AnimalsTestOptions, OutbreakLike } from './types'\n\nexport const ANIMALS_AREA_ID = 'animals_area'\nexport const ANIMAL_ITEM_PREFIX = 'animal_'\nconst SKIN_COUNT = 40\nconst SKIN_FIELD = { x0: -18, z0: -10, columns: 8, gap: 4.5 }\nconst DEFAULT_TIME_SCALE = 60\n\ntype Fate = NonNullable<ReturnType<OutbreakLike['bite']>>\ntype Placed = { readonly id: string; readonly rig: AnimalRig; fate?: Fate; counted?: 'turned' | 'dead' }\n\n/**\n * The animals test area as a `TestableModule`: the species of the pack in a row, each drawn by the Bichos do Vale builders, with the alive / infected / dead looks, the gait,\n * the joints and split views, the rings for how far its sound carries and how far a carcass lures, the outbreak rule with an accelerated bite clock, and a field of 40 animals\n * drawn as node skins. The species and the outbreak rule come in by option, so this package knows no game.\n */\nexport function createAnimalsTestModule(options: AnimalsTestOptions = {}): TestableModule<AnimalsContext> & { readonly placed: ReadonlyMap<string, unknown> } {\n const locale = options.locale ?? 'pt-BR'\n const text = TEXT[locale] ?? (TEXT['pt-BR'] as (typeof TEXT)[string])\n const species = options.species ?? []\n const settings = { visual: 'alive' as AnimalVisualState, gait: 'walk', speed: 1, outbreak: true, timeScale: DEFAULT_TIME_SCALE }\n let three: Three | null = null\n let animals: AnimalsThree | null = null\n let host: ModuleHost | null = null\n let outbreak: OutbreakLike | null = null\n let time = 0\n let clock = 0\n let skinGroup: THREE_NS.Group | null = null\n let skins: { rig: AnimalRig; skin: NodeSkin }[] = []\n let rings: THREE_NS.Object3D[] = []\n const placed = new Map<string, Placed>()\n const random = (): number => 0.5\n const drawSeed = options.seed ?? 7\n const bitten = () => ({ turned: [...placed.values()].filter((p) => p.counted === 'turned').length, dead: [...placed.values()].filter((p) => p.counted === 'dead').length })\n\n const ensure = (THREE: Three): AnimalsThree => {\n three = THREE\n animals ??= createAnimalsThree(THREE, { seed: drawSeed, ...(options.document ? { document: options.document } : {}) })\n return animals\n }\n const rebuildOutbreak = (): void => {\n outbreak = options.createOutbreak ? options.createOutbreak({ species, enabled: settings.outbreak, timeScale: settings.timeScale }) : null\n }\n rebuildOutbreak()\n\n const item = (animal: AnimalSpecies): TestableItem => ({\n id: `${ANIMAL_ITEM_PREFIX}${animal.id}`,\n name: animal.name[locale as 'en'] ?? animal.id,\n movable: false,\n build: (THREE: unknown) => {\n const rig = ensure(THREE as Three).build(animal)\n // the room puts the tree in its scene right after this; trees that never reach it are dropped at the next frame\n placed.set(rig.root.uuid, { id: rig.root.uuid, rig })\n if (settings.visual !== 'alive') animals?.setVisualState(rig, settings.visual)\n return rig.root\n },\n })\n\n const statusOf = (entry: Placed): void => {\n if (!entry.fate || !outbreak) return\n const state = outbreak.stateOf(entry.fate, clock)\n if (state === 'incubating') return\n entry.counted = state === 'turned' ? 'turned' : 'dead'\n animals?.setVisualState(entry.rig, visualStateOf(entry.rig.species.outcome, true, state === 'dead'))\n }\n\n const clearRings = (): void => {\n for (const ring of rings) ring.parent?.remove(ring)\n rings = []\n }\n const refreshLayers = (): void => {\n if (!host?.bench || !animals || !three) return\n clearRings()\n for (const entry of placed.values()) {\n animals.setJointView(entry.rig, host.bench.layer('joints'))\n animals.setSplit(entry.rig, host.bench.layer('split'))\n }\n const ring = (radius: number, color: number, parent: THREE_NS.Object3D): void => {\n const mesh = new (three as Three).Mesh(new (three as Three).RingGeometry(radius - 0.15, radius, 96).rotateX(-Math.PI / 2), new (three as Three).MeshBasicMaterial({ color, transparent: true, opacity: 0.55, depthWrite: false }))\n mesh.position.y = 0.03\n parent.add(mesh)\n rings.push(mesh)\n }\n for (const entry of placed.values()) {\n if (!entry.rig.root.parent) continue\n const radius = entry.rig.species.soundRangeMetres\n if (host.bench.layer('sound_range') && radius) ring(radius, 0x44aaff, entry.rig.root)\n const lure = entry.rig.species.outbreak?.carcass?.lureRadiusMetres\n if (host.bench.layer('carcass_lure') && lure) ring(lure, 0xff5533, entry.rig.root)\n }\n }\n\n const addSkins = (): void => {\n if (!animals || !three || !host) return\n skinGroup ??= new three.Group()\n if (!skinGroup.parent) (host.scene as THREE_NS.Object3D).add(skinGroup)\n for (let index = skins.length; index < SKIN_COUNT; index++) {\n const animal = species[index % Math.max(1, species.length)] as AnimalSpecies\n const rig = animals.build(animal)\n const skin = animals.createSkin(rig)\n rig.root.position.set(SKIN_FIELD.x0 + (index % SKIN_FIELD.columns) * SKIN_FIELD.gap, 0, SKIN_FIELD.z0 - Math.floor(index / SKIN_FIELD.columns) * SKIN_FIELD.gap)\n // the tree still drives the animation, but only the skin is drawn\n rig.root.traverse((object) => {\n if ((object as THREE_NS.Mesh).isMesh) object.visible = false\n })\n skinGroup.add(rig.root, skin.mesh)\n skins.push({ rig, skin })\n }\n }\n const clearSkins = (): void => {\n skinGroup?.parent?.remove(skinGroup)\n skinGroup = null\n skins = []\n }\n\n const applyVisual = (): void => {\n for (const entry of placed.values()) {\n if (entry.fate) continue\n animals?.setVisualState(entry.rig, settings.visual)\n }\n }\n\n const onChange = (change: BenchChange): void => {\n if (change.kind === 'layer') return refreshLayers()\n if (change.kind === 'action') {\n if (change.id === 'bite_all') {\n for (const entry of placed.values()) {\n entry.fate = outbreak?.bite(entry.rig.species.id, random, clock)\n if (entry.fate) animals?.setVisualState(entry.rig, visualStateOf(entry.rig.species.outcome, true))\n }\n } else if (change.id === 'recover') {\n for (const entry of placed.values()) {\n delete entry.fate\n delete entry.counted\n animals?.setVisualState(entry.rig, settings.visual)\n }\n } else if (change.id === 'skin_40') addSkins()\n else if (change.id === 'clear_skins') clearSkins()\n return\n }\n switch (change.id) {\n case 'visual_state': settings.visual = String(change.value) as AnimalVisualState; applyVisual(); break\n case 'gait': settings.gait = String(change.value); break\n case 'speed': settings.speed = Number(change.value); break\n case 'outbreak': settings.outbreak = Boolean(change.value); if (outbreak) outbreak.enabled = settings.outbreak; break\n case 'time_scale': settings.timeScale = Number(change.value); rebuildOutbreak(); break\n default: break\n }\n }\n\n const frame = (dt: number): void => {\n time += dt * settings.speed\n clock += dt\n for (const [id, entry] of placed) {\n if (!entry.rig.root.parent) {\n placed.delete(id)\n continue\n }\n statusOf(entry)\n animals?.animate(entry.rig, { time, delta: dt * settings.speed, clip: settings.gait, split: host?.bench?.layer('split') ?? false })\n animals?.updateSplit(entry.rig, dt)\n }\n for (const { rig, skin } of skins) {\n animals?.animate(rig, { time, delta: dt * settings.speed, clip: settings.gait })\n rig.root.updateMatrixWorld(true)\n skin.update()\n }\n }\n\n const countMeshes = (only?: 'skins'): { drawCalls: number; triangles: number } => {\n let drawCalls = 0\n let triangles = 0\n const count = (root: THREE_NS.Object3D): void =>\n root.traverse((object) => {\n const mesh = object as THREE_NS.Mesh\n if (!mesh.isMesh || !mesh.visible) return\n drawCalls += 1\n const geometry = mesh.geometry\n triangles += geometry.index ? geometry.index.count / 3 : geometry.attributes.position.count / 3\n })\n if (only !== 'skins') for (const entry of placed.values()) count(entry.rig.root)\n for (const { skin } of skins) count(skin.mesh)\n return { drawCalls, triangles: Math.round(triangles) }\n }\n\n const deps: ScenarioDeps = {\n text: text.scenarios,\n species: () => species,\n ensure: () => ensure((three ?? host?.THREE) as Three),\n outbreak: () => outbreak,\n rebuildOutbreak: (enabled) => {\n settings.outbreak = enabled\n rebuildOutbreak()\n return outbreak\n },\n skins: () => {\n ensure((three ?? host?.THREE) as Three)\n addSkins()\n return { count: skins.length, meshes: countMeshes('skins'), nodes: skins[0]?.skin.nodes.length ?? 0, rich: skins[0]?.rig.triangles ?? 0 }\n },\n clearSkins,\n }\n\n return {\n id: ANIMALS_AREA_ID,\n name: text.name,\n group: text.group,\n get placed() {\n return placed\n },\n items: () => species.map(item),\n area: (): ModuleArea => {\n // the page's line-up: each animal given room by its length (and a gap), the row centred on the origin\n const gap = 0.85\n let cursor = 0\n const spots = species.map((animal) => {\n const length = lineUpLength(animal.body)\n const x = cursor + length / 2\n cursor += length + gap\n return { animal, x }\n })\n const offset = -(cursor - gap) / 2\n return {\n placements: spots.map(({ animal, x }) => ({ item: `${ANIMAL_ITEM_PREFIX}${animal.id}`, position: [x + offset, 0, 0], rotationY: animal.body.kind === 'snake' ? 2.2 : 1.1 })),\n view: { eye: [0, 4, Math.max(10, (cursor - gap) * 0.55)], target: [0, 0.6, 0] },\n }\n },\n controls: (): ModuleControl[] => [\n { kind: 'choice', id: 'visual_state', name: text.controls.visual_state, hint: text.hints.visual_state, options: (['alive', 'infected', 'dead'] as const).map((id) => ({ id, name: text.options.visual_state[id] as string })), default: 'alive' },\n { kind: 'choice', id: 'gait', name: text.controls.gait, hint: text.hints.gait, options: (['idle', 'walk', 'run'] as const).map((id) => ({ id, name: text.options.gait[id] as string })), default: 'walk' },\n { kind: 'number', id: 'speed', name: text.controls.speed, min: 0, max: 4, step: 0.25, default: 1 },\n { kind: 'boolean', id: 'outbreak', name: text.controls.outbreak, hint: text.hints.outbreak, default: true },\n { kind: 'number', id: 'time_scale', name: text.controls.time_scale, hint: text.hints.time_scale, min: 1, max: 600, step: 1, default: DEFAULT_TIME_SCALE },\n { kind: 'action', id: 'bite_all', name: text.actions.bite_all },\n { kind: 'action', id: 'recover', name: text.actions.recover },\n { kind: 'action', id: 'skin_40', name: text.actions.skin_40 },\n { kind: 'action', id: 'clear_skins', name: text.actions.clear_skins },\n ],\n layers: (): ModuleLayer[] => (['joints', 'split', 'sound_range', 'carcass_lure'] as const).map((id) => ({ id, name: text.layers[id], default: false })),\n metrics: (): ModuleMetric[] => [\n { id: 'animals', name: text.metrics.animals, read: () => placed.size + skins.length },\n { id: 'draw_calls', name: text.metrics.draw_calls, read: () => countMeshes().drawCalls },\n { id: 'triangles', name: text.metrics.triangles, read: () => countMeshes().triangles },\n { id: 'nodes_per_skin', name: text.metrics.nodes_per_skin, read: () => skins[0]?.skin.nodes.length ?? 0 },\n { id: 'incubating', name: text.metrics.incubating, read: () => [...placed.values()].filter((p) => p.fate && !p.counted).length },\n { id: 'turned', name: text.metrics.turned, read: () => bitten().turned },\n { id: 'dead', name: text.metrics.dead, read: () => bitten().dead },\n ],\n scenarios: (): ModuleScenario<AnimalsContext>[] => createScenarios(deps),\n attach(lent) {\n host = lent\n ensure(lent.THREE as Three)\n const stopChange = lent.bench?.onChange(onChange)\n const stopFrame = lent.onFrame(frame)\n return () => {\n stopChange?.()\n stopFrame()\n clearRings()\n clearSkins()\n host = null\n }\n },\n }\n\n}\n"],"mappings":"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","names":["mesh","material","geometry","PI","PI","document","SKIN_COUNT"]}
|