pixi-effects 0.46.0 → 0.47.1
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 +21 -0
- package/README.md +5 -5
- package/ai/chat-template.html +3 -3
- package/ai/tools/check.mjs +2 -2
- package/ai/tools/lookup.mjs +6 -1
- package/ai/tools/pixi-effects.mjs +1 -0
- package/ai/tools/render.mjs +25 -2
- package/dist/Composition-AZEATHJB.cjs +16 -0
- package/dist/{Composition-PME3P5LP.cjs.map → Composition-AZEATHJB.cjs.map} +1 -1
- package/dist/Composition-ME3L3EFT.js +7 -0
- package/dist/{Composition-NSY7A32Y.js.map → Composition-ME3L3EFT.js.map} +1 -1
- package/dist/{Spans-2TZCNREQ.cjs → Spans-LTKEUHDN.cjs} +11 -11
- package/dist/{Spans-2TZCNREQ.cjs.map → Spans-LTKEUHDN.cjs.map} +1 -1
- package/dist/{Spans-TESJPQKX.js → Spans-YV7K4X5I.js} +6 -6
- package/dist/{Spans-TESJPQKX.js.map → Spans-YV7K4X5I.js.map} +1 -1
- package/dist/{blendModes-FMYO6SQN.js → blendModes-56NHK2MP.js} +4 -4
- package/dist/{blendModes-FMYO6SQN.js.map → blendModes-56NHK2MP.js.map} +1 -1
- package/dist/{blendModes-FD3THLNC.cjs → blendModes-ONOPMMAB.cjs} +5 -5
- package/dist/{blendModes-FD3THLNC.cjs.map → blendModes-ONOPMMAB.cjs.map} +1 -1
- package/dist/{chunk-LALEBV63.cjs → chunk-4NOTVQ3I.cjs} +29 -29
- package/dist/{chunk-LALEBV63.cjs.map → chunk-4NOTVQ3I.cjs.map} +1 -1
- package/dist/{chunk-JN7JHNZR.cjs → chunk-53DXJEO7.cjs} +5 -5
- package/dist/{chunk-JN7JHNZR.cjs.map → chunk-53DXJEO7.cjs.map} +1 -1
- package/dist/{chunk-DM2OLQOJ.js → chunk-6MHJKCXO.js} +5 -5
- package/dist/{chunk-DM2OLQOJ.js.map → chunk-6MHJKCXO.js.map} +1 -1
- package/dist/{chunk-K24FF4BT.js → chunk-7IDEWQPH.js} +19 -5
- package/dist/chunk-7IDEWQPH.js.map +1 -0
- package/dist/{chunk-DKCMJILW.cjs → chunk-BFERTUXK.cjs} +92 -92
- package/dist/{chunk-DKCMJILW.cjs.map → chunk-BFERTUXK.cjs.map} +1 -1
- package/dist/{chunk-3SAS3ZE5.cjs → chunk-NEMWRJQS.cjs} +11 -2
- package/dist/chunk-NEMWRJQS.cjs.map +1 -0
- package/dist/{chunk-32MMNDDN.js → chunk-NVKHUAHU.js} +11 -2
- package/dist/chunk-NVKHUAHU.js.map +1 -0
- package/dist/{chunk-2E74SP63.js → chunk-OVTTCX2E.js} +105 -25
- package/dist/chunk-OVTTCX2E.js.map +1 -0
- package/dist/{chunk-FPV3NPYC.js → chunk-QMVK55LC.js} +5 -5
- package/dist/{chunk-FPV3NPYC.js.map → chunk-QMVK55LC.js.map} +1 -1
- package/dist/{chunk-O66JGPVV.cjs → chunk-SMHTOWXG.cjs} +19 -5
- package/dist/chunk-SMHTOWXG.cjs.map +1 -0
- package/dist/{chunk-VNP7QCJE.js → chunk-UTDELFOU.js} +4 -4
- package/dist/{chunk-VNP7QCJE.js.map → chunk-UTDELFOU.js.map} +1 -1
- package/dist/{chunk-7M63Y6MO.cjs → chunk-YXIEPTFG.cjs} +150 -70
- package/dist/chunk-YXIEPTFG.cjs.map +1 -0
- package/dist/index.cjs +37 -37
- package/dist/index.d.cts +2 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.js +6 -6
- package/dist/loader.css +1 -1
- package/dist/present.cjs +6 -6
- package/dist/present.js +6 -6
- package/dist/sound.cjs +2 -2
- package/dist/sound.js +1 -1
- package/dist/three.cjs +6 -6
- package/dist/three.js +2 -2
- package/docs/api.md +1 -1
- package/docs/dsl.md +2 -2
- package/llms-full.txt +8 -7
- package/package.json +1 -1
- package/skills/pixi-effects/SKILL.md +2 -1
- package/skills/pixi-effects/reference/cheatsheet.md +2 -2
- package/skills/pixi-effects/reference/recipes.md +1 -1
- package/skills/pixi-effects/template.html +6 -6
- package/dist/Composition-NSY7A32Y.js +0 -7
- package/dist/Composition-PME3P5LP.cjs +0 -16
- package/dist/chunk-2E74SP63.js.map +0 -1
- package/dist/chunk-32MMNDDN.js.map +0 -1
- package/dist/chunk-3SAS3ZE5.cjs.map +0 -1
- package/dist/chunk-7M63Y6MO.cjs.map +0 -1
- package/dist/chunk-K24FF4BT.js.map +0 -1
- package/dist/chunk-O66JGPVV.cjs.map +0 -1
package/dist/index.cjs
CHANGED
|
@@ -1,138 +1,138 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
|
-
var
|
|
4
|
-
require('./chunk-
|
|
5
|
-
var
|
|
6
|
-
var
|
|
7
|
-
require('./chunk-
|
|
8
|
-
require('./chunk-
|
|
3
|
+
var chunkYXIEPTFG_cjs = require('./chunk-YXIEPTFG.cjs');
|
|
4
|
+
require('./chunk-BFERTUXK.cjs');
|
|
5
|
+
var chunk4NOTVQ3I_cjs = require('./chunk-4NOTVQ3I.cjs');
|
|
6
|
+
var chunkSMHTOWXG_cjs = require('./chunk-SMHTOWXG.cjs');
|
|
7
|
+
require('./chunk-53DXJEO7.cjs');
|
|
8
|
+
require('./chunk-NEMWRJQS.cjs');
|
|
9
9
|
var chunkTWZNOUM7_cjs = require('./chunk-TWZNOUM7.cjs');
|
|
10
10
|
|
|
11
11
|
|
|
12
12
|
|
|
13
13
|
Object.defineProperty(exports, "Movie", {
|
|
14
14
|
enumerable: true,
|
|
15
|
-
get: function () { return
|
|
15
|
+
get: function () { return chunkYXIEPTFG_cjs.Movie; }
|
|
16
16
|
});
|
|
17
17
|
Object.defineProperty(exports, "animateText", {
|
|
18
18
|
enumerable: true,
|
|
19
|
-
get: function () { return
|
|
19
|
+
get: function () { return chunkYXIEPTFG_cjs.animateText; }
|
|
20
20
|
});
|
|
21
21
|
Object.defineProperty(exports, "audioEnvelope", {
|
|
22
22
|
enumerable: true,
|
|
23
|
-
get: function () { return
|
|
23
|
+
get: function () { return chunkYXIEPTFG_cjs.audioEnvelope; }
|
|
24
24
|
});
|
|
25
25
|
Object.defineProperty(exports, "bpmEnvelope", {
|
|
26
26
|
enumerable: true,
|
|
27
|
-
get: function () { return
|
|
27
|
+
get: function () { return chunkYXIEPTFG_cjs.bpmEnvelope; }
|
|
28
28
|
});
|
|
29
29
|
Object.defineProperty(exports, "cameraPath", {
|
|
30
30
|
enumerable: true,
|
|
31
|
-
get: function () { return
|
|
31
|
+
get: function () { return chunkYXIEPTFG_cjs.cameraPath; }
|
|
32
32
|
});
|
|
33
33
|
Object.defineProperty(exports, "computeEnvelope", {
|
|
34
34
|
enumerable: true,
|
|
35
|
-
get: function () { return
|
|
35
|
+
get: function () { return chunkYXIEPTFG_cjs.computeEnvelope; }
|
|
36
36
|
});
|
|
37
37
|
Object.defineProperty(exports, "dismissLoader", {
|
|
38
38
|
enumerable: true,
|
|
39
|
-
get: function () { return
|
|
39
|
+
get: function () { return chunkYXIEPTFG_cjs.dismissLoader; }
|
|
40
40
|
});
|
|
41
41
|
Object.defineProperty(exports, "ease", {
|
|
42
42
|
enumerable: true,
|
|
43
|
-
get: function () { return
|
|
43
|
+
get: function () { return chunkYXIEPTFG_cjs.parseEase; }
|
|
44
44
|
});
|
|
45
45
|
Object.defineProperty(exports, "failLoader", {
|
|
46
46
|
enumerable: true,
|
|
47
|
-
get: function () { return
|
|
47
|
+
get: function () { return chunkYXIEPTFG_cjs.failLoader; }
|
|
48
48
|
});
|
|
49
49
|
Object.defineProperty(exports, "followPath", {
|
|
50
50
|
enumerable: true,
|
|
51
|
-
get: function () { return
|
|
51
|
+
get: function () { return chunkYXIEPTFG_cjs.followPath; }
|
|
52
52
|
});
|
|
53
53
|
Object.defineProperty(exports, "kenBurns", {
|
|
54
54
|
enumerable: true,
|
|
55
|
-
get: function () { return
|
|
55
|
+
get: function () { return chunkYXIEPTFG_cjs.kenBurns; }
|
|
56
56
|
});
|
|
57
57
|
Object.defineProperty(exports, "measureText", {
|
|
58
58
|
enumerable: true,
|
|
59
|
-
get: function () { return
|
|
59
|
+
get: function () { return chunkYXIEPTFG_cjs.measureText; }
|
|
60
60
|
});
|
|
61
61
|
Object.defineProperty(exports, "musicBuffer", {
|
|
62
62
|
enumerable: true,
|
|
63
|
-
get: function () { return
|
|
63
|
+
get: function () { return chunkYXIEPTFG_cjs.musicBuffer; }
|
|
64
64
|
});
|
|
65
65
|
Object.defineProperty(exports, "musicEnvelope", {
|
|
66
66
|
enumerable: true,
|
|
67
|
-
get: function () { return
|
|
67
|
+
get: function () { return chunkYXIEPTFG_cjs.musicEnvelope; }
|
|
68
68
|
});
|
|
69
69
|
Object.defineProperty(exports, "musicEvents", {
|
|
70
70
|
enumerable: true,
|
|
71
|
-
get: function () { return
|
|
71
|
+
get: function () { return chunkYXIEPTFG_cjs.musicEvents; }
|
|
72
72
|
});
|
|
73
73
|
Object.defineProperty(exports, "orbit", {
|
|
74
74
|
enumerable: true,
|
|
75
|
-
get: function () { return
|
|
75
|
+
get: function () { return chunkYXIEPTFG_cjs.orbit; }
|
|
76
76
|
});
|
|
77
77
|
Object.defineProperty(exports, "particles", {
|
|
78
78
|
enumerable: true,
|
|
79
|
-
get: function () { return
|
|
79
|
+
get: function () { return chunkYXIEPTFG_cjs.particles; }
|
|
80
80
|
});
|
|
81
81
|
Object.defineProperty(exports, "react", {
|
|
82
82
|
enumerable: true,
|
|
83
|
-
get: function () { return
|
|
83
|
+
get: function () { return chunkYXIEPTFG_cjs.react; }
|
|
84
84
|
});
|
|
85
85
|
Object.defineProperty(exports, "resolveLoader", {
|
|
86
86
|
enumerable: true,
|
|
87
|
-
get: function () { return
|
|
87
|
+
get: function () { return chunkYXIEPTFG_cjs.resolveLoader; }
|
|
88
88
|
});
|
|
89
89
|
Object.defineProperty(exports, "samplePath", {
|
|
90
90
|
enumerable: true,
|
|
91
|
-
get: function () { return
|
|
91
|
+
get: function () { return chunkYXIEPTFG_cjs.samplePath; }
|
|
92
92
|
});
|
|
93
93
|
Object.defineProperty(exports, "splitText", {
|
|
94
94
|
enumerable: true,
|
|
95
|
-
get: function () { return
|
|
95
|
+
get: function () { return chunkYXIEPTFG_cjs.splitText; }
|
|
96
96
|
});
|
|
97
97
|
Object.defineProperty(exports, "stagger", {
|
|
98
98
|
enumerable: true,
|
|
99
|
-
get: function () { return
|
|
99
|
+
get: function () { return chunkYXIEPTFG_cjs.stagger; }
|
|
100
100
|
});
|
|
101
101
|
Object.defineProperty(exports, "wiggle", {
|
|
102
102
|
enumerable: true,
|
|
103
|
-
get: function () { return
|
|
103
|
+
get: function () { return chunkYXIEPTFG_cjs.wiggle; }
|
|
104
104
|
});
|
|
105
105
|
Object.defineProperty(exports, "withFade", {
|
|
106
106
|
enumerable: true,
|
|
107
|
-
get: function () { return
|
|
107
|
+
get: function () { return chunkYXIEPTFG_cjs.withFade; }
|
|
108
108
|
});
|
|
109
109
|
Object.defineProperty(exports, "Sequence", {
|
|
110
110
|
enumerable: true,
|
|
111
|
-
get: function () { return
|
|
111
|
+
get: function () { return chunk4NOTVQ3I_cjs.Sequence; }
|
|
112
112
|
});
|
|
113
113
|
Object.defineProperty(exports, "noise", {
|
|
114
114
|
enumerable: true,
|
|
115
|
-
get: function () { return
|
|
115
|
+
get: function () { return chunk4NOTVQ3I_cjs.noise; }
|
|
116
116
|
});
|
|
117
117
|
Object.defineProperty(exports, "noise2", {
|
|
118
118
|
enumerable: true,
|
|
119
|
-
get: function () { return
|
|
119
|
+
get: function () { return chunk4NOTVQ3I_cjs.noise2; }
|
|
120
120
|
});
|
|
121
121
|
Object.defineProperty(exports, "rand", {
|
|
122
122
|
enumerable: true,
|
|
123
|
-
get: function () { return
|
|
123
|
+
get: function () { return chunk4NOTVQ3I_cjs.rand; }
|
|
124
124
|
});
|
|
125
125
|
Object.defineProperty(exports, "random", {
|
|
126
126
|
enumerable: true,
|
|
127
|
-
get: function () { return
|
|
127
|
+
get: function () { return chunk4NOTVQ3I_cjs.random; }
|
|
128
128
|
});
|
|
129
129
|
Object.defineProperty(exports, "registerSequenceType", {
|
|
130
130
|
enumerable: true,
|
|
131
|
-
get: function () { return
|
|
131
|
+
get: function () { return chunk4NOTVQ3I_cjs.registerSequenceType; }
|
|
132
132
|
});
|
|
133
133
|
Object.defineProperty(exports, "inspectSound", {
|
|
134
134
|
enumerable: true,
|
|
135
|
-
get: function () { return
|
|
135
|
+
get: function () { return chunkSMHTOWXG_cjs.inspectSound; }
|
|
136
136
|
});
|
|
137
137
|
Object.defineProperty(exports, "warnUnknownOptions", {
|
|
138
138
|
enumerable: true,
|
package/dist/index.d.cts
CHANGED
|
@@ -449,6 +449,8 @@ interface AnimateTextTween {
|
|
|
449
449
|
ease?: string;
|
|
450
450
|
/** `out` only: the composition second the exit starts at (every piece leaves in the same wave from then on, and holds its exit state until the layer ends). Without it the exit is the end of the layer run backwards. Not for `in` (an entrance starts with its piece: the options' `at`). */
|
|
451
451
|
at?: number;
|
|
452
|
+
/** `out` only: the wave of the exit, when it should not be the entrance's: `0` (all pieces leave at once), or `{ each: 0.1 }` and the other {@link stagger} options. Default: the same wave as the entrance (the options' `stagger`). */
|
|
453
|
+
stagger?: StaggerOptions | 0;
|
|
452
454
|
}
|
|
453
455
|
interface AnimateTextOptions {
|
|
454
456
|
/** What a piece is: a character (default), a word or a line. */
|
package/dist/index.d.ts
CHANGED
|
@@ -449,6 +449,8 @@ interface AnimateTextTween {
|
|
|
449
449
|
ease?: string;
|
|
450
450
|
/** `out` only: the composition second the exit starts at (every piece leaves in the same wave from then on, and holds its exit state until the layer ends). Without it the exit is the end of the layer run backwards. Not for `in` (an entrance starts with its piece: the options' `at`). */
|
|
451
451
|
at?: number;
|
|
452
|
+
/** `out` only: the wave of the exit, when it should not be the entrance's: `0` (all pieces leave at once), or `{ each: 0.1 }` and the other {@link stagger} options. Default: the same wave as the entrance (the options' `stagger`). */
|
|
453
|
+
stagger?: StaggerOptions | 0;
|
|
452
454
|
}
|
|
453
455
|
interface AnimateTextOptions {
|
|
454
456
|
/** What a piece is: a character (default), a word or a line. */
|
package/dist/index.js
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
|
-
export { Movie, animateText, audioEnvelope, bpmEnvelope, cameraPath, computeEnvelope, dismissLoader, parseEase as ease, failLoader, followPath, kenBurns, measureText, musicBuffer, musicEnvelope, musicEvents, orbit, particles, react, resolveLoader, samplePath, splitText, stagger, wiggle, withFade } from './chunk-
|
|
2
|
-
import './chunk-
|
|
3
|
-
export { Sequence, noise, noise2, rand, random, registerSequenceType } from './chunk-
|
|
4
|
-
export { inspectSound } from './chunk-
|
|
5
|
-
import './chunk-
|
|
6
|
-
import './chunk-
|
|
1
|
+
export { Movie, animateText, audioEnvelope, bpmEnvelope, cameraPath, computeEnvelope, dismissLoader, parseEase as ease, failLoader, followPath, kenBurns, measureText, musicBuffer, musicEnvelope, musicEvents, orbit, particles, react, resolveLoader, samplePath, splitText, stagger, wiggle, withFade } from './chunk-OVTTCX2E.js';
|
|
2
|
+
import './chunk-QMVK55LC.js';
|
|
3
|
+
export { Sequence, noise, noise2, rand, random, registerSequenceType } from './chunk-6MHJKCXO.js';
|
|
4
|
+
export { inspectSound } from './chunk-7IDEWQPH.js';
|
|
5
|
+
import './chunk-UTDELFOU.js';
|
|
6
|
+
import './chunk-NVKHUAHU.js';
|
|
7
7
|
export { warnUnknownOptions } from './chunk-BXOCEZ4U.js';
|
|
8
8
|
//# sourceMappingURL=index.js.map
|
|
9
9
|
//# sourceMappingURL=index.js.map
|
package/dist/loader.css
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
/*
|
|
2
2
|
* pixi-effects loader: one line of HTML on the page, a few lines of CSS, no JavaScript of your own.
|
|
3
3
|
*
|
|
4
|
-
* <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/pixi-effects@0.
|
|
4
|
+
* <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/pixi-effects@0.47.1/dist/loader.css">
|
|
5
5
|
* <div class="stage" style="position: relative"> <!-- any box the canvas sits in, with position: relative -->
|
|
6
6
|
* <canvas id="stage" width="1280" height="720"></canvas>
|
|
7
7
|
* <div class="pe-loader" data-label="LOADING"></div> <!-- or class="pe-loader pe-loader--bar" -->
|
package/dist/present.cjs
CHANGED
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
|
-
require('./chunk-
|
|
4
|
-
require('./chunk-
|
|
5
|
-
require('./chunk-
|
|
6
|
-
require('./chunk-
|
|
7
|
-
require('./chunk-
|
|
8
|
-
require('./chunk-
|
|
3
|
+
require('./chunk-YXIEPTFG.cjs');
|
|
4
|
+
require('./chunk-BFERTUXK.cjs');
|
|
5
|
+
require('./chunk-4NOTVQ3I.cjs');
|
|
6
|
+
require('./chunk-SMHTOWXG.cjs');
|
|
7
|
+
require('./chunk-53DXJEO7.cjs');
|
|
8
|
+
require('./chunk-NEMWRJQS.cjs');
|
|
9
9
|
var chunkTWZNOUM7_cjs = require('./chunk-TWZNOUM7.cjs');
|
|
10
10
|
|
|
11
11
|
// src/present/stops.ts
|
package/dist/present.js
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
|
-
import './chunk-
|
|
2
|
-
import './chunk-
|
|
3
|
-
import './chunk-
|
|
4
|
-
import './chunk-
|
|
5
|
-
import './chunk-
|
|
6
|
-
import './chunk-
|
|
1
|
+
import './chunk-OVTTCX2E.js';
|
|
2
|
+
import './chunk-QMVK55LC.js';
|
|
3
|
+
import './chunk-6MHJKCXO.js';
|
|
4
|
+
import './chunk-7IDEWQPH.js';
|
|
5
|
+
import './chunk-UTDELFOU.js';
|
|
6
|
+
import './chunk-NVKHUAHU.js';
|
|
7
7
|
import { warnUnknownOptions } from './chunk-BXOCEZ4U.js';
|
|
8
8
|
|
|
9
9
|
// src/present/stops.ts
|
package/dist/sound.cjs
CHANGED
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
|
-
var
|
|
3
|
+
var chunkSMHTOWXG_cjs = require('./chunk-SMHTOWXG.cjs');
|
|
4
4
|
|
|
5
5
|
|
|
6
6
|
|
|
7
7
|
Object.defineProperty(exports, "inspectSound", {
|
|
8
8
|
enumerable: true,
|
|
9
|
-
get: function () { return
|
|
9
|
+
get: function () { return chunkSMHTOWXG_cjs.inspectSound; }
|
|
10
10
|
});
|
|
11
11
|
//# sourceMappingURL=sound.cjs.map
|
|
12
12
|
//# sourceMappingURL=sound.cjs.map
|
package/dist/sound.js
CHANGED
package/dist/three.cjs
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
|
-
var
|
|
4
|
-
require('./chunk-
|
|
3
|
+
var chunk4NOTVQ3I_cjs = require('./chunk-4NOTVQ3I.cjs');
|
|
4
|
+
require('./chunk-NEMWRJQS.cjs');
|
|
5
5
|
require('./chunk-TWZNOUM7.cjs');
|
|
6
6
|
var pixi_js = require('pixi.js');
|
|
7
7
|
var three$1 = require('three');
|
|
@@ -170,7 +170,7 @@ function releaseThree(kind) {
|
|
|
170
170
|
|
|
171
171
|
// src/three/ThreeSequence.ts
|
|
172
172
|
var NOT_PURE = /\bMath\s*\.\s*random\s*\(|\bDate\s*\.\s*now\s*\(|\bperformance\s*\.\s*now\s*\(|\bnew\s+Date\s*\(/;
|
|
173
|
-
var ThreeSequence = class extends
|
|
173
|
+
var ThreeSequence = class extends chunk4NOTVQ3I_cjs.Sequence {
|
|
174
174
|
_renderer = null;
|
|
175
175
|
/** The renderer this layer draws with (`'webgl'` or `'webgpu'`), once it is built. */
|
|
176
176
|
renderer = null;
|
|
@@ -221,7 +221,7 @@ var ThreeSequence = class extends chunkLALEBV63_cjs.Sequence {
|
|
|
221
221
|
if (typeof spec.update === "function" && NOT_PURE.test(spec.update.toString())) {
|
|
222
222
|
console.warn(`pixi-effects: three layer${spec.name ? ` "${spec.name}"` : ""}: update calls Math.random, Date.now, performance.now or new Date, so it is not deterministic: the same frame would draw differently in playback, in a seek and in an export. Derive the value from t`);
|
|
223
223
|
}
|
|
224
|
-
const scope =
|
|
224
|
+
const scope = chunk4NOTVQ3I_cjs.buildScope(this, this.parent, this.root);
|
|
225
225
|
const width = resolveDim(spec.width, scope) ?? this.parent?.width ?? this.root.width;
|
|
226
226
|
const height = resolveDim(spec.height, scope) ?? this.parent?.height ?? this.root.height;
|
|
227
227
|
const resolution = spec.resolution ?? 1;
|
|
@@ -784,7 +784,7 @@ var ThreeSequence = class extends chunkLALEBV63_cjs.Sequence {
|
|
|
784
784
|
function resolveDim(v, scope) {
|
|
785
785
|
if (v === void 0) return void 0;
|
|
786
786
|
if (typeof v === "number") return v;
|
|
787
|
-
return
|
|
787
|
+
return chunk4NOTVQ3I_cjs.evaluateExpr(v, scope);
|
|
788
788
|
}
|
|
789
789
|
var ids = /* @__PURE__ */ new WeakMap();
|
|
790
790
|
var lastId = 0;
|
|
@@ -1026,7 +1026,7 @@ function registerThree(options = {}) {
|
|
|
1026
1026
|
const kind = options.renderer ?? "webgl";
|
|
1027
1027
|
checkRendererKind(kind, "registerThree's renderer");
|
|
1028
1028
|
setPageRenderer(kind);
|
|
1029
|
-
|
|
1029
|
+
chunk4NOTVQ3I_cjs.registerSequenceType("three", ThreeSequence);
|
|
1030
1030
|
}
|
|
1031
1031
|
function three(spec) {
|
|
1032
1032
|
return spec;
|
package/dist/three.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { Sequence, buildScope, evaluateExpr, registerSequenceType } from './chunk-
|
|
2
|
-
import './chunk-
|
|
1
|
+
import { Sequence, buildScope, evaluateExpr, registerSequenceType } from './chunk-6MHJKCXO.js';
|
|
2
|
+
import './chunk-NVKHUAHU.js';
|
|
3
3
|
import './chunk-BXOCEZ4U.js';
|
|
4
4
|
import { Texture, Sprite, TextureSource, RenderTexture, Matrix } from 'pixi.js';
|
|
5
5
|
import { WebGLRenderer, Scene, PerspectiveCamera, Raycaster, Vector2, Vector3, Quaternion, Plane, Box3, RenderTarget, Group, AnimationMixer, LoopOnce, LoopRepeat, AmbientLight, DirectionalLight, SpotLight, PointLight, Color, SRGBColorSpace, Fog } from 'three';
|
package/docs/api.md
CHANGED
|
@@ -44,7 +44,7 @@ interface MovieOptions {
|
|
|
44
44
|
composition?: CompositionSpec; // root composition (see DSL reference)
|
|
45
45
|
vars?: Record<string, number | string>; // named values the composition reads: a number as a name in an expression, any as {name} in a string (see Variables)
|
|
46
46
|
loop?: boolean; // start with movie.loop on: playing goes back to the start at the end (default false, like a <video>)
|
|
47
|
-
loudness?: number | false; // the whole mix at this many LUFS (-16 is usual for web video): one gain, up or down, the
|
|
47
|
+
loudness?: number | false; // the whole mix at this many LUFS (-16 is usual for web video): one gain, up or down, and a look-ahead limiter keeping the true peak at -1 dBTP or under (a click over a quiet bed is pulled down; more than 10 dB of limiting is out of reach and `check` names it); false / left out: the mix as the layers make it (check says when it is quiet)
|
|
48
48
|
poster?: number; // seconds: the frame shown before play (negative: from the end), see movie.poster
|
|
49
49
|
motionBlur?: boolean | number | { samples?: number; shutter?: number }; // blur for render() / snapshot() / contactSheet(), not live playback; see Motion blur
|
|
50
50
|
loader?: HTMLElement | string | false; // the page's loader (see pixi-effects/loader.css): shows how far init is (a bar, "BUILDING LAYERS 62%"), faded out when ready, stopped if init fails; default: a .pe-loader next to the canvas
|
package/docs/dsl.md
CHANGED
|
@@ -224,7 +224,7 @@ Audio-only sequence. No visual. Volume is animatable via keyframes.
|
|
|
224
224
|
|
|
225
225
|
Audio is mixed during `Movie.init()` and during `Movie.render()`. Volume keyframes interpolate linearly.
|
|
226
226
|
|
|
227
|
-
**The loudness of the whole mix: `movie.init({ loudness: -16 })`.** Layers make whatever level their `volume` gives (a few `sfx` at volume 0.15 mix to about -40 LUFS, far quieter than web video's -14 to -16). `loudness` is a target for the finished mix in LUFS (ITU-R BS.1770): one gain, up or down,
|
|
227
|
+
**The loudness of the whole mix: `movie.init({ loudness: -16 })`.** Layers make whatever level their `volume` gives (a few `sfx` at volume 0.15 mix to about -40 LUFS, far quieter than web video's -14 to -16). `loudness` is a target for the finished mix in LUFS (ITU-R BS.1770): one gain, up or down, and a look-ahead limiter that takes a click or a hit on top of a quiet bed down so that no peak passes -1 dBTP (true peak), the same for playback and export. A mix whose peaks are within 10 dB of what the limiter can take reaches the target (`check` says where the limiter worked hardest and which sounds play there when it took 3 dB or more off); a click 30 dB over its bed is out of reach and stops short (`reached -19.4 LUFS`), and `check` / `inspectAudio()` name the moment and the sounds that make it, with the fix (lower that sound, or ask for less). **Raising a `sfx` over music is safe:** the limiter keeps the peak, so give an accent the volume the `buried` note suggests (an accent over music needs 2 to 3). `false` or no option leaves the mix as the layers make it; `check` then says when it is quiet (found in a trial of nine films with sound: eight were -22 to -26 LUFS and only one was raised).
|
|
228
228
|
|
|
229
229
|
#### Sound effects without files: `sfx`
|
|
230
230
|
|
|
@@ -867,7 +867,7 @@ three({ type: 'three', width: 'GW', height: 'GH',
|
|
|
867
867
|
|
|
868
868
|
- **The rules.** The layer must be a `composition` with a `width` and `height`, in the same composition as the three layer and **listed before it** (a layer built later cannot be found: the error lists the names that are there). `await` the call in `setup`. `resolution` (default 1) is the pixels of the texture per pixel of the layer: 2 for a screen that is seen large. `transparent: true` lets what is behind the mesh show through the empty and half-transparent parts of the composition (a sticker, a label with rounded corners; the material blends and does not write depth); default `false`, an opaque screen. The layer's own place, scale and rotation do not matter: its content is drawn from (0, 0) to (width, height); its alpha and filters do.
|
|
869
869
|
- **The material.** `screen.material` is unlit (a screen shines by itself; scene lights do not shade it) and carries the colour decoding; put it on a mesh, or on one face of a box (`[dark, dark, dark, dark, screen.material, dark]`). Use `screen.texture` yourself and its colours may be wrong. Without `transparent`, give the composition a background rect: what it leaves empty is black on the mesh.
|
|
870
|
-
- **Two routes, the same colours** (measured: the background, a moving dot and a growing bar equal the 2D layer, channel for channel, on both). When the three layer draws on PixiJS's own GPU device (
|
|
870
|
+
- **Two routes, the same colours** (measured: the background, a moving dot and a growing bar equal the 2D layer, channel for channel, on both). When the three layer has `renderer: 'webgpu'` and draws on PixiJS's own GPU device (a WebGPU movie) the texture is PixiJS's own GPU texture used through three's `ExternalTexture`: no copy, 0.3 ms a frame, and the page's import map needs `"three/webgpu"` and `"three/tsl"` next to `"three"` (the template's has only `"three"` and `"three/addons/"`: add the two lines for this route). Otherwise (the layer has the default `renderer: 'webgl'`, a canvas of its own with `shareGpu: false`, or PixiJS on WebGL) the pixels are read back into a canvas: 1.6 ms a frame at 480 x 270, 4 ms at 1280 x 720, and no import-map entry beyond the template's.
|
|
871
871
|
- **A function of the time.** The 2D layer is drawn when the three layer draws, after the timeline has put every layer at the frame: a seek, an export and a repeat give the same picture (`check` draws the layer twice, in two orders, as for any three layer). A layer that has not started yet, or has ended, shows nothing on the mesh.
|
|
872
872
|
- **A rebuild** (`setVars`, `resize`) keeps the three layer and shows the layer of the new tree (the text that changed shows on the mesh); a layer that changed size is drawn stretched to the texture.
|
|
873
873
|
- **Seen small or at a slant** the texture is filtered, not aliased (1-pixel stripes on a plane a quarter of the picture come out as one even grey, not black and white stripes; four taps along a slant). The mip levels are PixiJS's own on the shared GPU, averaged in the stored sRGB values, so very fine bright detail seen very small is a little darker there than on a read-back canvas, whose mipmaps three makes in linear light (stripes average to 128 and 188).
|
package/llms-full.txt
CHANGED
|
@@ -6,7 +6,7 @@ Concatenation of the skill, cheatsheet, pitfalls, recipes and the DSL / API / me
|
|
|
6
6
|
|
|
7
7
|
<!-- ===== skills/pixi-effects/SKILL.md ===== -->
|
|
8
8
|
|
|
9
|
-
> Written for pixi-effects 0.
|
|
9
|
+
> Written for pixi-effects 0.47.1. Update this skill with `npx skills update`; the newest docs are at https://yjmtmtk.github.io/pixi-effects/
|
|
10
10
|
|
|
11
11
|
# pixi-effects — write a video as data
|
|
12
12
|
|
|
@@ -53,6 +53,7 @@ The same command checks a file you MADE before it goes somewhere with rules (a s
|
|
|
53
53
|
|
|
54
54
|
- **Keyframe `at` starts at 0 when the layer appears** (negative = back from the layer's end). A layer's own `at` and a transition's `at` are composition time.
|
|
55
55
|
- **Layers are hidden, not removed, after their lifespan; z-order is array order.** Switch scenes by stacking layers with `at`/`duration` over an opaque background rect.
|
|
56
|
+
- **Shell traps** (8 trial agents lost a command to these): zsh runs `echo ====` as a command (quote it, or leave the separator out); macOS `sed -i` needs an empty suffix, `sed -i '' …`.
|
|
56
57
|
- **Angles are degrees. `+z` is toward the viewer. Numbers can be expressions** (`'GW/2 - w/2'`; no `pi`; no per-frame variable).
|
|
57
58
|
- **Anchors**: rect/circle/ellipse are centred on `x,y`; text and image are top-left (use `anchorX/anchorY: 0.5`); compositions use `pivotX/pivotY`. A bar that grows from its base needs `anchorY: 1`.
|
|
58
59
|
- **Sound effects need no files:** `{ type: 'audio', sfx: 'swoosh', at: 2 }` — presets `click pop swoosh swipe hit riser chime beep coin glitch typewriter`; knobs `pitch`, `brightness`, `seed`. The layer lasts as long as the sound (`duration` stretches it); a `riser` is loudest at its end (`at = hit − duration`), a `swoosh` 0.16 s in. A music file shorter than its layer goes silent — `loop: true`.
|
|
@@ -169,7 +170,7 @@ blendMode: 'normal' | 'add' | 'screen' | 'multiply' | 'overlay' | 'soft-light' |
|
|
|
169
170
|
|
|
170
171
|
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>'`. **These go in `initial` / keyframes, never at the top level of a shape or text layer** (top-level `x`, `rotation`, `strokeColor`, `fillAlpha` each warn "is not a … key"): the top level of a shape holds its geometry (`width height radius d startAngle endAngle cornerRadius anchorX anchorY`), `trimStart` / `trimEnd`, `strokeCap` / `strokeJoin`, `fillGradient`.
|
|
171
172
|
|
|
172
|
-
Keyframe kinds: `set` (jump at `at`; undone when you seek back), `to` (animate to), `from` (animate from), `from`+`to`; a value may be relative to where the layer stands (`from: { x: '-=36' }` slides in from 36 px to the left of its place). `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` = an ease name (`'none'`, `'power2.out'`, `'expo.out'`, `'back.out(1.7)'`, `'elastic.out(1,0.5)'`, `'sine.inOut'`, `'bounce.out'`, **`'cubic-bezier(.4, 0, .2, 1)'`** (CSS syntax, x1 and x2 in 0…1; `.4, 0, .2, 1` is a gentle in-out; `.2, .8, .2, 1` is FRONT-LOADED, not slow motion: half of the change in the first 13 % of the time, 90 % by 39 %, 99 % by 74 %, then a long settle, so what sits at the END of the content gets the glide; `.2, .8, .5, 1` has a shorter tail). `power1…4` are the powers 2…5: `power2` is a cubic, `power2.in` has done only 12.5 % at half time (42 % at three quarters)… and springs: `'spring(mass, stiffness, damping)'` or `'spring.gentle' | 'snappy' | 'bouncy' | 'wobbly' | 'slow'`; **`duration: 'auto'` = the time the spring takes to settle** (presets, settle time / highest value reached as a multiple of the target: `snappy` 0.42 s / 1.01, `gentle` 0.72 s / 1.02, `bouncy` 1.08 s / 1.28, `slow` 1.29 s / 1.00, `wobbly` 1.61 s / 1.40: time the next beat from these) (real physics; with a number `duration` is the settle time and only the damping ratio shapes it; a damping ratio of 1 or more never overshoots, so `spring(1,170,26)` does not bounce: use damping below 20 at stiffness 170; `'auto'` works on keyframes only, not in `animateText` / `orbit` tweens; a `stagger` ease may be a spring, its delays are held inside the spread). Default ease is linear.
|
|
173
|
+
Keyframe kinds: `set` (jump at `at`; undone when you seek back), `to` (animate to), `from` (animate from), `from`+`to`; a value may be relative to where the layer stands (`from: { x: '-=36' }` slides in from 36 px to the left of its place). `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: `repeat: -1` (the GSAP habit) is refused with a warning, write a count that covers the layer, `repeat: 40`; a `from` keyframe with a later `at` puts its start value on the layer from frame 0, the layer does not wait for the `at`). `ease` = an ease name (`'none'`, `'power2.out'`, `'expo.out'`, `'back.out(1.7)'`, `'elastic.out(1,0.5)'`, `'sine.inOut'`, `'bounce.out'`, **`'cubic-bezier(.4, 0, .2, 1)'`** (CSS syntax, x1 and x2 in 0…1; `.4, 0, .2, 1` is a gentle in-out; `.2, .8, .2, 1` is FRONT-LOADED, not slow motion: half of the change in the first 13 % of the time, 90 % by 39 %, 99 % by 74 %, then a long settle, so what sits at the END of the content gets the glide; `.2, .8, .5, 1` has a shorter tail). `power1…4` are the powers 2…5: `power2` is a cubic, `power2.in` has done only 12.5 % at half time (42 % at three quarters)… and springs: `'spring(mass, stiffness, damping)'` or `'spring.gentle' | 'snappy' | 'bouncy' | 'wobbly' | 'slow'`; **`duration: 'auto'` = the time the spring takes to settle** (presets, settle time / highest value reached as a multiple of the target: `snappy` 0.42 s / 1.01, `gentle` 0.72 s / 1.02, `bouncy` 1.08 s / 1.28, `slow` 1.29 s / 1.00, `wobbly` 1.61 s / 1.40: time the next beat from these) (real physics; with a number `duration` is the settle time and only the damping ratio shapes it; a damping ratio of 1 or more never overshoots, so `spring(1,170,26)` does not bounce: use damping below 20 at stiffness 170; `'auto'` works on keyframes only, not in `animateText` / `orbit` tweens; a `stagger` ease may be a spring, its delays are held inside the spread). Default ease is linear.
|
|
173
174
|
|
|
174
175
|
## Layer types
|
|
175
176
|
|
|
@@ -280,7 +281,7 @@ measureText('Hello', style) // → { width, height,
|
|
|
280
281
|
splitText('Hello world', style, { by: 'chars' | 'words' | 'lines', x, y, align: 'left' | 'center' | 'right' })
|
|
281
282
|
// → [{ text, x, y, width, index, line }] — one text layer per piece, same style, anchor top-left
|
|
282
283
|
```
|
|
283
|
-
Per-letter / per-word / per-line animation in one call: `...animateText(text, style, { x, y, align, vertical: true /* tategaki: down a column, new line = new column to the left, x = RIGHT edge of the first column; 、。 ー 「」 placed and turned for you */, by: 'chars'|'words'|'lines', at, duration /* required: until the last piece is gone */, in: 'rise'|'drop'|'fade'|'pop'|'zoom'|'slide'|'spin'|{ from, to, duration, ease }|false, out: <same, in the same wave (leave `out` out and the pieces stay until the layer ends); by default BACKWARDS FROM THE LAYER'S END (at + duration, so to be gone at time T set duration = T − at); `out: { preset: 'fade', at: 6 }` starts the exit at composition second 6 instead
|
|
284
|
+
Per-letter / per-word / per-line animation in one call: `...animateText(text, style, { x, y, align, vertical: true /* tategaki: down a column, new line = new column to the left, x = RIGHT edge of the first column; 、。 ー 「」 placed and turned for you */, by: 'chars'|'words'|'lines', at, duration /* required: until the last piece is gone */, in: 'rise'|'drop'|'fade'|'pop'|'zoom'|'slide'|'spin'|{ from, to, duration, ease }|false, out: <same, in the same wave (leave `out` out and the pieces stay until the layer ends); by default BACKWARDS FROM THE LAYER'S END (at + duration, so to be gone at time T set duration = T − at); `out: { preset: 'fade', at: 6 }` starts the exit at composition second 6 instead; `out: { preset: 'fade', at: 6, stagger: 0 }` makes everything leave AT ONCE after it came in letter by letter (or `stagger: { each: 0.1 }`: its own wave); an exit is described by `from` = the state the piece leaves TO: `out: { from: { y: 18, alpha: 0 } }`; no exit: omit `out`, or `out: false` / `'none'`>, stagger: { each, from, … }, idle: { y: 4, rotation: 1 }, styleFor: p => ({ fill }) })` → text layers `<name>-0…` (anchor centre; `x`/`y` in `from` are offsets) to spread into `sequences`. **`x` / `y` are pixel NUMBERS (an expression like `'GW/2'` throws: compute `W / 2`), and `y` is the TOP of the line box**: the visible text is centred `lineHeight / 2` below it, so an underline goes at `y + lineHeight`, not at `y` (recipe `animate-text`). By hand: `splitText(...)` + one layer per piece (recipe `split-text`). A web font must be loaded before measuring.
|
|
284
285
|
|
|
285
286
|
## Assets
|
|
286
287
|
|
|
@@ -1858,7 +1859,7 @@ A moving, shadow-casting model is held to "a function of the time" by `check`: p
|
|
|
1858
1859
|
|
|
1859
1860
|
## An app or video on a phone, a television, a billboard (`threeLayerTexture`)
|
|
1860
1861
|
|
|
1861
|
-
A 2D composition is the screen; a `three` layer holds the object it is on. The composition keeps animating (its own keyframes, text, charts, a counter) and the mesh shows it live, turning with the object. Put the composition BEFORE the three layer, give it a background rect, and `await threeLayerTexture(ctx, 'screen')` in `setup`: `screen.material` goes on the face of the mesh. The
|
|
1862
|
+
A 2D composition is the screen; a `three` layer holds the object it is on. The composition keeps animating (its own keyframes, text, charts, a counter) and the mesh shows it live, turning with the object. Put the composition BEFORE the three layer, give it a background rect, and `await threeLayerTexture(ctx, 'screen')` in `setup`: `screen.material` goes on the face of the mesh. The three layer as written here (the default `renderer`, WebGL) needs nothing beyond the template's import map: the screen's pixels are read back each frame. Only a layer with `renderer: 'webgpu'` (the no-copy route) also needs `"three/webgpu"` and `"three/tsl"` next to `"three"`.
|
|
1862
1863
|
|
|
1863
1864
|
```js
|
|
1864
1865
|
// @docs-only three-screen
|
|
@@ -2533,7 +2534,7 @@ Audio-only sequence. No visual. Volume is animatable via keyframes.
|
|
|
2533
2534
|
|
|
2534
2535
|
Audio is mixed during `Movie.init()` and during `Movie.render()`. Volume keyframes interpolate linearly.
|
|
2535
2536
|
|
|
2536
|
-
**The loudness of the whole mix: `movie.init({ loudness: -16 })`.** Layers make whatever level their `volume` gives (a few `sfx` at volume 0.15 mix to about -40 LUFS, far quieter than web video's -14 to -16). `loudness` is a target for the finished mix in LUFS (ITU-R BS.1770): one gain, up or down,
|
|
2537
|
+
**The loudness of the whole mix: `movie.init({ loudness: -16 })`.** Layers make whatever level their `volume` gives (a few `sfx` at volume 0.15 mix to about -40 LUFS, far quieter than web video's -14 to -16). `loudness` is a target for the finished mix in LUFS (ITU-R BS.1770): one gain, up or down, and a look-ahead limiter that takes a click or a hit on top of a quiet bed down so that no peak passes -1 dBTP (true peak), the same for playback and export. A mix whose peaks are within 10 dB of what the limiter can take reaches the target (`check` says where the limiter worked hardest and which sounds play there when it took 3 dB or more off); a click 30 dB over its bed is out of reach and stops short (`reached -19.4 LUFS`), and `check` / `inspectAudio()` name the moment and the sounds that make it, with the fix (lower that sound, or ask for less). **Raising a `sfx` over music is safe:** the limiter keeps the peak, so give an accent the volume the `buried` note suggests (an accent over music needs 2 to 3). `false` or no option leaves the mix as the layers make it; `check` then says when it is quiet (found in a trial of nine films with sound: eight were -22 to -26 LUFS and only one was raised).
|
|
2537
2538
|
|
|
2538
2539
|
#### Sound effects without files: `sfx`
|
|
2539
2540
|
|
|
@@ -3176,7 +3177,7 @@ three({ type: 'three', width: 'GW', height: 'GH',
|
|
|
3176
3177
|
|
|
3177
3178
|
- **The rules.** The layer must be a `composition` with a `width` and `height`, in the same composition as the three layer and **listed before it** (a layer built later cannot be found: the error lists the names that are there). `await` the call in `setup`. `resolution` (default 1) is the pixels of the texture per pixel of the layer: 2 for a screen that is seen large. `transparent: true` lets what is behind the mesh show through the empty and half-transparent parts of the composition (a sticker, a label with rounded corners; the material blends and does not write depth); default `false`, an opaque screen. The layer's own place, scale and rotation do not matter: its content is drawn from (0, 0) to (width, height); its alpha and filters do.
|
|
3178
3179
|
- **The material.** `screen.material` is unlit (a screen shines by itself; scene lights do not shade it) and carries the colour decoding; put it on a mesh, or on one face of a box (`[dark, dark, dark, dark, screen.material, dark]`). Use `screen.texture` yourself and its colours may be wrong. Without `transparent`, give the composition a background rect: what it leaves empty is black on the mesh.
|
|
3179
|
-
- **Two routes, the same colours** (measured: the background, a moving dot and a growing bar equal the 2D layer, channel for channel, on both). When the three layer draws on PixiJS's own GPU device (
|
|
3180
|
+
- **Two routes, the same colours** (measured: the background, a moving dot and a growing bar equal the 2D layer, channel for channel, on both). When the three layer has `renderer: 'webgpu'` and draws on PixiJS's own GPU device (a WebGPU movie) the texture is PixiJS's own GPU texture used through three's `ExternalTexture`: no copy, 0.3 ms a frame, and the page's import map needs `"three/webgpu"` and `"three/tsl"` next to `"three"` (the template's has only `"three"` and `"three/addons/"`: add the two lines for this route). Otherwise (the layer has the default `renderer: 'webgl'`, a canvas of its own with `shareGpu: false`, or PixiJS on WebGL) the pixels are read back into a canvas: 1.6 ms a frame at 480 x 270, 4 ms at 1280 x 720, and no import-map entry beyond the template's.
|
|
3180
3181
|
- **A function of the time.** The 2D layer is drawn when the three layer draws, after the timeline has put every layer at the frame: a seek, an export and a repeat give the same picture (`check` draws the layer twice, in two orders, as for any three layer). A layer that has not started yet, or has ended, shows nothing on the mesh.
|
|
3181
3182
|
- **A rebuild** (`setVars`, `resize`) keeps the three layer and shows the layer of the new tree (the text that changed shows on the mesh); a layer that changed size is drawn stretched to the texture.
|
|
3182
3183
|
- **Seen small or at a slant** the texture is filtered, not aliased (1-pixel stripes on a plane a quarter of the picture come out as one even grey, not black and white stripes; four taps along a slant). The mip levels are PixiJS's own on the shared GPU, averaged in the stored sRGB values, so very fine bright detail seen very small is a little darker there than on a read-back canvas, whose mipmaps three makes in linear light (stripes average to 128 and 188).
|
|
@@ -4211,7 +4212,7 @@ interface MovieOptions {
|
|
|
4211
4212
|
composition?: CompositionSpec; // root composition (see DSL reference)
|
|
4212
4213
|
vars?: Record<string, number | string>; // named values the composition reads: a number as a name in an expression, any as {name} in a string (see Variables)
|
|
4213
4214
|
loop?: boolean; // start with movie.loop on: playing goes back to the start at the end (default false, like a <video>)
|
|
4214
|
-
loudness?: number | false; // the whole mix at this many LUFS (-16 is usual for web video): one gain, up or down, the
|
|
4215
|
+
loudness?: number | false; // the whole mix at this many LUFS (-16 is usual for web video): one gain, up or down, and a look-ahead limiter keeping the true peak at -1 dBTP or under (a click over a quiet bed is pulled down; more than 10 dB of limiting is out of reach and `check` names it); false / left out: the mix as the layers make it (check says when it is quiet)
|
|
4215
4216
|
poster?: number; // seconds: the frame shown before play (negative: from the end), see movie.poster
|
|
4216
4217
|
motionBlur?: boolean | number | { samples?: number; shutter?: number }; // blur for render() / snapshot() / contactSheet(), not live playback; see Motion blur
|
|
4217
4218
|
loader?: HTMLElement | string | false; // the page's loader (see pixi-effects/loader.css): shows how far init is (a bar, "BUILDING LAYERS 62%"), faded out when ready, stopped if init fails; default: a .pe-loader next to the canvas
|
package/package.json
CHANGED
|
@@ -3,7 +3,7 @@ name: pixi-effects
|
|
|
3
3
|
description: Use when asked to make, animate, preview or export a video, motion graphics, an animated title, a lower third, kinetic type, a promo, a slideshow with transitions, an animated chart or data story, a social clip, a 2.5D / depth scene, or music and sound for a video, written as code in JavaScript or HTML. pixi-effects is a JS library where a video is a plain-object composition (text, shape, image, video, audio and file-free sfx / music, camera, light and shader layers with keyframes) that plays in the browser, is checked by a tool the agent can run, and exports MP4 / WebM / MOV with no server. Not for a project that already uses another video tool (Remotion, Motion Canvas, ffmpeg); follow that tool instead.
|
|
4
4
|
---
|
|
5
5
|
|
|
6
|
-
> Written for pixi-effects 0.
|
|
6
|
+
> Written for pixi-effects 0.47.1. Update this skill with `npx skills update`; the newest docs are at https://yjmtmtk.github.io/pixi-effects/
|
|
7
7
|
|
|
8
8
|
# pixi-effects — write a video as data
|
|
9
9
|
|
|
@@ -50,6 +50,7 @@ The same command checks a file you MADE before it goes somewhere with rules (a s
|
|
|
50
50
|
|
|
51
51
|
- **Keyframe `at` starts at 0 when the layer appears** (negative = back from the layer's end). A layer's own `at` and a transition's `at` are composition time.
|
|
52
52
|
- **Layers are hidden, not removed, after their lifespan; z-order is array order.** Switch scenes by stacking layers with `at`/`duration` over an opaque background rect.
|
|
53
|
+
- **Shell traps** (8 trial agents lost a command to these): zsh runs `echo ====` as a command (quote it, or leave the separator out); macOS `sed -i` needs an empty suffix, `sed -i '' …`.
|
|
53
54
|
- **Angles are degrees. `+z` is toward the viewer. Numbers can be expressions** (`'GW/2 - w/2'`; no `pi`; no per-frame variable).
|
|
54
55
|
- **Anchors**: rect/circle/ellipse are centred on `x,y`; text and image are top-left (use `anchorX/anchorY: 0.5`); compositions use `pivotX/pivotY`. A bar that grows from its base needs `anchorY: 1`.
|
|
55
56
|
- **Sound effects need no files:** `{ type: 'audio', sfx: 'swoosh', at: 2 }` — presets `click pop swoosh swipe hit riser chime beep coin glitch typewriter`; knobs `pitch`, `brightness`, `seed`. The layer lasts as long as the sound (`duration` stretches it); a `riser` is loudest at its end (`at = hit − duration`), a `swoosh` 0.16 s in. A music file shorter than its layer goes silent — `loop: true`.
|
|
@@ -47,7 +47,7 @@ blendMode: 'normal' | 'add' | 'screen' | 'multiply' | 'overlay' | 'soft-light' |
|
|
|
47
47
|
|
|
48
48
|
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>'`. **These go in `initial` / keyframes, never at the top level of a shape or text layer** (top-level `x`, `rotation`, `strokeColor`, `fillAlpha` each warn "is not a … key"): the top level of a shape holds its geometry (`width height radius d startAngle endAngle cornerRadius anchorX anchorY`), `trimStart` / `trimEnd`, `strokeCap` / `strokeJoin`, `fillGradient`.
|
|
49
49
|
|
|
50
|
-
Keyframe kinds: `set` (jump at `at`; undone when you seek back), `to` (animate to), `from` (animate from), `from`+`to`; a value may be relative to where the layer stands (`from: { x: '-=36' }` slides in from 36 px to the left of its place). `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` = an ease name (`'none'`, `'power2.out'`, `'expo.out'`, `'back.out(1.7)'`, `'elastic.out(1,0.5)'`, `'sine.inOut'`, `'bounce.out'`, **`'cubic-bezier(.4, 0, .2, 1)'`** (CSS syntax, x1 and x2 in 0…1; `.4, 0, .2, 1` is a gentle in-out; `.2, .8, .2, 1` is FRONT-LOADED, not slow motion: half of the change in the first 13 % of the time, 90 % by 39 %, 99 % by 74 %, then a long settle, so what sits at the END of the content gets the glide; `.2, .8, .5, 1` has a shorter tail). `power1…4` are the powers 2…5: `power2` is a cubic, `power2.in` has done only 12.5 % at half time (42 % at three quarters)… and springs: `'spring(mass, stiffness, damping)'` or `'spring.gentle' | 'snappy' | 'bouncy' | 'wobbly' | 'slow'`; **`duration: 'auto'` = the time the spring takes to settle** (presets, settle time / highest value reached as a multiple of the target: `snappy` 0.42 s / 1.01, `gentle` 0.72 s / 1.02, `bouncy` 1.08 s / 1.28, `slow` 1.29 s / 1.00, `wobbly` 1.61 s / 1.40: time the next beat from these) (real physics; with a number `duration` is the settle time and only the damping ratio shapes it; a damping ratio of 1 or more never overshoots, so `spring(1,170,26)` does not bounce: use damping below 20 at stiffness 170; `'auto'` works on keyframes only, not in `animateText` / `orbit` tweens; a `stagger` ease may be a spring, its delays are held inside the spread). Default ease is linear.
|
|
50
|
+
Keyframe kinds: `set` (jump at `at`; undone when you seek back), `to` (animate to), `from` (animate from), `from`+`to`; a value may be relative to where the layer stands (`from: { x: '-=36' }` slides in from 36 px to the left of its place). `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: `repeat: -1` (the GSAP habit) is refused with a warning, write a count that covers the layer, `repeat: 40`; a `from` keyframe with a later `at` puts its start value on the layer from frame 0, the layer does not wait for the `at`). `ease` = an ease name (`'none'`, `'power2.out'`, `'expo.out'`, `'back.out(1.7)'`, `'elastic.out(1,0.5)'`, `'sine.inOut'`, `'bounce.out'`, **`'cubic-bezier(.4, 0, .2, 1)'`** (CSS syntax, x1 and x2 in 0…1; `.4, 0, .2, 1` is a gentle in-out; `.2, .8, .2, 1` is FRONT-LOADED, not slow motion: half of the change in the first 13 % of the time, 90 % by 39 %, 99 % by 74 %, then a long settle, so what sits at the END of the content gets the glide; `.2, .8, .5, 1` has a shorter tail). `power1…4` are the powers 2…5: `power2` is a cubic, `power2.in` has done only 12.5 % at half time (42 % at three quarters)… and springs: `'spring(mass, stiffness, damping)'` or `'spring.gentle' | 'snappy' | 'bouncy' | 'wobbly' | 'slow'`; **`duration: 'auto'` = the time the spring takes to settle** (presets, settle time / highest value reached as a multiple of the target: `snappy` 0.42 s / 1.01, `gentle` 0.72 s / 1.02, `bouncy` 1.08 s / 1.28, `slow` 1.29 s / 1.00, `wobbly` 1.61 s / 1.40: time the next beat from these) (real physics; with a number `duration` is the settle time and only the damping ratio shapes it; a damping ratio of 1 or more never overshoots, so `spring(1,170,26)` does not bounce: use damping below 20 at stiffness 170; `'auto'` works on keyframes only, not in `animateText` / `orbit` tweens; a `stagger` ease may be a spring, its delays are held inside the spread). Default ease is linear.
|
|
51
51
|
|
|
52
52
|
## Layer types
|
|
53
53
|
|
|
@@ -158,7 +158,7 @@ measureText('Hello', style) // → { width, height,
|
|
|
158
158
|
splitText('Hello world', style, { by: 'chars' | 'words' | 'lines', x, y, align: 'left' | 'center' | 'right' })
|
|
159
159
|
// → [{ text, x, y, width, index, line }] — one text layer per piece, same style, anchor top-left
|
|
160
160
|
```
|
|
161
|
-
Per-letter / per-word / per-line animation in one call: `...animateText(text, style, { x, y, align, vertical: true /* tategaki: down a column, new line = new column to the left, x = RIGHT edge of the first column; 、。 ー 「」 placed and turned for you */, by: 'chars'|'words'|'lines', at, duration /* required: until the last piece is gone */, in: 'rise'|'drop'|'fade'|'pop'|'zoom'|'slide'|'spin'|{ from, to, duration, ease }|false, out: <same, in the same wave (leave `out` out and the pieces stay until the layer ends); by default BACKWARDS FROM THE LAYER'S END (at + duration, so to be gone at time T set duration = T − at); `out: { preset: 'fade', at: 6 }` starts the exit at composition second 6 instead
|
|
161
|
+
Per-letter / per-word / per-line animation in one call: `...animateText(text, style, { x, y, align, vertical: true /* tategaki: down a column, new line = new column to the left, x = RIGHT edge of the first column; 、。 ー 「」 placed and turned for you */, by: 'chars'|'words'|'lines', at, duration /* required: until the last piece is gone */, in: 'rise'|'drop'|'fade'|'pop'|'zoom'|'slide'|'spin'|{ from, to, duration, ease }|false, out: <same, in the same wave (leave `out` out and the pieces stay until the layer ends); by default BACKWARDS FROM THE LAYER'S END (at + duration, so to be gone at time T set duration = T − at); `out: { preset: 'fade', at: 6 }` starts the exit at composition second 6 instead; `out: { preset: 'fade', at: 6, stagger: 0 }` makes everything leave AT ONCE after it came in letter by letter (or `stagger: { each: 0.1 }`: its own wave); an exit is described by `from` = the state the piece leaves TO: `out: { from: { y: 18, alpha: 0 } }`; no exit: omit `out`, or `out: false` / `'none'`>, stagger: { each, from, … }, idle: { y: 4, rotation: 1 }, styleFor: p => ({ fill }) })` → text layers `<name>-0…` (anchor centre; `x`/`y` in `from` are offsets) to spread into `sequences`. **`x` / `y` are pixel NUMBERS (an expression like `'GW/2'` throws: compute `W / 2`), and `y` is the TOP of the line box**: the visible text is centred `lineHeight / 2` below it, so an underline goes at `y + lineHeight`, not at `y` (recipe `animate-text`). By hand: `splitText(...)` + one layer per piece (recipe `split-text`). A web font must be loaded before measuring.
|
|
162
162
|
|
|
163
163
|
## Assets
|
|
164
164
|
|
|
@@ -1388,7 +1388,7 @@ A moving, shadow-casting model is held to "a function of the time" by `check`: p
|
|
|
1388
1388
|
|
|
1389
1389
|
## An app or video on a phone, a television, a billboard (`threeLayerTexture`)
|
|
1390
1390
|
|
|
1391
|
-
A 2D composition is the screen; a `three` layer holds the object it is on. The composition keeps animating (its own keyframes, text, charts, a counter) and the mesh shows it live, turning with the object. Put the composition BEFORE the three layer, give it a background rect, and `await threeLayerTexture(ctx, 'screen')` in `setup`: `screen.material` goes on the face of the mesh. The
|
|
1391
|
+
A 2D composition is the screen; a `three` layer holds the object it is on. The composition keeps animating (its own keyframes, text, charts, a counter) and the mesh shows it live, turning with the object. Put the composition BEFORE the three layer, give it a background rect, and `await threeLayerTexture(ctx, 'screen')` in `setup`: `screen.material` goes on the face of the mesh. The three layer as written here (the default `renderer`, WebGL) needs nothing beyond the template's import map: the screen's pixels are read back each frame. Only a layer with `renderer: 'webgpu'` (the no-copy route) also needs `"three/webgpu"` and `"three/tsl"` next to `"three"`.
|
|
1392
1392
|
|
|
1393
1393
|
```js
|
|
1394
1394
|
// @docs-only three-screen
|
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
<meta charset="UTF-8" />
|
|
5
5
|
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
|
6
6
|
<title>pixi-effects video</title>
|
|
7
|
-
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/pixi-effects@0.
|
|
7
|
+
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/pixi-effects@0.47.1/dist/loader.css" /> <!-- the loader: HTML + CSS only, so it is on screen at once and keeps moving while the page builds the video -->
|
|
8
8
|
<style>
|
|
9
9
|
body { background: #0d1220; margin: 0; padding: 16px; }
|
|
10
10
|
.stage { position: relative; width: min(960px, 100%); } /* the player and the loader both sit inside this box */
|
|
@@ -37,17 +37,17 @@
|
|
|
37
37
|
"imports": {
|
|
38
38
|
"pixi.js": "https://esm.sh/pixi.js@8.22.0?bundle-deps",
|
|
39
39
|
"mediabunny": "https://esm.sh/mediabunny",
|
|
40
|
-
"pixi-effects": "https://cdn.jsdelivr.net/npm/pixi-effects@0.
|
|
41
|
-
"pixi-effects/controller": "https://cdn.jsdelivr.net/npm/pixi-effects@0.
|
|
42
|
-
"pixi-effects/present": "https://cdn.jsdelivr.net/npm/pixi-effects@0.
|
|
43
|
-
"pixi-effects/three": "https://cdn.jsdelivr.net/npm/pixi-effects@0.
|
|
40
|
+
"pixi-effects": "https://cdn.jsdelivr.net/npm/pixi-effects@0.47.1/dist/index.js",
|
|
41
|
+
"pixi-effects/controller": "https://cdn.jsdelivr.net/npm/pixi-effects@0.47.1/dist/Controller.js",
|
|
42
|
+
"pixi-effects/present": "https://cdn.jsdelivr.net/npm/pixi-effects@0.47.1/dist/present.js",
|
|
43
|
+
"pixi-effects/three": "https://cdn.jsdelivr.net/npm/pixi-effects@0.47.1/dist/three.js",
|
|
44
44
|
"pixi-filters": "https://esm.sh/pixi-filters@6.1.5?external=pixi.js",
|
|
45
45
|
"three": "https://esm.sh/three@0.178.0",
|
|
46
46
|
"three/addons/": "https://cdn.jsdelivr.net/npm/three@0.178.0/examples/jsm/"
|
|
47
47
|
}
|
|
48
48
|
}
|
|
49
49
|
</script>
|
|
50
|
-
<link rel="modulepreload" href="https://cdn.jsdelivr.net/npm/pixi-effects@0.
|
|
50
|
+
<link rel="modulepreload" href="https://cdn.jsdelivr.net/npm/pixi-effects@0.47.1/dist/index.js" /> <!-- after the import map: the library downloads while the page is parsed -->
|
|
51
51
|
|
|
52
52
|
<script type="module">
|
|
53
53
|
import { Movie, kenBurns, withFade } from 'pixi-effects';
|
|
@@ -1,7 +0,0 @@
|
|
|
1
|
-
export { CompositionSequence } from './chunk-FPV3NPYC.js';
|
|
2
|
-
import './chunk-DM2OLQOJ.js';
|
|
3
|
-
import './chunk-VNP7QCJE.js';
|
|
4
|
-
import './chunk-32MMNDDN.js';
|
|
5
|
-
import './chunk-BXOCEZ4U.js';
|
|
6
|
-
//# sourceMappingURL=Composition-NSY7A32Y.js.map
|
|
7
|
-
//# sourceMappingURL=Composition-NSY7A32Y.js.map
|