pixi-effects 0.1.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/dist/three.cjs ADDED
@@ -0,0 +1,161 @@
1
+ 'use strict';
2
+
3
+ var chunk7OIWYXGV_cjs = require('./chunk-7OIWYXGV.cjs');
4
+ var pixi_js = require('pixi.js');
5
+ var three$1 = require('three');
6
+
7
+ var ThreeSequence = class extends chunk7OIWYXGV_cjs.Sequence {
8
+ _renderer = null;
9
+ _scene = null;
10
+ _camera = null;
11
+ _ctx = null;
12
+ _objects = {};
13
+ _warnedUpdate = false;
14
+ _warnedPaths = /* @__PURE__ */ new Set();
15
+ get _threeSpec() {
16
+ return this.spec;
17
+ }
18
+ pathRouters() {
19
+ return { three: (path) => this._resolveThreePath(path) };
20
+ }
21
+ async build() {
22
+ const spec = this._threeSpec;
23
+ if (this.duration === void 0) {
24
+ this.duration = this.parent?.duration ?? this.root.duration;
25
+ }
26
+ const scope = chunk7OIWYXGV_cjs.buildScope(this, this.parent, this.root);
27
+ const width = resolveDim(spec.width, scope) ?? this.parent?.width ?? this.root.width;
28
+ const height = resolveDim(spec.height, scope) ?? this.parent?.height ?? this.root.height;
29
+ const resolution = spec.resolution ?? 1;
30
+ const canvas = document.createElement("canvas");
31
+ const renderer = new three$1.WebGLRenderer({ canvas, alpha: true, antialias: true });
32
+ this._renderer = renderer;
33
+ try {
34
+ renderer.setSize(Math.round(width * resolution), Math.round(height * resolution), false);
35
+ renderer.setClearColor(0, 0);
36
+ const scene = new three$1.Scene();
37
+ const camera = new three$1.PerspectiveCamera(50, width / height, 0.1, 2e3);
38
+ const ctx = { scene, camera, renderer, width, height };
39
+ const result = await spec.setup(ctx);
40
+ if (result?.camera) ctx.camera = result.camera;
41
+ this._scene = scene;
42
+ this._camera = ctx.camera;
43
+ this._ctx = ctx;
44
+ this._objects = { ...result?.objects ?? {} };
45
+ if (!("camera" in this._objects)) this._objects.camera = this._camera;
46
+ renderer.render(scene, this._camera);
47
+ const texture = pixi_js.Texture.from(canvas);
48
+ const sprite = new pixi_js.Sprite({ texture, label: spec.name });
49
+ sprite.cullable = true;
50
+ sprite.width = width;
51
+ sprite.height = height;
52
+ this.target = sprite;
53
+ this.intrinsicWidth = width;
54
+ this.intrinsicHeight = height;
55
+ this.buildFilters();
56
+ } catch (err) {
57
+ this._disposeRenderer();
58
+ throw err;
59
+ }
60
+ }
61
+ /**
62
+ * Per-frame sync hook. Movie._awaitVideoFrames duck-types on this method
63
+ * (same contract as VideoSequence) and awaits it inside gotoFrame — the
64
+ * single frame path shared by playback and export, which is what makes
65
+ * three layers deterministic in both.
66
+ */
67
+ async awaitFrameAt(local) {
68
+ if (!this._renderer || !this._scene || !this._camera || !this._ctx) return;
69
+ const spec = this._threeSpec;
70
+ const t = Math.max(0, Math.min(local, this.duration ?? local));
71
+ if (spec.update) {
72
+ try {
73
+ spec.update(t, this._ctx);
74
+ } catch (err) {
75
+ if (!this._warnedUpdate) {
76
+ this._warnedUpdate = true;
77
+ console.warn("pixi-effects: three update() threw (reported once) \u2014", err);
78
+ }
79
+ }
80
+ }
81
+ this._renderer.render(this._scene, this._camera);
82
+ this.target?.texture.source.update();
83
+ }
84
+ _resolveThreePath(path) {
85
+ const segs = path.split(".");
86
+ if (segs.length < 2) {
87
+ this._warnPath(path, "needs at least <object>.<prop>");
88
+ return null;
89
+ }
90
+ let obj = this._objects[segs[0]];
91
+ if (obj == null) {
92
+ this._warnPath(path, `unknown object "${segs[0]}" \u2014 expose it via setup's { objects }`);
93
+ return null;
94
+ }
95
+ for (let i = 1; i < segs.length - 1; i++) {
96
+ obj = obj[segs[i]];
97
+ if (obj == null) {
98
+ this._warnPath(path, `"${segs[i]}" is undefined along the path`);
99
+ return null;
100
+ }
101
+ }
102
+ const prop = segs[segs.length - 1];
103
+ if (typeof obj !== "object" || !(prop in obj)) {
104
+ this._warnPath(path, `no property "${prop}"`);
105
+ return null;
106
+ }
107
+ return { target: obj, prop };
108
+ }
109
+ _warnPath(path, why) {
110
+ if (this._warnedPaths.has(path)) return;
111
+ this._warnedPaths.add(path);
112
+ console.warn(`pixi-effects: keyframe path three.${path} ${why}; skipped`);
113
+ }
114
+ _disposeRenderer() {
115
+ if (!this._renderer) return;
116
+ try {
117
+ this._renderer.dispose();
118
+ this._renderer.forceContextLoss();
119
+ } catch (err) {
120
+ console.warn("pixi-effects: three renderer dispose threw \u2014", err);
121
+ }
122
+ this._renderer = null;
123
+ }
124
+ destroy() {
125
+ const spec = this._threeSpec;
126
+ if (this._ctx && spec.dispose) {
127
+ try {
128
+ spec.dispose(this._ctx);
129
+ } catch (err) {
130
+ console.warn("pixi-effects: three dispose() threw \u2014", err);
131
+ }
132
+ }
133
+ const texture = this.target?.texture;
134
+ this._disposeRenderer();
135
+ this._scene = null;
136
+ this._camera = null;
137
+ this._ctx = null;
138
+ this._objects = {};
139
+ super.destroy();
140
+ texture?.destroy(true);
141
+ }
142
+ };
143
+ function resolveDim(v, scope) {
144
+ if (v === void 0) return void 0;
145
+ if (typeof v === "number") return v;
146
+ return chunk7OIWYXGV_cjs.evaluateExpr(v, scope);
147
+ }
148
+
149
+ // src/three/index.ts
150
+ function registerThree() {
151
+ chunk7OIWYXGV_cjs.registerSequenceType("three", ThreeSequence);
152
+ }
153
+ function three(spec) {
154
+ return spec;
155
+ }
156
+
157
+ exports.ThreeSequence = ThreeSequence;
158
+ exports.registerThree = registerThree;
159
+ exports.three = three;
160
+ //# sourceMappingURL=three.cjs.map
161
+ //# sourceMappingURL=three.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/three/ThreeSequence.ts","../src/three/index.ts"],"names":["Sequence","buildScope","WebGLRenderer","Scene","PerspectiveCamera","Texture","Sprite","evaluateExpr","registerSequenceType"],"mappings":"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","file":"three.cjs","sourcesContent":["import { Sprite, Texture } from 'pixi.js';\nimport { PerspectiveCamera, Scene, WebGLRenderer, type Camera } from 'three';\nimport { Sequence } from '../sequences/Base';\nimport { buildScope } from '../expr/Scope';\nimport { evaluateExpr } from '../expr/Parser';\nimport type { PathRouters } from '../core/Timeline';\nimport type { PropValue } from '../types';\nimport type { ThreeContext, ThreeSequenceSpec } from './types';\n\nexport class ThreeSequence extends Sequence {\n private _renderer: WebGLRenderer | null = null;\n private _scene: Scene | null = null;\n private _camera: Camera | null = null;\n private _ctx: ThreeContext | null = null;\n private _objects: Record<string, object> = {};\n private _warnedUpdate = false;\n private _warnedPaths = new Set<string>();\n\n private get _threeSpec(): ThreeSequenceSpec {\n return this.spec as unknown as ThreeSequenceSpec;\n }\n\n protected override pathRouters(): PathRouters {\n return { three: (path) => this._resolveThreePath(path) };\n }\n\n async build(): Promise<void> {\n const spec = this._threeSpec;\n if (this.duration === undefined) {\n this.duration = this.parent?.duration ?? this.root.duration;\n }\n\n // Resolve layer size. Expressions see the usual scope; intrinsic w/h are\n // still 0 here (same chicken-and-egg as shapes), so W/H/GW/GH carry it.\n const scope = buildScope(this, this.parent, this.root) as unknown as Record<string, number>;\n const width = resolveDim(spec.width, scope) ?? this.parent?.width ?? this.root.width;\n const height = resolveDim(spec.height, scope) ?? this.parent?.height ?? this.root.height;\n const resolution = spec.resolution ?? 1;\n\n // Offscreen canvas — never attached to the DOM. document.createElement\n // (not OffscreenCanvas) so PIXI's Texture.from and three both accept it.\n const canvas = document.createElement('canvas');\n const renderer = new WebGLRenderer({ canvas, alpha: true, antialias: true });\n this._renderer = renderer;\n try {\n renderer.setSize(Math.round(width * resolution), Math.round(height * resolution), false);\n renderer.setClearColor(0x000000, 0);\n\n const scene = new Scene();\n const camera: Camera = new PerspectiveCamera(50, width / height, 0.1, 2000);\n const ctx: ThreeContext = { scene, camera, renderer, width, height };\n\n const result = await spec.setup(ctx);\n if (result?.camera) ctx.camera = result.camera;\n this._scene = scene;\n this._camera = ctx.camera;\n this._ctx = ctx;\n this._objects = { ...(result?.objects ?? {}) };\n if (!('camera' in this._objects)) this._objects.camera = this._camera;\n\n // Frame 0 so the texture is never blank before the first tick.\n renderer.render(scene, this._camera);\n\n const texture = Texture.from(canvas);\n const sprite = new Sprite({ texture, label: spec.name });\n sprite.cullable = true;\n // Texture is canvas-sized (layer px × resolution); scale back to comp px.\n sprite.width = width;\n sprite.height = height;\n this.target = sprite;\n this.intrinsicWidth = width;\n this.intrinsicHeight = height;\n this.buildFilters();\n } catch (err) {\n this._disposeRenderer();\n throw err;\n }\n }\n\n /**\n * Per-frame sync hook. Movie._awaitVideoFrames duck-types on this method\n * (same contract as VideoSequence) and awaits it inside gotoFrame — the\n * single frame path shared by playback and export, which is what makes\n * three layers deterministic in both.\n */\n async awaitFrameAt(local: number): Promise<void> {\n if (!this._renderer || !this._scene || !this._camera || !this._ctx) return;\n const spec = this._threeSpec;\n const t = Math.max(0, Math.min(local, this.duration ?? local));\n if (spec.update) {\n try {\n spec.update(t, this._ctx);\n } catch (err) {\n if (!this._warnedUpdate) {\n this._warnedUpdate = true;\n console.warn('pixi-effects: three update() threw (reported once) —', err);\n }\n }\n }\n this._renderer.render(this._scene, this._camera);\n (this.target as Sprite | null)?.texture.source.update();\n }\n\n private _resolveThreePath(path: string): { target: object; prop: string } | null {\n const segs = path.split('.');\n if (segs.length < 2) {\n this._warnPath(path, 'needs at least <object>.<prop>');\n return null;\n }\n let obj: unknown = this._objects[segs[0]!];\n if (obj == null) {\n this._warnPath(path, `unknown object \"${segs[0]}\" — expose it via setup's { objects }`);\n return null;\n }\n for (let i = 1; i < segs.length - 1; i++) {\n obj = (obj as Record<string, unknown>)[segs[i]!];\n if (obj == null) {\n this._warnPath(path, `\"${segs[i]}\" is undefined along the path`);\n return null;\n }\n }\n const prop = segs[segs.length - 1]!;\n if (typeof obj !== 'object' || !(prop in (obj as object))) {\n this._warnPath(path, `no property \"${prop}\"`);\n return null;\n }\n return { target: obj as object, prop };\n }\n\n private _warnPath(path: string, why: string): void {\n if (this._warnedPaths.has(path)) return;\n this._warnedPaths.add(path);\n console.warn(`pixi-effects: keyframe path three.${path} ${why}; skipped`);\n }\n\n private _disposeRenderer(): void {\n if (!this._renderer) return;\n try {\n this._renderer.dispose();\n this._renderer.forceContextLoss();\n } catch (err) {\n console.warn('pixi-effects: three renderer dispose threw —', err);\n }\n this._renderer = null;\n }\n\n override destroy(): void {\n const spec = this._threeSpec;\n if (this._ctx && spec.dispose) {\n try { spec.dispose(this._ctx); } catch (err) {\n console.warn('pixi-effects: three dispose() threw —', err);\n }\n }\n const texture = (this.target as Sprite | null)?.texture;\n this._disposeRenderer();\n this._scene = null;\n this._camera = null;\n this._ctx = null;\n this._objects = {};\n super.destroy();\n texture?.destroy(true); // canvas-backed source is per-sequence; safe to kill\n }\n}\n\nfunction resolveDim(v: PropValue | undefined, scope: Record<string, number>): number | undefined {\n if (v === undefined) return undefined;\n if (typeof v === 'number') return v;\n return evaluateExpr(v, scope);\n}\n","/**\n * pixi-effects/three — optional three.js integration.\n *\n * Import this entry only when you use `type: 'three'` sequences; the core\n * `pixi-effects` entry never touches three.js. Call `registerThree()` once\n * before Movie.init builds a composition containing a three sequence.\n */\nimport { registerSequenceType, type SequenceCtor } from '../core/Composition';\nimport { ThreeSequence } from './ThreeSequence';\nimport type { SequenceSpec } from '../types';\nimport type { ThreeSequenceSpec } from './types';\n\nexport { ThreeSequence } from './ThreeSequence';\nexport type { ThreeContext, ThreeSetupResult, ThreeSequenceSpec } from './types';\n\n/** Register the 'three' sequence type. Idempotent; explicit call so `sideEffects: false` bundlers can't drop it. */\nexport function registerThree(): void {\n registerSequenceType('three', ThreeSequence as unknown as SequenceCtor);\n}\n\n/**\n * Typing helper: accepts a strongly-typed three spec and returns it as a\n * core SequenceSpec, keeping three.js types out of the core union.\n */\nexport function three(spec: ThreeSequenceSpec): SequenceSpec {\n return spec as unknown as SequenceSpec;\n}\n"]}
@@ -0,0 +1,79 @@
1
+ import { a as SequenceCommon, n as PropValue, S as SequenceSpec } from './types-CNBilhpz.cjs';
2
+ import { Scene, Camera, WebGLRenderer } from 'three';
3
+ import { S as Sequence, P as PathRouters } from './Base-B1Tdn0Cv.cjs';
4
+ import 'pixi.js';
5
+ import 'gsap';
6
+
7
+ /** Handed to setup / update / dispose. One per three sequence. */
8
+ interface ThreeContext {
9
+ scene: Scene;
10
+ /** Default: PerspectiveCamera(50, width/height, 0.1, 2000). Replaced when setup returns { camera }. */
11
+ camera: Camera;
12
+ renderer: WebGLRenderer;
13
+ /** Resolved layer size in composition px. */
14
+ width: number;
15
+ height: number;
16
+ }
17
+ interface ThreeSetupResult {
18
+ /** Objects addressable from keyframes as `three.<name>.<path>`. `camera` is added implicitly unless present. */
19
+ objects?: Record<string, object>;
20
+ /** Replaces the default camera. */
21
+ camera?: Camera;
22
+ }
23
+ interface ThreeSequenceSpec extends SequenceCommon {
24
+ type: 'three';
25
+ /** Layer size in composition px. Expressions allowed (e.g. 'W * 0.5'). Default: parent composition size. */
26
+ width?: PropValue;
27
+ height?: PropValue;
28
+ /** Supersampling factor for the offscreen canvas. Default 1. */
29
+ resolution?: number;
30
+ /**
31
+ * Build the scene. Add objects to `ctx.scene`, position `ctx.camera`
32
+ * (or replace it entirely by returning `{ camera }`). Async so GLTF /
33
+ * texture loading can be awaited — Movie.init waits for it.
34
+ */
35
+ setup: (ctx: ThreeContext) => Promise<ThreeSetupResult | void> | ThreeSetupResult | void;
36
+ /**
37
+ * Optional per-frame hook; `t` is sequence-local time in seconds.
38
+ * MUST derive state purely from `t` (no wall clock, no unseeded
39
+ * randomness) — playback and export both seek arbitrarily and must
40
+ * produce identical frames.
41
+ */
42
+ update?: (t: number, ctx: ThreeContext) => void;
43
+ /** Cleanup for user-created GPU resources (geometries, materials, textures). Called from destroy(). */
44
+ dispose?: (ctx: ThreeContext) => void;
45
+ }
46
+
47
+ declare class ThreeSequence extends Sequence {
48
+ private _renderer;
49
+ private _scene;
50
+ private _camera;
51
+ private _ctx;
52
+ private _objects;
53
+ private _warnedUpdate;
54
+ private _warnedPaths;
55
+ private get _threeSpec();
56
+ protected pathRouters(): PathRouters;
57
+ build(): Promise<void>;
58
+ /**
59
+ * Per-frame sync hook. Movie._awaitVideoFrames duck-types on this method
60
+ * (same contract as VideoSequence) and awaits it inside gotoFrame — the
61
+ * single frame path shared by playback and export, which is what makes
62
+ * three layers deterministic in both.
63
+ */
64
+ awaitFrameAt(local: number): Promise<void>;
65
+ private _resolveThreePath;
66
+ private _warnPath;
67
+ private _disposeRenderer;
68
+ destroy(): void;
69
+ }
70
+
71
+ /** Register the 'three' sequence type. Idempotent; explicit call so `sideEffects: false` bundlers can't drop it. */
72
+ declare function registerThree(): void;
73
+ /**
74
+ * Typing helper: accepts a strongly-typed three spec and returns it as a
75
+ * core SequenceSpec, keeping three.js types out of the core union.
76
+ */
77
+ declare function three(spec: ThreeSequenceSpec): SequenceSpec;
78
+
79
+ export { type ThreeContext, ThreeSequence, type ThreeSequenceSpec, type ThreeSetupResult, registerThree, three };
@@ -0,0 +1,79 @@
1
+ import { a as SequenceCommon, n as PropValue, S as SequenceSpec } from './types-CNBilhpz.js';
2
+ import { Scene, Camera, WebGLRenderer } from 'three';
3
+ import { S as Sequence, P as PathRouters } from './Base-Bh_VSusi.js';
4
+ import 'pixi.js';
5
+ import 'gsap';
6
+
7
+ /** Handed to setup / update / dispose. One per three sequence. */
8
+ interface ThreeContext {
9
+ scene: Scene;
10
+ /** Default: PerspectiveCamera(50, width/height, 0.1, 2000). Replaced when setup returns { camera }. */
11
+ camera: Camera;
12
+ renderer: WebGLRenderer;
13
+ /** Resolved layer size in composition px. */
14
+ width: number;
15
+ height: number;
16
+ }
17
+ interface ThreeSetupResult {
18
+ /** Objects addressable from keyframes as `three.<name>.<path>`. `camera` is added implicitly unless present. */
19
+ objects?: Record<string, object>;
20
+ /** Replaces the default camera. */
21
+ camera?: Camera;
22
+ }
23
+ interface ThreeSequenceSpec extends SequenceCommon {
24
+ type: 'three';
25
+ /** Layer size in composition px. Expressions allowed (e.g. 'W * 0.5'). Default: parent composition size. */
26
+ width?: PropValue;
27
+ height?: PropValue;
28
+ /** Supersampling factor for the offscreen canvas. Default 1. */
29
+ resolution?: number;
30
+ /**
31
+ * Build the scene. Add objects to `ctx.scene`, position `ctx.camera`
32
+ * (or replace it entirely by returning `{ camera }`). Async so GLTF /
33
+ * texture loading can be awaited — Movie.init waits for it.
34
+ */
35
+ setup: (ctx: ThreeContext) => Promise<ThreeSetupResult | void> | ThreeSetupResult | void;
36
+ /**
37
+ * Optional per-frame hook; `t` is sequence-local time in seconds.
38
+ * MUST derive state purely from `t` (no wall clock, no unseeded
39
+ * randomness) — playback and export both seek arbitrarily and must
40
+ * produce identical frames.
41
+ */
42
+ update?: (t: number, ctx: ThreeContext) => void;
43
+ /** Cleanup for user-created GPU resources (geometries, materials, textures). Called from destroy(). */
44
+ dispose?: (ctx: ThreeContext) => void;
45
+ }
46
+
47
+ declare class ThreeSequence extends Sequence {
48
+ private _renderer;
49
+ private _scene;
50
+ private _camera;
51
+ private _ctx;
52
+ private _objects;
53
+ private _warnedUpdate;
54
+ private _warnedPaths;
55
+ private get _threeSpec();
56
+ protected pathRouters(): PathRouters;
57
+ build(): Promise<void>;
58
+ /**
59
+ * Per-frame sync hook. Movie._awaitVideoFrames duck-types on this method
60
+ * (same contract as VideoSequence) and awaits it inside gotoFrame — the
61
+ * single frame path shared by playback and export, which is what makes
62
+ * three layers deterministic in both.
63
+ */
64
+ awaitFrameAt(local: number): Promise<void>;
65
+ private _resolveThreePath;
66
+ private _warnPath;
67
+ private _disposeRenderer;
68
+ destroy(): void;
69
+ }
70
+
71
+ /** Register the 'three' sequence type. Idempotent; explicit call so `sideEffects: false` bundlers can't drop it. */
72
+ declare function registerThree(): void;
73
+ /**
74
+ * Typing helper: accepts a strongly-typed three spec and returns it as a
75
+ * core SequenceSpec, keeping three.js types out of the core union.
76
+ */
77
+ declare function three(spec: ThreeSequenceSpec): SequenceSpec;
78
+
79
+ export { type ThreeContext, ThreeSequence, type ThreeSequenceSpec, type ThreeSetupResult, registerThree, three };
package/dist/three.js ADDED
@@ -0,0 +1,157 @@
1
+ import { Sequence, buildScope, evaluateExpr, registerSequenceType } from './chunk-VJCDG6YG.js';
2
+ import { Texture, Sprite } from 'pixi.js';
3
+ import { WebGLRenderer, Scene, PerspectiveCamera } from 'three';
4
+
5
+ var ThreeSequence = class extends Sequence {
6
+ _renderer = null;
7
+ _scene = null;
8
+ _camera = null;
9
+ _ctx = null;
10
+ _objects = {};
11
+ _warnedUpdate = false;
12
+ _warnedPaths = /* @__PURE__ */ new Set();
13
+ get _threeSpec() {
14
+ return this.spec;
15
+ }
16
+ pathRouters() {
17
+ return { three: (path) => this._resolveThreePath(path) };
18
+ }
19
+ async build() {
20
+ const spec = this._threeSpec;
21
+ if (this.duration === void 0) {
22
+ this.duration = this.parent?.duration ?? this.root.duration;
23
+ }
24
+ const scope = buildScope(this, this.parent, this.root);
25
+ const width = resolveDim(spec.width, scope) ?? this.parent?.width ?? this.root.width;
26
+ const height = resolveDim(spec.height, scope) ?? this.parent?.height ?? this.root.height;
27
+ const resolution = spec.resolution ?? 1;
28
+ const canvas = document.createElement("canvas");
29
+ const renderer = new WebGLRenderer({ canvas, alpha: true, antialias: true });
30
+ this._renderer = renderer;
31
+ try {
32
+ renderer.setSize(Math.round(width * resolution), Math.round(height * resolution), false);
33
+ renderer.setClearColor(0, 0);
34
+ const scene = new Scene();
35
+ const camera = new PerspectiveCamera(50, width / height, 0.1, 2e3);
36
+ const ctx = { scene, camera, renderer, width, height };
37
+ const result = await spec.setup(ctx);
38
+ if (result?.camera) ctx.camera = result.camera;
39
+ this._scene = scene;
40
+ this._camera = ctx.camera;
41
+ this._ctx = ctx;
42
+ this._objects = { ...result?.objects ?? {} };
43
+ if (!("camera" in this._objects)) this._objects.camera = this._camera;
44
+ renderer.render(scene, this._camera);
45
+ const texture = Texture.from(canvas);
46
+ const sprite = new Sprite({ texture, label: spec.name });
47
+ sprite.cullable = true;
48
+ sprite.width = width;
49
+ sprite.height = height;
50
+ this.target = sprite;
51
+ this.intrinsicWidth = width;
52
+ this.intrinsicHeight = height;
53
+ this.buildFilters();
54
+ } catch (err) {
55
+ this._disposeRenderer();
56
+ throw err;
57
+ }
58
+ }
59
+ /**
60
+ * Per-frame sync hook. Movie._awaitVideoFrames duck-types on this method
61
+ * (same contract as VideoSequence) and awaits it inside gotoFrame — the
62
+ * single frame path shared by playback and export, which is what makes
63
+ * three layers deterministic in both.
64
+ */
65
+ async awaitFrameAt(local) {
66
+ if (!this._renderer || !this._scene || !this._camera || !this._ctx) return;
67
+ const spec = this._threeSpec;
68
+ const t = Math.max(0, Math.min(local, this.duration ?? local));
69
+ if (spec.update) {
70
+ try {
71
+ spec.update(t, this._ctx);
72
+ } catch (err) {
73
+ if (!this._warnedUpdate) {
74
+ this._warnedUpdate = true;
75
+ console.warn("pixi-effects: three update() threw (reported once) \u2014", err);
76
+ }
77
+ }
78
+ }
79
+ this._renderer.render(this._scene, this._camera);
80
+ this.target?.texture.source.update();
81
+ }
82
+ _resolveThreePath(path) {
83
+ const segs = path.split(".");
84
+ if (segs.length < 2) {
85
+ this._warnPath(path, "needs at least <object>.<prop>");
86
+ return null;
87
+ }
88
+ let obj = this._objects[segs[0]];
89
+ if (obj == null) {
90
+ this._warnPath(path, `unknown object "${segs[0]}" \u2014 expose it via setup's { objects }`);
91
+ return null;
92
+ }
93
+ for (let i = 1; i < segs.length - 1; i++) {
94
+ obj = obj[segs[i]];
95
+ if (obj == null) {
96
+ this._warnPath(path, `"${segs[i]}" is undefined along the path`);
97
+ return null;
98
+ }
99
+ }
100
+ const prop = segs[segs.length - 1];
101
+ if (typeof obj !== "object" || !(prop in obj)) {
102
+ this._warnPath(path, `no property "${prop}"`);
103
+ return null;
104
+ }
105
+ return { target: obj, prop };
106
+ }
107
+ _warnPath(path, why) {
108
+ if (this._warnedPaths.has(path)) return;
109
+ this._warnedPaths.add(path);
110
+ console.warn(`pixi-effects: keyframe path three.${path} ${why}; skipped`);
111
+ }
112
+ _disposeRenderer() {
113
+ if (!this._renderer) return;
114
+ try {
115
+ this._renderer.dispose();
116
+ this._renderer.forceContextLoss();
117
+ } catch (err) {
118
+ console.warn("pixi-effects: three renderer dispose threw \u2014", err);
119
+ }
120
+ this._renderer = null;
121
+ }
122
+ destroy() {
123
+ const spec = this._threeSpec;
124
+ if (this._ctx && spec.dispose) {
125
+ try {
126
+ spec.dispose(this._ctx);
127
+ } catch (err) {
128
+ console.warn("pixi-effects: three dispose() threw \u2014", err);
129
+ }
130
+ }
131
+ const texture = this.target?.texture;
132
+ this._disposeRenderer();
133
+ this._scene = null;
134
+ this._camera = null;
135
+ this._ctx = null;
136
+ this._objects = {};
137
+ super.destroy();
138
+ texture?.destroy(true);
139
+ }
140
+ };
141
+ function resolveDim(v, scope) {
142
+ if (v === void 0) return void 0;
143
+ if (typeof v === "number") return v;
144
+ return evaluateExpr(v, scope);
145
+ }
146
+
147
+ // src/three/index.ts
148
+ function registerThree() {
149
+ registerSequenceType("three", ThreeSequence);
150
+ }
151
+ function three(spec) {
152
+ return spec;
153
+ }
154
+
155
+ export { ThreeSequence, registerThree, three };
156
+ //# sourceMappingURL=three.js.map
157
+ //# sourceMappingURL=three.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/three/ThreeSequence.ts","../src/three/index.ts"],"names":[],"mappings":";;;;AASO,IAAM,aAAA,GAAN,cAA4B,QAAA,CAAS;AAAA,EAClC,SAAA,GAAkC,IAAA;AAAA,EAClC,MAAA,GAAuB,IAAA;AAAA,EACvB,OAAA,GAAyB,IAAA;AAAA,EACzB,IAAA,GAA4B,IAAA;AAAA,EAC5B,WAAmC,EAAC;AAAA,EACpC,aAAA,GAAgB,KAAA;AAAA,EAChB,YAAA,uBAAmB,GAAA,EAAY;AAAA,EAEvC,IAAY,UAAA,GAAgC;AAC1C,IAAA,OAAO,IAAA,CAAK,IAAA;AAAA,EACd;AAAA,EAEmB,WAAA,GAA2B;AAC5C,IAAA,OAAO,EAAE,KAAA,EAAO,CAAC,SAAS,IAAA,CAAK,iBAAA,CAAkB,IAAI,CAAA,EAAE;AAAA,EACzD;AAAA,EAEA,MAAM,KAAA,GAAuB;AAC3B,IAAA,MAAM,OAAO,IAAA,CAAK,UAAA;AAClB,IAAA,IAAI,IAAA,CAAK,aAAa,MAAA,EAAW;AAC/B,MAAA,IAAA,CAAK,QAAA,GAAW,IAAA,CAAK,MAAA,EAAQ,QAAA,IAAY,KAAK,IAAA,CAAK,QAAA;AAAA,IACrD;AAIA,IAAA,MAAM,QAAQ,UAAA,CAAW,IAAA,EAAM,IAAA,CAAK,MAAA,EAAQ,KAAK,IAAI,CAAA;AACrD,IAAA,MAAM,KAAA,GAAQ,UAAA,CAAW,IAAA,CAAK,KAAA,EAAO,KAAK,KAAK,IAAA,CAAK,MAAA,EAAQ,KAAA,IAAS,IAAA,CAAK,IAAA,CAAK,KAAA;AAC/E,IAAA,MAAM,MAAA,GAAS,UAAA,CAAW,IAAA,CAAK,MAAA,EAAQ,KAAK,KAAK,IAAA,CAAK,MAAA,EAAQ,MAAA,IAAU,IAAA,CAAK,IAAA,CAAK,MAAA;AAClF,IAAA,MAAM,UAAA,GAAa,KAAK,UAAA,IAAc,CAAA;AAItC,IAAA,MAAM,MAAA,GAAS,QAAA,CAAS,aAAA,CAAc,QAAQ,CAAA;AAC9C,IAAA,MAAM,QAAA,GAAW,IAAI,aAAA,CAAc,EAAE,QAAQ,KAAA,EAAO,IAAA,EAAM,SAAA,EAAW,IAAA,EAAM,CAAA;AAC3E,IAAA,IAAA,CAAK,SAAA,GAAY,QAAA;AACjB,IAAA,IAAI;AACF,MAAA,QAAA,CAAS,OAAA,CAAQ,IAAA,CAAK,KAAA,CAAM,KAAA,GAAQ,UAAU,CAAA,EAAG,IAAA,CAAK,KAAA,CAAM,MAAA,GAAS,UAAU,CAAA,EAAG,KAAK,CAAA;AACvF,MAAA,QAAA,CAAS,aAAA,CAAc,GAAU,CAAC,CAAA;AAElC,MAAA,MAAM,KAAA,GAAQ,IAAI,KAAA,EAAM;AACxB,MAAA,MAAM,SAAiB,IAAI,iBAAA,CAAkB,IAAI,KAAA,GAAQ,MAAA,EAAQ,KAAK,GAAI,CAAA;AAC1E,MAAA,MAAM,MAAoB,EAAE,KAAA,EAAO,MAAA,EAAQ,QAAA,EAAU,OAAO,MAAA,EAAO;AAEnE,MAAA,MAAM,MAAA,GAAS,MAAM,IAAA,CAAK,KAAA,CAAM,GAAG,CAAA;AACnC,MAAA,IAAI,MAAA,EAAQ,MAAA,EAAQ,GAAA,CAAI,MAAA,GAAS,MAAA,CAAO,MAAA;AACxC,MAAA,IAAA,CAAK,MAAA,GAAS,KAAA;AACd,MAAA,IAAA,CAAK,UAAU,GAAA,CAAI,MAAA;AACnB,MAAA,IAAA,CAAK,IAAA,GAAO,GAAA;AACZ,MAAA,IAAA,CAAK,WAAW,EAAE,GAAI,MAAA,EAAQ,OAAA,IAAW,EAAC,EAAG;AAC7C,MAAA,IAAI,EAAE,QAAA,IAAY,IAAA,CAAK,WAAW,IAAA,CAAK,QAAA,CAAS,SAAS,IAAA,CAAK,OAAA;AAG9D,MAAA,QAAA,CAAS,MAAA,CAAO,KAAA,EAAO,IAAA,CAAK,OAAO,CAAA;AAEnC,MAAA,MAAM,OAAA,GAAU,OAAA,CAAQ,IAAA,CAAK,MAAM,CAAA;AACnC,MAAA,MAAM,MAAA,GAAS,IAAI,MAAA,CAAO,EAAE,SAAS,KAAA,EAAO,IAAA,CAAK,MAAM,CAAA;AACvD,MAAA,MAAA,CAAO,QAAA,GAAW,IAAA;AAElB,MAAA,MAAA,CAAO,KAAA,GAAQ,KAAA;AACf,MAAA,MAAA,CAAO,MAAA,GAAS,MAAA;AAChB,MAAA,IAAA,CAAK,MAAA,GAAS,MAAA;AACd,MAAA,IAAA,CAAK,cAAA,GAAiB,KAAA;AACtB,MAAA,IAAA,CAAK,eAAA,GAAkB,MAAA;AACvB,MAAA,IAAA,CAAK,YAAA,EAAa;AAAA,IACpB,SAAS,GAAA,EAAK;AACZ,MAAA,IAAA,CAAK,gBAAA,EAAiB;AACtB,MAAA,MAAM,GAAA;AAAA,IACR;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAQA,MAAM,aAAa,KAAA,EAA8B;AAC/C,IAAA,IAAI,CAAC,IAAA,CAAK,SAAA,IAAa,CAAC,IAAA,CAAK,MAAA,IAAU,CAAC,IAAA,CAAK,OAAA,IAAW,CAAC,IAAA,CAAK,IAAA,EAAM;AACpE,IAAA,MAAM,OAAO,IAAA,CAAK,UAAA;AAClB,IAAA,MAAM,CAAA,GAAI,IAAA,CAAK,GAAA,CAAI,CAAA,EAAG,IAAA,CAAK,IAAI,KAAA,EAAO,IAAA,CAAK,QAAA,IAAY,KAAK,CAAC,CAAA;AAC7D,IAAA,IAAI,KAAK,MAAA,EAAQ;AACf,MAAA,IAAI;AACF,QAAA,IAAA,CAAK,MAAA,CAAO,CAAA,EAAG,IAAA,CAAK,IAAI,CAAA;AAAA,MAC1B,SAAS,GAAA,EAAK;AACZ,QAAA,IAAI,CAAC,KAAK,aAAA,EAAe;AACvB,UAAA,IAAA,CAAK,aAAA,GAAgB,IAAA;AACrB,UAAA,OAAA,CAAQ,IAAA,CAAK,6DAAwD,GAAG,CAAA;AAAA,QAC1E;AAAA,MACF;AAAA,IACF;AACA,IAAA,IAAA,CAAK,SAAA,CAAU,MAAA,CAAO,IAAA,CAAK,MAAA,EAAQ,KAAK,OAAO,CAAA;AAC/C,IAAC,IAAA,CAAK,MAAA,EAA0B,OAAA,CAAQ,MAAA,CAAO,MAAA,EAAO;AAAA,EACxD;AAAA,EAEQ,kBAAkB,IAAA,EAAuD;AAC/E,IAAA,MAAM,IAAA,GAAO,IAAA,CAAK,KAAA,CAAM,GAAG,CAAA;AAC3B,IAAA,IAAI,IAAA,CAAK,SAAS,CAAA,EAAG;AACnB,MAAA,IAAA,CAAK,SAAA,CAAU,MAAM,gCAAgC,CAAA;AACrD,MAAA,OAAO,IAAA;AAAA,IACT;AACA,IAAA,IAAI,GAAA,GAAe,IAAA,CAAK,QAAA,CAAS,IAAA,CAAK,CAAC,CAAE,CAAA;AACzC,IAAA,IAAI,OAAO,IAAA,EAAM;AACf,MAAA,IAAA,CAAK,UAAU,IAAA,EAAM,CAAA,gBAAA,EAAmB,IAAA,CAAK,CAAC,CAAC,CAAA,0CAAA,CAAuC,CAAA;AACtF,MAAA,OAAO,IAAA;AAAA,IACT;AACA,IAAA,KAAA,IAAS,IAAI,CAAA,EAAG,CAAA,GAAI,IAAA,CAAK,MAAA,GAAS,GAAG,CAAA,EAAA,EAAK;AACxC,MAAA,GAAA,GAAO,GAAA,CAAgC,IAAA,CAAK,CAAC,CAAE,CAAA;AAC/C,MAAA,IAAI,OAAO,IAAA,EAAM;AACf,QAAA,IAAA,CAAK,UAAU,IAAA,EAAM,CAAA,CAAA,EAAI,IAAA,CAAK,CAAC,CAAC,CAAA,6BAAA,CAA+B,CAAA;AAC/D,QAAA,OAAO,IAAA;AAAA,MACT;AAAA,IACF;AACA,IAAA,MAAM,IAAA,GAAO,IAAA,CAAK,IAAA,CAAK,MAAA,GAAS,CAAC,CAAA;AACjC,IAAA,IAAI,OAAO,GAAA,KAAQ,QAAA,IAAY,EAAE,QAAS,GAAA,CAAA,EAAiB;AACzD,MAAA,IAAA,CAAK,SAAA,CAAU,IAAA,EAAM,CAAA,aAAA,EAAgB,IAAI,CAAA,CAAA,CAAG,CAAA;AAC5C,MAAA,OAAO,IAAA;AAAA,IACT;AACA,IAAA,OAAO,EAAE,MAAA,EAAQ,GAAA,EAAe,IAAA,EAAK;AAAA,EACvC;AAAA,EAEQ,SAAA,CAAU,MAAc,GAAA,EAAmB;AACjD,IAAA,IAAI,IAAA,CAAK,YAAA,CAAa,GAAA,CAAI,IAAI,CAAA,EAAG;AACjC,IAAA,IAAA,CAAK,YAAA,CAAa,IAAI,IAAI,CAAA;AAC1B,IAAA,OAAA,CAAQ,IAAA,CAAK,CAAA,kCAAA,EAAqC,IAAI,CAAA,CAAA,EAAI,GAAG,CAAA,SAAA,CAAW,CAAA;AAAA,EAC1E;AAAA,EAEQ,gBAAA,GAAyB;AAC/B,IAAA,IAAI,CAAC,KAAK,SAAA,EAAW;AACrB,IAAA,IAAI;AACF,MAAA,IAAA,CAAK,UAAU,OAAA,EAAQ;AACvB,MAAA,IAAA,CAAK,UAAU,gBAAA,EAAiB;AAAA,IAClC,SAAS,GAAA,EAAK;AACZ,MAAA,OAAA,CAAQ,IAAA,CAAK,qDAAgD,GAAG,CAAA;AAAA,IAClE;AACA,IAAA,IAAA,CAAK,SAAA,GAAY,IAAA;AAAA,EACnB;AAAA,EAES,OAAA,GAAgB;AACvB,IAAA,MAAM,OAAO,IAAA,CAAK,UAAA;AAClB,IAAA,IAAI,IAAA,CAAK,IAAA,IAAQ,IAAA,CAAK,OAAA,EAAS;AAC7B,MAAA,IAAI;AAAE,QAAA,IAAA,CAAK,OAAA,CAAQ,KAAK,IAAI,CAAA;AAAA,MAAG,SAAS,GAAA,EAAK;AAC3C,QAAA,OAAA,CAAQ,IAAA,CAAK,8CAAyC,GAAG,CAAA;AAAA,MAC3D;AAAA,IACF;AACA,IAAA,MAAM,OAAA,GAAW,KAAK,MAAA,EAA0B,OAAA;AAChD,IAAA,IAAA,CAAK,gBAAA,EAAiB;AACtB,IAAA,IAAA,CAAK,MAAA,GAAS,IAAA;AACd,IAAA,IAAA,CAAK,OAAA,GAAU,IAAA;AACf,IAAA,IAAA,CAAK,IAAA,GAAO,IAAA;AACZ,IAAA,IAAA,CAAK,WAAW,EAAC;AACjB,IAAA,KAAA,CAAM,OAAA,EAAQ;AACd,IAAA,OAAA,EAAS,QAAQ,IAAI,CAAA;AAAA,EACvB;AACF;AAEA,SAAS,UAAA,CAAW,GAA0B,KAAA,EAAmD;AAC/F,EAAA,IAAI,CAAA,KAAM,QAAW,OAAO,MAAA;AAC5B,EAAA,IAAI,OAAO,CAAA,KAAM,QAAA,EAAU,OAAO,CAAA;AAClC,EAAA,OAAO,YAAA,CAAa,GAAG,KAAK,CAAA;AAC9B;;;ACxJO,SAAS,aAAA,GAAsB;AACpC,EAAA,oBAAA,CAAqB,SAAS,aAAwC,CAAA;AACxE;AAMO,SAAS,MAAM,IAAA,EAAuC;AAC3D,EAAA,OAAO,IAAA;AACT","file":"three.js","sourcesContent":["import { Sprite, Texture } from 'pixi.js';\nimport { PerspectiveCamera, Scene, WebGLRenderer, type Camera } from 'three';\nimport { Sequence } from '../sequences/Base';\nimport { buildScope } from '../expr/Scope';\nimport { evaluateExpr } from '../expr/Parser';\nimport type { PathRouters } from '../core/Timeline';\nimport type { PropValue } from '../types';\nimport type { ThreeContext, ThreeSequenceSpec } from './types';\n\nexport class ThreeSequence extends Sequence {\n private _renderer: WebGLRenderer | null = null;\n private _scene: Scene | null = null;\n private _camera: Camera | null = null;\n private _ctx: ThreeContext | null = null;\n private _objects: Record<string, object> = {};\n private _warnedUpdate = false;\n private _warnedPaths = new Set<string>();\n\n private get _threeSpec(): ThreeSequenceSpec {\n return this.spec as unknown as ThreeSequenceSpec;\n }\n\n protected override pathRouters(): PathRouters {\n return { three: (path) => this._resolveThreePath(path) };\n }\n\n async build(): Promise<void> {\n const spec = this._threeSpec;\n if (this.duration === undefined) {\n this.duration = this.parent?.duration ?? this.root.duration;\n }\n\n // Resolve layer size. Expressions see the usual scope; intrinsic w/h are\n // still 0 here (same chicken-and-egg as shapes), so W/H/GW/GH carry it.\n const scope = buildScope(this, this.parent, this.root) as unknown as Record<string, number>;\n const width = resolveDim(spec.width, scope) ?? this.parent?.width ?? this.root.width;\n const height = resolveDim(spec.height, scope) ?? this.parent?.height ?? this.root.height;\n const resolution = spec.resolution ?? 1;\n\n // Offscreen canvas — never attached to the DOM. document.createElement\n // (not OffscreenCanvas) so PIXI's Texture.from and three both accept it.\n const canvas = document.createElement('canvas');\n const renderer = new WebGLRenderer({ canvas, alpha: true, antialias: true });\n this._renderer = renderer;\n try {\n renderer.setSize(Math.round(width * resolution), Math.round(height * resolution), false);\n renderer.setClearColor(0x000000, 0);\n\n const scene = new Scene();\n const camera: Camera = new PerspectiveCamera(50, width / height, 0.1, 2000);\n const ctx: ThreeContext = { scene, camera, renderer, width, height };\n\n const result = await spec.setup(ctx);\n if (result?.camera) ctx.camera = result.camera;\n this._scene = scene;\n this._camera = ctx.camera;\n this._ctx = ctx;\n this._objects = { ...(result?.objects ?? {}) };\n if (!('camera' in this._objects)) this._objects.camera = this._camera;\n\n // Frame 0 so the texture is never blank before the first tick.\n renderer.render(scene, this._camera);\n\n const texture = Texture.from(canvas);\n const sprite = new Sprite({ texture, label: spec.name });\n sprite.cullable = true;\n // Texture is canvas-sized (layer px × resolution); scale back to comp px.\n sprite.width = width;\n sprite.height = height;\n this.target = sprite;\n this.intrinsicWidth = width;\n this.intrinsicHeight = height;\n this.buildFilters();\n } catch (err) {\n this._disposeRenderer();\n throw err;\n }\n }\n\n /**\n * Per-frame sync hook. Movie._awaitVideoFrames duck-types on this method\n * (same contract as VideoSequence) and awaits it inside gotoFrame — the\n * single frame path shared by playback and export, which is what makes\n * three layers deterministic in both.\n */\n async awaitFrameAt(local: number): Promise<void> {\n if (!this._renderer || !this._scene || !this._camera || !this._ctx) return;\n const spec = this._threeSpec;\n const t = Math.max(0, Math.min(local, this.duration ?? local));\n if (spec.update) {\n try {\n spec.update(t, this._ctx);\n } catch (err) {\n if (!this._warnedUpdate) {\n this._warnedUpdate = true;\n console.warn('pixi-effects: three update() threw (reported once) —', err);\n }\n }\n }\n this._renderer.render(this._scene, this._camera);\n (this.target as Sprite | null)?.texture.source.update();\n }\n\n private _resolveThreePath(path: string): { target: object; prop: string } | null {\n const segs = path.split('.');\n if (segs.length < 2) {\n this._warnPath(path, 'needs at least <object>.<prop>');\n return null;\n }\n let obj: unknown = this._objects[segs[0]!];\n if (obj == null) {\n this._warnPath(path, `unknown object \"${segs[0]}\" — expose it via setup's { objects }`);\n return null;\n }\n for (let i = 1; i < segs.length - 1; i++) {\n obj = (obj as Record<string, unknown>)[segs[i]!];\n if (obj == null) {\n this._warnPath(path, `\"${segs[i]}\" is undefined along the path`);\n return null;\n }\n }\n const prop = segs[segs.length - 1]!;\n if (typeof obj !== 'object' || !(prop in (obj as object))) {\n this._warnPath(path, `no property \"${prop}\"`);\n return null;\n }\n return { target: obj as object, prop };\n }\n\n private _warnPath(path: string, why: string): void {\n if (this._warnedPaths.has(path)) return;\n this._warnedPaths.add(path);\n console.warn(`pixi-effects: keyframe path three.${path} ${why}; skipped`);\n }\n\n private _disposeRenderer(): void {\n if (!this._renderer) return;\n try {\n this._renderer.dispose();\n this._renderer.forceContextLoss();\n } catch (err) {\n console.warn('pixi-effects: three renderer dispose threw —', err);\n }\n this._renderer = null;\n }\n\n override destroy(): void {\n const spec = this._threeSpec;\n if (this._ctx && spec.dispose) {\n try { spec.dispose(this._ctx); } catch (err) {\n console.warn('pixi-effects: three dispose() threw —', err);\n }\n }\n const texture = (this.target as Sprite | null)?.texture;\n this._disposeRenderer();\n this._scene = null;\n this._camera = null;\n this._ctx = null;\n this._objects = {};\n super.destroy();\n texture?.destroy(true); // canvas-backed source is per-sequence; safe to kill\n }\n}\n\nfunction resolveDim(v: PropValue | undefined, scope: Record<string, number>): number | undefined {\n if (v === undefined) return undefined;\n if (typeof v === 'number') return v;\n return evaluateExpr(v, scope);\n}\n","/**\n * pixi-effects/three — optional three.js integration.\n *\n * Import this entry only when you use `type: 'three'` sequences; the core\n * `pixi-effects` entry never touches three.js. Call `registerThree()` once\n * before Movie.init builds a composition containing a three sequence.\n */\nimport { registerSequenceType, type SequenceCtor } from '../core/Composition';\nimport { ThreeSequence } from './ThreeSequence';\nimport type { SequenceSpec } from '../types';\nimport type { ThreeSequenceSpec } from './types';\n\nexport { ThreeSequence } from './ThreeSequence';\nexport type { ThreeContext, ThreeSetupResult, ThreeSequenceSpec } from './types';\n\n/** Register the 'three' sequence type. Idempotent; explicit call so `sideEffects: false` bundlers can't drop it. */\nexport function registerThree(): void {\n registerSequenceType('three', ThreeSequence as unknown as SequenceCtor);\n}\n\n/**\n * Typing helper: accepts a strongly-typed three spec and returns it as a\n * core SequenceSpec, keeping three.js types out of the core union.\n */\nexport function three(spec: ThreeSequenceSpec): SequenceSpec {\n return spec as unknown as SequenceSpec;\n}\n"]}