pixi-effects 0.18.1 → 0.20.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 +49 -0
- package/README.md +6 -6
- package/ai/CHAT.md +1 -1
- package/ai/SKILL.md +2 -1
- package/ai/chat-template.html +4 -4
- package/ai/reference/cheatsheet.md +10 -9
- package/ai/reference/pitfalls.md +9 -0
- package/ai/reference/recipes.md +117 -0
- package/ai/template.html +5 -5
- package/ai/tools/check.mjs +29 -6
- package/dist/{Base-BQUodYZK.d.ts → Base-CzfLGoDr.d.ts} +9 -1
- package/dist/{Base-OHqp8qvX.d.cts → Base-wYJQ2g5Q.d.cts} +9 -1
- package/dist/Composition-6PA4C4TV.js +5 -0
- package/dist/{Composition-MLBHYYFF.js.map → Composition-6PA4C4TV.js.map} +1 -1
- package/dist/Composition-LL2XXU5N.cjs +14 -0
- package/dist/{Composition-6JMXWNVV.cjs.map → Composition-LL2XXU5N.cjs.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-DlHQ9C02.d.ts → Movie-CBxGH5ms.d.ts} +13 -2
- package/dist/{Movie-K2YuVAdg.d.cts → Movie-CzzJw8A-.d.cts} +13 -2
- 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/{chunk-SG3Y66FN.js → chunk-DQHXVNOI.js} +1029 -64
- package/dist/chunk-DQHXVNOI.js.map +1 -0
- package/dist/{chunk-JW67MDHQ.cjs → chunk-FFYA3UBU.cjs} +144 -36
- package/dist/chunk-FFYA3UBU.cjs.map +1 -0
- package/dist/{chunk-DKGG7WD4.js → chunk-MNM56B3X.js} +6 -3
- package/dist/chunk-MNM56B3X.js.map +1 -0
- package/dist/{chunk-ANO5R2E6.cjs → chunk-NO26HWR7.cjs} +1036 -65
- package/dist/chunk-NO26HWR7.cjs.map +1 -0
- package/dist/{chunk-UXDR3ZDU.js → chunk-TSPMKV2F.js} +121 -13
- package/dist/chunk-TSPMKV2F.js.map +1 -0
- package/dist/{chunk-UQBGW5DO.cjs → chunk-WTRKDIKH.cjs} +6 -3
- package/dist/chunk-WTRKDIKH.cjs.map +1 -0
- package/dist/index.cjs +246 -96
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +4 -4
- package/dist/index.d.ts +4 -4
- package/dist/index.js +187 -37
- package/dist/index.js.map +1 -1
- package/dist/loader.css +1 -1
- package/dist/{music-4HDFULNR.js → music-CFEC7HKL.js} +3 -3
- package/dist/{music-4HDFULNR.js.map → music-CFEC7HKL.js.map} +1 -1
- package/dist/{music-3OF5C6X5.cjs → music-UAN7DXK4.cjs} +7 -7
- package/dist/{music-3OF5C6X5.cjs.map → music-UAN7DXK4.cjs.map} +1 -1
- package/dist/{sfx-MZJZXYY3.cjs → sfx-EX4PUBMV.cjs} +8 -8
- package/dist/{sfx-MZJZXYY3.cjs.map → sfx-EX4PUBMV.cjs.map} +1 -1
- package/dist/{sfx-S37DDC66.js → sfx-U3GM2MED.js} +3 -3
- package/dist/{sfx-S37DDC66.js.map → sfx-U3GM2MED.js.map} +1 -1
- package/dist/three.cjs +6 -6
- package/dist/three.d.cts +2 -2
- package/dist/three.d.ts +2 -2
- package/dist/three.js +2 -2
- package/dist/{types-SS51lP6O.d.ts → types-YmUaViL1.d.cts} +40 -6
- package/dist/{types-SS51lP6O.d.cts → types-YmUaViL1.d.ts} +40 -6
- package/docs/dsl.md +58 -5
- package/llms-full.txt +196 -15
- package/package.json +3 -1
- package/dist/Composition-6JMXWNVV.cjs +0 -14
- package/dist/Composition-MLBHYYFF.js +0 -5
- package/dist/chunk-ANO5R2E6.cjs.map +0 -1
- package/dist/chunk-DKGG7WD4.js.map +0 -1
- package/dist/chunk-JW67MDHQ.cjs.map +0 -1
- package/dist/chunk-SG3Y66FN.js.map +0 -1
- package/dist/chunk-UQBGW5DO.cjs.map +0 -1
- package/dist/chunk-UXDR3ZDU.js.map +0 -1
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
|
-
var
|
|
3
|
+
var chunkWTRKDIKH_cjs = require('./chunk-WTRKDIKH.cjs');
|
|
4
4
|
var PIXI = require('pixi.js');
|
|
5
5
|
var gsap = require('gsap');
|
|
6
6
|
|
|
@@ -58,6 +58,113 @@ function noise(x, seed = 0) {
|
|
|
58
58
|
const u = f * f * f * (f * (f * 6 - 15) + 10);
|
|
59
59
|
return a + (b - a) * u;
|
|
60
60
|
}
|
|
61
|
+
var SETTLE_TOL = 5e-3;
|
|
62
|
+
var DEFAULTS = { mass: 1, stiffness: 100, damping: 10 };
|
|
63
|
+
function springResponse(t, { mass: m, stiffness: k, damping: c }) {
|
|
64
|
+
if (t <= 0) return 0;
|
|
65
|
+
const w0 = Math.sqrt(k / m);
|
|
66
|
+
const zeta = c / (2 * Math.sqrt(k * m));
|
|
67
|
+
if (Math.abs(zeta - 1) < 1e-6) return 1 - Math.exp(-w0 * t) * (1 + w0 * t);
|
|
68
|
+
if (zeta < 1) {
|
|
69
|
+
const wd = w0 * Math.sqrt(1 - zeta * zeta);
|
|
70
|
+
return 1 - Math.exp(-zeta * w0 * t) * (Math.cos(wd * t) + zeta * w0 / wd * Math.sin(wd * t));
|
|
71
|
+
}
|
|
72
|
+
const s = w0 * Math.sqrt(zeta * zeta - 1);
|
|
73
|
+
const r1 = -zeta * w0 + s, r2 = -zeta * w0 - s;
|
|
74
|
+
return 1 - (r2 * Math.exp(r1 * t) - r1 * Math.exp(r2 * t)) / (r2 - r1);
|
|
75
|
+
}
|
|
76
|
+
function complete(p) {
|
|
77
|
+
return { mass: p.mass ?? DEFAULTS.mass, stiffness: p.stiffness ?? DEFAULTS.stiffness, damping: p.damping ?? DEFAULTS.damping };
|
|
78
|
+
}
|
|
79
|
+
function springDuration(params = {}, tol = SETTLE_TOL) {
|
|
80
|
+
const p = complete(params);
|
|
81
|
+
const w0 = Math.sqrt(p.stiffness / p.mass);
|
|
82
|
+
const zeta = p.damping / (2 * Math.sqrt(p.stiffness * p.mass));
|
|
83
|
+
const bad = (t) => Math.abs(1 - springResponse(t, p)) > tol;
|
|
84
|
+
let lo, hi;
|
|
85
|
+
if (zeta < 1 - 1e-6) {
|
|
86
|
+
const wd = w0 * Math.sqrt(1 - zeta * zeta);
|
|
87
|
+
const decay = Math.PI * zeta / Math.sqrt(1 - zeta * zeta);
|
|
88
|
+
const n = Math.max(1, Math.ceil(Math.log(1 / tol) / decay));
|
|
89
|
+
lo = (n - 1) * Math.PI / wd;
|
|
90
|
+
hi = n * Math.PI / wd;
|
|
91
|
+
} else {
|
|
92
|
+
lo = 0;
|
|
93
|
+
hi = 1 / w0;
|
|
94
|
+
while (bad(hi)) {
|
|
95
|
+
lo = hi;
|
|
96
|
+
hi *= 2;
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
for (let i = 0; i < 60; i++) {
|
|
100
|
+
const mid = (lo + hi) / 2;
|
|
101
|
+
if (bad(mid)) lo = mid;
|
|
102
|
+
else hi = mid;
|
|
103
|
+
}
|
|
104
|
+
return hi;
|
|
105
|
+
}
|
|
106
|
+
function springEase(params = {}) {
|
|
107
|
+
const sp = complete(params);
|
|
108
|
+
const T = springDuration(sp);
|
|
109
|
+
const end = springResponse(T, sp);
|
|
110
|
+
return (p) => p <= 0 ? 0 : p >= 1 ? 1 : springResponse(p * T, sp) / end;
|
|
111
|
+
}
|
|
112
|
+
var SPRING_PRESETS = {
|
|
113
|
+
gentle: { mass: 1, stiffness: 100, damping: 15 },
|
|
114
|
+
// zeta .75, one soft overshoot
|
|
115
|
+
snappy: { mass: 1, stiffness: 300, damping: 28 },
|
|
116
|
+
// zeta .81, quick, barely rings
|
|
117
|
+
bouncy: { mass: 1, stiffness: 170, damping: 10 },
|
|
118
|
+
// zeta .38
|
|
119
|
+
wobbly: { mass: 1, stiffness: 120, damping: 6 },
|
|
120
|
+
// zeta .27, rings several times
|
|
121
|
+
slow: { mass: 1, stiffness: 60, damping: 18 }
|
|
122
|
+
// zeta 1.16, no overshoot
|
|
123
|
+
};
|
|
124
|
+
var SPRING_RE = /^spring(?:\.(\w+)|\(([^)]*)\))?$/;
|
|
125
|
+
function springProblem(name) {
|
|
126
|
+
const m = SPRING_RE.exec(name.trim());
|
|
127
|
+
if (!m) return 'expected "spring(mass, stiffness, damping)" or "spring.<preset>"';
|
|
128
|
+
if (m[1] && !SPRING_PRESETS[m[1]]) return `no preset "${m[1]}" (presets: ${Object.keys(SPRING_PRESETS).join(", ")})`;
|
|
129
|
+
if (m[2] !== void 0 && m[2].trim() !== "") {
|
|
130
|
+
const nums = m[2].split(",").map((s) => Number(s.trim()));
|
|
131
|
+
if (nums.length > 3 || nums.some((n) => !Number.isFinite(n) || n <= 0)) return "mass, stiffness and damping must be 1 to 3 numbers greater than 0";
|
|
132
|
+
}
|
|
133
|
+
return null;
|
|
134
|
+
}
|
|
135
|
+
function parseSpring(name) {
|
|
136
|
+
if (typeof name !== "string" || !/^\s*spring/.test(name) || springProblem(name)) return null;
|
|
137
|
+
const m = SPRING_RE.exec(name.trim());
|
|
138
|
+
if (m[1]) return SPRING_PRESETS[m[1]];
|
|
139
|
+
const [mass, stiffness, damping] = (m[2] ?? "").split(",").map((s) => s.trim()).filter(Boolean).map(Number);
|
|
140
|
+
return complete({ mass, stiffness, damping });
|
|
141
|
+
}
|
|
142
|
+
var registered = false;
|
|
143
|
+
function registerSpringEases() {
|
|
144
|
+
if (registered) return;
|
|
145
|
+
registered = true;
|
|
146
|
+
const base = springEase();
|
|
147
|
+
const ease = (p) => base(p);
|
|
148
|
+
ease.config = (mass, stiffness, damping) => {
|
|
149
|
+
const bad = [mass, stiffness, damping].some((v) => v !== void 0 && !(typeof v === "number" && v > 0 && Number.isFinite(v)));
|
|
150
|
+
return springEase(bad ? {} : { mass, stiffness, damping });
|
|
151
|
+
};
|
|
152
|
+
gsap.gsap.registerEase("spring", ease);
|
|
153
|
+
for (const [name, p] of Object.entries(SPRING_PRESETS)) gsap.gsap.registerEase(`spring.${name}`, springEase(p));
|
|
154
|
+
}
|
|
155
|
+
var autoWarned = /* @__PURE__ */ new Set();
|
|
156
|
+
function kfDuration(kf) {
|
|
157
|
+
if (kf.duration !== "auto") return kf.duration ?? 0;
|
|
158
|
+
const sp = parseSpring(kf.ease);
|
|
159
|
+
if (sp) return Math.round(springDuration(sp) * 1e3) / 1e3;
|
|
160
|
+
const name = String(kf.ease ?? "none");
|
|
161
|
+
if (!/^\s*spring/.test(name) && !autoWarned.has(name)) {
|
|
162
|
+
autoWarned.add(name);
|
|
163
|
+
console.warn(`pixi-effects: keyframe duration 'auto' needs a spring ease (ease: 'spring(1, 170, 12)' or 'spring.bouncy'), got ease ${JSON.stringify(name)} \u2014 using 0.5 s.`);
|
|
164
|
+
}
|
|
165
|
+
return 0.5;
|
|
166
|
+
}
|
|
167
|
+
registerSpringEases();
|
|
61
168
|
|
|
62
169
|
// src/expr/Parser.ts
|
|
63
170
|
var FUNCS = {
|
|
@@ -310,11 +417,77 @@ function looksLikeColorString(s) {
|
|
|
310
417
|
if (s.charCodeAt(0) === 35) return true;
|
|
311
418
|
return /^(rgb|hsl|oklab|oklch|lab|lch)\b/i.test(s);
|
|
312
419
|
}
|
|
420
|
+
function cubicBezierEase(x1, y1, x2, y2) {
|
|
421
|
+
const cx = 3 * x1, bx = 3 * (x2 - x1) - cx, ax = 1 - cx - bx;
|
|
422
|
+
const cy = 3 * y1, by = 3 * (y2 - y1) - cy, ay = 1 - cy - by;
|
|
423
|
+
const X = (t) => ((ax * t + bx) * t + cx) * t;
|
|
424
|
+
const Y = (t) => ((ay * t + by) * t + cy) * t;
|
|
425
|
+
const dX = (t) => (3 * ax * t + 2 * bx) * t + cx;
|
|
426
|
+
return (p) => {
|
|
427
|
+
if (p <= 0) return 0;
|
|
428
|
+
if (p >= 1) return 1;
|
|
429
|
+
let t = p;
|
|
430
|
+
for (let i = 0; i < 8; i++) {
|
|
431
|
+
const err = X(t) - p;
|
|
432
|
+
if (Math.abs(err) < 1e-9) return Y(t);
|
|
433
|
+
const d = dX(t);
|
|
434
|
+
if (Math.abs(d) < 1e-6) break;
|
|
435
|
+
t -= err / d;
|
|
436
|
+
}
|
|
437
|
+
let lo = 0, hi = 1;
|
|
438
|
+
t = p;
|
|
439
|
+
for (let i = 0; i < 60; i++) {
|
|
440
|
+
const x = X(t);
|
|
441
|
+
if (Math.abs(x - p) < 1e-10) break;
|
|
442
|
+
if (x < p) lo = t;
|
|
443
|
+
else hi = t;
|
|
444
|
+
t = (lo + hi) / 2;
|
|
445
|
+
}
|
|
446
|
+
return Y(t);
|
|
447
|
+
};
|
|
448
|
+
}
|
|
449
|
+
var NUM = String.raw`\s*(-?(?:\d+\.?\d*|\.\d+)(?:e[-+]?\d+)?)\s*`;
|
|
450
|
+
var RE = new RegExp(`^\\s*cubic-bezier\\(${NUM},${NUM},${NUM},${NUM}\\)\\s*$`, "i");
|
|
451
|
+
function cubicBezierProblem(name) {
|
|
452
|
+
const m = RE.exec(name);
|
|
453
|
+
if (!m) return 'expected "cubic-bezier(x1, y1, x2, y2)" with four numbers, like CSS';
|
|
454
|
+
const x1 = Number(m[1]), x2 = Number(m[3]);
|
|
455
|
+
if (x1 < 0 || x1 > 1 || x2 < 0 || x2 > 1) return "x1 and x2 must be between 0 and 1 (y1 and y2 may overshoot)";
|
|
456
|
+
return null;
|
|
457
|
+
}
|
|
458
|
+
var registered2 = false;
|
|
459
|
+
function registerCubicBezierEase() {
|
|
460
|
+
if (registered2) return;
|
|
461
|
+
registered2 = true;
|
|
462
|
+
const base = ((p) => p);
|
|
463
|
+
base.config = (x1, y1, x2, y2) => {
|
|
464
|
+
const bad = [x1, y1, x2, y2].some((v) => typeof v !== "number" || !Number.isFinite(v)) || x1 < 0 || x1 > 1 || x2 < 0 || x2 > 1;
|
|
465
|
+
return bad ? (p) => p : cubicBezierEase(x1, y1, x2, y2);
|
|
466
|
+
};
|
|
467
|
+
gsap.gsap.registerEase("cubic-bezier", base);
|
|
468
|
+
}
|
|
469
|
+
registerCubicBezierEase();
|
|
470
|
+
|
|
471
|
+
// src/core/ease.ts
|
|
313
472
|
var FAMILIES = ["power1", "power2", "power3", "power4", "back", "elastic", "bounce", "circ", "expo", "sine"];
|
|
314
473
|
var EASE_NAMES = ["none", ...FAMILIES.flatMap((f) => [`${f}.in`, `${f}.out`, `${f}.inOut`])];
|
|
315
474
|
var warned = /* @__PURE__ */ new Set();
|
|
316
475
|
function checkEase(ease, where) {
|
|
317
476
|
if (typeof ease !== "string") return;
|
|
477
|
+
if (/^\s*spring/.test(ease)) {
|
|
478
|
+
const problem = springProblem(ease);
|
|
479
|
+
if (!problem || warned.has(ease)) return;
|
|
480
|
+
warned.add(ease);
|
|
481
|
+
console.warn(`pixi-effects: ${where}: unknown ease "${ease}" \u2014 ${problem}. GSAP would run it as its default ease, power1.out.`);
|
|
482
|
+
return;
|
|
483
|
+
}
|
|
484
|
+
if (/^\s*cubic-bezier/i.test(ease)) {
|
|
485
|
+
const problem = cubicBezierProblem(ease);
|
|
486
|
+
if (!problem || warned.has(ease)) return;
|
|
487
|
+
warned.add(ease);
|
|
488
|
+
console.warn(`pixi-effects: ${where}: unknown ease "${ease}" \u2014 ${problem}. It runs as 'none' (a straight line).`);
|
|
489
|
+
return;
|
|
490
|
+
}
|
|
318
491
|
const found = gsap.gsap.parseEase(ease);
|
|
319
492
|
if (typeof found === "function") return;
|
|
320
493
|
if (warned.has(ease)) return;
|
|
@@ -327,7 +500,7 @@ function checkEase(ease, where) {
|
|
|
327
500
|
console.warn(`pixi-effects: ${where}: "${ease}" is a family, not an ease \u2014 write ${ease.toLowerCase()}.out, ${ease.toLowerCase()}.in or ${ease.toLowerCase()}.inOut`);
|
|
328
501
|
return;
|
|
329
502
|
}
|
|
330
|
-
const guess =
|
|
503
|
+
const guess = chunkWTRKDIKH_cjs.suggestName(ease, EASE_NAMES);
|
|
331
504
|
console.warn(`pixi-effects: ${where}: unknown ease "${ease}"${guess ? ` \u2014 did you mean "${guess}"?` : ""} (GSAP would run it as its default ease, power1.out). Examples: ${EASE_NAMES.slice(0, 7).join(", ")}, back.out(1.7), elastic.out(1, 0.3), steps(8)`);
|
|
332
505
|
}
|
|
333
506
|
|
|
@@ -355,7 +528,7 @@ function resolveAt(at, duration) {
|
|
|
355
528
|
}
|
|
356
529
|
function normalizeKeyframe(kf, parentDuration) {
|
|
357
530
|
const at = resolveAt(kf.at, parentDuration);
|
|
358
|
-
const duration = kf
|
|
531
|
+
const duration = kfDuration(kf);
|
|
359
532
|
const ease = kf.ease ?? "none";
|
|
360
533
|
checkEase(ease, "a keyframe");
|
|
361
534
|
const hasSet = !!kf.set;
|
|
@@ -785,8 +958,217 @@ var ChromaKeyFilter = class extends PIXI.Filter {
|
|
|
785
958
|
u[2] = rgb[2];
|
|
786
959
|
}
|
|
787
960
|
};
|
|
961
|
+
var HASH_GL = `
|
|
962
|
+
uint hash(uint x) { x ^= x >> 16; x *= 0x7feb352du; x ^= x >> 15; x *= 0x846ca68bu; x ^= x >> 16; return x; }
|
|
963
|
+
// one gaussian-ish value (sum of the four bytes of a hash), mean 0, std 1
|
|
964
|
+
float gauss(ivec2 p, uint k) {
|
|
965
|
+
uint h = hash(uint(p.x) + hash(uint(p.y) + hash(k)));
|
|
966
|
+
float s = float(h & 255u) + float((h >> 8) & 255u) + float((h >> 16) & 255u) + float(h >> 24);
|
|
967
|
+
return (s / 255.0 - 2.0) * 1.7320508;
|
|
968
|
+
}
|
|
969
|
+
// the grain value at a pixel: cells of size pixels, smoothly blended
|
|
970
|
+
float cell(vec2 pos, float size, uint k) {
|
|
971
|
+
vec2 q = pos / size - 0.5;
|
|
972
|
+
vec2 i = floor(q);
|
|
973
|
+
vec2 f = fract(q);
|
|
974
|
+
ivec2 p = ivec2(i);
|
|
975
|
+
float a = gauss(p, k), b = gauss(p + ivec2(1, 0), k), c = gauss(p + ivec2(0, 1), k), d = gauss(p + ivec2(1, 1), k);
|
|
976
|
+
float v = mix(mix(a, b, f.x), mix(c, d, f.x), f.y);
|
|
977
|
+
vec2 wx = vec2(1.0 - f.x, f.x), wy = vec2(1.0 - f.y, f.y);
|
|
978
|
+
return v * inversesqrt(dot(wx, wx) * dot(wy, wy)); // blending lowers the spread: keep std exactly 1 at every pixel
|
|
979
|
+
}`;
|
|
980
|
+
var GL_VERTEX = `#version 300 es
|
|
981
|
+
in vec2 aPosition;
|
|
982
|
+
out vec2 vTextureCoord;
|
|
983
|
+
uniform vec4 uInputSize;
|
|
984
|
+
uniform vec4 uOutputFrame;
|
|
985
|
+
uniform vec4 uOutputTexture;
|
|
986
|
+
void main(void) {
|
|
987
|
+
vec2 position = aPosition * uOutputFrame.zw + uOutputFrame.xy;
|
|
988
|
+
position.x = position.x * (2.0 / uOutputTexture.x) - 1.0;
|
|
989
|
+
position.y = position.y * (2.0 * uOutputTexture.z / uOutputTexture.y) - uOutputTexture.z;
|
|
990
|
+
gl_Position = vec4(position, 0.0, 1.0);
|
|
991
|
+
vTextureCoord = aPosition * (uOutputFrame.zw * uInputSize.zw);
|
|
992
|
+
}`;
|
|
993
|
+
var GL_FRAGMENT2 = `#version 300 es
|
|
994
|
+
precision highp float;
|
|
995
|
+
precision highp int;
|
|
996
|
+
in vec2 vTextureCoord;
|
|
997
|
+
uniform sampler2D uTexture;
|
|
998
|
+
uniform vec4 uInputSize;
|
|
999
|
+
uniform float uAmount;
|
|
1000
|
+
uniform float uSize;
|
|
1001
|
+
uniform float uSeed;
|
|
1002
|
+
uniform float uFrame;
|
|
1003
|
+
uniform float uColor;
|
|
1004
|
+
out vec4 finalColor;
|
|
1005
|
+
${HASH_GL}
|
|
1006
|
+
void main(void) {
|
|
1007
|
+
vec4 raw = texture(uTexture, vTextureCoord);
|
|
1008
|
+
vec3 rgb = raw.a > 0.0 ? raw.rgb / raw.a : vec3(0.0);
|
|
1009
|
+
float L = dot(rgb, vec3(0.2126, 0.7152, 0.0722));
|
|
1010
|
+
float w = clamp(4.0 * L * (1.0 - L), 0.0, 1.0);
|
|
1011
|
+
vec2 pos = vTextureCoord * uInputSize.xy;
|
|
1012
|
+
uint k = hash(uint(uSeed) * 0x9E3779B1u + uint(uFrame));
|
|
1013
|
+
float n0 = cell(pos, uSize, k);
|
|
1014
|
+
vec3 n = vec3(n0);
|
|
1015
|
+
if (uColor > 0.0) {
|
|
1016
|
+
vec3 nc = vec3(cell(pos, uSize, k + 1u), cell(pos, uSize, k + 2u), cell(pos, uSize, k + 3u));
|
|
1017
|
+
n = mix(n, nc, uColor);
|
|
1018
|
+
}
|
|
1019
|
+
rgb = clamp(rgb + n * (uAmount * w), 0.0, 1.0);
|
|
1020
|
+
finalColor = vec4(rgb * raw.a, raw.a);
|
|
1021
|
+
}`;
|
|
1022
|
+
var WGSL_SOURCE2 = `
|
|
1023
|
+
struct GlobalFilterUniforms {
|
|
1024
|
+
uInputSize: vec4<f32>,
|
|
1025
|
+
uInputPixel: vec4<f32>,
|
|
1026
|
+
uInputClamp: vec4<f32>,
|
|
1027
|
+
uOutputFrame: vec4<f32>,
|
|
1028
|
+
uGlobalFrame: vec4<f32>,
|
|
1029
|
+
uOutputTexture: vec4<f32>,
|
|
1030
|
+
};
|
|
1031
|
+
struct GrainUniforms {
|
|
1032
|
+
uAmount: f32,
|
|
1033
|
+
uSize: f32,
|
|
1034
|
+
uSeed: f32,
|
|
1035
|
+
uFrame: f32,
|
|
1036
|
+
uColor: f32,
|
|
1037
|
+
};
|
|
1038
|
+
@group(0) @binding(0) var<uniform> gfu: GlobalFilterUniforms;
|
|
1039
|
+
@group(0) @binding(1) var uTexture: texture_2d<f32>;
|
|
1040
|
+
@group(0) @binding(2) var uSampler : sampler;
|
|
1041
|
+
@group(1) @binding(0) var<uniform> grainUniforms : GrainUniforms;
|
|
1042
|
+
|
|
1043
|
+
struct VSOutput {
|
|
1044
|
+
@builtin(position) position: vec4<f32>,
|
|
1045
|
+
@location(0) uv : vec2<f32>,
|
|
1046
|
+
};
|
|
1047
|
+
fn filterVertexPosition(aPosition : vec2<f32>) -> vec4<f32> {
|
|
1048
|
+
var position = aPosition * gfu.uOutputFrame.zw + gfu.uOutputFrame.xy;
|
|
1049
|
+
position.x = position.x * (2.0 / gfu.uOutputTexture.x) - 1.0;
|
|
1050
|
+
position.y = position.y * (2.0 * gfu.uOutputTexture.z / gfu.uOutputTexture.y) - gfu.uOutputTexture.z;
|
|
1051
|
+
return vec4<f32>(position, 0.0, 1.0);
|
|
1052
|
+
}
|
|
1053
|
+
fn filterTextureCoord(aPosition : vec2<f32>) -> vec2<f32> {
|
|
1054
|
+
return aPosition * (gfu.uOutputFrame.zw * gfu.uInputSize.zw);
|
|
1055
|
+
}
|
|
1056
|
+
@vertex
|
|
1057
|
+
fn mainVertex(
|
|
1058
|
+
@location(0) aPosition : vec2<f32>,
|
|
1059
|
+
) -> VSOutput {
|
|
1060
|
+
return VSOutput(
|
|
1061
|
+
filterVertexPosition(aPosition),
|
|
1062
|
+
filterTextureCoord(aPosition),
|
|
1063
|
+
);
|
|
1064
|
+
}
|
|
1065
|
+
|
|
1066
|
+
fn hash(xIn: u32) -> u32 {
|
|
1067
|
+
var x = xIn;
|
|
1068
|
+
x = x ^ (x >> 16u); x = x * 0x7feb352du; x = x ^ (x >> 15u); x = x * 0x846ca68bu; x = x ^ (x >> 16u);
|
|
1069
|
+
return x;
|
|
1070
|
+
}
|
|
1071
|
+
fn gauss(p: vec2<i32>, k: u32) -> f32 {
|
|
1072
|
+
let h = hash(u32(p.x) + hash(u32(p.y) + hash(k)));
|
|
1073
|
+
let s = f32(h & 255u) + f32((h >> 8u) & 255u) + f32((h >> 16u) & 255u) + f32(h >> 24u);
|
|
1074
|
+
return (s / 255.0 - 2.0) * 1.7320508;
|
|
1075
|
+
}
|
|
1076
|
+
fn cell(pos: vec2<f32>, size: f32, k: u32) -> f32 {
|
|
1077
|
+
let q = pos / size - vec2<f32>(0.5);
|
|
1078
|
+
let i = floor(q);
|
|
1079
|
+
let f = fract(q);
|
|
1080
|
+
let p = vec2<i32>(i);
|
|
1081
|
+
let a = gauss(p, k);
|
|
1082
|
+
let b = gauss(p + vec2<i32>(1, 0), k);
|
|
1083
|
+
let c = gauss(p + vec2<i32>(0, 1), k);
|
|
1084
|
+
let d = gauss(p + vec2<i32>(1, 1), k);
|
|
1085
|
+
let v = mix(mix(a, b, f.x), mix(c, d, f.x), f.y);
|
|
1086
|
+
let wx = vec2<f32>(1.0 - f.x, f.x);
|
|
1087
|
+
let wy = vec2<f32>(1.0 - f.y, f.y);
|
|
1088
|
+
return v * inverseSqrt(dot(wx, wx) * dot(wy, wy));
|
|
1089
|
+
}
|
|
1090
|
+
|
|
1091
|
+
@fragment
|
|
1092
|
+
fn mainFragment(@location(0) uv : vec2<f32>) -> @location(0) vec4<f32> {
|
|
1093
|
+
let raw = textureSample(uTexture, uSampler, uv);
|
|
1094
|
+
var rgb = vec3<f32>(0.0);
|
|
1095
|
+
if (raw.a > 0.0) { rgb = raw.rgb / raw.a; }
|
|
1096
|
+
let L = dot(rgb, vec3<f32>(0.2126, 0.7152, 0.0722));
|
|
1097
|
+
let w = clamp(4.0 * L * (1.0 - L), 0.0, 1.0);
|
|
1098
|
+
let pos = uv * gfu.uInputSize.xy;
|
|
1099
|
+
let k = hash(u32(grainUniforms.uSeed) * 0x9E3779B1u + u32(grainUniforms.uFrame));
|
|
1100
|
+
let n0 = cell(pos, grainUniforms.uSize, k);
|
|
1101
|
+
var n = vec3<f32>(n0);
|
|
1102
|
+
if (grainUniforms.uColor > 0.0) {
|
|
1103
|
+
let nc = vec3<f32>(cell(pos, grainUniforms.uSize, k + 1u), cell(pos, grainUniforms.uSize, k + 2u), cell(pos, grainUniforms.uSize, k + 3u));
|
|
1104
|
+
n = mix(n, nc, grainUniforms.uColor);
|
|
1105
|
+
}
|
|
1106
|
+
rgb = clamp(rgb + n * (grainUniforms.uAmount * w), vec3<f32>(0.0), vec3<f32>(1.0));
|
|
1107
|
+
return vec4<f32>(rgb * raw.a, raw.a);
|
|
1108
|
+
}`;
|
|
1109
|
+
var GRAIN_KEYS = ["amount", "size", "seed", "fps", "color"];
|
|
1110
|
+
var GrainFilter = class extends PIXI.Filter {
|
|
1111
|
+
_fps;
|
|
1112
|
+
constructor(options = {}) {
|
|
1113
|
+
chunkWTRKDIKH_cjs.warnUnknownOptions("grain filter", options, GRAIN_KEYS);
|
|
1114
|
+
const { amount = 0.08, size = 1.5, seed = 0, fps = 24, color = 0 } = options;
|
|
1115
|
+
super({
|
|
1116
|
+
glProgram: PIXI.GlProgram.from({ vertex: GL_VERTEX, fragment: GL_FRAGMENT2, name: "grain-filter" }),
|
|
1117
|
+
gpuProgram: PIXI.GpuProgram.from({ vertex: { source: WGSL_SOURCE2, entryPoint: "mainVertex" }, fragment: { source: WGSL_SOURCE2, entryPoint: "mainFragment" } }),
|
|
1118
|
+
resources: {
|
|
1119
|
+
grainUniforms: new PIXI.UniformGroup({
|
|
1120
|
+
uAmount: { value: amount, type: "f32" },
|
|
1121
|
+
uSize: { value: Math.max(size, 0.25), type: "f32" },
|
|
1122
|
+
uSeed: { value: Math.floor(seed), type: "f32" },
|
|
1123
|
+
uFrame: { value: 0, type: "f32" },
|
|
1124
|
+
uColor: { value: color, type: "f32" }
|
|
1125
|
+
})
|
|
1126
|
+
}
|
|
1127
|
+
});
|
|
1128
|
+
this._fps = fps;
|
|
1129
|
+
}
|
|
1130
|
+
get u() {
|
|
1131
|
+
return this.resources.grainUniforms.uniforms;
|
|
1132
|
+
}
|
|
1133
|
+
get amount() {
|
|
1134
|
+
return this.u.uAmount;
|
|
1135
|
+
}
|
|
1136
|
+
set amount(v) {
|
|
1137
|
+
this.u.uAmount = v;
|
|
1138
|
+
}
|
|
1139
|
+
get size() {
|
|
1140
|
+
return this.u.uSize;
|
|
1141
|
+
}
|
|
1142
|
+
set size(v) {
|
|
1143
|
+
this.u.uSize = Math.max(v, 0.25);
|
|
1144
|
+
}
|
|
1145
|
+
get seed() {
|
|
1146
|
+
return this.u.uSeed;
|
|
1147
|
+
}
|
|
1148
|
+
set seed(v) {
|
|
1149
|
+
this.u.uSeed = Math.floor(v);
|
|
1150
|
+
}
|
|
1151
|
+
get color() {
|
|
1152
|
+
return this.u.uColor;
|
|
1153
|
+
}
|
|
1154
|
+
set color(v) {
|
|
1155
|
+
this.u.uColor = v;
|
|
1156
|
+
}
|
|
1157
|
+
get fps() {
|
|
1158
|
+
return this._fps;
|
|
1159
|
+
}
|
|
1160
|
+
set fps(v) {
|
|
1161
|
+
this._fps = v;
|
|
1162
|
+
}
|
|
1163
|
+
/** The movie calls this with the time (s) of the frame it is about to draw: the grain is new every 1/fps s. */
|
|
1164
|
+
setTime(t) {
|
|
1165
|
+
this.u.uFrame = this._fps > 0 ? Math.floor(t * this._fps + 1e-3) : 0;
|
|
1166
|
+
}
|
|
1167
|
+
};
|
|
1168
|
+
|
|
1169
|
+
// src/filters/named.ts
|
|
788
1170
|
var CORE = { blur: "BlurFilter", noise: "NoiseFilter", alpha: "AlphaFilter" };
|
|
789
|
-
var CORE_TYPES = [...Object.keys(CORE), "colorMatrix"];
|
|
1171
|
+
var CORE_TYPES = [...Object.keys(CORE), "colorMatrix", "grain"];
|
|
790
1172
|
var LIBRARY_TYPES = [
|
|
791
1173
|
"adjustment",
|
|
792
1174
|
"advancedBloom",
|
|
@@ -836,7 +1218,7 @@ function isNamedFilterType(t) {
|
|
|
836
1218
|
return !NOT_NAMED.has(t);
|
|
837
1219
|
}
|
|
838
1220
|
function unknownType(t) {
|
|
839
|
-
const guess =
|
|
1221
|
+
const guess = chunkWTRKDIKH_cjs.suggestName(t, FILTER_TYPES);
|
|
840
1222
|
return new Error(`pixi-effects: unknown filter type "${t}"${guess ? ` \u2014 did you mean "${guess}"?` : ""} (valid: ${[...FILTER_TYPES, "chromaKey", "custom"].join(", ")})`);
|
|
841
1223
|
}
|
|
842
1224
|
var library = null;
|
|
@@ -885,7 +1267,7 @@ function colorMatrix(params) {
|
|
|
885
1267
|
const preset = params.preset;
|
|
886
1268
|
if (preset !== void 0) {
|
|
887
1269
|
if (!MATRIX_PRESETS.includes(preset)) {
|
|
888
|
-
const guess =
|
|
1270
|
+
const guess = chunkWTRKDIKH_cjs.suggestName(preset, MATRIX_PRESETS);
|
|
889
1271
|
throw new Error(`pixi-effects: colorMatrix preset "${preset}" is not one of ${MATRIX_PRESETS.join(", ")}${guess ? ` \u2014 did you mean "${guess}"?` : ""}`);
|
|
890
1272
|
}
|
|
891
1273
|
f[preset === "grayscale" ? "desaturate" : preset].call(f);
|
|
@@ -903,6 +1285,7 @@ function colorGradientParams(params) {
|
|
|
903
1285
|
}
|
|
904
1286
|
function createNamedFilter(type, params) {
|
|
905
1287
|
if (lower(type) === "colormatrix") return colorMatrix(params);
|
|
1288
|
+
if (lower(type) === "grain") return new GrainFilter(params);
|
|
906
1289
|
const core = Object.entries(CORE).find(([k]) => lower(k) === lower(type));
|
|
907
1290
|
if (core) return new PIXI__namespace[core[1]](params);
|
|
908
1291
|
if (!isLibraryType(type)) throw unknownType(type);
|
|
@@ -994,13 +1377,21 @@ var Sequence = class {
|
|
|
994
1377
|
pathRouters() {
|
|
995
1378
|
return {};
|
|
996
1379
|
}
|
|
1380
|
+
/**
|
|
1381
|
+
* The `initial` and `keyframes` that go onto the display object. A layer whose `time` runs a clock (video, composition) takes `time`
|
|
1382
|
+
* out of them: it is not a property of the display object.
|
|
1383
|
+
*/
|
|
1384
|
+
displayProps() {
|
|
1385
|
+
return { initial: this.spec.initial, keyframes: this.spec.keyframes };
|
|
1386
|
+
}
|
|
997
1387
|
bindTimeline(timeline, offset = 0) {
|
|
998
1388
|
if (!this.target) return;
|
|
999
1389
|
const scope = this.scope();
|
|
1000
1390
|
const routers = this.pathRouters();
|
|
1001
1391
|
const startTime = offset + this.at;
|
|
1002
|
-
|
|
1003
|
-
|
|
1392
|
+
const { initial, keyframes } = this.displayProps();
|
|
1393
|
+
applyInitial(this.target, initial, scope, [], routers);
|
|
1394
|
+
applyKeyframes(timeline, this.target, keyframes, this.duration, scope, [], startTime, routers);
|
|
1004
1395
|
const endTime = startTime + this.duration;
|
|
1005
1396
|
this.absoluteStart = startTime;
|
|
1006
1397
|
if (this.keepHidden) return;
|
|
@@ -1051,6 +1442,141 @@ function collectPropKeys(spec) {
|
|
|
1051
1442
|
return out;
|
|
1052
1443
|
}
|
|
1053
1444
|
|
|
1445
|
+
// src/core/layerKeys.ts
|
|
1446
|
+
var COMMON = ["type", "name", "parent", "at", "duration", "initial", "keyframes", "filters", "filterArea", "mask", "maskInverted", "blendMode", "threeD", "hideBehindCamera"];
|
|
1447
|
+
var VIDEO = [...COMMON, "asset", "loop", "audio", "volume", "speed"];
|
|
1448
|
+
var IMAGE = [...COMMON, "asset", "colorSpace"];
|
|
1449
|
+
var TEXT = [...COMMON, "text", "format", "style", "colorSpace", "fillGradient"];
|
|
1450
|
+
var AUDIO = [...COMMON, "volume", "asset", "loop", "sfx", "music", "speed"];
|
|
1451
|
+
var COMPOSITION = [...COMMON, "width", "height", "sequences", "transitions", "speed"];
|
|
1452
|
+
var CAMERA = [...COMMON];
|
|
1453
|
+
var NULL = [...COMMON];
|
|
1454
|
+
var SHAPE = [...COMMON, "shape", "fillGradient", "colorSpace", "strokeCap", "strokeJoin"];
|
|
1455
|
+
var TRIM = ["trimStart", "trimEnd", "trimEach"];
|
|
1456
|
+
var RECT = [...SHAPE, ...TRIM, "width", "height", "cornerRadius", "anchorX", "anchorY"];
|
|
1457
|
+
var CIRCLE = [...SHAPE, ...TRIM, "radius", "anchorX", "anchorY"];
|
|
1458
|
+
var ELLIPSE = [...SHAPE, ...TRIM, "radiusX", "radiusY", "anchorX", "anchorY"];
|
|
1459
|
+
var ARC = [...SHAPE, "radius", "innerRadius", "startAngle", "endAngle"];
|
|
1460
|
+
var LINE = [...SHAPE, ...TRIM, "from", "to"];
|
|
1461
|
+
var POLYGON = [...SHAPE, ...TRIM, "points", "open"];
|
|
1462
|
+
var PATH = [...SHAPE, ...TRIM, "d", "morphTo", "morph", "morphPoints"];
|
|
1463
|
+
var SHAPES = { rect: RECT, circle: CIRCLE, ellipse: ELLIPSE, arc: ARC, line: LINE, polygon: POLYGON, path: PATH };
|
|
1464
|
+
var BY_TYPE = { video: VIDEO, image: IMAGE, text: TEXT, audio: AUDIO, composition: COMPOSITION, camera: CAMERA, null: NULL };
|
|
1465
|
+
function kindName(spec) {
|
|
1466
|
+
return spec.type === "shape" && spec.shape ? `${spec.shape} shape` : `${spec.type} layer`;
|
|
1467
|
+
}
|
|
1468
|
+
function layerKeys(spec) {
|
|
1469
|
+
if (spec.type === "shape") return spec.shape && SHAPES[spec.shape] || null;
|
|
1470
|
+
return BY_TYPE[spec.type] ?? null;
|
|
1471
|
+
}
|
|
1472
|
+
function kindsWithKey(key) {
|
|
1473
|
+
const out = [];
|
|
1474
|
+
for (const [shape, keys] of Object.entries(SHAPES)) if (keys.includes(key)) out.push(`${shape} shape`);
|
|
1475
|
+
for (const [type, keys] of Object.entries(BY_TYPE)) if (keys.includes(key)) out.push(`${type} layer`);
|
|
1476
|
+
return out;
|
|
1477
|
+
}
|
|
1478
|
+
var PROP_KEYS = /* @__PURE__ */ new Set([
|
|
1479
|
+
// transform and look (GSAP + PixiPlugin names)
|
|
1480
|
+
"x",
|
|
1481
|
+
"y",
|
|
1482
|
+
"z",
|
|
1483
|
+
"alpha",
|
|
1484
|
+
"rotation",
|
|
1485
|
+
"rotationX",
|
|
1486
|
+
"rotationY",
|
|
1487
|
+
"width",
|
|
1488
|
+
"height",
|
|
1489
|
+
"visible",
|
|
1490
|
+
"autoAlpha",
|
|
1491
|
+
"scale",
|
|
1492
|
+
"scaleX",
|
|
1493
|
+
"scaleY",
|
|
1494
|
+
"anchor",
|
|
1495
|
+
"anchorX",
|
|
1496
|
+
"anchorY",
|
|
1497
|
+
"pivot",
|
|
1498
|
+
"pivotX",
|
|
1499
|
+
"pivotY",
|
|
1500
|
+
"skew",
|
|
1501
|
+
"skewX",
|
|
1502
|
+
"skewY",
|
|
1503
|
+
"position",
|
|
1504
|
+
"positionX",
|
|
1505
|
+
"positionY",
|
|
1506
|
+
"tint",
|
|
1507
|
+
"colorize",
|
|
1508
|
+
"colorizeAmount",
|
|
1509
|
+
"blur",
|
|
1510
|
+
"blurX",
|
|
1511
|
+
"blurY",
|
|
1512
|
+
"blurPadding",
|
|
1513
|
+
// shapes
|
|
1514
|
+
"fillColor",
|
|
1515
|
+
"fillAlpha",
|
|
1516
|
+
"strokeColor",
|
|
1517
|
+
"strokeAlpha",
|
|
1518
|
+
"strokeWidth",
|
|
1519
|
+
"lineColor",
|
|
1520
|
+
"lineAlpha",
|
|
1521
|
+
"cornerRadius",
|
|
1522
|
+
"radius",
|
|
1523
|
+
"radiusX",
|
|
1524
|
+
"radiusY",
|
|
1525
|
+
"innerRadius",
|
|
1526
|
+
"startAngle",
|
|
1527
|
+
"endAngle",
|
|
1528
|
+
"trimStart",
|
|
1529
|
+
"trimEnd",
|
|
1530
|
+
"trimEach",
|
|
1531
|
+
"morph",
|
|
1532
|
+
"fillGradient",
|
|
1533
|
+
"strokeCap",
|
|
1534
|
+
"strokeJoin",
|
|
1535
|
+
// text, audio, video
|
|
1536
|
+
"fill",
|
|
1537
|
+
"value",
|
|
1538
|
+
"visibleChars",
|
|
1539
|
+
"text",
|
|
1540
|
+
"volume",
|
|
1541
|
+
"time",
|
|
1542
|
+
// camera
|
|
1543
|
+
"lookAtX",
|
|
1544
|
+
"lookAtY",
|
|
1545
|
+
"lookAtZ",
|
|
1546
|
+
"fov",
|
|
1547
|
+
"offsetX",
|
|
1548
|
+
"offsetY",
|
|
1549
|
+
"offsetZ",
|
|
1550
|
+
"lookOffsetX",
|
|
1551
|
+
"lookOffsetY",
|
|
1552
|
+
"lookOffsetZ"
|
|
1553
|
+
]);
|
|
1554
|
+
var STYLE_KEYS = [
|
|
1555
|
+
"fontSize",
|
|
1556
|
+
"fontFamily",
|
|
1557
|
+
"fontWeight",
|
|
1558
|
+
"fontStyle",
|
|
1559
|
+
"fontVariant",
|
|
1560
|
+
"fill",
|
|
1561
|
+
"stroke",
|
|
1562
|
+
"dropShadow",
|
|
1563
|
+
"letterSpacing",
|
|
1564
|
+
"lineHeight",
|
|
1565
|
+
"leading",
|
|
1566
|
+
"align",
|
|
1567
|
+
"wordWrap",
|
|
1568
|
+
"wordWrapWidth",
|
|
1569
|
+
"breakWords",
|
|
1570
|
+
"whiteSpace",
|
|
1571
|
+
"padding",
|
|
1572
|
+
"textBaseline",
|
|
1573
|
+
"trim",
|
|
1574
|
+
"lineJoin",
|
|
1575
|
+
"miterLimit",
|
|
1576
|
+
"filters",
|
|
1577
|
+
"tagStyles"
|
|
1578
|
+
];
|
|
1579
|
+
|
|
1054
1580
|
// src/core/lint.ts
|
|
1055
1581
|
var defaultWarn = (m) => console.warn(m);
|
|
1056
1582
|
function describeLayer(spec) {
|
|
@@ -1089,6 +1615,191 @@ function lintText(spec, warn = defaultWarn) {
|
|
|
1089
1615
|
warn(`pixi-effects: ${describeLayer(spec)}: \`value\` is set or animated but the text has no {value} placeholder, so nothing shows it. Use text: '{value}' (or e.g. '{value} users').`);
|
|
1090
1616
|
}
|
|
1091
1617
|
}
|
|
1618
|
+
var REMAPPABLE = /* @__PURE__ */ new Set(["video", "audio", "composition"]);
|
|
1619
|
+
var REMAP_NAMES = /* @__PURE__ */ new Set(["time", "timeRemap", "reverse"]);
|
|
1620
|
+
var TIME_BAGS = ["set", "to", "from"];
|
|
1621
|
+
function lintRemap(spec, warn) {
|
|
1622
|
+
const s = spec;
|
|
1623
|
+
const who = describeLayer(spec);
|
|
1624
|
+
const kfs = s.keyframes ?? [];
|
|
1625
|
+
const bags = [s.initial, ...kfs.flatMap((kf) => TIME_BAGS.map((b) => kf[b]))];
|
|
1626
|
+
const timeInInitial = !!s.initial && s.initial.time !== void 0;
|
|
1627
|
+
const timeInKeyframes = kfs.some((kf) => TIME_BAGS.some((b) => kf[b] && kf[b].time !== void 0));
|
|
1628
|
+
const timed = timeInInitial || timeInKeyframes;
|
|
1629
|
+
if (bags.some((bag) => bag && bag.speed !== void 0)) {
|
|
1630
|
+
warn(`pixi-effects: ${who}: speed is a fixed setting, not an animatable property: write it on the layer (speed: 2); to change the speed over time, animate time (keyframes: [{ at: 0, from: { time: 0 }, to: { time: 4 }, duration: 2, ease: 'power2.in' }])`);
|
|
1631
|
+
}
|
|
1632
|
+
if (!REMAPPABLE.has(spec.type)) {
|
|
1633
|
+
if (timed) warn(`pixi-effects: ${who}: "time" only works on video, audio and composition layers; put this layer in a composition and remap that (it is ignored here)`);
|
|
1634
|
+
return;
|
|
1635
|
+
}
|
|
1636
|
+
if (s.reverse !== void 0) warn(`pixi-effects: ${who}: "reverse" is not a key: write speed: -1 to play backward`);
|
|
1637
|
+
if (s.timeRemap !== void 0) warn(`pixi-effects: ${who}: "timeRemap" is not a key: animate time in keyframes (from / to / set), or write speed`);
|
|
1638
|
+
if (s.time !== void 0) warn(`pixi-effects: ${who}: "time" belongs in initial or keyframes (initial: { time: 2 }), not on the layer`);
|
|
1639
|
+
if (spec.type === "audio" && (s.sfx !== void 0 || s.music !== void 0) && (s.speed !== void 0 || timed)) {
|
|
1640
|
+
warn(`pixi-effects: ${who}: speed and time do not apply to a synthesised sound (sfx, music); change an sfx's pitch with pitch (semitones), or put it in a composition and remap that`);
|
|
1641
|
+
return;
|
|
1642
|
+
}
|
|
1643
|
+
if (s.speed !== void 0 && (typeof s.speed !== "number" || !Number.isFinite(s.speed) || s.speed === 0)) {
|
|
1644
|
+
warn(`pixi-effects: ${who}: speed ${JSON.stringify(s.speed)} cannot be used: write a number other than 0 (negative plays backward); to hold a moment, key time to the same value twice`);
|
|
1645
|
+
}
|
|
1646
|
+
if (s.speed !== void 0 && timeInKeyframes) {
|
|
1647
|
+
warn(`pixi-effects: ${who}: speed and keyframed time are both set; time wins and speed is ignored. Use one of them`);
|
|
1648
|
+
}
|
|
1649
|
+
if (timeInInitial && typeof s.initial.time !== "number") {
|
|
1650
|
+
warn(`pixi-effects: ${who}: initial.time must be a number of seconds, got ${JSON.stringify(s.initial.time)}`);
|
|
1651
|
+
}
|
|
1652
|
+
kfs.forEach((kf, i) => {
|
|
1653
|
+
for (const b of TIME_BAGS) {
|
|
1654
|
+
const v = kf[b]?.time;
|
|
1655
|
+
if (v !== void 0 && typeof v !== "number" && typeof v !== "string") warn(`pixi-effects: ${who}: keyframes[${i}].${b}.time must be a number of seconds, got ${JSON.stringify(v)}`);
|
|
1656
|
+
}
|
|
1657
|
+
});
|
|
1658
|
+
}
|
|
1659
|
+
function lintKeys(spec, warn = defaultWarn) {
|
|
1660
|
+
const who = describeLayer(spec);
|
|
1661
|
+
const valid = layerKeys(spec);
|
|
1662
|
+
if (valid) {
|
|
1663
|
+
for (const key of Object.keys(spec)) {
|
|
1664
|
+
if (valid.includes(key) || spec[key] === void 0) continue;
|
|
1665
|
+
if (REMAPPABLE.has(spec.type) && REMAP_NAMES.has(key)) continue;
|
|
1666
|
+
const guess = chunkWTRKDIKH_cjs.suggestName(key, valid.filter((k) => k !== "type"));
|
|
1667
|
+
const owners = kindsWithKey(key);
|
|
1668
|
+
const belongs = owners.length ? ` (it belongs to ${owners.slice(0, 3).join(", ")})` : "";
|
|
1669
|
+
const hint = guess ? ` \u2014 did you mean "${guess}"?${belongs}` : belongs;
|
|
1670
|
+
warn(`pixi-effects: ${who}: "${key}" is not a ${kindName(spec)} key${hint}. Valid keys: ${valid.join(", ")}`);
|
|
1671
|
+
}
|
|
1672
|
+
}
|
|
1673
|
+
lintRemap(spec, warn);
|
|
1674
|
+
const said = /* @__PURE__ */ new Set();
|
|
1675
|
+
const bags = [spec.initial, ...(spec.keyframes ?? []).flatMap((kf) => [kf.set, kf.to, kf.from])];
|
|
1676
|
+
for (const bag of bags) {
|
|
1677
|
+
for (const key of Object.keys(bag ?? {})) {
|
|
1678
|
+
if (bag[key] === void 0) continue;
|
|
1679
|
+
if (PROP_KEYS.has(key) || key.includes(".") || /^gradient/i.test(key) || said.has(key) || key === "speed") continue;
|
|
1680
|
+
said.add(key);
|
|
1681
|
+
const guess = chunkWTRKDIKH_cjs.suggestName(key, [...PROP_KEYS]);
|
|
1682
|
+
warn(`pixi-effects: ${who}: "${key}" is not an animatable property${guess ? ` \u2014 did you mean "${guess}"?` : ""} (in initial, set, to or from). See the cheatsheet for the properties of this kind of layer`);
|
|
1683
|
+
}
|
|
1684
|
+
}
|
|
1685
|
+
if (spec.type === "text" && spec.style && typeof spec.style === "object") {
|
|
1686
|
+
for (const key of Object.keys(spec.style)) {
|
|
1687
|
+
if (STYLE_KEYS.includes(key) || spec.style[key] === void 0) continue;
|
|
1688
|
+
const guess = chunkWTRKDIKH_cjs.suggestName(key, STYLE_KEYS);
|
|
1689
|
+
warn(`pixi-effects: ${who}: style.${key} is not a text style key${guess ? ` \u2014 did you mean "${guess}"?` : ""} (it is ignored). Keys: ${STYLE_KEYS.join(", ")}`);
|
|
1690
|
+
}
|
|
1691
|
+
}
|
|
1692
|
+
}
|
|
1693
|
+
var BAGS = ["set", "to", "from"];
|
|
1694
|
+
function timeRemapOf(spec, prop = "time") {
|
|
1695
|
+
const hasInitial = !!spec.initial && "time" in spec.initial;
|
|
1696
|
+
const hasKf = (spec.keyframes ?? []).some((kf) => BAGS.some((b) => kf[b] && "time" in kf[b]));
|
|
1697
|
+
const speed = typeof spec.speed === "number" && Number.isFinite(spec.speed) && spec.speed !== 0 ? spec.speed : void 0;
|
|
1698
|
+
if (!hasInitial && !hasKf && speed === void 0) return null;
|
|
1699
|
+
const timeKfs = [];
|
|
1700
|
+
const restKfs = [];
|
|
1701
|
+
for (const kf of spec.keyframes ?? []) {
|
|
1702
|
+
const t = { ...kf }, r = { ...kf };
|
|
1703
|
+
let touched = false, left = false;
|
|
1704
|
+
for (const b of BAGS) {
|
|
1705
|
+
const bag = kf[b];
|
|
1706
|
+
if (!bag) {
|
|
1707
|
+
delete t[b];
|
|
1708
|
+
delete r[b];
|
|
1709
|
+
continue;
|
|
1710
|
+
}
|
|
1711
|
+
const { time, ...others } = bag;
|
|
1712
|
+
if ("time" in bag) {
|
|
1713
|
+
touched = true;
|
|
1714
|
+
t[b] = { [prop]: time };
|
|
1715
|
+
} else delete t[b];
|
|
1716
|
+
if (Object.keys(others).length) {
|
|
1717
|
+
r[b] = others;
|
|
1718
|
+
left = true;
|
|
1719
|
+
} else delete r[b];
|
|
1720
|
+
}
|
|
1721
|
+
if (touched) timeKfs.push(t);
|
|
1722
|
+
if (!touched || left) restKfs.push(r);
|
|
1723
|
+
}
|
|
1724
|
+
let restInitial = spec.initial;
|
|
1725
|
+
let start;
|
|
1726
|
+
if (hasInitial) {
|
|
1727
|
+
const { time, ...others } = spec.initial;
|
|
1728
|
+
start = typeof time === "number" && Number.isFinite(time) ? time : void 0;
|
|
1729
|
+
restInitial = others;
|
|
1730
|
+
}
|
|
1731
|
+
return { timeKfs, restKfs: restKfs.length ? restKfs : void 0, restInitial, start, speed };
|
|
1732
|
+
}
|
|
1733
|
+
function resolveFromEnd(remap, length, prop) {
|
|
1734
|
+
const fix = (v) => typeof v === "number" && v < 0 ? Math.max(0, length + v) : v;
|
|
1735
|
+
const timeKfs = remap.timeKfs.map((kf) => {
|
|
1736
|
+
const out = { ...kf };
|
|
1737
|
+
for (const b of BAGS) {
|
|
1738
|
+
const bag = kf[b];
|
|
1739
|
+
if (bag && prop in bag) out[b] = { ...bag, [prop]: fix(bag[prop]) };
|
|
1740
|
+
}
|
|
1741
|
+
return out;
|
|
1742
|
+
});
|
|
1743
|
+
return { ...remap, timeKfs, start: remap.start === void 0 ? void 0 : fix(remap.start) };
|
|
1744
|
+
}
|
|
1745
|
+
function remapOf(spec, prop, length) {
|
|
1746
|
+
const r = timeRemapOf(spec, prop);
|
|
1747
|
+
return r && length !== null ? resolveFromEnd(r, length, prop) : r;
|
|
1748
|
+
}
|
|
1749
|
+
function contentLength(remap, duration) {
|
|
1750
|
+
let m = duration;
|
|
1751
|
+
if (remap.speed !== void 0) m = Math.max(m, Math.abs(remap.speed) * duration);
|
|
1752
|
+
if (remap.start !== void 0) m = Math.max(m, remap.start + (remap.speed ?? 1) * duration);
|
|
1753
|
+
for (const kf of remap.timeKfs) {
|
|
1754
|
+
for (const b of BAGS) {
|
|
1755
|
+
const bag = kf[b];
|
|
1756
|
+
const v = bag && Object.values(bag)[0];
|
|
1757
|
+
if (typeof v === "number") m = Math.max(m, v);
|
|
1758
|
+
}
|
|
1759
|
+
}
|
|
1760
|
+
return m;
|
|
1761
|
+
}
|
|
1762
|
+
function bindClock(timeline, clock, prop, remap, duration, at, scope) {
|
|
1763
|
+
if (remap.timeKfs.length) {
|
|
1764
|
+
if (remap.start !== void 0) timeline.set(clock, { [prop]: remap.start }, at);
|
|
1765
|
+
applyKeyframes(timeline, clock, remap.timeKfs, duration, scope, [], at);
|
|
1766
|
+
return;
|
|
1767
|
+
}
|
|
1768
|
+
const s = remap.speed ?? 1;
|
|
1769
|
+
const from = remap.start ?? (s < 0 ? -s * duration : 0);
|
|
1770
|
+
timeline.fromTo(clock, { [prop]: from }, { [prop]: from + s * duration, duration, ease: "none" }, at);
|
|
1771
|
+
}
|
|
1772
|
+
function clockTable(remap, prop, duration, at, scope, to) {
|
|
1773
|
+
const probe = gsap.gsap.timeline({ paused: true });
|
|
1774
|
+
const clock = { [prop]: remap.start ?? 0 };
|
|
1775
|
+
bindClock(probe, clock, prop, remap, duration, at, scope);
|
|
1776
|
+
probe.time(probe.duration());
|
|
1777
|
+
probe.time(0);
|
|
1778
|
+
const h = 1 / 1e3;
|
|
1779
|
+
const n = Math.max(2, Math.ceil(to / h) + 2);
|
|
1780
|
+
const tab = new Float64Array(n);
|
|
1781
|
+
let min = Infinity, max = -Infinity;
|
|
1782
|
+
for (let k = 0; k < n; k++) {
|
|
1783
|
+
probe.time(k * h);
|
|
1784
|
+
const v = clock[prop];
|
|
1785
|
+
tab[k] = v;
|
|
1786
|
+
const t = k * h;
|
|
1787
|
+
if (t >= at && t <= at + duration) {
|
|
1788
|
+
if (v < min) min = v;
|
|
1789
|
+
if (v > max) max = v;
|
|
1790
|
+
}
|
|
1791
|
+
}
|
|
1792
|
+
probe.kill();
|
|
1793
|
+
return {
|
|
1794
|
+
at(t) {
|
|
1795
|
+
const x = Math.min(Math.max(t / h, 0), n - 1.000001);
|
|
1796
|
+
const k = Math.floor(x), f = x - k;
|
|
1797
|
+
return tab[k] * (1 - f) + tab[k + 1] * f;
|
|
1798
|
+
},
|
|
1799
|
+
min: Number.isFinite(min) ? min : 0,
|
|
1800
|
+
max: Number.isFinite(max) ? max : 0
|
|
1801
|
+
};
|
|
1802
|
+
}
|
|
1092
1803
|
|
|
1093
1804
|
// src/space/math.ts
|
|
1094
1805
|
var DEG = Math.PI / 180;
|
|
@@ -1414,6 +2125,7 @@ function shortestHueDelta(from, to) {
|
|
|
1414
2125
|
}
|
|
1415
2126
|
|
|
1416
2127
|
// src/expr/colorTween.ts
|
|
2128
|
+
var css = (c) => typeof c === "number" ? "#" + c.toString(16).padStart(6, "0") : c;
|
|
1417
2129
|
function tweenColor(timeline, target, key, fromValue, toValue, duration, ease, at, colorSpace, onUpdate, loop = {}) {
|
|
1418
2130
|
let interp = null;
|
|
1419
2131
|
const proxy = { p: 0 };
|
|
@@ -1428,7 +2140,7 @@ function tweenColor(timeline, target, key, fromValue, toValue, duration, ease, a
|
|
|
1428
2140
|
onStart: () => {
|
|
1429
2141
|
const start = fromValue !== void 0 ? fromValue : target[key];
|
|
1430
2142
|
if (start === void 0) return;
|
|
1431
|
-
interp = colorSpace === "rgb" ? gsap.gsap.utils.interpolate(start, toValue) : buildColorInterp(start, toValue, colorSpace);
|
|
2143
|
+
interp = colorSpace === "rgb" ? gsap.gsap.utils.interpolate(css(start), css(toValue)) : buildColorInterp(start, toValue, colorSpace);
|
|
1432
2144
|
},
|
|
1433
2145
|
onUpdate: () => {
|
|
1434
2146
|
if (interp) {
|
|
@@ -1472,7 +2184,7 @@ var ImageSequence = class extends Sequence {
|
|
|
1472
2184
|
if (initTint !== void 0) this.target.tint = initTint;
|
|
1473
2185
|
for (const kf of this.spec.keyframes ?? []) {
|
|
1474
2186
|
const at = startTime + resolveAt(kf.at, this.duration);
|
|
1475
|
-
const duration = kf
|
|
2187
|
+
const duration = kfDuration(kf);
|
|
1476
2188
|
const ease = kf.ease ?? "none";
|
|
1477
2189
|
const fromTint = kf.from?.tint;
|
|
1478
2190
|
const toTint = kf.to?.tint;
|
|
@@ -1529,6 +2241,207 @@ function stripKeysInKeyframe(kf, keys) {
|
|
|
1529
2241
|
from: stripKeys(kf.from, keys)
|
|
1530
2242
|
};
|
|
1531
2243
|
}
|
|
2244
|
+
|
|
2245
|
+
// src/sequences/gradient.ts
|
|
2246
|
+
function cssColor(c) {
|
|
2247
|
+
return typeof c === "number" ? "#" + c.toString(16).padStart(6, "0") : c;
|
|
2248
|
+
}
|
|
2249
|
+
function normalizedStops(g) {
|
|
2250
|
+
const stops = g.stops ?? [];
|
|
2251
|
+
if (stops.length < 2) throw new Error('pixi-effects: fillGradient needs at least two colour stops, e.g. stops: [[0, "#000"], [1, "#fff"]]');
|
|
2252
|
+
return stops.map((s) => Array.isArray(s) ? { offset: s[0], color: s[1] } : { offset: s.offset, color: s.color });
|
|
2253
|
+
}
|
|
2254
|
+
function gradientOptions(g) {
|
|
2255
|
+
const colorStops = normalizedStops(g);
|
|
2256
|
+
const a = (g.angle ?? 90) * Math.PI / 180;
|
|
2257
|
+
const dx = Math.cos(a), dy = Math.sin(a);
|
|
2258
|
+
const h = (Math.abs(dx) + Math.abs(dy)) / 2;
|
|
2259
|
+
return {
|
|
2260
|
+
type: "linear",
|
|
2261
|
+
start: { x: 0.5 - dx * h, y: 0.5 - dy * h },
|
|
2262
|
+
end: { x: 0.5 + dx * h, y: 0.5 + dy * h },
|
|
2263
|
+
colorStops,
|
|
2264
|
+
textureSpace: "local"
|
|
2265
|
+
};
|
|
2266
|
+
}
|
|
2267
|
+
function paintRadial(ctx, size, g) {
|
|
2268
|
+
const stops = normalizedStops(g);
|
|
2269
|
+
const [cx, cy] = g.center ?? [0.5, 0.5];
|
|
2270
|
+
const grad = ctx.createRadialGradient(cx * size, cy * size, (g.innerRadius ?? 0) * size, cx * size, cy * size, (g.radius ?? 0.5) * size);
|
|
2271
|
+
for (const s of stops) grad.addColorStop(s.offset, cssColor(s.color));
|
|
2272
|
+
ctx.fillStyle = grad;
|
|
2273
|
+
ctx.fillRect(0, 0, size, size);
|
|
2274
|
+
}
|
|
2275
|
+
|
|
2276
|
+
// src/sequences/gradientAnim.ts
|
|
2277
|
+
var PATCH_KEYS = ["type", "angle", "center", "innerRadius", "radius", "stops"];
|
|
2278
|
+
function gradStateFrom(g) {
|
|
2279
|
+
return {
|
|
2280
|
+
type: g.type ?? "linear",
|
|
2281
|
+
angle: g.angle ?? 90,
|
|
2282
|
+
center: [...g.center ?? [0.5, 0.5]],
|
|
2283
|
+
innerRadius: g.innerRadius ?? 0,
|
|
2284
|
+
radius: g.radius ?? 0.5,
|
|
2285
|
+
stops: (g.stops ?? []).map((s) => Array.isArray(s) ? { offset: s[0], color: cssColor(s[1]) } : { offset: s.offset, color: cssColor(s.color) })
|
|
2286
|
+
};
|
|
2287
|
+
}
|
|
2288
|
+
function mergeGrad(base, patch) {
|
|
2289
|
+
const out = { ...base, center: [...base.center], stops: base.stops.map((s) => ({ ...s })) };
|
|
2290
|
+
if (patch === null || typeof patch !== "object" || Array.isArray(patch)) return out;
|
|
2291
|
+
const p = patch;
|
|
2292
|
+
if (typeof p.angle === "number") out.angle = p.angle;
|
|
2293
|
+
if (Array.isArray(p.center)) out.center = [Number(p.center[0]), Number(p.center[1])];
|
|
2294
|
+
if (typeof p.innerRadius === "number") out.innerRadius = p.innerRadius;
|
|
2295
|
+
if (typeof p.radius === "number") out.radius = p.radius;
|
|
2296
|
+
if (p.stops !== void 0) {
|
|
2297
|
+
const next = gradStateFrom({ stops: p.stops }).stops;
|
|
2298
|
+
if (next.length === base.stops.length) out.stops = next;
|
|
2299
|
+
}
|
|
2300
|
+
return out;
|
|
2301
|
+
}
|
|
2302
|
+
var objectHint = "a keyframe's fillGradient must be an object like { angle: 200, stops: [[0, '#f00'], [1, '#00f']] }";
|
|
2303
|
+
function validateGradientKeyframes(spec, who, warn = (m) => console.warn(m), kind = "shape") {
|
|
2304
|
+
const said = /* @__PURE__ */ new Set();
|
|
2305
|
+
const say = (m) => {
|
|
2306
|
+
if (!said.has(m)) {
|
|
2307
|
+
said.add(m);
|
|
2308
|
+
warn(`pixi-effects: ${who}: ${m}`);
|
|
2309
|
+
}
|
|
2310
|
+
};
|
|
2311
|
+
const startSpec = spec.fillGradient ?? spec.initial?.fillGradient;
|
|
2312
|
+
const start = startSpec && typeof startSpec === "object" && Array.isArray(startSpec.stops) ? gradStateFrom(startSpec) : null;
|
|
2313
|
+
let animated = false;
|
|
2314
|
+
if (kind === "text") {
|
|
2315
|
+
const radial = (g) => !!g && typeof g === "object" && ["type", "center", "innerRadius", "radius"].some((k) => g[k] !== void 0 && !(k === "type" && g.type === "linear"));
|
|
2316
|
+
const asked = radial(startSpec) || (spec.keyframes ?? []).some((kf) => [kf.set, kf.to, kf.from].some((b) => radial(b?.fillGradient)));
|
|
2317
|
+
if (asked) say("a text gradient is linear: type, center, innerRadius and radius are ignored (only angle and stops apply); use a shape for a radial gradient");
|
|
2318
|
+
}
|
|
2319
|
+
for (const kf of spec.keyframes ?? []) {
|
|
2320
|
+
for (const bag of [kf.set, kf.to, kf.from]) {
|
|
2321
|
+
if (!bag) continue;
|
|
2322
|
+
for (const [key, value] of Object.entries(bag)) {
|
|
2323
|
+
if (key === "fillGradient") {
|
|
2324
|
+
animated = true;
|
|
2325
|
+
if (value === null || typeof value !== "object" || Array.isArray(value)) {
|
|
2326
|
+
say(objectHint);
|
|
2327
|
+
continue;
|
|
2328
|
+
}
|
|
2329
|
+
const p = value;
|
|
2330
|
+
for (const k of Object.keys(p)) {
|
|
2331
|
+
if (PATCH_KEYS.includes(k)) continue;
|
|
2332
|
+
const guess = chunkWTRKDIKH_cjs.suggestName(k, PATCH_KEYS.filter((x) => x !== "type"));
|
|
2333
|
+
say(`fillGradient.${k} is not a gradient property${guess ? ` \u2014 did you mean "${guess}"?` : ""} (valid: ${PATCH_KEYS.join(", ")}); it is ignored`);
|
|
2334
|
+
}
|
|
2335
|
+
if (p.type !== void 0 && start && p.type !== start.type) say("fillGradient.type cannot change over time (linear <-> radial); it is ignored");
|
|
2336
|
+
if (p.stops !== void 0 && start) {
|
|
2337
|
+
const n = Array.isArray(p.stops) ? p.stops.length : 0;
|
|
2338
|
+
if (n !== start.stops.length) say(`a fillGradient keyframe must give the same number of stops as the gradient has (${start.stops.length}, got ${n}); the stops are left as they were`);
|
|
2339
|
+
}
|
|
2340
|
+
} else if (/^fillGradient\./i.test(key) || /^gradient/i.test(key)) {
|
|
2341
|
+
const tail = key.replace(/^fillGradient\./i, "").replace(/^gradient/i, "");
|
|
2342
|
+
const sub = tail ? tail[0].toLowerCase() + tail.slice(1) : "angle";
|
|
2343
|
+
say(`"${key}" is not an animatable property: write fillGradient: { ${PATCH_KEYS.includes(sub) ? sub : "angle"} } (the whole gradient is one object) in the keyframe's to / from / set`);
|
|
2344
|
+
}
|
|
2345
|
+
}
|
|
2346
|
+
}
|
|
2347
|
+
}
|
|
2348
|
+
if (animated && !start) say("a keyframe animates fillGradient but the layer has none to start from: give it a fillGradient first (top level or in initial)");
|
|
2349
|
+
}
|
|
2350
|
+
function tweenGradient(timeline, holder, fromPatch, toPatch, duration, ease, at, colorSpace, onChange, loop = {}) {
|
|
2351
|
+
let a = null, b = null;
|
|
2352
|
+
let resting = null;
|
|
2353
|
+
let colors = [];
|
|
2354
|
+
const proxy = { p: 0 };
|
|
2355
|
+
timeline.fromTo(proxy, { p: 0 }, {
|
|
2356
|
+
p: 1,
|
|
2357
|
+
duration,
|
|
2358
|
+
ease,
|
|
2359
|
+
...loop,
|
|
2360
|
+
onStart: () => {
|
|
2361
|
+
const live = holder.grad;
|
|
2362
|
+
a = fromPatch !== void 0 ? mergeGrad(live, fromPatch) : live;
|
|
2363
|
+
if (toPatch === void 0) resting ??= live;
|
|
2364
|
+
b = toPatch !== void 0 ? mergeGrad(a, toPatch) : resting;
|
|
2365
|
+
colors = a.stops.map((s, i) => colorSpace === "rgb" ? gsap.gsap.utils.interpolate(s.color, b.stops[i].color) : buildColorInterp(s.color, b.stops[i].color, colorSpace));
|
|
2366
|
+
},
|
|
2367
|
+
onUpdate: () => {
|
|
2368
|
+
if (!a || !b) return;
|
|
2369
|
+
const t = proxy.p;
|
|
2370
|
+
const l = (x, y) => x + (y - x) * t;
|
|
2371
|
+
holder.grad = {
|
|
2372
|
+
type: a.type,
|
|
2373
|
+
angle: l(a.angle, b.angle),
|
|
2374
|
+
center: [l(a.center[0], b.center[0]), l(a.center[1], b.center[1])],
|
|
2375
|
+
innerRadius: l(a.innerRadius, b.innerRadius),
|
|
2376
|
+
radius: l(a.radius, b.radius),
|
|
2377
|
+
stops: a.stops.map((s, i) => ({ offset: l(s.offset, b.stops[i].offset), color: colors[i](t) }))
|
|
2378
|
+
};
|
|
2379
|
+
onChange();
|
|
2380
|
+
}
|
|
2381
|
+
}, at);
|
|
2382
|
+
}
|
|
2383
|
+
var PAINT_SIZE = 512;
|
|
2384
|
+
var GradientPainter = class {
|
|
2385
|
+
constructor(size = PAINT_SIZE) {
|
|
2386
|
+
this.size = size;
|
|
2387
|
+
this.canvas.width = size;
|
|
2388
|
+
this.canvas.height = size;
|
|
2389
|
+
this.tex = PIXI.Texture.from(this.canvas);
|
|
2390
|
+
globalThis.__gradientPainters = (globalThis.__gradientPainters ?? 0) + 1;
|
|
2391
|
+
}
|
|
2392
|
+
size;
|
|
2393
|
+
canvas = document.createElement("canvas");
|
|
2394
|
+
tex;
|
|
2395
|
+
/** Paint `g` and return what `Graphics.fill(...)` takes. */
|
|
2396
|
+
paint(g) {
|
|
2397
|
+
const ctx = this.canvas.getContext("2d"), s = this.size;
|
|
2398
|
+
if (!ctx) return new PIXI.FillGradient(gradientOptions({ angle: g.angle, stops: g.stops.map((x) => [x.offset, x.color]) }));
|
|
2399
|
+
ctx.clearRect(0, 0, s, s);
|
|
2400
|
+
if (g.type === "radial") {
|
|
2401
|
+
paintRadial(ctx, s, { stops: g.stops.map((x) => [x.offset, x.color]), center: g.center, innerRadius: g.innerRadius, radius: g.radius });
|
|
2402
|
+
} else {
|
|
2403
|
+
const a = g.angle * Math.PI / 180, dx = Math.cos(a), dy = Math.sin(a);
|
|
2404
|
+
const h = (Math.abs(dx) + Math.abs(dy)) / 2;
|
|
2405
|
+
const grad = ctx.createLinearGradient((0.5 - dx * h) * s, (0.5 - dy * h) * s, (0.5 + dx * h) * s, (0.5 + dy * h) * s);
|
|
2406
|
+
for (const st of g.stops) grad.addColorStop(Math.min(1, Math.max(0, st.offset)), st.color);
|
|
2407
|
+
ctx.fillStyle = grad;
|
|
2408
|
+
ctx.fillRect(0, 0, s, s);
|
|
2409
|
+
}
|
|
2410
|
+
this.tex.source.update();
|
|
2411
|
+
return { texture: this.tex, textureSpace: "local" };
|
|
2412
|
+
}
|
|
2413
|
+
/** Give the texture and the canvas back (a layer that is destroyed must not leave them). */
|
|
2414
|
+
destroy() {
|
|
2415
|
+
this.tex.destroy(true);
|
|
2416
|
+
this.canvas.width = this.canvas.height = 0;
|
|
2417
|
+
globalThis.__gradientPainters = Math.max(0, (globalThis.__gradientPainters ?? 1) - 1);
|
|
2418
|
+
}
|
|
2419
|
+
};
|
|
2420
|
+
function bindGradientKeyframes(timeline, holder, keyframes, duration, offset, colorSpace, onChange) {
|
|
2421
|
+
const bag = (b) => b?.fillGradient;
|
|
2422
|
+
for (const kf of keyframes) {
|
|
2423
|
+
const at = offset + resolveAt(kf.at, duration);
|
|
2424
|
+
const setV = bag(kf.set), fromV = bag(kf.from), toV = bag(kf.to);
|
|
2425
|
+
if (setV !== void 0) {
|
|
2426
|
+
revertibleSet(
|
|
2427
|
+
timeline,
|
|
2428
|
+
at,
|
|
2429
|
+
() => ({ state: holder.grad }),
|
|
2430
|
+
(v) => {
|
|
2431
|
+
holder.grad = v.state ?? mergeGrad(holder.grad, v.patch);
|
|
2432
|
+
onChange();
|
|
2433
|
+
},
|
|
2434
|
+
{ patch: setV }
|
|
2435
|
+
);
|
|
2436
|
+
}
|
|
2437
|
+
if (fromV !== void 0 || toV !== void 0) {
|
|
2438
|
+
tweenGradient(timeline, holder, fromV, toV, kfDuration(kf), kf.ease ?? "none", at, colorSpace, onChange, loopVars(kf));
|
|
2439
|
+
}
|
|
2440
|
+
}
|
|
2441
|
+
}
|
|
2442
|
+
var hasGradientKeys = (keyframes) => (keyframes ?? []).some((kf) => [kf.set, kf.to, kf.from].some((b) => b && b.fillGradient !== void 0));
|
|
2443
|
+
|
|
2444
|
+
// src/sequences/Text.ts
|
|
1532
2445
|
var STYLE_OPAQUE_KEYS = [
|
|
1533
2446
|
"fontFamily",
|
|
1534
2447
|
"fill",
|
|
@@ -1563,6 +2476,21 @@ var TextSequence = class extends Sequence {
|
|
|
1563
2476
|
/** `visibleChars` is in play (initial or animated): otherwise the whole text shows. */
|
|
1564
2477
|
_typed = false;
|
|
1565
2478
|
_lastText = "";
|
|
2479
|
+
/** A gradient fill for the text (`fillGradient`, static or animated): rebuilt as a FillGradient on each change (the text is re-rasterised). */
|
|
2480
|
+
_grad = null;
|
|
2481
|
+
_fillGradient = null;
|
|
2482
|
+
_applyGradient() {
|
|
2483
|
+
const g = this._grad.grad;
|
|
2484
|
+
const next = new PIXI.FillGradient(gradientOptions({ angle: g.angle, stops: g.stops.map((s) => [s.offset, s.color]) }));
|
|
2485
|
+
this.target.style.fill = next;
|
|
2486
|
+
this._fillGradient?.destroy();
|
|
2487
|
+
this._fillGradient = next;
|
|
2488
|
+
}
|
|
2489
|
+
destroy() {
|
|
2490
|
+
super.destroy();
|
|
2491
|
+
this._fillGradient?.destroy();
|
|
2492
|
+
this._fillGradient = null;
|
|
2493
|
+
}
|
|
1566
2494
|
/** A typewriter that has typed nothing yet: the layer is empty on purpose (inspect must not call that "no size"). */
|
|
1567
2495
|
get showsNothingYet() {
|
|
1568
2496
|
return this._typed && this._lastText === "" && this._template !== "";
|
|
@@ -1609,6 +2537,12 @@ var TextSequence = class extends Sequence {
|
|
|
1609
2537
|
this.intrinsicWidth = text.width;
|
|
1610
2538
|
this.intrinsicHeight = text.height;
|
|
1611
2539
|
}
|
|
2540
|
+
validateGradientKeyframes(this.spec, describeLayer(this.spec), void 0, "text");
|
|
2541
|
+
const gradientSpec = this.spec.fillGradient ?? initialProps.fillGradient;
|
|
2542
|
+
if (gradientSpec) {
|
|
2543
|
+
this._grad = { grad: gradStateFrom(gradientSpec) };
|
|
2544
|
+
this._applyGradient();
|
|
2545
|
+
}
|
|
1612
2546
|
const scope = this.scope();
|
|
1613
2547
|
if (initialProps.value !== void 0) this._counters.value = resolveNumber(initialProps.value, scope);
|
|
1614
2548
|
this._typed = initialProps.visibleChars !== void 0 || animates(this.spec.keyframes, "visibleChars");
|
|
@@ -1627,11 +2561,12 @@ var TextSequence = class extends Sequence {
|
|
|
1627
2561
|
bindTimeline(timeline, offset = 0) {
|
|
1628
2562
|
if (!this.target) return;
|
|
1629
2563
|
const colorSpace = this.spec.colorSpace ?? "rgb";
|
|
1630
|
-
const stripped = stripKeys2(this.spec, ["fill", "value", "text", "visibleChars"]);
|
|
2564
|
+
const stripped = stripKeys2(this.spec, ["fill", "value", "text", "visibleChars", "fillGradient"]);
|
|
1631
2565
|
runSuperWithStrippedSpec(this, stripped, timeline, offset);
|
|
1632
2566
|
const keyframes = this.spec.keyframes ?? [];
|
|
1633
2567
|
const origin = offset + this.at;
|
|
1634
2568
|
bindFillKeyframes(timeline, this.target, keyframes, this.duration, origin, colorSpace);
|
|
2569
|
+
if (this._grad) bindGradientKeyframes(timeline, this._grad, keyframes, this.duration, origin, colorSpace, () => this._applyGradient());
|
|
1635
2570
|
const refresh = () => this._refreshText();
|
|
1636
2571
|
bindCounterKeyframes(timeline, this._counters, "value", refresh, keyframes, this.duration, origin, this.scope());
|
|
1637
2572
|
bindCounterKeyframes(timeline, this._counters, "visibleChars", refresh, keyframes, this.duration, origin, this.scope());
|
|
@@ -1681,7 +2616,7 @@ function bindCounterKeyframes(timeline, state, key, refresh, keyframes, parentDu
|
|
|
1681
2616
|
const toV = kf.to?.[key];
|
|
1682
2617
|
if (setV === void 0 && fromV === void 0 && toV === void 0) continue;
|
|
1683
2618
|
const at = origin + resolveAt(kf.at, parentDuration);
|
|
1684
|
-
const duration = kf
|
|
2619
|
+
const duration = kfDuration(kf);
|
|
1685
2620
|
const ease = kf.ease ?? "none";
|
|
1686
2621
|
const loop = loopVars(kf);
|
|
1687
2622
|
if (setV !== void 0) {
|
|
@@ -1727,7 +2662,7 @@ function bindFillKeyframes(timeline, text, keyframes, parentDuration, offset, co
|
|
|
1727
2662
|
};
|
|
1728
2663
|
for (const kf of keyframes) {
|
|
1729
2664
|
const at = offset + resolveAt(kf.at, parentDuration);
|
|
1730
|
-
const duration = kf
|
|
2665
|
+
const duration = kfDuration(kf);
|
|
1731
2666
|
const ease = kf.ease ?? "none";
|
|
1732
2667
|
const setFill = pickFill(kf.set);
|
|
1733
2668
|
const fromFill = pickFill(kf.from);
|
|
@@ -1765,6 +2700,7 @@ var AudioSequence = class extends Sequence {
|
|
|
1765
2700
|
_audioBuffer = null;
|
|
1766
2701
|
_synth = null;
|
|
1767
2702
|
_source = "";
|
|
2703
|
+
_remap = null;
|
|
1768
2704
|
async build() {
|
|
1769
2705
|
this.target = null;
|
|
1770
2706
|
if (this.spec.music !== void 0) return this._buildMusic(this.spec);
|
|
@@ -1773,13 +2709,16 @@ var AudioSequence = class extends Sequence {
|
|
|
1773
2709
|
this._source = `asset "${spec.asset}"`;
|
|
1774
2710
|
const data = await PIXI.Assets.get(spec.asset);
|
|
1775
2711
|
this._audioBuffer = data.audioBuffer;
|
|
2712
|
+
this._remap = remapOf(spec, "time", data.duration ?? null);
|
|
2713
|
+
const constant = this._remap && this._remap.timeKfs.length === 0 ? Math.abs(this._remap.speed ?? 1) : 1;
|
|
1776
2714
|
if (this.duration === void 0) {
|
|
1777
2715
|
const rest = Math.max(0, (this.parent?.duration ?? this.root.duration) - this.at);
|
|
1778
|
-
this.duration = spec.duration ?? (spec.loop ? rest : data.duration) ?? this.root.duration;
|
|
2716
|
+
this.duration = spec.duration ?? (spec.loop ? rest : data.duration !== void 0 ? data.duration / constant : void 0) ?? this.root.duration;
|
|
1779
2717
|
}
|
|
1780
|
-
|
|
2718
|
+
const playable = this._remap && this._remap.timeKfs.length > 0 ? Infinity : (data.duration ?? Infinity) / constant;
|
|
2719
|
+
if (!spec.loop && Number.isFinite(playable) && this.duration > playable + 0.05) {
|
|
1781
2720
|
console.warn(
|
|
1782
|
-
`pixi-effects: ${describeLayer(spec)}: audio asset "${spec.asset}"
|
|
2721
|
+
`pixi-effects: ${describeLayer(spec)}: audio asset "${spec.asset}" plays for ${playable.toFixed(1)}s (${data.duration.toFixed(1)}s at speed ${constant}) but the layer lasts ${this.duration.toFixed(1)}s, so it goes silent after ${playable.toFixed(1)}s. Add loop: true, or shorten the layer's duration.`
|
|
1783
2722
|
);
|
|
1784
2723
|
}
|
|
1785
2724
|
}
|
|
@@ -1788,7 +2727,7 @@ var AudioSequence = class extends Sequence {
|
|
|
1788
2727
|
const raw = spec;
|
|
1789
2728
|
if (raw.asset !== void 0) console.warn(`pixi-effects: ${who}: has both asset and sfx \u2014 the sfx plays; remove one`);
|
|
1790
2729
|
if (raw.loop) console.warn(`pixi-effects: ${who}: loop has no effect on an sfx \u2014 to repeat it, add one audio layer per hit (a JS loop)`);
|
|
1791
|
-
const { resolveSfx, renderSfx, sfxKey } = await import('./sfx-
|
|
2730
|
+
const { resolveSfx, renderSfx, sfxKey } = await import('./sfx-EX4PUBMV.cjs');
|
|
1792
2731
|
const sfx = resolveSfx(spec.sfx, spec.duration, who);
|
|
1793
2732
|
if (!sfx) return;
|
|
1794
2733
|
this.duration = sfx.length;
|
|
@@ -1807,7 +2746,7 @@ var AudioSequence = class extends Sequence {
|
|
|
1807
2746
|
const raw = spec;
|
|
1808
2747
|
if (raw.asset !== void 0) console.warn(`pixi-effects: ${who}: has both asset and music \u2014 the music plays; remove one`);
|
|
1809
2748
|
if (raw.sfx !== void 0) console.warn(`pixi-effects: ${who}: has both sfx and music \u2014 the music plays; remove one`);
|
|
1810
|
-
const { resolveMusic, renderMusic, musicLength, musicKey } = await import('./music-
|
|
2749
|
+
const { resolveMusic, renderMusic, musicLength, musicKey } = await import('./music-UAN7DXK4.cjs');
|
|
1811
2750
|
const music = resolveMusic(spec.music, who);
|
|
1812
2751
|
if (!music) return;
|
|
1813
2752
|
const natural = musicLength(music);
|
|
@@ -1833,7 +2772,9 @@ var AudioSequence = class extends Sequence {
|
|
|
1833
2772
|
const initialVolume = this.spec.volume ?? this.spec.initial?.volume ?? 1;
|
|
1834
2773
|
const t0 = baseTime + this.at;
|
|
1835
2774
|
const dur = this.duration;
|
|
2775
|
+
const sourceMap = this._remap ? clockTable(this._remap, "time", dur, t0, this.scope(), t0 + dur).at : void 0;
|
|
1836
2776
|
out.push({
|
|
2777
|
+
...sourceMap ? { sourceMap } : {},
|
|
1837
2778
|
...this._audioBuffer ? { buffer: this._audioBuffer } : { synth: this._synth },
|
|
1838
2779
|
layer: describeLayer(this.spec),
|
|
1839
2780
|
source: this._source,
|
|
@@ -1892,7 +2833,7 @@ var FrameCache = class {
|
|
|
1892
2833
|
this.capacity = options.capacity ?? 30;
|
|
1893
2834
|
}
|
|
1894
2835
|
_key(time) {
|
|
1895
|
-
return Math.round(time *
|
|
2836
|
+
return Math.round(time * 1e6);
|
|
1896
2837
|
}
|
|
1897
2838
|
async getFrameAt(time) {
|
|
1898
2839
|
const key = this._key(time);
|
|
@@ -1957,6 +2898,15 @@ var FrameCache = class {
|
|
|
1957
2898
|
}
|
|
1958
2899
|
};
|
|
1959
2900
|
|
|
2901
|
+
// src/core/sourceTime.ts
|
|
2902
|
+
var FRAME_EPS = 5e-5;
|
|
2903
|
+
function sourceLookup(v, sourceDuration, loop) {
|
|
2904
|
+
if (!(sourceDuration > 0)) return Math.max(0, v);
|
|
2905
|
+
const w = v + FRAME_EPS;
|
|
2906
|
+
if (loop) return (w % sourceDuration + sourceDuration) % sourceDuration;
|
|
2907
|
+
return Math.min(Math.max(w, 0), sourceDuration);
|
|
2908
|
+
}
|
|
2909
|
+
|
|
1960
2910
|
// src/sequences/Video.ts
|
|
1961
2911
|
var VideoSequence = class extends Sequence {
|
|
1962
2912
|
_sourceDuration = 0;
|
|
@@ -1965,9 +2915,15 @@ var VideoSequence = class extends Sequence {
|
|
|
1965
2915
|
_canvas = null;
|
|
1966
2916
|
_ctx = null;
|
|
1967
2917
|
_drawSeq = 0;
|
|
2918
|
+
/** The playhead value (seconds in the file) the timeline last wrote: already remapped, and local inside a remapped composition. */
|
|
2919
|
+
_cur = 0;
|
|
2920
|
+
_remap = null;
|
|
2921
|
+
/** Movie asks this layer to draw the frame its own timeline is at, not the one for a time it computed. */
|
|
2922
|
+
selfTimed = true;
|
|
1968
2923
|
async build() {
|
|
1969
2924
|
const data = await PIXI.Assets.get(this.spec.asset);
|
|
1970
2925
|
this._sourceDuration = data.duration;
|
|
2926
|
+
this._remap = remapOf(this.spec, "currentTime", this._sourceDuration);
|
|
1971
2927
|
this._audioBuffer = this.spec.audio !== false ? data.audioBuffer : null;
|
|
1972
2928
|
this._cache = new FrameCache(data.sink, { capacity: 30 });
|
|
1973
2929
|
const probeFrame = await this._cache.getFrameAt(0);
|
|
@@ -1986,7 +2942,8 @@ var VideoSequence = class extends Sequence {
|
|
|
1986
2942
|
this.intrinsicWidth = w;
|
|
1987
2943
|
this.intrinsicHeight = h;
|
|
1988
2944
|
if (this.duration === void 0) {
|
|
1989
|
-
this.
|
|
2945
|
+
const constant = this._remap && this._remap.timeKfs.length === 0 ? Math.abs(this._remap.speed ?? 1) : 1;
|
|
2946
|
+
this.duration = this.spec.duration ?? (data.duration ?? this.root.duration * constant) / constant;
|
|
1990
2947
|
}
|
|
1991
2948
|
let currentTime = 0;
|
|
1992
2949
|
const seq = this;
|
|
@@ -1996,8 +2953,9 @@ var VideoSequence = class extends Sequence {
|
|
|
1996
2953
|
},
|
|
1997
2954
|
set(v) {
|
|
1998
2955
|
currentTime = v;
|
|
2956
|
+
seq._cur = v;
|
|
1999
2957
|
const mySeq = ++seq._drawSeq;
|
|
2000
|
-
const lookup =
|
|
2958
|
+
const lookup = sourceLookup(v, seq._sourceDuration, !!seq.spec.loop);
|
|
2001
2959
|
seq._cache.getFrameAt(lookup).then((frame) => {
|
|
2002
2960
|
if (mySeq !== seq._drawSeq) return;
|
|
2003
2961
|
if (!frame || !seq._ctx) return;
|
|
@@ -2010,21 +2968,33 @@ var VideoSequence = class extends Sequence {
|
|
|
2010
2968
|
});
|
|
2011
2969
|
this.buildFilters();
|
|
2012
2970
|
}
|
|
2971
|
+
displayProps() {
|
|
2972
|
+
const r = this._remap;
|
|
2973
|
+
return r ? { initial: r.restInitial, keyframes: r.restKfs } : super.displayProps();
|
|
2974
|
+
}
|
|
2013
2975
|
bindTimeline(timeline, offset = 0) {
|
|
2014
2976
|
super.bindTimeline(timeline, offset);
|
|
2977
|
+
const at = offset + this.at;
|
|
2978
|
+
if (this._remap) {
|
|
2979
|
+
bindClock(timeline, this.target, "currentTime", this._remap, this.duration, at, this.scope());
|
|
2980
|
+
return;
|
|
2981
|
+
}
|
|
2015
2982
|
const playDuration = this.spec.loop ? this.duration : Math.min(this.duration, this._sourceDuration);
|
|
2016
2983
|
timeline.fromTo(
|
|
2017
2984
|
this.target,
|
|
2018
2985
|
{ currentTime: 0 },
|
|
2019
2986
|
{ currentTime: playDuration, duration: playDuration, ease: "none" },
|
|
2020
|
-
|
|
2987
|
+
at
|
|
2021
2988
|
// offset = start of the enclosing composition(s); dropping it misplaced videos inside nested compositions
|
|
2022
2989
|
);
|
|
2023
2990
|
}
|
|
2024
2991
|
collectAudio(out, baseTime) {
|
|
2025
2992
|
if (!this._audioBuffer) return;
|
|
2026
2993
|
const initialVolume = this.spec.volume ?? 1;
|
|
2994
|
+
const t0 = baseTime + this.at;
|
|
2995
|
+
const sourceMap = this._remap ? clockTable(this._remap, "currentTime", this.duration, t0, this.scope(), t0 + this.duration).at : void 0;
|
|
2027
2996
|
out.push({
|
|
2997
|
+
...sourceMap ? { sourceMap } : {},
|
|
2028
2998
|
buffer: this._audioBuffer,
|
|
2029
2999
|
layer: describeLayer(this.spec),
|
|
2030
3000
|
source: `video "${this.spec.asset}"`,
|
|
@@ -2035,9 +3005,12 @@ var VideoSequence = class extends Sequence {
|
|
|
2035
3005
|
volumeKeyframes: []
|
|
2036
3006
|
});
|
|
2037
3007
|
}
|
|
2038
|
-
|
|
3008
|
+
/** Draw the frame the playhead is at NOW (`_cur`). The argument (a time Movie worked out for layers that need it) is not used. */
|
|
3009
|
+
async awaitFrameAt(_time) {
|
|
3010
|
+
const time = this._cur;
|
|
3011
|
+
if (!this.keepHidden && !this.target?.renderable) return;
|
|
2039
3012
|
const mySeq = ++this._drawSeq;
|
|
2040
|
-
const lookup =
|
|
3013
|
+
const lookup = sourceLookup(time, this._sourceDuration, !!this.spec.loop);
|
|
2041
3014
|
let frame = null;
|
|
2042
3015
|
try {
|
|
2043
3016
|
frame = await this._cache.getFrameAt(lookup);
|
|
@@ -2061,39 +3034,6 @@ var VideoSequence = class extends Sequence {
|
|
|
2061
3034
|
super.destroy();
|
|
2062
3035
|
}
|
|
2063
3036
|
};
|
|
2064
|
-
|
|
2065
|
-
// src/sequences/gradient.ts
|
|
2066
|
-
function cssColor(c) {
|
|
2067
|
-
return typeof c === "number" ? "#" + c.toString(16).padStart(6, "0") : c;
|
|
2068
|
-
}
|
|
2069
|
-
function normalizedStops(g) {
|
|
2070
|
-
const stops = g.stops ?? [];
|
|
2071
|
-
if (stops.length < 2) throw new Error('pixi-effects: fillGradient needs at least two colour stops, e.g. stops: [[0, "#000"], [1, "#fff"]]');
|
|
2072
|
-
return stops.map((s) => Array.isArray(s) ? { offset: s[0], color: s[1] } : { offset: s.offset, color: s.color });
|
|
2073
|
-
}
|
|
2074
|
-
function gradientOptions(g) {
|
|
2075
|
-
const colorStops = normalizedStops(g);
|
|
2076
|
-
const a = (g.angle ?? 90) * Math.PI / 180;
|
|
2077
|
-
const dx = Math.cos(a), dy = Math.sin(a);
|
|
2078
|
-
const h = (Math.abs(dx) + Math.abs(dy)) / 2;
|
|
2079
|
-
return {
|
|
2080
|
-
type: "linear",
|
|
2081
|
-
start: { x: 0.5 - dx * h, y: 0.5 - dy * h },
|
|
2082
|
-
end: { x: 0.5 + dx * h, y: 0.5 + dy * h },
|
|
2083
|
-
colorStops,
|
|
2084
|
-
textureSpace: "local"
|
|
2085
|
-
};
|
|
2086
|
-
}
|
|
2087
|
-
function paintRadial(ctx, size, g) {
|
|
2088
|
-
const stops = normalizedStops(g);
|
|
2089
|
-
const [cx, cy] = g.center ?? [0.5, 0.5];
|
|
2090
|
-
const grad = ctx.createRadialGradient(cx * size, cy * size, (g.innerRadius ?? 0) * size, cx * size, cy * size, (g.radius ?? 0.5) * size);
|
|
2091
|
-
for (const s of stops) grad.addColorStop(s.offset, cssColor(s.color));
|
|
2092
|
-
ctx.fillStyle = grad;
|
|
2093
|
-
ctx.fillRect(0, 0, size, size);
|
|
2094
|
-
}
|
|
2095
|
-
|
|
2096
|
-
// src/sequences/gradientFill.ts
|
|
2097
3037
|
var RADIAL_SIZE = 256;
|
|
2098
3038
|
function makeGradientFill(g) {
|
|
2099
3039
|
if (g.type === "radial") {
|
|
@@ -2285,7 +3225,7 @@ function morphAt(pairs, t) {
|
|
|
2285
3225
|
}
|
|
2286
3226
|
|
|
2287
3227
|
// src/sequences/Shape.ts
|
|
2288
|
-
var
|
|
3228
|
+
var STYLE_KEYS2 = ["fillColor", "fillAlpha", "strokeColor", "strokeAlpha", "strokeWidth"];
|
|
2289
3229
|
var COLOR_KEYS = /* @__PURE__ */ new Set(["fillColor", "strokeColor"]);
|
|
2290
3230
|
var TRIM_KEYS = ["trimStart", "trimEnd"];
|
|
2291
3231
|
var GEOMETRY_KEYS_BY_SHAPE = {
|
|
@@ -2311,7 +3251,7 @@ var ShapeSequence = class extends Sequence {
|
|
|
2311
3251
|
// by `Container.onRender`.
|
|
2312
3252
|
_drawGeometry = () => {
|
|
2313
3253
|
};
|
|
2314
|
-
_liveKeys = new Set(
|
|
3254
|
+
_liveKeys = new Set(STYLE_KEYS2);
|
|
2315
3255
|
async build() {
|
|
2316
3256
|
const graphics = new PIXI.Graphics({ label: this.spec.name });
|
|
2317
3257
|
graphics.cullable = true;
|
|
@@ -2337,7 +3277,15 @@ var ShapeSequence = class extends Sequence {
|
|
|
2337
3277
|
this._state.trimEnd ??= 1;
|
|
2338
3278
|
}
|
|
2339
3279
|
const gradientSpec = this.spec.fillGradient ?? this.spec.initial?.fillGradient;
|
|
2340
|
-
|
|
3280
|
+
validateGradientKeyframes(this.spec, describeLayer(this.spec));
|
|
3281
|
+
if (gradientSpec) {
|
|
3282
|
+
if (hasGradientKeys(this.spec.keyframes)) {
|
|
3283
|
+
this._grad = { grad: gradStateFrom(gradientSpec) };
|
|
3284
|
+
this._painter = new GradientPainter();
|
|
3285
|
+
this._gradDirty = true;
|
|
3286
|
+
this._liveKeys.add("fillGradient");
|
|
3287
|
+
} else this._state.fillStyle = makeGradientFill(gradientSpec);
|
|
3288
|
+
}
|
|
2341
3289
|
const morph = this._setupMorph();
|
|
2342
3290
|
this._drawGeometry = makeDrawGeometry(this.spec, scope, this._state, morph);
|
|
2343
3291
|
this._outline = makeOutline(this.spec, scope, this._state, morph);
|
|
@@ -2396,11 +3344,23 @@ var ShapeSequence = class extends Sequence {
|
|
|
2396
3344
|
this._state.morph ??= 0;
|
|
2397
3345
|
return { pairs, to: String(top.morphTo) };
|
|
2398
3346
|
}
|
|
3347
|
+
destroy() {
|
|
3348
|
+
super.destroy();
|
|
3349
|
+
this._painter?.destroy();
|
|
3350
|
+
this._painter = null;
|
|
3351
|
+
}
|
|
2399
3352
|
_fresh = false;
|
|
3353
|
+
_grad = null;
|
|
3354
|
+
_painter = null;
|
|
3355
|
+
_gradDirty = false;
|
|
2400
3356
|
_outline = null;
|
|
2401
3357
|
_redraw() {
|
|
2402
3358
|
const graphics = this.target;
|
|
2403
3359
|
const s = this._state;
|
|
3360
|
+
if (this._grad && this._gradDirty) {
|
|
3361
|
+
s.fillStyle = this._painter.paint(this._grad.grad);
|
|
3362
|
+
this._gradDirty = false;
|
|
3363
|
+
}
|
|
2404
3364
|
graphics.clear();
|
|
2405
3365
|
const trimmed = (s.trimStart ?? 0) > 0 || (s.trimEnd ?? 1) < 1;
|
|
2406
3366
|
if (!trimmed || !this._outline || !(s.strokeColor !== void 0 && s.strokeWidth > 0)) {
|
|
@@ -2446,6 +3406,9 @@ var ShapeSequence = class extends Sequence {
|
|
|
2446
3406
|
applyKeyframes(timeline, this.target, keyframes, this.duration, scope, [], startTime);
|
|
2447
3407
|
const colorSpace = this.spec.colorSpace ?? "rgb";
|
|
2448
3408
|
bindLiveKeyframes(timeline, this._state, this._liveKeys, this.spec.keyframes ?? [], this.duration, scope, startTime, colorSpace);
|
|
3409
|
+
if (this._grad) bindGradientKeyframes(timeline, this._grad, this.spec.keyframes ?? [], this.duration, startTime, colorSpace, () => {
|
|
3410
|
+
this._gradDirty = true;
|
|
3411
|
+
});
|
|
2449
3412
|
this.absoluteStart = startTime;
|
|
2450
3413
|
const endTime = startTime + this.duration;
|
|
2451
3414
|
this.target.renderable = startTime <= 0;
|
|
@@ -2482,7 +3445,7 @@ function seedStrokeStyle(state, spec, initial, who) {
|
|
|
2482
3445
|
}
|
|
2483
3446
|
}
|
|
2484
3447
|
function seedStyle(state, initial, scope) {
|
|
2485
|
-
for (const k of
|
|
3448
|
+
for (const k of STYLE_KEYS2) {
|
|
2486
3449
|
const v = initial[k];
|
|
2487
3450
|
if (v === void 0) continue;
|
|
2488
3451
|
state[k] = COLOR_KEYS.has(k) ? v : numOrZero(v, scope);
|
|
@@ -2705,13 +3668,14 @@ function makeOutline(spec, scope, s, morph) {
|
|
|
2705
3668
|
function bindLiveKeyframes(timeline, state, liveKeys, keyframes, parentDuration, scope, offset, colorSpace) {
|
|
2706
3669
|
for (const kf of keyframes) {
|
|
2707
3670
|
const at = offset + resolveAt(kf.at, parentDuration);
|
|
2708
|
-
const duration = kf
|
|
3671
|
+
const duration = kfDuration(kf);
|
|
2709
3672
|
const ease = kf.ease ?? "none";
|
|
2710
3673
|
const loop = loopVars(kf);
|
|
2711
3674
|
if (kf.set) {
|
|
2712
3675
|
const live = pickLive(kf.set, liveKeys);
|
|
2713
3676
|
if (live) {
|
|
2714
3677
|
for (const [k, v] of Object.entries(live)) {
|
|
3678
|
+
if (k === "fillGradient") continue;
|
|
2715
3679
|
const resolved = resolveLiveValue(k, v, scope);
|
|
2716
3680
|
const live2 = state;
|
|
2717
3681
|
revertibleSet(timeline, at, () => live2[k], (v2) => {
|
|
@@ -2727,6 +3691,7 @@ function bindLiveKeyframes(timeline, state, liveKeys, keyframes, parentDuration,
|
|
|
2727
3691
|
...toLive ? Object.keys(toLive) : []
|
|
2728
3692
|
]);
|
|
2729
3693
|
for (const k of allKeys) {
|
|
3694
|
+
if (k === "fillGradient") continue;
|
|
2730
3695
|
const key = k;
|
|
2731
3696
|
const fromRaw = fromLive?.[key];
|
|
2732
3697
|
const toRaw = toLive?.[key];
|
|
@@ -2775,7 +3740,7 @@ function numOrZero(v, scope) {
|
|
|
2775
3740
|
var _CompositionSequence = null;
|
|
2776
3741
|
async function getCompositionSequence() {
|
|
2777
3742
|
if (!_CompositionSequence) {
|
|
2778
|
-
_CompositionSequence = (await import('./Composition-
|
|
3743
|
+
_CompositionSequence = (await import('./Composition-LL2XXU5N.cjs')).CompositionSequence;
|
|
2779
3744
|
}
|
|
2780
3745
|
return _CompositionSequence;
|
|
2781
3746
|
}
|
|
@@ -2819,17 +3784,21 @@ exports.DEG = DEG;
|
|
|
2819
3784
|
exports.NEAR = NEAR;
|
|
2820
3785
|
exports.NullSequence = NullSequence;
|
|
2821
3786
|
exports.Sequence = Sequence;
|
|
3787
|
+
exports.bindClock = bindClock;
|
|
2822
3788
|
exports.buildScope = buildScope;
|
|
2823
3789
|
exports.buildSequenceTree = buildSequenceTree;
|
|
2824
3790
|
exports.cameraBasis = cameraBasis;
|
|
2825
3791
|
exports.checkEase = checkEase;
|
|
3792
|
+
exports.clockTable = clockTable;
|
|
2826
3793
|
exports.collectPropKeys = collectPropKeys;
|
|
3794
|
+
exports.contentLength = contentLength;
|
|
2827
3795
|
exports.describeLayer = describeLayer;
|
|
2828
3796
|
exports.ensureFilterLibrary = ensureFilterLibrary;
|
|
2829
3797
|
exports.evaluateExpr = evaluateExpr;
|
|
2830
3798
|
exports.flattenSvgPath = flattenSvgPath;
|
|
2831
3799
|
exports.homeCamera = homeCamera;
|
|
2832
3800
|
exports.homeDistance = homeDistance;
|
|
3801
|
+
exports.lintKeys = lintKeys;
|
|
2833
3802
|
exports.lintText = lintText;
|
|
2834
3803
|
exports.lintTiming = lintTiming;
|
|
2835
3804
|
exports.noise = noise;
|
|
@@ -2837,7 +3806,9 @@ exports.projectLayer = projectLayer;
|
|
|
2837
3806
|
exports.rand = rand;
|
|
2838
3807
|
exports.random = random;
|
|
2839
3808
|
exports.registerSequenceType = registerSequenceType;
|
|
3809
|
+
exports.remapOf = remapOf;
|
|
2840
3810
|
exports.resolveAt = resolveAt;
|
|
2841
3811
|
exports.summarizeWarnings = summarizeWarnings;
|
|
2842
|
-
|
|
2843
|
-
//# sourceMappingURL=chunk-
|
|
3812
|
+
exports.timeRemapOf = timeRemapOf;
|
|
3813
|
+
//# sourceMappingURL=chunk-NO26HWR7.cjs.map
|
|
3814
|
+
//# sourceMappingURL=chunk-NO26HWR7.cjs.map
|