/** * The generator-asset seam: register a parametric asset generator (`generate(params, seed) → parts`) * so a slider-driven prop (a bookcase with width/shelves/book-density, a building with floors/bays) * lives in the catalog alongside static GLBs. A placed instance stores only `{ assetId, params, seed }` * — the geometry is re-resolved at runtime, never baked. Schema drives the inspector via #809. The * generic seam is engine; concrete generators (building, bookcase) are adopters registered from * game/example code — the building generator is the one engine adopter, as a proof it composes. * * @capability asset-generator seeded parametric geometry registered as a placeable asset */ import { type ParamSchema, type ParsedParams } from "./sceneKinds.js"; /** One generated primitive part — a box/panel placed in the asset's local space. */ export interface GeneratedPart { id: string; /** Optional semantic tag (shelf, board, book, wall, window …) for materials/inspection. */ kind?: string; /** Local-space center. */ position: readonly [number, number, number]; /** Full box dimensions (w, h, d) in meters. */ size: readonly [number, number, number]; rotationY?: number; /** Hex color; the renderer falls back to a neutral material when absent. */ color?: string; } /** A resolved generator asset: its parts plus the overall local-space bounds (min/max corners). */ export interface GeneratedAsset { parts: GeneratedPart[]; bounds: { min: readonly [number, number, number]; max: readonly [number, number, number]; }; /** * The declared local-space direction the asset's "front" faces (a bookcase's open/book face, a * building's entrance) — so a camera rig or placement tool can orient it without hand-tuned * `rotationY`. Omit to use the convention default, +Z (`DEFAULT_FORWARD` in `./facing`); every * generator should build its front toward +Z unless it declares otherwise. */ forward?: readonly [number, number, number]; } /** A registered asset generator — schema drives the inspector; `generate` is a pure seeded function. */ export interface AssetGeneratorDefinition { id: string; label: string; schema: ParamSchema; /** Deterministic geometry from validated params + a seed string. Same inputs → same parts. */ generate: (params: ParsedParams, seed: string) => GeneratedAsset; } /** Register a parametric asset generator. Idempotent per id (last wins); call at module load. */ export declare function registerAssetGenerator(definition: AssetGeneratorDefinition): void; /** The registered generator for an id, or undefined. @internal */ export declare function getAssetGenerator(id: string): AssetGeneratorDefinition | undefined; /** Every registered generator, in registration order. @internal */ export declare function listAssetGenerators(): AssetGeneratorDefinition[]; /** * Compute bounds from parts (each part is an axis-aligned box at its center) — a helper generators * return so callers can frame/ground the asset without re-deriving it. */ export declare function partsBounds(parts: readonly GeneratedPart[]): GeneratedAsset["bounds"]; /** * Re-resolve a placed generator instance from its stored `meta` (`{ assetId, seed, ...params }`): look * up the generator, parse its params off `meta` against the schema, and generate. Returns null when * `assetId` names no registered generator. This is what a runtime renderer calls per placed instance. * @internal */ export declare function resolveGeneratorAsset(meta: Record | undefined): GeneratedAsset | null;