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/README.md CHANGED
@@ -1,24 +1,107 @@
1
1
  # pixi-effects
2
2
 
3
- > **Status**: v0.1.0. API stable; semver from here.
3
+ > **Status**: experimental — current release `0.2.0`. The API may still change between minor versions.
4
4
 
5
- **[Live demos →](https://yjmtmtk.github.io/pixi-effects/)** · 8 numbered examples + an in-browser playground.
5
+ **[Live demos →](https://yjmtmtk.github.io/pixi-effects/)** · 12 numbered examples + an in-browser playground.
6
6
 
7
7
  Declarative composition and video rendering for the web. After Effects-style timelines on top of [PixiJS v8](https://pixijs.com/) and [GSAP](https://gsap.com/), with strict TypeScript types. Render to MP4 / WebM / MOV via [mediabunny](https://mediabunny.dev/).
8
8
 
9
- - **Declarative DSL** — describe your composition as a tree of typed sequences (text, image, video, audio, nested compositions). No imperative tween code.
9
+ - **Declarative DSL** — describe your composition as a tree of typed sequences (text, image, video, audio, shapes, nested compositions). No imperative tween code.
10
10
  - **Expression language** — sprinkle `'GW * 0.5'` or `'min(W, H) / 2'` anywhere a number goes. Resolved at runtime against a sequence-relative scope.
11
- - **Filters** — chroma key, blur, color matrix. Animatable per-keyframe.
11
+ - **Filters, masks, transitions** — chroma key, blur, color matrix (or any PixiJS filter); inline masks; seven scene transitions (`crossfade`, `wipe`, `iris`, `slide`, `dip`, `zoom`, `dissolve`).
12
+ - **Presets** — `kenBurns` for stills, `withFade` for fade-in/out.
13
+ - **2.5D layers & camera** — add `threeD: true`, `z`, `rotationX/Y` and a `{ type: 'camera' }` layer for parallax, flips and dolly zooms; no three.js needed.
14
+ - **three.js layer** *(optional)* — drop a real three.js scene in as a layer via `pixi-effects/three`; keyframes drive its objects (`three.cube.rotation.y`).
12
15
  - **Built-in player UI** — drop-in HTML5-`<video>`-style overlay controller (play, scrub, mute, volume, fullscreen, export-to-file).
13
16
  - **MP4 / WebM / MOV export** — pick container and quality from the controller, or call `movie.render()` from code.
14
- - **Tiny dependency surface** — only `mediabunny` (runtime) plus PixiJS and GSAP (peer deps).
17
+ - **Tiny dependency surface** — only `mediabunny` (runtime) plus PixiJS and GSAP (peer deps). three.js is an *optional* peer, needed only if you import `pixi-effects/three`.
15
18
 
16
19
  ## Install
17
20
 
18
21
  ```bash
19
22
  npm install pixi-effects pixi.js gsap
23
+ npm install three # optional — only if you import `pixi-effects/three`
20
24
  ```
21
25
 
26
+ ### Browser via CDN (no bundler)
27
+
28
+ Drop the imports into an [importmap](https://developer.mozilla.org/docs/Web/HTML/Element/script/type/importmap) and you're done — see [`examples/`](./examples/) for full files.
29
+
30
+ ```html
31
+ <script type="importmap">
32
+ {
33
+ "imports": {
34
+ "pixi.js": "https://esm.sh/pixi.js@8.22.0?bundle-deps",
35
+ "gsap": "https://esm.sh/gsap@3.12.5",
36
+ "gsap/PixiPlugin": "https://esm.sh/gsap@3.12.5/PixiPlugin",
37
+ "mediabunny": "https://esm.sh/mediabunny",
38
+ "pixi-effects": "https://cdn.jsdelivr.net/npm/pixi-effects@0.2.0/dist/index.js",
39
+ "pixi-effects/controller": "https://cdn.jsdelivr.net/npm/pixi-effects@0.2.0/dist/Controller.js"
40
+ }
41
+ }
42
+ </script>
43
+ <script type="module">
44
+ import { Movie } from 'pixi-effects';
45
+ import { Controller } from 'pixi-effects/controller';
46
+ // ...
47
+ </script>
48
+ ```
49
+
50
+ Load the `dist/` files **as they are** (jsDelivr's `/npm/…/dist/…`, or unpkg's `https://unpkg.com/pixi-effects@0.2.0/dist/index.js`) rather than a CDN-rebundled build such as `esm.sh/pixi-effects` or jsDelivr's `+esm`: the entries (`pixi-effects`, `…/controller`, `…/three`) share internal chunks, which only works when each file is served untouched.
51
+
52
+ > **Using three.js?** Add two more entries (`three` and `pixi-effects/three`) to this importmap — see [Adding three.js](#adding-threejs-optional) below.
53
+ >
54
+ > **Want the unreleased `main`?** Point the `pixi-effects*` entries at the GitHub Pages build instead: `https://yjmtmtk.github.io/pixi-effects/dist/index.js` (and `Controller.js`, `three.js`).
55
+
56
+ #### Adding three.js (optional)
57
+
58
+ Add two more entries to the importmap above: three.js itself, and the `pixi-effects/three` entry.
59
+
60
+ ```html
61
+ <script type="importmap">
62
+ {
63
+ "imports": {
64
+ "...": "(everything from the importmap above)",
65
+ "three": "https://esm.sh/three@0.178.0",
66
+ "pixi-effects/three": "https://cdn.jsdelivr.net/npm/pixi-effects@0.2.0/dist/three.js"
67
+ }
68
+ }
69
+ </script>
70
+ ```
71
+
72
+ Always route `three` through the importmap — both your code and `pixi-effects/three` then share **one** copy of three.js. Don't load a second copy from another URL (objects from one copy are not `instanceof` the other).
73
+
74
+ ```html
75
+ <script type="module">
76
+ import { Movie } from 'pixi-effects';
77
+ import { registerThree, three } from 'pixi-effects/three';
78
+ import * as THREE from 'three';
79
+
80
+ registerThree(); // once, before movie.init()
81
+
82
+ // ...inside composition.sequences:
83
+ three({
84
+ type: 'three', name: 'knot',
85
+ width: 'GW * 0.6', height: 'GH * 0.6',
86
+ initial: { x: 'GW/2', y: 'GH/2', anchorX: 0.5, anchorY: 0.5 },
87
+ setup: (ctx) => {
88
+ const knot = new THREE.Mesh(
89
+ new THREE.TorusKnotGeometry(1, 0.35, 128, 32),
90
+ new THREE.MeshStandardMaterial({ color: 0x7fb4ff }),
91
+ );
92
+ ctx.scene.add(knot, new THREE.AmbientLight(0xffffff, 0.4));
93
+ ctx.camera.position.z = 6;
94
+ return { objects: { knot } }; // addressable from keyframes
95
+ },
96
+ keyframes: [{ at: 0, to: { 'three.knot.rotation.y': Math.PI * 2 }, duration: 6 }],
97
+ })
98
+ </script>
99
+ ```
100
+
101
+ The layer is a normal sprite once built, so 2D keyframes, masks and filters work on it. Full spec, rules and caveats (one WebGL context per layer, `update(t)` must be a pure function of `t`): [DSL reference § three](./docs/dsl.md#three) and [API reference](./docs/api.md#pixi-effectsthree). Runnable: [`examples/10-three.html`](./examples/10-three.html).
102
+
103
+ With a bundler, `import { registerThree, three } from 'pixi-effects/three'` works the same once you've installed `three`.
104
+
22
105
  ## Quickstart
23
106
 
24
107
  ```ts
@@ -55,10 +138,24 @@ await movie.init({
55
138
  const blob = await movie.render({ format: 'mp4' });
56
139
  ```
57
140
 
141
+ ## 2.5D layers & camera
142
+
143
+ Any layer can be placed in depth and viewed through a camera — no three.js involved:
144
+
145
+ ```ts
146
+ sequences: [
147
+ { type: 'camera', keyframes: [{ at: 0, from: { x: 'GW/2 - 260' }, to: { x: 'GW/2 + 260' }, duration: 4, ease: 'sine.inOut' }] },
148
+ { type: 'shape', shape: 'rect', width: 300, height: 200, threeD: true, initial: { x: 'GW/2', y: 'GH/2', z: -400, fillColor: '#3a6ea5' } },
149
+ { type: 'shape', shape: 'rect', width: 300, height: 200, threeD: true, initial: { x: 'GW/2', y: 'GH/2', z: 250, fillColor: '#d96a3a' } },
150
+ ]
151
+ ```
152
+
153
+ `+z` is toward the viewer, rotations are degrees (CSS signs), and with `z = 0` and the default camera a `threeD` layer looks identical to a 2D one. See [DSL reference § 3D layers & camera](./docs/dsl.md#3d-layers--camera) and [`examples/11-depth.html`](./examples/11-depth.html).
154
+
58
155
  ## Documentation
59
156
 
60
- - [**DSL reference**](./docs/dsl.md) — composition, sequences, keyframes, expressions, filters
61
- - [**API reference**](./docs/api.md) — `Movie`, `Controller`, events, render options
157
+ - [**DSL reference**](./docs/dsl.md) — composition, sequences, 3D layers & camera, three.js layer, keyframes, expressions, filters
158
+ - [**API reference**](./docs/api.md) — `Movie`, `Controller`, `pixi-effects/three`, events, render options
62
159
  - [**Examples**](./examples/) — runnable HTML files (read in order):
63
160
  - `01-hello.html` — minimum viable composition
64
161
  - `02-keyframes.html` — keyframes, easings, expressions
@@ -69,6 +166,9 @@ const blob = await movie.render({ format: 'mp4' });
69
166
  - `07-transitions.html` — all seven transition kinds in one timeline
70
167
  - `08-presets-export.html` — `kenBurns` preset and `movie.render()` from code
71
168
  - `09-audio.html` — multi-track audio mixing with BGM ducking and SFX cues
169
+ - `10-three.html` — a three.js scene as a layer (`pixi-effects/three`)
170
+ - `11-depth.html` — 2.5D layers and camera: parallax, spin, dolly zoom
171
+ - `12-title-motion.html` — a staggered 2.5D title: letters fly in from depth, particles, orbiting camera
72
172
  - `playground.html` — in-browser editor with preset dropdown
73
173
 
74
174
  ## Browser support
@@ -0,0 +1,92 @@
1
+ import { Filter, Container, RenderTexture, Matrix } from 'pixi.js';
2
+ import { S as SequenceSpec, C as CompositionShape, t as AudioDescriptor } from './types-CNBilhpz.cjs';
3
+ import { gsap } from 'gsap';
4
+
5
+ /**
6
+ * Resolves a routed keyframe path to a concrete GSAP tween target.
7
+ * `path` is everything after the registered prefix + dot (for
8
+ * `three.cube.rotation.y` under prefix `three`, path = `cube.rotation.y`).
9
+ * Return null to skip the key (the router is expected to have warned).
10
+ */
11
+ type PathRouter = (path: string) => {
12
+ target: object;
13
+ prop: string;
14
+ } | null;
15
+ type PathRouters = Record<string, PathRouter>;
16
+
17
+ /** Variables available to expression evaluation. */
18
+ interface Scope {
19
+ w: number;
20
+ h: number;
21
+ W: number;
22
+ H: number;
23
+ GW: number;
24
+ GH: number;
25
+ contain: number;
26
+ cover: number;
27
+ t: number;
28
+ d: number;
29
+ T: number;
30
+ }
31
+
32
+ /** Internal marker we set on filter instances so partition path resolution finds them. */
33
+ interface NamedFilter extends Filter {
34
+ _name?: string;
35
+ }
36
+
37
+ /** The slice of a Pixi renderer Layer3D needs (also what tests fake). */
38
+ interface SpaceHost {
39
+ render(options: {
40
+ container: Container;
41
+ target: RenderTexture;
42
+ transform: Matrix;
43
+ clear: boolean;
44
+ clearColor: number[];
45
+ }): void;
46
+ }
47
+
48
+ type Timeline = ReturnType<typeof gsap.timeline>;
49
+ declare abstract class Sequence {
50
+ spec: SequenceSpec;
51
+ parent: CompositionShape | null;
52
+ root: CompositionShape;
53
+ target: Container | null;
54
+ intrinsicWidth: number;
55
+ intrinsicHeight: number;
56
+ at: number;
57
+ duration: number | undefined;
58
+ filters: NamedFilter[];
59
+ /**
60
+ * Mask sequence built from `spec.mask`, if any. Built and added to the
61
+ * scene graph by the parent CompositionSequence; rendered as a mask
62
+ * (not a normal child) by PIXI when `target.mask = maskSequence.target`.
63
+ */
64
+ maskSequence: Sequence | null;
65
+ /**
66
+ * Absolute start time on the global timeline (offset + at), recorded by
67
+ * bindTimeline. Movie._awaitVideoFrames uses it to determine the correct
68
+ * time to pass to awaitFrameAt. Subclasses that override bindTimeline
69
+ * without calling super must set this field themselves. Null until bound.
70
+ */
71
+ absoluteStart: number | null;
72
+ constructor(spec: SequenceSpec, parent: CompositionShape | null, root: CompositionShape);
73
+ abstract build(): Promise<void>;
74
+ buildFilters(): void;
75
+ scope(): Scope;
76
+ /**
77
+ * Prefix routers contributed to the keyframe pipeline (e.g. `three.` in
78
+ * pixi-effects/three). Base sequences route nothing extra.
79
+ */
80
+ protected pathRouters(): PathRouters;
81
+ bindTimeline(timeline: Timeline, offset?: number): void;
82
+ collectAudio(_out: AudioDescriptor[], _baseTime: number): void;
83
+ /**
84
+ * 2.5D hook. Runs once per rendered frame, after the timeline seek and the
85
+ * per-frame media sync, before the render. Compositions override it to
86
+ * project their `threeD` layers; everything else has nothing to do.
87
+ */
88
+ updateSpace(_t: number, _host: SpaceHost): void;
89
+ destroy(): void;
90
+ }
91
+
92
+ export { type PathRouters as P, Sequence as S };
@@ -0,0 +1,92 @@
1
+ import { Filter, Container, RenderTexture, Matrix } from 'pixi.js';
2
+ import { S as SequenceSpec, C as CompositionShape, t as AudioDescriptor } from './types-CNBilhpz.js';
3
+ import { gsap } from 'gsap';
4
+
5
+ /**
6
+ * Resolves a routed keyframe path to a concrete GSAP tween target.
7
+ * `path` is everything after the registered prefix + dot (for
8
+ * `three.cube.rotation.y` under prefix `three`, path = `cube.rotation.y`).
9
+ * Return null to skip the key (the router is expected to have warned).
10
+ */
11
+ type PathRouter = (path: string) => {
12
+ target: object;
13
+ prop: string;
14
+ } | null;
15
+ type PathRouters = Record<string, PathRouter>;
16
+
17
+ /** Variables available to expression evaluation. */
18
+ interface Scope {
19
+ w: number;
20
+ h: number;
21
+ W: number;
22
+ H: number;
23
+ GW: number;
24
+ GH: number;
25
+ contain: number;
26
+ cover: number;
27
+ t: number;
28
+ d: number;
29
+ T: number;
30
+ }
31
+
32
+ /** Internal marker we set on filter instances so partition path resolution finds them. */
33
+ interface NamedFilter extends Filter {
34
+ _name?: string;
35
+ }
36
+
37
+ /** The slice of a Pixi renderer Layer3D needs (also what tests fake). */
38
+ interface SpaceHost {
39
+ render(options: {
40
+ container: Container;
41
+ target: RenderTexture;
42
+ transform: Matrix;
43
+ clear: boolean;
44
+ clearColor: number[];
45
+ }): void;
46
+ }
47
+
48
+ type Timeline = ReturnType<typeof gsap.timeline>;
49
+ declare abstract class Sequence {
50
+ spec: SequenceSpec;
51
+ parent: CompositionShape | null;
52
+ root: CompositionShape;
53
+ target: Container | null;
54
+ intrinsicWidth: number;
55
+ intrinsicHeight: number;
56
+ at: number;
57
+ duration: number | undefined;
58
+ filters: NamedFilter[];
59
+ /**
60
+ * Mask sequence built from `spec.mask`, if any. Built and added to the
61
+ * scene graph by the parent CompositionSequence; rendered as a mask
62
+ * (not a normal child) by PIXI when `target.mask = maskSequence.target`.
63
+ */
64
+ maskSequence: Sequence | null;
65
+ /**
66
+ * Absolute start time on the global timeline (offset + at), recorded by
67
+ * bindTimeline. Movie._awaitVideoFrames uses it to determine the correct
68
+ * time to pass to awaitFrameAt. Subclasses that override bindTimeline
69
+ * without calling super must set this field themselves. Null until bound.
70
+ */
71
+ absoluteStart: number | null;
72
+ constructor(spec: SequenceSpec, parent: CompositionShape | null, root: CompositionShape);
73
+ abstract build(): Promise<void>;
74
+ buildFilters(): void;
75
+ scope(): Scope;
76
+ /**
77
+ * Prefix routers contributed to the keyframe pipeline (e.g. `three.` in
78
+ * pixi-effects/three). Base sequences route nothing extra.
79
+ */
80
+ protected pathRouters(): PathRouters;
81
+ bindTimeline(timeline: Timeline, offset?: number): void;
82
+ collectAudio(_out: AudioDescriptor[], _baseTime: number): void;
83
+ /**
84
+ * 2.5D hook. Runs once per rendered frame, after the timeline seek and the
85
+ * per-frame media sync, before the render. Compositions override it to
86
+ * project their `threeD` layers; everything else has nothing to do.
87
+ */
88
+ updateSpace(_t: number, _host: SpaceHost): void;
89
+ destroy(): void;
90
+ }
91
+
92
+ export { type PathRouters as P, Sequence as S };
@@ -0,0 +1,13 @@
1
+ 'use strict';
2
+
3
+ var chunk64IHCYYN_cjs = require('./chunk-64IHCYYN.cjs');
4
+ require('./chunk-7OIWYXGV.cjs');
5
+
6
+
7
+
8
+ Object.defineProperty(exports, "CompositionSequence", {
9
+ enumerable: true,
10
+ get: function () { return chunk64IHCYYN_cjs.CompositionSequence; }
11
+ });
12
+ //# sourceMappingURL=Composition-BI5HZJFL.cjs.map
13
+ //# sourceMappingURL=Composition-BI5HZJFL.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":[],"names":[],"mappings":"","file":"Composition-BI5HZJFL.cjs"}
@@ -0,0 +1,4 @@
1
+ export { CompositionSequence } from './chunk-H55V3U56.js';
2
+ import './chunk-VJCDG6YG.js';
3
+ //# sourceMappingURL=Composition-IO7ZN32J.js.map
4
+ //# sourceMappingURL=Composition-IO7ZN32J.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":[],"names":[],"mappings":"","file":"Composition-IO7ZN32J.js"}
@@ -1,6 +1,7 @@
1
- import { M as Movie } from './Movie-Bp66rkaC.cjs';
1
+ import { M as Movie } from './Movie-CcR6h2jO.cjs';
2
2
  import 'pixi.js';
3
3
  import 'gsap';
4
+ import './types-CNBilhpz.cjs';
4
5
 
5
6
  declare function formatTime(seconds: number): string;
6
7
  declare function frameToPercent(frame: number, totalFrames: number): number;
@@ -1,6 +1,7 @@
1
- import { M as Movie } from './Movie-Bp66rkaC.js';
1
+ import { M as Movie } from './Movie-D-n8glA6.js';
2
2
  import 'pixi.js';
3
3
  import 'gsap';
4
+ import './types-CNBilhpz.js';
4
5
 
5
6
  declare function formatTime(seconds: number): string;
6
7
  declare function frameToPercent(frame: number, totalFrames: number): number;
@@ -0,0 +1,82 @@
1
+ import { Application } from 'pixi.js';
2
+ import { gsap } from 'gsap';
3
+ import { A as AssetSpec, g as CompositionSpec } from './types-CNBilhpz.cjs';
4
+
5
+ interface MovieOptions {
6
+ width?: number;
7
+ height?: number;
8
+ duration?: number;
9
+ frameRate?: number;
10
+ background?: string;
11
+ canvas?: HTMLCanvasElement;
12
+ assets?: AssetSpec[];
13
+ composition?: CompositionSpec;
14
+ }
15
+ interface RenderOptions {
16
+ format?: 'mp4' | 'mov' | 'webm' | 'mkv';
17
+ video?: {
18
+ codec?: string;
19
+ bitrate?: 'very-low' | 'low' | 'medium' | 'high' | 'very-high';
20
+ };
21
+ audio?: {
22
+ codec?: string;
23
+ bitrate?: 'very-low' | 'low' | 'medium' | 'high' | 'very-high';
24
+ };
25
+ }
26
+ interface FrameEvent {
27
+ frame: number;
28
+ totalFrames: number;
29
+ }
30
+ interface ProgressEvent {
31
+ progress: number;
32
+ frame: number;
33
+ totalFrames: number;
34
+ }
35
+ type Listener = (...args: any[]) => void;
36
+ declare class Movie {
37
+ private _events;
38
+ private _initState;
39
+ app: Application | null;
40
+ timeline: ReturnType<typeof gsap.timeline> | null;
41
+ audioBuffer: AudioBuffer | null;
42
+ audioSource: AudioBufferSourceNode | null;
43
+ gainNode: GainNode | null;
44
+ private _volume;
45
+ private _muted;
46
+ isPlaying: boolean;
47
+ currentFrame: number;
48
+ totalFrames: number;
49
+ width: number;
50
+ height: number;
51
+ duration: number;
52
+ frameRate: number;
53
+ background: string;
54
+ private _audioContext;
55
+ private _rootSequence;
56
+ private _rootContainer;
57
+ private _raf;
58
+ on(event: 'ready', fn: () => void): this;
59
+ on(event: 'frame', fn: (e: FrameEvent) => void): this;
60
+ on(event: 'progress', fn: (e: ProgressEvent) => void): this;
61
+ on(event: 'pause', fn: () => void): this;
62
+ off(event: string, fn: Listener): this;
63
+ emit(event: string, ...args: unknown[]): void;
64
+ get isReady(): boolean;
65
+ private _ensureAudioContext;
66
+ init(options?: MovieOptions): Promise<void>;
67
+ gotoFrame(frame: number, force?: boolean): Promise<void>;
68
+ private _awaitVideoFrames;
69
+ /** Projects every `threeD` layer for the current frame (see src/space). */
70
+ private _updateSpace;
71
+ play(): void;
72
+ pause(): void;
73
+ set volume(v: number);
74
+ get volume(): number;
75
+ set muted(v: boolean);
76
+ get muted(): boolean;
77
+ toggleMute(): boolean;
78
+ render(options?: RenderOptions): Promise<Blob>;
79
+ destroy(): Promise<void>;
80
+ }
81
+
82
+ export { type FrameEvent as F, Movie as M, type ProgressEvent as P, type RenderOptions as R, type MovieOptions as a };
@@ -0,0 +1,82 @@
1
+ import { Application } from 'pixi.js';
2
+ import { gsap } from 'gsap';
3
+ import { A as AssetSpec, g as CompositionSpec } from './types-CNBilhpz.js';
4
+
5
+ interface MovieOptions {
6
+ width?: number;
7
+ height?: number;
8
+ duration?: number;
9
+ frameRate?: number;
10
+ background?: string;
11
+ canvas?: HTMLCanvasElement;
12
+ assets?: AssetSpec[];
13
+ composition?: CompositionSpec;
14
+ }
15
+ interface RenderOptions {
16
+ format?: 'mp4' | 'mov' | 'webm' | 'mkv';
17
+ video?: {
18
+ codec?: string;
19
+ bitrate?: 'very-low' | 'low' | 'medium' | 'high' | 'very-high';
20
+ };
21
+ audio?: {
22
+ codec?: string;
23
+ bitrate?: 'very-low' | 'low' | 'medium' | 'high' | 'very-high';
24
+ };
25
+ }
26
+ interface FrameEvent {
27
+ frame: number;
28
+ totalFrames: number;
29
+ }
30
+ interface ProgressEvent {
31
+ progress: number;
32
+ frame: number;
33
+ totalFrames: number;
34
+ }
35
+ type Listener = (...args: any[]) => void;
36
+ declare class Movie {
37
+ private _events;
38
+ private _initState;
39
+ app: Application | null;
40
+ timeline: ReturnType<typeof gsap.timeline> | null;
41
+ audioBuffer: AudioBuffer | null;
42
+ audioSource: AudioBufferSourceNode | null;
43
+ gainNode: GainNode | null;
44
+ private _volume;
45
+ private _muted;
46
+ isPlaying: boolean;
47
+ currentFrame: number;
48
+ totalFrames: number;
49
+ width: number;
50
+ height: number;
51
+ duration: number;
52
+ frameRate: number;
53
+ background: string;
54
+ private _audioContext;
55
+ private _rootSequence;
56
+ private _rootContainer;
57
+ private _raf;
58
+ on(event: 'ready', fn: () => void): this;
59
+ on(event: 'frame', fn: (e: FrameEvent) => void): this;
60
+ on(event: 'progress', fn: (e: ProgressEvent) => void): this;
61
+ on(event: 'pause', fn: () => void): this;
62
+ off(event: string, fn: Listener): this;
63
+ emit(event: string, ...args: unknown[]): void;
64
+ get isReady(): boolean;
65
+ private _ensureAudioContext;
66
+ init(options?: MovieOptions): Promise<void>;
67
+ gotoFrame(frame: number, force?: boolean): Promise<void>;
68
+ private _awaitVideoFrames;
69
+ /** Projects every `threeD` layer for the current frame (see src/space). */
70
+ private _updateSpace;
71
+ play(): void;
72
+ pause(): void;
73
+ set volume(v: number);
74
+ get volume(): number;
75
+ set muted(v: boolean);
76
+ get muted(): boolean;
77
+ toggleMute(): boolean;
78
+ render(options?: RenderOptions): Promise<Blob>;
79
+ destroy(): Promise<void>;
80
+ }
81
+
82
+ export { type FrameEvent as F, Movie as M, type ProgressEvent as P, type RenderOptions as R, type MovieOptions as a };