export const CORE_MACHINE_IDS = [ 'four-stroke-petrol-engine', 'two-stroke-engine', 'diesel-engine', 'v8-engine', 'wankel-rotary-engine', 'steam-engine', 'jet-engine-turbojet', 'turbofan-engine', 'planetary-gearbox', 'differential-gear', 'manual-gearbox-5-speed', 'cvt', 'worm-gear-drive', 'bevel-gear-set', 'centrifugal-pump', 'gear-pump', 'piston-pump', 'hydraulic-cylinder', 'scotch-yoke', 'geneva-drive', 'cam-and-follower', 'rack-and-pinion', 'slider-crank', 'toggle-clamp', 'ball-bearing', 'roller-bearing', 'disc-brake-caliper', 'turbocharger', ] as const; export type CoreMachineId = (typeof CORE_MACHINE_IDS)[number]; export type MachineCategoryId = | 'engines' | 'gearboxes-drives' | 'pumps-fluid' | 'mechanisms' | 'structural-other'; export type Vector3Tuple = readonly [number, number, number]; export type EulerTuple = readonly [number, number, number]; export type CameraPresetId = | 'front' | 'back' | 'left' | 'right' | 'top' | 'bottom' | 'isometric' | 'section' | 'exploded' | 'flow'; export type ProceduralMaterialToken = | 'cast-iron' | 'dark-cast-iron' | 'brushed-steel' | 'polished-steel' | 'aluminium' | 'anodized-blue' | 'copper' | 'brass' | 'bronze' | 'rubber' | 'ceramic' | 'glass' | 'smoked-glass' | 'fuel' | 'diesel-spray' | 'steam' | 'hydraulic-fluid' | 'coolant' | 'hot-gas' | 'exhaust-gas' | 'intake-air' | 'lubricant' | 'carbon-friction' | 'warning-amber' | 'accent-blue' | 'accent-warm' | 'section-red' | 'transparent-shell' | 'ghosted' | 'label-anchor' | (string & {}); export type ProceduralPrimitiveKind = | 'group' | 'box' | 'rounded-box' | 'cylinder' | 'hollow-cylinder' | 'sphere' | 'torus' | 'disc' | 'gear' | 'ring-gear' | 'bevel-gear' | 'worm' | 'belt' | 'chain' | 'shaft' | 'rod' | 'link' | 'pipe' | 'manifold' | 'valve' | 'spring' | 'cam' | 'roller' | 'fan-stage' | 'compressor-stage' | 'turbine-stage' | 'impeller' | 'rotor-triangle' | 'epitrochoid-housing' | 'vane-wheel' | 'caliper-body' | 'fluid-volume' | 'flow-arrow' | 'heat-glow' | 'spark-pulse' | 'pressure-gauge' | 'load-arrow' | 'cutaway-plane' | 'polyline' | 'label-anchor' | (string & {}); export type ProceduralValue = | string | number | boolean | null | readonly number[] | readonly string[]; export type ProceduralMetadata = Readonly>; export interface ProceduralTransform { readonly position?: Vector3Tuple; readonly rotation?: EulerTuple; readonly scale?: Vector3Tuple; } export interface ProceduralMotionBinding { readonly channel: string; readonly kind: | 'continuous-rotation' | 'reciprocating-translation' | 'reciprocating-rotation' | 'timed-lift' | 'planetary-orbit' | 'geneva-index' | 'ratio-change' | 'flow-pulse' | 'visibility-pulse' | 'pressure-pulse' | 'heat-pulse' | 'custom-linkage' | (string & {}); readonly axis?: 'x' | 'y' | 'z'; readonly amplitude?: number; readonly phase?: number; readonly speedMultiplier?: number; readonly notes?: string; } export interface ProceduralNode { readonly id: string; readonly kind: ProceduralPrimitiveKind; readonly label?: string; readonly partId?: string; readonly material?: ProceduralMaterialToken; readonly transform?: ProceduralTransform; readonly dimensions?: ProceduralMetadata; readonly metadata?: ProceduralMetadata; readonly explodedOffset?: Vector3Tuple; readonly labelAnchor?: Vector3Tuple; readonly motionBindings?: readonly ProceduralMotionBinding[]; readonly children?: readonly ProceduralNode[]; } export interface ProceduralLabel { readonly id: string; readonly partId: string; readonly text: string; readonly anchorNodeId: string; readonly position: Vector3Tuple; readonly normal?: Vector3Tuple; readonly screenPriority?: number; } export interface AssetReplacementPoint { readonly id: string; readonly partId: string; readonly label: string; readonly anchorNodeId: string; readonly suggestedAssetPath: string; readonly preferredFormat: 'glb' | 'gltf'; readonly units: 'meters' | 'millimeters'; readonly origin: 'component-local-center' | 'machine-origin' | 'documented-pivot'; readonly upAxis: 'Y' | 'Z'; readonly notes: string; } export interface CatalogueThumbnailStrategy { readonly strategy: 'procedural-hero' | 'asset-render' | 'hybrid'; readonly cameraPreset: CameraPresetId; readonly accentPartIds: readonly string[]; readonly cropping: 'tight' | 'wide' | 'square'; readonly background: 'dark-radial' | 'transparent' | 'blueprint-grid'; readonly notes: string; } export interface ProceduralMachineBlueprint { readonly machineId: CoreMachineId; readonly title: string; readonly category: MachineCategoryId; readonly summary: string; readonly layout: 'cutaway' | 'sectioned' | 'exploded' | 'schematic' | 'hybrid'; readonly scaleMeters: number; readonly anchorPartId: string; readonly animationProfileId: string; readonly guidedTourStageIds: readonly string[]; readonly nodes: readonly ProceduralNode[]; readonly labels: readonly ProceduralLabel[]; readonly replacementPoints: readonly AssetReplacementPoint[]; readonly thumbnail: CatalogueThumbnailStrategy; readonly performanceNotes: readonly string[]; } export const isCoreMachineId = (value: string): value is CoreMachineId => (CORE_MACHINE_IDS as readonly string[]).includes(value);