pixi-effects 0.22.0 → 0.25.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 +25 -0
- package/README.md +9 -7
- package/ai/SKILL.md +5 -3
- package/ai/chat-template.html +3 -3
- package/ai/reference/cheatsheet.md +8 -5
- package/ai/reference/pitfalls.md +13 -1
- package/ai/reference/recipes.md +131 -0
- package/ai/template.html +5 -5
- package/ai/tools/check.mjs +7 -0
- package/dist/{Base-gu-5X0Cv.d.ts → Base-BgnRXbtJ.d.ts} +1 -1
- package/dist/{Base-BzlPgd-D.d.cts → Base-DHVKqA46.d.cts} +1 -1
- package/dist/Composition-2GJSCHPP.cjs +16 -0
- package/dist/{Composition-BK5SH6J7.cjs.map → Composition-2GJSCHPP.cjs.map} +1 -1
- package/dist/Composition-C4FSWJZF.js +7 -0
- package/dist/{Composition-Q5TVG3HM.js.map → Composition-C4FSWJZF.js.map} +1 -1
- package/dist/Controller.cjs +2 -2
- package/dist/Controller.d.cts +2 -2
- package/dist/Controller.d.ts +2 -2
- package/dist/Controller.js +1 -1
- package/dist/{Movie-DMxOoTdW.d.cts → Movie-CTpN1wYL.d.cts} +3 -1
- package/dist/{Movie--_TJvdJa.d.ts → Movie-FM5m67V0.d.ts} +3 -1
- package/dist/Presenter.cjs +2 -2
- package/dist/Presenter.d.cts +2 -2
- package/dist/Presenter.d.ts +2 -2
- package/dist/Presenter.js +1 -1
- package/dist/{blendModes-HCP5XTNP.js → blendModes-G3NOAU3T.js} +5 -5
- package/dist/{blendModes-HCP5XTNP.js.map → blendModes-G3NOAU3T.js.map} +1 -1
- package/dist/{blendModes-5E4G2ZZQ.cjs → blendModes-YV43K6E7.cjs} +6 -6
- package/dist/{blendModes-5E4G2ZZQ.cjs.map → blendModes-YV43K6E7.cjs.map} +1 -1
- package/dist/{chunk-K4JVI5HK.cjs → chunk-3DLYAPK7.cjs} +7 -9
- package/dist/{chunk-K4JVI5HK.cjs.map → chunk-3DLYAPK7.cjs.map} +1 -1
- package/dist/{chunk-YEPDQ7I3.js → chunk-AXZUKNXF.js} +6 -6
- package/dist/{chunk-YEPDQ7I3.js.map → chunk-AXZUKNXF.js.map} +1 -1
- package/dist/{chunk-NHICCDTC.js → chunk-BXOCEZ4U.js} +12 -3
- package/dist/chunk-BXOCEZ4U.js.map +1 -0
- package/dist/{chunk-IFZOI3JQ.cjs → chunk-DP37TTMO.cjs} +842 -40
- package/dist/chunk-DP37TTMO.cjs.map +1 -0
- package/dist/{chunk-BPTW7L25.cjs → chunk-ECA2WNRX.cjs} +23 -9
- package/dist/chunk-ECA2WNRX.cjs.map +1 -0
- package/dist/{chunk-DC4JPY6A.js → chunk-PRZ4U6JN.js} +814 -22
- package/dist/chunk-PRZ4U6JN.js.map +1 -0
- package/dist/chunk-SY27HZC5.cjs +1727 -0
- package/dist/chunk-SY27HZC5.cjs.map +1 -0
- package/dist/{chunk-E7RONUZ7.js → chunk-TLYTYBWX.js} +20 -6
- package/dist/chunk-TLYTYBWX.js.map +1 -0
- package/dist/{chunk-UZTKEYFP.cjs → chunk-TWZNOUM7.cjs} +12 -3
- package/dist/chunk-TWZNOUM7.cjs.map +1 -0
- package/dist/chunk-XS6GSJCN.js +1724 -0
- package/dist/chunk-XS6GSJCN.js.map +1 -0
- package/dist/index.cjs +227 -77
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +5 -5
- package/dist/index.d.ts +5 -5
- package/dist/index.js +166 -16
- package/dist/index.js.map +1 -1
- package/dist/loader.css +1 -1
- package/dist/{music-FUN7N225.js → music-AF4VTFAF.js} +3 -3
- package/dist/{music-FUN7N225.js.map → music-AF4VTFAF.js.map} +1 -1
- package/dist/{music-GEAH2XCT.cjs → music-KB7YZLHP.cjs} +7 -7
- package/dist/{music-GEAH2XCT.cjs.map → music-KB7YZLHP.cjs.map} +1 -1
- package/dist/{sfx-2DYTYNYW.cjs → sfx-2O6UQEUP.cjs} +8 -8
- package/dist/{sfx-2DYTYNYW.cjs.map → sfx-2O6UQEUP.cjs.map} +1 -1
- package/dist/{sfx-3IDAJ3UZ.js → sfx-VUKARHDX.js} +3 -3
- package/dist/{sfx-3IDAJ3UZ.js.map → sfx-VUKARHDX.js.map} +1 -1
- package/dist/three.cjs +7 -7
- package/dist/three.d.cts +2 -2
- package/dist/three.d.ts +2 -2
- package/dist/three.js +3 -3
- package/dist/{types-DBbZVKGS.d.cts → types-CoT0ypcx.d.cts} +60 -4
- package/dist/{types-DBbZVKGS.d.ts → types-CoT0ypcx.d.ts} +60 -4
- package/docs/dsl.md +138 -5
- package/llms-full.txt +295 -14
- package/package.json +1 -1
- package/dist/Composition-BK5SH6J7.cjs +0 -16
- package/dist/Composition-Q5TVG3HM.js +0 -7
- package/dist/chunk-BPTW7L25.cjs.map +0 -1
- package/dist/chunk-DC4JPY6A.js.map +0 -1
- package/dist/chunk-E7RONUZ7.js.map +0 -1
- package/dist/chunk-IFZOI3JQ.cjs.map +0 -1
- package/dist/chunk-MHOO2CVU.cjs +0 -840
- package/dist/chunk-MHOO2CVU.cjs.map +0 -1
- package/dist/chunk-NHICCDTC.js.map +0 -1
- package/dist/chunk-UQDEDYVM.js +0 -838
- package/dist/chunk-UQDEDYVM.js.map +0 -1
- package/dist/chunk-UZTKEYFP.cjs.map +0 -1
package/dist/chunk-UQDEDYVM.js
DELETED
|
@@ -1,838 +0,0 @@
|
|
|
1
|
-
import { Sequence, timeRemapOf, contentLength, remapOf, buildSequenceTree, CameraSequence, layerInitialZ, bindClock, clockTable, NullSequence, homeCamera, cameraBasis, projectPoint, NEAR, blurRadius, MANY_BLURRED, focusProblems, projectLayer, MIN_BLUR, MAX_BLUR, DEG } from './chunk-DC4JPY6A.js';
|
|
2
|
-
import { maxConcurrentAdvanced, MANY_ADVANCED, applyBlendMode, blendProblem, isAdvancedBlend, blendFilterFor, blendUnavailableMessage } from './chunk-YEPDQ7I3.js';
|
|
3
|
-
import { lintTiming, lintText, lintKeys, summarizeWarnings, describeLayer, collectPropKeys } from './chunk-E7RONUZ7.js';
|
|
4
|
-
import { suggestName } from './chunk-NHICCDTC.js';
|
|
5
|
-
import { Container, Rectangle, AlphaFilter, AlphaMask, PerspectiveMesh, Texture, Matrix, RenderTexture, Filter, UniformGroup, GpuProgram, GlProgram } from 'pixi.js';
|
|
6
|
-
import { gsap } from 'gsap';
|
|
7
|
-
|
|
8
|
-
// src/space/camera.ts
|
|
9
|
-
function pickActiveCamera(cams, t, compEnd) {
|
|
10
|
-
for (let i = cams.length - 1; i >= 0; i--) {
|
|
11
|
-
const c = cams[i];
|
|
12
|
-
const inside = t >= c.start && (t < c.end || c.end >= compEnd && t <= compEnd);
|
|
13
|
-
if (inside) return c;
|
|
14
|
-
}
|
|
15
|
-
return null;
|
|
16
|
-
}
|
|
17
|
-
function findOverlap(cams) {
|
|
18
|
-
for (let i = 0; i < cams.length; i++) {
|
|
19
|
-
for (let j = i + 1; j < cams.length; j++) {
|
|
20
|
-
const a = cams[i];
|
|
21
|
-
const b = cams[j];
|
|
22
|
-
if (a.start < b.end && b.start < a.end) return [i, j];
|
|
23
|
-
}
|
|
24
|
-
}
|
|
25
|
-
return null;
|
|
26
|
-
}
|
|
27
|
-
|
|
28
|
-
// src/space/depth.ts
|
|
29
|
-
var finite = (n) => Number.isFinite(n) ? n : 0;
|
|
30
|
-
function assignDepthOrder(items) {
|
|
31
|
-
const out = items.map((i2) => i2.stackIndex);
|
|
32
|
-
let i = 0;
|
|
33
|
-
while (i < items.length) {
|
|
34
|
-
if (!items[i].threeD) {
|
|
35
|
-
i++;
|
|
36
|
-
continue;
|
|
37
|
-
}
|
|
38
|
-
let j = i;
|
|
39
|
-
while (j + 1 < items.length && items[j + 1].threeD) j++;
|
|
40
|
-
const run = items.slice(i, j + 1).map((it, k) => ({ it, pos: i + k }));
|
|
41
|
-
const slots = run.map((r) => r.it.stackIndex);
|
|
42
|
-
const farthestFirst = [...run].sort((a, b) => finite(b.it.depth) - finite(a.it.depth));
|
|
43
|
-
farthestFirst.forEach((r, k) => {
|
|
44
|
-
out[r.pos] = slots[k];
|
|
45
|
-
});
|
|
46
|
-
i = j + 1;
|
|
47
|
-
}
|
|
48
|
-
return out;
|
|
49
|
-
}
|
|
50
|
-
var DISC_TAPS = 48;
|
|
51
|
-
var GL_VERTEX = `#version 300 es
|
|
52
|
-
in vec2 aPosition;
|
|
53
|
-
out vec2 vTextureCoord;
|
|
54
|
-
uniform vec4 uInputSize;
|
|
55
|
-
uniform vec4 uOutputFrame;
|
|
56
|
-
uniform vec4 uOutputTexture;
|
|
57
|
-
void main(void) {
|
|
58
|
-
vec2 position = aPosition * uOutputFrame.zw + uOutputFrame.xy;
|
|
59
|
-
position.x = position.x * (2.0 / uOutputTexture.x) - 1.0;
|
|
60
|
-
position.y = position.y * (2.0 * uOutputTexture.z / uOutputTexture.y) - uOutputTexture.z;
|
|
61
|
-
gl_Position = vec4(position, 0.0, 1.0);
|
|
62
|
-
vTextureCoord = aPosition * (uOutputFrame.zw * uInputSize.zw);
|
|
63
|
-
}`;
|
|
64
|
-
var GL_FRAGMENT = `#version 300 es
|
|
65
|
-
precision highp float;
|
|
66
|
-
in vec2 vTextureCoord;
|
|
67
|
-
uniform sampler2D uTexture;
|
|
68
|
-
uniform vec4 uInputSize;
|
|
69
|
-
uniform float uRadius;
|
|
70
|
-
out vec4 finalColor;
|
|
71
|
-
void main(void) {
|
|
72
|
-
vec4 acc = vec4(0.0);
|
|
73
|
-
for (int i = 0; i < ${DISC_TAPS}; i++) {
|
|
74
|
-
float r = sqrt((float(i) + 0.5) / ${DISC_TAPS}.0) * uRadius;
|
|
75
|
-
float a = float(i) * 2.39996323;
|
|
76
|
-
acc += texture(uTexture, vTextureCoord + vec2(cos(a), sin(a)) * r * uInputSize.zw);
|
|
77
|
-
}
|
|
78
|
-
finalColor = acc / ${DISC_TAPS}.0;
|
|
79
|
-
}`;
|
|
80
|
-
var WGSL = `
|
|
81
|
-
struct GlobalFilterUniforms {
|
|
82
|
-
uInputSize: vec4<f32>, uInputPixel: vec4<f32>, uInputClamp: vec4<f32>,
|
|
83
|
-
uOutputFrame: vec4<f32>, uGlobalFrame: vec4<f32>, uOutputTexture: vec4<f32>,
|
|
84
|
-
};
|
|
85
|
-
struct DiscUniforms { uRadius: f32 };
|
|
86
|
-
@group(0) @binding(0) var<uniform> gfu: GlobalFilterUniforms;
|
|
87
|
-
@group(0) @binding(1) var uTexture: texture_2d<f32>;
|
|
88
|
-
@group(0) @binding(2) var uSampler : sampler;
|
|
89
|
-
@group(1) @binding(0) var<uniform> disc : DiscUniforms;
|
|
90
|
-
struct VSOutput { @builtin(position) position: vec4<f32>, @location(0) uv : vec2<f32> };
|
|
91
|
-
fn filterVertexPosition(aPosition : vec2<f32>) -> vec4<f32> {
|
|
92
|
-
var position = aPosition * gfu.uOutputFrame.zw + gfu.uOutputFrame.xy;
|
|
93
|
-
position.x = position.x * (2.0 / gfu.uOutputTexture.x) - 1.0;
|
|
94
|
-
position.y = position.y * (2.0 * gfu.uOutputTexture.z / gfu.uOutputTexture.y) - gfu.uOutputTexture.z;
|
|
95
|
-
return vec4<f32>(position, 0.0, 1.0);
|
|
96
|
-
}
|
|
97
|
-
fn filterTextureCoord(aPosition : vec2<f32>) -> vec2<f32> {
|
|
98
|
-
return aPosition * (gfu.uOutputFrame.zw * gfu.uInputSize.zw);
|
|
99
|
-
}
|
|
100
|
-
@vertex
|
|
101
|
-
fn mainVertex(@location(0) aPosition : vec2<f32>) -> VSOutput {
|
|
102
|
-
return VSOutput(filterVertexPosition(aPosition), filterTextureCoord(aPosition));
|
|
103
|
-
}
|
|
104
|
-
@fragment
|
|
105
|
-
fn mainFragment(@location(0) uv : vec2<f32>) -> @location(0) vec4<f32> {
|
|
106
|
-
var acc = vec4<f32>(0.0);
|
|
107
|
-
for (var i = 0; i < ${DISC_TAPS}; i++) {
|
|
108
|
-
let r = sqrt((f32(i) + 0.5) / ${DISC_TAPS}.0) * disc.uRadius;
|
|
109
|
-
let a = f32(i) * 2.39996323;
|
|
110
|
-
acc += textureSampleLevel(uTexture, uSampler, uv + vec2<f32>(cos(a), sin(a)) * r * gfu.uInputSize.zw, 0.0);
|
|
111
|
-
}
|
|
112
|
-
return acc / ${DISC_TAPS}.0;
|
|
113
|
-
}`;
|
|
114
|
-
var DiscBlurFilter = class extends Filter {
|
|
115
|
-
constructor(radius = 8) {
|
|
116
|
-
super({
|
|
117
|
-
glProgram: GlProgram.from({ vertex: GL_VERTEX, fragment: GL_FRAGMENT, name: "disc-blur" }),
|
|
118
|
-
gpuProgram: GpuProgram.from({ vertex: { source: WGSL, entryPoint: "mainVertex" }, fragment: { source: WGSL, entryPoint: "mainFragment" } }),
|
|
119
|
-
resources: { disc: new UniformGroup({ uRadius: { value: radius, type: "f32" } }) }
|
|
120
|
-
});
|
|
121
|
-
this.radius = radius;
|
|
122
|
-
}
|
|
123
|
-
/** Blur radius in pixels. The padding follows it, so the blurred edge is not cut off. */
|
|
124
|
-
get radius() {
|
|
125
|
-
return this.resources.disc.uniforms.uRadius;
|
|
126
|
-
}
|
|
127
|
-
set radius(v) {
|
|
128
|
-
const r = Math.max(0, v);
|
|
129
|
-
this.resources.disc.uniforms.uRadius = r;
|
|
130
|
-
this.padding = Math.ceil(r) + 2;
|
|
131
|
-
}
|
|
132
|
-
};
|
|
133
|
-
|
|
134
|
-
// src/space/Layer3D.ts
|
|
135
|
-
var MAX_TEXTURE_SIZE = 4096;
|
|
136
|
-
var SUPERSAMPLE = 2;
|
|
137
|
-
var MAX_TEXTURE_PIXELS = 2048 * 2048;
|
|
138
|
-
var ANTIALIAS_MAX_PIXELS = 1024 * 1024;
|
|
139
|
-
var MESH_GRID = 20;
|
|
140
|
-
function filterPadding(target) {
|
|
141
|
-
const filters = target.filters;
|
|
142
|
-
if (!Array.isArray(filters)) return 0;
|
|
143
|
-
let pad = 0;
|
|
144
|
-
for (const f of filters) pad += f?.padding ?? 0;
|
|
145
|
-
return Number.isFinite(pad) && pad > 0 ? Math.ceil(pad) : 0;
|
|
146
|
-
}
|
|
147
|
-
function readLayerTransform(target) {
|
|
148
|
-
const c = target;
|
|
149
|
-
return {
|
|
150
|
-
x: c.x,
|
|
151
|
-
y: c.y,
|
|
152
|
-
z: c.z ?? 0,
|
|
153
|
-
rotationX: (c.rotationX ?? 0) * DEG,
|
|
154
|
-
rotationY: (c.rotationY ?? 0) * DEG,
|
|
155
|
-
rotationZ: c.rotation,
|
|
156
|
-
scaleX: c.scale.x,
|
|
157
|
-
scaleY: c.scale.y,
|
|
158
|
-
pivotX: c.pivot.x,
|
|
159
|
-
pivotY: c.pivot.y
|
|
160
|
-
};
|
|
161
|
-
}
|
|
162
|
-
var Layer3D = class {
|
|
163
|
-
constructor(seq, frameOf2) {
|
|
164
|
-
this.seq = seq;
|
|
165
|
-
this.frameOf = frameOf2;
|
|
166
|
-
const target = seq.target;
|
|
167
|
-
target.z ??= 0;
|
|
168
|
-
target.rotationX ??= 0;
|
|
169
|
-
target.rotationY ??= 0;
|
|
170
|
-
this.display = new PerspectiveMesh({ texture: Texture.WHITE, verticesX: MESH_GRID, verticesY: MESH_GRID });
|
|
171
|
-
if (seq.spec.name) this.display.label = seq.spec.name;
|
|
172
|
-
this.display.visible = false;
|
|
173
|
-
}
|
|
174
|
-
seq;
|
|
175
|
-
frameOf;
|
|
176
|
-
display;
|
|
177
|
-
/** Camera-space depth from the last update (larger = farther). */
|
|
178
|
-
depth = 0;
|
|
179
|
-
rt = null;
|
|
180
|
-
/**
|
|
181
|
-
* Textures replaced by a bigger / smaller one. Destroying one right away warns "destroyed while still
|
|
182
|
-
* bound": the mesh's bind group still points at it until the next render. They go at the next update,
|
|
183
|
-
* by which time a frame has been drawn with the new texture.
|
|
184
|
-
*/
|
|
185
|
-
retired = [];
|
|
186
|
-
size = null;
|
|
187
|
-
warnedBehind = false;
|
|
188
|
-
/** Depth-of-field blur radius (px) from the last `setBlur`; 0 = no filter. */
|
|
189
|
-
blur = 0;
|
|
190
|
-
blurFilter = null;
|
|
191
|
-
blendWas = "normal";
|
|
192
|
-
blendFilter = null;
|
|
193
|
-
update(host, basis) {
|
|
194
|
-
this.flushRetired();
|
|
195
|
-
const target = this.seq.target;
|
|
196
|
-
if (!target || !target.renderable || !target.visible) return this.hide();
|
|
197
|
-
const bounds = this.frameOf();
|
|
198
|
-
const pad = filterPadding(target);
|
|
199
|
-
const needW = Math.ceil(bounds.width + 2 * pad);
|
|
200
|
-
const needH = Math.ceil(bounds.height + 2 * pad);
|
|
201
|
-
if (!(needW >= 1 && needH >= 1) || !Number.isFinite(bounds.x) || !Number.isFinite(bounds.y)) return this.hide();
|
|
202
|
-
const size = this.sizeFor(needW, needH);
|
|
203
|
-
const frame = { x: bounds.x - pad, y: bounds.y - pad, width: size.w, height: size.h };
|
|
204
|
-
const projected = projectLayer(readLayerTransform(target), frame, basis);
|
|
205
|
-
this.depth = projected.depth;
|
|
206
|
-
if (!projected.visible) {
|
|
207
|
-
if (!this.warnedBehind) {
|
|
208
|
-
this.warnedBehind = true;
|
|
209
|
-
if (this.seq.spec.hideBehindCamera) return this.hide();
|
|
210
|
-
if (projected.depth > NEAR) {
|
|
211
|
-
console.warn(
|
|
212
|
-
`pixi-effects: ${describeLayer(this.seq.spec)}: part of it (a corner) reaches the camera plane (z = ${(target.z ?? 0).toFixed(0)}, rotationX ${(target.rotationX ?? 0).toFixed(0)}\xB0, rotationY ${(target.rotationY ?? 0).toFixed(0)}\xB0), and a layer is hidden whole when any corner is at or behind it. Tilt it less (rotationX / rotationY), make it smaller, or keep the camera further away from it (the default camera sits at z = (height/2)/tan(fov/2), about 989 for 720p at fov 40).`
|
|
213
|
-
);
|
|
214
|
-
} else {
|
|
215
|
-
console.warn(
|
|
216
|
-
`pixi-effects: ${describeLayer(this.seq.spec)} is at or behind the camera plane (z = ${(target.z ?? 0).toFixed(0)}) and is hidden. 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).`
|
|
217
|
-
);
|
|
218
|
-
}
|
|
219
|
-
}
|
|
220
|
-
return this.hide();
|
|
221
|
-
}
|
|
222
|
-
this.ensureTexture(size);
|
|
223
|
-
host.render({
|
|
224
|
-
container: target,
|
|
225
|
-
target: this.rt,
|
|
226
|
-
transform: new Matrix().translate(-frame.x, -frame.y),
|
|
227
|
-
clear: true,
|
|
228
|
-
clearColor: [0, 0, 0, 0]
|
|
229
|
-
});
|
|
230
|
-
this.display.geometry.setCorners(...projected.corners);
|
|
231
|
-
this.display.visible = true;
|
|
232
|
-
}
|
|
233
|
-
/**
|
|
234
|
-
* Depth-of-field blur on the projected mesh (screen space), so a tilted or scaled layer blurs by the size it is drawn at.
|
|
235
|
-
* A radius under MIN_BLUR removes the filter: a sharp layer costs nothing. A blend mode moves to the filter while it is on
|
|
236
|
-
* (a filtered object blends as a whole), and comes back when it goes.
|
|
237
|
-
*/
|
|
238
|
-
setBlur(radius) {
|
|
239
|
-
const d = this.display;
|
|
240
|
-
const r = radius > MIN_BLUR ? Math.min(radius, MAX_BLUR) : 0;
|
|
241
|
-
this.blur = r;
|
|
242
|
-
if (r === 0) {
|
|
243
|
-
if (this.blurFilter) {
|
|
244
|
-
d.filters = null;
|
|
245
|
-
d.blendMode = this.blendWas;
|
|
246
|
-
this.blurFilter.destroy();
|
|
247
|
-
this.blurFilter = null;
|
|
248
|
-
this.blendFilter?.destroy();
|
|
249
|
-
this.blendFilter = null;
|
|
250
|
-
}
|
|
251
|
-
return;
|
|
252
|
-
}
|
|
253
|
-
if (!this.blurFilter) {
|
|
254
|
-
this.blurFilter = new DiscBlurFilter(r);
|
|
255
|
-
this.blendWas = d.blendMode ?? "normal";
|
|
256
|
-
const chain = [this.blurFilter];
|
|
257
|
-
if (isAdvancedBlend(this.blendWas)) {
|
|
258
|
-
this.blendFilter = blendFilterFor(this.blendWas);
|
|
259
|
-
if (this.blendFilter) {
|
|
260
|
-
chain.push(this.blendFilter);
|
|
261
|
-
d.blendMode = "normal";
|
|
262
|
-
}
|
|
263
|
-
} else if (this.blendWas !== "normal" && this.blendWas !== "inherit") {
|
|
264
|
-
this.blurFilter.blendMode = this.blendWas;
|
|
265
|
-
d.blendMode = "normal";
|
|
266
|
-
}
|
|
267
|
-
d.filters = chain;
|
|
268
|
-
}
|
|
269
|
-
this.blurFilter.radius = r;
|
|
270
|
-
}
|
|
271
|
-
destroy() {
|
|
272
|
-
this.setBlur(0);
|
|
273
|
-
this.display.destroy();
|
|
274
|
-
this.rt?.destroy(true);
|
|
275
|
-
this.rt = null;
|
|
276
|
-
this.flushRetired();
|
|
277
|
-
}
|
|
278
|
-
flushRetired() {
|
|
279
|
-
for (const t of this.retired) t.destroy(true);
|
|
280
|
-
this.retired = [];
|
|
281
|
-
}
|
|
282
|
-
hide() {
|
|
283
|
-
this.display.visible = false;
|
|
284
|
-
}
|
|
285
|
-
/**
|
|
286
|
-
* Texture size for content of w×h. An existing texture is kept while it is at
|
|
287
|
-
* least that big and at most 2x too big, so content whose bounds change every
|
|
288
|
-
* frame (typewriter text, growing shapes) does not reallocate each frame.
|
|
289
|
-
*/
|
|
290
|
-
sizeFor(w, h) {
|
|
291
|
-
const cur = this.size;
|
|
292
|
-
if (cur && cur.w >= w && cur.h >= h && cur.w <= 2 * w && cur.h <= 2 * h) return cur;
|
|
293
|
-
const resolution = Math.min(
|
|
294
|
-
SUPERSAMPLE,
|
|
295
|
-
MAX_TEXTURE_SIZE / Math.max(w, h),
|
|
296
|
-
Math.sqrt(MAX_TEXTURE_PIXELS / (w * h))
|
|
297
|
-
);
|
|
298
|
-
const antialias = w * h * resolution * resolution <= ANTIALIAS_MAX_PIXELS;
|
|
299
|
-
return { w, h, resolution, antialias };
|
|
300
|
-
}
|
|
301
|
-
ensureTexture(size) {
|
|
302
|
-
if (this.rt && this.size === size) return;
|
|
303
|
-
if (this.rt && this.size && this.size.antialias === size.antialias) {
|
|
304
|
-
this.rt.resize(size.w, size.h, size.resolution);
|
|
305
|
-
this.size = size;
|
|
306
|
-
return;
|
|
307
|
-
}
|
|
308
|
-
const next = RenderTexture.create({
|
|
309
|
-
width: size.w,
|
|
310
|
-
height: size.h,
|
|
311
|
-
resolution: size.resolution,
|
|
312
|
-
antialias: size.antialias
|
|
313
|
-
});
|
|
314
|
-
this.display.texture = next;
|
|
315
|
-
if (this.rt) this.retired.push(this.rt);
|
|
316
|
-
this.rt = next;
|
|
317
|
-
this.size = size;
|
|
318
|
-
}
|
|
319
|
-
};
|
|
320
|
-
|
|
321
|
-
// src/space/lint.ts
|
|
322
|
-
var defaultWarn = (m) => console.warn(m);
|
|
323
|
-
var FOV_HINT = `perspective is the camera's "fov" \u2014 add a { type: "camera" } layer and set fov in its initial / keyframes`;
|
|
324
|
-
var DOF_HINT = `depth of field is the camera's "focus" (the plane that is sharp: a layer name or a z) and "aperture" (how shallow: 0 = off, 30 = default) \u2014 put them in the camera's initial / keyframes`;
|
|
325
|
-
var LAYER_ALIASES = {
|
|
326
|
-
rotateX: 'did you mean "rotationX"?',
|
|
327
|
-
rotateY: 'did you mean "rotationY"?',
|
|
328
|
-
rotateZ: 'did you mean "rotation"?',
|
|
329
|
-
rotationZ: 'did you mean "rotation" (it is the Z rotation)?',
|
|
330
|
-
translateZ: 'did you mean "z"?',
|
|
331
|
-
depth: 'did you mean "z"?',
|
|
332
|
-
posZ: 'did you mean "z"?',
|
|
333
|
-
perspective: FOV_HINT,
|
|
334
|
-
zoom: FOV_HINT
|
|
335
|
-
};
|
|
336
|
-
var CAMERA_ALIASES = {
|
|
337
|
-
pointOfInterest: 'did you mean "lookAtX / lookAtY / lookAtZ"?',
|
|
338
|
-
lookAt: 'did you mean "lookAtX / lookAtY / lookAtZ"?',
|
|
339
|
-
depthOfField: DOF_HINT,
|
|
340
|
-
dof: DOF_HINT,
|
|
341
|
-
focalDistance: DOF_HINT,
|
|
342
|
-
focusDistance: DOF_HINT,
|
|
343
|
-
fStop: DOF_HINT,
|
|
344
|
-
blurAmount: DOF_HINT
|
|
345
|
-
};
|
|
346
|
-
var CAMERA_PROPS = ["x", "y", "z", "fov", "focus", "aperture", "lookAtX", "lookAtY", "lookAtZ", "offsetX", "offsetY", "offsetZ", "lookOffsetX", "lookOffsetY", "lookOffsetZ"];
|
|
347
|
-
var NEEDS_THREE_D = ["z", "rotationX", "rotationY"];
|
|
348
|
-
var CAMERA_ONLY = ["focus", "aperture"];
|
|
349
|
-
var SKEW_KEYS = ["skew", "skewX", "skewY"];
|
|
350
|
-
function lintSequence(spec, warn = defaultWarn) {
|
|
351
|
-
const who = describeLayer(spec);
|
|
352
|
-
const keys = collectPropKeys(spec);
|
|
353
|
-
const explained = /* @__PURE__ */ new Set();
|
|
354
|
-
for (const k of keys) {
|
|
355
|
-
const hint = LAYER_ALIASES[k] ?? (spec.type === "camera" ? CAMERA_ALIASES[k] : void 0);
|
|
356
|
-
if (hint) {
|
|
357
|
-
explained.add(k);
|
|
358
|
-
warn(`pixi-effects: ${who}: "${k}" is not a property \u2014 ${hint}`);
|
|
359
|
-
}
|
|
360
|
-
}
|
|
361
|
-
if (spec.type === "camera") {
|
|
362
|
-
const raw = spec;
|
|
363
|
-
for (const p of CAMERA_PROPS) {
|
|
364
|
-
if (p in raw) warn(`pixi-effects: ${who}: "${p}" must go inside initial / keyframes, not on the camera itself`);
|
|
365
|
-
}
|
|
366
|
-
for (const k of Object.keys(raw)) {
|
|
367
|
-
const hint = CAMERA_ALIASES[k] ?? LAYER_ALIASES[k];
|
|
368
|
-
if (hint) warn(`pixi-effects: ${who}: "${k}" is not a property \u2014 ${hint} (inside initial)`);
|
|
369
|
-
}
|
|
370
|
-
for (const k of keys) {
|
|
371
|
-
if (!explained.has(k) && !CAMERA_PROPS.includes(k)) {
|
|
372
|
-
warn(`pixi-effects: ${who}: "${k}" has no effect on a camera (use ${CAMERA_PROPS.join(", ")})`);
|
|
373
|
-
}
|
|
374
|
-
}
|
|
375
|
-
return;
|
|
376
|
-
}
|
|
377
|
-
for (const k of CAMERA_ONLY) {
|
|
378
|
-
if (keys.has(k)) warn(`pixi-effects: ${who}: "${k}" is a camera property and does nothing on this layer: write it in the initial / keyframes of a { type: 'camera' } layer`);
|
|
379
|
-
}
|
|
380
|
-
if (spec.type === "audio") {
|
|
381
|
-
if (spec.threeD) warn(`pixi-effects: ${who}: threeD has no effect on audio`);
|
|
382
|
-
return;
|
|
383
|
-
}
|
|
384
|
-
if (!spec.threeD) {
|
|
385
|
-
for (const k of NEEDS_THREE_D) {
|
|
386
|
-
if (keys.has(k)) warn(`pixi-effects: ${who}: "${k}" needs threeD: true (it is ignored otherwise)`);
|
|
387
|
-
}
|
|
388
|
-
} else {
|
|
389
|
-
for (const k of SKEW_KEYS) {
|
|
390
|
-
if (keys.has(k)) warn(`pixi-effects: ${who}: "${k}" is ignored on threeD layers`);
|
|
391
|
-
}
|
|
392
|
-
}
|
|
393
|
-
}
|
|
394
|
-
function lintFocus(camera, siblings, warn = defaultWarn) {
|
|
395
|
-
if (camera.type !== "camera") return;
|
|
396
|
-
const who = describeLayer(camera);
|
|
397
|
-
for (const p of focusProblems(camera, siblings)) {
|
|
398
|
-
if (p.kind === "missing") {
|
|
399
|
-
warn(`pixi-effects: ${who}: focus: no layer named "${p.name}"${p.hint ? `; did you mean "${p.hint}"?` : ""} (the z = 0 plane is used). Write a threeD layer's name or a z number`);
|
|
400
|
-
} else if (p.kind === "not-threeD") {
|
|
401
|
-
warn(`pixi-effects: ${who}: focus "${p.name}" is not a threeD layer, so it has no depth (the z = 0 plane is used). Write a threeD layer's name or a z number`);
|
|
402
|
-
} else if (p.kind === "duplicate") {
|
|
403
|
-
warn(`pixi-effects: ${who}: focus "${p.name}": ${p.count} layers are named "${p.name}"; the first threeD one is used. Give the layers different names`);
|
|
404
|
-
} else {
|
|
405
|
-
warn(`pixi-effects: ${who}: focus "${p.name}" reads only the first z of that layer; its z moves later and the focus does not follow. Animate focus itself with numbers to follow it`);
|
|
406
|
-
}
|
|
407
|
-
}
|
|
408
|
-
}
|
|
409
|
-
|
|
410
|
-
// src/sequences/Composition.ts
|
|
411
|
-
var CompositionSequence = class extends Sequence {
|
|
412
|
-
_innerContainer = null;
|
|
413
|
-
_compositionShape = null;
|
|
414
|
-
_children = [];
|
|
415
|
-
_cameras = [];
|
|
416
|
-
_layers3d = [];
|
|
417
|
-
_dofSaid = { behind: false, many: false };
|
|
418
|
-
/** What this composition made for blend modes (filters added to layers' chains, groups and their carrier filters): destroyed with it. */
|
|
419
|
-
_blendOwned = [];
|
|
420
|
-
/** Drawn children in stack order (cameras and target-less sequences excluded). */
|
|
421
|
-
_visual = [];
|
|
422
|
-
/** Layers drawn inside a null layer (`parent`): they are not in the composition's own stack. */
|
|
423
|
-
_nested = [];
|
|
424
|
-
/** The null layer each parented layer is drawn inside. */
|
|
425
|
-
_parentOf = /* @__PURE__ */ new Map();
|
|
426
|
-
/** Set when this composition's own time is remapped: the children live on `_inner` in LOCAL time, driven by `_clock`. */
|
|
427
|
-
_inner = null;
|
|
428
|
-
_clock = null;
|
|
429
|
-
_remap = null;
|
|
430
|
-
_childBase = 0;
|
|
431
|
-
_contentSpan = 0;
|
|
432
|
-
/** Where the children's time starts: the composition's absolute start, or 0 when their time is local (remapped). */
|
|
433
|
-
get childBase() {
|
|
434
|
-
return this._childBase;
|
|
435
|
-
}
|
|
436
|
-
/** How long the children's time runs: the composition's duration, or its content length when its time is remapped. */
|
|
437
|
-
get contentSpan() {
|
|
438
|
-
return this._contentSpan;
|
|
439
|
-
}
|
|
440
|
-
/** The time the children live in at movie time `t`: the movie's own, or this composition's local clock when it is remapped. */
|
|
441
|
-
childTime(t) {
|
|
442
|
-
return this._clock ? this._clock.time : t;
|
|
443
|
-
}
|
|
444
|
-
/** The clock reader for filters that want the time (grain), or null when the children run on the movie's time. */
|
|
445
|
-
localClock() {
|
|
446
|
-
return this._clock ? () => this._clock.time : null;
|
|
447
|
-
}
|
|
448
|
-
/** How the time is remapped, for the timeline chart: `×0.5`, `×-1`, `time keyframes`, or null. */
|
|
449
|
-
remapLabel() {
|
|
450
|
-
const r = this._remap;
|
|
451
|
-
if (!r) return null;
|
|
452
|
-
return r.timeKfs.length ? "time keyframes" : `\xD7${r.speed ?? 1}`;
|
|
453
|
-
}
|
|
454
|
-
async build() {
|
|
455
|
-
const width = this.spec.width ?? this.parent?.width ?? this.root.width;
|
|
456
|
-
const height = this.spec.height ?? this.parent?.height ?? this.root.height;
|
|
457
|
-
if (this.duration === void 0) {
|
|
458
|
-
this.duration = this.spec.duration ?? this.parent?.duration ?? this.root.duration;
|
|
459
|
-
}
|
|
460
|
-
const wrapper = new Container();
|
|
461
|
-
wrapper.cullable = true;
|
|
462
|
-
wrapper.cullableChildren = true;
|
|
463
|
-
wrapper.cullArea = new Rectangle(0, 0, width, height);
|
|
464
|
-
const inner = new Container();
|
|
465
|
-
inner.cullable = true;
|
|
466
|
-
inner.cullableChildren = true;
|
|
467
|
-
wrapper.addChild(inner);
|
|
468
|
-
this.target = wrapper;
|
|
469
|
-
this.intrinsicWidth = width;
|
|
470
|
-
this.intrinsicHeight = height;
|
|
471
|
-
this._innerContainer = inner;
|
|
472
|
-
const base = timeRemapOf(this.spec);
|
|
473
|
-
const span = base ? contentLength(base, this.duration) : this.duration;
|
|
474
|
-
this._remap = base ? remapOf(this.spec, "time", span) : null;
|
|
475
|
-
this._contentSpan = span;
|
|
476
|
-
this._compositionShape = { width, height, duration: span };
|
|
477
|
-
const lateKeyframes = [];
|
|
478
|
-
for (const s of this.spec.sequences ?? []) {
|
|
479
|
-
lintSequence(s);
|
|
480
|
-
lintFocus(s, this.spec.sequences ?? []);
|
|
481
|
-
lintTiming(s, span, (message, kind) => kind === "late-keyframe" ? lateKeyframes.push(message) : console.warn(message));
|
|
482
|
-
lintText(s);
|
|
483
|
-
lintKeys(s);
|
|
484
|
-
}
|
|
485
|
-
for (const message of summarizeWarnings(lateKeyframes)) console.warn(message);
|
|
486
|
-
const crowd = maxConcurrentAdvanced(this.spec.sequences ?? [], span);
|
|
487
|
-
if (crowd >= MANY_ADVANCED) {
|
|
488
|
-
console.warn(`pixi-effects: ${describeLayer(this.spec)}: ${crowd} layers with an advanced blendMode are on screen at once (a composition with one counts each layer inside it, since its children blend one by one); each is a full-frame pass (about 2 ms on WebGL). Put fewer layers in the blend (or draw the glow as one layer), or use add / screen / multiply`);
|
|
489
|
-
}
|
|
490
|
-
this._children = await buildSequenceTree(
|
|
491
|
-
this.spec.sequences ?? [],
|
|
492
|
-
this._compositionShape,
|
|
493
|
-
this.root
|
|
494
|
-
);
|
|
495
|
-
this._resolveParents();
|
|
496
|
-
const layerNames = new Set(this._children.map((c) => c.spec.name).filter((n) => !!n));
|
|
497
|
-
for (const cam of this._children) {
|
|
498
|
-
if (!(cam instanceof CameraSequence)) continue;
|
|
499
|
-
cam.resolveFocusNames((name) => {
|
|
500
|
-
const hit = this._children.find((c) => c.spec.name === name && c.spec.threeD);
|
|
501
|
-
return hit ? layerInitialZ(hit.spec, hit.scope()) : void 0;
|
|
502
|
-
}, layerNames);
|
|
503
|
-
}
|
|
504
|
-
const blendSaid = /* @__PURE__ */ new Map();
|
|
505
|
-
const report = (message, spec) => {
|
|
506
|
-
const seen = blendSaid.get(message);
|
|
507
|
-
if (seen) seen.n++;
|
|
508
|
-
else blendSaid.set(message, { spec, n: 1 });
|
|
509
|
-
};
|
|
510
|
-
for (const child of this._children) {
|
|
511
|
-
if (child instanceof CameraSequence) {
|
|
512
|
-
this._cameras.push(child);
|
|
513
|
-
continue;
|
|
514
|
-
}
|
|
515
|
-
if (!child.target) continue;
|
|
516
|
-
const holder = this._parentOf.get(child);
|
|
517
|
-
const into = holder?.target ?? inner;
|
|
518
|
-
const maskSpec = child.spec.mask;
|
|
519
|
-
if (child.spec.threeD) {
|
|
520
|
-
const layer = new Layer3D(child, frameOf(child));
|
|
521
|
-
inner.addChild(layer.display);
|
|
522
|
-
this._layers3d.push(layer);
|
|
523
|
-
this._visual.push({ seq: child, layer });
|
|
524
|
-
const added3d = applyBlendMode(child.spec, layer.display, report);
|
|
525
|
-
if (added3d) this._blendOwned.push(added3d);
|
|
526
|
-
if (maskSpec) {
|
|
527
|
-
console.warn(`pixi-effects: ${describeLayer(child.spec)}: mask is not supported on threeD layers yet; ignored`);
|
|
528
|
-
}
|
|
529
|
-
continue;
|
|
530
|
-
}
|
|
531
|
-
const mode = child.spec.blendMode;
|
|
532
|
-
const eraseMask = !!maskSpec && child.spec.maskInverted === true && mode !== void 0 && mode !== "normal" && blendProblem(mode) === null;
|
|
533
|
-
const alphaMaskLosesBlend = !!maskSpec && (maskSpec.type === "text" || maskSpec.type === "image" || maskSpec.type === "video") && !eraseMask && mode !== void 0 && mode !== "normal" && blendProblem(mode) === null;
|
|
534
|
-
if (alphaMaskLosesBlend) {
|
|
535
|
-
report(`blendMode "${mode}" cannot be used together with ${maskSpec.type === "image" ? "an" : "a"} ${maskSpec.type} layer as the mask (the blend is lost); the layer is drawn normal. Put the ${maskSpec.type} on a layer of its own with the blendMode instead of masking with it, or use maskInverted`, child.spec);
|
|
536
|
-
}
|
|
537
|
-
let wrap;
|
|
538
|
-
if (eraseMask) {
|
|
539
|
-
wrap = new Container();
|
|
540
|
-
wrap.addChild(child.target);
|
|
541
|
-
let carrier = null;
|
|
542
|
-
if (isAdvancedBlend(mode)) carrier = blendFilterFor(mode);
|
|
543
|
-
else {
|
|
544
|
-
const f = new AlphaFilter({ alpha: 1 });
|
|
545
|
-
f.blendMode = mode;
|
|
546
|
-
carrier = f;
|
|
547
|
-
}
|
|
548
|
-
if (carrier) {
|
|
549
|
-
wrap.filters = [carrier];
|
|
550
|
-
this._blendOwned.push(carrier);
|
|
551
|
-
} else report(blendUnavailableMessage(mode), child.spec);
|
|
552
|
-
this._blendOwned.push(wrap);
|
|
553
|
-
into.addChild(wrap);
|
|
554
|
-
} else into.addChild(child.target);
|
|
555
|
-
if (holder) this._nested.push(child);
|
|
556
|
-
else this._visual.push({ seq: child, layer: null, wrap });
|
|
557
|
-
if (!wrap && !alphaMaskLosesBlend) {
|
|
558
|
-
const added = applyBlendMode(child.spec, child.target, report);
|
|
559
|
-
if (added) this._blendOwned.push(added);
|
|
560
|
-
}
|
|
561
|
-
if (maskSpec) {
|
|
562
|
-
const lifetime = maskSpec.at === void 0 ? { at: child.at, duration: maskSpec.duration ?? child.duration } : {};
|
|
563
|
-
const built = await buildSequenceTree([{ ...maskSpec, ...lifetime }], this._compositionShape, this.root);
|
|
564
|
-
const maskSeq = built[0];
|
|
565
|
-
if (maskSeq?.target) {
|
|
566
|
-
(wrap ?? into).addChild(maskSeq.target);
|
|
567
|
-
const inverse = child.spec.maskInverted ?? false;
|
|
568
|
-
const t = child.target;
|
|
569
|
-
if (wrap) {
|
|
570
|
-
const mt = maskSeq.target;
|
|
571
|
-
const mf = Array.isArray(mt.filters) && mt.filters.length > 0 ? mt.filters[mt.filters.length - 1] : null;
|
|
572
|
-
if (mf) mf.blendMode = "erase";
|
|
573
|
-
else mt.blendMode = "erase";
|
|
574
|
-
} else if (inverse || maskSpec.type === "text") {
|
|
575
|
-
const effect = new AlphaMask({ mask: maskSeq.target });
|
|
576
|
-
effect.inverse = inverse;
|
|
577
|
-
t.setMask?.({ mask: void 0, inverse });
|
|
578
|
-
t.addEffect(effect);
|
|
579
|
-
} else if (typeof t.setMask === "function") {
|
|
580
|
-
t.setMask({ mask: maskSeq.target, inverse });
|
|
581
|
-
} else {
|
|
582
|
-
t.mask = maskSeq.target;
|
|
583
|
-
}
|
|
584
|
-
child.maskSequence = maskSeq;
|
|
585
|
-
maskSeq.keepHidden = !wrap && (maskSpec.type === "image" || maskSpec.type === "video");
|
|
586
|
-
}
|
|
587
|
-
}
|
|
588
|
-
}
|
|
589
|
-
for (const [message, seen] of blendSaid) {
|
|
590
|
-
console.warn(`pixi-effects: ${describeLayer(seen.spec)}: ${message}${seen.n > 1 ? ` (and ${seen.n - 1} more layers have the same mistake)` : ""}`);
|
|
591
|
-
}
|
|
592
|
-
if (this._layers3d.length > 0) {
|
|
593
|
-
inner.sortableChildren = true;
|
|
594
|
-
this._visual.forEach((v, i) => {
|
|
595
|
-
(v.layer?.display ?? v.wrap ?? v.seq.target).zIndex = i;
|
|
596
|
-
});
|
|
597
|
-
} else if (this._cameras.length > 0) {
|
|
598
|
-
console.warn("pixi-effects: camera has no effect: this composition has no threeD layers");
|
|
599
|
-
}
|
|
600
|
-
this.buildFilters();
|
|
601
|
-
}
|
|
602
|
-
displayProps() {
|
|
603
|
-
const r = this._remap;
|
|
604
|
-
return r ? { initial: r.restInitial, keyframes: r.restKfs } : super.displayProps();
|
|
605
|
-
}
|
|
606
|
-
bindTimeline(timeline, offset = 0) {
|
|
607
|
-
super.bindTimeline(timeline, offset);
|
|
608
|
-
const remap = this._remap;
|
|
609
|
-
const childOffset = remap ? 0 : offset + this.at;
|
|
610
|
-
this._childBase = childOffset;
|
|
611
|
-
const target = remap ? gsap.timeline({ paused: true, defaults: { ease: "none" } }) : timeline;
|
|
612
|
-
for (const child of this._children) {
|
|
613
|
-
const own = gsap.timeline({ defaults: { ease: "none" } });
|
|
614
|
-
child.bindTimeline(own, childOffset);
|
|
615
|
-
child.maskSequence?.bindTimeline(own, childOffset);
|
|
616
|
-
target.add(own, 0);
|
|
617
|
-
}
|
|
618
|
-
if (remap) this._bindClock(timeline, target, remap, offset);
|
|
619
|
-
const overlap = findOverlap(this._cameras.map((c) => c.window()));
|
|
620
|
-
if (overlap) {
|
|
621
|
-
console.warn(`pixi-effects: cameras #${overlap[0] + 1} and #${overlap[1] + 1} overlap in time; the top-most one wins`);
|
|
622
|
-
}
|
|
623
|
-
}
|
|
624
|
-
/** Drive the local timeline `inner` from the clock, and put the clock's tweens on the outer `timeline`. */
|
|
625
|
-
_bindClock(timeline, inner, remap, offset) {
|
|
626
|
-
let last = NaN;
|
|
627
|
-
let cur = 0;
|
|
628
|
-
const clock = {
|
|
629
|
-
get time() {
|
|
630
|
-
return cur;
|
|
631
|
-
},
|
|
632
|
-
set time(v) {
|
|
633
|
-
cur = v;
|
|
634
|
-
if (v === last) return;
|
|
635
|
-
last = v;
|
|
636
|
-
inner.time(v);
|
|
637
|
-
}
|
|
638
|
-
};
|
|
639
|
-
this._inner = inner;
|
|
640
|
-
this._clock = clock;
|
|
641
|
-
const scope = this.scope();
|
|
642
|
-
if (remap.start !== void 0 && remap.timeKfs.length === 0) clock.time = remap.start;
|
|
643
|
-
bindClock(timeline, clock, "time", remap, this.duration, offset + this.at, scope);
|
|
644
|
-
inner.time(inner.duration());
|
|
645
|
-
inner.time(0);
|
|
646
|
-
last = NaN;
|
|
647
|
-
this._warnUnreachable(clockTable(remap, "time", this.duration, offset + this.at, scope, offset + this.at + this.duration), offset + this.at, offset + this.at + this.duration);
|
|
648
|
-
}
|
|
649
|
-
/**
|
|
650
|
-
* A child the clock never dwells in is never visible: say so. Its `at` is in THIS composition's local time, so the usual mistake is
|
|
651
|
-
* writing it in the outer time (or forgetting that speed 0.5 reaches only half as far). Decided by dwell, not by the clock's end
|
|
652
|
-
* points: a clock that arrives at the child's `at` and HOLDS there shows it for the whole hold; one that only touches it in a single
|
|
653
|
-
* instant (speed 0.5, a child at exactly the farthest local time) does not.
|
|
654
|
-
*/
|
|
655
|
-
_warnUnreachable(table, from, to) {
|
|
656
|
-
const remap = this._remap;
|
|
657
|
-
const how = remap.timeKfs.length ? "time keyframes" : `speed ${remap.speed ?? 1}`;
|
|
658
|
-
const span = this._contentSpan;
|
|
659
|
-
const EPS = 1e-9;
|
|
660
|
-
for (const child of this._children) {
|
|
661
|
-
const at = child.at;
|
|
662
|
-
if (at >= span) continue;
|
|
663
|
-
const end = Math.min(at + (child.duration ?? span), span);
|
|
664
|
-
let dwell = 0;
|
|
665
|
-
for (let t = from; t <= to && dwell < 2; t += 1e-3) {
|
|
666
|
-
const v = table.at(t);
|
|
667
|
-
if (v >= at - EPS && v < end + EPS) dwell++;
|
|
668
|
-
}
|
|
669
|
-
if (dwell >= 2) continue;
|
|
670
|
-
console.warn(
|
|
671
|
-
`pixi-effects: ${describeLayer(child.spec)} starts at ${at}s of ${describeLayer(this.spec)}'s own time, but its clock only reaches ${Number(table.min.toFixed(3))}\u2013${Number(table.max.toFixed(3))}s (${how}), so it is never visible. Layers inside a remapped composition are placed in that composition's local time.`
|
|
672
|
-
);
|
|
673
|
-
}
|
|
674
|
-
}
|
|
675
|
-
/**
|
|
676
|
-
* Drawn children in stack order, with the display object that stands in for each (the mesh for a threeD layer).
|
|
677
|
-
* Null layers draw nothing and are left out; the layers inside them follow, with the null layers that carry them.
|
|
678
|
-
*/
|
|
679
|
-
layers() {
|
|
680
|
-
const carriersOf = (seq) => {
|
|
681
|
-
const out = [];
|
|
682
|
-
for (let p = this._parentOf.get(seq); p; p = this._parentOf.get(p)) out.push(p);
|
|
683
|
-
return out;
|
|
684
|
-
};
|
|
685
|
-
return [...this._visual.map((v) => v.seq), ...this._nested].filter((seq) => !(seq instanceof NullSequence)).map((seq) => {
|
|
686
|
-
const layer = this._visual.find((v) => v.seq === seq)?.layer ?? null;
|
|
687
|
-
return {
|
|
688
|
-
seq,
|
|
689
|
-
display: layer?.display ?? seq.target,
|
|
690
|
-
threeD: layer !== null,
|
|
691
|
-
carriers: carriersOf(seq),
|
|
692
|
-
depthBlur: layer?.blur ?? 0
|
|
693
|
-
};
|
|
694
|
-
});
|
|
695
|
-
}
|
|
696
|
-
/** Match every `parent: 'name'` to a null layer; anything that cannot work is said out loud and drawn unparented. */
|
|
697
|
-
_resolveParents() {
|
|
698
|
-
const nulls = this._children.filter((c) => c instanceof NullSequence);
|
|
699
|
-
const nullNames = nulls.map((n) => n.spec.name).filter((n) => !!n);
|
|
700
|
-
const warned = /* @__PURE__ */ new Set();
|
|
701
|
-
for (const child of this._children) {
|
|
702
|
-
const want = child.spec.parent;
|
|
703
|
-
if (want === void 0) continue;
|
|
704
|
-
const who = describeLayer(child.spec);
|
|
705
|
-
if (child instanceof CameraSequence) {
|
|
706
|
-
console.warn(`pixi-effects: ${who}: a camera cannot have a parent; ignored`);
|
|
707
|
-
continue;
|
|
708
|
-
}
|
|
709
|
-
if (child.spec.threeD) {
|
|
710
|
-
console.warn(`pixi-effects: ${who}: a threeD layer cannot have a parent (parent "${want}" ignored)`);
|
|
711
|
-
continue;
|
|
712
|
-
}
|
|
713
|
-
const same = this._children.filter((c) => c.spec.name === want);
|
|
714
|
-
if (same.length === 0) {
|
|
715
|
-
const hint = suggestName(want, nullNames);
|
|
716
|
-
console.warn(`pixi-effects: ${who}: parent "${want}": no layer with that name${hint ? `; did you mean "${hint}"?` : ""} (the layer is drawn without a parent)`);
|
|
717
|
-
continue;
|
|
718
|
-
}
|
|
719
|
-
const holder = same.find((c) => c instanceof NullSequence);
|
|
720
|
-
if (!holder) {
|
|
721
|
-
console.warn(`pixi-effects: ${who}: parent "${want}" is a ${same[0].spec.type} layer; only { type: 'null' } layers can be parents (the layer is drawn without a parent)`);
|
|
722
|
-
continue;
|
|
723
|
-
}
|
|
724
|
-
if (same.length > 1 && !warned.has(want)) {
|
|
725
|
-
warned.add(want);
|
|
726
|
-
console.warn(`pixi-effects: ${same.length} layers are named "${want}"; parent "${want}" uses the first null layer with that name`);
|
|
727
|
-
}
|
|
728
|
-
if (holder === child) {
|
|
729
|
-
console.warn(`pixi-effects: ${who} is its own parent; ignored`);
|
|
730
|
-
continue;
|
|
731
|
-
}
|
|
732
|
-
this._parentOf.set(child, holder);
|
|
733
|
-
}
|
|
734
|
-
for (const start of this._children) {
|
|
735
|
-
const seen = /* @__PURE__ */ new Set([start]);
|
|
736
|
-
for (let p = this._parentOf.get(start); p; p = this._parentOf.get(p)) {
|
|
737
|
-
if (p === start) {
|
|
738
|
-
const names = [...seen].map((s) => s.spec.name ?? s.spec.type).join(" \u2192 ");
|
|
739
|
-
console.warn(`pixi-effects: parent cycle: ${names} \u2192 ${start.spec.name ?? start.spec.type}; the parent of "${start.spec.name ?? start.spec.type}" is ignored`);
|
|
740
|
-
this._parentOf.delete(start);
|
|
741
|
-
break;
|
|
742
|
-
}
|
|
743
|
-
if (seen.has(p)) break;
|
|
744
|
-
seen.add(p);
|
|
745
|
-
}
|
|
746
|
-
}
|
|
747
|
-
}
|
|
748
|
-
syncFrame() {
|
|
749
|
-
super.syncFrame();
|
|
750
|
-
for (const child of this._children) child.syncFrame();
|
|
751
|
-
}
|
|
752
|
-
updateSpace(t, host) {
|
|
753
|
-
const childT = this.childTime(t);
|
|
754
|
-
for (const child of this._children) child.updateSpace(childT, host);
|
|
755
|
-
if (this._layers3d.length === 0 || !this._compositionShape) return;
|
|
756
|
-
const { width, height } = this._compositionShape;
|
|
757
|
-
const compEnd = this._childBase + (this.duration ?? 0);
|
|
758
|
-
const active = pickActiveCamera(
|
|
759
|
-
this._cameras.map((cam2) => ({ cam: cam2, ...cam2.window() })),
|
|
760
|
-
childT,
|
|
761
|
-
compEnd
|
|
762
|
-
);
|
|
763
|
-
const cam = active ? active.cam.state() : homeCamera(width, height);
|
|
764
|
-
const basis = cameraBasis(cam, width, height);
|
|
765
|
-
for (const layer of this._layers3d) layer.update(host, basis);
|
|
766
|
-
this._applyDepthOfField(cam, basis);
|
|
767
|
-
const order = assignDepthOrder(
|
|
768
|
-
this._visual.map((v, i) => ({ stackIndex: i, threeD: v.layer !== null, depth: v.layer?.depth ?? 0 }))
|
|
769
|
-
);
|
|
770
|
-
this._visual.forEach((v, i) => {
|
|
771
|
-
if (v.layer) v.layer.display.zIndex = order[i];
|
|
772
|
-
});
|
|
773
|
-
}
|
|
774
|
-
/** Depth of field: each threeD layer is blurred by how far its depth is from the focal plane (a pure function of the camera and the layers). */
|
|
775
|
-
_applyDepthOfField(cam, basis) {
|
|
776
|
-
const aperture = cam.aperture ?? 0;
|
|
777
|
-
if (!(aperture > 0)) {
|
|
778
|
-
for (const l of this._layers3d) l.setBlur(0);
|
|
779
|
-
return;
|
|
780
|
-
}
|
|
781
|
-
const focusDepth = projectPoint(basis, { x: cam.lookAtX, y: cam.lookAtY, z: cam.focus ?? 0 }).depth;
|
|
782
|
-
if (!(focusDepth > NEAR)) {
|
|
783
|
-
if (!this._dofSaid.behind) {
|
|
784
|
-
this._dofSaid.behind = true;
|
|
785
|
-
console.warn(`pixi-effects: ${describeLayer(this.spec)}: the camera's focus (z = ${(cam.focus ?? 0).toFixed(0)}) is at or behind the camera, so nothing is blurred. Put focus in front of the camera (a z below the camera's z)`);
|
|
786
|
-
}
|
|
787
|
-
for (const l of this._layers3d) l.setBlur(0);
|
|
788
|
-
return;
|
|
789
|
-
}
|
|
790
|
-
let blurred = 0;
|
|
791
|
-
for (const l of this._layers3d) {
|
|
792
|
-
l.setBlur(l.display.visible ? blurRadius(aperture, basis.focal, l.depth, focusDepth) : 0);
|
|
793
|
-
if (l.blur > 0) blurred++;
|
|
794
|
-
}
|
|
795
|
-
if (blurred >= MANY_BLURRED && !this._dofSaid.many) {
|
|
796
|
-
this._dofSaid.many = true;
|
|
797
|
-
console.warn(`pixi-effects: ${describeLayer(this.spec)}: ${blurred} layers are blurred by depth of field at once; each costs a filter pass per frame (WebGPU more). Merge the far layers or lower aperture`);
|
|
798
|
-
}
|
|
799
|
-
}
|
|
800
|
-
collectAudio(out, baseTime) {
|
|
801
|
-
super.collectAudio(out, baseTime);
|
|
802
|
-
const remap = this._remap;
|
|
803
|
-
if (!remap) {
|
|
804
|
-
const childBase = baseTime + this.at;
|
|
805
|
-
for (const child of this._children) child.collectAudio(out, childBase);
|
|
806
|
-
return;
|
|
807
|
-
}
|
|
808
|
-
const inner = [];
|
|
809
|
-
for (const child of this._children) child.collectAudio(inner, 0);
|
|
810
|
-
const lo = baseTime + this.at, hi = lo + this.duration;
|
|
811
|
-
const table = clockTable(remap, "time", this.duration, lo, this.scope(), hi);
|
|
812
|
-
for (const d of inner) {
|
|
813
|
-
const prev = d.warp;
|
|
814
|
-
out.push({ ...d, warp: (t) => t < lo || t > hi ? NaN : prev ? prev(table.at(t)) : table.at(t) });
|
|
815
|
-
}
|
|
816
|
-
}
|
|
817
|
-
destroy() {
|
|
818
|
-
this._inner?.kill();
|
|
819
|
-
this._inner = null;
|
|
820
|
-
this._clock = null;
|
|
821
|
-
for (const l of this._layers3d) l.destroy();
|
|
822
|
-
this._layers3d = [];
|
|
823
|
-
for (const c of this._children) c.destroy();
|
|
824
|
-
for (const o of this._blendOwned) o.destroy();
|
|
825
|
-
this._blendOwned = [];
|
|
826
|
-
super.destroy();
|
|
827
|
-
}
|
|
828
|
-
};
|
|
829
|
-
function frameOf(child) {
|
|
830
|
-
if (child instanceof CompositionSequence) {
|
|
831
|
-
return () => ({ x: 0, y: 0, width: child.intrinsicWidth, height: child.intrinsicHeight });
|
|
832
|
-
}
|
|
833
|
-
return () => child.target.getLocalBounds();
|
|
834
|
-
}
|
|
835
|
-
|
|
836
|
-
export { CompositionSequence };
|
|
837
|
-
//# sourceMappingURL=chunk-UQDEDYVM.js.map
|
|
838
|
-
//# sourceMappingURL=chunk-UQDEDYVM.js.map
|