pixi-effects 0.2.0 → 0.3.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/CHANGELOG.md +31 -0
- package/README.md +15 -5
- package/ai/SKILL.md +44 -0
- package/ai/reference/cheatsheet.md +120 -0
- package/ai/reference/pitfalls.md +54 -0
- package/ai/reference/recipes.md +375 -0
- package/ai/template.html +82 -0
- package/ai/tools/save-image.py +24 -0
- package/dist/{Base-B1Tdn0Cv.d.cts → Base-BDw6dKRB.d.cts} +1 -1
- package/dist/{Base-Bh_VSusi.d.ts → Base-Ba4Ta4ap.d.ts} +1 -1
- package/dist/Composition-6FDH5OPM.cjs +13 -0
- package/dist/{Composition-BI5HZJFL.cjs.map → Composition-6FDH5OPM.cjs.map} +1 -1
- package/dist/Composition-FEYAUMFI.js +4 -0
- package/dist/{Composition-IO7ZN32J.js.map → Composition-FEYAUMFI.js.map} +1 -1
- package/dist/Controller.d.cts +2 -2
- package/dist/Controller.d.ts +2 -2
- package/dist/Movie-DMpaT67V.d.ts +179 -0
- package/dist/Movie-W8ISiEBB.d.cts +179 -0
- package/dist/{chunk-H55V3U56.js → chunk-DIJG2RSF.js} +28 -11
- package/dist/chunk-DIJG2RSF.js.map +1 -0
- package/dist/{chunk-VJCDG6YG.js → chunk-PN5A6QA7.js} +248 -64
- package/dist/chunk-PN5A6QA7.js.map +1 -0
- package/dist/{chunk-7OIWYXGV.cjs → chunk-SIRVULFF.cjs} +251 -62
- package/dist/chunk-SIRVULFF.cjs.map +1 -0
- package/dist/{chunk-64IHCYYN.cjs → chunk-ZL262ZRM.cjs} +37 -20
- package/dist/chunk-ZL262ZRM.cjs.map +1 -0
- package/dist/index.cjs +324 -24
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +61 -31
- package/dist/index.d.ts +61 -31
- package/dist/index.js +321 -22
- package/dist/index.js.map +1 -1
- package/dist/three.cjs +5 -5
- package/dist/three.d.cts +2 -2
- package/dist/three.d.ts +2 -2
- package/dist/three.js +1 -1
- package/dist/{types-CNBilhpz.d.cts → types-3c8Vymgw.d.cts} +53 -6
- package/dist/{types-CNBilhpz.d.ts → types-3c8Vymgw.d.ts} +53 -6
- package/docs/api.md +333 -0
- package/docs/dsl.md +1017 -0
- package/llms-full.txt +1966 -0
- package/llms.txt +30 -0
- package/package.json +4 -3
- package/dist/Composition-BI5HZJFL.cjs +0 -13
- package/dist/Composition-IO7ZN32J.js +0 -4
- package/dist/Movie-CcR6h2jO.d.cts +0 -82
- package/dist/Movie-D-n8glA6.d.ts +0 -82
- package/dist/chunk-64IHCYYN.cjs.map +0 -1
- package/dist/chunk-7OIWYXGV.cjs.map +0 -1
- package/dist/chunk-H55V3U56.js.map +0 -1
- package/dist/chunk-VJCDG6YG.js.map +0 -1
package/dist/three.cjs
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
|
-
var
|
|
3
|
+
var chunkSIRVULFF_cjs = require('./chunk-SIRVULFF.cjs');
|
|
4
4
|
var pixi_js = require('pixi.js');
|
|
5
5
|
var three$1 = require('three');
|
|
6
6
|
|
|
7
|
-
var ThreeSequence = class extends
|
|
7
|
+
var ThreeSequence = class extends chunkSIRVULFF_cjs.Sequence {
|
|
8
8
|
_renderer = null;
|
|
9
9
|
_scene = null;
|
|
10
10
|
_camera = null;
|
|
@@ -23,7 +23,7 @@ var ThreeSequence = class extends chunk7OIWYXGV_cjs.Sequence {
|
|
|
23
23
|
if (this.duration === void 0) {
|
|
24
24
|
this.duration = this.parent?.duration ?? this.root.duration;
|
|
25
25
|
}
|
|
26
|
-
const scope =
|
|
26
|
+
const scope = chunkSIRVULFF_cjs.buildScope(this, this.parent, this.root);
|
|
27
27
|
const width = resolveDim(spec.width, scope) ?? this.parent?.width ?? this.root.width;
|
|
28
28
|
const height = resolveDim(spec.height, scope) ?? this.parent?.height ?? this.root.height;
|
|
29
29
|
const resolution = spec.resolution ?? 1;
|
|
@@ -143,12 +143,12 @@ var ThreeSequence = class extends chunk7OIWYXGV_cjs.Sequence {
|
|
|
143
143
|
function resolveDim(v, scope) {
|
|
144
144
|
if (v === void 0) return void 0;
|
|
145
145
|
if (typeof v === "number") return v;
|
|
146
|
-
return
|
|
146
|
+
return chunkSIRVULFF_cjs.evaluateExpr(v, scope);
|
|
147
147
|
}
|
|
148
148
|
|
|
149
149
|
// src/three/index.ts
|
|
150
150
|
function registerThree() {
|
|
151
|
-
|
|
151
|
+
chunkSIRVULFF_cjs.registerSequenceType("three", ThreeSequence);
|
|
152
152
|
}
|
|
153
153
|
function three(spec) {
|
|
154
154
|
return spec;
|
package/dist/three.d.cts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { b as SequenceCommon, n as PropValue, S as SequenceSpec } from './types-3c8Vymgw.cjs';
|
|
2
2
|
import { Scene, Camera, WebGLRenderer } from 'three';
|
|
3
|
-
import { S as Sequence, P as PathRouters } from './Base-
|
|
3
|
+
import { S as Sequence, P as PathRouters } from './Base-BDw6dKRB.cjs';
|
|
4
4
|
import 'pixi.js';
|
|
5
5
|
import 'gsap';
|
|
6
6
|
|
package/dist/three.d.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { b as SequenceCommon, n as PropValue, S as SequenceSpec } from './types-3c8Vymgw.js';
|
|
2
2
|
import { Scene, Camera, WebGLRenderer } from 'three';
|
|
3
|
-
import { S as Sequence, P as PathRouters } from './Base-
|
|
3
|
+
import { S as Sequence, P as PathRouters } from './Base-Ba4Ta4ap.js';
|
|
4
4
|
import 'pixi.js';
|
|
5
5
|
import 'gsap';
|
|
6
6
|
|
package/dist/three.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { Sequence, buildScope, evaluateExpr, registerSequenceType } from './chunk-
|
|
1
|
+
import { Sequence, buildScope, evaluateExpr, registerSequenceType } from './chunk-PN5A6QA7.js';
|
|
2
2
|
import { Texture, Sprite } from 'pixi.js';
|
|
3
3
|
import { WebGLRenderer, Scene, PerspectiveCamera } from 'three';
|
|
4
4
|
|
|
@@ -13,9 +13,21 @@ type PropValue = number | string;
|
|
|
13
13
|
type Props = Record<string, PropValue>;
|
|
14
14
|
/** A single keyframe entry. Either `set`, `to`, `from`, or `from`+`to` is meaningful per kind. */
|
|
15
15
|
interface Keyframe {
|
|
16
|
+
/**
|
|
17
|
+
* Start time in seconds, measured from the start of the sequence this
|
|
18
|
+
* keyframe belongs to (After Effects style): `0` = the moment the layer
|
|
19
|
+
* appears. Negative values count back from the sequence's end
|
|
20
|
+
* (`-0.5` = 0.5 s before it ends).
|
|
21
|
+
*/
|
|
16
22
|
at?: number;
|
|
17
23
|
duration?: number;
|
|
18
24
|
ease?: string;
|
|
25
|
+
/** Extra plays of this tween after the first (a finite count; infinite repeats are not allowed — the timeline needs a fixed length). Total time = duration × (repeat + 1) plus delays. */
|
|
26
|
+
repeat?: number;
|
|
27
|
+
/** With `repeat`: every other play runs backwards (there-and-back). */
|
|
28
|
+
yoyo?: boolean;
|
|
29
|
+
/** With `repeat`: seconds to wait between plays. */
|
|
30
|
+
repeatDelay?: number;
|
|
19
31
|
set?: Props;
|
|
20
32
|
to?: Props;
|
|
21
33
|
from?: Props;
|
|
@@ -63,7 +75,7 @@ interface TransitionCommon {
|
|
|
63
75
|
from: string;
|
|
64
76
|
/** Sibling sequence's `name` — the incoming scene. Must be declared after `from` in the parent's `sequences[]`. */
|
|
65
77
|
to: string;
|
|
66
|
-
/** Start time (
|
|
78
|
+
/** Start time in the PARENT composition's time (like a sequence's `at`, not sequence-local). Negative = back from the parent's end. */
|
|
67
79
|
at: number;
|
|
68
80
|
/** Length of the transition in seconds. Must be > 0. */
|
|
69
81
|
duration: number;
|
|
@@ -127,10 +139,11 @@ interface SequenceCommon {
|
|
|
127
139
|
filters?: FilterSpec[];
|
|
128
140
|
/**
|
|
129
141
|
* Override PIXI's auto-computed filter region. By default, filters apply
|
|
130
|
-
* only inside the target's bounding box.
|
|
131
|
-
*
|
|
132
|
-
*
|
|
133
|
-
*
|
|
142
|
+
* only inside the target's bounding box. This rectangle is in the layer's
|
|
143
|
+
* OWN coordinate space (origin = the layer's local origin, before its
|
|
144
|
+
* x/y/scale/rotation — e.g. a circle's centre), not the parent's. Use it to
|
|
145
|
+
* let a filter (blur, glow, a wipe / iris transition) draw beyond the
|
|
146
|
+
* layer's own bounds; without it a blur is clipped to the bounding box.
|
|
134
147
|
*/
|
|
135
148
|
filterArea?: {
|
|
136
149
|
x: number;
|
|
@@ -189,7 +202,17 @@ interface ImageSequenceSpec extends SequenceCommon {
|
|
|
189
202
|
}
|
|
190
203
|
interface TextSequenceSpec extends SequenceCommon {
|
|
191
204
|
type: 'text';
|
|
205
|
+
/**
|
|
206
|
+
* The text. May contain `{value}`, replaced by the layer's animatable number
|
|
207
|
+
* `value` (a counter): `text: '{value} users'`, `initial: { value: 0 }`,
|
|
208
|
+
* keyframe `to: { value: 2480 }`. Format it with `format`.
|
|
209
|
+
*/
|
|
192
210
|
text?: string;
|
|
211
|
+
/** How `{value}` is printed: `decimals` (default 0) and thousands `grouping` (default false). */
|
|
212
|
+
format?: {
|
|
213
|
+
decimals?: number;
|
|
214
|
+
grouping?: boolean;
|
|
215
|
+
};
|
|
193
216
|
/** Subset of PIXI v8 TextStyleOptions. String values may be exprs (e.g. fontSize: 'GW * 0.05'). */
|
|
194
217
|
style?: Record<string, PropValue | {
|
|
195
218
|
color?: PropValue;
|
|
@@ -225,8 +248,32 @@ interface CompositionSequenceSpec extends SequenceCommon {
|
|
|
225
248
|
interface CameraSequenceSpec extends SequenceCommon {
|
|
226
249
|
type: 'camera';
|
|
227
250
|
}
|
|
251
|
+
/**
|
|
252
|
+
* A gradient fill for a shape (replaces `fillColor`). Positions are relative to the shape's own
|
|
253
|
+
* bounds (0–1), so it follows the shape's size. Colours may have alpha (`'rgba(0,0,0,0.6)'`), so a
|
|
254
|
+
* radial gradient from transparent to dark is a vignette. Not animatable.
|
|
255
|
+
*/
|
|
256
|
+
interface GradientSpec {
|
|
257
|
+
/** Default `'linear'`. */
|
|
258
|
+
type?: 'linear' | 'radial';
|
|
259
|
+
/** Colour stops, `[offset 0–1, colour]` or `{ offset, color }`. At least two. */
|
|
260
|
+
stops: Array<[number, string | number] | {
|
|
261
|
+
offset: number;
|
|
262
|
+
color: string | number;
|
|
263
|
+
}>;
|
|
264
|
+
/** linear: direction in degrees — 0 = left → right, 90 = top → bottom (default). */
|
|
265
|
+
angle?: number;
|
|
266
|
+
/** radial: centre in 0–1 of the bounds. Default `[0.5, 0.5]`. */
|
|
267
|
+
center?: [number, number];
|
|
268
|
+
/** radial: inner radius where the first stop applies, 0–1. Default 0. */
|
|
269
|
+
innerRadius?: number;
|
|
270
|
+
/** radial: outer radius where the last stop applies, 0–1. Default 0.5. */
|
|
271
|
+
radius?: number;
|
|
272
|
+
}
|
|
228
273
|
interface ShapeBase extends SequenceCommon {
|
|
229
274
|
type: 'shape';
|
|
275
|
+
/** Fill with a gradient instead of `fillColor` (top level or in `initial`). */
|
|
276
|
+
fillGradient?: GradientSpec;
|
|
230
277
|
/**
|
|
231
278
|
* Colour space used to interpolate `fillColor` / `strokeColor` keyframes.
|
|
232
279
|
*
|
|
@@ -317,4 +364,4 @@ interface AudioDescriptor {
|
|
|
317
364
|
}[];
|
|
318
365
|
}
|
|
319
366
|
|
|
320
|
-
export type { AssetSpec as A, CompositionShape as C, DipTransition as D, EllipseShapeSpec as E, FilterSpec as F, ImageSequenceSpec as I, Keyframe as K, LineShapeSpec as L, PathShapeSpec as P, RectShapeSpec as R, SequenceSpec as S, TextSequenceSpec as T, VideoSequenceSpec as V, WipeTransition as W, ZoomTransition as Z,
|
|
367
|
+
export type { AssetSpec as A, CompositionShape as C, DipTransition as D, EllipseShapeSpec as E, FilterSpec as F, GradientSpec as G, ImageSequenceSpec as I, Keyframe as K, LineShapeSpec as L, PathShapeSpec as P, RectShapeSpec as R, SequenceSpec as S, TextSequenceSpec as T, VideoSequenceSpec as V, WipeTransition as W, ZoomTransition as Z, CameraSequenceSpec as a, SequenceCommon as b, AudioSequenceSpec as c, ChromaKeyFilterSpec as d, CircleShapeSpec as e, CompositionSequenceSpec as f, CompositionSpec as g, CrossfadeTransition as h, CustomFilterSpec as i, DissolveTransition as j, Expr as k, IrisTransition as l, PolygonShapeSpec as m, PropValue as n, Props as o, ShapeSequenceSpec as p, SlideTransition as q, TransitionCommon as r, TransitionSpec as s, AudioDescriptor as t };
|
|
@@ -13,9 +13,21 @@ type PropValue = number | string;
|
|
|
13
13
|
type Props = Record<string, PropValue>;
|
|
14
14
|
/** A single keyframe entry. Either `set`, `to`, `from`, or `from`+`to` is meaningful per kind. */
|
|
15
15
|
interface Keyframe {
|
|
16
|
+
/**
|
|
17
|
+
* Start time in seconds, measured from the start of the sequence this
|
|
18
|
+
* keyframe belongs to (After Effects style): `0` = the moment the layer
|
|
19
|
+
* appears. Negative values count back from the sequence's end
|
|
20
|
+
* (`-0.5` = 0.5 s before it ends).
|
|
21
|
+
*/
|
|
16
22
|
at?: number;
|
|
17
23
|
duration?: number;
|
|
18
24
|
ease?: string;
|
|
25
|
+
/** Extra plays of this tween after the first (a finite count; infinite repeats are not allowed — the timeline needs a fixed length). Total time = duration × (repeat + 1) plus delays. */
|
|
26
|
+
repeat?: number;
|
|
27
|
+
/** With `repeat`: every other play runs backwards (there-and-back). */
|
|
28
|
+
yoyo?: boolean;
|
|
29
|
+
/** With `repeat`: seconds to wait between plays. */
|
|
30
|
+
repeatDelay?: number;
|
|
19
31
|
set?: Props;
|
|
20
32
|
to?: Props;
|
|
21
33
|
from?: Props;
|
|
@@ -63,7 +75,7 @@ interface TransitionCommon {
|
|
|
63
75
|
from: string;
|
|
64
76
|
/** Sibling sequence's `name` — the incoming scene. Must be declared after `from` in the parent's `sequences[]`. */
|
|
65
77
|
to: string;
|
|
66
|
-
/** Start time (
|
|
78
|
+
/** Start time in the PARENT composition's time (like a sequence's `at`, not sequence-local). Negative = back from the parent's end. */
|
|
67
79
|
at: number;
|
|
68
80
|
/** Length of the transition in seconds. Must be > 0. */
|
|
69
81
|
duration: number;
|
|
@@ -127,10 +139,11 @@ interface SequenceCommon {
|
|
|
127
139
|
filters?: FilterSpec[];
|
|
128
140
|
/**
|
|
129
141
|
* Override PIXI's auto-computed filter region. By default, filters apply
|
|
130
|
-
* only inside the target's bounding box.
|
|
131
|
-
*
|
|
132
|
-
*
|
|
133
|
-
*
|
|
142
|
+
* only inside the target's bounding box. This rectangle is in the layer's
|
|
143
|
+
* OWN coordinate space (origin = the layer's local origin, before its
|
|
144
|
+
* x/y/scale/rotation — e.g. a circle's centre), not the parent's. Use it to
|
|
145
|
+
* let a filter (blur, glow, a wipe / iris transition) draw beyond the
|
|
146
|
+
* layer's own bounds; without it a blur is clipped to the bounding box.
|
|
134
147
|
*/
|
|
135
148
|
filterArea?: {
|
|
136
149
|
x: number;
|
|
@@ -189,7 +202,17 @@ interface ImageSequenceSpec extends SequenceCommon {
|
|
|
189
202
|
}
|
|
190
203
|
interface TextSequenceSpec extends SequenceCommon {
|
|
191
204
|
type: 'text';
|
|
205
|
+
/**
|
|
206
|
+
* The text. May contain `{value}`, replaced by the layer's animatable number
|
|
207
|
+
* `value` (a counter): `text: '{value} users'`, `initial: { value: 0 }`,
|
|
208
|
+
* keyframe `to: { value: 2480 }`. Format it with `format`.
|
|
209
|
+
*/
|
|
192
210
|
text?: string;
|
|
211
|
+
/** How `{value}` is printed: `decimals` (default 0) and thousands `grouping` (default false). */
|
|
212
|
+
format?: {
|
|
213
|
+
decimals?: number;
|
|
214
|
+
grouping?: boolean;
|
|
215
|
+
};
|
|
193
216
|
/** Subset of PIXI v8 TextStyleOptions. String values may be exprs (e.g. fontSize: 'GW * 0.05'). */
|
|
194
217
|
style?: Record<string, PropValue | {
|
|
195
218
|
color?: PropValue;
|
|
@@ -225,8 +248,32 @@ interface CompositionSequenceSpec extends SequenceCommon {
|
|
|
225
248
|
interface CameraSequenceSpec extends SequenceCommon {
|
|
226
249
|
type: 'camera';
|
|
227
250
|
}
|
|
251
|
+
/**
|
|
252
|
+
* A gradient fill for a shape (replaces `fillColor`). Positions are relative to the shape's own
|
|
253
|
+
* bounds (0–1), so it follows the shape's size. Colours may have alpha (`'rgba(0,0,0,0.6)'`), so a
|
|
254
|
+
* radial gradient from transparent to dark is a vignette. Not animatable.
|
|
255
|
+
*/
|
|
256
|
+
interface GradientSpec {
|
|
257
|
+
/** Default `'linear'`. */
|
|
258
|
+
type?: 'linear' | 'radial';
|
|
259
|
+
/** Colour stops, `[offset 0–1, colour]` or `{ offset, color }`. At least two. */
|
|
260
|
+
stops: Array<[number, string | number] | {
|
|
261
|
+
offset: number;
|
|
262
|
+
color: string | number;
|
|
263
|
+
}>;
|
|
264
|
+
/** linear: direction in degrees — 0 = left → right, 90 = top → bottom (default). */
|
|
265
|
+
angle?: number;
|
|
266
|
+
/** radial: centre in 0–1 of the bounds. Default `[0.5, 0.5]`. */
|
|
267
|
+
center?: [number, number];
|
|
268
|
+
/** radial: inner radius where the first stop applies, 0–1. Default 0. */
|
|
269
|
+
innerRadius?: number;
|
|
270
|
+
/** radial: outer radius where the last stop applies, 0–1. Default 0.5. */
|
|
271
|
+
radius?: number;
|
|
272
|
+
}
|
|
228
273
|
interface ShapeBase extends SequenceCommon {
|
|
229
274
|
type: 'shape';
|
|
275
|
+
/** Fill with a gradient instead of `fillColor` (top level or in `initial`). */
|
|
276
|
+
fillGradient?: GradientSpec;
|
|
230
277
|
/**
|
|
231
278
|
* Colour space used to interpolate `fillColor` / `strokeColor` keyframes.
|
|
232
279
|
*
|
|
@@ -317,4 +364,4 @@ interface AudioDescriptor {
|
|
|
317
364
|
}[];
|
|
318
365
|
}
|
|
319
366
|
|
|
320
|
-
export type { AssetSpec as A, CompositionShape as C, DipTransition as D, EllipseShapeSpec as E, FilterSpec as F, ImageSequenceSpec as I, Keyframe as K, LineShapeSpec as L, PathShapeSpec as P, RectShapeSpec as R, SequenceSpec as S, TextSequenceSpec as T, VideoSequenceSpec as V, WipeTransition as W, ZoomTransition as Z,
|
|
367
|
+
export type { AssetSpec as A, CompositionShape as C, DipTransition as D, EllipseShapeSpec as E, FilterSpec as F, GradientSpec as G, ImageSequenceSpec as I, Keyframe as K, LineShapeSpec as L, PathShapeSpec as P, RectShapeSpec as R, SequenceSpec as S, TextSequenceSpec as T, VideoSequenceSpec as V, WipeTransition as W, ZoomTransition as Z, CameraSequenceSpec as a, SequenceCommon as b, AudioSequenceSpec as c, ChromaKeyFilterSpec as d, CircleShapeSpec as e, CompositionSequenceSpec as f, CompositionSpec as g, CrossfadeTransition as h, CustomFilterSpec as i, DissolveTransition as j, Expr as k, IrisTransition as l, PolygonShapeSpec as m, PropValue as n, Props as o, ShapeSequenceSpec as p, SlideTransition as q, TransitionCommon as r, TransitionSpec as s, AudioDescriptor as t };
|
package/docs/api.md
ADDED
|
@@ -0,0 +1,333 @@
|
|
|
1
|
+
# API Reference
|
|
2
|
+
|
|
3
|
+
- [`Movie`](#movie) — composition runtime: init, playback, render
|
|
4
|
+
- [`Controller`](#controller) — drop-in player UI overlay
|
|
5
|
+
- [Helpers](#helpers) — pure utilities exported from `pixi-effects/controller`
|
|
6
|
+
- [`pixi-effects/three`](#pixi-effectsthree) — optional three.js integration
|
|
7
|
+
|
|
8
|
+
For DSL types (composition spec, sequences, filters, keyframes, expressions), see [DSL reference](./dsl.md).
|
|
9
|
+
|
|
10
|
+
---
|
|
11
|
+
|
|
12
|
+
## `Movie`
|
|
13
|
+
|
|
14
|
+
Imported from `pixi-effects`.
|
|
15
|
+
|
|
16
|
+
```ts
|
|
17
|
+
import { Movie } from 'pixi-effects';
|
|
18
|
+
|
|
19
|
+
const movie = new Movie();
|
|
20
|
+
await movie.init({ /* ... */ });
|
|
21
|
+
movie.play();
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
### Constructor
|
|
25
|
+
|
|
26
|
+
```ts
|
|
27
|
+
new Movie()
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
No arguments. State is fully populated by `init()`.
|
|
31
|
+
|
|
32
|
+
### `movie.init(options): Promise<void>`
|
|
33
|
+
|
|
34
|
+
Loads assets, builds the composition tree, mixes audio, and renders frame 0.
|
|
35
|
+
|
|
36
|
+
```ts
|
|
37
|
+
interface MovieOptions {
|
|
38
|
+
width?: number; // canvas pixels (default 1920)
|
|
39
|
+
height?: number; // canvas pixels (default 1080)
|
|
40
|
+
duration?: number; // seconds (default 10)
|
|
41
|
+
frameRate?: number; // fps (default 30)
|
|
42
|
+
background?: string; // CSS color hex (default '#000000')
|
|
43
|
+
canvas?: HTMLCanvasElement; // existing canvas to render into; otherwise PixiJS creates one
|
|
44
|
+
assets?: AssetSpec[]; // [{ name, src }]
|
|
45
|
+
composition?: CompositionSpec; // root composition (see DSL reference)
|
|
46
|
+
}
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
Resolves once the composition is ready and the first frame has been rendered. Emits the `ready` event.
|
|
50
|
+
|
|
51
|
+
### `movie.play(): void`
|
|
52
|
+
|
|
53
|
+
Starts the requestAnimationFrame loop that drives `gotoFrame()` per tick. If `currentFrame >= totalFrames`, restarts from 0.
|
|
54
|
+
|
|
55
|
+
If audio sources exist, schedules them on the AudioContext at the appropriate offsets.
|
|
56
|
+
|
|
57
|
+
### `movie.pause(): void`
|
|
58
|
+
|
|
59
|
+
Stops the rAF loop and any playing audio. Emits `'pause'` only when the previous state was playing (so calling `pause()` on an already-paused movie is a no-op for listeners).
|
|
60
|
+
|
|
61
|
+
### `movie.gotoFrame(frame, force?): Promise<void>`
|
|
62
|
+
|
|
63
|
+
```ts
|
|
64
|
+
gotoFrame(frame: number, force?: boolean): Promise<void>
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
Seeks to a specific frame. Pauses if currently playing? **No** — does not change `isPlaying`. Updates `timeline.time()`, awaits any video frame readiness, renders, and emits `'frame'`.
|
|
68
|
+
|
|
69
|
+
`force=true` skips the early-return when the requested frame equals `currentFrame`. Use it after a composition rebuild.
|
|
70
|
+
|
|
71
|
+
### `movie.snapshot(frame?, options?): Promise<Blob | string>`
|
|
72
|
+
|
|
73
|
+
```ts
|
|
74
|
+
snapshot(frame?: number, options?: { scale?: number; type?: 'image/png' | 'image/jpeg'; as?: 'blob' | 'dataURL' }): Promise<Blob | string>
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
A picture of one frame: **the canvas only** (the player bar is not in it). Seeks to `frame` (default: the current frame) and stays there. `as: 'dataURL'` returns a `data:` URL string, handy when a script can only return text. Use it to look at what you built.
|
|
78
|
+
|
|
79
|
+
### `movie.contactSheet(options?): Promise<Blob | string>`
|
|
80
|
+
|
|
81
|
+
```ts
|
|
82
|
+
contactSheet(options?: {
|
|
83
|
+
frames?: number[]; times?: number[]; count?: number; // which frames: explicit, in seconds, or `count` evenly spread (default 6)
|
|
84
|
+
columns?: number; // default 3
|
|
85
|
+
cellWidth?: number; // picture width in px, default 480
|
|
86
|
+
as?: 'blob' | 'dataURL';
|
|
87
|
+
}): Promise<Blob | string>
|
|
88
|
+
```
|
|
89
|
+
|
|
90
|
+
Many frames on **one** PNG, each labelled `frame N · T s`. The cheapest way to check a whole animation by eye (include the middle of every transition and the last second). Restores the current frame afterwards.
|
|
91
|
+
|
|
92
|
+
### `movie.inspect(frame?, options?): Promise<InspectReport>`
|
|
93
|
+
|
|
94
|
+
Where every layer is drawn at `frame`, as JSON — for checking layout without eyes. Seeks there and stays there. `options.layers`: `'visible'` (default, only layers drawn at this frame), `'all'`, or `'none'` (just `summary` and `issues`). Faint layers (alpha < 0.3) and text whose x / y is animated (tickers) are not reported.
|
|
95
|
+
|
|
96
|
+
```ts
|
|
97
|
+
interface InspectReport {
|
|
98
|
+
frame: number; time: number; canvas: { width: number; height: number };
|
|
99
|
+
summary: { layers: number; visible: number };
|
|
100
|
+
issues: string[]; // text off the canvas / cut by an edge / empty / overlapping other text — read this first
|
|
101
|
+
layers: Array<{
|
|
102
|
+
path: string; // names (or type#index) from the root, joined by '/'
|
|
103
|
+
name?: string; type: string; threeD: boolean;
|
|
104
|
+
visible: boolean; // alive at this frame, not hidden by an ancestor, alpha > 0
|
|
105
|
+
alpha: number;
|
|
106
|
+
bounds: { x: number; y: number; width: number; height: number } | null; // canvas pixels; null inside a threeD layer
|
|
107
|
+
onCanvas: 'full' | 'partial' | 'none' | null;
|
|
108
|
+
}>;
|
|
109
|
+
}
|
|
110
|
+
```
|
|
111
|
+
|
|
112
|
+
### `movie.render(options?): Promise<Blob>`
|
|
113
|
+
|
|
114
|
+
Renders the entire timeline to a single video file. Pauses playback first.
|
|
115
|
+
|
|
116
|
+
```ts
|
|
117
|
+
interface RenderOptions {
|
|
118
|
+
format?: 'mp4' | 'mov' | 'webm' | 'mkv'; // default 'mp4'
|
|
119
|
+
video?: {
|
|
120
|
+
codec?: string; // default per format (mp4/mov→avc, webm/mkv→vp9)
|
|
121
|
+
bitrate?: 'very-low' | 'low' | 'medium' | 'high' | 'very-high'; // default 'high'
|
|
122
|
+
};
|
|
123
|
+
audio?: {
|
|
124
|
+
codec?: string; // default per format (mp4/mov→aac, webm/mkv→opus)
|
|
125
|
+
bitrate?: 'very-low' | 'low' | 'medium' | 'high' | 'very-high'; // default 'high'
|
|
126
|
+
};
|
|
127
|
+
}
|
|
128
|
+
```
|
|
129
|
+
|
|
130
|
+
Returns a `Blob` whose `type` is the container's MIME (e.g. `video/mp4`). Emits `'progress'` repeatedly during the render.
|
|
131
|
+
|
|
132
|
+
The renderer also forces a keyframe every ~2 seconds so the resulting file scrubs efficiently in standard players.
|
|
133
|
+
|
|
134
|
+
### `movie.destroy(): Promise<void>`
|
|
135
|
+
|
|
136
|
+
Pauses playback, destroys the underlying PIXI Application, releases audio buffers and AudioContext, and marks the instance unusable.
|
|
137
|
+
|
|
138
|
+
### Events
|
|
139
|
+
|
|
140
|
+
```ts
|
|
141
|
+
movie.on(event, fn): this
|
|
142
|
+
movie.off(event, fn): this
|
|
143
|
+
```
|
|
144
|
+
|
|
145
|
+
| Event | Payload | Fired |
|
|
146
|
+
| ----------- | ------------------------------------------------- | ----------------------------------------------------- |
|
|
147
|
+
| `'ready'` | none | once, after `init()` resolves |
|
|
148
|
+
| `'frame'` | `{ frame: number; totalFrames: number }` | every `gotoFrame` (so once per playback frame too) |
|
|
149
|
+
| `'pause'` | none | when `pause()` actually transitions from playing |
|
|
150
|
+
| `'progress'`| `{ progress: number; frame: number; totalFrames: number }` | during `render()`, once per encoded frame |
|
|
151
|
+
|
|
152
|
+
`progress` is `0..100` (rounded integer percent).
|
|
153
|
+
|
|
154
|
+
### Public properties
|
|
155
|
+
|
|
156
|
+
| Property | Type | Notes |
|
|
157
|
+
| ---------------- | --------- | ------------------------------------------------------- |
|
|
158
|
+
| `isPlaying` | boolean | true while the rAF loop is active |
|
|
159
|
+
| `currentFrame` | number | 0-based current frame |
|
|
160
|
+
| `totalFrames` | number | `Math.round(duration * frameRate)` |
|
|
161
|
+
| `frameRate` | number | from `init` |
|
|
162
|
+
| `duration` | number | seconds |
|
|
163
|
+
| `width`, `height`| number | canvas pixels |
|
|
164
|
+
| `background` | string | CSS color |
|
|
165
|
+
| `volume` | number | 0..1 getter/setter; immediate. Setter clamps and applies to active audio |
|
|
166
|
+
| `muted` | boolean | getter/setter; immediate |
|
|
167
|
+
| `app` | `pixi.js Application \| null` | PIXI Application instance (advanced/escape hatch) |
|
|
168
|
+
| `timeline` | GSAP Timeline `\| null` | underlying GSAP timeline (advanced) |
|
|
169
|
+
|
|
170
|
+
### `movie.toggleMute(): boolean`
|
|
171
|
+
|
|
172
|
+
Flips `muted` and returns the new value.
|
|
173
|
+
|
|
174
|
+
---
|
|
175
|
+
|
|
176
|
+
## `Controller`
|
|
177
|
+
|
|
178
|
+
Imported from `pixi-effects/controller`.
|
|
179
|
+
|
|
180
|
+
```ts
|
|
181
|
+
import { Controller } from 'pixi-effects/controller';
|
|
182
|
+
|
|
183
|
+
const ctrl = new Controller(movie, { canvas });
|
|
184
|
+
// later:
|
|
185
|
+
ctrl.destroy();
|
|
186
|
+
```
|
|
187
|
+
|
|
188
|
+
A YouTube-style overlay anchored to the canvas:
|
|
189
|
+
|
|
190
|
+
```
|
|
191
|
+
[▶] [🔉━━━] 0:00 / 0:08 ··· [⬇] [⛶]
|
|
192
|
+
└── play └── volume └── time └── export └── fullscreen
|
|
193
|
+
```
|
|
194
|
+
|
|
195
|
+
The bar auto-hides 2.5s after pointer activity stops (in both playing and paused state) and reappears on pointer move. Clicking the download icon opens a popover with format/quality selectors and a `Download` confirm button. Fullscreen scales the canvas + bar to the viewport.
|
|
196
|
+
|
|
197
|
+
### Constructor
|
|
198
|
+
|
|
199
|
+
```ts
|
|
200
|
+
new Controller(movie: Movie, options: ControllerOptions)
|
|
201
|
+
|
|
202
|
+
interface ControllerOptions {
|
|
203
|
+
canvas: HTMLCanvasElement; // required
|
|
204
|
+
showExportButton?: boolean; // default true; hides ⬇ + popover
|
|
205
|
+
enableKeyboardShortcuts?: boolean; // default true
|
|
206
|
+
className?: string; // default 'movie-controller'
|
|
207
|
+
}
|
|
208
|
+
```
|
|
209
|
+
|
|
210
|
+
Mounting strategy:
|
|
211
|
+
|
|
212
|
+
- If `canvas.parentElement` already has a non-static `position`, the controller is appended directly into it.
|
|
213
|
+
- Otherwise the canvas is wrapped in a `<div class="movie-controller-wrap">` (with `position: relative`). The wrapper is removed on `destroy()`.
|
|
214
|
+
|
|
215
|
+
### `controller.destroy(): void`
|
|
216
|
+
|
|
217
|
+
Idempotent. Removes:
|
|
218
|
+
|
|
219
|
+
- the controller bar DOM
|
|
220
|
+
- all listeners (Movie events, document keydown/pointerdown/fullscreenchange, wrapper pointermove/mouseleave)
|
|
221
|
+
- the auto-hide timer
|
|
222
|
+
- the wrapper, if it was created here
|
|
223
|
+
- the injected stylesheet (ref-counted across multiple controllers)
|
|
224
|
+
|
|
225
|
+
If the controller still owns `document.fullscreenElement`, it calls `exitFullscreen()`.
|
|
226
|
+
|
|
227
|
+
### Export popover
|
|
228
|
+
|
|
229
|
+
Format options: **MP4**, **WebM**, **MOV** (mp4 ↔ avc/aac, webm ↔ vp9/opus, mov ↔ avc/aac).
|
|
230
|
+
|
|
231
|
+
Quality options: **Low**, **Medium**, **High** (default), **Very High**.
|
|
232
|
+
|
|
233
|
+
These map directly to `Movie.render()`'s `format` and `video.bitrate` / `audio.bitrate` parameters. Selection persists for the lifetime of the controller instance (no localStorage).
|
|
234
|
+
|
|
235
|
+
The download is triggered by an in-page `<a download>` click, so the file lands in the browser's default download location with a name like `movie-{YYYYMMDD-HHMMSS}.{ext}`.
|
|
236
|
+
|
|
237
|
+
### Keyboard shortcuts
|
|
238
|
+
|
|
239
|
+
Active when `enableKeyboardShortcuts: true` and the key target is not `<input>`/`<textarea>`/`<select>`/contenteditable.
|
|
240
|
+
|
|
241
|
+
| Key | Action |
|
|
242
|
+
| ----------- | --------------------------------------------------- |
|
|
243
|
+
| `Space` | play / pause |
|
|
244
|
+
| `←` / `→` | step ±1 frame |
|
|
245
|
+
| `↑` / `↓` | volume ±5% (clears mute when increasing past zero) |
|
|
246
|
+
| `M` | toggle mute |
|
|
247
|
+
| `Shift+E` | export with current settings (skips the popover) |
|
|
248
|
+
| `F` | toggle fullscreen |
|
|
249
|
+
| `Esc` | close the export popover or exit fullscreen (browser) |
|
|
250
|
+
|
|
251
|
+
### Theming
|
|
252
|
+
|
|
253
|
+
The bar uses fixed colors (`#007AFF` for the active track / fill / confirm button, white for icons, `rgba(0,0,0,0.75)` gradient background). Override by adding stricter CSS rules under `.movie-controller`. A theming API (CSS custom properties) is on the roadmap.
|
|
254
|
+
|
|
255
|
+
---
|
|
256
|
+
|
|
257
|
+
## Helpers
|
|
258
|
+
|
|
259
|
+
These pure functions are exported from `pixi-effects/controller` for consumers who want to build custom controls or reuse the parsing utilities. All are side-effect-free.
|
|
260
|
+
|
|
261
|
+
```ts
|
|
262
|
+
import { formatTime, frameToPercent, pxToFrame, pxToFraction, extensionForMimeType }
|
|
263
|
+
from 'pixi-effects/controller';
|
|
264
|
+
```
|
|
265
|
+
|
|
266
|
+
### `formatTime(seconds: number): string`
|
|
267
|
+
|
|
268
|
+
Returns `M:SS` (no leading zero on minutes). `formatTime(125)` → `"2:05"`. Negatives clamp to zero.
|
|
269
|
+
|
|
270
|
+
### `frameToPercent(frame: number, totalFrames: number): number`
|
|
271
|
+
|
|
272
|
+
Returns 0..100 (clamped). `totalFrames <= 0` returns 0.
|
|
273
|
+
|
|
274
|
+
### `pxToFrame(clientX, rect, totalFrames): number`
|
|
275
|
+
|
|
276
|
+
Maps a pointer X coordinate (relative to viewport) inside a `DOMRect`-shaped object to a frame index 0..totalFrames. Rounded.
|
|
277
|
+
|
|
278
|
+
```ts
|
|
279
|
+
pxToFrame(150, { left: 100, width: 200 } as DOMRect, 100) // 25
|
|
280
|
+
```
|
|
281
|
+
|
|
282
|
+
### `pxToFraction(clientX, rect, inset?): number`
|
|
283
|
+
|
|
284
|
+
Same as `pxToFrame` but returns a normalized 0..1 fraction. The optional `inset` shrinks the active range by that many pixels on each side (used internally for the volume slider).
|
|
285
|
+
|
|
286
|
+
### `extensionForMimeType(mime: string): string`
|
|
287
|
+
|
|
288
|
+
Maps common video MIME types to file extensions. Falls back to `'mp4'`.
|
|
289
|
+
|
|
290
|
+
| MIME contains | Extension |
|
|
291
|
+
| ------------------- | --------- |
|
|
292
|
+
| `webm` | `webm` |
|
|
293
|
+
| `quicktime` / `mov` | `mov` |
|
|
294
|
+
| `matroska` / `mkv` | `mkv` |
|
|
295
|
+
| anything else | `mp4` |
|
|
296
|
+
|
|
297
|
+
---
|
|
298
|
+
|
|
299
|
+
## `pixi-effects/three`
|
|
300
|
+
|
|
301
|
+
Optional three.js integration, imported from its own entry so the core `pixi-effects` entry never touches three.js:
|
|
302
|
+
|
|
303
|
+
```ts
|
|
304
|
+
import { registerThree, three, ThreeSequence } from 'pixi-effects/three';
|
|
305
|
+
```
|
|
306
|
+
|
|
307
|
+
**Install:** `npm i three`. `three` is a peer dependency marked optional (`peerDependenciesMeta.three.optional = true`) — consumers who never import `pixi-effects/three` are unaffected either way.
|
|
308
|
+
|
|
309
|
+
For the `type: 'three'` spec shape (fields, keyframe paths, rules), see [DSL reference § three](./dsl.md#three).
|
|
310
|
+
|
|
311
|
+
### `registerThree(): void`
|
|
312
|
+
|
|
313
|
+
Registers the `'three'` sequence type with the composition builder. Call once, before `Movie.init()` builds a composition containing a `type: 'three'` sequence. Idempotent.
|
|
314
|
+
|
|
315
|
+
### `three(spec: ThreeSequenceSpec): SequenceSpec`
|
|
316
|
+
|
|
317
|
+
Typing helper — accepts a strongly-typed three spec and returns it as a plain `SequenceSpec`, so it drops straight into `composition.sequences` alongside `text` / `image` / etc. A cast only; not required for the sequence to work, but gives editor autocomplete on `setup` / `update` / `dispose`.
|
|
318
|
+
|
|
319
|
+
### `ThreeSequence`
|
|
320
|
+
|
|
321
|
+
The `Sequence` subclass that backs `type: 'three'`. Exported for advanced use (e.g. `instanceof` checks); most consumers only need `registerThree()` and `three()`.
|
|
322
|
+
|
|
323
|
+
### Exported types
|
|
324
|
+
|
|
325
|
+
```ts
|
|
326
|
+
import type { ThreeContext, ThreeSetupResult, ThreeSequenceSpec } from 'pixi-effects/three';
|
|
327
|
+
```
|
|
328
|
+
|
|
329
|
+
| Type | Notes |
|
|
330
|
+
| ------------------- | ------------------------------------------------------------------------------- |
|
|
331
|
+
| `ThreeContext` | `{ scene, camera, renderer, width, height }` handed to `setup` / `update` / `dispose`. |
|
|
332
|
+
| `ThreeSetupResult` | `{ objects?, camera? }` returned from `setup`. |
|
|
333
|
+
| `ThreeSequenceSpec` | the `type: 'three'` sequence spec. |
|