scena3d 0.1.0 → 0.3.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/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/core/random.ts","../src/core/palette.ts","../src/core/types.ts","../src/props/tree.ts","../src/props/rock.ts","../src/props/crate.ts","../src/props/fence.ts","../src/props/lamp.ts","../src/environment/terrain.ts","../src/environment/sky.ts","../src/environment/lighting.ts","../src/scatter/scatter.ts"],"sourcesContent":["/**\n * Deterministic seeded randomness — the backbone of SCENA. Same seed,\n * same tree; forests are reproducible, diffable and network-syncable.\n */\nexport class Rng {\n private state: number;\n\n constructor(seed = 1) {\n this.state = seed >>> 0 || 1;\n }\n\n /** Next float in [0, 1) (mulberry32). */\n next(): number {\n this.state = (this.state + 0x6d2b79f5) >>> 0;\n let t = this.state;\n t = Math.imul(t ^ (t >>> 15), t | 1);\n t ^= t + Math.imul(t ^ (t >>> 7), t | 61);\n return ((t ^ (t >>> 14)) >>> 0) / 4294967296;\n }\n\n /** Float in [min, max). */\n range(min: number, max: number): number {\n return min + this.next() * (max - min);\n }\n\n /** Integer in [min, max] inclusive. */\n int(min: number, max: number): number {\n return min + Math.floor(this.next() * (max - min + 1));\n }\n\n /** Random element of a non-empty array. */\n pick<T>(items: readonly T[]): T {\n return items[Math.floor(this.next() * items.length)];\n }\n\n /** value ± spread (uniform). */\n jitter(value: number, spread: number): number {\n return value + (this.next() * 2 - 1) * spread;\n }\n\n /** A new independent Rng derived from this one. */\n fork(): Rng {\n return new Rng(Math.floor(this.next() * 0xffffffff) || 1);\n }\n}\n\n/** Integer-lattice hash to [0, 1) — the base of the value noise. */\nexport function hash2(ix: number, iz: number, seed: number): number {\n let h = (ix * 374761393 + iz * 668265263 + seed * 2246822519) >>> 0;\n h = Math.imul(h ^ (h >>> 13), 1274126177) >>> 0;\n return ((h ^ (h >>> 16)) >>> 0) / 4294967296;\n}\n\nconst smooth = (t: number): number => t * t * (3 - 2 * t);\n\n/** 2D value noise in [0, 1). Continuous; used by terrain and scatter density. */\nexport function valueNoise2(x: number, z: number, seed: number): number {\n const ix = Math.floor(x);\n const iz = Math.floor(z);\n const fx = smooth(x - ix);\n const fz = smooth(z - iz);\n const a = hash2(ix, iz, seed);\n const b = hash2(ix + 1, iz, seed);\n const c = hash2(ix, iz + 1, seed);\n const d = hash2(ix + 1, iz + 1, seed);\n return a + (b - a) * fx + (c - a) * fz + (a - b - c + d) * fx * fz;\n}\n\n/** Fractal (octaved) value noise in [0, 1). */\nexport function fractalNoise2(\n x: number,\n z: number,\n seed: number,\n octaves = 4,\n lacunarity = 2,\n gain = 0.5\n): number {\n let amplitude = 1;\n let frequency = 1;\n let sum = 0;\n let total = 0;\n for (let i = 0; i < octaves; i++) {\n sum += valueNoise2(x * frequency, z * frequency, seed + i * 101) * amplitude;\n total += amplitude;\n amplitude *= gain;\n frequency *= lacunarity;\n }\n return sum / total;\n}\n","/**\n * Theme palettes: one coherent set of colors shared by every generator,\n * so procedural props look like a matched set rather than a junk drawer.\n * Pass `palette` to any generator to restyle it; whole scenes retheme by\n * building with a different palette.\n */\nexport interface Palette {\n foliage: number[];\n trunk: number;\n rock: number[];\n wood: number;\n woodDark: number;\n metal: number;\n lampGlow: number;\n grassLow: number;\n grassHigh: number;\n cliff: number;\n peak: number;\n skyTop: number;\n skyBottom: number;\n fog: number;\n}\n\nexport const PALETTES: Record<'meadow' | 'autumn' | 'dusk', Palette> = {\n meadow: {\n foliage: [0x2f9e57, 0x37b26a, 0x2a8f4f, 0x45b878],\n trunk: 0x6b4a33,\n rock: [0x8a8f98, 0x767c86, 0x9aa0a8],\n wood: 0x8a6642,\n woodDark: 0x6b4a33,\n metal: 0x3d4451,\n lampGlow: 0xffd889,\n grassLow: 0x3f9d5a,\n grassHigh: 0x6fae66,\n cliff: 0x7d7a72,\n peak: 0xe8ecef,\n skyTop: 0x3d70b8,\n skyBottom: 0xbfd9e8,\n fog: 0xb8cfdd,\n },\n autumn: {\n foliage: [0xc9752f, 0xd98e3a, 0xb35c2a, 0xe0a545],\n trunk: 0x5d4030,\n rock: [0x8d8578, 0x776f63, 0x9c948a],\n wood: 0x7d5a3a,\n woodDark: 0x5d4030,\n metal: 0x463f3a,\n lampGlow: 0xffc571,\n grassLow: 0x9d8a3f,\n grassHigh: 0xb59b4a,\n cliff: 0x82746a,\n peak: 0xe3ded4,\n skyTop: 0x8e6ca8,\n skyBottom: 0xe8c9a8,\n fog: 0xd9c1a8,\n },\n dusk: {\n foliage: [0x1f5e46, 0x24684f, 0x1a5240, 0x2d7458],\n trunk: 0x413147,\n rock: [0x565672, 0x484861, 0x646484],\n wood: 0x5d4a63,\n woodDark: 0x413147,\n metal: 0x2b2b3d,\n lampGlow: 0xffb35c,\n grassLow: 0x2d6b52,\n grassHigh: 0x3d7a5e,\n cliff: 0x52516b,\n peak: 0xb8b8d9,\n skyTop: 0x1d2145,\n skyBottom: 0xc96a4a,\n fog: 0x6a5a7a,\n },\n};\n\nexport const DEFAULT_PALETTE: Palette = PALETTES.meadow;\n","import { Vector3, type Group, type Object3D } from 'three';\n\n/**\n * A steering obstacle in world space — structurally identical to GAMA's\n * `Obstacle`, so SCENA props plug straight into `ObstacleAvoidance`\n * without either library importing the other.\n */\nexport interface Obstacle {\n center: Vector3;\n radius: number;\n}\n\n/** What a prop generator returns: the visual plus gameplay metadata. */\nexport interface Prop {\n object: Group;\n /**\n * Footprint radius for steering/placement, in the prop's local space\n * (centered at its origin). 0 means walk-through (e.g. grass).\n */\n obstacleRadius: number;\n}\n\n/** Collect world-space obstacles from placed props (call after positioning). */\nexport function collectObstacles(props: Iterable<Prop>): Obstacle[] {\n const obstacles: Obstacle[] = [];\n for (const prop of props) {\n if (prop.obstacleRadius <= 0) continue;\n prop.object.updateWorldMatrix(true, false);\n obstacles.push({\n center: prop.object.getWorldPosition(new Vector3()),\n radius: prop.obstacleRadius * maxScale(prop.object),\n });\n }\n return obstacles;\n}\n\nfunction maxScale(object: Object3D): number {\n return Math.max(object.scale.x, object.scale.z);\n}\n","import {\n ConeGeometry,\n CylinderGeometry,\n Group,\n IcosahedronGeometry,\n Mesh,\n MeshStandardMaterial,\n} from 'three';\nimport { Rng } from '../core/random';\nimport { DEFAULT_PALETTE, type Palette } from '../core/palette';\nimport type { Prop } from '../core/types';\n\nexport interface TreeOptions {\n seed?: number;\n /** Overall height in world units. Default ~3.5–5 by seed. */\n height?: number;\n style?: 'pine' | 'oak';\n palette?: Palette;\n}\n\n/**\n * A seeded low-poly tree. `pine` stacks cones; `oak` clusters foliage\n * blobs on a forked trunk. Same seed → identical tree, forever.\n */\nexport function createTree(options: TreeOptions = {}): Prop {\n const rng = new Rng(options.seed ?? 1);\n const palette = options.palette ?? DEFAULT_PALETTE;\n const style = options.style ?? (rng.next() < 0.6 ? 'pine' : 'oak');\n const height = options.height ?? rng.range(3.2, 5.2);\n const group = new Group();\n group.name = `tree-${style}`;\n\n const trunkMaterial = new MeshStandardMaterial({ color: palette.trunk, flatShading: true });\n const foliageMaterial = new MeshStandardMaterial({\n color: rng.pick(palette.foliage),\n flatShading: true,\n });\n\n if (style === 'pine') {\n const trunkHeight = height * 0.25;\n const trunk = new Mesh(new CylinderGeometry(0.09, 0.14, trunkHeight, 6), trunkMaterial);\n trunk.position.y = trunkHeight / 2;\n group.add(trunk);\n\n const tiers = rng.int(3, 4);\n let y = trunkHeight;\n let radius = height * rng.range(0.24, 0.3);\n const tierHeight = (height - trunkHeight) / tiers + 0.15;\n for (let i = 0; i < tiers; i++) {\n const cone = new Mesh(new ConeGeometry(radius, tierHeight * 1.35, 7), foliageMaterial);\n cone.position.y = y + tierHeight * 0.55;\n cone.rotation.y = rng.range(0, Math.PI);\n group.add(cone);\n y += tierHeight * 0.8;\n radius *= 0.72;\n }\n } else {\n const trunkHeight = height * 0.45;\n const trunk = new Mesh(new CylinderGeometry(0.12, 0.2, trunkHeight, 6), trunkMaterial);\n trunk.position.y = trunkHeight / 2;\n trunk.rotation.z = rng.range(-0.08, 0.08);\n group.add(trunk);\n\n const blobs = rng.int(2, 4);\n for (let i = 0; i < blobs; i++) {\n const radius = height * rng.range(0.18, 0.28);\n const blob = new Mesh(new IcosahedronGeometry(radius, 0), foliageMaterial);\n blob.position.set(\n rng.jitter(0, height * 0.16),\n trunkHeight + radius * rng.range(0.5, 0.9) + i * radius * 0.35,\n rng.jitter(0, height * 0.16)\n );\n blob.rotation.set(rng.range(0, Math.PI), rng.range(0, Math.PI), 0);\n group.add(blob);\n }\n }\n\n return { object: group, obstacleRadius: style === 'pine' ? 0.5 : 0.6 };\n}\n","import {\n BufferAttribute,\n Group,\n IcosahedronGeometry,\n Mesh,\n MeshStandardMaterial,\n} from 'three';\nimport { Rng } from '../core/random';\nimport { DEFAULT_PALETTE, type Palette } from '../core/palette';\nimport type { Prop } from '../core/types';\n\nexport interface RockOptions {\n seed?: number;\n /** Approximate radius. Default ~0.4–1.1 by seed. */\n size?: number;\n palette?: Palette;\n}\n\n/**\n * A seeded low-poly boulder: an icosahedron with jittered vertices and a\n * flattened underside so it sits on the ground.\n */\nexport function createRock(options: RockOptions = {}): Prop {\n const rng = new Rng(options.seed ?? 1);\n const palette = options.palette ?? DEFAULT_PALETTE;\n const size = options.size ?? rng.range(0.4, 1.1);\n\n const geometry = new IcosahedronGeometry(size, 0);\n const positions = geometry.getAttribute('position') as BufferAttribute;\n // Jitter welded-by-value: identical vertex values get identical offsets,\n // so faces stay connected.\n const seen = new Map<string, [number, number, number]>();\n for (let i = 0; i < positions.count; i++) {\n const key = `${positions.getX(i).toFixed(4)},${positions.getY(i).toFixed(4)},${positions.getZ(i).toFixed(4)}`;\n let offset = seen.get(key);\n if (!offset) {\n offset = [rng.jitter(0, size * 0.22), rng.jitter(0, size * 0.16), rng.jitter(0, size * 0.22)];\n seen.set(key, offset);\n }\n positions.setXYZ(\n i,\n positions.getX(i) + offset[0],\n Math.max(positions.getY(i) + offset[1], -size * 0.15), // flatten the bottom\n positions.getZ(i) + offset[2]\n );\n }\n geometry.computeVertexNormals();\n\n const rock = new Mesh(\n geometry,\n new MeshStandardMaterial({ color: rng.pick(palette.rock), flatShading: true })\n );\n rock.position.y = size * 0.15;\n rock.scale.y = rng.range(0.6, 0.9);\n\n const group = new Group();\n group.name = 'rock';\n group.add(rock);\n return { object: group, obstacleRadius: size * 1.05 };\n}\n","import { BoxGeometry, Group, Mesh, MeshStandardMaterial } from 'three';\nimport { Rng } from '../core/random';\nimport { DEFAULT_PALETTE, type Palette } from '../core/palette';\nimport type { Prop } from '../core/types';\n\nexport interface CrateOptions {\n seed?: number;\n size?: number;\n /** 0–1 color wear. Default 0.3. */\n weathering?: number;\n palette?: Palette;\n}\n\n/** A wooden crate: panel box with darker edge framing, seeded wear tint. */\nexport function createCrate(options: CrateOptions = {}): Prop {\n const rng = new Rng(options.seed ?? 1);\n const palette = options.palette ?? DEFAULT_PALETTE;\n const size = options.size ?? 1;\n const wear = options.weathering ?? 0.3;\n\n const group = new Group();\n group.name = 'crate';\n\n const panelMaterial = new MeshStandardMaterial({ color: palette.wood, flatShading: true });\n panelMaterial.color.offsetHSL(0, 0, -rng.range(0, wear * 0.18));\n const frameMaterial = new MeshStandardMaterial({ color: palette.woodDark, flatShading: true });\n\n const body = new Mesh(new BoxGeometry(size * 0.92, size * 0.92, size * 0.92), panelMaterial);\n body.position.y = size / 2;\n group.add(body);\n\n const beam = size * 0.12;\n const long = size * 1.0;\n for (const y of [beam / 2, size - beam / 2]) {\n for (const [rx, rz, w, d] of [\n [0, size / 2 - beam / 2, long, beam],\n [0, -(size / 2 - beam / 2), long, beam],\n [size / 2 - beam / 2, 0, beam, long],\n [-(size / 2 - beam / 2), 0, beam, long],\n ] as const) {\n const rail = new Mesh(new BoxGeometry(w, beam, d), frameMaterial);\n rail.position.set(rx, y, rz);\n group.add(rail);\n }\n }\n for (const x of [-1, 1]) {\n for (const z of [-1, 1]) {\n const post = new Mesh(new BoxGeometry(beam, size, beam), frameMaterial);\n post.position.set(x * (size / 2 - beam / 2), size / 2, z * (size / 2 - beam / 2));\n group.add(post);\n }\n }\n group.rotation.y = rng.range(0, Math.PI / 2);\n\n return { object: group, obstacleRadius: size * 0.75 };\n}\n","import { BoxGeometry, CylinderGeometry, Group, Mesh, MeshStandardMaterial } from 'three';\nimport { Rng } from '../core/random';\nimport { DEFAULT_PALETTE, type Palette } from '../core/palette';\nimport type { Prop } from '../core/types';\n\nexport interface FenceOptions {\n seed?: number;\n /** Run length along local +x. Default 6. */\n length?: number;\n postSpacing?: number;\n height?: number;\n palette?: Palette;\n}\n\n/**\n * A rustic fence run along local +x, centered at the origin: posts with\n * two slightly-crooked rails. Chain several and rotate to enclose areas.\n * The obstacle radius covers the whole run (rough but steering-safe);\n * for tight navigation, bake a navmesh — the geometry is authoritative.\n */\nexport function createFence(options: FenceOptions = {}): Prop {\n const rng = new Rng(options.seed ?? 1);\n const palette = options.palette ?? DEFAULT_PALETTE;\n const length = options.length ?? 6;\n const spacing = options.postSpacing ?? 1.5;\n const height = options.height ?? 1.1;\n\n const group = new Group();\n group.name = 'fence';\n const postMaterial = new MeshStandardMaterial({ color: palette.woodDark, flatShading: true });\n const railMaterial = new MeshStandardMaterial({ color: palette.wood, flatShading: true });\n\n const posts = Math.max(2, Math.round(length / spacing) + 1);\n const step = length / (posts - 1);\n for (let i = 0; i < posts; i++) {\n const post = new Mesh(new CylinderGeometry(0.06, 0.075, height, 5), postMaterial);\n post.position.set(-length / 2 + i * step, height / 2, rng.jitter(0, 0.03));\n post.rotation.z = rng.range(-0.04, 0.04);\n group.add(post);\n }\n for (const railY of [height * 0.55, height * 0.85]) {\n const rail = new Mesh(new BoxGeometry(length, 0.07, 0.05), railMaterial);\n rail.position.y = rng.jitter(railY, 0.02);\n rail.rotation.x = rng.range(-0.02, 0.02);\n group.add(rail);\n }\n\n return { object: group, obstacleRadius: length / 2 };\n}\n","import {\n BoxGeometry,\n CylinderGeometry,\n Group,\n Mesh,\n MeshStandardMaterial,\n PointLight,\n SphereGeometry,\n} from 'three';\nimport { Rng } from '../core/random';\nimport { DEFAULT_PALETTE, type Palette } from '../core/palette';\nimport type { Prop } from '../core/types';\n\nexport interface LampOptions {\n seed?: number;\n height?: number;\n /** Add a real PointLight. Off by default — lights are a budget. */\n light?: boolean;\n lightIntensity?: number;\n palette?: Palette;\n}\n\n/** A street lamp: post, head, glowing bulb, optional real PointLight. */\nexport function createLamp(options: LampOptions = {}): Prop {\n const rng = new Rng(options.seed ?? 1);\n const palette = options.palette ?? DEFAULT_PALETTE;\n const height = options.height ?? rng.range(2.6, 3.1);\n\n const group = new Group();\n group.name = 'lamp';\n const metal = new MeshStandardMaterial({ color: palette.metal, flatShading: true });\n\n const post = new Mesh(new CylinderGeometry(0.05, 0.08, height, 6), metal);\n post.position.y = height / 2;\n group.add(post);\n\n const head = new Mesh(new BoxGeometry(0.34, 0.26, 0.34), metal);\n head.position.y = height + 0.1;\n group.add(head);\n\n const bulb = new Mesh(\n new SphereGeometry(0.11, 8, 6),\n new MeshStandardMaterial({\n color: palette.lampGlow,\n emissive: palette.lampGlow,\n emissiveIntensity: 1.6,\n })\n );\n bulb.position.y = height - 0.03;\n group.add(bulb);\n\n if (options.light) {\n const light = new PointLight(palette.lampGlow, options.lightIntensity ?? 6, 12, 1.8);\n light.position.y = height - 0.05;\n group.add(light);\n }\n\n return { object: group, obstacleRadius: 0.25 };\n}\n","import {\n BufferAttribute,\n Color,\n Mesh,\n MeshStandardMaterial,\n PlaneGeometry,\n} from 'three';\nimport { fractalNoise2 } from '../core/random';\nimport { DEFAULT_PALETTE, type Palette } from '../core/palette';\n\nexport interface TerrainOptions {\n seed?: number;\n /** Square side length. Default 80. */\n size?: number;\n /** Vertices per side. Default 96. */\n resolution?: number;\n /** Peak height. Default 6. */\n amplitude?: number;\n /** Noise feature size in world units. Default 28. */\n noiseScale?: number;\n octaves?: number;\n /** Flatten low areas into meadows (0–1, higher = flatter valleys). Default 0.55. */\n valleyFlatness?: number;\n palette?: Palette;\n}\n\nexport interface Terrain {\n mesh: Mesh;\n /** Exact analytic height at any (x, z) — same function that built the\n * mesh, so agents/navmesh queries never disagree with the visuals. */\n heightAt(x: number, z: number): number;\n size: number;\n seed: number;\n}\n\n/**\n * A seeded low-poly terrain: fractal value noise displacing a plane, with\n * height/slope-banded vertex colors (grass → high grass → cliff → peak).\n * The height function is exported, not just baked into vertices — that's\n * what lets gameplay (spawning, scattering, navmesh baking, agent ground\n * clamping) agree exactly with what's rendered.\n */\nexport function createTerrain(options: TerrainOptions = {}): Terrain {\n const seed = options.seed ?? 1;\n const size = options.size ?? 80;\n const resolution = options.resolution ?? 96;\n const amplitude = options.amplitude ?? 6;\n const noiseScale = options.noiseScale ?? 28;\n const octaves = options.octaves ?? 4;\n const flatness = options.valleyFlatness ?? 0.55;\n const palette = options.palette ?? DEFAULT_PALETTE;\n\n const heightAt = (x: number, z: number): number => {\n const n = fractalNoise2(x / noiseScale, z / noiseScale, seed, octaves);\n // Push valleys down and flatten them; keep peaks.\n const shaped = Math.pow(n, 1 + flatness * 2);\n return shaped * amplitude;\n };\n\n const geometry = new PlaneGeometry(size, size, resolution - 1, resolution - 1);\n geometry.rotateX(-Math.PI / 2);\n const positions = geometry.getAttribute('position') as BufferAttribute;\n for (let i = 0; i < positions.count; i++) {\n positions.setY(i, heightAt(positions.getX(i), positions.getZ(i)));\n }\n geometry.computeVertexNormals();\n\n // Vertex colors by height band + slope.\n const normals = geometry.getAttribute('normal') as BufferAttribute;\n const colors = new Float32Array(positions.count * 3);\n const grassLow = new Color(palette.grassLow);\n const grassHigh = new Color(palette.grassHigh);\n const cliff = new Color(palette.cliff);\n const peak = new Color(palette.peak);\n const scratch = new Color();\n for (let i = 0; i < positions.count; i++) {\n const h = positions.getY(i) / amplitude;\n const slope = 1 - normals.getY(i); // 0 flat … 1 vertical\n scratch.copy(grassLow).lerp(grassHigh, Math.min(1, h * 1.6));\n if (h > 0.75) scratch.lerp(peak, (h - 0.75) * 4);\n if (slope > 0.15) scratch.lerp(cliff, Math.min(1, (slope - 0.15) * 4));\n colors[i * 3] = scratch.r;\n colors[i * 3 + 1] = scratch.g;\n colors[i * 3 + 2] = scratch.b;\n }\n geometry.setAttribute('color', new BufferAttribute(colors, 3));\n\n const mesh = new Mesh(\n geometry,\n new MeshStandardMaterial({ vertexColors: true, flatShading: true })\n );\n mesh.name = 'terrain';\n\n return { mesh, heightAt, size, seed };\n}\n","import {\n BackSide,\n Color,\n Mesh,\n ShaderMaterial,\n SphereGeometry,\n} from 'three';\nimport { DEFAULT_PALETTE, type Palette } from '../core/palette';\n\nexport interface SkyOptions {\n topColor?: number;\n bottomColor?: number;\n radius?: number;\n palette?: Palette;\n}\n\nexport interface Sky {\n mesh: Mesh;\n setColors(top: number, bottom: number): void;\n}\n\n/**\n * A gradient sky dome (vertical color blend on an inverted sphere).\n * Colors default to the palette, so themed scenes get matching skies.\n */\nexport function createSky(options: SkyOptions = {}): Sky {\n const palette = options.palette ?? DEFAULT_PALETTE;\n const material = new ShaderMaterial({\n side: BackSide,\n depthWrite: false,\n uniforms: {\n topColor: { value: new Color(options.topColor ?? palette.skyTop) },\n bottomColor: { value: new Color(options.bottomColor ?? palette.skyBottom) },\n },\n vertexShader: /* glsl */ `\n varying vec3 vWorld;\n void main() {\n vWorld = (modelMatrix * vec4(position, 1.0)).xyz;\n gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0);\n }`,\n fragmentShader: /* glsl */ `\n uniform vec3 topColor;\n uniform vec3 bottomColor;\n varying vec3 vWorld;\n void main() {\n float t = clamp(normalize(vWorld).y * 0.5 + 0.5, 0.0, 1.0);\n gl_FragColor = vec4(mix(bottomColor, topColor, pow(t, 0.8)), 1.0);\n }`,\n });\n const mesh = new Mesh(new SphereGeometry(options.radius ?? 400, 16, 12), material);\n mesh.name = 'sky';\n\n return {\n mesh,\n setColors(top, bottom) {\n (material.uniforms.topColor.value as Color).setHex(top);\n (material.uniforms.bottomColor.value as Color).setHex(bottom);\n },\n };\n}\n","import {\n AmbientLight,\n DirectionalLight,\n Fog,\n Group,\n HemisphereLight,\n type Scene,\n} from 'three';\nimport { DEFAULT_PALETTE, type Palette } from '../core/palette';\n\nexport type LightingPreset = 'day' | 'golden-hour' | 'overcast' | 'night';\n\nexport interface LightingRig {\n group: Group;\n sun: DirectionalLight;\n ambient: AmbientLight;\n hemisphere: HemisphereLight;\n}\n\nconst PRESETS: Record<\n LightingPreset,\n { sun: number; sunIntensity: number; sunPos: [number, number, number]; ambient: number; ambientIntensity: number; skyTint: number; groundTint: number }\n> = {\n day: {\n sun: 0xfff4e0, sunIntensity: 1.6, sunPos: [30, 45, 20],\n ambient: 0xdfeaff, ambientIntensity: 0.35, skyTint: 0xbcd8ff, groundTint: 0x6a7d66,\n },\n 'golden-hour': {\n sun: 0xffb861, sunIntensity: 1.7, sunPos: [40, 14, -12],\n ambient: 0xffdcc0, ambientIntensity: 0.3, skyTint: 0xffcf9e, groundTint: 0x7a6a58,\n },\n overcast: {\n sun: 0xd8dee8, sunIntensity: 0.7, sunPos: [12, 40, 8],\n ambient: 0xcfd6e0, ambientIntensity: 0.65, skyTint: 0xc8d0dc, groundTint: 0x707a78,\n },\n night: {\n sun: 0x8ea6d8, sunIntensity: 0.35, sunPos: [-20, 30, -25],\n ambient: 0x3a4468, ambientIntensity: 0.35, skyTint: 0x2c3560, groundTint: 0x1e2430,\n },\n};\n\n/**\n * The three lights every scene rebuilds, as a preset: warm directional\n * \"sun\" (position doubles as light direction), ambient fill, and a\n * hemisphere tint. Retune any of them via the returned rig.\n */\nexport function createLightingRig(preset: LightingPreset = 'day'): LightingRig {\n const config = PRESETS[preset];\n const group = new Group();\n group.name = `lighting-${preset}`;\n const sun = new DirectionalLight(config.sun, config.sunIntensity);\n sun.position.set(...config.sunPos);\n const ambient = new AmbientLight(config.ambient, config.ambientIntensity);\n const hemisphere = new HemisphereLight(config.skyTint, config.groundTint, 0.5);\n group.add(sun, ambient, hemisphere);\n return { group, sun, ambient, hemisphere };\n}\n\nexport type FogPreset = 'clear' | 'haze' | 'thick' | 'eerie';\n\nconst FOG: Record<Exclude<FogPreset, 'clear'>, { near: number; far: number }> = {\n haze: { near: 45, far: 160 },\n thick: { near: 12, far: 70 },\n eerie: { near: 6, far: 42 },\n};\n\n/** Distance fog matched to the palette's fog color. 'clear' removes it. */\nexport function applyFog(scene: Scene, preset: FogPreset, palette: Palette = DEFAULT_PALETTE): void {\n if (preset === 'clear') {\n scene.fog = null;\n return;\n }\n const { near, far } = FOG[preset];\n scene.fog = new Fog(palette.fog, near, far);\n}\n","import {\n DynamicDrawUsage,\n Group,\n InstancedMesh,\n Matrix4,\n Mesh,\n Quaternion,\n Vector3,\n} from 'three';\nimport { Rng, valueNoise2 } from '../core/random';\nimport type { Obstacle, Prop } from '../core/types';\n\nexport interface ScatterItem {\n /** Prop factory, called once per visual variant with a seeded Rng. */\n create(rng: Rng): Prop;\n /** Relative frequency among items. Default 1. */\n weight?: number;\n /** Distinct variants generated per item (visual variety). Default 4. */\n variants?: number;\n /** Per-instance uniform scale range. Default [0.8, 1.25]. */\n scale?: [number, number];\n}\n\nexport interface ScatterOptions {\n seed?: number;\n items: ScatterItem[];\n /** Placement region in the XZ plane. */\n area: { min: { x: number; z: number }; max: { x: number; z: number } };\n /** Ground height lookup; a number means flat ground. Default 0. */\n surface?: number | ((x: number, z: number) => number);\n /** Expected instances per square unit (thinned by density noise). */\n density?: number;\n /** Or an exact target count (before masks/spacing rejections). */\n count?: number;\n /** Veto function: return false to reject a candidate point. */\n mask?: (x: number, z: number, y: number) => boolean;\n /** Minimum distance between any two placements. Default 1.2. */\n minSpacing?: number;\n /** World-space circles to keep clear (paths, spawns, buildings). */\n keepOut?: Obstacle[] | { center: { x: number; z: number }; radius: number }[];\n /** Density-noise feature size in world units. Default 18. */\n clumpScale?: number;\n}\n\nexport interface Placement {\n position: Vector3;\n rotationY: number;\n scale: number;\n itemIndex: number;\n}\n\nexport interface ScatterResult {\n /** One InstancedMesh per template part — a handful of draw calls total. */\n group: Group;\n placements: Placement[];\n /** World-space steering obstacles for everything with a footprint. */\n obstacles: Obstacle[];\n count: number;\n}\n\n/**\n * Populate an area with seeded, instanced props: \"empty plane → forest\"\n * in one call. Placement uses density noise for natural clumping, a\n * spatial hash for minimum spacing, and masks/keep-out circles for\n * exclusion. Rendering merges every placement into InstancedMeshes — a\n * few draw calls for thousands of props.\n *\n * ```ts\n * const forest = scatter({\n * seed: 7,\n * area: { min: { x: -40, z: -40 }, max: { x: 40, z: 40 } },\n * surface: terrain.heightAt,\n * density: 0.04,\n * items: [\n * { create: (rng) => createTree({ seed: rng.int(1, 1e9) }), weight: 3 },\n * { create: (rng) => createRock({ seed: rng.int(1, 1e9) }) },\n * ],\n * mask: (x, z, y) => y > 0.5 && y < 5, // between shore and peaks\n * keepOut: [{ center: village, radius: 12 }],\n * });\n * scene.add(forest.group);\n * agent.addBehavior(new ObstacleAvoidance(() => forest.obstacles));\n * ```\n */\nexport function scatter(options: ScatterOptions): ScatterResult {\n const seed = options.seed ?? 1;\n const rng = new Rng(seed);\n const { area } = options;\n const width = area.max.x - area.min.x;\n const depth = area.max.z - area.min.z;\n const surface = options.surface ?? 0;\n const heightAt =\n typeof surface === 'number' ? () => surface : (x: number, z: number) => surface(x, z);\n const minSpacing = options.minSpacing ?? 1.2;\n const clumpScale = options.clumpScale ?? 18;\n const attempts = options.count ?? Math.round(width * depth * (options.density ?? 0.03));\n\n const keepOut = (options.keepOut ?? []).map((k) => ({\n x: k.center.x,\n z: 'z' in k.center ? k.center.z : (k.center as { z: number }).z,\n radius: k.radius,\n }));\n\n // Weighted item choice.\n const weights = options.items.map((i) => i.weight ?? 1);\n const totalWeight = weights.reduce((a, b) => a + b, 0);\n const pickItem = (): number => {\n let r = rng.next() * totalWeight;\n for (let i = 0; i < weights.length; i++) {\n r -= weights[i];\n if (r <= 0) return i;\n }\n return weights.length - 1;\n };\n\n // Spatial hash for min-spacing rejection.\n const cell = Math.max(minSpacing, 0.001);\n const occupied = new Map<string, Array<{ x: number; z: number }>>();\n const tooClose = (x: number, z: number): boolean => {\n const cx = Math.floor(x / cell);\n const cz = Math.floor(z / cell);\n for (let dx = -1; dx <= 1; dx++) {\n for (let dz = -1; dz <= 1; dz++) {\n const bucket = occupied.get(`${cx + dx},${cz + dz}`);\n if (!bucket) continue;\n for (const p of bucket) {\n if ((p.x - x) ** 2 + (p.z - z) ** 2 < minSpacing * minSpacing) return true;\n }\n }\n }\n return false;\n };\n\n const placements: Placement[] = [];\n for (let i = 0; i < attempts; i++) {\n const x = rng.range(area.min.x, area.max.x);\n const z = rng.range(area.min.z, area.max.z);\n // Density noise: clumps and clearings instead of uniform confetti.\n if (valueNoise2(x / clumpScale, z / clumpScale, seed + 77) < rng.range(0.15, 0.55)) continue;\n if (keepOut.some((k) => (k.x - x) ** 2 + (k.z - z) ** 2 < k.radius * k.radius)) continue;\n if (tooClose(x, z)) continue;\n const y = heightAt(x, z);\n if (options.mask && !options.mask(x, z, y)) continue;\n\n const itemIndex = pickItem();\n const [minScale, maxScale] = options.items[itemIndex].scale ?? [0.8, 1.25];\n placements.push({\n position: new Vector3(x, y, z),\n rotationY: rng.range(0, Math.PI * 2),\n scale: rng.range(minScale, maxScale),\n itemIndex,\n });\n const key = `${Math.floor(x / cell)},${Math.floor(z / cell)}`;\n let bucket = occupied.get(key);\n if (!bucket) occupied.set(key, (bucket = []));\n bucket.push({ x, z });\n }\n\n // Build variants per item, bucket placements per variant, then emit one\n // InstancedMesh per (variant, mesh part).\n const group = new Group();\n group.name = 'scatter';\n const obstacles: Obstacle[] = [];\n const placementMatrix = new Matrix4();\n const composed = new Matrix4();\n const quaternion = new Quaternion();\n const up = new Vector3(0, 1, 0);\n const scaleVector = new Vector3();\n\n options.items.forEach((item, itemIndex) => {\n const variantCount = item.variants ?? 4;\n const variants: Prop[] = [];\n for (let v = 0; v < variantCount; v++) variants.push(item.create(rng.fork()));\n\n const byVariant: Placement[][] = variants.map(() => []);\n for (const placement of placements) {\n if (placement.itemIndex !== itemIndex) continue;\n // Deterministic variant choice from position.\n const v = Math.abs(Math.floor(placement.position.x * 31 + placement.position.z * 17)) % variantCount;\n byVariant[v].push(placement);\n }\n\n variants.forEach((variant, v) => {\n const list = byVariant[v];\n if (list.length === 0) return;\n variant.object.updateMatrixWorld(true);\n variant.object.traverse((child) => {\n if (!(child instanceof Mesh)) return;\n const instanced = new InstancedMesh(child.geometry, child.material, list.length);\n instanced.instanceMatrix.setUsage(DynamicDrawUsage);\n list.forEach((placement, index) => {\n quaternion.setFromAxisAngle(up, placement.rotationY);\n scaleVector.setScalar(placement.scale);\n placementMatrix.compose(placement.position, quaternion, scaleVector);\n composed.multiplyMatrices(placementMatrix, child.matrixWorld);\n instanced.setMatrixAt(index, composed);\n });\n instanced.instanceMatrix.needsUpdate = true;\n group.add(instanced);\n });\n if (variant.obstacleRadius > 0) {\n for (const placement of list) {\n obstacles.push({\n center: placement.position.clone(),\n radius: variant.obstacleRadius * placement.scale,\n });\n }\n }\n });\n });\n\n return { group, placements, obstacles, count: placements.length };\n}\n"],"mappings":"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","names":["Group","IcosahedronGeometry","Mesh","MeshStandardMaterial","IcosahedronGeometry","Mesh","MeshStandardMaterial","Group","Group","Mesh","MeshStandardMaterial","Group","MeshStandardMaterial","Mesh","BoxGeometry","CylinderGeometry","Group","Mesh","MeshStandardMaterial","Group","MeshStandardMaterial","Mesh","CylinderGeometry","BoxGeometry","BoxGeometry","CylinderGeometry","Group","Mesh","MeshStandardMaterial","Group","MeshStandardMaterial","Mesh","CylinderGeometry","BoxGeometry","BufferAttribute","Mesh","MeshStandardMaterial","BufferAttribute","Mesh","MeshStandardMaterial","Color","Mesh","SphereGeometry","Color","Mesh","SphereGeometry","Group","Group","Group","Mesh","Vector3","maxScale","Vector3","Group","Mesh"]}
1
+ {"version":3,"sources":["../src/core/random.ts","../src/core/palette.ts","../src/core/types.ts","../src/props/tree.ts","../src/props/rock.ts","../src/props/crate.ts","../src/props/fence.ts","../src/props/lamp.ts","../src/props/grass.ts","../src/props/building.ts","../src/environment/terrain.ts","../src/environment/sky.ts","../src/environment/lighting.ts","../src/environment/water.ts","../src/environment/dayCycle.ts","../src/environment/wind.ts","../src/environment/path.ts","../src/generators/village.ts","../src/scatter/scatter.ts"],"sourcesContent":["/**\n * Deterministic seeded randomness — the backbone of SCENA. Same seed,\n * same tree; forests are reproducible, diffable and network-syncable.\n */\nexport class Rng {\n private state: number;\n\n constructor(seed = 1) {\n this.state = seed >>> 0 || 1;\n }\n\n /** Next float in [0, 1) (mulberry32). */\n next(): number {\n this.state = (this.state + 0x6d2b79f5) >>> 0;\n let t = this.state;\n t = Math.imul(t ^ (t >>> 15), t | 1);\n t ^= t + Math.imul(t ^ (t >>> 7), t | 61);\n return ((t ^ (t >>> 14)) >>> 0) / 4294967296;\n }\n\n /** Float in [min, max). */\n range(min: number, max: number): number {\n return min + this.next() * (max - min);\n }\n\n /** Integer in [min, max] inclusive. */\n int(min: number, max: number): number {\n return min + Math.floor(this.next() * (max - min + 1));\n }\n\n /** Random element of a non-empty array. */\n pick<T>(items: readonly T[]): T {\n return items[Math.floor(this.next() * items.length)];\n }\n\n /** value ± spread (uniform). */\n jitter(value: number, spread: number): number {\n return value + (this.next() * 2 - 1) * spread;\n }\n\n /** A new independent Rng derived from this one. */\n fork(): Rng {\n return new Rng(Math.floor(this.next() * 0xffffffff) || 1);\n }\n}\n\n/** Integer-lattice hash to [0, 1) — the base of the value noise. */\nexport function hash2(ix: number, iz: number, seed: number): number {\n let h = (ix * 374761393 + iz * 668265263 + seed * 2246822519) >>> 0;\n h = Math.imul(h ^ (h >>> 13), 1274126177) >>> 0;\n return ((h ^ (h >>> 16)) >>> 0) / 4294967296;\n}\n\nconst smooth = (t: number): number => t * t * (3 - 2 * t);\n\n/** 2D value noise in [0, 1). Continuous; used by terrain and scatter density. */\nexport function valueNoise2(x: number, z: number, seed: number): number {\n const ix = Math.floor(x);\n const iz = Math.floor(z);\n const fx = smooth(x - ix);\n const fz = smooth(z - iz);\n const a = hash2(ix, iz, seed);\n const b = hash2(ix + 1, iz, seed);\n const c = hash2(ix, iz + 1, seed);\n const d = hash2(ix + 1, iz + 1, seed);\n return a + (b - a) * fx + (c - a) * fz + (a - b - c + d) * fx * fz;\n}\n\n/** Fractal (octaved) value noise in [0, 1). */\nexport function fractalNoise2(\n x: number,\n z: number,\n seed: number,\n octaves = 4,\n lacunarity = 2,\n gain = 0.5\n): number {\n let amplitude = 1;\n let frequency = 1;\n let sum = 0;\n let total = 0;\n for (let i = 0; i < octaves; i++) {\n sum += valueNoise2(x * frequency, z * frequency, seed + i * 101) * amplitude;\n total += amplitude;\n amplitude *= gain;\n frequency *= lacunarity;\n }\n return sum / total;\n}\n","/**\n * Theme palettes: one coherent set of colors shared by every generator,\n * so procedural props look like a matched set rather than a junk drawer.\n * Pass `palette` to any generator to restyle it; whole scenes retheme by\n * building with a different palette.\n */\nexport interface Palette {\n foliage: number[];\n trunk: number;\n rock: number[];\n wood: number;\n woodDark: number;\n metal: number;\n lampGlow: number;\n grassLow: number;\n grassHigh: number;\n cliff: number;\n peak: number;\n skyTop: number;\n skyBottom: number;\n fog: number;\n water: number;\n sand: number;\n path: number;\n /** Building plaster/wall color. */\n wall: number;\n /** Building roof color. */\n roof: number;\n}\n\nexport const PALETTES: Record<'meadow' | 'autumn' | 'dusk' | 'winter', Palette> = {\n meadow: {\n foliage: [0x2f9e57, 0x37b26a, 0x2a8f4f, 0x45b878],\n trunk: 0x6b4a33,\n rock: [0x8a8f98, 0x767c86, 0x9aa0a8],\n wood: 0x8a6642,\n woodDark: 0x6b4a33,\n metal: 0x3d4451,\n lampGlow: 0xffd889,\n grassLow: 0x3f9d5a,\n grassHigh: 0x6fae66,\n cliff: 0x7d7a72,\n peak: 0xe8ecef,\n skyTop: 0x3d70b8,\n skyBottom: 0xbfd9e8,\n fog: 0xb8cfdd,\n water: 0x3f7fae,\n sand: 0xc9b98a,\n path: 0x9a815f,\n wall: 0xd9ccb0,\n roof: 0xa8563e,\n },\n autumn: {\n foliage: [0xc9752f, 0xd98e3a, 0xb35c2a, 0xe0a545],\n trunk: 0x5d4030,\n rock: [0x8d8578, 0x776f63, 0x9c948a],\n wood: 0x7d5a3a,\n woodDark: 0x5d4030,\n metal: 0x463f3a,\n lampGlow: 0xffc571,\n grassLow: 0x9d8a3f,\n grassHigh: 0xb59b4a,\n cliff: 0x82746a,\n peak: 0xe3ded4,\n skyTop: 0x8e6ca8,\n skyBottom: 0xe8c9a8,\n fog: 0xd9c1a8,\n water: 0x4a7a92,\n sand: 0xcbb083,\n path: 0x8d7454,\n wall: 0xccb894,\n roof: 0x8a4a30,\n },\n dusk: {\n foliage: [0x1f5e46, 0x24684f, 0x1a5240, 0x2d7458],\n trunk: 0x413147,\n rock: [0x565672, 0x484861, 0x646484],\n wood: 0x5d4a63,\n woodDark: 0x413147,\n metal: 0x2b2b3d,\n lampGlow: 0xffb35c,\n grassLow: 0x2d6b52,\n grassHigh: 0x3d7a5e,\n cliff: 0x52516b,\n peak: 0xb8b8d9,\n skyTop: 0x1d2145,\n skyBottom: 0xc96a4a,\n fog: 0x6a5a7a,\n water: 0x2d4a68,\n sand: 0x8a7a6a,\n path: 0x6a5a52,\n wall: 0x8d8299,\n roof: 0x453558,\n },\n winter: {\n foliage: [0x2e5c48, 0x38695a, 0x527a68, 0x87a596],\n trunk: 0x4a3a33,\n rock: [0x9aa4ad, 0x848e98, 0xb0b8c0],\n wood: 0x776049,\n woodDark: 0x54453a,\n metal: 0x39404d,\n lampGlow: 0xffd889,\n grassLow: 0xcfd9de,\n grassHigh: 0xe4ebee,\n cliff: 0x76797d,\n peak: 0xf4f7fa,\n skyTop: 0x5a7ba6,\n skyBottom: 0xd8e4ec,\n fog: 0xccd8e0,\n water: 0x4a7086,\n sand: 0xb8c2c6,\n path: 0x8b8378,\n wall: 0xd2c9bb,\n roof: 0x6b4638,\n },\n};\n\nexport const DEFAULT_PALETTE: Palette = PALETTES.meadow;\n","import { Vector3, type Group, type Object3D } from 'three';\n\n/**\n * A steering obstacle in world space — structurally identical to GAMA's\n * `Obstacle`, so SCENA props plug straight into `ObstacleAvoidance`\n * without either library importing the other.\n */\nexport interface Obstacle {\n center: Vector3;\n radius: number;\n}\n\n/** What a prop generator returns: the visual plus gameplay metadata. */\nexport interface Prop {\n object: Group;\n /**\n * Footprint radius for steering/placement, in the prop's local space\n * (centered at its origin). 0 means walk-through (e.g. grass).\n */\n obstacleRadius: number;\n}\n\n/** Collect world-space obstacles from placed props (call after positioning). */\nexport function collectObstacles(props: Iterable<Prop>): Obstacle[] {\n const obstacles: Obstacle[] = [];\n for (const prop of props) {\n if (prop.obstacleRadius <= 0) continue;\n prop.object.updateWorldMatrix(true, false);\n obstacles.push({\n center: prop.object.getWorldPosition(new Vector3()),\n radius: prop.obstacleRadius * maxScale(prop.object),\n });\n }\n return obstacles;\n}\n\nfunction maxScale(object: Object3D): number {\n return Math.max(object.scale.x, object.scale.z);\n}\n","import {\n ConeGeometry,\n CylinderGeometry,\n Group,\n IcosahedronGeometry,\n Mesh,\n MeshStandardMaterial,\n} from 'three';\nimport { Rng } from '../core/random';\nimport { DEFAULT_PALETTE, type Palette } from '../core/palette';\nimport type { Prop } from '../core/types';\n\nexport interface TreeOptions {\n seed?: number;\n /** Overall height in world units. Default ~3.5–5 by seed. */\n height?: number;\n style?: 'pine' | 'oak';\n palette?: Palette;\n}\n\n/**\n * A seeded low-poly tree. `pine` stacks cones; `oak` clusters foliage\n * blobs on a forked trunk. Same seed → identical tree, forever.\n */\nexport function createTree(options: TreeOptions = {}): Prop {\n const rng = new Rng(options.seed ?? 1);\n const palette = options.palette ?? DEFAULT_PALETTE;\n const style = options.style ?? (rng.next() < 0.6 ? 'pine' : 'oak');\n const height = options.height ?? rng.range(3.2, 5.2);\n const group = new Group();\n group.name = `tree-${style}`;\n\n const trunkMaterial = new MeshStandardMaterial({ color: palette.trunk, flatShading: true });\n const foliageMaterial = new MeshStandardMaterial({\n color: rng.pick(palette.foliage),\n flatShading: true,\n });\n\n if (style === 'pine') {\n const trunkHeight = height * 0.25;\n const trunk = new Mesh(new CylinderGeometry(0.09, 0.14, trunkHeight, 6), trunkMaterial);\n trunk.position.y = trunkHeight / 2;\n group.add(trunk);\n\n const tiers = rng.int(3, 4);\n let y = trunkHeight;\n let radius = height * rng.range(0.24, 0.3);\n const tierHeight = (height - trunkHeight) / tiers + 0.15;\n for (let i = 0; i < tiers; i++) {\n const cone = new Mesh(new ConeGeometry(radius, tierHeight * 1.35, 7), foliageMaterial);\n cone.position.y = y + tierHeight * 0.55;\n cone.rotation.y = rng.range(0, Math.PI);\n group.add(cone);\n y += tierHeight * 0.8;\n radius *= 0.72;\n }\n } else {\n const trunkHeight = height * 0.45;\n const trunk = new Mesh(new CylinderGeometry(0.12, 0.2, trunkHeight, 6), trunkMaterial);\n trunk.position.y = trunkHeight / 2;\n trunk.rotation.z = rng.range(-0.08, 0.08);\n group.add(trunk);\n\n const blobs = rng.int(2, 4);\n for (let i = 0; i < blobs; i++) {\n const radius = height * rng.range(0.18, 0.28);\n const blob = new Mesh(new IcosahedronGeometry(radius, 0), foliageMaterial);\n blob.position.set(\n rng.jitter(0, height * 0.16),\n trunkHeight + radius * rng.range(0.5, 0.9) + i * radius * 0.35,\n rng.jitter(0, height * 0.16)\n );\n blob.rotation.set(rng.range(0, Math.PI), rng.range(0, Math.PI), 0);\n group.add(blob);\n }\n }\n\n return { object: group, obstacleRadius: style === 'pine' ? 0.5 : 0.6 };\n}\n","import {\n BufferAttribute,\n Group,\n IcosahedronGeometry,\n Mesh,\n MeshStandardMaterial,\n} from 'three';\nimport { Rng } from '../core/random';\nimport { DEFAULT_PALETTE, type Palette } from '../core/palette';\nimport type { Prop } from '../core/types';\n\nexport interface RockOptions {\n seed?: number;\n /** Approximate radius. Default ~0.4–1.1 by seed. */\n size?: number;\n palette?: Palette;\n}\n\n/**\n * A seeded low-poly boulder: an icosahedron with jittered vertices and a\n * flattened underside so it sits on the ground.\n */\nexport function createRock(options: RockOptions = {}): Prop {\n const rng = new Rng(options.seed ?? 1);\n const palette = options.palette ?? DEFAULT_PALETTE;\n const size = options.size ?? rng.range(0.4, 1.1);\n\n const geometry = new IcosahedronGeometry(size, 0);\n const positions = geometry.getAttribute('position') as BufferAttribute;\n // Jitter welded-by-value: identical vertex values get identical offsets,\n // so faces stay connected.\n const seen = new Map<string, [number, number, number]>();\n for (let i = 0; i < positions.count; i++) {\n const key = `${positions.getX(i).toFixed(4)},${positions.getY(i).toFixed(4)},${positions.getZ(i).toFixed(4)}`;\n let offset = seen.get(key);\n if (!offset) {\n offset = [rng.jitter(0, size * 0.22), rng.jitter(0, size * 0.16), rng.jitter(0, size * 0.22)];\n seen.set(key, offset);\n }\n positions.setXYZ(\n i,\n positions.getX(i) + offset[0],\n Math.max(positions.getY(i) + offset[1], -size * 0.15), // flatten the bottom\n positions.getZ(i) + offset[2]\n );\n }\n geometry.computeVertexNormals();\n\n const rock = new Mesh(\n geometry,\n new MeshStandardMaterial({ color: rng.pick(palette.rock), flatShading: true })\n );\n rock.position.y = size * 0.15;\n rock.scale.y = rng.range(0.6, 0.9);\n\n const group = new Group();\n group.name = 'rock';\n group.add(rock);\n return { object: group, obstacleRadius: size * 1.05 };\n}\n","import { BoxGeometry, Group, Mesh, MeshStandardMaterial } from 'three';\nimport { Rng } from '../core/random';\nimport { DEFAULT_PALETTE, type Palette } from '../core/palette';\nimport type { Prop } from '../core/types';\n\nexport interface CrateOptions {\n seed?: number;\n size?: number;\n /** 0–1 color wear. Default 0.3. */\n weathering?: number;\n palette?: Palette;\n}\n\n/** A wooden crate: panel box with darker edge framing, seeded wear tint. */\nexport function createCrate(options: CrateOptions = {}): Prop {\n const rng = new Rng(options.seed ?? 1);\n const palette = options.palette ?? DEFAULT_PALETTE;\n const size = options.size ?? 1;\n const wear = options.weathering ?? 0.3;\n\n const group = new Group();\n group.name = 'crate';\n\n const panelMaterial = new MeshStandardMaterial({ color: palette.wood, flatShading: true });\n panelMaterial.color.offsetHSL(0, 0, -rng.range(0, wear * 0.18));\n const frameMaterial = new MeshStandardMaterial({ color: palette.woodDark, flatShading: true });\n\n const body = new Mesh(new BoxGeometry(size * 0.92, size * 0.92, size * 0.92), panelMaterial);\n body.position.y = size / 2;\n group.add(body);\n\n const beam = size * 0.12;\n const long = size * 1.0;\n for (const y of [beam / 2, size - beam / 2]) {\n for (const [rx, rz, w, d] of [\n [0, size / 2 - beam / 2, long, beam],\n [0, -(size / 2 - beam / 2), long, beam],\n [size / 2 - beam / 2, 0, beam, long],\n [-(size / 2 - beam / 2), 0, beam, long],\n ] as const) {\n const rail = new Mesh(new BoxGeometry(w, beam, d), frameMaterial);\n rail.position.set(rx, y, rz);\n group.add(rail);\n }\n }\n for (const x of [-1, 1]) {\n for (const z of [-1, 1]) {\n const post = new Mesh(new BoxGeometry(beam, size, beam), frameMaterial);\n post.position.set(x * (size / 2 - beam / 2), size / 2, z * (size / 2 - beam / 2));\n group.add(post);\n }\n }\n group.rotation.y = rng.range(0, Math.PI / 2);\n\n return { object: group, obstacleRadius: size * 0.75 };\n}\n","import { BoxGeometry, CylinderGeometry, Group, Mesh, MeshStandardMaterial } from 'three';\nimport { Rng } from '../core/random';\nimport { DEFAULT_PALETTE, type Palette } from '../core/palette';\nimport type { Prop } from '../core/types';\n\nexport interface FenceOptions {\n seed?: number;\n /** Run length along local +x. Default 6. */\n length?: number;\n postSpacing?: number;\n height?: number;\n palette?: Palette;\n}\n\n/**\n * A rustic fence run along local +x, centered at the origin: posts with\n * two slightly-crooked rails. Chain several and rotate to enclose areas.\n * The obstacle radius covers the whole run (rough but steering-safe);\n * for tight navigation, bake a navmesh — the geometry is authoritative.\n */\nexport function createFence(options: FenceOptions = {}): Prop {\n const rng = new Rng(options.seed ?? 1);\n const palette = options.palette ?? DEFAULT_PALETTE;\n const length = options.length ?? 6;\n const spacing = options.postSpacing ?? 1.5;\n const height = options.height ?? 1.1;\n\n const group = new Group();\n group.name = 'fence';\n const postMaterial = new MeshStandardMaterial({ color: palette.woodDark, flatShading: true });\n const railMaterial = new MeshStandardMaterial({ color: palette.wood, flatShading: true });\n\n const posts = Math.max(2, Math.round(length / spacing) + 1);\n const step = length / (posts - 1);\n for (let i = 0; i < posts; i++) {\n const post = new Mesh(new CylinderGeometry(0.06, 0.075, height, 5), postMaterial);\n post.position.set(-length / 2 + i * step, height / 2, rng.jitter(0, 0.03));\n post.rotation.z = rng.range(-0.04, 0.04);\n group.add(post);\n }\n for (const railY of [height * 0.55, height * 0.85]) {\n const rail = new Mesh(new BoxGeometry(length, 0.07, 0.05), railMaterial);\n rail.position.y = rng.jitter(railY, 0.02);\n rail.rotation.x = rng.range(-0.02, 0.02);\n group.add(rail);\n }\n\n return { object: group, obstacleRadius: length / 2 };\n}\n","import {\n BoxGeometry,\n CylinderGeometry,\n Group,\n Mesh,\n MeshStandardMaterial,\n PointLight,\n SphereGeometry,\n} from 'three';\nimport { Rng } from '../core/random';\nimport { DEFAULT_PALETTE, type Palette } from '../core/palette';\nimport type { Prop } from '../core/types';\n\nexport interface LampOptions {\n seed?: number;\n height?: number;\n /** Add a real PointLight. Off by default — lights are a budget. */\n light?: boolean;\n lightIntensity?: number;\n palette?: Palette;\n}\n\n/** A street lamp: post, head, glowing bulb, optional real PointLight. */\nexport function createLamp(options: LampOptions = {}): Prop {\n const rng = new Rng(options.seed ?? 1);\n const palette = options.palette ?? DEFAULT_PALETTE;\n const height = options.height ?? rng.range(2.6, 3.1);\n\n const group = new Group();\n group.name = 'lamp';\n const metal = new MeshStandardMaterial({ color: palette.metal, flatShading: true });\n\n const post = new Mesh(new CylinderGeometry(0.05, 0.08, height, 6), metal);\n post.position.y = height / 2;\n group.add(post);\n\n const head = new Mesh(new BoxGeometry(0.34, 0.26, 0.34), metal);\n head.position.y = height + 0.1;\n group.add(head);\n\n const bulb = new Mesh(\n new SphereGeometry(0.11, 8, 6),\n new MeshStandardMaterial({\n color: palette.lampGlow,\n emissive: palette.lampGlow,\n emissiveIntensity: 1.6,\n })\n );\n bulb.position.y = height - 0.03;\n group.add(bulb);\n\n if (options.light) {\n const light = new PointLight(palette.lampGlow, options.lightIntensity ?? 6, 12, 1.8);\n light.position.y = height - 0.05;\n group.add(light);\n }\n\n return { object: group, obstacleRadius: 0.25 };\n}\n","import { ConeGeometry, Group, IcosahedronGeometry, Mesh, MeshStandardMaterial } from 'three';\nimport { Rng } from '../core/random';\nimport { DEFAULT_PALETTE, type Palette } from '../core/palette';\nimport type { Prop } from '../core/types';\n\nexport interface GrassOptions {\n seed?: number;\n /** Blades per tuft. Default 4–6 by seed. */\n blades?: number;\n palette?: Palette;\n}\n\n/**\n * A tuft of grass blades — pure scatter fodder (zero obstacle footprint,\n * walk straight through). Sways beautifully under `applyWind`.\n */\nexport function createGrassTuft(options: GrassOptions = {}): Prop {\n const rng = new Rng(options.seed ?? 1);\n const palette = options.palette ?? DEFAULT_PALETTE;\n const blades = options.blades ?? rng.int(4, 6);\n const group = new Group();\n group.name = 'grass';\n const material = new MeshStandardMaterial({\n color: rng.next() < 0.5 ? palette.grassHigh : rng.pick(palette.foliage),\n flatShading: true,\n });\n for (let i = 0; i < blades; i++) {\n const height = rng.range(0.25, 0.5);\n const blade = new Mesh(new ConeGeometry(0.035, height, 3), material);\n blade.position.set(rng.jitter(0, 0.12), height / 2, rng.jitter(0, 0.12));\n blade.rotation.set(rng.range(-0.25, 0.25), rng.range(0, Math.PI), rng.range(-0.25, 0.25));\n group.add(blade);\n }\n return { object: group, obstacleRadius: 0 };\n}\n\nexport interface BushOptions {\n seed?: number;\n size?: number;\n palette?: Palette;\n}\n\n/** A low foliage bush: two or three squashed blobs. Small footprint. */\nexport function createBush(options: BushOptions = {}): Prop {\n const rng = new Rng(options.seed ?? 1);\n const palette = options.palette ?? DEFAULT_PALETTE;\n const size = options.size ?? rng.range(0.4, 0.7);\n const group = new Group();\n group.name = 'bush';\n const material = new MeshStandardMaterial({ color: rng.pick(palette.foliage), flatShading: true });\n const blobs = rng.int(2, 3);\n for (let i = 0; i < blobs; i++) {\n const radius = size * rng.range(0.55, 0.85);\n const blob = new Mesh(new IcosahedronGeometry(radius, 0), material);\n blob.position.set(rng.jitter(0, size * 0.4), radius * 0.7, rng.jitter(0, size * 0.4));\n blob.scale.y = rng.range(0.7, 0.85);\n blob.rotation.y = rng.range(0, Math.PI);\n group.add(blob);\n }\n return { object: group, obstacleRadius: size * 0.6 };\n}\n","import {\n BoxGeometry,\n BufferAttribute,\n BufferGeometry,\n CylinderGeometry,\n Group,\n Mesh,\n MeshStandardMaterial,\n} from 'three';\nimport { Rng } from '../core/random';\nimport { DEFAULT_PALETTE, type Palette } from '../core/palette';\nimport type { Prop } from '../core/types';\n\n/** A gabled-roof prism: ridge along local z, base resting on y = 0. */\nfunction prismGeometry(width: number, height: number, depth: number): BufferGeometry {\n const w = width / 2;\n const d = depth / 2;\n // prettier-ignore\n const positions = new Float32Array([\n // front gable (z = +d)\n -w, 0, d, w, 0, d, 0, height, d,\n // back gable (z = -d)\n w, 0, -d, -w, 0, -d, 0, height, -d,\n // left slope\n -w, 0, -d, -w, 0, d, 0, height, d,\n -w, 0, -d, 0, height, d, 0, height, -d,\n // right slope\n w, 0, d, w, 0, -d, 0, height, -d,\n w, 0, d, 0, height, -d, 0, height, d,\n // bottom\n -w, 0, -d, w, 0, -d, w, 0, d,\n -w, 0, -d, w, 0, d, -w, 0, d,\n ]);\n const geometry = new BufferGeometry();\n geometry.setAttribute('position', new BufferAttribute(positions, 3));\n geometry.computeVertexNormals();\n return geometry;\n}\n\nexport interface HouseOptions {\n seed?: number;\n /** Footprint width (gable side). Default seeded 3.2–4.2. */\n width?: number;\n depth?: number;\n wallHeight?: number;\n palette?: Palette;\n}\n\n/**\n * A cottage: plastered walls, gabled roof, door, chimney and emissive\n * windows. Pass the house in `createDayCycle`'s `lamps` list and its\n * windows glow at night along with the street lamps. A stone foundation\n * extends below ground so sloped terrain never shows a gap.\n */\nexport function createHouse(options: HouseOptions = {}): Prop {\n const rng = new Rng(options.seed ?? 1);\n const palette = options.palette ?? DEFAULT_PALETTE;\n const width = options.width ?? rng.range(3.2, 4.2);\n const depth = options.depth ?? width * rng.range(0.75, 0.9);\n const wallHeight = options.wallHeight ?? rng.range(2.1, 2.4);\n\n const group = new Group();\n group.name = 'house';\n const wall = new MeshStandardMaterial({ color: palette.wall, flatShading: true });\n wall.color.offsetHSL(0, 0, rng.range(-0.03, 0.03));\n const roof = new MeshStandardMaterial({ color: palette.roof, flatShading: true });\n roof.color.offsetHSL(0, 0, rng.range(-0.04, 0.04));\n const stone = new MeshStandardMaterial({ color: palette.rock[0], flatShading: true });\n const wood = new MeshStandardMaterial({ color: palette.woodDark, flatShading: true });\n\n const foundation = new Mesh(new BoxGeometry(width + 0.3, 1.6, depth + 0.3), stone);\n foundation.position.y = -0.55;\n group.add(foundation);\n\n const body = new Mesh(new BoxGeometry(width, wallHeight, depth), wall);\n body.position.y = wallHeight / 2;\n group.add(body);\n\n const ridgeHeight = width * rng.range(0.32, 0.4);\n const roofMesh = new Mesh(prismGeometry(width + 0.5, ridgeHeight, depth + 0.6), roof);\n roofMesh.position.y = wallHeight - 0.02;\n group.add(roofMesh);\n\n const chimney = new Mesh(new BoxGeometry(0.34, ridgeHeight + 0.8, 0.34), stone);\n chimney.position.set(rng.pick([-1, 1]) * width * 0.22, wallHeight + ridgeHeight * 0.45, depth * 0.12);\n group.add(chimney);\n\n // Door on the front face (+z).\n const door = new Mesh(new BoxGeometry(0.85, 1.5, 0.08), wood);\n door.position.set(rng.range(-0.4, 0.4), 0.75, depth / 2 + 0.02);\n group.add(door);\n\n // Emissive windows — createDayCycle treats these like lamp bulbs.\n const glass = new MeshStandardMaterial({\n color: palette.lampGlow,\n emissive: palette.lampGlow,\n emissiveIntensity: 1.0,\n });\n const windowGeometry = new BoxGeometry(0.6, 0.62, 0.08);\n const front = new Mesh(windowGeometry, glass);\n front.position.set(door.position.x < 0 ? width * 0.28 : -width * 0.28, 1.35, depth / 2 + 0.02);\n group.add(front);\n for (const side of [-1, 1]) {\n if (rng.next() < 0.35) continue;\n const pane = new Mesh(windowGeometry, glass);\n pane.position.set(side * (width / 2 + 0.02), 1.35, rng.range(-0.3, 0.3) * depth);\n pane.rotation.y = Math.PI / 2;\n group.add(pane);\n }\n\n return { object: group, obstacleRadius: Math.hypot(width + 0.5, depth + 0.5) / 2 };\n}\n\nexport interface TowerOptions {\n seed?: number;\n height?: number;\n palette?: Palette;\n}\n\n/** A wooden watchtower: splayed legs, platform with railing, pyramid roof. */\nexport function createTower(options: TowerOptions = {}): Prop {\n const rng = new Rng(options.seed ?? 1);\n const palette = options.palette ?? DEFAULT_PALETTE;\n const height = options.height ?? rng.range(4.2, 5.2);\n\n const group = new Group();\n group.name = 'tower';\n const wood = new MeshStandardMaterial({ color: palette.wood, flatShading: true });\n const woodDark = new MeshStandardMaterial({ color: palette.woodDark, flatShading: true });\n const roof = new MeshStandardMaterial({ color: palette.roof, flatShading: true });\n\n const spread = 1.0;\n for (const x of [-1, 1]) {\n for (const z of [-1, 1]) {\n const leg = new Mesh(new CylinderGeometry(0.09, 0.12, height, 6), woodDark);\n leg.position.set(x * spread * 0.75, height / 2 - 0.6, z * spread * 0.75);\n leg.rotation.z = -x * 0.1;\n leg.rotation.x = z * 0.1;\n group.add(leg);\n }\n }\n // Cross-braces.\n for (const level of [0.3, 0.62]) {\n const brace = new Mesh(new BoxGeometry(spread * 2.1, 0.09, 0.07), wood);\n brace.position.set(0, height * level, spread * 0.82 * (1 - level * 0.35));\n brace.rotation.z = rng.pick([-0.5, 0.5]);\n group.add(brace);\n const braceSide = new Mesh(new BoxGeometry(0.07, 0.09, spread * 2.1), wood);\n braceSide.position.set(spread * 0.82 * (1 - level * 0.35), height * level, 0);\n braceSide.rotation.x = rng.pick([-0.5, 0.5]);\n group.add(braceSide);\n }\n\n const platform = new Mesh(new BoxGeometry(spread * 2.2, 0.14, spread * 2.2), wood);\n platform.position.y = height - 0.5;\n group.add(platform);\n for (const x of [-1, 1]) {\n for (const z of [-1, 1]) {\n const post = new Mesh(new BoxGeometry(0.08, 0.9, 0.08), woodDark);\n post.position.set(x * spread * 1.0, height - 0.05, z * spread * 1.0);\n group.add(post);\n }\n }\n for (const [rx, rz, w, d] of [\n [0, 1, spread * 2.1, 0.06],\n [0, -1, spread * 2.1, 0.06],\n [1, 0, 0.06, spread * 2.1],\n [-1, 0, 0.06, spread * 2.1],\n ] as const) {\n const rail = new Mesh(new BoxGeometry(w, 0.07, d), wood);\n rail.position.set(rx * spread, height + 0.28, rz * spread);\n group.add(rail);\n }\n\n const cap = new Mesh(new CylinderGeometry(0, spread * 1.55, 1.0, 4), roof);\n cap.position.y = height + 1.15;\n cap.rotation.y = Math.PI / 4;\n group.add(cap);\n\n return { object: group, obstacleRadius: spread * 1.35 };\n}\n\nexport interface WellOptions {\n seed?: number;\n palette?: Palette;\n}\n\n/** A stone well: ring, posts, little gabled roof, hanging bucket. */\nexport function createWell(options: WellOptions = {}): Prop {\n const rng = new Rng(options.seed ?? 1);\n const palette = options.palette ?? DEFAULT_PALETTE;\n\n const group = new Group();\n group.name = 'well';\n const stone = new MeshStandardMaterial({ color: rng.pick(palette.rock), flatShading: true });\n const wood = new MeshStandardMaterial({ color: palette.woodDark, flatShading: true });\n const roof = new MeshStandardMaterial({ color: palette.roof, flatShading: true });\n\n const ring = new Mesh(new CylinderGeometry(0.85, 0.95, 0.75, 10), stone);\n ring.position.y = 0.375;\n group.add(ring);\n const inner = new Mesh(\n new CylinderGeometry(0.62, 0.62, 0.05, 10),\n new MeshStandardMaterial({ color: 0x16222e })\n );\n inner.position.y = 0.76;\n group.add(inner);\n\n for (const side of [-1, 1]) {\n const post = new Mesh(new CylinderGeometry(0.06, 0.075, 1.9, 5), wood);\n post.position.set(side * 0.72, 0.95, 0);\n group.add(post);\n }\n const bar = new Mesh(new CylinderGeometry(0.045, 0.045, 1.5, 5), wood);\n bar.rotation.z = Math.PI / 2;\n bar.position.y = 1.72;\n group.add(bar);\n\n const cap = new Mesh(prismGeometry(2.0, 0.55, 0.65), roof);\n cap.position.y = 1.86;\n cap.rotation.y = Math.PI / 2;\n group.add(cap);\n\n const rope = new Mesh(new CylinderGeometry(0.012, 0.012, 0.6, 4), wood);\n rope.position.y = 1.42;\n group.add(rope);\n const bucket = new Mesh(new CylinderGeometry(0.13, 0.1, 0.2, 7), wood);\n bucket.position.y = 1.05;\n group.add(bucket);\n\n return { object: group, obstacleRadius: 1.0 };\n}\n\nexport interface RuinOptions {\n seed?: number;\n /** Footprint width. Default seeded 3.5–5. */\n size?: number;\n palette?: Palette;\n}\n\n/**\n * A ruined building: a partial rectangle of crumbling wall segments with\n * seeded gaps and heights, and tumbled blocks around the floor.\n */\nexport function createRuin(options: RuinOptions = {}): Prop {\n const rng = new Rng(options.seed ?? 1);\n const palette = options.palette ?? DEFAULT_PALETTE;\n const size = options.size ?? rng.range(3.5, 5);\n const depth = size * rng.range(0.7, 0.9);\n\n const group = new Group();\n group.name = 'ruin';\n const stone = new MeshStandardMaterial({ color: rng.pick(palette.rock), flatShading: true });\n stone.color.offsetHSL(0, 0, rng.range(-0.04, 0.02));\n\n const thickness = 0.35;\n // Wall runs: [centerX, centerZ, length, alongX]. Front wall mostly gone.\n const runs: Array<[number, number, number, boolean]> = [\n [0, -depth / 2, size, true],\n [-size / 2, 0, depth, false],\n [size / 2, 0, depth, false],\n [size * 0.3, depth / 2, size * 0.35, true],\n ];\n for (const [cx, cz, length, alongX] of runs) {\n const segments = Math.max(2, Math.round(length / 1.1));\n const step = length / segments;\n for (let i = 0; i < segments; i++) {\n if (rng.next() < 0.22) continue; // collapsed gap\n const height = rng.range(0.5, 2.2);\n const wall = new Mesh(\n new BoxGeometry(alongX ? step * 0.96 : thickness, height, alongX ? thickness : step * 0.96),\n stone\n );\n const offset = -length / 2 + step * (i + 0.5);\n wall.position.set(alongX ? cx + offset : cx, height / 2, alongX ? cz : cz + offset);\n wall.rotation.y = rng.range(-0.03, 0.03);\n group.add(wall);\n }\n }\n // Tumbled blocks.\n const blocks = rng.int(4, 7);\n for (let i = 0; i < blocks; i++) {\n const s = rng.range(0.25, 0.55);\n const block = new Mesh(new BoxGeometry(s, s * rng.range(0.6, 1), s * rng.range(0.7, 1.2)), stone);\n block.position.set(rng.range(-size * 0.6, size * 0.6), s * 0.3, rng.range(-depth * 0.6, depth * 0.7));\n block.rotation.set(rng.range(-0.3, 0.3), rng.range(0, Math.PI), rng.range(-0.3, 0.3));\n group.add(block);\n }\n\n return { object: group, obstacleRadius: Math.hypot(size, depth) / 2 };\n}\n","import {\n BufferAttribute,\n Color,\n Mesh,\n MeshStandardMaterial,\n PlaneGeometry,\n} from 'three';\nimport { fractalNoise2 } from '../core/random';\nimport { DEFAULT_PALETTE, type Palette } from '../core/palette';\n\nexport interface TerrainOptions {\n seed?: number;\n /** Square side length. Default 80. */\n size?: number;\n /** Vertices per side. Default 96. */\n resolution?: number;\n /** Peak height. Default 6. */\n amplitude?: number;\n /** Noise feature size in world units. Default 28. */\n noiseScale?: number;\n octaves?: number;\n /** Flatten low areas into meadows (0–1, higher = flatter valleys). Default 0.55. */\n valleyFlatness?: number;\n /** Blend low bands toward sand below (waterLevel + shore margin). */\n waterLevel?: number;\n palette?: Palette;\n}\n\nexport interface Terrain {\n mesh: Mesh;\n /** Exact analytic height at any (x, z) — same function that built the\n * mesh, so agents/navmesh queries never disagree with the visuals. */\n heightAt(x: number, z: number): number;\n size: number;\n seed: number;\n}\n\n/**\n * A seeded low-poly terrain: fractal value noise displacing a plane, with\n * height/slope-banded vertex colors (grass → high grass → cliff → peak).\n * The height function is exported, not just baked into vertices — that's\n * what lets gameplay (spawning, scattering, navmesh baking, agent ground\n * clamping) agree exactly with what's rendered.\n */\nexport function createTerrain(options: TerrainOptions = {}): Terrain {\n const seed = options.seed ?? 1;\n const size = options.size ?? 80;\n const resolution = options.resolution ?? 96;\n const amplitude = options.amplitude ?? 6;\n const noiseScale = options.noiseScale ?? 28;\n const octaves = options.octaves ?? 4;\n const flatness = options.valleyFlatness ?? 0.55;\n const palette = options.palette ?? DEFAULT_PALETTE;\n\n const heightAt = (x: number, z: number): number => {\n const n = fractalNoise2(x / noiseScale, z / noiseScale, seed, octaves);\n // Push valleys down and flatten them; keep peaks.\n const shaped = Math.pow(n, 1 + flatness * 2);\n return shaped * amplitude;\n };\n\n const geometry = new PlaneGeometry(size, size, resolution - 1, resolution - 1);\n geometry.rotateX(-Math.PI / 2);\n const positions = geometry.getAttribute('position') as BufferAttribute;\n for (let i = 0; i < positions.count; i++) {\n positions.setY(i, heightAt(positions.getX(i), positions.getZ(i)));\n }\n geometry.computeVertexNormals();\n\n // Vertex colors by height band + slope.\n const normals = geometry.getAttribute('normal') as BufferAttribute;\n const colors = new Float32Array(positions.count * 3);\n const grassLow = new Color(palette.grassLow);\n const grassHigh = new Color(palette.grassHigh);\n const cliff = new Color(palette.cliff);\n const peak = new Color(palette.peak);\n const sand = new Color(palette.sand);\n const waterLevel = options.waterLevel;\n const scratch = new Color();\n for (let i = 0; i < positions.count; i++) {\n const y = positions.getY(i);\n const h = y / amplitude;\n const slope = 1 - normals.getY(i); // 0 flat … 1 vertical\n scratch.copy(grassLow).lerp(grassHigh, Math.min(1, h * 1.6));\n if (h > 0.75) scratch.lerp(peak, (h - 0.75) * 4);\n if (slope > 0.15) scratch.lerp(cliff, Math.min(1, (slope - 0.15) * 4));\n if (waterLevel !== undefined && y < waterLevel + 0.5) {\n scratch.lerp(sand, Math.min(1, (waterLevel + 0.5 - y) * 1.6));\n }\n colors[i * 3] = scratch.r;\n colors[i * 3 + 1] = scratch.g;\n colors[i * 3 + 2] = scratch.b;\n }\n geometry.setAttribute('color', new BufferAttribute(colors, 3));\n\n const mesh = new Mesh(\n geometry,\n new MeshStandardMaterial({ vertexColors: true, flatShading: true })\n );\n mesh.name = 'terrain';\n\n return { mesh, heightAt, size, seed };\n}\n","import {\n BackSide,\n Color,\n Mesh,\n ShaderMaterial,\n SphereGeometry,\n} from 'three';\nimport { DEFAULT_PALETTE, type Palette } from '../core/palette';\n\nexport interface SkyOptions {\n topColor?: number;\n bottomColor?: number;\n radius?: number;\n palette?: Palette;\n}\n\nexport interface Sky {\n mesh: Mesh;\n setColors(top: number, bottom: number): void;\n}\n\n/**\n * A gradient sky dome (vertical color blend on an inverted sphere).\n * Colors default to the palette, so themed scenes get matching skies.\n */\nexport function createSky(options: SkyOptions = {}): Sky {\n const palette = options.palette ?? DEFAULT_PALETTE;\n const material = new ShaderMaterial({\n side: BackSide,\n depthWrite: false,\n uniforms: {\n topColor: { value: new Color(options.topColor ?? palette.skyTop) },\n bottomColor: { value: new Color(options.bottomColor ?? palette.skyBottom) },\n },\n vertexShader: /* glsl */ `\n varying vec3 vWorld;\n void main() {\n vWorld = (modelMatrix * vec4(position, 1.0)).xyz;\n gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0);\n }`,\n fragmentShader: /* glsl */ `\n uniform vec3 topColor;\n uniform vec3 bottomColor;\n varying vec3 vWorld;\n void main() {\n float t = clamp(normalize(vWorld).y * 0.5 + 0.5, 0.0, 1.0);\n gl_FragColor = vec4(mix(bottomColor, topColor, pow(t, 0.8)), 1.0);\n }`,\n });\n const mesh = new Mesh(new SphereGeometry(options.radius ?? 400, 16, 12), material);\n mesh.name = 'sky';\n\n return {\n mesh,\n setColors(top, bottom) {\n (material.uniforms.topColor.value as Color).setHex(top);\n (material.uniforms.bottomColor.value as Color).setHex(bottom);\n },\n };\n}\n","import {\n AmbientLight,\n DirectionalLight,\n Fog,\n Group,\n HemisphereLight,\n type Scene,\n} from 'three';\nimport { DEFAULT_PALETTE, type Palette } from '../core/palette';\n\nexport type LightingPreset = 'day' | 'golden-hour' | 'overcast' | 'night';\n\nexport interface LightingRig {\n group: Group;\n sun: DirectionalLight;\n ambient: AmbientLight;\n hemisphere: HemisphereLight;\n}\n\nconst PRESETS: Record<\n LightingPreset,\n { sun: number; sunIntensity: number; sunPos: [number, number, number]; ambient: number; ambientIntensity: number; skyTint: number; groundTint: number }\n> = {\n day: {\n sun: 0xfff4e0, sunIntensity: 1.6, sunPos: [30, 45, 20],\n ambient: 0xdfeaff, ambientIntensity: 0.35, skyTint: 0xbcd8ff, groundTint: 0x6a7d66,\n },\n 'golden-hour': {\n sun: 0xffb861, sunIntensity: 1.7, sunPos: [40, 14, -12],\n ambient: 0xffdcc0, ambientIntensity: 0.3, skyTint: 0xffcf9e, groundTint: 0x7a6a58,\n },\n overcast: {\n sun: 0xd8dee8, sunIntensity: 0.7, sunPos: [12, 40, 8],\n ambient: 0xcfd6e0, ambientIntensity: 0.65, skyTint: 0xc8d0dc, groundTint: 0x707a78,\n },\n night: {\n sun: 0x8ea6d8, sunIntensity: 0.35, sunPos: [-20, 30, -25],\n ambient: 0x3a4468, ambientIntensity: 0.35, skyTint: 0x2c3560, groundTint: 0x1e2430,\n },\n};\n\n/**\n * The three lights every scene rebuilds, as a preset: warm directional\n * \"sun\" (position doubles as light direction), ambient fill, and a\n * hemisphere tint. Retune any of them via the returned rig.\n */\nexport function createLightingRig(preset: LightingPreset = 'day'): LightingRig {\n const config = PRESETS[preset];\n const group = new Group();\n group.name = `lighting-${preset}`;\n const sun = new DirectionalLight(config.sun, config.sunIntensity);\n sun.position.set(...config.sunPos);\n const ambient = new AmbientLight(config.ambient, config.ambientIntensity);\n const hemisphere = new HemisphereLight(config.skyTint, config.groundTint, 0.5);\n group.add(sun, ambient, hemisphere);\n return { group, sun, ambient, hemisphere };\n}\n\nexport type FogPreset = 'clear' | 'haze' | 'thick' | 'eerie';\n\nconst FOG: Record<Exclude<FogPreset, 'clear'>, { near: number; far: number }> = {\n haze: { near: 45, far: 160 },\n thick: { near: 12, far: 70 },\n eerie: { near: 6, far: 42 },\n};\n\n/** Distance fog matched to the palette's fog color. 'clear' removes it. */\nexport function applyFog(scene: Scene, preset: FogPreset, palette: Palette = DEFAULT_PALETTE): void {\n if (preset === 'clear') {\n scene.fog = null;\n return;\n }\n const { near, far } = FOG[preset];\n scene.fog = new Fog(palette.fog, near, far);\n}\n","import { BufferAttribute, Mesh, MeshStandardMaterial, PlaneGeometry } from 'three';\nimport { DEFAULT_PALETTE, type Palette } from '../core/palette';\nimport type { Terrain } from './terrain';\n\nexport interface WaterOptions {\n /** World-space water surface height. Default 0.8. */\n level?: number;\n size?: number;\n resolution?: number;\n /** Wave height. Default 0.06. */\n amplitude?: number;\n /** Wave speed multiplier. Default 1. */\n speed?: number;\n palette?: Palette;\n}\n\nexport interface Water {\n mesh: Mesh;\n level: number;\n /** Advance the wave animation. Call from your frame loop. */\n update(dt: number): void;\n /** Is ground at this height below the surface? */\n isUnderwater(groundHeight: number): boolean;\n}\n\n/**\n * A low-poly animated water plane at a fixed level. Pair it with a\n * terrain built using the same `waterLevel` so shores blend to sand, and\n * keep scatter/agents ashore with `aboveWater(terrain, water)`.\n */\nexport function createWater(options: WaterOptions = {}): Water {\n const level = options.level ?? 0.8;\n const size = options.size ?? 200;\n const resolution = options.resolution ?? 40;\n const amplitude = options.amplitude ?? 0.06;\n const speed = options.speed ?? 1;\n const palette = options.palette ?? DEFAULT_PALETTE;\n\n const geometry = new PlaneGeometry(size, size, resolution, resolution);\n geometry.rotateX(-Math.PI / 2);\n const positions = geometry.getAttribute('position') as BufferAttribute;\n const mesh = new Mesh(\n geometry,\n new MeshStandardMaterial({\n color: palette.water,\n transparent: true,\n opacity: 0.85,\n flatShading: true,\n metalness: 0.35,\n roughness: 0.4,\n })\n );\n mesh.name = 'water';\n mesh.position.y = level;\n\n let time = 0;\n const update = (dt: number): void => {\n time += dt * speed;\n for (let i = 0; i < positions.count; i++) {\n const x = positions.getX(i);\n const z = positions.getZ(i);\n positions.setY(\n i,\n Math.sin(x * 0.35 + time) * Math.cos(z * 0.3 + time * 0.8) * amplitude\n );\n }\n positions.needsUpdate = true;\n geometry.computeVertexNormals();\n };\n update(0);\n\n return {\n mesh,\n level,\n update,\n isUnderwater: (groundHeight) => groundHeight < level,\n };\n}\n\n/**\n * A scatter mask keeping placements on dry land: true when the terrain\n * at (x, z) sits above the water level plus `margin`.\n */\nexport function aboveWater(\n terrain: Terrain,\n water: Pick<Water, 'level'>,\n margin = 0.25\n): (x: number, z: number) => boolean {\n return (x, z) => terrain.heightAt(x, z) > water.level + margin;\n}\n","import { Color, PointLight, type MeshStandardMaterial, type Mesh, type Object3D, type Scene } from 'three';\nimport { DEFAULT_PALETTE, type Palette } from '../core/palette';\nimport type { LightingRig } from './lighting';\nimport type { Sky } from './sky';\n\ninterface Keyframe {\n t: number;\n skyTop: number;\n skyBottom: number;\n sun: number;\n sunIntensity: number;\n ambientIntensity: number;\n fog: number;\n}\n\nexport interface DayCycleOptions {\n sky?: Sky;\n rig?: LightingRig;\n /** Scene whose fog color should track the cycle. */\n scene?: Scene;\n /** Lamp props/objects whose PointLights + glow bulbs ignite at night. */\n lamps?: Array<{ object: Object3D } | Object3D>;\n palette?: Palette;\n /** Seconds per full day. Default 60. */\n dayLength?: number;\n /** Initial time: 0 = midnight, 0.25 = dawn, 0.5 = noon, 0.75 = dusk. */\n timeOfDay?: number;\n}\n\nexport interface DayCycle {\n timeOfDay: number;\n /** Sun elevation in [-1, 1]; negative = below the horizon. */\n readonly sunElevation: number;\n readonly isNight: boolean;\n /** Advance by dt seconds of real time and re-apply everything. */\n update(dt: number): void;\n /** Jump to a time of day and re-apply everything. */\n set(t: number): void;\n}\n\n/**\n * One `timeOfDay` parameter driving the whole environment in lockstep:\n * sun position/color/intensity, sky gradient, ambient level, fog color,\n * and lamps that ignite as the sun drops below the horizon.\n *\n * ```ts\n * const cycle = createDayCycle({ sky, rig, scene, lamps: [lampA, lampB], dayLength: 120 });\n * game.onUpdate((t) => cycle.update(t.delta));\n * ```\n */\nexport function createDayCycle(options: DayCycleOptions = {}): DayCycle {\n const palette = options.palette ?? DEFAULT_PALETTE;\n const dayLength = options.dayLength ?? 60;\n\n // Universal ramp; noon colors come from the palette so themes carry through.\n const frames: Keyframe[] = [\n { t: 0.0, skyTop: 0x0b1026, skyBottom: 0x1a2340, sun: 0x8ea6d8, sunIntensity: 0.03, ambientIntensity: 0.06, fog: 0x141a2e },\n { t: 0.23, skyTop: 0x27335c, skyBottom: 0x6a5470, sun: 0xcf9a72, sunIntensity: 0.3, ambientIntensity: 0.12, fog: 0x4a4258 },\n { t: 0.3, skyTop: 0x4a6ba0, skyBottom: 0xe8a97a, sun: 0xffb861, sunIntensity: 1.0, ambientIntensity: 0.26, fog: 0xb08a72 },\n { t: 0.5, skyTop: palette.skyTop, skyBottom: palette.skyBottom, sun: 0xfff4e0, sunIntensity: 1.9, ambientIntensity: 0.45, fog: palette.fog },\n { t: 0.7, skyTop: 0x4a5a94, skyBottom: 0xe0955e, sun: 0xffa050, sunIntensity: 1.0, ambientIntensity: 0.26, fog: 0xa07a68 },\n { t: 0.78, skyTop: 0x232a52, skyBottom: 0x8a5560, sun: 0xd88a5a, sunIntensity: 0.25, ambientIntensity: 0.11, fog: 0x463e54 },\n { t: 1.0, skyTop: 0x0b1026, skyBottom: 0x1a2340, sun: 0x8ea6d8, sunIntensity: 0.03, ambientIntensity: 0.06, fog: 0x141a2e },\n ];\n\n // Collect lamp lights and glowing bulb materials once.\n const lampLights: Array<{ light: PointLight; base: number }> = [];\n const lampBulbs: Array<{ material: MeshStandardMaterial; base: number }> = [];\n for (const entry of options.lamps ?? []) {\n const root = (entry as { isObject3D?: boolean }).isObject3D\n ? (entry as Object3D)\n : (entry as { object: Object3D }).object;\n root.traverse((child) => {\n if (child instanceof PointLight) {\n lampLights.push({ light: child, base: child.intensity || 6 });\n }\n const material = (child as Mesh).material as MeshStandardMaterial | undefined;\n if (material?.emissive && material.emissiveIntensity > 0.5) {\n lampBulbs.push({ material, base: material.emissiveIntensity });\n }\n });\n }\n\n const colorA = new Color();\n const colorB = new Color();\n let timeOfDay = options.timeOfDay ?? 0.5;\n let sunElevation = 0;\n\n const sample = (t: number): Keyframe => {\n let a = frames[0];\n let b = frames[frames.length - 1];\n for (let i = 0; i < frames.length - 1; i++) {\n if (t >= frames[i].t && t <= frames[i + 1].t) {\n a = frames[i];\n b = frames[i + 1];\n break;\n }\n }\n const f = b.t === a.t ? 0 : (t - a.t) / (b.t - a.t);\n const lerpHex = (ha: number, hb: number): number =>\n colorA.setHex(ha).lerp(colorB.setHex(hb), f).getHex();\n return {\n t,\n skyTop: lerpHex(a.skyTop, b.skyTop),\n skyBottom: lerpHex(a.skyBottom, b.skyBottom),\n sun: lerpHex(a.sun, b.sun),\n sunIntensity: a.sunIntensity + (b.sunIntensity - a.sunIntensity) * f,\n ambientIntensity: a.ambientIntensity + (b.ambientIntensity - a.ambientIntensity) * f,\n fog: lerpHex(a.fog, b.fog),\n };\n };\n\n const apply = (): void => {\n const t = timeOfDay;\n const frame = sample(t);\n const sunAngle = (t - 0.25) * Math.PI * 2;\n sunElevation = Math.sin(sunAngle);\n\n options.sky?.setColors(frame.skyTop, frame.skyBottom);\n if (options.rig) {\n const { sun, ambient, hemisphere } = options.rig;\n sun.color.setHex(frame.sun);\n sun.intensity = frame.sunIntensity;\n sun.position.set(Math.cos(sunAngle) * 40, Math.max(sunElevation, -0.2) * 45 + 6, 16);\n ambient.intensity = frame.ambientIntensity;\n // Hemisphere fill follows the ambient curve so nights actually darken.\n hemisphere.intensity = frame.ambientIntensity * 1.4;\n }\n if (options.scene?.fog && 'color' in options.scene.fog) {\n options.scene.fog.color.setHex(frame.fog);\n }\n // Lamps fade in as the sun dips below the horizon.\n const night = Math.min(1, Math.max(0, (0.06 - sunElevation) / 0.16));\n for (const { light, base } of lampLights) light.intensity = base * night;\n for (const { material, base } of lampBulbs) {\n material.emissiveIntensity = 0.15 * base + 0.85 * base * night;\n }\n };\n apply();\n\n return {\n get timeOfDay() {\n return timeOfDay;\n },\n set timeOfDay(t: number) {\n timeOfDay = ((t % 1) + 1) % 1;\n apply();\n },\n get sunElevation() {\n return sunElevation;\n },\n get isNight() {\n return sunElevation < 0;\n },\n update(dt) {\n timeOfDay = (timeOfDay + dt / dayLength) % 1;\n apply();\n },\n set(t) {\n timeOfDay = ((t % 1) + 1) % 1;\n apply();\n },\n };\n}\n","import { Mesh, type Material, type Object3D } from 'three';\n\n/** The slice of the shader object onBeforeCompile receives. */\ninterface PatchableShader {\n uniforms: Record<string, { value: unknown }>;\n vertexShader: string;\n}\n\nexport interface WindOptions {\n /** Sway amplitude in world units at the top of a prop. Default 0.06. */\n strength?: number;\n /** Oscillation speed. Default 1.2. */\n frequency?: number;\n /** Local height where sway begins (keeps trunks planted). Default 0.6. */\n anchorHeight?: number;\n}\n\nexport interface Wind {\n /** Advance the animation. Call from your frame loop. */\n update(dt: number): void;\n /** Materials that were patched (for debugging/cleanup). */\n materials: Material[];\n}\n\n/**\n * Vertex-shader wind sway for scattered vegetation: displacement grows\n * with local height (trunk bases stay planted), phase varies per\n * instance so a forest shimmers instead of marching in step. Works on\n * meshes and InstancedMeshes; patches each unique material once via\n * onBeforeCompile.\n *\n * ```ts\n * const wind = applyWind(forest.group, { strength: 0.08 });\n * game.onUpdate((t) => wind.update(t.delta));\n * ```\n */\nexport function applyWind(target: Object3D, options: WindOptions = {}): Wind {\n const strength = options.strength ?? 0.06;\n const frequency = options.frequency ?? 1.2;\n const anchor = options.anchorHeight ?? 0.6;\n const time = { value: 0 };\n const patched = new Set<Material>();\n\n target.traverse((child) => {\n if (!(child instanceof Mesh)) return;\n const materials = Array.isArray(child.material) ? child.material : [child.material];\n for (const material of materials) {\n if (patched.has(material)) continue;\n patched.add(material);\n material.onBeforeCompile = (shader: PatchableShader) => {\n shader.uniforms.uWindTime = time;\n shader.vertexShader = shader.vertexShader\n .replace(\n '#include <common>',\n `#include <common>\n uniform float uWindTime;`\n )\n .replace(\n '#include <begin_vertex>',\n `#include <begin_vertex>\n {\n float sway = max(position.y - ${anchor.toFixed(3)}, 0.0);\n float phase = 0.0;\n #ifdef USE_INSTANCING\n phase = instanceMatrix[3].x * 0.7 + instanceMatrix[3].z * 1.3;\n #endif\n float w = sin(uWindTime * ${(frequency * 2).toFixed(3)} + phase + position.y * 0.8);\n transformed.x += w * sway * ${strength.toFixed(4)} * 4.0;\n transformed.z += cos(uWindTime * ${(frequency * 1.4).toFixed(3)} + phase) * sway * ${strength.toFixed(4)} * 2.0;\n }`\n );\n };\n material.needsUpdate = true;\n }\n });\n\n return {\n update(dt) {\n time.value += dt;\n },\n materials: [...patched],\n };\n}\n","import {\n BufferAttribute,\n BufferGeometry,\n CatmullRomCurve3,\n Mesh,\n MeshStandardMaterial,\n Vector3,\n} from 'three';\nimport { DEFAULT_PALETTE, type Palette } from '../core/palette';\n\nexport interface PathOptions {\n /** Ribbon width. Default 1.8. */\n width?: number;\n /** Ground height lookup; a number means flat ground. Default 0. */\n surface?: number | ((x: number, z: number) => number);\n /** Samples per world unit of path length. Default 1. */\n samplesPerUnit?: number;\n /** Close the path into a loop. Default false. */\n loop?: boolean;\n /** Extra clearance added to scatter keep-out circles. Default 0.6. */\n keepOutMargin?: number;\n palette?: Palette;\n}\n\nexport interface WorldPath {\n mesh: Mesh;\n /** Smoothed centerline draped on the surface — feed straight into a\n * GAMA `Path` for patrols, or use as camera dolly points. */\n route: Vector3[];\n /** Keep-out circles for `scatter()` so nothing grows on the road. */\n keepOut: Array<{ center: { x: number; z: number }; radius: number }>;\n /** Is (x, z) on the path surface? (e.g. to exclude grass) */\n contains(x: number, z: number): boolean;\n loop: boolean;\n}\n\n/**\n * A dirt path: a Catmull-Rom-smoothed ribbon draped over the surface.\n * One authored polyline feeds three things at once — the visual ribbon,\n * scatter keep-out, and a patrol route for agents. That's the SCENA\n * handshake applied to level design.\n *\n * ```ts\n * const road = createPath([a, b, c], { surface: terrain.heightAt, loop: true });\n * scene.add(road.mesh);\n * scatter({ ..., keepOut: road.keepOut });\n * agent.addBehavior(new FollowPath(new Path(road.route, road.loop), 1.5));\n * ```\n */\nexport function createPath(\n points: Array<Vector3 | { x: number; z: number }>,\n options: PathOptions = {}\n): WorldPath {\n const width = options.width ?? 1.8;\n const surface = options.surface ?? 0;\n const heightAt =\n typeof surface === 'number' ? () => surface : (x: number, z: number) => surface(x, z);\n const loop = options.loop ?? false;\n const palette = options.palette ?? DEFAULT_PALETTE;\n\n const controls = points.map((p) => new Vector3(p.x, 0, 'z' in p ? p.z : 0));\n const curve = new CatmullRomCurve3(controls, loop, 'centripetal');\n const length = curve.getLength();\n const samples = Math.max(8, Math.ceil(length * (options.samplesPerUnit ?? 1)));\n\n const route: Vector3[] = [];\n for (let i = 0; i <= samples; i++) {\n if (loop && i === samples) break; // avoid duplicate closing point\n const p = curve.getPoint(i / samples);\n route.push(new Vector3(p.x, heightAt(p.x, p.z), p.z));\n }\n\n // Ribbon strip: left/right edge vertices per sample.\n const edgeCount = loop ? route.length + 1 : route.length;\n const positions = new Float32Array(edgeCount * 2 * 3);\n const direction = new Vector3();\n const perp = new Vector3();\n for (let i = 0; i < edgeCount; i++) {\n const current = route[i % route.length];\n const previous = route[(i - 1 + route.length) % route.length];\n const next = route[(i + 1) % route.length];\n if (!loop && i === 0) direction.subVectors(next, current);\n else if (!loop && i === edgeCount - 1) direction.subVectors(current, previous);\n else direction.subVectors(next, previous);\n perp.set(-direction.z, 0, direction.x).normalize().multiplyScalar(width / 2);\n const left = i * 6;\n positions[left] = current.x - perp.x;\n positions[left + 1] = heightAt(current.x - perp.x, current.z - perp.z) + 0.05;\n positions[left + 2] = current.z - perp.z;\n positions[left + 3] = current.x + perp.x;\n positions[left + 4] = heightAt(current.x + perp.x, current.z + perp.z) + 0.05;\n positions[left + 5] = current.z + perp.z;\n }\n const indices: number[] = [];\n for (let i = 0; i < edgeCount - 1; i++) {\n const a = i * 2;\n indices.push(a, a + 1, a + 2, a + 1, a + 3, a + 2);\n }\n const geometry = new BufferGeometry();\n geometry.setAttribute('position', new BufferAttribute(positions, 3));\n geometry.setIndex(indices);\n geometry.computeVertexNormals();\n\n const mesh = new Mesh(\n geometry,\n new MeshStandardMaterial({\n color: palette.path,\n flatShading: true,\n polygonOffset: true,\n polygonOffsetFactor: -1,\n })\n );\n mesh.name = 'path';\n\n const keepOutMargin = options.keepOutMargin ?? 0.6;\n const keepOut = route\n .filter((_p, i) => i % 2 === 0 || i === route.length - 1) // never drop the endpoint\n .map((p) => ({ center: { x: p.x, z: p.z }, radius: width / 2 + keepOutMargin }));\n\n const half = width / 2;\n const contains = (x: number, z: number): boolean => {\n const count = loop ? route.length : route.length - 1;\n for (let i = 0; i < count; i++) {\n const a = route[i];\n const b = route[(i + 1) % route.length];\n const abx = b.x - a.x;\n const abz = b.z - a.z;\n const lengthSq = abx * abx + abz * abz || 1e-9;\n const t = Math.max(0, Math.min(1, ((x - a.x) * abx + (z - a.z) * abz) / lengthSq));\n const dx = x - (a.x + abx * t);\n const dz = z - (a.z + abz * t);\n if (dx * dx + dz * dz <= half * half) return true;\n }\n return false;\n };\n\n return { mesh, route, keepOut, contains, loop };\n}\n","import { Group } from 'three';\nimport { Rng } from '../core/random';\nimport { DEFAULT_PALETTE, type Palette } from '../core/palette';\nimport { collectObstacles, type Obstacle, type Prop } from '../core/types';\nimport { createHouse, createRuin, createTower, createWell } from '../props/building';\nimport { createCrate } from '../props/crate';\nimport { createLamp } from '../props/lamp';\n\nexport interface VillageOptions {\n seed?: number;\n /** Village center in the XZ plane. Default origin. */\n center?: { x: number; z: number };\n /** Ring radius the houses settle on. Default 12. */\n radius?: number;\n /** House count. Default 5. */\n houses?: number;\n /** Ground height lookup; a number means flat ground. Default 0. */\n surface?: number | ((x: number, z: number) => number);\n /** Veto candidate spots (e.g. water, roads). Return false to reject. */\n mask?: (x: number, z: number, y: number) => boolean;\n /** Add real PointLights to this many street lamps. Default 3. */\n lampLights?: number;\n /** Add a watchtower at the edge. Default true. */\n tower?: boolean;\n /** Add a ruin outside the ring. Default true. */\n ruin?: boolean;\n palette?: Palette;\n}\n\nexport interface Village {\n group: Group;\n /** Every placed prop (houses, well, lamps, crates, tower, ruin). */\n props: Prop[];\n /** World-space steering obstacles — feed GAMA's ObstacleAvoidance. */\n obstacles: Obstacle[];\n /**\n * Props with something to ignite at night (street lamps AND house\n * windows). Pass straight to `createDayCycle({ lamps })`.\n */\n lamps: Prop[];\n /** One clearing circle covering the village — feed `scatter`'s keepOut. */\n keepOut: Array<{ center: { x: number; z: number }; radius: number }>;\n center: { x: number; z: number };\n}\n\n/**\n * A seeded hamlet: a well at the center, houses ringed around it facing\n * inward, street lamps between them, crates by the doors, a watchtower on\n * the edge and a ruin beyond. Everything is placed on the given surface\n * (steep or masked spots are rejected and re-rolled), and the result\n * carries the full gameplay handshake: `obstacles` for steering,\n * `keepOut` for scatter, and `lamps` for the day-night cycle — windows\n * and lamps ignite together at dusk.\n *\n * ```ts\n * const village = createVillage({ seed: 5, radius: 10, surface: terrain.heightAt, palette });\n * scene.add(village.group);\n * const cycle = createDayCycle({ sky, rig, scene, lamps: village.lamps, palette });\n * const forest = scatter({ ..., keepOut: village.keepOut });\n * ```\n */\nexport function createVillage(options: VillageOptions = {}): Village {\n const rng = new Rng(options.seed ?? 1);\n const palette = options.palette ?? DEFAULT_PALETTE;\n const center = options.center ?? { x: 0, z: 0 };\n const radius = options.radius ?? 12;\n const houseCount = options.houses ?? 5;\n const surface = options.surface ?? 0;\n const heightAt =\n typeof surface === 'number' ? () => surface : (x: number, z: number) => surface(x, z);\n\n const group = new Group();\n group.name = 'village';\n const props: Prop[] = [];\n const lamps: Prop[] = [];\n\n const place = (prop: Prop, x: number, z: number, rotY: number): Prop => {\n prop.object.position.set(x, heightAt(x, z), z);\n prop.object.rotation.y = rotY;\n group.add(prop.object);\n props.push(prop);\n return prop;\n };\n\n /**\n * Find a buildable spot near (angle, distance): reasonably level across\n * the footprint and not vetoed by the mask. Re-rolls up to 10 times,\n * then falls back to the last candidate so layout never dead-ends.\n */\n const findSpot = (\n angle: number,\n distance: number,\n footprint: number\n ): { x: number; z: number } => {\n let x = center.x;\n let z = center.z;\n for (let attempt = 0; attempt < 10; attempt++) {\n const a = angle + rng.range(-0.25, 0.25) * (attempt > 0 ? 1 : 0.3);\n const d = distance * rng.range(attempt > 0 ? 0.8 : 0.95, 1.1);\n x = center.x + Math.cos(a) * d;\n z = center.z + Math.sin(a) * d;\n const y = heightAt(x, z);\n if (options.mask && !options.mask(x, z, y)) continue;\n let min = y;\n let max = y;\n for (const [dx, dz] of [[footprint, 0], [-footprint, 0], [0, footprint], [0, -footprint]]) {\n const h = heightAt(x + dx, z + dz);\n min = Math.min(min, h);\n max = Math.max(max, h);\n }\n if (max - min <= Math.max(0.9, footprint * 0.35)) break;\n }\n return { x, z };\n };\n\n // The well anchors the plaza.\n const well = createWell({ seed: rng.int(1, 1e9), palette });\n place(well, center.x, center.z, rng.range(0, Math.PI * 2));\n\n // Houses on the ring, facing the well.\n let lightBudget = options.lampLights ?? 3;\n for (let i = 0; i < houseCount; i++) {\n const angle = (i / houseCount) * Math.PI * 2 + rng.range(-0.15, 0.15);\n const house = createHouse({ seed: rng.int(1, 1e9), palette });\n const spot = findSpot(angle, radius * rng.range(0.7, 0.95), house.obstacleRadius);\n const facing = Math.atan2(center.x - spot.x, center.z - spot.z);\n place(house, spot.x, spot.z, facing);\n lamps.push(house);\n\n // A crate by most doors, a lamp partway toward the plaza for some.\n if (rng.next() < 0.7) {\n const crateAngle = angle + rng.range(-0.5, 0.5);\n const crateDistance = Math.hypot(spot.x - center.x, spot.z - center.z) - house.obstacleRadius - 0.7;\n place(\n createCrate({ seed: rng.int(1, 1e9), size: rng.range(0.7, 1), palette }),\n center.x + Math.cos(crateAngle) * crateDistance,\n center.z + Math.sin(crateAngle) * crateDistance,\n rng.range(0, Math.PI)\n );\n }\n if (i % 2 === 0) {\n const lampDistance = Math.hypot(spot.x - center.x, spot.z - center.z) * 0.55;\n const lamp = createLamp({ seed: rng.int(1, 1e9), light: lightBudget > 0, palette });\n lightBudget--;\n place(lamp, center.x + Math.cos(angle) * lampDistance, center.z + Math.sin(angle) * lampDistance, 0);\n lamps.push(lamp);\n }\n }\n\n if (options.tower ?? true) {\n const angle = rng.range(0, Math.PI * 2);\n const tower = createTower({ seed: rng.int(1, 1e9), palette });\n const spot = findSpot(angle, radius * 1.05, tower.obstacleRadius);\n place(tower, spot.x, spot.z, rng.range(0, Math.PI * 2));\n }\n if (options.ruin ?? true) {\n const angle = rng.range(0, Math.PI * 2);\n const ruin = createRuin({ seed: rng.int(1, 1e9), palette });\n const spot = findSpot(angle, radius * 1.35, ruin.obstacleRadius);\n place(ruin, spot.x, spot.z, rng.range(0, Math.PI * 2));\n }\n\n return {\n group,\n props,\n obstacles: collectObstacles(props),\n lamps,\n keepOut: [{ center: { ...center }, radius: radius * 1.5 }],\n center,\n };\n}\n","import {\n DynamicDrawUsage,\n Group,\n InstancedMesh,\n Matrix4,\n Mesh,\n Quaternion,\n Vector3,\n} from 'three';\nimport { Rng, valueNoise2 } from '../core/random';\nimport type { Obstacle, Prop } from '../core/types';\n\nexport interface ScatterItem {\n /** Prop factory, called once per visual variant with a seeded Rng. */\n create(rng: Rng): Prop;\n /** Relative frequency among items. Default 1. */\n weight?: number;\n /** Distinct variants generated per item (visual variety). Default 4. */\n variants?: number;\n /** Per-instance uniform scale range. Default [0.8, 1.25]. */\n scale?: [number, number];\n}\n\nexport interface ScatterOptions {\n seed?: number;\n items: ScatterItem[];\n /** Placement region in the XZ plane. */\n area: { min: { x: number; z: number }; max: { x: number; z: number } };\n /** Ground height lookup; a number means flat ground. Default 0. */\n surface?: number | ((x: number, z: number) => number);\n /** Expected instances per square unit (thinned by density noise). */\n density?: number;\n /** Or an exact target count (before masks/spacing rejections). */\n count?: number;\n /** Veto function: return false to reject a candidate point. */\n mask?: (x: number, z: number, y: number) => boolean;\n /** Minimum distance between any two placements. Default 1.2. */\n minSpacing?: number;\n /** World-space circles to keep clear (paths, spawns, buildings). */\n keepOut?: Obstacle[] | { center: { x: number; z: number }; radius: number }[];\n /** Density-noise feature size in world units. Default 18. */\n clumpScale?: number;\n}\n\nexport interface Placement {\n position: Vector3;\n rotationY: number;\n scale: number;\n itemIndex: number;\n}\n\nexport interface ScatterResult {\n /** One InstancedMesh per template part — a handful of draw calls total. */\n group: Group;\n placements: Placement[];\n /** World-space steering obstacles for everything with a footprint. */\n obstacles: Obstacle[];\n count: number;\n}\n\n/**\n * Populate an area with seeded, instanced props: \"empty plane → forest\"\n * in one call. Placement uses density noise for natural clumping, a\n * spatial hash for minimum spacing, and masks/keep-out circles for\n * exclusion. Rendering merges every placement into InstancedMeshes — a\n * few draw calls for thousands of props.\n *\n * ```ts\n * const forest = scatter({\n * seed: 7,\n * area: { min: { x: -40, z: -40 }, max: { x: 40, z: 40 } },\n * surface: terrain.heightAt,\n * density: 0.04,\n * items: [\n * { create: (rng) => createTree({ seed: rng.int(1, 1e9) }), weight: 3 },\n * { create: (rng) => createRock({ seed: rng.int(1, 1e9) }) },\n * ],\n * mask: (x, z, y) => y > 0.5 && y < 5, // between shore and peaks\n * keepOut: [{ center: village, radius: 12 }],\n * });\n * scene.add(forest.group);\n * agent.addBehavior(new ObstacleAvoidance(() => forest.obstacles));\n * ```\n */\nexport function scatter(options: ScatterOptions): ScatterResult {\n const seed = options.seed ?? 1;\n const rng = new Rng(seed);\n const { area } = options;\n const width = area.max.x - area.min.x;\n const depth = area.max.z - area.min.z;\n const surface = options.surface ?? 0;\n const heightAt =\n typeof surface === 'number' ? () => surface : (x: number, z: number) => surface(x, z);\n const minSpacing = options.minSpacing ?? 1.2;\n const clumpScale = options.clumpScale ?? 18;\n const attempts = options.count ?? Math.round(width * depth * (options.density ?? 0.03));\n\n const keepOut = (options.keepOut ?? []).map((k) => ({\n x: k.center.x,\n z: 'z' in k.center ? k.center.z : (k.center as { z: number }).z,\n radius: k.radius,\n }));\n\n // Weighted item choice.\n const weights = options.items.map((i) => i.weight ?? 1);\n const totalWeight = weights.reduce((a, b) => a + b, 0);\n const pickItem = (): number => {\n let r = rng.next() * totalWeight;\n for (let i = 0; i < weights.length; i++) {\n r -= weights[i];\n if (r <= 0) return i;\n }\n return weights.length - 1;\n };\n\n // Spatial hash for min-spacing rejection.\n const cell = Math.max(minSpacing, 0.001);\n const occupied = new Map<string, Array<{ x: number; z: number }>>();\n const tooClose = (x: number, z: number): boolean => {\n const cx = Math.floor(x / cell);\n const cz = Math.floor(z / cell);\n for (let dx = -1; dx <= 1; dx++) {\n for (let dz = -1; dz <= 1; dz++) {\n const bucket = occupied.get(`${cx + dx},${cz + dz}`);\n if (!bucket) continue;\n for (const p of bucket) {\n if ((p.x - x) ** 2 + (p.z - z) ** 2 < minSpacing * minSpacing) return true;\n }\n }\n }\n return false;\n };\n\n const placements: Placement[] = [];\n for (let i = 0; i < attempts; i++) {\n const x = rng.range(area.min.x, area.max.x);\n const z = rng.range(area.min.z, area.max.z);\n // Density noise: clumps and clearings instead of uniform confetti.\n if (valueNoise2(x / clumpScale, z / clumpScale, seed + 77) < rng.range(0.15, 0.55)) continue;\n if (keepOut.some((k) => (k.x - x) ** 2 + (k.z - z) ** 2 < k.radius * k.radius)) continue;\n if (tooClose(x, z)) continue;\n const y = heightAt(x, z);\n if (options.mask && !options.mask(x, z, y)) continue;\n\n const itemIndex = pickItem();\n const [minScale, maxScale] = options.items[itemIndex].scale ?? [0.8, 1.25];\n placements.push({\n position: new Vector3(x, y, z),\n rotationY: rng.range(0, Math.PI * 2),\n scale: rng.range(minScale, maxScale),\n itemIndex,\n });\n const key = `${Math.floor(x / cell)},${Math.floor(z / cell)}`;\n let bucket = occupied.get(key);\n if (!bucket) occupied.set(key, (bucket = []));\n bucket.push({ x, z });\n }\n\n // Build variants per item, bucket placements per variant, then emit one\n // InstancedMesh per (variant, mesh part).\n const group = new Group();\n group.name = 'scatter';\n const obstacles: Obstacle[] = [];\n const placementMatrix = new Matrix4();\n const composed = new Matrix4();\n const quaternion = new Quaternion();\n const up = new Vector3(0, 1, 0);\n const scaleVector = new Vector3();\n\n options.items.forEach((item, itemIndex) => {\n const variantCount = item.variants ?? 4;\n const variants: Prop[] = [];\n for (let v = 0; v < variantCount; v++) variants.push(item.create(rng.fork()));\n\n const byVariant: Placement[][] = variants.map(() => []);\n for (const placement of placements) {\n if (placement.itemIndex !== itemIndex) continue;\n // Deterministic variant choice from position.\n const v = Math.abs(Math.floor(placement.position.x * 31 + placement.position.z * 17)) % variantCount;\n byVariant[v].push(placement);\n }\n\n variants.forEach((variant, v) => {\n const list = byVariant[v];\n if (list.length === 0) return;\n variant.object.updateMatrixWorld(true);\n variant.object.traverse((child) => {\n if (!(child instanceof Mesh)) return;\n const instanced = new InstancedMesh(child.geometry, child.material, list.length);\n instanced.instanceMatrix.setUsage(DynamicDrawUsage);\n list.forEach((placement, index) => {\n quaternion.setFromAxisAngle(up, placement.rotationY);\n scaleVector.setScalar(placement.scale);\n placementMatrix.compose(placement.position, quaternion, scaleVector);\n composed.multiplyMatrices(placementMatrix, child.matrixWorld);\n instanced.setMatrixAt(index, composed);\n });\n instanced.instanceMatrix.needsUpdate = true;\n group.add(instanced);\n });\n if (variant.obstacleRadius > 0) {\n for (const placement of list) {\n obstacles.push({\n center: placement.position.clone(),\n radius: variant.obstacleRadius * placement.scale,\n });\n }\n }\n });\n });\n\n return { group, placements, obstacles, count: placements.length };\n}\n"],"mappings":"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","names":["Group","IcosahedronGeometry","Mesh","MeshStandardMaterial","IcosahedronGeometry","Mesh","MeshStandardMaterial","Group","Group","Mesh","MeshStandardMaterial","Group","MeshStandardMaterial","Mesh","BoxGeometry","CylinderGeometry","Group","Mesh","MeshStandardMaterial","Group","MeshStandardMaterial","Mesh","CylinderGeometry","BoxGeometry","BoxGeometry","CylinderGeometry","Group","Mesh","MeshStandardMaterial","Group","MeshStandardMaterial","Mesh","CylinderGeometry","BoxGeometry","ConeGeometry","Group","IcosahedronGeometry","Mesh","MeshStandardMaterial","Group","MeshStandardMaterial","Mesh","ConeGeometry","IcosahedronGeometry","BoxGeometry","BufferAttribute","CylinderGeometry","Group","Mesh","MeshStandardMaterial","BufferAttribute","Group","MeshStandardMaterial","Mesh","BoxGeometry","CylinderGeometry","BufferAttribute","Mesh","MeshStandardMaterial","BufferAttribute","Mesh","MeshStandardMaterial","Color","Mesh","SphereGeometry","Color","Mesh","SphereGeometry","Group","Group","Mesh","MeshStandardMaterial","PlaneGeometry","PlaneGeometry","Mesh","MeshStandardMaterial","Color","PointLight","PointLight","Color","Mesh","BufferAttribute","BufferGeometry","Mesh","MeshStandardMaterial","Vector3","Vector3","BufferGeometry","BufferAttribute","Mesh","MeshStandardMaterial","Group","Group","Group","Mesh","Vector3","maxScale","Vector3","Group","Mesh"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "scena3d",
3
- "version": "0.1.0",
3
+ "version": "0.3.0",
4
4
  "description": "SCENA — SCenes & ENvironment Assets: a 3D world-building library on top of three.js. Seeded procedural props, terrain, sky and scattering — with gameplay metadata (obstacles, walkability) that game libraries like GAMA understand.",
5
5
  "type": "module",
6
6
  "main": "./dist/index.cjs",
@@ -56,6 +56,7 @@
56
56
  "devDependencies": {
57
57
  "@types/node": "^26.1.1",
58
58
  "@types/three": "^0.165.0",
59
+ "gama3d": "^0.9.0",
59
60
  "three": "^0.165.0",
60
61
  "tsup": "^8.0.0",
61
62
  "typescript": "^5.4.0",