export type Vec2 = [number, number]; export type Vec3 = [number, number, number]; export type Quaternion = [number, number, number, number]; export type InlineElementMaterial = { color?: string; roughness?: number; metalness?: number; }; export type ElementMaterial = InlineElementMaterial | { ref: string; }; /** * Immutable Vault material pin used by one or more semantic elements. * `fallback` is rendered before the descriptor and texture maps arrive. */ export type ElementMaterialPin = { assetId: string; revision: number; integritySha256: string; mimeType?: string; bytes?: number; fallback?: InlineElementMaterial; defaults?: { tint?: string; repeatPerMeter?: number; roughnessScale?: number; metalnessScale?: number; }; }; export type SceneElementRole = 'exterior' | 'interior' | 'structure' | 'detail'; export type ElementStreamPolicy = { mode?: 'eager' | 'distance' | 'portal'; priority?: number; }; /** Properties which resolve from the nearest ancestor before Scene compilation. */ export type CascadingElementProperties = { material?: ElementMaterial; collision?: boolean; role?: SceneElementRole; stream?: ElementStreamPolicy; }; type ArchitecturalElementBase = CascadingElementProperties & { id: string; }; export type WallElement = ArchitecturalElementBase & { type: 'wall'; start: Vec2; end: Vec2; baseY?: number; height: number; thickness: number; }; export type SlabElement = ArchitecturalElementBase & { type: 'floor' | 'ceiling'; center: Vec2; elevation: number; size: Vec2; thickness: number; }; export type BoxElement = ArchitecturalElementBase & { type: 'primitive'; shape: 'box'; position: Vec3; size: Vec3; /** Full source rotation for deterministic import/conversion workflows. */ rotation?: Quaternion; rotationYDeg?: number; slot?: string; }; export type ArchitecturalElement = WallElement | SlabElement | BoxElement; type LightElementBase = { id: string; type: 'light'; position: Vec3; color: string; luminousIntensityCandela: number; rangeM: number; /** Local orientation for spot lights; points down -Z when omitted. */ rotation?: Quaternion; rotationYDeg?: number; /** Local practical lights default to unshadowed for portable performance. */ castShadow?: boolean; shadowMapSize?: 256 | 512 | 1024 | 2048; }; export type PointLightElement = LightElementBase & { kind: 'point'; }; export type SpotLightElement = LightElementBase & { kind: 'spot'; innerConeDeg: number; outerConeDeg: number; }; export type LightElement = PointLightElement | SpotLightElement; type ContainerElementBase = CascadingElementProperties & { id: string; position?: Vec3; children: SceneElement[]; }; export type GroupElement = ContainerElementBase & { type: 'group'; }; export type LevelElement = ContainerElementBase & { type: 'level'; /** Local Y translation added to `position`, convenient for storeys. */ elevation?: number; }; export type SpaceElement = ContainerElementBase & { type: 'space'; }; export type ContainerElement = GroupElement | LevelElement | SpaceElement; export type SceneElement = ArchitecturalElement | LightElement | ContainerElement; type BuildingElementBase = CascadingElementProperties & { id: string; type: 'building'; position?: Vec3; }; export type BuildingElement = BuildingElementBase & { /** Version 2 semantic tree. */ children: SceneElement[]; elements?: never; }; export type LegacyBuildingElement = BuildingElementBase & { /** Version 1 flat input, retained for immutable authoring compatibility. */ elements: ArchitecturalElement[]; children?: never; }; /** * Creator-facing semantic document. Version 2 adds semantic containment and a * bounded compile-time cascade. It remains typed data rather than a runtime * DOM: there are no selectors, specificity rules, layout, or script. */ type SceneElementsDocumentBase = { format: 'helix.scene-elements'; id: string; title: string; materials?: Record; spawn: { position: Vec3; rotationYDeg?: number; }; }; export type SceneElementsDocument = SceneElementsDocumentBase & ({ version: 1; buildings: LegacyBuildingElement[]; } | { version: 2; buildings: BuildingElement[]; }); export {};