/** * StudioManager — orchestrates Studio mode rendering. * * Extracted from viewer.ts to reduce its complexity. Owns the Studio-specific * resources (composer, floor, shadow lights, environment manager) and handles * all Studio subscriptions and mode enter/leave logic. * * Communicates with the Viewer via the StudioManagerContext interface to avoid * a circular dependency. */ import * as THREE from "three"; import { EnvironmentManager } from "../rendering/environment.js"; import { StudioFloor } from "../rendering/studio-floor.js"; import { ViewerState } from "./viewer-state.js"; import type { NestedGroup, ObjectGroup } from "../scene/nestedgroup.js"; import type { Camera } from "../camera/camera.js"; import type { Clipping } from "../scene/clipping.js"; import type { BoundingBox } from "../scene/bbox.js"; /** * Abstraction over Viewer that StudioManager uses. Keeps the dependency * one-directional (StudioManager → context, never StudioManager → Viewer). */ export interface StudioManagerContext { renderer: THREE.WebGLRenderer; state: ViewerState; /** Whether viewer has rendered content. */ isRendered(): boolean; getScene(): THREE.Scene; getCamera(): Camera; getAmbientLight(): THREE.AmbientLight; getDirectLight(): THREE.DirectionalLight; getNestedGroup(): NestedGroup; getClipping(): Clipping; getBbox(): BoundingBox | null; getLastBboxId(): string | null; setAxes(flag: boolean, notify?: boolean): void; setGrids(grids: [boolean, boolean, boolean], notify?: boolean): void; setOrtho(flag: boolean, notify?: boolean): void; update(updateMarker: boolean, notify?: boolean): void; dispatchEvent(event: Event): void; onSelectionChanged(id: string | null): void; } declare class StudioManager { readonly envManager: EnvironmentManager; readonly floor: StudioFloor; private _composer; private _active; private _savedClippingState; private _shadowLights; private _ctx; /** * Renderer pixel ratio saved on Studio entry, restored on leave. * Studio mode bumps the pixel ratio to apply supersampling, which * compensates for low DPR (e.g., VSCode webviews report DPR=1 even * on Retina displays) and improves AA on shallow-angle edges. */ private _savedPixelRatio; constructor(ctx: StudioManagerContext); get isActive(): boolean; get hasComposer(): boolean; /** Render via composer (call from Viewer.update / _animate). */ render(): void; /** Update composer camera (call from Viewer.switchCamera). */ setCamera(camera: THREE.Camera): void; /** Resize composer (call from Viewer.resize). */ setSize(width: number, height: number): void; /** Whether env background needs per-frame update. */ get isEnvBackgroundActive(): boolean; /** Update env background (ortho workaround, call per frame). */ updateEnvBackground(renderer: THREE.WebGLRenderer, camera: THREE.Camera): void; /** Check if an environment name is a Poly Haven preset. */ isEnvPreset(name: string): boolean; /** * Get the ObjectGroup and path for the currently selected object. * Returns null if nothing selected or Studio mode inactive. */ getSelectedObjectGroup(): { object: ObjectGroup; path: string; } | null; enterStudioMode: () => Promise; leaveStudioMode: () => void; resetStudio: () => void; /** * Dispose all Studio resources. Called from Viewer.dispose(). * Must be called BEFORE renderer.dispose(). */ dispose(): void; private _setupSubscriptions; private _configureFloor; private _configureShadowLights; private _removeShadowLights; private _setShadowsEnabled; private _applyToneMapping; private _rebuildMaterials; } export { StudioManager };