pixi-effects 0.35.0 → 0.37.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 +35 -0
- package/README.md +5 -5
- package/ai/chat-template.html +3 -3
- package/ai/tools/check.mjs +38 -9
- package/ai/tools/lookup.mjs +15 -2
- package/dist/{Base-pNq6sVGl.d.cts → Base-BlA6SeqJ.d.cts} +1 -1
- package/dist/{Base-CXsMdmJB.d.ts → Base-YqM0Ljvp.d.ts} +1 -1
- package/dist/Composition-5KZETM4J.js +7 -0
- package/dist/{Composition-NDXKQHB4.js.map → Composition-5KZETM4J.js.map} +1 -1
- package/dist/Composition-MHDI7UNZ.cjs +16 -0
- package/dist/{Composition-OLH7RC5Z.cjs.map → Composition-MHDI7UNZ.cjs.map} +1 -1
- package/dist/Controller.d.cts +2 -2
- package/dist/Controller.d.ts +2 -2
- package/dist/{Movie-VYtUN4TS.d.ts → Movie-CJN_gvLB.d.cts} +26 -2
- package/dist/{Movie-Db4QnMIH.d.cts → Movie-CfHaGmUP.d.ts} +26 -2
- package/dist/{Spans-QHHWC2PB.js → Spans-FSSO2HGX.js} +6 -6
- package/dist/{Spans-QHHWC2PB.js.map → Spans-FSSO2HGX.js.map} +1 -1
- package/dist/{Spans-QRMN2EZO.cjs → Spans-WVJH77BW.cjs} +11 -11
- package/dist/{Spans-QRMN2EZO.cjs.map → Spans-WVJH77BW.cjs.map} +1 -1
- package/dist/{blendModes-WIUCYIMC.cjs → blendModes-FD3THLNC.cjs} +5 -5
- package/dist/{blendModes-WIUCYIMC.cjs.map → blendModes-FD3THLNC.cjs.map} +1 -1
- package/dist/{blendModes-PP5NPBXY.js → blendModes-FMYO6SQN.js} +4 -4
- package/dist/{blendModes-PP5NPBXY.js.map → blendModes-FMYO6SQN.js.map} +1 -1
- package/dist/{chunk-ITDYFBB6.js → chunk-32MMNDDN.js} +7 -6
- package/dist/chunk-32MMNDDN.js.map +1 -0
- package/dist/{chunk-GL2AQFLQ.cjs → chunk-3SAS3ZE5.cjs} +7 -6
- package/dist/chunk-3SAS3ZE5.cjs.map +1 -0
- package/dist/{chunk-7TTCPHAV.cjs → chunk-E26M4NTL.cjs} +235 -49
- package/dist/chunk-E26M4NTL.cjs.map +1 -0
- package/dist/{chunk-XV4L72FW.js → chunk-IPQNT65V.js} +6 -6
- package/dist/chunk-IPQNT65V.js.map +1 -0
- package/dist/{chunk-IMQJVRMT.cjs → chunk-JN7JHNZR.cjs} +5 -5
- package/dist/{chunk-IMQJVRMT.cjs.map → chunk-JN7JHNZR.cjs.map} +1 -1
- package/dist/{chunk-2GNK6DPV.js → chunk-KNDEKWQO.js} +203 -18
- package/dist/chunk-KNDEKWQO.js.map +1 -0
- package/dist/{chunk-5IJENZOG.cjs → chunk-MJMOPWMK.cjs} +92 -92
- package/dist/chunk-MJMOPWMK.cjs.map +1 -0
- package/dist/{chunk-LEECUCTG.cjs → chunk-QHIOOK5S.cjs} +436 -29
- package/dist/chunk-QHIOOK5S.cjs.map +1 -0
- package/dist/{chunk-Y253JQOH.js → chunk-SBR75G73.js} +416 -11
- package/dist/chunk-SBR75G73.js.map +1 -0
- package/dist/{chunk-RTJD3ZSW.js → chunk-VNP7QCJE.js} +4 -4
- package/dist/{chunk-RTJD3ZSW.js.map → chunk-VNP7QCJE.js.map} +1 -1
- package/dist/index.cjs +41 -33
- package/dist/index.d.cts +47 -7
- package/dist/index.d.ts +47 -7
- package/dist/index.js +5 -5
- package/dist/loader.css +1 -1
- package/dist/present.cjs +5 -5
- package/dist/present.d.cts +2 -2
- package/dist/present.d.ts +2 -2
- package/dist/present.js +5 -5
- 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-CavnUvd5.d.cts → types-DvnXXm33.d.cts} +67 -3
- package/dist/{types-CavnUvd5.d.ts → types-DvnXXm33.d.ts} +67 -3
- package/docs/api.md +5 -4
- package/docs/dsl.md +42 -5
- package/llms-full.txt +305 -22
- package/package.json +1 -1
- package/skills/pixi-effects/SKILL.md +5 -4
- package/skills/pixi-effects/reference/cheatsheet.md +9 -6
- package/skills/pixi-effects/reference/pitfalls.md +7 -0
- package/skills/pixi-effects/reference/recipes.md +237 -3
- package/skills/pixi-effects/template.html +6 -6
- package/dist/Composition-NDXKQHB4.js +0 -7
- package/dist/Composition-OLH7RC5Z.cjs +0 -16
- package/dist/chunk-2GNK6DPV.js.map +0 -1
- package/dist/chunk-5IJENZOG.cjs.map +0 -1
- package/dist/chunk-7TTCPHAV.cjs.map +0 -1
- package/dist/chunk-GL2AQFLQ.cjs.map +0 -1
- package/dist/chunk-ITDYFBB6.js.map +0 -1
- package/dist/chunk-LEECUCTG.cjs.map +0 -1
- package/dist/chunk-XV4L72FW.js.map +0 -1
- package/dist/chunk-Y253JQOH.js.map +0 -1
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { describeLayer, collectPropKeys } from './chunk-
|
|
1
|
+
import { describeLayer, collectPropKeys } from './chunk-32MMNDDN.js';
|
|
2
2
|
import { suggestName, warnUnknownOptions } from './chunk-BXOCEZ4U.js';
|
|
3
3
|
import * as PIXI from 'pixi.js';
|
|
4
4
|
import { Rectangle, Container, FillGradient, Text, Color, GraphicsPath, Sprite, Texture, Graphics, Assets, Filter, GlProgram, defaultFilterVert, GpuProgram, UniformGroup, TextStyle, CanvasTextMetrics } from 'pixi.js';
|
|
@@ -971,6 +971,17 @@ function noise(x, seed = 0) {
|
|
|
971
971
|
const u = f * f * f * (f * (f * 6 - 15) + 10);
|
|
972
972
|
return a + (b - a) * u;
|
|
973
973
|
}
|
|
974
|
+
function noise2(x, y, seed = 0) {
|
|
975
|
+
if (!Number.isFinite(x) || !Number.isFinite(y)) return 0;
|
|
976
|
+
const i = Math.floor(x), j = Math.floor(y);
|
|
977
|
+
const fx = x - i, fy = y - j;
|
|
978
|
+
const s = fold(seed) * 668265261;
|
|
979
|
+
const corner = (a, b) => mix2(Math.imul((a | 0) + s, 2654435761) ^ Math.imul((b | 0) + 2135587861, 2246822507)) / 2147483648 - 1;
|
|
980
|
+
const ux = fx * fx * fx * (fx * (fx * 6 - 15) + 10), uy = fy * fy * fy * (fy * (fy * 6 - 15) + 10);
|
|
981
|
+
const top = corner(i, j) + (corner(i + 1, j) - corner(i, j)) * ux;
|
|
982
|
+
const bottom = corner(i, j + 1) + (corner(i + 1, j + 1) - corner(i, j + 1)) * ux;
|
|
983
|
+
return top + (bottom - top) * uy;
|
|
984
|
+
}
|
|
974
985
|
|
|
975
986
|
// src/expr/Parser.ts
|
|
976
987
|
var FUNCS = {
|
|
@@ -2326,6 +2337,11 @@ function createFilter(spec) {
|
|
|
2326
2337
|
return named;
|
|
2327
2338
|
}
|
|
2328
2339
|
const { type, name, ...given } = spec;
|
|
2340
|
+
const unset = Object.keys(given).filter((k) => given[k] === void 0);
|
|
2341
|
+
if (unset.length > 0) {
|
|
2342
|
+
console.warn(`pixi-effects: the "${type}" filter has ${unset.map((k) => `"${k}"`).join(", ")} set to undefined (a misspelt variable or a missing field?): the filter's default is used instead.`);
|
|
2343
|
+
for (const k of unset) delete given[k];
|
|
2344
|
+
}
|
|
2329
2345
|
const params = copyPlain(given);
|
|
2330
2346
|
const Cls = registry[type];
|
|
2331
2347
|
const inst = Cls ? new Cls(params) : createNamedFilter(type, params);
|
|
@@ -2841,7 +2857,37 @@ var TEXT_STYLE_DEFAULTS = {
|
|
|
2841
2857
|
};
|
|
2842
2858
|
|
|
2843
2859
|
// src/sequences/Text.ts
|
|
2844
|
-
|
|
2860
|
+
var TIME_PATTERNS = ["hh:mm:ss", "h:mm:ss", "hh:mm", "mm:ss", "m:ss"];
|
|
2861
|
+
function formatTime(v, pattern, warned2) {
|
|
2862
|
+
if (!TIME_PATTERNS.includes(pattern)) {
|
|
2863
|
+
if (!warned2.has(pattern)) {
|
|
2864
|
+
warned2.add(pattern);
|
|
2865
|
+
console.warn(`pixi-effects: format.time "${pattern}" is not one of ${TIME_PATTERNS.map((p) => `"${p}"`).join(", ")}: the value is printed as a number`);
|
|
2866
|
+
}
|
|
2867
|
+
return null;
|
|
2868
|
+
}
|
|
2869
|
+
const total = Math.floor(Math.abs(v));
|
|
2870
|
+
const h = Math.floor(total / 3600), m = Math.floor(total % 3600 / 60), sec = total % 60;
|
|
2871
|
+
const two = (n) => String(n).padStart(2, "0");
|
|
2872
|
+
const sign = v < 0 && total > 0 ? "-" : "";
|
|
2873
|
+
switch (pattern) {
|
|
2874
|
+
case "hh:mm:ss":
|
|
2875
|
+
return `${sign}${two(h)}:${two(m)}:${two(sec)}`;
|
|
2876
|
+
case "h:mm:ss":
|
|
2877
|
+
return `${sign}${h}:${two(m)}:${two(sec)}`;
|
|
2878
|
+
case "hh:mm":
|
|
2879
|
+
return `${sign}${two(h)}:${two(m)}`;
|
|
2880
|
+
case "mm:ss":
|
|
2881
|
+
return `${sign}${two(Math.floor(total / 60))}:${two(sec)}`;
|
|
2882
|
+
default:
|
|
2883
|
+
return `${sign}${Math.floor(total / 60)}:${two(sec)}`;
|
|
2884
|
+
}
|
|
2885
|
+
}
|
|
2886
|
+
function formatValue(v, f, warned2 = /* @__PURE__ */ new Set()) {
|
|
2887
|
+
if (f?.time !== void 0) {
|
|
2888
|
+
const t = formatTime(v, String(f.time), warned2);
|
|
2889
|
+
if (t !== null) return t;
|
|
2890
|
+
}
|
|
2845
2891
|
const fixed = v.toFixed(Math.max(0, Math.floor(f?.decimals ?? 0)));
|
|
2846
2892
|
const pad = Math.max(0, Math.floor(f?.pad ?? 0));
|
|
2847
2893
|
if (!f?.grouping && !pad) return fixed;
|
|
@@ -2860,6 +2906,8 @@ var TextSequence = class extends Sequence {
|
|
|
2860
2906
|
/** `visibleChars` is in play (initial or animated): otherwise the whole text shows. */
|
|
2861
2907
|
_typed = false;
|
|
2862
2908
|
_lastText = "";
|
|
2909
|
+
/** The `format.time` patterns already said to be wrong on this layer. */
|
|
2910
|
+
_timeWarned = /* @__PURE__ */ new Set();
|
|
2863
2911
|
/** A gradient fill for the text (`fillGradient`, static or animated): rebuilt as a FillGradient on each change (the text is re-rasterised). */
|
|
2864
2912
|
_grad = null;
|
|
2865
2913
|
_fillGradient = null;
|
|
@@ -2886,7 +2934,7 @@ var TextSequence = class extends Sequence {
|
|
|
2886
2934
|
}
|
|
2887
2935
|
/** Rewrite the displayed string from the template, the current `value` and `visibleChars`. */
|
|
2888
2936
|
_refreshText() {
|
|
2889
|
-
let next = this._template.includes("{value}") ? this._template.split("{value}").join(formatValue(this._counters.value, this.spec.format)) : this._template;
|
|
2937
|
+
let next = this._template.includes("{value}") ? this._template.split("{value}").join(formatValue(this._counters.value, this.spec.format, this._timeWarned)) : this._template;
|
|
2890
2938
|
if (this._typed) next = Array.from(next).slice(0, Math.max(0, Math.floor(this._counters.visibleChars))).join("");
|
|
2891
2939
|
if (next === this._lastText) return;
|
|
2892
2940
|
this._lastText = next;
|
|
@@ -2902,6 +2950,11 @@ var TextSequence = class extends Sequence {
|
|
|
2902
2950
|
label: this.spec.name
|
|
2903
2951
|
});
|
|
2904
2952
|
text.cullable = true;
|
|
2953
|
+
if (this.spec.resolution !== void 0) {
|
|
2954
|
+
const r = this.spec.resolution;
|
|
2955
|
+
if (typeof r === "number" && r >= 1 && r <= 8) text.resolution = r;
|
|
2956
|
+
else console.warn(`pixi-effects: ${describeLayer(this.spec)}: resolution must be a number from 1 to 8 (the text is drawn at that many times the pixels), got ${JSON.stringify(r)}: ignored`);
|
|
2957
|
+
}
|
|
2905
2958
|
this.target = text;
|
|
2906
2959
|
this.intrinsicWidth = text.width;
|
|
2907
2960
|
this.intrinsicHeight = text.height;
|
|
@@ -2926,6 +2979,8 @@ var TextSequence = class extends Sequence {
|
|
|
2926
2979
|
this.intrinsicWidth = text.width;
|
|
2927
2980
|
this.intrinsicHeight = text.height;
|
|
2928
2981
|
}
|
|
2982
|
+
const startFill = initialProps.fill;
|
|
2983
|
+
if (typeof startFill === "string" || typeof startFill === "number") text.style.fill = startFill;
|
|
2929
2984
|
validateGradientKeyframes(this.spec, describeLayer(this.spec), void 0, "text");
|
|
2930
2985
|
const gradientSpec = this.spec.fillGradient ?? initialProps.fillGradient;
|
|
2931
2986
|
if (gradientSpec) {
|
|
@@ -3730,7 +3785,7 @@ function resolveSpansStyle(style, scope, who, warn = defaultWarn) {
|
|
|
3730
3785
|
}
|
|
3731
3786
|
return out;
|
|
3732
3787
|
}
|
|
3733
|
-
var TEXT_ONLY = ["type", "spans", "text", "style", "format", "colorSpace", "fillGradient", "initial", "keyframes"];
|
|
3788
|
+
var TEXT_ONLY = ["type", "spans", "text", "style", "format", "colorSpace", "fillGradient", "initial", "keyframes", "resolution"];
|
|
3734
3789
|
var NOT_FOR_A_GROUP = ["fill", "text", "value", "fillGradient"];
|
|
3735
3790
|
function expandSpans(spec, warn = defaultWarn, scope) {
|
|
3736
3791
|
const who = describeLayer(spec);
|
|
@@ -3775,7 +3830,9 @@ function expandSpans(spec, warn = defaultWarn, scope) {
|
|
|
3775
3830
|
name: `${baseName}.${i}`,
|
|
3776
3831
|
text: p.text,
|
|
3777
3832
|
style: { ...style, ...p.style },
|
|
3778
|
-
initial: { x: p.x, y: p.y, ...typed ? { visibleChars: p.length } : {} }
|
|
3833
|
+
initial: { x: p.x, y: p.y, ...typed ? { visibleChars: p.length } : {} },
|
|
3834
|
+
...s.resolution !== void 0 ? { resolution: s.resolution } : {}
|
|
3835
|
+
// the pieces are what is drawn
|
|
3779
3836
|
}));
|
|
3780
3837
|
const rest = {};
|
|
3781
3838
|
for (const [k, v] of Object.entries(s)) if (!TEXT_ONLY.includes(k)) rest[k] = v;
|
|
@@ -3783,9 +3840,15 @@ function expandSpans(spec, warn = defaultWarn, scope) {
|
|
|
3783
3840
|
spansMeta.set(group, { typed, pieces: drawn.map((p) => ({ start: p.start, length: p.length })), preview: layout.pieces.map((p, i) => (i > 0 && p.line !== layout.pieces[i - 1].line ? " " : "") + p.text).join("") });
|
|
3784
3841
|
return group;
|
|
3785
3842
|
}
|
|
3843
|
+
var ORIGINAL_SCALE_MODE = /* @__PURE__ */ new WeakMap();
|
|
3786
3844
|
var ImageSequence = class extends Sequence {
|
|
3787
3845
|
async build() {
|
|
3788
3846
|
const texture = await Assets.get(this.spec.asset);
|
|
3847
|
+
const source = texture.source;
|
|
3848
|
+
if (source && !ORIGINAL_SCALE_MODE.has(source)) ORIGINAL_SCALE_MODE.set(source, source.scaleMode);
|
|
3849
|
+
const mode = this.spec.scaleMode;
|
|
3850
|
+
if (mode !== void 0 && mode !== "nearest" && mode !== "linear") console.warn(`pixi-effects: ${describeLayer(this.spec)}: scaleMode "${String(mode)}" is not "nearest" or "linear": ignored`);
|
|
3851
|
+
if (source) source.scaleMode = mode === "nearest" || mode === "linear" ? mode : ORIGINAL_SCALE_MODE.get(source);
|
|
3789
3852
|
const sprite = new Sprite({ texture, label: this.spec.name });
|
|
3790
3853
|
sprite.cullable = true;
|
|
3791
3854
|
this.target = sprite;
|
|
@@ -4642,6 +4705,21 @@ function slice(line, a, b) {
|
|
|
4642
4705
|
}
|
|
4643
4706
|
return out;
|
|
4644
4707
|
}
|
|
4708
|
+
function splitEvenOdd(d) {
|
|
4709
|
+
const parts = d.split(/(?=[Mm])/).map((x) => x.trim()).filter(Boolean);
|
|
4710
|
+
if (parts.length < 2) return { main: d.trim(), holes: [] };
|
|
4711
|
+
const area = (sub2) => flattenSvgPath(sub2).reduce((sum, line) => {
|
|
4712
|
+
let a = 0;
|
|
4713
|
+
for (let i = 0; i < line.pts.length; i += 2) {
|
|
4714
|
+
const j = (i + 2) % line.pts.length;
|
|
4715
|
+
a += line.pts[i] * line.pts[j + 1] - line.pts[j] * line.pts[i + 1];
|
|
4716
|
+
}
|
|
4717
|
+
return sum + Math.abs(a) / 2;
|
|
4718
|
+
}, 0);
|
|
4719
|
+
const areas = parts.map(area);
|
|
4720
|
+
const big = areas.indexOf(Math.max(...areas));
|
|
4721
|
+
return { main: parts[big], holes: parts.filter((_, i) => i !== big) };
|
|
4722
|
+
}
|
|
4645
4723
|
|
|
4646
4724
|
// src/sequences/morphPath.ts
|
|
4647
4725
|
function resample(line, n) {
|
|
@@ -4704,6 +4782,11 @@ function buildMorph(from, to, n = 128) {
|
|
|
4704
4782
|
for (let i = 0; i < count; i++) {
|
|
4705
4783
|
const fa = from[i], fb = to[i];
|
|
4706
4784
|
const closed = (fa?.closed ?? fb.closed) && (fb?.closed ?? fa.closed);
|
|
4785
|
+
if (fa && fb && fa.closed === fb.closed && fa.pts.length === fb.pts.length && fa.pts.length >= 6) {
|
|
4786
|
+
const a2 = [...fa.pts];
|
|
4787
|
+
pairs.push({ a: a2, b: closed ? align(a2, [...fb.pts]) : [...fb.pts], closed });
|
|
4788
|
+
continue;
|
|
4789
|
+
}
|
|
4707
4790
|
const a = fa ? resample({ pts: fa.pts, closed }, n) : collapsed(resample({ pts: fb.pts, closed }, n));
|
|
4708
4791
|
let b = fb ? resample({ pts: fb.pts, closed }, n) : collapsed(a);
|
|
4709
4792
|
if (closed && fa && fb) b = align(a, b);
|
|
@@ -4787,6 +4870,8 @@ var ShapeSequence = class extends Sequence {
|
|
|
4787
4870
|
const morph = this._setupMorph();
|
|
4788
4871
|
this._drawGeometry = makeDrawGeometry(this.spec, scope, this._state, morph);
|
|
4789
4872
|
this._outline = makeOutline(this.spec, scope, this._state, morph);
|
|
4873
|
+
const eo = this.spec.shape === "path" && this.spec.fillRule === "evenodd" && !morph ? splitEvenOdd(this.spec.d) : null;
|
|
4874
|
+
this._evenOdd = eo && eo.holes.length > 0 ? eo : null;
|
|
4790
4875
|
const { trimStart, trimEnd } = this._state;
|
|
4791
4876
|
this._state.trimStart = 0;
|
|
4792
4877
|
this._state.trimEnd = 1;
|
|
@@ -4852,6 +4937,27 @@ var ShapeSequence = class extends Sequence {
|
|
|
4852
4937
|
_painter = null;
|
|
4853
4938
|
_gradDirty = false;
|
|
4854
4939
|
_outline = null;
|
|
4940
|
+
/** fillRule 'evenodd' on a path: the shape and the sub-paths cut out of it after it is filled (null: not used). */
|
|
4941
|
+
_evenOdd = null;
|
|
4942
|
+
/**
|
|
4943
|
+
* fillRule 'evenodd': the shape is filled, each hole is cut out of that fill, and the stroke goes round the shape and every hole. (PIXI's `cut()` only reaches the
|
|
4944
|
+
* LAST instruction, so it has to come between the fill and the stroke.)
|
|
4945
|
+
*/
|
|
4946
|
+
_fillWithHoles(g) {
|
|
4947
|
+
const s = this._state, { main, holes } = this._evenOdd;
|
|
4948
|
+
applyFill(g, s);
|
|
4949
|
+
for (const hole of holes) {
|
|
4950
|
+
g.beginPath();
|
|
4951
|
+
g.path(new GraphicsPath(hole));
|
|
4952
|
+
g.cut();
|
|
4953
|
+
}
|
|
4954
|
+
if (s.strokeColor !== void 0 && s.strokeWidth > 0) {
|
|
4955
|
+
g.beginPath();
|
|
4956
|
+
g.path(new GraphicsPath(main));
|
|
4957
|
+
for (const hole of holes) g.path(new GraphicsPath(hole));
|
|
4958
|
+
applyStroke(g, s);
|
|
4959
|
+
}
|
|
4960
|
+
}
|
|
4855
4961
|
_redraw() {
|
|
4856
4962
|
const graphics = this.target;
|
|
4857
4963
|
const s = this._state;
|
|
@@ -4863,6 +4969,10 @@ var ShapeSequence = class extends Sequence {
|
|
|
4863
4969
|
const trimmed = (s.trimStart ?? 0) > 0 || (s.trimEnd ?? 1) < 1;
|
|
4864
4970
|
if (!trimmed || !this._outline || !(s.strokeColor !== void 0 && s.strokeWidth > 0)) {
|
|
4865
4971
|
this._drawGeometry(graphics);
|
|
4972
|
+
if (this._evenOdd) {
|
|
4973
|
+
this._fillWithHoles(graphics);
|
|
4974
|
+
return;
|
|
4975
|
+
}
|
|
4866
4976
|
applyState(graphics, s);
|
|
4867
4977
|
return;
|
|
4868
4978
|
}
|
|
@@ -5086,8 +5196,9 @@ function makePolygonDraw(spec, scope) {
|
|
|
5086
5196
|
};
|
|
5087
5197
|
}
|
|
5088
5198
|
function makePathDraw(spec) {
|
|
5199
|
+
const d = spec.fillRule === "evenodd" ? splitEvenOdd(spec.d).main : spec.d;
|
|
5089
5200
|
return (g) => {
|
|
5090
|
-
g.path(new GraphicsPath(
|
|
5201
|
+
g.path(new GraphicsPath(d));
|
|
5091
5202
|
};
|
|
5092
5203
|
}
|
|
5093
5204
|
var STATE_DRAWERS = {
|
|
@@ -5618,18 +5729,311 @@ function resolveDim(v, scope) {
|
|
|
5618
5729
|
if (typeof v === "number") return v;
|
|
5619
5730
|
return evaluateExpr(v, scope);
|
|
5620
5731
|
}
|
|
5732
|
+
var MAX_SIZE = 8192;
|
|
5733
|
+
var MIN_RESOLUTION = 0.25;
|
|
5734
|
+
var MAX_RESOLUTION = 4;
|
|
5735
|
+
var NOT_PURE = /\bMath\s*\.\s*random\s*\(|\bDate\s*\.\s*now\s*\(|\bperformance\s*\.\s*now\s*\(|\bnew\s+Date\s*\(/;
|
|
5736
|
+
function seeded(seed) {
|
|
5737
|
+
let a = seed >>> 0;
|
|
5738
|
+
return () => {
|
|
5739
|
+
a = a + 1831565813 >>> 0;
|
|
5740
|
+
let t = a;
|
|
5741
|
+
t = Math.imul(t ^ t >>> 15, t | 1);
|
|
5742
|
+
t ^= t + Math.imul(t ^ t >>> 7, t | 61);
|
|
5743
|
+
return ((t ^ t >>> 14) >>> 0) / 4294967296;
|
|
5744
|
+
};
|
|
5745
|
+
}
|
|
5746
|
+
function offscreen(width, height) {
|
|
5747
|
+
const c = document.createElement("canvas");
|
|
5748
|
+
c.width = Math.max(1, Math.round(width));
|
|
5749
|
+
c.height = Math.max(1, Math.round(height));
|
|
5750
|
+
c.getContext("2d", { willReadFrequently: true });
|
|
5751
|
+
return c;
|
|
5752
|
+
}
|
|
5753
|
+
var CanvasSequence = class extends Sequence {
|
|
5754
|
+
canvas = null;
|
|
5755
|
+
w = 1;
|
|
5756
|
+
h = 1;
|
|
5757
|
+
res = 1;
|
|
5758
|
+
fps = 30;
|
|
5759
|
+
layerW = 1;
|
|
5760
|
+
layerH = 1;
|
|
5761
|
+
seed = 0;
|
|
5762
|
+
smoothing = true;
|
|
5763
|
+
drawFn = null;
|
|
5764
|
+
state;
|
|
5765
|
+
/** The current value of every param: what keyframes move (`params.amount`). */
|
|
5766
|
+
carrier = {};
|
|
5767
|
+
failed = false;
|
|
5768
|
+
warnedDraw = false;
|
|
5769
|
+
warnedPaths = /* @__PURE__ */ new Set();
|
|
5770
|
+
lastKey = "";
|
|
5771
|
+
lastLocal = 0;
|
|
5772
|
+
get canvasSpec() {
|
|
5773
|
+
return this.spec;
|
|
5774
|
+
}
|
|
5775
|
+
pathRouters() {
|
|
5776
|
+
return { params: (path) => this.resolveParam(path) };
|
|
5777
|
+
}
|
|
5778
|
+
async build() {
|
|
5779
|
+
const spec = this.canvasSpec;
|
|
5780
|
+
const who = describeLayer(spec);
|
|
5781
|
+
if (this.duration === void 0) this.duration = this.parent?.duration ?? this.root.duration;
|
|
5782
|
+
const scope = buildScope(this, this.parent, this.root);
|
|
5783
|
+
this.layerW = this.size("width", spec.width, scope, this.parent?.width ?? this.root.width, who);
|
|
5784
|
+
this.layerH = this.size("height", spec.height, scope, this.parent?.height ?? this.root.height, who);
|
|
5785
|
+
const r = spec.resolution;
|
|
5786
|
+
if (r === void 0) this.res = 1;
|
|
5787
|
+
else if (typeof r === "number" && Number.isFinite(r) && r >= MIN_RESOLUTION && r <= MAX_RESOLUTION) this.res = r;
|
|
5788
|
+
else {
|
|
5789
|
+
this.res = typeof r === "number" && Number.isFinite(r) ? Math.min(MAX_RESOLUTION, Math.max(MIN_RESOLUTION, r)) : 1;
|
|
5790
|
+
console.warn(`pixi-effects: ${who}: resolution must be a number from ${MIN_RESOLUTION} to ${MAX_RESOLUTION} (canvas pixels per layer pixel), got ${JSON.stringify(r)}: ${this.res} is used`);
|
|
5791
|
+
}
|
|
5792
|
+
const longest = Math.max(this.layerW, this.layerH);
|
|
5793
|
+
if (longest * this.res > MAX_SIZE) {
|
|
5794
|
+
const fitted = MAX_SIZE / longest;
|
|
5795
|
+
console.warn(`pixi-effects: ${who}: ${this.layerW}\xD7${this.layerH} at resolution ${this.res} would be a canvas of ${Math.round(longest * this.res)} pixels, more than ${MAX_SIZE}: resolution ${Math.round(fitted * 1e3) / 1e3} is used (lower the size or the resolution)`);
|
|
5796
|
+
this.res = fitted;
|
|
5797
|
+
}
|
|
5798
|
+
this.w = Math.max(1, Math.round(this.layerW * this.res));
|
|
5799
|
+
this.h = Math.max(1, Math.round(this.layerH * this.res));
|
|
5800
|
+
this.fps = this.root.frameRate ?? 30;
|
|
5801
|
+
this.seed = typeof spec.seed === "number" && Number.isFinite(spec.seed) ? Math.floor(spec.seed) : 0;
|
|
5802
|
+
this.smoothing = spec.smoothing !== false;
|
|
5803
|
+
const params = spec.params;
|
|
5804
|
+
if (params !== void 0) {
|
|
5805
|
+
if (params === null || typeof params !== "object" || Array.isArray(params)) {
|
|
5806
|
+
console.warn(`pixi-effects: ${who}: params must be an object of numbers, got ${JSON.stringify(params)}: ignored`);
|
|
5807
|
+
} else {
|
|
5808
|
+
const bad = [];
|
|
5809
|
+
for (const [k, v] of Object.entries(params)) {
|
|
5810
|
+
if (typeof v === "number" && Number.isFinite(v)) this.carrier[k] = v;
|
|
5811
|
+
else bad.push(`"${k}"`);
|
|
5812
|
+
}
|
|
5813
|
+
if (bad.length) console.warn(`pixi-effects: ${who}: params ${bad.join(", ")} ${bad.length > 1 ? "are" : "is"} not a number, so ${bad.length > 1 ? "they are" : "it is"} ignored (params holds numbers that keyframes can animate as 'params.<name>')`);
|
|
5814
|
+
}
|
|
5815
|
+
}
|
|
5816
|
+
if (typeof spec.draw === "function") {
|
|
5817
|
+
this.drawFn = spec.draw;
|
|
5818
|
+
if (NOT_PURE.test(spec.draw.toString())) {
|
|
5819
|
+
console.warn(`pixi-effects: ${who}: draw calls Math.random, Date.now, performance.now or new Date, so it is not deterministic: the same frame would draw differently in playback, in a seek and in an export. Use info.random() (seeded), or derive the value from t`);
|
|
5820
|
+
}
|
|
5821
|
+
} else {
|
|
5822
|
+
this.failed = true;
|
|
5823
|
+
console.warn(`pixi-effects: ${who}: a canvas layer needs draw: (ctx, t, info) => { \u2026 } (a function that draws the picture at time t); the layer is drawn as a checkerboard`);
|
|
5824
|
+
}
|
|
5825
|
+
this.canvas = document.createElement("canvas");
|
|
5826
|
+
this.canvas.width = this.w;
|
|
5827
|
+
this.canvas.height = this.h;
|
|
5828
|
+
const sprite = new Sprite({ texture: Texture.from(this.canvas), label: spec.name });
|
|
5829
|
+
if (!this.smoothing) sprite.texture.source.scaleMode = "nearest";
|
|
5830
|
+
sprite.width = this.layerW;
|
|
5831
|
+
sprite.height = this.layerH;
|
|
5832
|
+
this.target = sprite;
|
|
5833
|
+
this.intrinsicWidth = this.layerW;
|
|
5834
|
+
this.intrinsicHeight = this.layerH;
|
|
5835
|
+
this.buildFilters();
|
|
5836
|
+
if (typeof spec.setup === "function" && !this.failed) {
|
|
5837
|
+
try {
|
|
5838
|
+
this.state = await spec.setup(this.info(0));
|
|
5839
|
+
} catch (e) {
|
|
5840
|
+
this.failed = true;
|
|
5841
|
+
this.say(`setup failed: ${e instanceof Error ? e.message : String(e)}; the layer is drawn as a checkerboard`);
|
|
5842
|
+
}
|
|
5843
|
+
}
|
|
5844
|
+
this.drawAt(0);
|
|
5845
|
+
}
|
|
5846
|
+
async awaitFrameAt(local) {
|
|
5847
|
+
this.drawAt(Math.max(0, Math.min(local, this.duration ?? local)));
|
|
5848
|
+
}
|
|
5849
|
+
size(name, v, scope, fallback, who) {
|
|
5850
|
+
if (v === void 0) return fallback;
|
|
5851
|
+
const n = typeof v === "number" ? v : evaluateExpr(v, scope);
|
|
5852
|
+
if (!Number.isFinite(n) || n < 1) {
|
|
5853
|
+
console.warn(`pixi-effects: ${who}: ${name} must be a number of pixels of at least 1 (or an expression), got ${JSON.stringify(v)}: ${fallback} is used`);
|
|
5854
|
+
return fallback;
|
|
5855
|
+
}
|
|
5856
|
+
if (n > MAX_SIZE) {
|
|
5857
|
+
console.warn(`pixi-effects: ${who}: ${name} ${n} is more than ${MAX_SIZE}: ${MAX_SIZE} is used`);
|
|
5858
|
+
return MAX_SIZE;
|
|
5859
|
+
}
|
|
5860
|
+
return n;
|
|
5861
|
+
}
|
|
5862
|
+
say(why) {
|
|
5863
|
+
if (this.warnedDraw) return;
|
|
5864
|
+
this.warnedDraw = true;
|
|
5865
|
+
console.warn(`pixi-effects: ${describeLayer(this.spec)}: ${why}`);
|
|
5866
|
+
}
|
|
5867
|
+
info(local) {
|
|
5868
|
+
const duration = this.duration ?? 0;
|
|
5869
|
+
const start = this.absoluteStart ?? this.at;
|
|
5870
|
+
return {
|
|
5871
|
+
frame: Math.round(local * this.fps),
|
|
5872
|
+
duration,
|
|
5873
|
+
progress: duration > 0 ? local / duration : 0,
|
|
5874
|
+
width: this.layerW,
|
|
5875
|
+
height: this.layerH,
|
|
5876
|
+
resolution: this.res,
|
|
5877
|
+
frameRate: this.fps,
|
|
5878
|
+
params: { ...this.carrier },
|
|
5879
|
+
state: this.state,
|
|
5880
|
+
random: seeded(this.seed),
|
|
5881
|
+
start,
|
|
5882
|
+
time: start + local,
|
|
5883
|
+
canvas: offscreen
|
|
5884
|
+
};
|
|
5885
|
+
}
|
|
5886
|
+
/** Resolve `params.amount` for the keyframe pipeline; a name nobody declared is said once and dropped. */
|
|
5887
|
+
resolveParam(path) {
|
|
5888
|
+
if (path in this.carrier && !path.includes(".")) return { target: this.carrier, prop: path };
|
|
5889
|
+
if (!this.warnedPaths.has(path)) {
|
|
5890
|
+
this.warnedPaths.add(path);
|
|
5891
|
+
const guess = suggestName(path.split(".")[0], Object.keys(this.carrier));
|
|
5892
|
+
console.warn(`pixi-effects: ${describeLayer(this.spec)}: keyframe path params.${path} names no param "${path}"${guess ? `; did you mean "${guess}"?` : ""} (declare it in params with a starting value); skipped`);
|
|
5893
|
+
}
|
|
5894
|
+
return null;
|
|
5895
|
+
}
|
|
5896
|
+
drawAt(local) {
|
|
5897
|
+
const c = this.canvas;
|
|
5898
|
+
if (!c) return;
|
|
5899
|
+
const ctx = c.getContext("2d");
|
|
5900
|
+
if (!ctx) {
|
|
5901
|
+
this.say("this browser gave no 2D context for the layer's canvas, so nothing can be drawn");
|
|
5902
|
+
return;
|
|
5903
|
+
}
|
|
5904
|
+
const key = `${local}|${this.absoluteStart ?? this.at}|${JSON.stringify(this.carrier)}`;
|
|
5905
|
+
if (key === this.lastKey) return;
|
|
5906
|
+
this.lastKey = key;
|
|
5907
|
+
this.lastLocal = local;
|
|
5908
|
+
if (!this.paint(ctx, c, local)) this.lastKey = "";
|
|
5909
|
+
this.target?.texture.source.update();
|
|
5910
|
+
}
|
|
5911
|
+
/** Draws one frame of the layer into `ctx` (the layer's own canvas, or the scratch one of the determinism check). false: `draw` threw. */
|
|
5912
|
+
paint(ctx, c, local) {
|
|
5913
|
+
const hasReset = "reset" in ctx && typeof ctx.reset === "function";
|
|
5914
|
+
const fresh = () => {
|
|
5915
|
+
if (hasReset) ctx.reset();
|
|
5916
|
+
else {
|
|
5917
|
+
ctx.setTransform(1, 0, 0, 1, 0, 0);
|
|
5918
|
+
ctx.clearRect(0, 0, c.width, c.height);
|
|
5919
|
+
}
|
|
5920
|
+
};
|
|
5921
|
+
fresh();
|
|
5922
|
+
if (this.failed || !this.drawFn) {
|
|
5923
|
+
this.checkerboard(ctx, c);
|
|
5924
|
+
return true;
|
|
5925
|
+
}
|
|
5926
|
+
if (!hasReset) ctx.save();
|
|
5927
|
+
let ok = true;
|
|
5928
|
+
try {
|
|
5929
|
+
ctx.scale(this.res, this.res);
|
|
5930
|
+
ctx.imageSmoothingEnabled = this.smoothing;
|
|
5931
|
+
this.drawFn(ctx, local, this.info(local));
|
|
5932
|
+
} catch (e) {
|
|
5933
|
+
if (!hasReset) {
|
|
5934
|
+
ctx.restore();
|
|
5935
|
+
ctx.save();
|
|
5936
|
+
}
|
|
5937
|
+
fresh();
|
|
5938
|
+
this.say(`draw threw at ${local.toFixed(2)} s: ${e instanceof Error ? e.message : String(e)}; that frame is drawn as a checkerboard (the other frames are tried again)`);
|
|
5939
|
+
this.checkerboard(ctx, c);
|
|
5940
|
+
ok = false;
|
|
5941
|
+
}
|
|
5942
|
+
if (!hasReset) ctx.restore();
|
|
5943
|
+
return ok;
|
|
5944
|
+
}
|
|
5945
|
+
/**
|
|
5946
|
+
* Draws each of `times` in two orders and returns the moments where the pictures differ (a draw that uses Math.random, the clock or state that outlives the call), with how much
|
|
5947
|
+
* (channel values that differ, the largest difference out of 255), and how long a draw took. One draw of every moment comes first and is thrown away: a browser can draw a canvas
|
|
5948
|
+
* made in `setup` differently the first time it is used as a source, and a cache a draw fills on its first call is fine. The layer's own canvas is not touched (everything is drawn in a scratch canvas).
|
|
5949
|
+
* A layer that failed, or a draw that throws, is reported in `threw`.
|
|
5950
|
+
*/
|
|
5951
|
+
checkDeterminism(times) {
|
|
5952
|
+
const none = { differs: [], drawMs: 0, threw: [] };
|
|
5953
|
+
if (!this.canvas) return none;
|
|
5954
|
+
if (this.failed || !this.drawFn) return { ...none, threw: [...times] };
|
|
5955
|
+
const scratch = document.createElement("canvas");
|
|
5956
|
+
scratch.width = this.w;
|
|
5957
|
+
scratch.height = this.h;
|
|
5958
|
+
const ctx = scratch.getContext("2d", { willReadFrequently: true });
|
|
5959
|
+
if (!ctx) return none;
|
|
5960
|
+
const keep = this.w * this.h * 4 * times.length <= 96e6;
|
|
5961
|
+
const read2 = () => ctx.getImageData(0, 0, scratch.width, scratch.height).data;
|
|
5962
|
+
const hash = (d) => {
|
|
5963
|
+
let h = 2166136261;
|
|
5964
|
+
for (let i = 0; i < d.length; i++) {
|
|
5965
|
+
h ^= d[i];
|
|
5966
|
+
h = Math.imul(h, 16777619);
|
|
5967
|
+
}
|
|
5968
|
+
return h >>> 0;
|
|
5969
|
+
};
|
|
5970
|
+
const ms = [];
|
|
5971
|
+
const threw = /* @__PURE__ */ new Set();
|
|
5972
|
+
const once = (t, timed) => {
|
|
5973
|
+
const from = performance.now();
|
|
5974
|
+
if (!this.paint(ctx, scratch, t)) threw.add(t);
|
|
5975
|
+
if (timed) {
|
|
5976
|
+
ctx.getImageData(0, 0, 1, 1);
|
|
5977
|
+
ms.push(performance.now() - from);
|
|
5978
|
+
}
|
|
5979
|
+
return read2();
|
|
5980
|
+
};
|
|
5981
|
+
for (const t of times) once(t, false);
|
|
5982
|
+
const first = times.map((t) => {
|
|
5983
|
+
const d = once(t, true);
|
|
5984
|
+
return keep ? d.slice() : hash(d);
|
|
5985
|
+
});
|
|
5986
|
+
const second = [...times].reverse().map((t) => once(t, false)).reverse();
|
|
5987
|
+
scratch.width = scratch.height = 1;
|
|
5988
|
+
const differs = [];
|
|
5989
|
+
times.forEach((t, i) => {
|
|
5990
|
+
const a = first[i], b = second[i];
|
|
5991
|
+
if (typeof a === "number") {
|
|
5992
|
+
if (a !== hash(b)) differs.push({ t, pixels: -1, maxDiff: -1 });
|
|
5993
|
+
return;
|
|
5994
|
+
}
|
|
5995
|
+
let pixels = 0, maxDiff = 0;
|
|
5996
|
+
for (let k = 0; k < a.length; k++) {
|
|
5997
|
+
const d = Math.abs(a[k] - b[k]);
|
|
5998
|
+
if (d) {
|
|
5999
|
+
pixels++;
|
|
6000
|
+
if (d > maxDiff) maxDiff = d;
|
|
6001
|
+
}
|
|
6002
|
+
}
|
|
6003
|
+
if (pixels) differs.push({ t, pixels, maxDiff });
|
|
6004
|
+
});
|
|
6005
|
+
ms.sort((x, y) => x - y);
|
|
6006
|
+
return { differs: differs.filter((d) => !threw.has(d.t)), drawMs: ms.length ? ms[Math.floor(ms.length / 2)] : 0, threw: times.filter((t) => threw.has(t)) };
|
|
6007
|
+
}
|
|
6008
|
+
checkerboard(ctx, c) {
|
|
6009
|
+
const s = 32;
|
|
6010
|
+
for (let y = 0; y < c.height; y += s) for (let x = 0; x < c.width; x += s) {
|
|
6011
|
+
ctx.fillStyle = x / s + y / s & 1 ? "#ff00ff" : "#220022";
|
|
6012
|
+
ctx.fillRect(x, y, s, s);
|
|
6013
|
+
}
|
|
6014
|
+
}
|
|
6015
|
+
destroy() {
|
|
6016
|
+
const texture = this.target?.texture;
|
|
6017
|
+
if (this.canvas) {
|
|
6018
|
+
this.canvas.width = this.canvas.height = 1;
|
|
6019
|
+
this.canvas = null;
|
|
6020
|
+
}
|
|
6021
|
+
super.destroy();
|
|
6022
|
+
texture?.destroy(true);
|
|
6023
|
+
}
|
|
6024
|
+
};
|
|
5621
6025
|
|
|
5622
6026
|
// src/core/Composition.ts
|
|
5623
6027
|
var _CompositionSequence = null;
|
|
5624
6028
|
async function getCompositionSequence() {
|
|
5625
6029
|
if (!_CompositionSequence) {
|
|
5626
|
-
_CompositionSequence = (await import('./Composition-
|
|
6030
|
+
_CompositionSequence = (await import('./Composition-5KZETM4J.js')).CompositionSequence;
|
|
5627
6031
|
}
|
|
5628
6032
|
return _CompositionSequence;
|
|
5629
6033
|
}
|
|
5630
6034
|
var _SpansSequence = null;
|
|
5631
6035
|
async function getSpansSequence() {
|
|
5632
|
-
if (!_SpansSequence) _SpansSequence = (await import('./Spans-
|
|
6036
|
+
if (!_SpansSequence) _SpansSequence = (await import('./Spans-FSSO2HGX.js')).SpansSequence;
|
|
5633
6037
|
return _SpansSequence;
|
|
5634
6038
|
}
|
|
5635
6039
|
var staticTypes = {
|
|
@@ -5641,6 +6045,7 @@ var staticTypes = {
|
|
|
5641
6045
|
camera: CameraSequence,
|
|
5642
6046
|
light: LightSequence,
|
|
5643
6047
|
shader: ShaderSequence,
|
|
6048
|
+
canvas: CanvasSequence,
|
|
5644
6049
|
null: NullSequence
|
|
5645
6050
|
};
|
|
5646
6051
|
var registry2 = {};
|
|
@@ -5674,6 +6079,6 @@ async function buildSequenceTree(specs, parent, root) {
|
|
|
5674
6079
|
return out;
|
|
5675
6080
|
}
|
|
5676
6081
|
|
|
5677
|
-
export { CameraSequence, DEFAULT_FOV, DEG3 as DEG, EXPRESSION_NAMES, FALLOFFS, LIGHT_KINDS, LIGHT_PROPS, LightSequence, MANY_BLURRED, MAX_BLUR, MAX_CASTERS, MAX_LIGHTS, MIN_BLUR, NEAR, NullSequence, SHADOW_TAPS, Sequence, TextSequence, bindClock, bindCounterKeyframes, blurRadius, buildScope, buildSequenceTree, cameraBasis, checkEase, clockTable, contentLength, createTimeline, ensureFilterLibrary, evaluateExpr, flattenSvgPath, focusProblems, homeCamera, homeDistance, layerInitialZ, layerToWorld, lengthen, lightLevel, noise, packLights, parseEase, parseSpring, projectLayer, projectPoint, rand, random, registerSequenceType, remapOf, resolveAt, resolveNumber, spansMeta, springDuration, timeRemapOf };
|
|
5678
|
-
//# sourceMappingURL=chunk-
|
|
5679
|
-
//# sourceMappingURL=chunk-
|
|
6082
|
+
export { CameraSequence, DEFAULT_FOV, DEG3 as DEG, EXPRESSION_NAMES, FALLOFFS, LIGHT_KINDS, LIGHT_PROPS, LightSequence, MANY_BLURRED, MAX_BLUR, MAX_CASTERS, MAX_LIGHTS, MIN_BLUR, NEAR, NullSequence, SHADOW_TAPS, Sequence, TextSequence, bindClock, bindCounterKeyframes, blurRadius, buildScope, buildSequenceTree, cameraBasis, checkEase, clockTable, contentLength, createTimeline, ensureFilterLibrary, evaluateExpr, flattenSvgPath, focusProblems, homeCamera, homeDistance, layerInitialZ, layerToWorld, lengthen, lightLevel, noise, noise2, packLights, parseEase, parseSpring, projectLayer, projectPoint, rand, random, registerSequenceType, remapOf, resolveAt, resolveNumber, spansMeta, springDuration, timeRemapOf, trimPolylines };
|
|
6083
|
+
//# sourceMappingURL=chunk-SBR75G73.js.map
|
|
6084
|
+
//# sourceMappingURL=chunk-SBR75G73.js.map
|