import { Group, MeshStandardMaterial, Vector3, Scene, Object3D } from 'three'; import { c as Prop, O as Obstacle, b as Palette, P as PALETTES } from './types-C_yucwmh.js'; import { R as Room, T as Terrain, W as Water, S as Sky, b as LightingRig, D as DayCycle, j as WorldPath, L as LightingPreset, F as FogPreset } from './room-DIaNP0xj.js'; export { c as RoomHearth, d as RoomOptions, e as RoomWall, f as RoomWindow, p as createRoom } from './room-DIaNP0xj.js'; import { b as ScatterResult } from './scatter-DqtkmBLg.js'; export { P as Placement, S as ScatterItem, a as ScatterOptions, c as ScatterTile, s as scatter } from './scatter-DqtkmBLg.js'; interface VillageOptions { seed?: number; /** Village center in the XZ plane. Default origin. */ center?: { x: number; z: number; }; /** Ring radius the houses settle on. Default 12. */ radius?: number; /** House count. Default 5. */ houses?: number; /** Ground height lookup; a number means flat ground. Default 0. */ surface?: number | ((x: number, z: number) => number); /** Veto candidate spots (e.g. water, roads). Return false to reject. */ mask?: (x: number, z: number, y: number) => boolean; /** Add real PointLights to this many street lamps. Default 3. */ lampLights?: number; /** Add a watchtower at the edge. Default true. */ tower?: boolean; /** Add a ruin outside the ring. Default true. */ ruin?: boolean; palette?: Palette; } interface Village { group: Group; /** Every placed prop (houses, well, lamps, crates, tower, ruin). */ props: Prop[]; /** World-space steering obstacles — feed GAMA's ObstacleAvoidance. */ obstacles: Obstacle[]; /** * Props with something to ignite at night (street lamps AND house * windows). Pass straight to `createDayCycle({ lamps })`. */ lamps: Prop[]; /** One clearing circle covering the village — feed `scatter`'s keepOut. */ keepOut: Array<{ center: { x: number; z: number; }; radius: number; }>; center: { x: number; z: number; }; } /** * A seeded hamlet: a well at the center, houses ringed around it facing * inward, street lamps between them, crates by the doors, a watchtower on * the edge and a ruin beyond. Everything is placed on the given surface * (steep or masked spots are rejected and re-rolled), and the result * carries the full gameplay handshake: `obstacles` for steering, * `keepOut` for scatter, and `lamps` for the day-night cycle — windows * and lamps ignite together at dusk. * * ```ts * const village = createVillage({ seed: 5, radius: 10, surface: terrain.heightAt, palette }); * scene.add(village.group); * const cycle = createDayCycle({ sky, rig, scene, lamps: village.lamps, palette }); * const forest = scatter({ ..., keepOut: village.keepOut }); * ``` */ declare function createVillage(options?: VillageOptions): Village; interface BungalowOptions { seed?: number; /** Storeys: 1 or 2. Default 2. */ floors?: 1 | 2; /** Ground-floor footprint. Defaults seeded around 9 × 7. */ width?: number; depth?: number; palette?: Palette; } interface Bungalow { /** The villa, origin at ground level, entry facing +z. */ object: Group; /** Steering circle for the whole footprint. */ obstacleRadius: number; /** Every glass pane material — all `nightGlow`, ready for a day cycle. */ panes: MeshStandardMaterial[]; /** World-local point just outside the entry (spawn/walk-to target). */ entry: Vector3; } /** * A seeded modern bungalow — the Tier-4 materials composed into * architecture: a rendered ground box under a cantilevered concrete upper * box, floor-to-ceiling glazing on the garden face, a teak-slat or stone * accent, a balcony behind a glass or laser-cut railing, flat parapet * roofs, an entry canopy on steel posts and corten planters by the door. * * Every seed masses differently (cantilever side, accent style, glazing * rhythm, upper-box proportions); one palette themes the street. All the * glazing defaults to `nightGlow`, so listing the bungalow in a * `createDayCycle`'s `lamps` lights the house window-by-window at dusk. */ declare function createBungalow(options?: BungalowOptions): Bungalow; interface HighriseOptions { seed?: number; /** Storeys above the lobby. Default 8. */ floors?: number; /** Footprint. Defaults seeded around 12 × 10. */ width?: number; depth?: number; /** 'grid' punched windows in render, or full 'curtain' glazing. Seeded default. */ facade?: 'grid' | 'curtain'; /** Fraction of windows lit at night — the "who's home" mask. Default 0.55. */ occupancy?: number; palette?: Palette; } interface Highrise { /** The building, origin at ground level. */ object: Group; /** Steering circle for the footprint. */ obstacleRadius: number; /** Storeys above the lobby. */ floors: number; /** The occupied-window glass — `nightGlow`, day-cycle adoptable. */ litPanes: MeshStandardMaterial; /** How many of the tower's windows belong to the lit set. */ litCount: number; /** Total windows. */ windowCount: number; } /** * A multi-storey modern tower whose cost does NOT scale with height: every * repeated element — windows, spandrels, mullions, floor bands — is an * `InstancedMesh`, so a 30-floor tower draws the same handful of calls as a * 6-floor one. * * The facade is either **punched windows in render** (`'grid'`) or a full * **curtain wall** (`'curtain'`): glass units around all four faces, split * into two seeded sets — *occupied* windows use `nightGlow` glass, the rest * stay dark. List the tower in a `createDayCycle`'s `lamps` and the classic * random lit-window skyline appears at dusk for free. * * Below and above the shaft: a double-height glazed lobby with a steel * canopy, and a parapet roof carrying the plant room. */ declare function createHighrise(options?: HighriseOptions): Highrise; /** * The kit grid: every kit piece snaps to this cell size (in world units). * Shared snap dimensions are what make pieces combinable — a doorway cut * in one wall lines up with the corridor on the other side. */ declare const KIT_UNIT = 2; interface KitOptions { seed?: number; /** Cell size override. Default KIT_UNIT. */ unit?: number; /** Wall height. Default 2.6. */ wallHeight?: number; /** Add real PointLights to this many torches. Default 4. */ torchLights?: number; palette?: Palette; } interface Kit { group: Group; /** One obstacle per wall cell — feed GAMA's ObstacleAvoidance. */ obstacles: Obstacle[]; /** World positions of 'S' cells (player/NPC spawn points). */ spawns: Vector3[]; /** World positions of 'T' cells (torches), lit in placement order. */ torches: Vector3[]; /** Is (x, z) over a walkable floor cell? */ floorAt(x: number, z: number): boolean; /** Footprint in world units: { width, depth } centered on the origin. */ size: { width: number; depth: number; }; } /** * Assemble a dungeon/compound from an ASCII map — each character is one * KIT_UNIT × KIT_UNIT cell, centered on the group origin: * * - `#` wall block (blocks movement, becomes an obstacle) * - `.` floor tile * - `D` doorway: floor + lintel spanning the gap overhead * - `T` floor + standing torch (emissive flame; `createDayCycle` adopts it) * - `S` floor + recorded spawn point * - ` ` nothing * * ```ts * const fort = assembleKit([ * '#######', * '#..T..#', * '#.....D', * '#..S..#', * '#######', * ], { palette }); * fort.group.position.set(20, terrain.heightAt(20, 5), 5); * ``` * * Walls and floors render as two InstancedMeshes regardless of map size. */ declare function assembleKit(rows: string[], options?: KitOptions): Kit; type RoomRole = 'cottage' | 'tavern' | 'smithy' | 'bakery' | 'weaver' | 'study' | 'barracks'; interface FurnishOptions { seed?: number; /** What the room is for. Default 'cottage'. */ role?: RoomRole; palette?: Palette; } /** Named points ANIMA characters can use: where to sit, sleep, work, warm up. */ interface RoomMarkers { /** One per seat (chairs, stools, bench places, counter fronts). */ sit: Vector3[]; /** One per sleeping place (bed decks). */ sleep: Vector3[]; /** In front of each work utility (forge, oven, loom, counter, desk). */ work: Vector3[]; /** A spot in front of each hearth, for warming hands. */ hearth: Vector3[]; } interface Furnished { /** Everything placed, already added to `group`. */ props: Prop[]; /** Room-local steering circles for the placed furniture. */ obstacles: Obstacle[]; /** Room-local gameplay markers by kind. */ markers: RoomMarkers; /** The container — already a child of `room.group`. */ group: Group; } /** * Furnish a `createRoom` interior for a role, using the room's own grid: * beds and shelves go against walls facing inward, tables take the middle * (the rug if there is one), seats gather round, and the role's trade * utility — a tavern's counter, a smith's forge, a baker's oven, a * weaver-less study's book wall — anchors the room. Doorways stay clear, * nothing overlaps, and the same seed always furnishes the same way. * * The payoff for agents: `markers` — named, room-local points (`sit`, * `sleep`, `work`, `hearth`) a GAMA/ANIMA character can walk to and use, * and `obstacles` ready for steering. * * ```ts * const tavern = furnishRoom(room, { role: 'tavern', seed: 4 }); * guest.walkTo(room.group.localToWorld(tavern.markers.sit[0].clone())); * ``` */ declare function furnishRoom(room: Room, options?: FurnishOptions): Furnished; /** Prop vocabulary available to manifest scatters. */ type ScatterPropType = 'tree' | 'rock' | 'bush' | 'grass' | 'crate' | 'fence' | 'lamp'; interface ManifestScatterItem { type: ScatterPropType; weight?: number; variants?: number; scale?: [number, number]; } interface ManifestScatter { /** Defaults to the terrain footprint (slightly inset). */ area?: { min: { x: number; z: number; }; max: { x: number; z: number; }; }; density?: number; count?: number; minSpacing?: number; clumpScale?: number; items: ManifestScatterItem[]; /** Reject spots above this ground height (keep peaks bare). */ maxHeight?: number; /** Keep placements ashore. Default true when the scene has water. */ avoidWater?: boolean; /** Keep placements off paths and out of the village. Default true. */ avoidPaths?: boolean; /** Opt into tile-based LOD (see ScatterOptions.lod). */ lod?: { distance: number; tileSize?: number; }; } /** * A whole world as plain JSON — every field is data, so manifests can be * stored, diffed, sent over the network, or edited in a tool. */ interface SceneManifest { seed?: number; palette?: keyof typeof PALETTES; terrain?: { size?: number; resolution?: number; amplitude?: number; noiseScale?: number; octaves?: number; valleyFlatness?: number; }; water?: { level: number; size?: number; }; /** Sky dome. Default true. */ sky?: boolean; lighting?: LightingPreset; /** Fog preset, or false for none. Default 'haze'. */ fog?: FogPreset | false; /** Animated day-night cycle. Off unless specified. */ dayCycle?: { dayLength?: number; timeOfDay?: number; }; paths?: Array<{ points: Array<{ x: number; z: number; }>; width?: number; loop?: boolean; }>; village?: { center?: { x: number; z: number; }; radius?: number; houses?: number; lampLights?: number; tower?: boolean; ruin?: boolean; }; scatters?: ManifestScatter[]; /** Vegetation sway. Default on; false disables, or set the strength. */ wind?: boolean | { strength?: number; }; } interface BuiltScene { /** Everything visual, ready to add to a scene (already added if one was passed). */ group: Group; palette: Palette; terrain?: Terrain; water?: Water; sky?: Sky; rig: LightingRig; cycle?: DayCycle; paths: WorldPath[]; village?: Village; scatters: ScatterResult[]; /** Combined steering obstacles from the village and every scatter. */ obstacles: Obstacle[]; /** Ground height (terrain's, or 0 for flat scenes). */ heightAt(x: number, z: number): number; /** Advance water, wind and the day cycle. Call from your frame loop. */ update(dt: number): void; } /** * Compile a `SceneManifest` into a live world: terrain, water, sky, * lighting, fog, paths, a village, scatters and the day cycle — with all * the cross-feature wiring the forest demo does by hand applied * automatically (scatters stay ashore, off paths and out of the village; * the village avoids water and roads; village lamps and windows feed the * day cycle). * * ```ts * const world = buildScene(JSON.parse(manifestJson), scene); * game.onUpdate((t) => world.update(t.delta)); * agent.addBehavior(new ObstacleAvoidance(() => world.obstacles)); * ``` */ declare function buildScene(manifest: SceneManifest, scene?: Scene): BuiltScene; interface Markers { /** `spawn_` → world position. */ spawns: Record; /** `route__` → world positions ordered by index. */ routes: Record; /** `obstacle_` → steering obstacle (radius from the node's scale). */ obstacles: Obstacle[]; /** `keepout_` → scatter keep-out circle (radius from scale). */ keepOut: Array<{ center: { x: number; z: number; }; radius: number; }>; } /** * Extract gameplay markers from an object tree by naming convention — the * bridge between a DCC tool (Blender empties, glTF nodes) and SCENA/GAMA: * * - `spawn_player`, `spawn_boss` → named spawn points * - `route_patrol_0`, `route_patrol_1`, … → ordered patrol routes * - `obstacle_statue` → steering obstacle; radius = max(scale.x, scale.z) * - `keepout_plaza` → scatter keep-out circle; radius = max(scale.x, scale.z) * * Blender's duplicate suffixes (`.001`) are stripped, so `route_a_0.001` * still parses. Positions are world-space (the tree is updated first). * * ```ts * const gltf = await new GLTFLoader().loadAsync('level.glb'); * const markers = extractMarkers(gltf.scene); * player.position.copy(markers.spawns.player); * guard.addBehavior(new FollowPath(new Path(markers.routes.patrol, true), 1.5)); * scatter({ ..., keepOut: markers.keepOut }); * ``` */ declare function extractMarkers(root: Object3D): Markers; export { type BuiltScene, type Bungalow, type BungalowOptions, type FurnishOptions, type Furnished, type Highrise, type HighriseOptions, KIT_UNIT, type Kit, type KitOptions, type ManifestScatter, type ManifestScatterItem, type Markers, Room, type RoomMarkers, type RoomRole, type ScatterPropType, ScatterResult, type SceneManifest, type Village, type VillageOptions, assembleKit, buildScene, createBungalow, createHighrise, createVillage, extractMarkers, furnishRoom };