@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.
- package/README.md +81 -16
- package/dist/channels-Dp6gFE5b.js +1324 -0
- package/dist/channels-Dp6gFE5b.js.map +1 -0
- package/dist/index.d.ts +17 -2
- package/dist/index.js +2 -2
- package/dist/{lab-AaEFBp_R.d.ts → lab-DuEV-i3c.d.ts} +165 -3
- package/dist/mount-BAkbs7K2.js +1974 -0
- package/dist/mount-BAkbs7K2.js.map +1 -0
- package/dist/{mount-Gf7I61p2.d.ts → mount-DPlwtFv9.d.ts} +7 -5
- package/dist/react.d.ts +2 -2
- package/dist/react.js +1 -1
- package/dist/ui.d.ts +40 -5
- package/dist/ui.js +2 -2
- package/package.json +2 -2
- package/dist/lab-D4PnOVwG.js +0 -605
- package/dist/lab-D4PnOVwG.js.map +0 -1
- package/dist/mount-DBjcu7if.js +0 -770
- package/dist/mount-DBjcu7if.js.map +0 -1
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"channels-Dp6gFE5b.js","names":[],"sources":["../src/core/discover.ts","../src/core/pose.ts","../src/core/track.ts","../src/core/lab.ts","../src/core/channels.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 * A camera's track: keyframes in time, each a pose and the ease into the next. `sampleTrack` gives\n * the pose at any time: the camera travels a smooth curve through the keyed positions\n * (Catmull-Rom), turns by slerp, and its lens (fov, zoom, near, far) goes straight between keys,\n * all paced by the outgoing key's ease. Before the first key it holds the first; after the last,\n * the last.\n *\n * An ease is a preset or a custom cubic Bézier (CSS `cubic-bezier` terms: the curve from (0, 0) to\n * (1, 1) through two handles). A handle may go above 1 or below 0, for overshoot and anticipation.\n */\nimport { Vector3 } from \"three\";\n\nimport { blendPoses, type Pose } from \"./pose.ts\";\n\nexport type Ease = \"linear\" | \"ease-in-out\" | \"ease-in\" | \"ease-out\" | \"hold\" | \"custom\";\n\n/** A cubic Bézier ease's two handles, `[x1, y1, x2, y2]`; x in 0–1, y free. */\nexport type Bezier = [number, number, number, number];\n\nexport type Keyframe = {\n id: string;\n /** Seconds from the start of the timeline. */\n time: number;\n pose: Pose;\n /** How it moves on to the next key. `hold` stays put until the next key, then jumps. */\n ease: Ease;\n /** The curve, when `ease` is `custom`. */\n bezier?: Bezier;\n};\n\nexport const EASES: readonly Ease[] = [\n \"ease-in-out\",\n \"linear\",\n \"ease-in\",\n \"ease-out\",\n \"hold\",\n \"custom\",\n];\n\n/** The presets as Bézier handles: where a custom curve starts when a preset is reshaped. */\nexport const PRESET_BEZIERS: Record<Exclude<Ease, \"custom\" | \"hold\">, Bezier> = {\n linear: [0.25, 0.25, 0.75, 0.75],\n \"ease-in\": [0.32, 0, 0.67, 0],\n \"ease-out\": [0.33, 1, 0.68, 1],\n \"ease-in-out\": [0.65, 0, 0.35, 1],\n};\n\nconst bezierAxis = (a: number, b: number, t: number) => {\n const u = 1 - t;\n\n return 3 * u * u * t * a + 3 * u * t * t * b + t * t * t;\n};\n\nconst bezierSlope = (a: number, b: number, t: number) => {\n const u = 1 - t;\n\n return 3 * u * u * a + 6 * u * t * (b - a) + 3 * t * t * (1 - b);\n};\n\n/** A cubic Bézier ease: progress (y) at time share `x`, solving the curve's x for its parameter. */\nexport const cubicBezier = ([x1, y1, x2, y2]: Bezier, x: number) => {\n if (x <= 0 || x >= 1) {\n return x <= 0 ? 0 : 1;\n }\n\n let t = x;\n\n // Newton's method, which converges in a few steps on these curves; bisection if it stalls.\n for (let i = 0; i < 8; i += 1) {\n const error = bezierAxis(x1, x2, t) - x;\n const slope = bezierSlope(x1, x2, t);\n\n if (Math.abs(error) < 1e-7) {\n return bezierAxis(y1, y2, t);\n }\n\n if (Math.abs(slope) < 1e-6) {\n break;\n }\n\n t -= error / slope;\n }\n\n let low = 0;\n let high = 1;\n\n t = x;\n\n for (let i = 0; i < 40; i += 1) {\n const value = bezierAxis(x1, x2, t);\n\n if (Math.abs(value - x) < 1e-7) {\n break;\n }\n\n if (value < x) {\n low = t;\n } else {\n high = t;\n }\n\n t = (low + high) / 2;\n }\n\n return bezierAxis(y1, y2, t);\n};\n\nconst easeFns: Record<Exclude<Ease, \"custom\">, (t: number) => number> = {\n linear: (t) => t,\n \"ease-in\": (t) => t * t * t,\n \"ease-out\": (t) => 1 - Math.pow(1 - t, 3),\n \"ease-in-out\": (t) => (t < 0.5 ? 4 * t * t * t : 1 - Math.pow(-2 * t + 2, 3) / 2),\n hold: () => 0,\n};\n\n/** Progress through a segment at time share `t` (0–1). A custom curve may leave 0–1 in between. */\nexport const applyEase = (ease: Ease, t: number, bezier?: Bezier) => {\n const clamped = Math.min(1, Math.max(0, t));\n\n if (ease === \"custom\") {\n return cubicBezier(bezier ?? PRESET_BEZIERS.linear, clamped);\n }\n\n return easeFns[ease](clamped);\n};\n\nexport const sortKeys = (keys: readonly Keyframe[]) => [...keys].sort((a, b) => a.time - b.time);\n\nconst p0 = new Vector3();\nconst p1 = new Vector3();\nconst p2 = new Vector3();\nconst p3 = new Vector3();\nconst out = new Vector3();\n\n/** Uniform Catmull-Rom through p1 → p2, with p0 and p3 as the neighbours shaping the bend. */\nconst catmullRom = (t: number) => {\n const t2 = t * t;\n const t3 = t2 * t;\n\n return out.set(\n 0.5 *\n (2 * p1.x +\n (-p0.x + p2.x) * t +\n (2 * p0.x - 5 * p1.x + 4 * p2.x - p3.x) * t2 +\n (-p0.x + 3 * p1.x - 3 * p2.x + p3.x) * t3),\n 0.5 *\n (2 * p1.y +\n (-p0.y + p2.y) * t +\n (2 * p0.y - 5 * p1.y + 4 * p2.y - p3.y) * t2 +\n (-p0.y + 3 * p1.y - 3 * p2.y + p3.y) * t3),\n 0.5 *\n (2 * p1.z +\n (-p0.z + p2.z) * t +\n (2 * p0.z - 5 * p1.z + 4 * p2.z - p3.z) * t2 +\n (-p0.z + 3 * p1.z - 3 * p2.z + p3.z) * t3),\n );\n};\n\n/** The pose at `time` on sorted `keys`, or `null` with no keys. */\nexport const sampleTrack = (keys: readonly Keyframe[], time: number): Pose | null => {\n const first = keys[0];\n const last = keys.at(-1);\n\n if (!first || !last) {\n return null;\n }\n\n if (time <= first.time || keys.length === 1) {\n return first.pose;\n }\n\n if (time >= last.time) {\n return last.pose;\n }\n\n let index = 0;\n\n while (index < keys.length - 2 && keys[index + 1]!.time <= time) {\n index += 1;\n }\n\n const from = keys[index]!;\n const to = keys[index + 1]!;\n const span = to.time - from.time;\n const t = applyEase(from.ease, span > 0 ? (time - from.time) / span : 1, from.bezier);\n const pose = blendPoses(from.pose, to.pose, t);\n\n // The path bends through the neighbours; a held segment doesn't travel at all.\n if (from.ease !== \"hold\") {\n const before = keys[index - 1];\n const after = keys[index + 2];\n\n p1.fromArray(from.pose.position);\n p2.fromArray(to.pose.position);\n\n // A missing neighbour continues the line, so an end segment (or a two-key move) runs straight.\n if (before) {\n p0.fromArray(before.pose.position);\n } else {\n p0.copy(p1).multiplyScalar(2).sub(p2);\n }\n\n if (after) {\n p3.fromArray(after.pose.position);\n } else {\n p3.copy(p2).multiplyScalar(2).sub(p1);\n }\n\n const point = catmullRom(t);\n\n pose.position = [point.x, point.y, point.z];\n }\n\n return pose;\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), a move to a saved view steps\n * once per frame, and the timeline plays: each camera with keyframes is put where its track says,\n * right before the frame draws, so it wins over an app that moves the camera itself.\n *\n * Once the timeline has been played or scrubbed, tracked cameras are held to their tracks, even\n * paused. Editing one (`set`, a move to a saved view) lets it go, so the edit sticks until it's\n * keyed or the timeline moves again; `stop()` lets them all go.\n */\nimport {\n BufferGeometry,\n type Camera,\n CameraHelper,\n Euler,\n Float32BufferAttribute,\n Group,\n Line,\n LineBasicMaterial,\n Matrix4,\n type Object3D,\n type OrthographicCamera,\n type PerspectiveCamera,\n Points,\n PointsMaterial,\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\";\nimport {\n type Bezier,\n type Ease,\n type Keyframe,\n PRESET_BEZIERS,\n sampleTrack,\n sortKeys,\n} from \"./track.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 /** Where keyframe tracks live. Default: this page only. */\n trackStore?: TrackStore;\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/** Keyframe tracks by camera name, and the timeline's length. */\nexport type TrackStore = {\n load(): { duration?: number; tracks: Record<string, Keyframe[]> };\n save(data: { duration: number; tracks: Record<string, Keyframe[]> }): void;\n};\n\nexport type TimelineState = {\n /** The playhead, seconds. */\n time: number;\n /** Seconds. */\n duration: number;\n playing: boolean;\n loop: boolean;\n /** Tracked cameras are held to their tracks (after a play or a scrub, until `stop`). */\n engaged: boolean;\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 /** Keyframes on its track. */\n keys: number;\n /** Its motion path is drawn in the scene. */\n trail: boolean;\n /** It moved in the last second: the app animates it, or its track plays. */\n moving: boolean;\n /** Its recent moves are recorded, to draw or to bake into keys. */\n recorded: boolean;\n /** Picked in a panel: the camera \"add key\" and the controls act on. */\n selected: boolean;\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 /** Held to its track while the timeline is engaged; an edit lets it go. */\n held: boolean;\n /** Its motion path in the scene: the track line, the key markers, and the recorded line. */\n trail: Group | null;\n /** `auto`: drawn while it moves or has keys (in the scene). `on` / `off`: as set. */\n trailMode: \"auto\" | \"on\" | \"off\";\n /** Where it's been lately (its own position and rotation), oldest first. */\n motion: MotionSample[];\n /** When it last moved, ms. */\n lastMoved: number;\n /** When its recorded line was last redrawn, ms. */\n motionDrawn: number;\n};\n\n/** A recorded moment of a camera's motion: when, and its own position and rotation. */\nexport type MotionSample = {\n /** ms, on the lab's clock. */\n time: number;\n position: [number, number, number];\n quaternion: [number, number, number, number];\n};\n\n/** The main view as last drawn: for turning screen points into rays (dragging path handles). */\nexport type ViewTransform = {\n /** The camera's world matrix. */\n world: Matrix4;\n projection: Matrix4;\n /** x, y, width, height in drawing-buffer pixels, y from the bottom. */\n viewport: Vector4;\n};\n\n/** How long a camera's moves are kept, ms, and at most how many samples. */\nconst RECORD_MS = 8000;\nconst RECORD_MAX = 900;\n/** Moved this recently counts as moving, ms. */\nconst MOVING_MS = 1000;\n/** Less than this, in its own units, isn't a move. */\nconst STILL = 1e-4;\n/** How often a recorded line redraws, ms. */\nconst MOTION_REDRAW_MS = 100;\n\n/** Path points per second of track, and the most a path gets. */\nconst TRAIL_RATE = 30;\nconst TRAIL_MAX = 600;\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/** A new timeline's length, s. */\nconst DURATION_S = 10;\n/** Keys closer than this, s, are the same key. */\nconst SAME_TIME = 1e-3;\n\nconst newId = () => `${Date.now().toString(36)}${Math.random().toString(36).slice(2, 6)}`;\n\nconst memoryTracks = (): TrackStore => {\n let data: ReturnType<TrackStore[\"load\"]> = { tracks: {} };\n\n return {\n load: () => data,\n save: (next) => {\n data = next;\n },\n };\n};\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\n/** Ramer–Douglas–Peucker on positions: the samples where the path bends by more than `tolerance`. */\nconst simplify = (samples: MotionSample[], tolerance: number, maxKeys: number): MotionSample[] => {\n const keep = new Set<number>([0, samples.length - 1]);\n const a = new Vector3();\n const b = new Vector3();\n const p = new Vector3();\n\n const distance = (index: number, from: number, to: number) => {\n a.fromArray(samples[from]!.position);\n b.fromArray(samples[to]!.position);\n p.fromArray(samples[index]!.position);\n\n const span = b.clone().sub(a);\n const length = span.lengthSq();\n\n if (length === 0) {\n return p.distanceTo(a);\n }\n\n const t = Math.min(1, Math.max(0, p.clone().sub(a).dot(span) / length));\n\n return p.distanceTo(a.clone().addScaledVector(span, t));\n };\n\n const split = (from: number, to: number) => {\n let far = -1;\n let most = tolerance;\n\n for (let i = from + 1; i < to; i += 1) {\n const d = distance(i, from, to);\n\n if (d > most) {\n most = d;\n far = i;\n }\n }\n\n if (far >= 0 && keep.size < maxKeys) {\n keep.add(far);\n split(from, far);\n split(far, to);\n }\n };\n\n split(0, samples.length - 1);\n\n return [...keep].sort((x, y) => x - y).map((index) => samples[index]!);\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 view: ViewTransform | null = null;\n private readonly trackStore: TrackStore;\n private tracks: Record<string, Keyframe[]>;\n private readonly state: TimelineState;\n /** When the playhead last advanced, ms; `null` until the next frame after a play. */\n private lastTick: number | null = null;\n private selectedId: string | null = null;\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.trackStore = options.trackStore ?? memoryTracks();\n\n const loaded = this.trackStore.load();\n\n this.tracks = { ...loaded.tracks };\n this.state = {\n time: 0,\n duration: loaded.duration && loaded.duration > 0 ? loaded.duration : DURATION_S,\n playing: false,\n loop: true,\n engaged: false,\n };\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 item.held = false;\n this.options.invalidate?.();\n }\n\n /** The camera picked in a panel, which \"add key\" and the controls act on. */\n get selected() {\n return this.selectedId;\n }\n\n select(id: string | null) {\n if (id !== this.selectedId && (id === null || this.byId.has(id))) {\n this.selectedId = id;\n this.notify();\n }\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 item.held = false;\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 // Timeline ---------------------------------------------------------------------------------\n\n timeline(): TimelineState {\n return { ...this.state };\n }\n\n /** Play from the playhead (from the start if it's at the end). Needs a renderer to advance. */\n play() {\n if (this.state.time >= this.state.duration) {\n this.state.time = 0;\n }\n\n this.state.playing = true;\n this.lastTick = null;\n this.engage();\n }\n\n pause() {\n this.state.playing = false;\n this.notify();\n }\n\n /** Stop and let every camera go back to the app (and to edits). The playhead stays. */\n stop() {\n this.state.playing = false;\n this.state.engaged = false;\n this.notify();\n }\n\n /** Move the playhead, and hold tracked cameras where their tracks are then. */\n seek(time: number) {\n this.state.time = Math.min(Math.max(0, time), this.state.duration);\n this.lastTick = null;\n this.engage();\n }\n\n setLoop(loop: boolean) {\n this.state.loop = loop;\n this.notify();\n }\n\n /** The timeline's length, s. Keys past it stay, and it grows to fit a key added later. */\n setDuration(duration: number) {\n if (duration > 0) {\n this.state.duration = duration;\n this.state.time = Math.min(this.state.time, duration);\n this.saveTracks();\n this.notify();\n }\n }\n\n /** A camera's keyframes, in time order. */\n keys(id: string): Keyframe[] {\n return this.tracks[id] ?? [];\n }\n\n /**\n * Key the camera as it is now, at `time` (default: the playhead). A key already there is\n * replaced, keeping its ease.\n */\n addKey(id: string, { time, ease }: { time?: number; ease?: Ease } = {}): Keyframe {\n const item = this.require(id);\n\n if (!this.projects(item)) {\n throw new Error(`three-cameras: \"${id}\" has no lens to key (${item.kind})`);\n }\n\n const at = Math.max(0, time ?? this.state.time);\n const list = this.keys(id);\n const existing = list.find((key) => Math.abs(key.time - at) < SAME_TIME);\n const key: Keyframe = {\n id: existing?.id ?? newId(),\n time: at,\n pose: capturePose(item.camera as Camera),\n ease: ease ?? existing?.ease ?? \"ease-in-out\",\n };\n\n this.setTrack(id, [...list.filter((other) => other !== existing), key]);\n\n if (at > this.state.duration) {\n this.state.duration = Math.ceil(at);\n }\n\n item.held = true;\n this.state.engaged = true;\n this.saveTracks();\n this.notify();\n\n return key;\n }\n\n /**\n * Change a key: move it in time, change its ease or its curve (`bezier`, which makes the ease\n * `custom`), set its pose outright (a graph editor's drag), or re-key it from the camera as it is.\n */\n updateKey(\n id: string,\n keyId: string,\n change: { time?: number; ease?: Ease; bezier?: Bezier; pose?: Pose; recapture?: boolean },\n ) {\n const item = this.require(id);\n const key = this.keys(id).find((other) => other.id === keyId);\n\n if (!key) {\n throw new Error(`three-cameras: \"${id}\" has no key \"${keyId}\"`);\n }\n\n const ease = change.bezier ? \"custom\" : (change.ease ?? key.ease);\n const next: Keyframe = {\n ...key,\n time: change.time === undefined ? key.time : Math.max(0, change.time),\n ease,\n pose: change.recapture ? capturePose(item.camera as Camera) : (change.pose ?? key.pose),\n };\n\n if (ease === \"custom\") {\n // Custom from a preset starts from the preset's shape.\n next.bezier =\n change.bezier ??\n key.bezier ??\n (key.ease === \"custom\" || key.ease === \"hold\"\n ? PRESET_BEZIERS.linear\n : PRESET_BEZIERS[key.ease]);\n } else {\n delete next.bezier;\n }\n\n this.setTrack(\n id,\n this.keys(id).map((other) => (other === key ? next : other)),\n );\n\n if (change.recapture) {\n item.held = true;\n }\n\n this.saveTracks();\n this.options.invalidate?.();\n this.notify();\n }\n\n deleteKey(id: string, keyId: string) {\n this.setTrack(\n id,\n this.keys(id).filter((key) => key.id !== keyId),\n );\n this.saveTracks();\n this.notify();\n }\n\n private setTrack(id: string, keys: Keyframe[]) {\n const next = { ...this.tracks };\n\n if (keys.length > 0) {\n next[id] = sortKeys(keys);\n } else {\n delete next[id];\n }\n\n this.tracks = next;\n\n const item = this.byId.get(id);\n\n if (item) {\n this.syncTrail(item);\n }\n }\n\n /**\n * Show or hide a camera's motion path in the scene, or `auto` (the default): shown while it\n * moves or has keys, for cameras in the scene. The path is its track as a line with a dot per\n * key; a camera without keys shows where it's been lately instead.\n */\n setTrail(id: string, on: boolean | \"auto\") {\n const item = this.require(id);\n\n item.trailMode = on === \"auto\" ? \"auto\" : on ? \"on\" : \"off\";\n this.syncTrail(item);\n this.options.invalidate?.();\n this.notify();\n }\n\n /** Where the camera has been lately, oldest first. */\n motion(id: string): MotionSample[] {\n return [...this.require(id).motion];\n }\n\n /**\n * Turn a camera's recorded moves into keys, replacing its track: a key where the path bends\n * (within `tolerance`, in its own units), timed from the first sample, linear between. The\n * lens is the camera's as it is now.\n */\n bakeMotion(\n id: string,\n { tolerance = 0.05, maxKeys = 40 }: { tolerance?: number; maxKeys?: number } = {},\n ) {\n const item = this.require(id);\n\n if (!this.projects(item)) {\n throw new Error(`three-cameras: \"${id}\" has no lens to key (${item.kind})`);\n }\n\n const samples = item.motion;\n\n if (samples.length < 2) {\n throw new Error(`three-cameras: \"${id}\" hasn't moved lately, so there's nothing to bake`);\n }\n\n const picked = simplify(samples, tolerance, maxKeys);\n const start = samples[0]!.time;\n const lens = capturePose(item.camera as Camera);\n const keys: Keyframe[] = picked.map((sample) => ({\n id: newId(),\n time: Math.round(((sample.time - start) / 1000) * 1000) / 1000,\n pose: { ...lens, position: [...sample.position], quaternion: [...sample.quaternion] },\n ease: \"linear\",\n }));\n\n this.setTrack(id, keys);\n this.state.duration = Math.max(this.state.duration, Math.ceil(keys.at(-1)!.time));\n this.saveTracks();\n this.syncTrail(item);\n this.notify();\n\n return keys;\n }\n\n /** The main view as last drawn, or `null` before its first frame. */\n viewTransform(): ViewTransform | null {\n return this.view\n ? {\n world: this.view.world.clone(),\n projection: this.view.projection.clone(),\n viewport: this.view.viewport.clone(),\n }\n : null;\n }\n\n /** Every key dot drawn in the scene, where it is in the world. */\n keyHandles(): { camera: string; key: string; position: Vector3 }[] {\n const handles: { camera: string; key: string; position: Vector3 }[] = [];\n\n for (const item of this.records.values()) {\n const keys = this.tracks[item.id];\n\n if (!item.trail || !keys) {\n continue;\n }\n\n const parent = item.camera.parent;\n\n parent?.updateWorldMatrix(true, false);\n\n for (const key of keys) {\n const position = new Vector3().fromArray(key.pose.position);\n\n if (parent) {\n position.applyMatrix4(parent.matrixWorld);\n }\n\n handles.push({ camera: item.id, key: key.id, position });\n }\n }\n\n return handles;\n }\n\n /** Move a key to a point in the world (a dragged dot): its position, in the camera's parent's space. */\n moveKeyTo(id: string, keyId: string, world: Vector3) {\n const item = this.require(id);\n const key = this.keys(id).find((other) => other.id === keyId);\n\n if (!key) {\n throw new Error(`three-cameras: \"${id}\" has no key \"${keyId}\"`);\n }\n\n const local = world.clone();\n\n if (item.camera.parent) {\n item.camera.parent.updateWorldMatrix(true, false);\n item.camera.parent.worldToLocal(local);\n }\n\n this.updateKey(id, keyId, { pose: { ...key.pose, position: [local.x, local.y, local.z] } });\n }\n\n private autoTrail(item: Item, time: number) {\n return (\n this.projects(item) &&\n this.inScene(item.camera) &&\n ((this.tracks[item.id]?.length ?? 0) > 0 || time - item.lastMoved < MOVING_MS)\n );\n }\n\n /** Make the path match its mode: create, draw or drop it. */\n private syncTrail(item: Item, time = now()) {\n const wanted =\n item.trailMode === \"on\" || (item.trailMode === \"auto\" && this.autoTrail(item, time));\n\n if (wanted && !item.trail) {\n const trail = new Group();\n const line = new Line(\n new BufferGeometry(),\n new LineBasicMaterial({ color: \"#fbbf24\", transparent: true, opacity: 0.9 }),\n );\n const markers = new Points(\n new BufferGeometry(),\n new PointsMaterial({ color: \"#ffffff\", size: 8, sizeAttenuation: false }),\n );\n const recorded = new Line(\n new BufferGeometry(),\n new LineBasicMaterial({ color: \"#7dd3fc\", transparent: true, opacity: 0.55 }),\n );\n\n trail.name = `${item.id} (three-cameras path)`;\n trail.userData.threeCameras = true;\n trail.add(line, markers, recorded);\n // Poses are the camera's own, relative to its parent: the path lives there too.\n (item.camera.parent ?? this.options.scene).add(trail);\n item.trail = trail;\n this.drawTrail(item);\n this.notifySoon();\n } else if (!wanted && item.trail) {\n this.dropTrail(item);\n this.notifySoon();\n } else if (item.trail) {\n this.drawTrail(item);\n }\n }\n\n private drawTrail(item: Item) {\n const trail = item.trail;\n\n if (!trail) {\n return;\n }\n\n const [line, markers, recorded] = trail.children as [Line, Points, Line];\n const keys = this.tracks[item.id] ?? [];\n\n // Where it's been, for a camera without keys (with keys, the track is the path).\n recorded.geometry.setAttribute(\n \"position\",\n new Float32BufferAttribute(\n keys.length > 0 ? [] : item.motion.flatMap((sample) => sample.position),\n 3,\n ),\n );\n recorded.geometry.computeBoundingSphere();\n const first = keys[0];\n const last = keys.at(-1);\n const path: number[] = [];\n\n if (first && last) {\n const span = last.time - first.time;\n const count = Math.min(TRAIL_MAX, Math.max(1, Math.ceil(span * TRAIL_RATE)));\n\n for (let i = 0; i <= count; i += 1) {\n const pose = sampleTrack(keys, first.time + (span * i) / count);\n\n if (pose) {\n path.push(...pose.position);\n }\n }\n }\n\n line.geometry.setAttribute(\"position\", new Float32BufferAttribute(path, 3));\n line.geometry.computeBoundingSphere();\n markers.geometry.setAttribute(\n \"position\",\n new Float32BufferAttribute(\n keys.flatMap((key) => key.pose.position),\n 3,\n ),\n );\n markers.geometry.computeBoundingSphere();\n this.options.invalidate?.();\n }\n\n private dropTrail(item: Item) {\n if (!item.trail) {\n return;\n }\n\n for (const child of item.trail.children as (Line | Points)[]) {\n child.geometry.dispose();\n (child.material as LineBasicMaterial).dispose();\n }\n\n item.trail.removeFromParent();\n item.trail = null;\n }\n\n private saveTracks() {\n this.trackStore.save({ duration: this.state.duration, tracks: this.tracks });\n }\n\n private engage() {\n this.state.engaged = true;\n\n for (const item of this.records.values()) {\n item.held = true;\n this.tweens.delete(item);\n }\n\n this.applyTracks();\n this.options.invalidate?.();\n this.notify();\n }\n\n /** Every held camera with a track, to where its track is at the playhead. */\n private applyTracks() {\n if (!this.state.engaged) {\n return;\n }\n\n for (const item of this.records.values()) {\n const keys = this.tracks[item.id];\n\n if (item.held && keys && keys.length > 0) {\n const pose = sampleTrack(keys, this.state.time);\n\n if (pose) {\n applyPose(item.camera as Camera, pose);\n }\n }\n }\n }\n\n /** Move the playhead by the time since the last frame. */\n private advance(time: number) {\n if (!this.state.playing) {\n return;\n }\n\n // Seconds, capped so a stall (a tab coming back) doesn't jump the playhead; a slow frame\n // rate still plays in real time down to 4 fps.\n const step = this.lastTick === null ? 0 : Math.min(0.25, (time - this.lastTick) / 1000);\n\n this.lastTick = time;\n this.state.time += step;\n\n if (this.state.time >= this.state.duration) {\n if (this.state.loop && this.state.duration > 0) {\n this.state.time %= this.state.duration;\n } else {\n this.state.time = this.state.duration;\n this.state.playing = false;\n this.notifySoon();\n }\n }\n\n // Keep frames coming while playing, for render-on-demand loops.\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 this.dropTrail(item);\n }\n\n this.looking = null;\n this.standIn = null;\n this.state.playing = false;\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.record(time);\n this.advance(time);\n this.applyTracks();\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 this.captureView(camera, shown);\n\n return shown;\n }\n\n /** The main view's matrices, when this frame is it: the camera drawing the most of the screen. */\n private captureView(requested: Camera, shown: Camera) {\n const item = this.records.get(requested);\n\n if (!item) {\n return;\n }\n\n let main = true;\n\n for (const other of this.records.values()) {\n if (other.area > item.area) {\n main = false;\n break;\n }\n }\n\n if (!main || item.area === 0) {\n return;\n }\n\n shown.updateWorldMatrix(true, false);\n this.view ??= { world: new Matrix4(), projection: new Matrix4(), viewport: new Vector4() };\n this.view.world.copy(shown.matrixWorld);\n this.view.projection.copy(shown.projectionMatrix);\n this.view.viewport.copy(this.viewport);\n }\n\n /**\n * Note where cameras in the scene are, when they've moved: their recent motion, drawn for a\n * camera without keys and bakeable into keys. A camera its track is driving isn't recorded.\n */\n private record(time: number) {\n const driving = this.state.engaged;\n\n for (const item of this.records.values()) {\n if (!this.projects(item) || !this.inScene(item.camera)) {\n continue;\n }\n\n const tracked = (this.tracks[item.id]?.length ?? 0) > 0;\n\n if (!(driving && item.held && tracked)) {\n const { position, quaternion } = item.camera;\n const last = item.motion.at(-1);\n const moved =\n !last ||\n Math.abs(last.position[0] - position.x) > STILL ||\n Math.abs(last.position[1] - position.y) > STILL ||\n Math.abs(last.position[2] - position.z) > STILL ||\n Math.abs(last.quaternion[3] - quaternion.w) > STILL;\n\n if (moved) {\n if (last) {\n item.lastMoved = time;\n }\n\n item.motion.push({\n time,\n position: [position.x, position.y, position.z],\n quaternion: [quaternion.x, quaternion.y, quaternion.z, quaternion.w],\n });\n }\n\n while (\n item.motion.length > RECORD_MAX ||\n (item.motion.length > 0 && time - item.motion[0]!.time > RECORD_MS)\n ) {\n item.motion.shift();\n }\n }\n\n if (item.trailMode === \"auto\" || item.trail) {\n const was = item.trail !== null;\n\n if (item.trail && !tracked && time - item.motionDrawn >= MOTION_REDRAW_MS) {\n item.motionDrawn = time;\n this.drawTrail(item);\n }\n\n if (item.trailMode === \"auto\" && was !== this.autoTrail(item, time)) {\n this.syncTrail(item, time);\n }\n }\n }\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 = {\n id,\n camera,\n kind,\n helper: null,\n frames: [],\n area: 0,\n held: true,\n trail: null,\n trailMode: \"auto\",\n motion: [],\n lastMoved: Number.NEGATIVE_INFINITY,\n motionDrawn: 0,\n };\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.dropTrail(item);\n this.tweens.delete(item);\n\n if (this.selectedId === item.id) {\n this.selectedId = null;\n }\n\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 keys: this.tracks[item.id]?.length ?? 0,\n trail: item.trail !== null,\n moving: time - item.lastMoved < MOVING_MS,\n recorded: item.motion.length > 1,\n selected: this.selectedId === item.id,\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","/**\n * A pose as separate channels, the way a graph editor shows it: position x, y, z; rotation x, y, z\n * (XYZ Euler, degrees); and the lens (fov, zoom, near, far). Read one, or write one back into a\n * pose. Rotation is stored as a quaternion, so a rotation channel goes through Euler angles on the\n * way in and out.\n */\nimport { Euler, Quaternion } from \"three\";\n\nimport type { Pose } from \"./pose.ts\";\nimport { type Keyframe, sampleTrack } from \"./track.ts\";\n\nexport type Channel = \"px\" | \"py\" | \"pz\" | \"rx\" | \"ry\" | \"rz\" | \"fov\" | \"zoom\" | \"near\" | \"far\";\n\nexport const CHANNELS: readonly Channel[] = [\n \"px\",\n \"py\",\n \"pz\",\n \"rx\",\n \"ry\",\n \"rz\",\n \"fov\",\n \"zoom\",\n \"near\",\n \"far\",\n];\n\nexport const CHANNEL_LABELS: Record<Channel, string> = {\n px: \"position x\",\n py: \"position y\",\n pz: \"position z\",\n rx: \"rotation x\",\n ry: \"rotation y\",\n rz: \"rotation z\",\n fov: \"fov\",\n zoom: \"zoom\",\n near: \"near\",\n far: \"far\",\n};\n\nconst euler = new Euler();\nconst quaternion = new Quaternion();\nconst DEGREES = 180 / Math.PI;\n\n/** One channel's value in a pose; `undefined` for fov on an orthographic pose. */\nexport const readChannel = (pose: Pose, channel: Channel): number | undefined => {\n switch (channel) {\n case \"px\":\n return pose.position[0];\n case \"py\":\n return pose.position[1];\n case \"pz\":\n return pose.position[2];\n case \"rx\":\n case \"ry\":\n case \"rz\": {\n euler.setFromQuaternion(quaternion.fromArray(pose.quaternion));\n\n return (channel === \"rx\" ? euler.x : channel === \"ry\" ? euler.y : euler.z) * DEGREES;\n }\n default:\n return pose[channel];\n }\n};\n\n/** A copy of `pose` with one channel set. */\nexport const writeChannel = (pose: Pose, channel: Channel, value: number): Pose => {\n const next: Pose = {\n ...pose,\n position: [...pose.position],\n quaternion: [...pose.quaternion],\n };\n\n switch (channel) {\n case \"px\":\n case \"py\":\n case \"pz\":\n next.position[channel === \"px\" ? 0 : channel === \"py\" ? 1 : 2] = value;\n break;\n case \"rx\":\n case \"ry\":\n case \"rz\": {\n euler.setFromQuaternion(quaternion.fromArray(pose.quaternion));\n euler[channel === \"rx\" ? \"x\" : channel === \"ry\" ? \"y\" : \"z\"] = value / DEGREES;\n quaternion.setFromEuler(euler);\n next.quaternion = [quaternion.x, quaternion.y, quaternion.z, quaternion.w];\n break;\n }\n default:\n next[channel] = value;\n }\n\n return next;\n};\n\n/**\n * A channel over time, `samples + 1` points from `start` to `end`, as the track plays it. Angles\n * are unwrapped (no jump at ±180°) so a turn reads as one curve.\n */\nexport const sampleChannel = (\n keys: readonly Keyframe[],\n channel: Channel,\n start: number,\n end: number,\n samples: number,\n): [number, number][] => {\n const points: [number, number][] = [];\n let previous: number | undefined;\n\n for (let i = 0; i <= samples; i += 1) {\n const time = start + ((end - start) * i) / samples;\n const pose = sampleTrack(keys, time);\n let value = pose ? readChannel(pose, channel) : undefined;\n\n if (value === undefined) {\n continue;\n }\n\n if (previous !== undefined && channel.startsWith(\"r\")) {\n while (value - previous > 180) {\n value -= 360;\n }\n\n while (value - previous < -180) {\n value += 360;\n }\n }\n\n previous = value;\n points.push([time, value]);\n }\n\n return points;\n};\n"],"mappings":"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"}
|
package/dist/index.d.ts
CHANGED
|
@@ -1,2 +1,17 @@
|
|
|
1
|
-
import { C as pathOf, S as
|
|
2
|
-
|
|
1
|
+
import { A as CameraKind, C as sortKeys, D as capturePose, E as blendPoses, F as kindOf, I as pathOf, M as findCameras, N as isCamera, O as easeInOut, P as isCubeCamera, S as sampleTrack, T as applyPose, _ as Ease, a as CameraLabOptions, b as applyEase, c as Projection, d as TimelineState, f as TrackStore, g as EASES, h as Bezier, i as CameraLab, j as SceneCamera, k as poseToCode, l as RendererLike, m as ViewTransform, n as CameraEntry, o as CameraPatch, p as ViewStore, r as CameraInfo, s as MotionSample, t as CameraDetails, u as SavedView, v as Keyframe, w as Pose, x as cubicBezier, y as PRESET_BEZIERS } from "./lab-DuEV-i3c.js";
|
|
2
|
+
//#region src/core/channels.d.ts
|
|
3
|
+
type Channel = "px" | "py" | "pz" | "rx" | "ry" | "rz" | "fov" | "zoom" | "near" | "far";
|
|
4
|
+
export declare const CHANNELS: readonly Channel[];
|
|
5
|
+
export declare const CHANNEL_LABELS: Record<Channel, string>;
|
|
6
|
+
/** One channel's value in a pose; `undefined` for fov on an orthographic pose. */
|
|
7
|
+
export declare const readChannel: (pose: Pose, channel: Channel) => number | undefined;
|
|
8
|
+
/** A copy of `pose` with one channel set. */
|
|
9
|
+
export declare const writeChannel: (pose: Pose, channel: Channel, value: number) => Pose;
|
|
10
|
+
/**
|
|
11
|
+
* A channel over time, `samples + 1` points from `start` to `end`, as the track plays it. Angles
|
|
12
|
+
* are unwrapped (no jump at ±180°) so a turn reads as one curve.
|
|
13
|
+
*/
|
|
14
|
+
export declare const sampleChannel: (keys: readonly Keyframe[], channel: Channel, start: number, end: number, samples: number) => [number, number][];
|
|
15
|
+
//#endregion
|
|
16
|
+
export { type Bezier, type CameraDetails, type CameraEntry, type CameraInfo, type CameraKind, CameraLab, type CameraLabOptions, type CameraPatch, type Channel, EASES, type Ease, type Keyframe, type MotionSample, PRESET_BEZIERS, type Pose, type Projection, type RendererLike, type SavedView, type SceneCamera, type TimelineState, type TrackStore, type ViewStore, type ViewTransform, applyEase, applyPose, blendPoses, capturePose, cubicBezier, easeInOut, findCameras, isCamera, isCubeCamera, kindOf, pathOf, poseToCode, sampleTrack, sortKeys };
|
|
17
|
+
//# sourceMappingURL=index.d.ts.map
|
package/dist/index.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { a as
|
|
2
|
-
export { CameraLab, applyPose, blendPoses, capturePose, easeInOut, findCameras, isCamera, isCubeCamera, kindOf, pathOf, poseToCode };
|
|
1
|
+
import { S as pathOf, _ as poseToCode, a as writeChannel, b as isCubeCamera, c as PRESET_BEZIERS, d as sampleTrack, f as sortKeys, g as easeInOut, h as capturePose, i as sampleChannel, l as applyEase, m as blendPoses, n as CHANNEL_LABELS, o as CameraLab, p as applyPose, r as readChannel, s as EASES, t as CHANNELS, u as cubicBezier, v as findCameras, x as kindOf, y as isCamera } from "./channels-Dp6gFE5b.js";
|
|
2
|
+
export { CHANNELS, CHANNEL_LABELS, CameraLab, EASES, PRESET_BEZIERS, applyEase, applyPose, blendPoses, capturePose, cubicBezier, easeInOut, findCameras, isCamera, isCubeCamera, kindOf, pathOf, poseToCode, readChannel, sampleChannel, sampleTrack, sortKeys, writeChannel };
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { Camera, Object3D } from "three";
|
|
1
|
+
import { Camera, Matrix4, Object3D, Vector3, Vector4 } from "three";
|
|
2
2
|
//#region src/core/discover.d.ts
|
|
3
3
|
type CameraKind = "perspective" | "orthographic" | "array" | "cube" | "other";
|
|
4
4
|
/** A camera, or a `CubeCamera`, which is an `Object3D` holding six. */
|
|
@@ -31,6 +31,31 @@ declare const easeInOut: (t: number) => number;
|
|
|
31
31
|
/** Three.js to recreate the pose on a camera called `name`. */
|
|
32
32
|
declare const poseToCode: (pose: Pose, name?: string) => string;
|
|
33
33
|
//#endregion
|
|
34
|
+
//#region src/core/track.d.ts
|
|
35
|
+
type Ease = "linear" | "ease-in-out" | "ease-in" | "ease-out" | "hold" | "custom";
|
|
36
|
+
/** A cubic Bézier ease's two handles, `[x1, y1, x2, y2]`; x in 0–1, y free. */
|
|
37
|
+
type Bezier = [number, number, number, number];
|
|
38
|
+
type Keyframe = {
|
|
39
|
+
id: string;
|
|
40
|
+
/** Seconds from the start of the timeline. */
|
|
41
|
+
time: number;
|
|
42
|
+
pose: Pose;
|
|
43
|
+
/** How it moves on to the next key. `hold` stays put until the next key, then jumps. */
|
|
44
|
+
ease: Ease;
|
|
45
|
+
/** The curve, when `ease` is `custom`. */
|
|
46
|
+
bezier?: Bezier;
|
|
47
|
+
};
|
|
48
|
+
declare const EASES: readonly Ease[];
|
|
49
|
+
/** The presets as Bézier handles: where a custom curve starts when a preset is reshaped. */
|
|
50
|
+
declare const PRESET_BEZIERS: Record<Exclude<Ease, "custom" | "hold">, Bezier>;
|
|
51
|
+
/** A cubic Bézier ease: progress (y) at time share `x`, solving the curve's x for its parameter. */
|
|
52
|
+
declare const cubicBezier: ([x1, y1, x2, y2]: Bezier, x: number) => number;
|
|
53
|
+
/** Progress through a segment at time share `t` (0–1). A custom curve may leave 0–1 in between. */
|
|
54
|
+
declare const applyEase: (ease: Ease, t: number, bezier?: Bezier) => number;
|
|
55
|
+
declare const sortKeys: (keys: readonly Keyframe[]) => Keyframe[];
|
|
56
|
+
/** The pose at `time` on sorted `keys`, or `null` with no keys. */
|
|
57
|
+
declare const sampleTrack: (keys: readonly Keyframe[], time: number) => Pose | null;
|
|
58
|
+
//#endregion
|
|
34
59
|
//#region src/core/lab.d.ts
|
|
35
60
|
type CameraInfo = {
|
|
36
61
|
name: string;
|
|
@@ -51,6 +76,8 @@ type CameraLabOptions = {
|
|
|
51
76
|
invalidate?: () => void;
|
|
52
77
|
/** Where saved views live. Default: this page only. */
|
|
53
78
|
store?: ViewStore;
|
|
79
|
+
/** Where keyframe tracks live. Default: this page only. */
|
|
80
|
+
trackStore?: TrackStore;
|
|
54
81
|
};
|
|
55
82
|
/** A pose saved on a camera, to go back to. */
|
|
56
83
|
type SavedView = {
|
|
@@ -63,6 +90,27 @@ type ViewStore = {
|
|
|
63
90
|
load(): Record<string, SavedView[]>;
|
|
64
91
|
save(views: Record<string, SavedView[]>): void;
|
|
65
92
|
};
|
|
93
|
+
/** Keyframe tracks by camera name, and the timeline's length. */
|
|
94
|
+
type TrackStore = {
|
|
95
|
+
load(): {
|
|
96
|
+
duration?: number;
|
|
97
|
+
tracks: Record<string, Keyframe[]>;
|
|
98
|
+
};
|
|
99
|
+
save(data: {
|
|
100
|
+
duration: number;
|
|
101
|
+
tracks: Record<string, Keyframe[]>;
|
|
102
|
+
}): void;
|
|
103
|
+
};
|
|
104
|
+
type TimelineState = {
|
|
105
|
+
/** The playhead, seconds. */
|
|
106
|
+
time: number;
|
|
107
|
+
/** Seconds. */
|
|
108
|
+
duration: number;
|
|
109
|
+
playing: boolean;
|
|
110
|
+
loop: boolean;
|
|
111
|
+
/** Tracked cameras are held to their tracks (after a play or a scrub, until `stop`). */
|
|
112
|
+
engaged: boolean;
|
|
113
|
+
};
|
|
66
114
|
/** Values to set on a camera. Position and rotation are its own (local); rotation in degrees. */
|
|
67
115
|
type CameraPatch = {
|
|
68
116
|
position?: readonly [number, number, number];
|
|
@@ -96,6 +144,16 @@ type CameraEntry = {
|
|
|
96
144
|
standingIn: boolean;
|
|
97
145
|
/** Saved views on it. */
|
|
98
146
|
views: number;
|
|
147
|
+
/** Keyframes on its track. */
|
|
148
|
+
keys: number;
|
|
149
|
+
/** Its motion path is drawn in the scene. */
|
|
150
|
+
trail: boolean;
|
|
151
|
+
/** It moved in the last second: the app animates it, or its track plays. */
|
|
152
|
+
moving: boolean;
|
|
153
|
+
/** Its recent moves are recorded, to draw or to bake into keys. */
|
|
154
|
+
recorded: boolean;
|
|
155
|
+
/** Picked in a panel: the camera "add key" and the controls act on. */
|
|
156
|
+
selected: boolean;
|
|
99
157
|
};
|
|
100
158
|
type Projection = {
|
|
101
159
|
near: number;
|
|
@@ -122,6 +180,21 @@ type CameraDetails = {
|
|
|
122
180
|
};
|
|
123
181
|
projection: Projection | null;
|
|
124
182
|
};
|
|
183
|
+
/** A recorded moment of a camera's motion: when, and its own position and rotation. */
|
|
184
|
+
type MotionSample = {
|
|
185
|
+
/** ms, on the lab's clock. */
|
|
186
|
+
time: number;
|
|
187
|
+
position: [number, number, number];
|
|
188
|
+
quaternion: [number, number, number, number];
|
|
189
|
+
};
|
|
190
|
+
/** The main view as last drawn: for turning screen points into rays (dragging path handles). */
|
|
191
|
+
type ViewTransform = {
|
|
192
|
+
/** The camera's world matrix. */
|
|
193
|
+
world: Matrix4;
|
|
194
|
+
projection: Matrix4;
|
|
195
|
+
/** x, y, width, height in drawing-buffer pixels, y from the bottom. */
|
|
196
|
+
viewport: Vector4;
|
|
197
|
+
};
|
|
125
198
|
declare class CameraLab {
|
|
126
199
|
private readonly options;
|
|
127
200
|
private readonly records;
|
|
@@ -137,6 +210,13 @@ declare class CameraLab {
|
|
|
137
210
|
/** The frame being drawn: what to put back after it. */
|
|
138
211
|
private fitted;
|
|
139
212
|
private readonly viewport;
|
|
213
|
+
private view;
|
|
214
|
+
private readonly trackStore;
|
|
215
|
+
private tracks;
|
|
216
|
+
private readonly state;
|
|
217
|
+
/** When the playhead last advanced, ms; `null` until the next frame after a play. */
|
|
218
|
+
private lastTick;
|
|
219
|
+
private selectedId;
|
|
140
220
|
private notifyQueued;
|
|
141
221
|
private disposed;
|
|
142
222
|
constructor(options: CameraLabOptions);
|
|
@@ -153,6 +233,9 @@ declare class CameraLab {
|
|
|
153
233
|
* render-on-demand loop gets a frame. An app that sets the camera every frame wins on the next.
|
|
154
234
|
*/
|
|
155
235
|
set(id: string, patch: CameraPatch): void;
|
|
236
|
+
/** The camera picked in a panel, which "add key" and the controls act on. */
|
|
237
|
+
get selected(): string | null;
|
|
238
|
+
select(id: string | null): void;
|
|
156
239
|
/**
|
|
157
240
|
* Show the main view through `id`, or back through the app's own camera with `null`. The camera
|
|
158
241
|
* it stands in for is the app's main view: the one drawing the most of the screen (a
|
|
@@ -170,6 +253,78 @@ declare class CameraLab {
|
|
|
170
253
|
goToView(id: string, viewId: string, { duration }?: {
|
|
171
254
|
duration?: number;
|
|
172
255
|
}): void;
|
|
256
|
+
timeline(): TimelineState;
|
|
257
|
+
/** Play from the playhead (from the start if it's at the end). Needs a renderer to advance. */
|
|
258
|
+
play(): void;
|
|
259
|
+
pause(): void;
|
|
260
|
+
/** Stop and let every camera go back to the app (and to edits). The playhead stays. */
|
|
261
|
+
stop(): void;
|
|
262
|
+
/** Move the playhead, and hold tracked cameras where their tracks are then. */
|
|
263
|
+
seek(time: number): void;
|
|
264
|
+
setLoop(loop: boolean): void;
|
|
265
|
+
/** The timeline's length, s. Keys past it stay, and it grows to fit a key added later. */
|
|
266
|
+
setDuration(duration: number): void;
|
|
267
|
+
/** A camera's keyframes, in time order. */
|
|
268
|
+
keys(id: string): Keyframe[];
|
|
269
|
+
/**
|
|
270
|
+
* Key the camera as it is now, at `time` (default: the playhead). A key already there is
|
|
271
|
+
* replaced, keeping its ease.
|
|
272
|
+
*/
|
|
273
|
+
addKey(id: string, { time, ease }?: {
|
|
274
|
+
time?: number;
|
|
275
|
+
ease?: Ease;
|
|
276
|
+
}): Keyframe;
|
|
277
|
+
/**
|
|
278
|
+
* Change a key: move it in time, change its ease or its curve (`bezier`, which makes the ease
|
|
279
|
+
* `custom`), set its pose outright (a graph editor's drag), or re-key it from the camera as it is.
|
|
280
|
+
*/
|
|
281
|
+
updateKey(id: string, keyId: string, change: {
|
|
282
|
+
time?: number;
|
|
283
|
+
ease?: Ease;
|
|
284
|
+
bezier?: Bezier;
|
|
285
|
+
pose?: Pose;
|
|
286
|
+
recapture?: boolean;
|
|
287
|
+
}): void;
|
|
288
|
+
deleteKey(id: string, keyId: string): void;
|
|
289
|
+
private setTrack;
|
|
290
|
+
/**
|
|
291
|
+
* Show or hide a camera's motion path in the scene, or `auto` (the default): shown while it
|
|
292
|
+
* moves or has keys, for cameras in the scene. The path is its track as a line with a dot per
|
|
293
|
+
* key; a camera without keys shows where it's been lately instead.
|
|
294
|
+
*/
|
|
295
|
+
setTrail(id: string, on: boolean | "auto"): void;
|
|
296
|
+
/** Where the camera has been lately, oldest first. */
|
|
297
|
+
motion(id: string): MotionSample[];
|
|
298
|
+
/**
|
|
299
|
+
* Turn a camera's recorded moves into keys, replacing its track: a key where the path bends
|
|
300
|
+
* (within `tolerance`, in its own units), timed from the first sample, linear between. The
|
|
301
|
+
* lens is the camera's as it is now.
|
|
302
|
+
*/
|
|
303
|
+
bakeMotion(id: string, { tolerance, maxKeys }?: {
|
|
304
|
+
tolerance?: number;
|
|
305
|
+
maxKeys?: number;
|
|
306
|
+
}): Keyframe[];
|
|
307
|
+
/** The main view as last drawn, or `null` before its first frame. */
|
|
308
|
+
viewTransform(): ViewTransform | null;
|
|
309
|
+
/** Every key dot drawn in the scene, where it is in the world. */
|
|
310
|
+
keyHandles(): {
|
|
311
|
+
camera: string;
|
|
312
|
+
key: string;
|
|
313
|
+
position: Vector3;
|
|
314
|
+
}[];
|
|
315
|
+
/** Move a key to a point in the world (a dragged dot): its position, in the camera's parent's space. */
|
|
316
|
+
moveKeyTo(id: string, keyId: string, world: Vector3): void;
|
|
317
|
+
private autoTrail;
|
|
318
|
+
/** Make the path match its mode: create, draw or drop it. */
|
|
319
|
+
private syncTrail;
|
|
320
|
+
private drawTrail;
|
|
321
|
+
private dropTrail;
|
|
322
|
+
private saveTracks;
|
|
323
|
+
private engage;
|
|
324
|
+
/** Every held camera with a track, to where its track is at the playhead. */
|
|
325
|
+
private applyTracks;
|
|
326
|
+
/** Move the playhead by the time since the last frame. */
|
|
327
|
+
private advance;
|
|
173
328
|
/**
|
|
174
329
|
* Look at the scene again: new cameras get entries, ones that left go (a camera outside the
|
|
175
330
|
* scene stays while it's still rendering, and a few seconds after).
|
|
@@ -181,6 +336,13 @@ declare class CameraLab {
|
|
|
181
336
|
private watch;
|
|
182
337
|
/** Before a frame: count it, step moves, and pick the camera it's drawn with. */
|
|
183
338
|
private beforeFrame;
|
|
339
|
+
/** The main view's matrices, when this frame is it: the camera drawing the most of the screen. */
|
|
340
|
+
private captureView;
|
|
341
|
+
/**
|
|
342
|
+
* Note where cameras in the scene are, when they've moved: their recent motion, drawn for a
|
|
343
|
+
* camera without keys and bakeable into keys. A camera its track is driving isn't recorded.
|
|
344
|
+
*/
|
|
345
|
+
private record;
|
|
184
346
|
private afterFrame;
|
|
185
347
|
/** How much of the screen this frame covers, if the renderer says. */
|
|
186
348
|
private measure;
|
|
@@ -202,5 +364,5 @@ declare class CameraLab {
|
|
|
202
364
|
private notify;
|
|
203
365
|
}
|
|
204
366
|
//#endregion
|
|
205
|
-
export {
|
|
206
|
-
//# sourceMappingURL=lab-
|
|
367
|
+
export { CameraKind as A, sortKeys as C, capturePose as D, blendPoses as E, kindOf as F, pathOf as I, findCameras as M, isCamera as N, easeInOut as O, isCubeCamera as P, sampleTrack as S, applyPose as T, Ease as _, CameraLabOptions as a, applyEase as b, Projection as c, TimelineState as d, TrackStore as f, EASES as g, Bezier as h, CameraLab as i, SceneCamera as j, poseToCode as k, RendererLike as l, ViewTransform as m, CameraEntry as n, CameraPatch as o, ViewStore as p, CameraInfo as r, MotionSample as s, CameraDetails as t, SavedView as u, Keyframe as v, Pose as w, cubicBezier as x, PRESET_BEZIERS as y };
|
|
368
|
+
//# sourceMappingURL=lab-DuEV-i3c.d.ts.map
|