import type { CameraPresetId, CrossSectionState, DisplayMode, MachineDefinition, MachinePart, MachinePartViewState, Vector3Tuple, } from '../modules/machines/schema'; import type { AnimationFrameState } from '../animations/types'; export type RenderQualityTier = 'mobile-low' | 'balanced' | 'desktop-high'; export interface SceneQualitySettings { tier: RenderQualityTier; shadowsEnabled: boolean; ambientOcclusionEnabled: boolean; maxDevicePixelRatio: number; particleBudget: number; annotationBudget: number; } export interface SceneCameraState { position: Vector3Tuple; target: Vector3Tuple; fov: number; preset?: CameraPresetId; } export interface SceneDisplayState { displayMode: DisplayMode; explodeDistance: number; annotationsVisible: boolean; crossSection: CrossSectionState; selectedPartId?: string; hoveredPartId?: string; partViewState: Record; } export interface MachineSceneBuildContext { machine: MachineDefinition; quality: SceneQualitySettings; display: SceneDisplayState; camera: SceneCameraState; reducedMotion: boolean; } export interface MachineScenePartBinding { part: MachinePart; objectName: string; selectable: boolean; receivesAnimation: boolean; defaultExplode: Vector3Tuple; } export interface MachineSceneAdapter { id: string; machineId: string; build(context: MachineSceneBuildContext): readonly MachineScenePartBinding[]; applyAnimation(frame: AnimationFrameState): void; applyDisplayState(display: SceneDisplayState): void; dispose(): void; } export const defaultSceneQualitySettings: SceneQualitySettings = { tier: 'balanced', shadowsEnabled: true, ambientOcclusionEnabled: true, maxDevicePixelRatio: 1.75, particleBudget: 1600, annotationBudget: 64, }; export const mobileSceneQualitySettings: SceneQualitySettings = { tier: 'mobile-low', shadowsEnabled: false, ambientOcclusionEnabled: false, maxDevicePixelRatio: 1.25, particleBudget: 500, annotationBudget: 32, }; export const desktopSceneQualitySettings: SceneQualitySettings = { tier: 'desktop-high', shadowsEnabled: true, ambientOcclusionEnabled: true, maxDevicePixelRatio: 2, particleBudget: 3000, annotationBudget: 96, };