@zkmake/three-cameras 0.0.0 → 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1 +0,0 @@
1
- {"version":3,"file":"lab-D4PnOVwG.js","names":[],"sources":["../src/core/discover.ts","../src/core/pose.ts","../src/core/lab.ts"],"sourcesContent":["/**\n * Find the cameras under a scene, and tell them apart. A `CubeCamera` is one entry (its six face\n * cameras are its own business); an `ArrayCamera`'s sub-cameras aren't children, so they never show.\n */\nimport type { Camera, Object3D, OrthographicCamera, PerspectiveCamera } from \"three\";\n\nexport type CameraKind = \"perspective\" | \"orthographic\" | \"array\" | \"cube\" | \"other\";\n\n/** A camera, or a `CubeCamera`, which is an `Object3D` holding six. */\nexport type SceneCamera = Camera | Object3D;\n\nexport const isCubeCamera = (object: Object3D) => object.type === \"CubeCamera\";\n\nexport const isCamera = (object: Object3D): object is Camera =>\n (object as Camera).isCamera === true;\n\nexport const kindOf = (camera: SceneCamera): CameraKind => {\n if (isCubeCamera(camera)) {\n return \"cube\";\n }\n\n // An ArrayCamera is a PerspectiveCamera too: check it first.\n if ((camera as { isArrayCamera?: boolean }).isArrayCamera) {\n return \"array\";\n }\n\n if ((camera as PerspectiveCamera).isPerspectiveCamera) {\n return \"perspective\";\n }\n\n if ((camera as OrthographicCamera).isOrthographicCamera) {\n return \"orthographic\";\n }\n\n return \"other\";\n};\n\n/** Every camera under `root`, in scene order, `root` included. */\nexport const findCameras = (root: Object3D): SceneCamera[] => {\n const found: SceneCamera[] = [];\n\n const visit = (object: Object3D) => {\n if (isCubeCamera(object)) {\n found.push(object);\n\n return;\n }\n\n if (isCamera(object)) {\n found.push(object);\n }\n\n for (const child of object.children) {\n visit(child);\n }\n };\n\n visit(root);\n\n return found;\n};\n\n/** Where it sits: its ancestors' names (or types) from the root down, `scene › rig › cam`. */\nexport const pathOf = (object: Object3D): string[] => {\n const path: string[] = [];\n\n for (let node: Object3D | null = object.parent; node; node = node.parent) {\n path.unshift(node.name || node.type);\n }\n\n return path;\n};\n","/**\n * A camera's pose: where it is, which way it faces, and how it projects. Poses are what saved\n * views hold now and what keyframes will: capture one, put one back, and blend between two.\n *\n * Position and rotation are the camera's own (local, relative to its parent), so a pose put back\n * lands where it was taken even if the parent has moved since, the same way a keyframe would.\n */\nimport { Quaternion, Vector3 } from \"three\";\nimport type { Camera, OrthographicCamera, PerspectiveCamera } from \"three\";\n\nexport type Pose = {\n position: [number, number, number];\n /** x, y, z, w. */\n quaternion: [number, number, number, number];\n near: number;\n far: number;\n zoom: number;\n /** Perspective cameras only. */\n fov?: number;\n};\n\ntype Projecting = PerspectiveCamera | OrthographicCamera;\n\nconst isPerspective = (camera: Camera): camera is PerspectiveCamera =>\n (camera as PerspectiveCamera).isPerspectiveCamera === true;\n\nconst projects = (camera: Camera): camera is Projecting =>\n isPerspective(camera) || (camera as OrthographicCamera).isOrthographicCamera === true;\n\nexport const capturePose = (camera: Camera): Pose => {\n const { position, quaternion } = camera;\n const pose: Pose = {\n position: [position.x, position.y, position.z],\n quaternion: [quaternion.x, quaternion.y, quaternion.z, quaternion.w],\n near: 0,\n far: 0,\n zoom: 1,\n };\n\n if (projects(camera)) {\n pose.near = camera.near;\n pose.far = camera.far;\n pose.zoom = camera.zoom;\n }\n\n if (isPerspective(camera)) {\n pose.fov = camera.fov;\n }\n\n return pose;\n};\n\nexport const applyPose = (camera: Camera, pose: Pose) => {\n camera.position.fromArray(pose.position);\n camera.quaternion.fromArray(pose.quaternion);\n\n if (projects(camera)) {\n camera.near = pose.near;\n camera.far = pose.far;\n camera.zoom = pose.zoom;\n\n if (isPerspective(camera) && pose.fov !== undefined) {\n camera.fov = pose.fov;\n }\n\n camera.updateProjectionMatrix();\n }\n};\n\nconst lerp = (a: number, b: number, t: number) => a + (b - a) * t;\n\nconst from = new Quaternion();\nconst to = new Quaternion();\nconst va = new Vector3();\nconst vb = new Vector3();\n\n/** The pose `t` of the way from `a` to `b`: positions and lenses straight, rotation by slerp. */\nexport const blendPoses = (a: Pose, b: Pose, t: number): Pose => {\n const position = va.fromArray(a.position).lerp(vb.fromArray(b.position), t);\n const quaternion = from.fromArray(a.quaternion).slerp(to.fromArray(b.quaternion), t);\n const pose: Pose = {\n position: [position.x, position.y, position.z],\n quaternion: [quaternion.x, quaternion.y, quaternion.z, quaternion.w],\n near: lerp(a.near, b.near, t),\n far: lerp(a.far, b.far, t),\n zoom: lerp(a.zoom, b.zoom, t),\n };\n\n if (a.fov !== undefined && b.fov !== undefined) {\n pose.fov = lerp(a.fov, b.fov, t);\n }\n\n return pose;\n};\n\n/** Slow in, slow out: a camera move that starts and settles gently. */\nexport const easeInOut = (t: number) => (t < 0.5 ? 4 * t * t * t : 1 - Math.pow(-2 * t + 2, 3) / 2);\n\nconst round = (value: number, digits = 4) => {\n const text = value.toFixed(digits);\n\n return text.includes(\".\") ? text.replace(/\\.?0+$/, \"\") : text;\n};\n\n/** Three.js to recreate the pose on a camera called `name`. */\nexport const poseToCode = (pose: Pose, name = \"camera\") => {\n const [x, y, z, w] = pose.quaternion;\n const lines = [\n `${name}.position.set(${pose.position.map((value) => round(value)).join(\", \")});`,\n `${name}.quaternion.set(${[x, y, z, w].map((value) => round(value, 5)).join(\", \")});`,\n ];\n\n if (pose.fov !== undefined) {\n lines.push(`${name}.fov = ${round(pose.fov, 2)};`);\n }\n\n if (pose.zoom !== 1) {\n lines.push(`${name}.zoom = ${round(pose.zoom, 3)};`);\n }\n\n lines.push(`${name}.near = ${round(pose.near)};`, `${name}.far = ${round(pose.far)};`);\n lines.push(`${name}.updateProjectionMatrix();`);\n\n return lines.join(\"\\n\");\n};\n","/**\n * `CameraLab`: the cameras a scene has and the ones drawing it. No UI; the panel drives it.\n *\n * Cameras come from two places: the scene graph, and the renderer. The camera an app renders with\n * is often not in the scene at all (R3F's default camera isn't; most vanilla apps never add\n * theirs), so the lab wraps `renderer.render` and notes every camera it's handed: that's how it\n * knows which are live, and how often each draws.\n *\n * Entries are named by the `cameras` option, else the camera's name, else its kind, numbered when\n * they repeat. A name holds for as long as the camera is listed, and saved views are kept by it.\n *\n * The same watch lets the lab act on frames: \"look through\" hands the renderer another camera in\n * place of the app's main one (fitted to its aspect for that frame), and a move to a saved view\n * steps once per frame, before the frame draws.\n */\nimport {\n type Camera,\n CameraHelper,\n Euler,\n type Object3D,\n type OrthographicCamera,\n type PerspectiveCamera,\n Quaternion,\n Vector3,\n Vector4,\n} from \"three\";\n\nimport {\n type CameraKind,\n findCameras,\n isCamera,\n kindOf,\n pathOf,\n type SceneCamera,\n} from \"./discover.ts\";\nimport { applyPose, blendPoses, capturePose, easeInOut, type Pose } from \"./pose.ts\";\n\nexport type CameraInfo = {\n name: string;\n camera: SceneCamera;\n};\n\n/** The part of a renderer the lab needs: `render(scene, camera)`. */\nexport type RendererLike = {\n render: (scene: Object3D, camera: Camera, ...rest: never[]) => unknown;\n};\n\nexport type CameraLabOptions = {\n /** Where to look for cameras, and where frustum helpers go. */\n scene: Object3D;\n /** A three renderer: its `render` is watched, so cameras outside the scene show up and live ones are marked. */\n renderer?: unknown;\n /** Cameras to list whether or not the scene holds them yet, with names. */\n cameras?: readonly CameraInfo[];\n /** Ask for a frame, for render-on-demand loops (R3F `frameloop=\"demand\"`). */\n invalidate?: () => void;\n /** Where saved views live. Default: this page only. */\n store?: ViewStore;\n};\n\n/** A pose saved on a camera, to go back to. */\nexport type SavedView = {\n id: string;\n name: string;\n pose: Pose;\n};\n\n/** Saved views by camera name. `mountCameraPanel` keeps them in localStorage. */\nexport type ViewStore = {\n load(): Record<string, SavedView[]>;\n save(views: Record<string, SavedView[]>): void;\n};\n\n/** Values to set on a camera. Position and rotation are its own (local); rotation in degrees. */\nexport type CameraPatch = {\n position?: readonly [number, number, number];\n rotation?: readonly [number, number, number];\n fov?: number;\n near?: number;\n far?: number;\n zoom?: number;\n};\n\nexport type CameraEntry = {\n id: string;\n kind: CameraKind;\n camera: SceneCamera;\n /** Under the lab's scene. A camera only the renderer knows about isn't. */\n inScene: boolean;\n /** Drew a frame in the last half second. */\n live: boolean;\n /** Frames drawn with it in the last second. */\n fps: number;\n /** Its frustum helper is showing. */\n helper: boolean;\n /** A frustum helper can draw it: perspective and orthographic cameras. */\n canHelp: boolean;\n /** Its ancestors, root first. */\n path: string[];\n /** Perspective or orthographic: its lens can be edited, looked through and saved. */\n projects: boolean;\n /** The main view shows through it now. */\n viewing: boolean;\n /** The app's camera that it's standing in for, while another is looked through. */\n standingIn: boolean;\n /** Saved views on it. */\n views: number;\n};\n\nexport type Projection = {\n near: number;\n far: number;\n zoom: number;\n /** Perspective: vertical field of view in degrees, and aspect. */\n fov?: number;\n aspect?: number;\n /** Orthographic: the frustum's sides. */\n left?: number;\n right?: number;\n top?: number;\n bottom?: number;\n};\n\nexport type CameraDetails = {\n /** World position. */\n position: [number, number, number];\n /** World rotation, XYZ Euler in degrees. */\n rotation: [number, number, number];\n /** Its own position and rotation (degrees), relative to its parent: what `set` changes. */\n local: {\n position: [number, number, number];\n rotation: [number, number, number];\n };\n projection: Projection | null;\n};\n\ntype Tween = { from: Pose; to: Pose; start: number; duration: number };\n\ntype Item = {\n id: string;\n camera: SceneCamera;\n kind: CameraKind;\n helper: CameraHelper | null;\n /** When each of the last second's frames drew, ms. */\n frames: number[];\n /** Screen pixels its last frame drew into; 0 for a render target. How the main view is told apart. */\n area: number;\n};\n\n/** What the lab reads off a WebGL or WebGPU renderer, when it has them. */\ntype Viewported = {\n getCurrentViewport?: (target: Vector4) => Vector4;\n getRenderTarget?: () => unknown;\n};\n\n/** Rendered this recently counts as live, ms. */\nconst LIVE_MS = 500;\n/** A camera outside the scene stays listed this long after its last frame, ms. */\nconst KEEP_MS = 5000;\n/** A move to a saved view, ms. */\nconst MOVE_MS = 800;\n\nconst memoryViews = (): ViewStore => {\n let views: Record<string, SavedView[]> = {};\n\n return {\n load: () => views,\n save: (next) => {\n views = next;\n },\n };\n};\n\nconst KIND_LABELS: Record<CameraKind, string> = {\n perspective: \"perspective\",\n orthographic: \"orthographic\",\n array: \"array\",\n cube: \"cube\",\n other: \"camera\",\n};\n\nconst now = () => (typeof performance === \"undefined\" ? Date.now() : performance.now());\n\nconst toDegrees = (radians: number) => (radians * 180) / Math.PI;\nconst toRadians = (degrees: number) => (degrees * Math.PI) / 180;\n\nconst projectionOf = (camera: SceneCamera, kind: CameraKind): Projection | null => {\n if (kind === \"perspective\" || kind === \"array\") {\n const { near, far, zoom, fov, aspect } = camera as PerspectiveCamera;\n\n return { near, far, zoom, fov, aspect };\n }\n\n if (kind === \"orthographic\") {\n const { near, far, zoom, left, right, top, bottom } = camera as OrthographicCamera;\n\n return { near, far, zoom, left, right, top, bottom };\n }\n\n return null;\n};\n\nexport class CameraLab {\n private readonly options: CameraLabOptions;\n private readonly records = new Map<SceneCamera, Item>();\n private readonly byId = new Map<string, Item>();\n private readonly listeners = new Set<() => void>();\n private readonly tweens = new Map<Item, Tween>();\n private readonly store: ViewStore;\n private saved: Record<string, SavedView[]>;\n private restoreRender: (() => void) | null = null;\n /** Look-through: the camera shown, and the app camera it stands in for. */\n private looking: Item | null = null;\n private standIn: Camera | null = null;\n /** The frame being drawn: what to put back after it. */\n private fitted: { camera: PerspectiveCamera; aspect: number } | null = null;\n private readonly viewport = new Vector4();\n private notifyQueued = false;\n private disposed = false;\n\n constructor(options: CameraLabOptions) {\n this.options = options;\n this.store = options.store ?? memoryViews();\n this.saved = { ...this.store.load() };\n this.watch(options.renderer);\n this.refresh();\n }\n\n /** Whether the lab sees frames: look-through and animated moves need a renderer. */\n get watching() {\n return this.restoreRender !== null;\n }\n\n subscribe(listener: () => void) {\n this.listeners.add(listener);\n\n return () => {\n this.listeners.delete(listener);\n };\n }\n\n /** Every camera, in scene order; ones only the renderer knows about after. */\n entries(): CameraEntry[] {\n const time = now();\n\n return [...this.byId.values()].map((item) => this.entryOf(item, time));\n }\n\n entry(id: string): CameraEntry | null {\n const item = this.byId.get(id);\n\n return item ? this.entryOf(item, now()) : null;\n }\n\n /** Where it is and how it projects, read now. */\n details(id: string): CameraDetails | null {\n const item = this.byId.get(id);\n\n if (!item) {\n return null;\n }\n\n const { camera } = item;\n const position = new Vector3();\n const quaternion = new Quaternion();\n\n camera.updateWorldMatrix(true, false);\n camera.matrixWorld.decompose(position, quaternion, new Vector3());\n\n const euler = new Euler().setFromQuaternion(quaternion);\n const own = camera.rotation;\n\n return {\n position: [position.x, position.y, position.z],\n rotation: [toDegrees(euler.x), toDegrees(euler.y), toDegrees(euler.z)],\n local: {\n position: [camera.position.x, camera.position.y, camera.position.z],\n rotation: [toDegrees(own.x), toDegrees(own.y), toDegrees(own.z)],\n },\n projection: projectionOf(camera, item.kind),\n };\n }\n\n /**\n * Change a camera: its own position or rotation, or its lens. The projection updates, and a\n * render-on-demand loop gets a frame. An app that sets the camera every frame wins on the next.\n */\n set(id: string, patch: CameraPatch) {\n const item = this.require(id);\n const camera = item.camera;\n\n if (patch.position) {\n camera.position.set(...patch.position);\n }\n\n if (patch.rotation) {\n const [x, y, z] = patch.rotation.map(toRadians) as [number, number, number];\n\n camera.rotation.set(x, y, z);\n }\n\n if (this.projects(item)) {\n const lens = camera as PerspectiveCamera | OrthographicCamera;\n\n if (patch.near !== undefined) {\n lens.near = patch.near;\n }\n\n if (patch.far !== undefined) {\n lens.far = patch.far;\n }\n\n if (patch.zoom !== undefined) {\n lens.zoom = patch.zoom;\n }\n\n if (patch.fov !== undefined && item.kind === \"perspective\") {\n (lens as PerspectiveCamera).fov = patch.fov;\n }\n\n lens.updateProjectionMatrix();\n }\n\n this.tweens.delete(item);\n this.options.invalidate?.();\n }\n\n /**\n * Show the main view through `id`, or back through the app's own camera with `null`. The camera\n * it stands in for is the app's main view: the one drawing the most of the screen (a\n * picture-in-picture inset or a render target loses to it), most often on a tie.\n */\n lookThrough(id: string | null) {\n if (id === null || this.looking?.id === id) {\n this.looking = null;\n this.standIn = null;\n } else {\n const item = this.require(id);\n\n if (!this.projects(item)) {\n throw new Error(`three-cameras: \"${id}\" can't be looked through (${item.kind})`);\n }\n\n const time = now();\n const main = [...this.records.values()]\n .filter((other) => other !== item && isCamera(other.camera))\n .map((other) => ({ other, fps: other.frames.filter((at) => time - at <= 1000).length }))\n .filter(({ fps }) => fps > 0)\n .sort((a, b) => b.other.area - a.other.area || b.fps - a.fps)[0];\n\n if (!main) {\n throw new Error(\"three-cameras: no camera is drawing, so there's no view to look through\");\n }\n\n this.looking = item;\n this.standIn = main.other.camera as Camera;\n }\n\n this.options.invalidate?.();\n this.notify();\n }\n\n /** Save where the camera is and how it projects, as a view to go back to. */\n saveView(id: string, name?: string): SavedView {\n const item = this.require(id);\n\n if (!this.projects(item)) {\n throw new Error(`three-cameras: \"${id}\" has no lens to save (${item.kind})`);\n }\n\n const list = this.saved[id] ?? [];\n const taken = new Set(list.map((view) => view.name));\n let label = name ?? `view ${list.length + 1}`;\n\n for (let n = 2; taken.has(label); n += 1) {\n label = `${name ?? \"view\"} ${n}`;\n }\n\n const view: SavedView = {\n id: `${Date.now().toString(36)}${Math.random().toString(36).slice(2, 6)}`,\n name: label,\n pose: capturePose(item.camera as Camera),\n };\n\n this.saved = { ...this.saved, [id]: [...list, view] };\n this.store.save(this.saved);\n this.notify();\n\n return view;\n }\n\n views(id: string): SavedView[] {\n return this.saved[id] ?? [];\n }\n\n deleteView(id: string, viewId: string) {\n const list = this.saved[id] ?? [];\n\n this.saved = { ...this.saved, [id]: list.filter((view) => view.id !== viewId) };\n this.store.save(this.saved);\n this.notify();\n }\n\n /**\n * Move the camera to a saved view: eased over `duration` ms, stepped once per frame (so it needs\n * a renderer; without one, or with `duration: 0`, it lands at once).\n */\n goToView(id: string, viewId: string, { duration = MOVE_MS }: { duration?: number } = {}) {\n const item = this.require(id);\n const view = this.views(id).find((saved) => saved.id === viewId);\n\n if (!view) {\n throw new Error(`three-cameras: \"${id}\" has no saved view \"${viewId}\"`);\n }\n\n const camera = item.camera as Camera;\n\n if (duration <= 0 || !this.watching) {\n this.tweens.delete(item);\n applyPose(camera, view.pose);\n } else {\n this.tweens.set(item, { from: capturePose(camera), to: view.pose, start: now(), duration });\n }\n\n this.options.invalidate?.();\n }\n\n /**\n * Look at the scene again: new cameras get entries, ones that left go (a camera outside the\n * scene stays while it's still rendering, and a few seconds after).\n */\n refresh() {\n if (this.disposed) {\n return;\n }\n\n const time = now();\n const listed = new Set<SceneCamera>();\n let changed = false;\n\n for (const camera of findCameras(this.options.scene)) {\n listed.add(camera);\n }\n\n for (const info of this.options.cameras ?? []) {\n listed.add(info.camera);\n }\n\n for (const [camera, item] of this.records) {\n const last = item.frames.at(-1);\n\n if ((last !== undefined && time - last < KEEP_MS) || camera === this.standIn) {\n listed.add(camera);\n }\n }\n\n for (const camera of listed) {\n if (!this.records.has(camera)) {\n this.add(camera);\n changed = true;\n }\n }\n\n for (const [camera, item] of this.records) {\n if (!listed.has(camera)) {\n this.remove(item);\n changed = true;\n }\n }\n\n if (this.looking && !this.records.has(this.looking.camera)) {\n this.looking = null;\n this.standIn = null;\n }\n\n if (changed) {\n this.notify();\n }\n }\n\n /** Show or hide a camera's frustum. The helper sits in the lab's scene and follows the camera. */\n setHelper(id: string, on: boolean) {\n const item = this.require(id);\n\n if (on === (item.helper !== null)) {\n return;\n }\n\n if (on) {\n if (!this.canHelp(item)) {\n throw new Error(`three-cameras: \"${id}\" has no frustum to draw (${item.kind})`);\n }\n\n const helper = new CameraHelper(item.camera as Camera);\n\n helper.name = `${id} (three-cameras helper)`;\n helper.userData.threeCameras = true;\n this.options.scene.add(helper);\n item.helper = helper;\n } else {\n this.dropHelper(item);\n }\n\n this.options.invalidate?.();\n this.notify();\n }\n\n dispose() {\n this.disposed = true;\n\n for (const item of this.records.values()) {\n this.dropHelper(item);\n }\n\n this.looking = null;\n this.standIn = null;\n this.tweens.clear();\n this.restoreRender?.();\n this.restoreRender = null;\n this.listeners.clear();\n }\n\n private watch(renderer: unknown) {\n const target = renderer as Partial<RendererLike> | null | undefined;\n\n if (!target || typeof target.render !== \"function\") {\n return;\n }\n\n const render = target.render;\n const own = Object.hasOwn(target, \"render\");\n const before = (camera: Camera, host: unknown) => this.beforeFrame(camera, host);\n const after = () => this.afterFrame();\n const watched = function (this: unknown, scene: Object3D, camera: Camera, ...rest: never[]) {\n const shown = before(camera, this);\n\n try {\n return render.call(this, scene, shown, ...rest);\n } finally {\n after();\n }\n };\n\n target.render = watched;\n this.restoreRender = () => {\n // Someone wrapped it after us: leave theirs in place; ours passes through once disposed.\n if (target.render !== watched) {\n return;\n }\n\n if (own) {\n target.render = render;\n } else {\n delete target.render;\n }\n };\n }\n\n /** Before a frame: count it, step moves, and pick the camera it's drawn with. */\n private beforeFrame(camera: Camera, host: unknown): Camera {\n if (this.disposed || !camera) {\n return camera;\n }\n\n const time = now();\n\n this.count(camera, time);\n this.measure(camera, host as Viewported | null);\n this.step(time);\n\n let shown = camera;\n\n if (this.looking && camera === this.standIn) {\n shown = this.looking.camera as Camera;\n this.count(shown, time);\n\n // Fit it to the view it's drawn into for this frame; afterFrame puts its aspect back.\n const lens = shown as PerspectiveCamera;\n const view = camera as PerspectiveCamera;\n\n if (lens.isPerspectiveCamera && view.isPerspectiveCamera && lens.aspect !== view.aspect) {\n this.fitted = { camera: lens, aspect: lens.aspect };\n lens.aspect = view.aspect;\n lens.updateProjectionMatrix();\n }\n }\n\n // Frustums follow their cameras; the one being looked through hides its own.\n for (const other of this.records.values()) {\n if (other.helper) {\n other.helper.visible = other.camera !== shown;\n other.helper.update();\n }\n }\n\n return shown;\n }\n\n private afterFrame() {\n if (this.fitted) {\n this.fitted.camera.aspect = this.fitted.aspect;\n this.fitted.camera.updateProjectionMatrix();\n this.fitted = null;\n }\n }\n\n /** How much of the screen this frame covers, if the renderer says. */\n private measure(camera: Camera, host: Viewported | null) {\n const item = this.records.get(camera);\n\n if (!item || typeof host?.getCurrentViewport !== \"function\") {\n return;\n }\n\n const offscreen = typeof host.getRenderTarget === \"function\" && host.getRenderTarget() !== null;\n const viewport = host.getCurrentViewport(this.viewport);\n\n item.area = offscreen ? 0 : viewport.z * viewport.w;\n }\n\n private count(camera: Camera, time: number) {\n const item = this.records.get(camera);\n\n if (item) {\n item.frames.push(time);\n\n while (item.frames.length > 0 && time - item.frames[0]! > 1000) {\n item.frames.shift();\n }\n } else if (this.findOwner(camera) === null) {\n // A new camera: listed now, with this frame counted. Listeners hear after the frame.\n this.add(camera).frames.push(time);\n this.notifySoon();\n }\n }\n\n /** Moves to saved views, one step per frame. */\n private step(time: number) {\n if (this.tweens.size === 0) {\n return;\n }\n\n for (const [item, tween] of this.tweens) {\n const t = Math.min(1, (time - tween.start) / tween.duration);\n\n applyPose(item.camera as Camera, blendPoses(tween.from, tween.to, easeInOut(t)));\n\n if (t >= 1) {\n this.tweens.delete(item);\n }\n }\n\n // Keep frames coming until the move lands, for render-on-demand loops.\n this.options.invalidate?.();\n }\n\n /** A camera the renderer was handed that belongs to one listed, like a CubeCamera's faces. */\n private findOwner(camera: Camera) {\n for (let node: Object3D | null = camera.parent; node; node = node.parent) {\n if (this.records.has(node)) {\n return node;\n }\n }\n\n return null;\n }\n\n private canHelp(item: Item) {\n return this.projects(item);\n }\n\n private projects(item: Item) {\n return item.kind === \"perspective\" || item.kind === \"orthographic\";\n }\n\n private add(camera: SceneCamera): Item {\n const kind = kindOf(camera);\n const registered = this.options.cameras?.find((info) => info.camera === camera)?.name;\n const id = this.uniqueName(registered || camera.name || `${KIND_LABELS[kind]} camera`);\n const item: Item = { id, camera, kind, helper: null, frames: [], area: 0 };\n\n this.records.set(camera, item);\n this.byId.set(id, item);\n\n return item;\n }\n\n private remove(item: Item) {\n this.dropHelper(item);\n this.tweens.delete(item);\n this.records.delete(item.camera);\n this.byId.delete(item.id);\n }\n\n private dropHelper(item: Item) {\n if (item.helper) {\n item.helper.removeFromParent();\n item.helper.dispose();\n item.helper = null;\n }\n }\n\n private uniqueName(base: string) {\n let name = base;\n\n for (let n = 2; this.byId.has(name); n += 1) {\n name = `${base} ${n}`;\n }\n\n return name;\n }\n\n private inScene(camera: SceneCamera) {\n let top: Object3D = camera;\n\n while (top.parent) {\n top = top.parent;\n }\n\n return top === this.options.scene;\n }\n\n private entryOf(item: Item, time: number): CameraEntry {\n const recent = item.frames.filter((at) => time - at <= 1000);\n const last = recent.at(-1);\n\n return {\n id: item.id,\n kind: item.kind,\n camera: item.camera,\n inScene: this.inScene(item.camera),\n live: last !== undefined && time - last < LIVE_MS,\n fps: recent.length,\n helper: item.helper !== null,\n canHelp: this.canHelp(item),\n path: pathOf(item.camera),\n projects: this.projects(item),\n viewing: this.looking === item,\n standingIn: this.looking !== null && this.standIn === item.camera,\n views: this.saved[item.id]?.length ?? 0,\n };\n }\n\n private require(id: string) {\n const item = this.byId.get(id);\n\n if (!item) {\n throw new Error(`three-cameras: no camera \"${id}\"`);\n }\n\n return item;\n }\n\n private notifySoon() {\n if (!this.notifyQueued) {\n this.notifyQueued = true;\n queueMicrotask(() => {\n this.notifyQueued = false;\n this.notify();\n });\n }\n }\n\n private notify() {\n for (const listener of this.listeners) {\n listener();\n }\n }\n}\n"],"mappings":"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"}