pixi-effects 0.3.0 → 0.4.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 +24 -0
- package/README.md +6 -6
- package/ai/SKILL.md +3 -1
- package/ai/reference/cheatsheet.md +6 -5
- package/ai/reference/pitfalls.md +24 -3
- package/ai/template.html +3 -3
- package/dist/{Base-Ba4Ta4ap.d.ts → Base-5R7C5pHR.d.cts} +7 -1
- package/dist/{Base-BDw6dKRB.d.cts → Base-DhY9oMxr.d.ts} +7 -1
- package/dist/Composition-D7RCAGEA.cjs +13 -0
- package/dist/{Composition-6FDH5OPM.cjs.map → Composition-D7RCAGEA.cjs.map} +1 -1
- package/dist/Composition-RGTRZ2JX.js +4 -0
- package/dist/{Composition-FEYAUMFI.js.map → Composition-RGTRZ2JX.js.map} +1 -1
- package/dist/Controller.d.cts +2 -2
- package/dist/Controller.d.ts +2 -2
- package/dist/{Movie-W8ISiEBB.d.cts → Movie-CghFXprP.d.cts} +1 -1
- package/dist/{Movie-DMpaT67V.d.ts → Movie-DRZtIGU7.d.ts} +1 -1
- package/dist/{chunk-SIRVULFF.cjs → chunk-6BQ6IEW2.cjs} +119 -36
- package/dist/chunk-6BQ6IEW2.cjs.map +1 -0
- package/dist/{chunk-DIJG2RSF.js → chunk-A574IA4F.js} +44 -6
- package/dist/chunk-A574IA4F.js.map +1 -0
- package/dist/{chunk-ZL262ZRM.cjs → chunk-QGBOC5YL.cjs} +56 -18
- package/dist/chunk-QGBOC5YL.cjs.map +1 -0
- package/dist/{chunk-PN5A6QA7.js → chunk-ZQX7WIYL.js} +119 -37
- package/dist/chunk-ZQX7WIYL.js.map +1 -0
- package/dist/index.cjs +58 -16
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +4 -4
- package/dist/index.d.ts +4 -4
- package/dist/index.js +50 -8
- 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-3c8Vymgw.d.cts → types-CRE9WKd4.d.cts} +6 -0
- package/dist/{types-3c8Vymgw.d.ts → types-CRE9WKd4.d.ts} +6 -0
- package/docs/dsl.md +12 -1
- package/llms-full.txt +45 -10
- package/package.json +2 -1
- package/dist/Composition-6FDH5OPM.cjs +0 -13
- package/dist/Composition-FEYAUMFI.js +0 -4
- package/dist/chunk-DIJG2RSF.js.map +0 -1
- package/dist/chunk-PN5A6QA7.js.map +0 -1
- package/dist/chunk-SIRVULFF.cjs.map +0 -1
- package/dist/chunk-ZL262ZRM.cjs.map +0 -1
package/dist/three.cjs
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
|
-
var
|
|
3
|
+
var chunk6BQ6IEW2_cjs = require('./chunk-6BQ6IEW2.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 chunk6BQ6IEW2_cjs.Sequence {
|
|
8
8
|
_renderer = null;
|
|
9
9
|
_scene = null;
|
|
10
10
|
_camera = null;
|
|
@@ -23,7 +23,7 @@ var ThreeSequence = class extends chunkSIRVULFF_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 = chunk6BQ6IEW2_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 chunkSIRVULFF_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 chunk6BQ6IEW2_cjs.evaluateExpr(v, scope);
|
|
147
147
|
}
|
|
148
148
|
|
|
149
149
|
// src/three/index.ts
|
|
150
150
|
function registerThree() {
|
|
151
|
-
|
|
151
|
+
chunk6BQ6IEW2_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 { b as SequenceCommon, n as PropValue, S as SequenceSpec } from './types-
|
|
1
|
+
import { b as SequenceCommon, n as PropValue, S as SequenceSpec } from './types-CRE9WKd4.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-5R7C5pHR.cjs';
|
|
4
4
|
import 'pixi.js';
|
|
5
5
|
import 'gsap';
|
|
6
6
|
|
package/dist/three.d.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import { b as SequenceCommon, n as PropValue, S as SequenceSpec } from './types-
|
|
1
|
+
import { b as SequenceCommon, n as PropValue, S as SequenceSpec } from './types-CRE9WKd4.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-DhY9oMxr.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-ZQX7WIYL.js';
|
|
2
2
|
import { Texture, Sprite } from 'pixi.js';
|
|
3
3
|
import { WebGLRenderer, Scene, PerspectiveCamera } from 'three';
|
|
4
4
|
|
|
@@ -174,6 +174,12 @@ interface SequenceCommon {
|
|
|
174
174
|
* Routed through PIXI's native `setMask({ inverse: true })`.
|
|
175
175
|
*/
|
|
176
176
|
maskInverted?: boolean;
|
|
177
|
+
/**
|
|
178
|
+
* How this layer blends with what is behind it. `'add'` and `'screen'` brighten (glows, light leaks,
|
|
179
|
+
* overlapping halos add up instead of covering each other), `'multiply'` darkens. Default `'normal'`.
|
|
180
|
+
* On a composition the mode is inherited by its children: each one blends with what is behind it.
|
|
181
|
+
*/
|
|
182
|
+
blendMode?: 'normal' | 'add' | 'screen' | 'multiply';
|
|
177
183
|
/**
|
|
178
184
|
* Opt this layer into 2.5D: it can then use `z`, `rotationX`, `rotationY`
|
|
179
185
|
* (in `initial` / keyframes) and is projected through the composition's
|
|
@@ -174,6 +174,12 @@ interface SequenceCommon {
|
|
|
174
174
|
* Routed through PIXI's native `setMask({ inverse: true })`.
|
|
175
175
|
*/
|
|
176
176
|
maskInverted?: boolean;
|
|
177
|
+
/**
|
|
178
|
+
* How this layer blends with what is behind it. `'add'` and `'screen'` brighten (glows, light leaks,
|
|
179
|
+
* overlapping halos add up instead of covering each other), `'multiply'` darkens. Default `'normal'`.
|
|
180
|
+
* On a composition the mode is inherited by its children: each one blends with what is behind it.
|
|
181
|
+
*/
|
|
182
|
+
blendMode?: 'normal' | 'add' | 'screen' | 'multiply';
|
|
177
183
|
/**
|
|
178
184
|
* Opt this layer into 2.5D: it can then use `z`, `rotationX`, `rotationY`
|
|
179
185
|
* (in `initial` / keyframes) and is projected through the composition's
|
package/docs/dsl.md
CHANGED
|
@@ -71,7 +71,7 @@ A layer is **not removed** when its lifespan `[at, at + duration)` ends: it is o
|
|
|
71
71
|
|
|
72
72
|
### `text`
|
|
73
73
|
|
|
74
|
-
Renders a [PIXI.Text](https://pixijs.com/8.x/guides/components/scene-objects/text/text). Animatable position, rotation, scale, opacity and `fill`. `style` accepts any PixiJS `TextStyle` field and is applied once at build time — notably `fontSize fontFamily fontWeight fill letterSpacing lineHeight align wordWrap wordWrapWidth stroke dropShadow padding` (numbers may be expressions). A `dropShadow` glow is clipped unless `padding` is at least twice its `blur`. Text content cannot change over time (
|
|
74
|
+
Renders a [PIXI.Text](https://pixijs.com/8.x/guides/components/scene-objects/text/text). Animatable position, rotation, scale, opacity and `fill`. `style` accepts any PixiJS `TextStyle` field and is applied once at build time — notably `fontSize fontFamily fontWeight fill letterSpacing lineHeight align wordWrap wordWrapWidth stroke dropShadow padding` (numbers may be expressions). A `dropShadow` glow is clipped unless `padding` is at least twice its `blur`. Text content cannot change over time, with one exception: a `{value}` placeholder in `text` prints an animatable number (`text: '{value} users'`, `initial: { value: 0 }`, a keyframe `to: { value: 2480 }`; `format: { decimals, grouping }`) — that is how counters work. Any other change of wording is a second layer (stack layers with `at` / `duration`). Multi-line text is centre-aligned unless `style.align` says otherwise. In expressions `w` / `h` are the size of the styled text, so `x: '-w'` places it just off the left edge.
|
|
75
75
|
|
|
76
76
|
```ts
|
|
77
77
|
{
|
|
@@ -546,6 +546,17 @@ When `true`, flip the mask sense: pixels INSIDE the mask shape become transparen
|
|
|
546
546
|
|
|
547
547
|
Routed through PIXI v8's native `setMask({ inverse: true })`.
|
|
548
548
|
|
|
549
|
+
#### `blendMode`
|
|
550
|
+
|
|
551
|
+
How a layer blends with what is behind it: `'normal'` (default), `'add'`, `'screen'` or `'multiply'`. `add` and `screen` brighten, so overlapping glows, halos and light leaks add up instead of covering each other; `multiply` darkens. It works on every layer type, on `threeD` layers, and on a composition (its children inherit the mode, each blending with what is behind it). Any other value warns and is ignored.
|
|
552
|
+
|
|
553
|
+
```ts
|
|
554
|
+
// A soft white glow that brightens whatever it overlaps
|
|
555
|
+
{ type: 'shape', shape: 'circle', radius: 120, blendMode: 'add',
|
|
556
|
+
fillGradient: { type: 'radial', stops: [[0, 'rgba(255,255,255,0.9)'], [1, 'rgba(255,255,255,0)']] },
|
|
557
|
+
initial: { x: 'W/2', y: 'H/2' } }
|
|
558
|
+
```
|
|
559
|
+
|
|
549
560
|
---
|
|
550
561
|
|
|
551
562
|
## Assets
|
package/llms-full.txt
CHANGED
|
@@ -31,7 +31,9 @@ You describe a video as a tree of plain objects; the library plays it in a canva
|
|
|
31
31
|
- **`audio` shorter than its layer goes silent** — add `loop: true`.
|
|
32
32
|
- **Masks live in the parent's coordinates and don't follow the masked layer.** **`filterArea` is in the layer's own coordinates.**
|
|
33
33
|
- **2.5D needs `threeD: true`** on each layer plus a `{ type: 'camera' }` layer; camera props go in `initial`/keyframes; keep every `z` below the camera distance (≈ 989 at 720p, fov 40); under a dolly zoom only `z = 0` stays fixed.
|
|
34
|
-
- **Built in:** `fillGradient` (linear/radial, alpha stops → vignettes), `{value}` counters, `repeat`/`yoyo`, `orbit()`. **Not in the DSL (hand-roll, recipes exist or loops are easy):** other per-frame curves, per-letter text animators (one layer per letter),
|
|
34
|
+
- **Built in:** `fillGradient` (linear/radial, alpha stops → vignettes), `{value}` counters, `repeat`/`yoyo`, `orbit()`. **Not in the DSL (hand-roll, recipes exist or loops are easy):** arc / progress-ring and stroke draw-on, text that changes over time (other than `{value}`), other per-frame curves and jitter, per-letter text animators (one layer per letter), particle emitters, group/parent layers.
|
|
35
|
+
- **Blend modes:** `blendMode: 'add' | 'screen' | 'multiply'` on any layer (glows, light leaks).
|
|
36
|
+
- **One `Movie` per page.** A sound effect needs no `duration` (it lasts as long as its clip). Seeking is safe: counters, colours and growing shapes are right after any jump.
|
|
35
37
|
|
|
36
38
|
## Layout sanity (the cheap bugs a screenshot catches)
|
|
37
39
|
|
|
@@ -87,24 +89,25 @@ name, at, duration,
|
|
|
87
89
|
initial: { ...props applied before any keyframe },
|
|
88
90
|
keyframes: [ { at, duration, ease, set | to | from | (from + to), repeat?, yoyo?, repeatDelay? } ],
|
|
89
91
|
filters: [ { type: 'chromaKey', keyColor, threshold, smoothing, spill } | { type: 'custom', name, filter: <Pixi Filter> } ],
|
|
90
|
-
mask: <a layer spec>, maskInverted,
|
|
92
|
+
mask: <a layer spec>, maskInverted, // a mask with no `at` of its own starts and ends with the layer it masks (its keyframes count from that layer's start); an explicit mask `at` is composition time
|
|
91
93
|
filterArea: { x, y, width, height } // in the layer's OWN coordinates; lets blur/glow draw past the layer's bounds
|
|
92
94
|
threeD: true // opt into 2.5D (see below)
|
|
95
|
+
blendMode: 'normal' | 'add' | 'screen' | 'multiply' // add / screen brighten (glows, light leaks: overlapping halos add up); on a composition its children inherit the mode
|
|
93
96
|
```
|
|
94
97
|
|
|
95
98
|
Animatable props (`initial` / keyframes): `x y alpha rotation scale scaleX scaleY pivotX pivotY anchorX anchorY skewX skewY tint width height visible autoAlpha`, plus for shapes their style/geometry, for text `fill`, for audio `volume`, for 3D `z rotationX rotationY`, filter params as `'filters.<name>.<param>'`, three objects as `'three.<obj>.<path>'`.
|
|
96
99
|
|
|
97
|
-
Keyframe kinds: `set` (jump), `to` (animate to), `from` (animate from), `from`+`to`. `repeat` (finite extra plays), `yoyo`, `repeatDelay` loop any of them (endless repeats are not allowed). `ease` = any GSAP ease (`'none'`, `'power2.out'`, `'expo.out'`, `'back.out(1.7)'`, `'elastic.out(1,0.5)'`, `'sine.inOut'`, `'bounce.out'`…). Default ease is linear.
|
|
100
|
+
Keyframe kinds: `set` (jump at `at`; undone when you seek back), `to` (animate to), `from` (animate from), `from`+`to`. `from` / `from+to` show their start value from the layer's start, so a delayed fade-in needs no `initial.alpha`. `repeat` (finite extra plays), `yoyo`, `repeatDelay` loop any of them (endless repeats are not allowed). `ease` = any GSAP ease (`'none'`, `'power2.out'`, `'expo.out'`, `'back.out(1.7)'`, `'elastic.out(1,0.5)'`, `'sine.inOut'`, `'bounce.out'`…). Default ease is linear.
|
|
98
101
|
|
|
99
102
|
## Layer types
|
|
100
103
|
|
|
101
|
-
**text** — `text`, `style` (any PixiJS TextStyle field: `fontSize fontFamily fontWeight fill letterSpacing lineHeight align wordWrap wordWrapWidth stroke dropShadow padding`; expressions OK for numbers), `colorSpace`. Default anchor is **top-left**; use `anchorX/anchorY: 0.5` to centre on `x,y`. A text layer has one animatable number, `value`, printed where the text contains `{value}` (`text: '{value} users'`, `initial: { value: 0 }`, keyframe `to: { value: 2480 }`; `format: { decimals, grouping }`) — that is how counters work. Other content cannot change over time.
|
|
104
|
+
**text** — `text`, `style` (any PixiJS TextStyle field: `fontSize fontFamily fontWeight fill letterSpacing lineHeight align wordWrap wordWrapWidth stroke dropShadow padding`; expressions OK for numbers), `colorSpace`. Default anchor is **top-left**; use `anchorX/anchorY: 0.5` to centre on `x,y`. A text layer has one animatable number, `value`, printed where the text contains `{value}` (`text: '{value} users'`, `initial: { value: 0 }`, keyframe `to: { value: 2480 }`; `format: { decimals, grouping }`) — that is how counters work. Other content cannot change over time. Multi-line text is centre-aligned by default (`style.align: 'left'` to change).
|
|
102
105
|
|
|
103
106
|
**image** — `asset`, `tint`, `colorSpace: 'rgb'|'oklab'|'oklch'`. Default anchor top-left; natural size = `w`,`h`.
|
|
104
107
|
|
|
105
108
|
**video** — `asset`, `loop`, `audio`, `volume`; `initial: { scale: 'cover' }`.
|
|
106
109
|
|
|
107
|
-
**audio** — `asset`, `loop`, `volume`; fade with volume keyframes. **
|
|
110
|
+
**audio** — `asset`, `loop`, `volume`; fade with volume keyframes (`{ at: -2, to: { volume: 0 }, duration: 2 }` fades the last 2 s). **Omit `duration` for a one-shot sound effect: it lasts exactly as long as its clip.** With `loop: true` and no `duration` it lasts until the composition ends. An explicit `duration` longer than the clip goes silent after the clip unless `loop: true`.
|
|
108
111
|
|
|
109
112
|
**shape** — `shape: 'rect' | 'circle' | 'ellipse' | 'line' | 'polygon' | 'path'`:
|
|
110
113
|
|
|
@@ -119,7 +122,7 @@ Keyframe kinds: `set` (jump), `to` (animate to), `from` (animate from), `from`+`
|
|
|
119
122
|
|
|
120
123
|
Style (`initial` / keyframes): `fillColor fillAlpha strokeColor strokeAlpha strokeWidth`; `colorSpace: 'oklab'|'oklch'` for clean colour tweens. rect/circle/ellipse are **centred on `x,y` by default** (`anchorX/anchorY` default 0.5): for a bar growing from its base use `anchorY: 1` (or `anchorX: 0` for left-to-right). **`fillGradient`** (top level or `initial`; instead of `fillColor`): `{ type?: 'linear'|'radial', stops: [[0, '#000'], [1, 'rgba(0,0,0,.6)']], angle? /* linear, deg, 90 = top→bottom */, center?, innerRadius?, radius? /* radial, 0–1 of bounds */ }` — stops may have alpha, so a radial transparent→dark is a vignette.
|
|
121
124
|
|
|
122
|
-
**composition** — `width height duration sequences transitions`. With `threeD: true` it is a **card**: its children are drawn into one texture and move / rotate in depth together. Children use the composition's local coordinates and times. Position/rotate/scale it as a unit; to rotate/scale about its centre set `pivotX/pivotY` to the centre and `x/y` to where that point should sit.
|
|
125
|
+
**composition** — `width height duration sequences transitions`. With `threeD: true` it is a **card**: its children are drawn into one texture (content outside its `width × height` is clipped: size it for a soft shadow too) and move / rotate in depth together. Children use the composition's local coordinates and times. Position/rotate/scale it as a unit; to rotate/scale about its centre set `pivotX/pivotY` to the centre and `x/y` to where that point should sit.
|
|
123
126
|
|
|
124
127
|
**camera** (2.5D) — props in `initial`/keyframes: `x y z lookAtX lookAtY lookAtZ fov` (defaults: centred, looking at the z = 0 plane, `fov` 40, `z` auto = `(H/2)/tan(fov/2)` ≈ 989 at 720p). Never on the camera object itself. An orbit is `orbit()`; by hand: `x = cx + R·sin θ`, `z = R·cos θ`, `R = (H/2)/tan(fov/2)`, `lookAt` = the centre at `z = 0`.
|
|
125
128
|
|
|
@@ -175,7 +178,7 @@ new Controller(movie, { canvas }) // optional player bar (overlay
|
|
|
175
178
|
|
|
176
179
|
# pixi-effects pitfalls — what actually went wrong
|
|
177
180
|
|
|
178
|
-
Collected by having fresh AI sessions build
|
|
181
|
+
Collected by having fresh AI sessions build pieces from the docs alone: first six (kinetic type, news lower-third, slideshow, 2.5D showcase, three.js title, bar chart), then a portfolio of 16 more (items 32 and up), made by three different models. Each entry is a real stumble. **Status**: `fixed` = the library now handles or warns; `docs` = nothing can catch it, so remember it; `hand-roll` = the DSL has no feature, see the workaround.
|
|
179
182
|
|
|
180
183
|
A good habit that catches most of these: after `init`, read `window.__logs` (see `ai/template.html`) — every pixi-effects warning says what to change.
|
|
181
184
|
|
|
@@ -185,7 +188,7 @@ A good habit that catches most of these: after `init`, read `window.__logs` (see
|
|
|
185
188
|
2. **A layer's own `at` and a transition's `at` are composition time** (seconds from the parent composition's start). Only keyframes are layer-local.
|
|
186
189
|
3. **Layers are hidden, not removed, after `[at, at+duration)`** and keep their last values. Z-order is array order (later = on top). To switch scenes, stack scenes with `at`/`duration`, each starting with an opaque full-screen rect. *(docs)*
|
|
187
190
|
4. **Transitions need overlapping lifespans.** Both layers must be alive for the whole window: scene `i` starts at `i·(L−T)`, the transition's `at` is the next scene's start, total = `n·(L−T)+T`. A scene that ends while the transition is still running leaves a gap. *(docs)*
|
|
188
|
-
5. **Audio
|
|
191
|
+
5. **Audio length.** Omit `duration` on a one-shot sound effect: the layer lasts exactly as long as its clip (pop 0.13 s, click 0.1 s, chime 0.6 s, swoosh 0.55 s; nothing to measure). `loop: true` with no `duration` lasts until the composition ends. An explicit `duration` longer than the clip goes silent after the clip unless `loop: true` (`bgm.mp3` is 6 s) and warns. Volume fades work like any keyframe: `volume: 0` + `{ at: 0, to: { volume: v }, duration: 2 }` + `{ at: -2, to: { volume: 0 }, duration: 2 }` (the last 2 s only; `set` is a jump). *(fixed: volume keyframes used to ramp from the previous keyframe's end, so the music faded across the whole piece)*
|
|
189
192
|
6. **Snap times to the frame grid (`Math.round(t*30)/30`) when two things must stay locked** (a bar and its label). Drive both from one JS easing function with per-frame `set` keyframes rather than mixing a tween with computed positions. *(docs)*
|
|
190
193
|
7. **Pick eases on purpose.** `expo.in` stays tiny until the very end (a "flood" circle never reaches the corners — use a bigger radius and `power2.in`). A zoom transition with `power2.out` looks like a cut because the incoming scene is nearly opaque after 40 %. Default is linear. *(docs)*
|
|
191
194
|
8. **`render()` runs in roughly real time** (6 s of 720p ≈ 6 s). Listen to `movie.on('progress', e => e.progress)` (0–100). *(docs)*
|
|
@@ -195,7 +198,7 @@ A good habit that catches most of these: after `init`, read `window.__logs` (see
|
|
|
195
198
|
9. **Defaults differ by type.** rect/circle/ellipse are centred on `x,y`; text and image are top-left; a composition has no anchor — use `pivotX/pivotY` and set `x,y` to where the pivot should land. For a bar growing from its base use `anchorY: 1` (or `anchorX: 0`). *(docs)*
|
|
196
199
|
10. **Shape geometry may be at the top level or in `initial`** (`width height radius anchorX …`). *(fixed: `initial` used to be silently ignored)*
|
|
197
200
|
11. **Angles are degrees** — `rotation`, `skew*`, `rotationX/Y` — and `rotation: -0.2` is almost no rotation. *(docs)*
|
|
198
|
-
12. **Text**: anchor 0.5 centres the line *box*, not the cap height (
|
|
201
|
+
12. **Text**: anchor 0.5 centres the line *box*, not the cap height (an underline under serif or italic text needs ~`0.9·size` below the centre: `0.46·size` touches the descenders of a g or y). Arial Black is ~0.8·size wide per glyph, monospace ~0.6·size; leave ~7 % for hold-scale. `style` accepts any PixiJS TextStyle field: `letterSpacing`, `wordWrap` + `wordWrapWidth`, `lineHeight`, `stroke`, `dropShadow`, `padding`. A glow (`dropShadow` with `blur`) is clipped unless `padding ≥ 2·blur`. *(docs)*
|
|
199
202
|
13. **`w` / `h` in expressions** are the layer's own size. For text they now describe the styled text (`x: '-w'` scrolls a marquee fully out). *(fixed)*
|
|
200
203
|
14. **Masks live in the parent's coordinate space and do not follow the masked layer.** Reveal by growing the mask's `width` from a fixed edge (`anchorX: 0`); exit by tweening `x` and `width` together; slide the content separately. *(docs)*
|
|
201
204
|
15. **`line` / `polygon` / `path` use plain canvas coordinates** when you give no `x,y` (they used to be drawn around (0,0)); with `x,y` those place the shape's centre. Stroke colour and width go in `initial`. A background pill must be sized from its text (~0.58 × fontSize per glyph + padding): `inspect` does not check text against shapes. *(fixed)*
|
|
@@ -228,6 +231,27 @@ A good habit that catches most of these: after `init`, read `window.__logs` (see
|
|
|
228
231
|
30c. **Look with the built-in tools, not OS screenshots**: `await movie.contactSheet({ count: 6, as: 'dataURL' })` returns one labelled image of the whole animation; `await movie.inspect(frame)` returns every layer's canvas bounds and `issues`. If you do use a browser tool, `screenshot` needs an **absolute path**, macOS `sed -i` needs `''`, and a static server may redirect `/x.html` → `/x` and drop `?query`. Keep the template's `try/catch` around `init` so failures land in `window.__logs`. Check ≥ 5 timestamps including mid-transition. *(fixed: tools built in)*
|
|
229
232
|
31. **Check audio without rendering by decoding the render**: `const b = await movie.render({format:'mp4'})` then `new OfflineAudioContext(...).decodeAudioData(await b.arrayBuffer())` and measure RMS over time. `movie.audioBuffer` holds the mix. *(docs)*
|
|
230
233
|
|
|
234
|
+
## Round 2 — found by building 16 portfolio pieces (examples/gallery)
|
|
235
|
+
|
|
236
|
+
32. **Seeking is safe now** *(fixed)*: a `set` keyframe (counter value, text fill, image tint, shape style) is undone when you seek back before it, and shapes are redrawn before they are culled, so a rect growing from `width: 0` at the left edge draws after any jump seek (contact sheet, snapshot, scrubbing, export). The old workarounds (`width: 0.01`, a one-frame `to` instead of `set`) are not needed.
|
|
237
|
+
33. **A mask starts and ends with the layer it masks** *(fixed)*, so its keyframes count from that layer's start. A mask with an explicit `at` keeps composition time. Before, a mask `at: 0` reveal had finished before a layer that appeared at 8 s, and the layer stayed invisible without any warning.
|
|
238
|
+
34. **`from` and `from+to` show their start value from the LAYER's start**, not from the keyframe's `at` (GSAP behaviour): a delayed fade-in `{ at: 2, from: { alpha: 0 }, to: { alpha: 1 } }` needs no `initial.alpha`. To keep the current value until `at` and then jump, use `set`. *(docs)*
|
|
239
|
+
35. **One `Movie` per page.** Creating a second Movie (for an isolated repro) and destroying it breaks the first (`null.clear`). Reload instead. *(docs)*
|
|
240
|
+
36. **Multi-line text is centre-aligned by default** (`style.align: 'left'` for left-aligned paragraphs). *(docs)*
|
|
241
|
+
37. **A `threeD` composition (a card) clips its children at its own width × height.** Size the card for its soft shadow too. A growing `threeD` shape or text is fine: its texture is resized in place (it used to warn "destroyed while still bound"). *(docs / fixed)*
|
|
242
|
+
38. **Under an orbit the side the camera swings toward becomes the NEAR side**: a "far" card at `z: −200` can be drawn bigger than 1× on that side and run off the frame (`inspect` only checks text). Pull those cards inward / lower `z`, and check a frame at the extreme of the sweep. After `orbit()` ends the default camera returns, so to hold the final pose add a camera layer that starts there. Near particles balloon under a dolly zoom: cap particle `z` at about +150, or one becomes a fake full stop. *(docs)*
|
|
243
|
+
39. **`fillGradient` stops span the whole unmasked shape**, not the visible part: under a mask, place the stops for the visible fraction (e.g. 0.64→1). A translucent shape over near-black reads as grey: put the alpha in the gradient stops. *(docs)*
|
|
244
|
+
40. **Rotate a polygon / path about a chosen point** by wrapping it in a `composition` with `pivotX/pivotY` (its centre is otherwise the bounds centre). *(docs)*
|
|
245
|
+
41. **Glow a whole set of layers** by putting them in one `composition` with a blur filter and `filterArea` (only a composition carries a filter for its children): wide enough for the blur, and the set is built once, so the extra copy is just a second group. *(docs)*
|
|
246
|
+
42. **Transition looks:** the default `dissolve` reads as a hard black-and-white camouflage and `scale: 220` as static; `scale: 90, smoothing: 0.5` is a soft film dissolve. The default edge softness of `iris` (0.02) and `wipe` blurs flat graphics at 720p: `smoothing: 0.004`–`0.01` gives a clean edge. *(docs)*
|
|
247
|
+
43. **Layers built in a loop need their z-order planned**: anything pushed to the array after the loop is drawn over what the loop made (rings crossed over a header). Keyframes on different properties of one layer may overlap in time. Keep a subject in the upper ~60 % of a source image if a caption will sit under it (`inspect` does not look at picture content). *(docs)*
|
|
248
|
+
44. **`{value}` has no number padding**: a clock or timecode cannot show `:05`. Keep the value in a range that always has the same digit count, or split digits into two counters. *(hand-roll)*
|
|
249
|
+
45. **The same mistake in a loop warns once**: the warning "keyframe starts after the layer ends" is summarised after three layers. The usual cause is an off-by-one (`f <= frames` instead of `f < frames`) that puts the last sample exactly at the layer's end. *(fixed)*
|
|
250
|
+
46. **Still not in the DSL (hand-roll; round-two notes have workarounds):** arc / progress-ring primitive and stroke draw-on / trim path (use a growing rect mask for a one-direction reveal, tick marks, or pre-drawn arcs shown one per frame), text content that changes over time (only `{value}`), per-frame jitter (film grain = seeded `set` keyframes on an oversized image), particle emitters, per-letter / per-line text split (measure with `canvas.measureText` using Pixi's font string), shared masks, `zIndex`.
|
|
251
|
+
46b. **Blend modes exist now** (`blendMode: 'add' | 'screen' | 'multiply'` on any layer, threeD layers and compositions included; a composition's children inherit it). Additive white cores no longer read grey on a coloured background. *(fixed)*
|
|
252
|
+
47. **Browser tooling:** the `agent-browser` daemon is shared, so a `contactSheet` can come back from another session: after saving an image, look at it and confirm it is YOUR piece. In zsh a variable holding `agent-browser --session x` is not split into words (use a small wrapper script). `inspect` now clips overlaps to the visible area and ignores the two scenes of a running transition; it still does not compare text with picture content or shapes.
|
|
253
|
+
48. **A composition's `alpha` is applied to each child separately, not to the flattened group** (measured: two overlapping opaque circles in a composition at `alpha: 0.5` show the lower one through the upper one in the overlap). Fading a group that has overlapping children therefore shows the overlap; fade the children themselves, or keep overlapping parts out of the group. Expressions have no way to read a sibling's size: measure text with `canvas.measureText` (the font string Pixi uses) and compute pill widths in JS. *(docs)*
|
|
254
|
+
|
|
231
255
|
|
|
232
256
|
<!-- ===== ai/reference/recipes.md ===== -->
|
|
233
257
|
|
|
@@ -683,7 +707,7 @@ A layer is **not removed** when its lifespan `[at, at + duration)` ends: it is o
|
|
|
683
707
|
|
|
684
708
|
### `text`
|
|
685
709
|
|
|
686
|
-
Renders a [PIXI.Text](https://pixijs.com/8.x/guides/components/scene-objects/text/text). Animatable position, rotation, scale, opacity and `fill`. `style` accepts any PixiJS `TextStyle` field and is applied once at build time — notably `fontSize fontFamily fontWeight fill letterSpacing lineHeight align wordWrap wordWrapWidth stroke dropShadow padding` (numbers may be expressions). A `dropShadow` glow is clipped unless `padding` is at least twice its `blur`. Text content cannot change over time (
|
|
710
|
+
Renders a [PIXI.Text](https://pixijs.com/8.x/guides/components/scene-objects/text/text). Animatable position, rotation, scale, opacity and `fill`. `style` accepts any PixiJS `TextStyle` field and is applied once at build time — notably `fontSize fontFamily fontWeight fill letterSpacing lineHeight align wordWrap wordWrapWidth stroke dropShadow padding` (numbers may be expressions). A `dropShadow` glow is clipped unless `padding` is at least twice its `blur`. Text content cannot change over time, with one exception: a `{value}` placeholder in `text` prints an animatable number (`text: '{value} users'`, `initial: { value: 0 }`, a keyframe `to: { value: 2480 }`; `format: { decimals, grouping }`) — that is how counters work. Any other change of wording is a second layer (stack layers with `at` / `duration`). Multi-line text is centre-aligned unless `style.align` says otherwise. In expressions `w` / `h` are the size of the styled text, so `x: '-w'` places it just off the left edge.
|
|
687
711
|
|
|
688
712
|
```ts
|
|
689
713
|
{
|
|
@@ -1158,6 +1182,17 @@ When `true`, flip the mask sense: pixels INSIDE the mask shape become transparen
|
|
|
1158
1182
|
|
|
1159
1183
|
Routed through PIXI v8's native `setMask({ inverse: true })`.
|
|
1160
1184
|
|
|
1185
|
+
#### `blendMode`
|
|
1186
|
+
|
|
1187
|
+
How a layer blends with what is behind it: `'normal'` (default), `'add'`, `'screen'` or `'multiply'`. `add` and `screen` brighten, so overlapping glows, halos and light leaks add up instead of covering each other; `multiply` darkens. It works on every layer type, on `threeD` layers, and on a composition (its children inherit the mode, each blending with what is behind it). Any other value warns and is ignored.
|
|
1188
|
+
|
|
1189
|
+
```ts
|
|
1190
|
+
// A soft white glow that brightens whatever it overlaps
|
|
1191
|
+
{ type: 'shape', shape: 'circle', radius: 120, blendMode: 'add',
|
|
1192
|
+
fillGradient: { type: 'radial', stops: [[0, 'rgba(255,255,255,0.9)'], [1, 'rgba(255,255,255,0)']] },
|
|
1193
|
+
initial: { x: 'W/2', y: 'H/2' } }
|
|
1194
|
+
```
|
|
1195
|
+
|
|
1161
1196
|
---
|
|
1162
1197
|
|
|
1163
1198
|
## Assets
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "pixi-effects",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.4.0",
|
|
4
4
|
"description": "Declarative composition and video rendering for the web. Built on PixiJS v8.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"exports": {
|
|
@@ -39,6 +39,7 @@
|
|
|
39
39
|
"test:watch": "vitest",
|
|
40
40
|
"typecheck": "tsc --noEmit",
|
|
41
41
|
"build:ai": "node scripts/build-llms.mjs",
|
|
42
|
+
"build:gallery": "node scripts/build-gallery.mjs",
|
|
42
43
|
"prepublishOnly": "npm run build:ai && npm run typecheck && npm test && npm run build"
|
|
43
44
|
},
|
|
44
45
|
"dependencies": {
|
|
@@ -1,13 +0,0 @@
|
|
|
1
|
-
'use strict';
|
|
2
|
-
|
|
3
|
-
var chunkZL262ZRM_cjs = require('./chunk-ZL262ZRM.cjs');
|
|
4
|
-
require('./chunk-SIRVULFF.cjs');
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
Object.defineProperty(exports, "CompositionSequence", {
|
|
9
|
-
enumerable: true,
|
|
10
|
-
get: function () { return chunkZL262ZRM_cjs.CompositionSequence; }
|
|
11
|
-
});
|
|
12
|
-
//# sourceMappingURL=Composition-6FDH5OPM.cjs.map
|
|
13
|
-
//# sourceMappingURL=Composition-6FDH5OPM.cjs.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/space/camera.ts","../src/space/depth.ts","../src/space/Layer3D.ts","../src/space/lint.ts","../src/sequences/Composition.ts"],"names":["i","frameOf","Container"],"mappings":"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","file":"chunk-DIJG2RSF.js","sourcesContent":["/** A camera layer's lifespan on the global timeline, seconds. */\nexport interface CameraWindow { start: number; end: number }\n\n/**\n * The active camera at time `t`: the last-listed (top-most) camera whose\n * lifespan covers `t`. Windows are [start, end), except that a camera running\n * to the end of its composition also covers the final instant `t === compEnd`.\n */\nexport function pickActiveCamera<T extends CameraWindow>(\n cams: readonly T[],\n t: number,\n compEnd: number,\n): T | null {\n for (let i = cams.length - 1; i >= 0; i--) {\n const c = cams[i]!;\n const inside = t >= c.start && (t < c.end || (c.end >= compEnd && t <= compEnd));\n if (inside) return c;\n }\n return null;\n}\n\n/** First pair of camera indices whose lifespans strictly overlap, or null. */\nexport function findOverlap(cams: readonly CameraWindow[]): [number, number] | null {\n for (let i = 0; i < cams.length; i++) {\n for (let j = i + 1; j < cams.length; j++) {\n const a = cams[i]!;\n const b = cams[j]!;\n if (a.start < b.end && b.start < a.end) return [i, j];\n }\n }\n return null;\n}\n","export interface DepthItem {\n /** Position in the composition's stack (monotonic; gaps allowed). */\n stackIndex: number;\n threeD: boolean;\n /** Camera-space depth (larger = farther). Only read for threeD items. */\n depth: number;\n}\n\nconst finite = (n: number): number => (Number.isFinite(n) ? n : 0);\n\n/**\n * zIndex per item. Non-3D items keep their stack index. Each run of\n * consecutive threeD items is redistributed over the same index slots,\n * farthest first (drawn first), ties in stack order.\n */\nexport function assignDepthOrder(items: readonly DepthItem[]): number[] {\n const out = items.map(i => i.stackIndex);\n let i = 0;\n while (i < items.length) {\n if (!items[i]!.threeD) { i++; continue; }\n let j = i;\n while (j + 1 < items.length && items[j + 1]!.threeD) j++;\n const run = items.slice(i, j + 1).map((it, k) => ({ it, pos: i + k }));\n const slots = run.map(r => r.it.stackIndex);\n const farthestFirst = [...run].sort((a, b) => finite(b.it.depth) - finite(a.it.depth));\n farthestFirst.forEach((r, k) => { out[r.pos] = slots[k]!; });\n i = j + 1;\n }\n return out;\n}\n","import { Container, Matrix, PerspectiveMesh, RenderTexture, Texture } from 'pixi.js';\nimport type { Sequence } from '../sequences/Base';\nimport { describeLayer } from '../core/lint';\nimport { DEG, projectLayer, type CameraBasis, type LayerTransform, type Rect } from './math';\n\n/** Render textures are capped at this many pixels on the long side; larger layers are downscaled. */\nexport const MAX_TEXTURE_SIZE = 4096;\n/**\n * Render textures are drawn at this multiple of the layer size (until the caps),\n * so a layer enlarged by perspective (z > 0) stays sharp instead of showing\n * jagged edges and soft text.\n */\nexport const SUPERSAMPLE = 2;\n/** Total texture pixels per layer are capped here (≈ one 2048² target); resolution drops to fit. */\nexport const MAX_TEXTURE_PIXELS = 2048 * 2048;\n/** MSAA multiplies target memory ~4x, so only small textures get it (supersampling covers the rest). */\nexport const ANTIALIAS_MAX_PIXELS = 1024 * 1024;\n/** Mesh grid per side. 20 keeps steeply tilted planes free of visible affine warping. */\nexport const MESH_GRID = 20;\n\n/** The slice of a Pixi renderer Layer3D needs (also what tests fake). */\nexport interface SpaceHost {\n render(options: {\n container: Container;\n target: RenderTexture;\n transform: Matrix;\n clear: boolean;\n clearColor: number[];\n }): void;\n}\n\ntype Carrier = Container & { z?: number; rotationX?: number; rotationY?: number };\n\ninterface TextureSize { w: number; h: number; resolution: number; antialias: boolean }\n\n/** Sum of the target's filter paddings: the texture must be this much larger on every side or filter output is clipped. */\nfunction filterPadding(target: Container): number {\n const filters = (target as unknown as { filters?: ReadonlyArray<{ padding?: number }> | null }).filters;\n if (!Array.isArray(filters)) return 0;\n let pad = 0;\n for (const f of filters) pad += f?.padding ?? 0;\n return Number.isFinite(pad) && pad > 0 ? Math.ceil(pad) : 0;\n}\n\nexport function readLayerTransform(target: Container): LayerTransform {\n const c = target as Carrier;\n return {\n x: c.x, y: c.y, z: c.z ?? 0,\n rotationX: (c.rotationX ?? 0) * DEG,\n rotationY: (c.rotationY ?? 0) * DEG,\n rotationZ: c.rotation,\n scaleX: c.scale.x, scaleY: c.scale.y,\n pivotX: c.pivot.x, pivotY: c.pivot.y,\n };\n}\n\n/**\n * Draws one `threeD` sequence: its display object is rendered into a\n * RenderTexture (with its own 2D transform replaced, so layer-local content\n * lands at the texture origin) and shown on a PerspectiveMesh whose four\n * corners come from projecting the layer through the active camera.\n *\n * The sequence's `target` is never in the scene graph; the composition adds\n * `display` instead. `z`, `rotationX`, `rotationY` live on `target` as plain\n * numeric props so GSAP tweens them like any other prop.\n */\nexport class Layer3D {\n readonly display: PerspectiveMesh;\n /** Camera-space depth from the last update (larger = farther). */\n depth = 0;\n private rt: RenderTexture | null = null;\n private size: TextureSize | null = null;\n private warnedBehind = false;\n\n constructor(\n private readonly seq: Sequence,\n private readonly frameOf: () => Rect,\n ) {\n const target = seq.target as Carrier;\n target.z ??= 0;\n target.rotationX ??= 0;\n target.rotationY ??= 0;\n this.display = new PerspectiveMesh({ texture: Texture.WHITE, verticesX: MESH_GRID, verticesY: MESH_GRID });\n if (seq.spec.name) this.display.label = seq.spec.name;\n this.display.visible = false;\n }\n\n update(host: SpaceHost, basis: CameraBasis): void {\n const target = this.seq.target as Carrier | null;\n // Pixi skips rendering (and clearing) a container that is not `visible`\n // (e.g. PixiPlugin autoAlpha at alpha 0), which would leave a stale texture.\n if (!target || !target.renderable || !target.visible) return this.hide();\n\n const bounds = this.frameOf();\n const pad = filterPadding(target);\n const needW = Math.ceil(bounds.width + 2 * pad);\n const needH = Math.ceil(bounds.height + 2 * pad);\n if (!(needW >= 1 && needH >= 1) || !Number.isFinite(bounds.x) || !Number.isFinite(bounds.y)) return this.hide();\n\n const size = this.sizeFor(needW, needH);\n // The quad covers exactly the texture's pixel rect in layer space.\n const frame: Rect = { x: bounds.x - pad, y: bounds.y - pad, width: size.w, height: size.h };\n const projected = projectLayer(readLayerTransform(target), frame, basis);\n this.depth = projected.depth;\n if (!projected.visible) {\n if (!this.warnedBehind) {\n this.warnedBehind = true;\n console.warn(\n `pixi-effects: ${describeLayer(this.seq.spec)} is at or behind the camera plane (z = ${(target.z ?? 0).toFixed(0)}) and is hidden. ` +\n `If that is unintended, lower its z or move the camera back (the default camera sits at z = (height/2)/tan(fov/2), about 989 for 720p at fov 40).`,\n );\n }\n return this.hide();\n }\n\n this.ensureTexture(size);\n // `transform` replaces the container's own local transform for this render\n // (Pixi RenderGroupSystem), while `container.alpha` still applies — so the\n // texture carries the layer's alpha and the mesh alpha stays at 1.\n host.render({\n container: target,\n target: this.rt!,\n transform: new Matrix().translate(-frame.x, -frame.y),\n clear: true,\n clearColor: [0, 0, 0, 0],\n });\n this.display.geometry.setCorners(...projected.corners);\n this.display.visible = true;\n }\n\n destroy(): void {\n this.display.destroy();\n this.rt?.destroy(true);\n this.rt = null;\n }\n\n private hide(): void {\n this.display.visible = false;\n }\n\n /**\n * Texture size for content of w×h. An existing texture is kept while it is at\n * least that big and at most 2x too big, so content whose bounds change every\n * frame (typewriter text, growing shapes) does not reallocate each frame.\n */\n private sizeFor(w: number, h: number): TextureSize {\n const cur = this.size;\n if (cur && cur.w >= w && cur.h >= h && cur.w <= 2 * w && cur.h <= 2 * h) return cur;\n const resolution = Math.min(\n SUPERSAMPLE,\n MAX_TEXTURE_SIZE / Math.max(w, h),\n Math.sqrt(MAX_TEXTURE_PIXELS / (w * h)),\n );\n const antialias = w * h * resolution * resolution <= ANTIALIAS_MAX_PIXELS;\n return { w, h, resolution, antialias };\n }\n\n private ensureTexture(size: TextureSize): void {\n if (this.rt && this.size === size) return;\n const next = RenderTexture.create({\n width: size.w, height: size.h, resolution: size.resolution, antialias: size.antialias,\n });\n this.display.texture = next;\n this.rt?.destroy(true);\n this.rt = next;\n this.size = size;\n }\n}\n","import { collectPropKeys } from './specKeys';\nimport { describeLayer } from '../core/lint';\nimport type { SequenceSpec } from '../types';\n\ntype Warn = (message: string) => void;\nconst defaultWarn: Warn = m => console.warn(m);\n\nconst FOV_HINT = 'perspective is the camera\\'s \"fov\" — add a { type: \"camera\" } layer and set fov in its initial / keyframes';\n\n/** Keys that are never valid for any layer, with a hint at what the author probably meant. */\nconst LAYER_ALIASES: Record<string, string> = {\n rotateX: 'did you mean \"rotationX\"?',\n rotateY: 'did you mean \"rotationY\"?',\n rotateZ: 'did you mean \"rotation\"?',\n rotationZ: 'did you mean \"rotation\" (it is the Z rotation)?',\n translateZ: 'did you mean \"z\"?',\n depth: 'did you mean \"z\"?',\n posZ: 'did you mean \"z\"?',\n perspective: FOV_HINT,\n zoom: FOV_HINT,\n};\n\n/** Camera-only mistakes. */\nconst CAMERA_ALIASES: Record<string, string> = {\n pointOfInterest: 'did you mean \"lookAtX / lookAtY / lookAtZ\"?',\n lookAt: 'did you mean \"lookAtX / lookAtY / lookAtZ\"?',\n};\n\nconst CAMERA_PROPS = ['x', 'y', 'z', 'fov', 'lookAtX', 'lookAtY', 'lookAtZ'];\nconst NEEDS_THREE_D = ['z', 'rotationX', 'rotationY'];\nconst SKEW_KEYS = ['skew', 'skewX', 'skewY'];\n\n/**\n * Warn (never throw) about the inputs an AI author is most likely to get wrong,\n * with a message that says what to change. One call per layer, at build time.\n */\nexport function lintSequence(spec: SequenceSpec, warn: Warn = defaultWarn): void {\n const who = describeLayer(spec);\n const keys = collectPropKeys(spec);\n const explained = new Set<string>();\n\n for (const k of keys) {\n const hint = LAYER_ALIASES[k] ?? (spec.type === 'camera' ? CAMERA_ALIASES[k] : undefined);\n if (hint) {\n explained.add(k);\n warn(`pixi-effects: ${who}: \"${k}\" is not a property — ${hint}`);\n }\n }\n\n if (spec.type === 'camera') {\n const raw = spec as unknown as Record<string, unknown>;\n for (const p of CAMERA_PROPS) {\n if (p in raw) warn(`pixi-effects: ${who}: \"${p}\" must go inside initial / keyframes, not on the camera itself`);\n }\n for (const k of Object.keys(raw)) {\n const hint = CAMERA_ALIASES[k] ?? LAYER_ALIASES[k];\n if (hint) warn(`pixi-effects: ${who}: \"${k}\" is not a property — ${hint} (inside initial)`);\n }\n for (const k of keys) {\n if (!explained.has(k) && !CAMERA_PROPS.includes(k)) {\n warn(`pixi-effects: ${who}: \"${k}\" has no effect on a camera (use ${CAMERA_PROPS.join(', ')})`);\n }\n }\n return;\n }\n\n if (spec.type === 'audio') {\n if (spec.threeD) warn(`pixi-effects: ${who}: threeD has no effect on audio`);\n return;\n }\n\n if (!spec.threeD) {\n for (const k of NEEDS_THREE_D) {\n if (keys.has(k)) warn(`pixi-effects: ${who}: \"${k}\" needs threeD: true (it is ignored otherwise)`);\n }\n } else {\n for (const k of SKEW_KEYS) {\n if (keys.has(k)) warn(`pixi-effects: ${who}: \"${k}\" is ignored on threeD layers`);\n }\n }\n}\n","import { Container, Rectangle } from 'pixi.js';\nimport { Sequence } from './Base';\nimport { buildSequenceTree } from '../core/Composition';\nimport { CameraSequence } from '../space/CameraSequence';\nimport { findOverlap, pickActiveCamera } from '../space/camera';\nimport { assignDepthOrder } from '../space/depth';\nimport { Layer3D, type SpaceHost } from '../space/Layer3D';\nimport { lintSequence } from '../space/lint';\nimport { describeLayer, lintText, lintTiming } from '../core/lint';\nimport { cameraBasis, homeCamera } from '../space/math';\nimport type { CompositionSequenceSpec, AudioDescriptor, CompositionShape, SequenceSpec } from '../types';\n\nimport type { gsap } from 'gsap';\ntype Timeline = ReturnType<typeof gsap.timeline>;\n\nexport class CompositionSequence extends Sequence {\n declare spec: CompositionSequenceSpec;\n private _innerContainer: Container | null = null;\n private _compositionShape: CompositionShape | null = null;\n _children: Sequence[] = [];\n private _cameras: CameraSequence[] = [];\n private _layers3d: Layer3D[] = [];\n /** Drawn children in stack order (cameras and target-less sequences excluded). */\n private _visual: Array<{ seq: Sequence; layer: Layer3D | null }> = [];\n\n async build(): Promise<void> {\n const width = this.spec.width ?? this.parent?.width ?? this.root.width;\n const height = this.spec.height ?? this.parent?.height ?? this.root.height;\n if (this.duration === undefined) {\n this.duration = this.spec.duration ?? this.parent?.duration ?? this.root.duration;\n }\n const wrapper = new Container();\n wrapper.cullable = true;\n wrapper.cullableChildren = true;\n wrapper.cullArea = new Rectangle(0, 0, width, height);\n\n const inner = new Container();\n inner.cullable = true;\n inner.cullableChildren = true;\n wrapper.addChild(inner);\n\n this.target = wrapper;\n this.intrinsicWidth = width;\n this.intrinsicHeight = height;\n this._innerContainer = inner;\n this._compositionShape = { width, height, duration: this.duration };\n\n for (const s of this.spec.sequences ?? []) {\n lintSequence(s);\n lintTiming(s, this.duration);\n lintText(s);\n }\n\n this._children = await buildSequenceTree(\n this.spec.sequences ?? [],\n this._compositionShape,\n this.root,\n );\n for (const child of this._children) {\n // Cameras are display-less: they only feed the projection pass.\n if (child instanceof CameraSequence) {\n this._cameras.push(child);\n continue;\n }\n if (!child.target) continue;\n\n const maskSpec = (child.spec as { mask?: SequenceSpec }).mask;\n\n // threeD layers never enter the scene graph themselves: their display\n // object is rendered into a texture and a perspective mesh stands in.\n if (child.spec.threeD) {\n const layer = new Layer3D(child, frameOf(child));\n inner.addChild(layer.display);\n this._layers3d.push(layer);\n this._visual.push({ seq: child, layer });\n if (maskSpec) {\n console.warn(`pixi-effects: ${describeLayer(child.spec)}: mask is not supported on threeD layers yet; ignored`);\n }\n continue;\n }\n\n inner.addChild(child.target);\n this._visual.push({ seq: child, layer: null });\n // If this child has a `mask` spec, build the mask sequence in the same\n // composition shape, add its target to the same parent (so its\n // transforms resolve in the same coord space), and wire PIXI's\n // mask channel. PIXI v8 renders mask containers into the stencil /\n // alpha buffer; they don't render as normal children.\n if (maskSpec) {\n const built = await buildSequenceTree([maskSpec], this._compositionShape, this.root);\n const maskSeq = built[0];\n if (maskSeq?.target) {\n inner.addChild(maskSeq.target);\n // PIXI v8 `setMask` accepts an `inverse` flag — that's how we\n // expose `maskInverted` from the spec. Falls back to plain\n // `target.mask = …` for runtimes that don't have setMask\n // (older PIXI builds).\n const inverse = (child.spec as { maskInverted?: boolean }).maskInverted ?? false;\n const t = child.target as Container & {\n setMask?: (opts: { mask: Container | null; inverse?: boolean }) => void;\n mask: Container | null;\n };\n if (typeof t.setMask === 'function') {\n t.setMask({ mask: maskSeq.target, inverse });\n } else {\n t.mask = maskSeq.target;\n }\n child.maskSequence = maskSeq;\n }\n }\n }\n\n if (this._layers3d.length > 0) {\n // Stack order becomes explicit zIndex so threeD layers can be re-sorted\n // by depth each frame without reparenting.\n inner.sortableChildren = true;\n this._visual.forEach((v, i) => {\n (v.layer?.display ?? v.seq.target!).zIndex = i;\n });\n } else if (this._cameras.length > 0) {\n console.warn('pixi-effects: camera has no effect: this composition has no threeD layers');\n }\n\n this.buildFilters();\n }\n\n override bindTimeline(timeline: Timeline, offset = 0): void {\n super.bindTimeline(timeline, offset);\n // Children's `at` is relative to this composition's start, so push them\n // forward by our absolute start time on the global timeline.\n const childOffset = offset + this.at;\n for (const child of this._children) {\n child.bindTimeline(timeline, childOffset);\n // The mask shares the maskee's offset — its `at` is interpreted\n // relative to the composition's start, just like the child itself,\n // so a reveal-from-zero animation lines up naturally.\n child.maskSequence?.bindTimeline(timeline, childOffset);\n }\n const overlap = findOverlap(this._cameras.map(c => c.window()));\n if (overlap) {\n console.warn(`pixi-effects: cameras #${overlap[0] + 1} and #${overlap[1] + 1} overlap in time; the top-most one wins`);\n }\n }\n\n /** Drawn children in stack order, with the display object that stands in for each (the mesh for a threeD layer). */\n layers(): Array<{ seq: Sequence; display: Container; threeD: boolean }> {\n return this._visual.map(v => ({\n seq: v.seq,\n display: (v.layer?.display ?? v.seq.target!) as unknown as Container,\n threeD: v.layer !== null,\n }));\n }\n\n override updateSpace(t: number, host: SpaceHost): void {\n // Inner compositions first: a threeD composition is rendered into its own\n // texture by this level, so its content must already be projected.\n for (const child of this._children) child.updateSpace(t, host);\n if (this._layers3d.length === 0 || !this._compositionShape) return;\n\n const { width, height } = this._compositionShape;\n const compEnd = (this.absoluteStart ?? 0) + (this.duration ?? 0);\n const active = pickActiveCamera(\n this._cameras.map(cam => ({ cam, ...cam.window() })),\n t,\n compEnd,\n );\n const basis = cameraBasis(active ? active.cam.state() : homeCamera(width, height), width, height);\n\n for (const layer of this._layers3d) layer.update(host, basis);\n\n const order = assignDepthOrder(\n this._visual.map((v, i) => ({ stackIndex: i, threeD: v.layer !== null, depth: v.layer?.depth ?? 0 })),\n );\n this._visual.forEach((v, i) => {\n if (v.layer) v.layer.display.zIndex = order[i]!;\n });\n }\n\n override collectAudio(out: AudioDescriptor[], baseTime: number): void {\n super.collectAudio(out, baseTime);\n const childBase = baseTime + this.at;\n for (const child of this._children) child.collectAudio(out, childBase);\n }\n\n override destroy(): void {\n for (const l of this._layers3d) l.destroy();\n this._layers3d = [];\n for (const c of this._children) c.destroy();\n super.destroy();\n }\n}\n\n/** Layer-space rectangle a threeD child projects: a composition's frame, otherwise its content bounds. */\nfunction frameOf(child: Sequence): () => { x: number; y: number; width: number; height: number } {\n if (child instanceof CompositionSequence) {\n return () => ({ x: 0, y: 0, width: child.intrinsicWidth, height: child.intrinsicHeight });\n }\n return () => child.target!.getLocalBounds();\n}\n"]}
|