pixi-effects 0.48.2 → 0.50.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.
Files changed (88) hide show
  1. package/CHANGELOG.md +17 -0
  2. package/README.md +53 -8
  3. package/ai/chat-template.html +8 -4
  4. package/ai/tools/check.mjs +6 -6
  5. package/dist/3d.cjs +967 -0
  6. package/dist/3d.cjs.map +1 -0
  7. package/dist/3d.d.cts +305 -0
  8. package/dist/3d.d.ts +305 -0
  9. package/dist/3d.js +960 -0
  10. package/dist/3d.js.map +1 -0
  11. package/dist/Canvas-BfZkAFJm.d.cts +12 -0
  12. package/dist/Canvas-BfZkAFJm.d.ts +12 -0
  13. package/dist/Composition-47U5U637.cjs +16 -0
  14. package/dist/{Composition-TJ5D7Z63.cjs.map → Composition-47U5U637.cjs.map} +1 -1
  15. package/dist/Composition-GVWWLFDL.js +7 -0
  16. package/dist/{Composition-5FKV2IBP.js.map → Composition-GVWWLFDL.js.map} +1 -1
  17. package/dist/Controller.d.cts +2 -2
  18. package/dist/Controller.d.ts +2 -2
  19. package/dist/{Movie-svZQF-9Z.d.cts → Movie-DogzDBuW.d.cts} +36 -5
  20. package/dist/{Movie--qSYKgAQ.d.ts → Movie-Y7iHg2V8.d.ts} +36 -5
  21. package/dist/{Spans-6A3VLHRH.js → Spans-3SEZSTQV.js} +6 -6
  22. package/dist/{Spans-6A3VLHRH.js.map → Spans-3SEZSTQV.js.map} +1 -1
  23. package/dist/{Spans-5ENZ3XGS.cjs → Spans-R426NVY3.cjs} +11 -11
  24. package/dist/{Spans-5ENZ3XGS.cjs.map → Spans-R426NVY3.cjs.map} +1 -1
  25. package/dist/{blendModes-V5XHC7U4.cjs → blendModes-2IDILRN6.cjs} +5 -5
  26. package/dist/{blendModes-V5XHC7U4.cjs.map → blendModes-2IDILRN6.cjs.map} +1 -1
  27. package/dist/{blendModes-535EMYGK.js → blendModes-4QH44GOL.js} +4 -4
  28. package/dist/{blendModes-535EMYGK.js.map → blendModes-4QH44GOL.js.map} +1 -1
  29. package/dist/{chunk-NGJXVJB7.cjs → chunk-3FCDRLW3.cjs} +5 -3
  30. package/dist/chunk-3FCDRLW3.cjs.map +1 -0
  31. package/dist/{chunk-JBDBICS2.js → chunk-C2HL5236.js} +4 -4
  32. package/dist/{chunk-JBDBICS2.js.map → chunk-C2HL5236.js.map} +1 -1
  33. package/dist/{chunk-WYR2AU4W.cjs → chunk-GXGIISFS.cjs} +5 -5
  34. package/dist/{chunk-WYR2AU4W.cjs.map → chunk-GXGIISFS.cjs.map} +1 -1
  35. package/dist/{chunk-BFRWSV3R.js → chunk-J4ZP76IL.js} +5 -4
  36. package/dist/chunk-J4ZP76IL.js.map +1 -0
  37. package/dist/{chunk-CCPJD76D.cjs → chunk-O2MD3L4J.cjs} +93 -93
  38. package/dist/chunk-O2MD3L4J.cjs.map +1 -0
  39. package/dist/{chunk-IVKI6CPH.js → chunk-SSVHAF3Q.js} +483 -20
  40. package/dist/chunk-SSVHAF3Q.js.map +1 -0
  41. package/dist/{chunk-6D4W2KZQ.js → chunk-TXNQLMRT.js} +6 -6
  42. package/dist/chunk-TXNQLMRT.js.map +1 -0
  43. package/dist/{chunk-RCKLUCB7.js → chunk-UTUUOQ47.js} +46 -20
  44. package/dist/chunk-UTUUOQ47.js.map +1 -0
  45. package/dist/{chunk-Z3DM4ETD.cjs → chunk-VVUSZVP7.cjs} +507 -42
  46. package/dist/chunk-VVUSZVP7.cjs.map +1 -0
  47. package/dist/{chunk-45ALIMAF.cjs → chunk-YOKRPAKA.cjs} +89 -63
  48. package/dist/chunk-YOKRPAKA.cjs.map +1 -0
  49. package/dist/index.cjs +35 -35
  50. package/dist/index.d.cts +3 -3
  51. package/dist/index.d.ts +3 -3
  52. package/dist/index.js +5 -5
  53. package/dist/loader.css +1 -1
  54. package/dist/{music-P4JRT73P.js → music-ATX22VAT.js} +3 -3
  55. package/dist/{music-P4JRT73P.js.map → music-ATX22VAT.js.map} +1 -1
  56. package/dist/{music-XQEPBIDT.cjs → music-OFVM3PYH.cjs} +3 -3
  57. package/dist/{music-XQEPBIDT.cjs.map → music-OFVM3PYH.cjs.map} +1 -1
  58. package/dist/present.cjs +5 -5
  59. package/dist/present.d.cts +2 -2
  60. package/dist/present.d.ts +2 -2
  61. package/dist/present.js +5 -5
  62. package/dist/three.cjs +13 -10
  63. package/dist/three.cjs.map +1 -1
  64. package/dist/three.d.cts +4 -12
  65. package/dist/three.d.ts +4 -12
  66. package/dist/three.js +8 -5
  67. package/dist/three.js.map +1 -1
  68. package/dist/{types-CTSrPvY3.d.cts → types-BZngm4nT.d.cts} +48 -5
  69. package/dist/{types-CTSrPvY3.d.ts → types-BZngm4nT.d.ts} +48 -5
  70. package/docs/api.md +45 -2
  71. package/docs/dsl.md +115 -1
  72. package/llms-full.txt +307 -6
  73. package/package.json +19 -3
  74. package/skills/pixi-effects/SKILL.md +4 -2
  75. package/skills/pixi-effects/reference/cheatsheet.md +4 -0
  76. package/skills/pixi-effects/reference/pitfalls.md +20 -0
  77. package/skills/pixi-effects/reference/recipes.md +119 -1
  78. package/skills/pixi-effects/template.html +14 -8
  79. package/dist/Composition-5FKV2IBP.js +0 -7
  80. package/dist/Composition-TJ5D7Z63.cjs +0 -16
  81. package/dist/chunk-45ALIMAF.cjs.map +0 -1
  82. package/dist/chunk-6D4W2KZQ.js.map +0 -1
  83. package/dist/chunk-BFRWSV3R.js.map +0 -1
  84. package/dist/chunk-CCPJD76D.cjs.map +0 -1
  85. package/dist/chunk-IVKI6CPH.js.map +0 -1
  86. package/dist/chunk-NGJXVJB7.cjs.map +0 -1
  87. package/dist/chunk-RCKLUCB7.js.map +0 -1
  88. package/dist/chunk-Z3DM4ETD.cjs.map +0 -1
@@ -1,6 +1,6 @@
1
- import { describeLayer, collectPropKeys } from './chunk-BFRWSV3R.js';
1
+ import { describeLayer, collectPropKeys } from './chunk-J4ZP76IL.js';
2
2
  import { suggestName, warnUnknownOptions } from './chunk-WGRWFQOB.js';
3
- import { Rectangle, Container, FillGradient, Text, Color, GraphicsPath, Sprite, Texture, Graphics, Assets, Filter, GlProgram, defaultFilterVert, GpuProgram, UniformGroup, AlphaFilter, NoiseFilter, BlurFilter, TextStyle, CanvasTextMetrics, ColorMatrixFilter } from 'pixi.js';
3
+ import { Rectangle, Container, FillGradient, Text, Color, GraphicsPath, RenderTexture, Sprite, Texture, Graphics, Assets, Filter, GlProgram, defaultFilterVert, GpuProgram, UniformGroup, AlphaFilter, NoiseFilter, BlurFilter, Point, Matrix, TextStyle, CanvasTextMetrics, ColorMatrixFilter } from 'pixi.js';
4
4
 
5
5
  // src/core/spring.ts
6
6
  var SETTLE_TOL = 5e-3;
@@ -512,9 +512,9 @@ var PureTimeline = class _PureTimeline {
512
512
  };
513
513
  const ends = given(vars);
514
514
  const starts = fromVars ? given(fromVars) : /* @__PURE__ */ new Map();
515
- const ids = kind === "fromTo" ? [.../* @__PURE__ */ new Set([...starts.keys(), ...ends.keys()])] : [...ends.keys()];
515
+ const ids2 = kind === "fromTo" ? [.../* @__PURE__ */ new Set([...starts.keys(), ...ends.keys()])] : [...ends.keys()];
516
516
  let lastAlpha;
517
- for (const id of ids) {
517
+ for (const id of ids2) {
518
518
  const e = ends.get(id), f = starts.get(id);
519
519
  const acc = (e ?? f).acc;
520
520
  const ch = this.channel(t, acc);
@@ -1383,6 +1383,9 @@ var PIXI_SHORTHANDS = /* @__PURE__ */ new Set([
1383
1383
  "fillColor",
1384
1384
  "fillAlpha"
1385
1385
  ]);
1386
+ function routedProp(prop, value) {
1387
+ return prop === "tint" ? { pixi: { tint: value } } : { [prop]: value };
1388
+ }
1386
1389
  function pixiwrap(props) {
1387
1390
  const out = {};
1388
1391
  const pixi = {};
@@ -1405,7 +1408,7 @@ function applyKeyframes(timeline, target, keyframes, parentDuration, scope, skip
1405
1408
  if (kf.kind === "set") {
1406
1409
  const resolved = normalizeProps(kf.set, scope, { skipKeys, relative: "allow" });
1407
1410
  const { rest, routed } = splitRouted(resolved, routers);
1408
- for (const r of routed) timeline.set(r.target, { [r.prop]: r.value }, at);
1411
+ for (const r of routed) timeline.set(r.target, routedProp(r.prop, r.value), at);
1409
1412
  const { ownProps, filterProps } = partitionProps(rest);
1410
1413
  if (Object.keys(ownProps).length > 0) timeline.set(target, pixiwrap(ownProps), at);
1411
1414
  for (const [name, props] of Object.entries(filterProps)) {
@@ -1417,7 +1420,7 @@ function applyKeyframes(timeline, target, keyframes, parentDuration, scope, skip
1417
1420
  const resolved = normalizeProps(kf.to, scope, { skipKeys, relative: "allow" });
1418
1421
  const { rest, routed } = splitRouted(resolved, routers);
1419
1422
  for (const r of routed)
1420
- timeline.to(r.target, { [r.prop]: r.value, duration: kf.duration, ease: kf.ease, ...kf.loop }, at);
1423
+ timeline.to(r.target, { ...routedProp(r.prop, r.value), duration: kf.duration, ease: kf.ease, ...kf.loop }, at);
1421
1424
  const { ownProps, filterProps } = partitionProps(rest);
1422
1425
  if (Object.keys(ownProps).length > 0)
1423
1426
  timeline.to(target, { ...pixiwrap(ownProps), duration: kf.duration, ease: kf.ease, ...kf.loop }, at);
@@ -1430,7 +1433,7 @@ function applyKeyframes(timeline, target, keyframes, parentDuration, scope, skip
1430
1433
  const resolved = normalizeProps(kf.from, scope, { skipKeys, relative: "allow" });
1431
1434
  const { rest, routed } = splitRouted(resolved, routers);
1432
1435
  for (const r of routed)
1433
- timeline.from(r.target, { [r.prop]: r.value, duration: kf.duration, ease: kf.ease, ...kf.loop }, at);
1436
+ timeline.from(r.target, { ...routedProp(r.prop, r.value), duration: kf.duration, ease: kf.ease, ...kf.loop }, at);
1434
1437
  const { ownProps, filterProps } = partitionProps(rest);
1435
1438
  if (Object.keys(ownProps).length > 0)
1436
1439
  timeline.from(target, { ...pixiwrap(ownProps), duration: kf.duration, ease: kf.ease, ...kf.loop }, at);
@@ -1451,16 +1454,16 @@ function applyKeyframes(timeline, target, keyframes, parentDuration, scope, skip
1451
1454
  if (f) {
1452
1455
  timeline.fromTo(
1453
1456
  r.target,
1454
- { [r.prop]: f.value },
1455
- { [r.prop]: r.value, duration: kf.duration, ease: kf.ease, ...kf.loop },
1457
+ routedProp(r.prop, f.value),
1458
+ { ...routedProp(r.prop, r.value), duration: kf.duration, ease: kf.ease, ...kf.loop },
1456
1459
  at
1457
1460
  );
1458
1461
  } else {
1459
- timeline.to(r.target, { [r.prop]: r.value, duration: kf.duration, ease: kf.ease, ...kf.loop }, at);
1462
+ timeline.to(r.target, { ...routedProp(r.prop, r.value), duration: kf.duration, ease: kf.ease, ...kf.loop }, at);
1460
1463
  }
1461
1464
  }
1462
1465
  for (const f of fromByKey.values())
1463
- timeline.from(f.target, { [f.prop]: f.value, duration: kf.duration, ease: kf.ease, ...kf.loop }, at);
1466
+ timeline.from(f.target, { ...routedProp(f.prop, f.value), duration: kf.duration, ease: kf.ease, ...kf.loop }, at);
1464
1467
  const fromSplit = partitionProps(fromRouted.rest);
1465
1468
  const toSplit = partitionProps(toRouted.rest);
1466
1469
  const ownKeys = /* @__PURE__ */ new Set([...Object.keys(fromSplit.ownProps), ...Object.keys(toSplit.ownProps)]);
@@ -1493,7 +1496,7 @@ function applyInitial(target, initial, scope, skipKeys = [], routers) {
1493
1496
  if (!initial) return;
1494
1497
  const resolved = normalizeProps(initial, scope, { skipKeys, where: "initial" });
1495
1498
  const { rest, routed } = splitRouted(resolved, routers);
1496
- for (const r of routed) setNow(r.target, { [r.prop]: r.value });
1499
+ for (const r of routed) setNow(r.target, routedProp(r.prop, r.value));
1497
1500
  const { ownProps, filterProps } = partitionProps(rest);
1498
1501
  if (Object.keys(ownProps).length > 0) setNow(target, pixiwrap(ownProps));
1499
1502
  for (const [name, props] of Object.entries(filterProps)) {
@@ -4005,7 +4008,7 @@ var AudioSequence = class extends Sequence {
4005
4008
  const raw = spec;
4006
4009
  if (raw.asset !== void 0) console.warn(`pixi-effects: ${who}: has both asset and music \u2014 the music plays; remove one`);
4007
4010
  if (raw.sfx !== void 0) console.warn(`pixi-effects: ${who}: has both sfx and music \u2014 the music plays; remove one`);
4008
- const { resolveMusic, renderMusic, renderMusicAsync, musicLength, musicKey, summarizeMusic } = await import('./music-P4JRT73P.js');
4011
+ const { resolveMusic, renderMusic, renderMusicAsync, musicLength, musicKey, summarizeMusic } = await import('./music-ATX22VAT.js');
4009
4012
  const music = resolveMusic(spec.music, who);
4010
4013
  if (!music) return;
4011
4014
  const natural = musicLength(music);
@@ -5772,10 +5775,14 @@ function resolveDim(v, scope) {
5772
5775
  if (typeof v === "number") return v;
5773
5776
  return evaluateExpr(v, scope);
5774
5777
  }
5778
+
5779
+ // src/core/purity.ts
5780
+ var NOT_PURE = /\bMath\s*\.\s*random\s*\(|\bDate\s*\.\s*now\s*\(|\bperformance\s*\.\s*now\s*\(|\bnew\s+Date\s*\(/;
5781
+
5782
+ // src/sequences/Canvas.ts
5775
5783
  var MAX_SIZE = 8192;
5776
5784
  var MIN_RESOLUTION = 0.25;
5777
5785
  var MAX_RESOLUTION = 4;
5778
- var NOT_PURE = /\bMath\s*\.\s*random\s*\(|\bDate\s*\.\s*now\s*\(|\bperformance\s*\.\s*now\s*\(|\bnew\s+Date\s*\(/;
5779
5786
  function seeded(seed) {
5780
5787
  let a = seed >>> 0;
5781
5788
  return () => {
@@ -6066,17 +6073,466 @@ var CanvasSequence = class extends Sequence {
6066
6073
  }
6067
6074
  };
6068
6075
 
6076
+ // src/core/setupValues.ts
6077
+ var SetupValues = class {
6078
+ values = /* @__PURE__ */ new Map();
6079
+ /** The value `target[prop]` has now, noted the first time only. */
6080
+ note(target, prop) {
6081
+ let props = this.values.get(target);
6082
+ if (!props) {
6083
+ props = /* @__PURE__ */ new Map();
6084
+ this.values.set(target, props);
6085
+ }
6086
+ if (!props.has(prop)) props.set(prop, target[prop]);
6087
+ }
6088
+ /** For a layer that borrowed: a one-property stand-in for `target[prop]`, the noted value while `borrowed()`, the object itself after. */
6089
+ view(target, prop, borrowed) {
6090
+ this.note(target, prop);
6091
+ const noted = () => this.values.get(target).get(prop);
6092
+ let held = null;
6093
+ const view = {};
6094
+ Object.defineProperty(view, prop, {
6095
+ enumerable: true,
6096
+ get: () => borrowed() ? held ? held.v : noted() : target[prop],
6097
+ set: (v) => {
6098
+ if (borrowed()) held = { v };
6099
+ else target[prop] = v;
6100
+ }
6101
+ });
6102
+ return { target: view, prop };
6103
+ }
6104
+ /** The swap: every noted property back to the value setup left. */
6105
+ restore() {
6106
+ for (const [target, props] of this.values) {
6107
+ for (const [prop, v] of props) {
6108
+ try {
6109
+ target[prop] = v;
6110
+ } catch {
6111
+ }
6112
+ }
6113
+ }
6114
+ }
6115
+ };
6116
+
6117
+ // src/sequences/Scene2D.ts
6118
+ var Scene2DBox = class extends Container {
6119
+ boxWidth = 1;
6120
+ boxHeight = 1;
6121
+ _ax = 0;
6122
+ _ay = 0;
6123
+ anchor = /* @__PURE__ */ (() => {
6124
+ const box = this;
6125
+ return {
6126
+ get x() {
6127
+ return box._ax;
6128
+ },
6129
+ set x(v) {
6130
+ box._ax = v;
6131
+ box.pivot.x = v * box.boxWidth;
6132
+ },
6133
+ get y() {
6134
+ return box._ay;
6135
+ },
6136
+ set y(v) {
6137
+ box._ay = v;
6138
+ box.pivot.y = v * box.boxHeight;
6139
+ },
6140
+ set(x, y = x) {
6141
+ this.x = x;
6142
+ this.y = y;
6143
+ }
6144
+ };
6145
+ })();
6146
+ };
6147
+ var isFlipbook = (n) => {
6148
+ const f = n;
6149
+ return typeof f.gotoAndStop === "function" && typeof f.totalFrames === "number" && typeof f.animationSpeed === "number" && "autoUpdate" in n;
6150
+ };
6151
+ var DEFAULT_LABELS = /* @__PURE__ */ new Set([
6152
+ "Container",
6153
+ "Graphics",
6154
+ "Sprite",
6155
+ "AnimatedSprite",
6156
+ "TilingSprite",
6157
+ "NineSliceSprite",
6158
+ "Text",
6159
+ "BitmapText",
6160
+ "HTMLText",
6161
+ "Mesh",
6162
+ "MeshSimple",
6163
+ "MeshPlane",
6164
+ "MeshRope",
6165
+ "PerspectiveMesh",
6166
+ "ParticleContainer",
6167
+ "RenderContainer",
6168
+ "DOMContainer"
6169
+ ]);
6170
+ var ids = /* @__PURE__ */ new WeakMap();
6171
+ var lastId = 0;
6172
+ function idOf(fn) {
6173
+ if (typeof fn !== "function") return 0;
6174
+ let id = ids.get(fn);
6175
+ if (id === void 0) {
6176
+ id = ++lastId;
6177
+ ids.set(fn, id);
6178
+ }
6179
+ return id;
6180
+ }
6181
+ var Scene2DSequence = class extends Sequence {
6182
+ _box = null;
6183
+ _ctx = null;
6184
+ _objects = {};
6185
+ _flipbooks = [];
6186
+ _warned = /* @__PURE__ */ new Set();
6187
+ /** What a rebuild matches this layer by; null: never kept (`reuse: false`, no `name`). */
6188
+ _key = null;
6189
+ /** The layer of the tree being replaced whose scene this one takes over at the swap (`commitReuse`): until then it is not this layer's. */
6190
+ _borrowed = null;
6191
+ /** True once another layer took this layer's scene: destroying this one must not let it go. */
6192
+ _donated = false;
6193
+ /** What setup left on the objects the keyframes reach, shared with a layer that takes the scene over (core/setupValues.ts). */
6194
+ _setupValues = new SetupValues();
6195
+ get _spec() {
6196
+ return this.spec;
6197
+ }
6198
+ _who() {
6199
+ const name = this._spec.name;
6200
+ return `pixi-effects: scene2d layer${name ? ` "${name}"` : ""}`;
6201
+ }
6202
+ _say(key, message) {
6203
+ if (this._warned.has(key)) return;
6204
+ this._warned.add(key);
6205
+ console.warn(`${this._who()}: ${message}`);
6206
+ }
6207
+ pathRouters() {
6208
+ return { scene2d: (path) => this._resolvePath(path) };
6209
+ }
6210
+ async build() {
6211
+ const spec = this._spec;
6212
+ if (this.duration === void 0) this.duration = this.parent?.duration ?? this.root.duration;
6213
+ if (typeof spec.setup !== "function") {
6214
+ throw new Error(`${this._who()}: a scene2d layer needs setup: ({ root }) => { \u2026 } (a function that adds PixiJS display objects to root)`);
6215
+ }
6216
+ if (typeof spec.update === "function" && NOT_PURE.test(spec.update.toString())) {
6217
+ this._say("pure", "update calls Math.random, Date.now, performance.now or new Date, so it is not deterministic: the same frame would draw differently in playback, in a seek and in an export. Derive the value from t (random(seed) from pixi-effects is repeatable)");
6218
+ }
6219
+ const scope = buildScope(this, this.parent, this.root);
6220
+ const width = dim(spec.width, scope) ?? this.parent?.width ?? this.root.width;
6221
+ const height = dim(spec.height, scope) ?? this.parent?.height ?? this.root.height;
6222
+ const box = new Scene2DBox({ label: spec.name ?? "scene2d" });
6223
+ box.boxWidth = width;
6224
+ box.boxHeight = height;
6225
+ this._box = box;
6226
+ this.target = box;
6227
+ this.intrinsicWidth = width;
6228
+ this.intrinsicHeight = height;
6229
+ this._key = spec.reuse === false || !spec.name ? null : JSON.stringify(["scene2d", spec.name, idOf(spec.setup), width, height]);
6230
+ const donor = this._key !== null ? this.root.reuse?.claim(this._key, this) : null;
6231
+ if (donor && donor._lendable()) {
6232
+ this._borrowed = donor;
6233
+ this._objects = donor._objects;
6234
+ this._flipbooks = donor._flipbooks;
6235
+ this._setupValues = donor._setupValues;
6236
+ this._ctx = { ...donor._ctx, width, height };
6237
+ this.buildFilters();
6238
+ return;
6239
+ }
6240
+ const root = new Container({ label: "root" });
6241
+ box.addChild(root);
6242
+ const renderer = this.root.pixiRenderer;
6243
+ const objects = {};
6244
+ const ctx = { root, renderer, width, height, objects, texture: (name) => textureOf(name) };
6245
+ let result;
6246
+ try {
6247
+ result = await spec.setup(ctx);
6248
+ } catch (err) {
6249
+ box.destroy({ children: true });
6250
+ this._box = null;
6251
+ this.target = null;
6252
+ throw new Error(`${this._who()}: setup failed: ${err instanceof Error ? err.message : String(err)}`, { cause: err });
6253
+ }
6254
+ Object.assign(objects, result?.objects ?? {});
6255
+ if (!("root" in objects)) objects.root = root;
6256
+ this._objects = objects;
6257
+ this._ctx = ctx;
6258
+ this._stopSelfUpdating(root);
6259
+ this.buildFilters();
6260
+ }
6261
+ /** Reuse (core/reuse.ts): the key this layer is matched by, while it can still lend its scene. */
6262
+ reuseKey() {
6263
+ return this._lendable() ? this._key : null;
6264
+ }
6265
+ _lendable() {
6266
+ return !!this._box && !!this._ctx && !this._donated && !this._borrowed;
6267
+ }
6268
+ /** The new tree is on stage: the old layer's scene moves into this layer's box, for good. */
6269
+ commitReuse() {
6270
+ const d = this._borrowed, box = this._box;
6271
+ if (!d || !box || !this._ctx) return;
6272
+ this._setupValues.restore();
6273
+ box.addChild(this._ctx.root);
6274
+ d._donated = true;
6275
+ this._borrowed = null;
6276
+ }
6277
+ /**
6278
+ * Anything that would move on PixiJS's shared ticker instead of the video's time is turned off: an AnimatedSprite is posed by the layer from its time (so a sprite left
6279
+ * playing still plays, frame for frame the same in a seek and an export); anything else with `autoUpdate` is said once (drive it from update). A sprite showing a
6280
+ * `<video>` plays by the browser's clock: said once.
6281
+ */
6282
+ _stopSelfUpdating(root) {
6283
+ const stopped = [];
6284
+ const visit = (node) => {
6285
+ const n = node;
6286
+ if (isFlipbook(node)) {
6287
+ if (!this._flipbooks.includes(node)) this._flipbooks.push(node);
6288
+ if (node.autoUpdate) node.autoUpdate = false;
6289
+ } else if (n.autoUpdate === true) {
6290
+ n.autoUpdate = false;
6291
+ stopped.push(n.label || n.constructor?.name || "a node");
6292
+ }
6293
+ const resource = n.texture?.source?.resource;
6294
+ if (typeof HTMLVideoElement !== "undefined" && resource instanceof HTMLVideoElement) {
6295
+ this._say("video", `a sprite shows a <video> texture, which plays by the browser's clock, not the video's time: use a video layer (type: 'video') for footage`);
6296
+ }
6297
+ for (const c of node.children ?? []) visit(c);
6298
+ };
6299
+ visit(root);
6300
+ if (stopped.length) {
6301
+ this._say("autoUpdate", `turned off autoUpdate on ${stopped.join(", ")}: a video draws from the time, so drive them from update(t)`);
6302
+ }
6303
+ }
6304
+ /** An AnimatedSprite still playing after `update` is posed from the layer's time: frame floor(t × 60 × animationSpeed) (PixiJS counts ticks of 1/60 s), its loop and frame times kept. */
6305
+ _poseFlipbooks(t) {
6306
+ for (const f of this._flipbooks) {
6307
+ if (!f.playing || f.totalFrames <= 0) continue;
6308
+ const n = f.totalFrames;
6309
+ let frame;
6310
+ const durations = f._durations;
6311
+ if (durations && durations.length === n) {
6312
+ const total = durations.reduce((a, b) => a + b, 0);
6313
+ let ms = t * 1e3 * Math.abs(f.animationSpeed);
6314
+ ms = f.loop && total > 0 ? ms % total : Math.min(ms, total);
6315
+ frame = 0;
6316
+ for (let acc = durations[0]; frame < n - 1 && acc <= ms; acc += durations[++frame]) {
6317
+ }
6318
+ } else {
6319
+ const ticks = Math.floor(t * 60 * Math.abs(f.animationSpeed) + 1e-9);
6320
+ frame = f.loop ? ticks % n : Math.min(ticks, n - 1);
6321
+ }
6322
+ if (f.animationSpeed < 0) frame = n - 1 - frame;
6323
+ f.gotoAndStop(frame);
6324
+ f.play();
6325
+ }
6326
+ }
6327
+ /** Per-frame hook, duck-typed by the movie (as the video, canvas and 3D layers are). */
6328
+ async awaitFrameAt(local) {
6329
+ if (!this._ctx || this._borrowed) return;
6330
+ this._frame(Math.max(0, Math.min(local, this.duration ?? local)));
6331
+ }
6332
+ _frame(t) {
6333
+ const update = this._spec.update;
6334
+ if (update) {
6335
+ try {
6336
+ update(t, this._ctx);
6337
+ } catch (err) {
6338
+ this._say("update", `update threw (reported once): ${err instanceof Error ? err.message : String(err)}`);
6339
+ }
6340
+ }
6341
+ this._poseFlipbooks(t);
6342
+ }
6343
+ /**
6344
+ * `movie.pick`: the top object of the scene under a canvas point, by PixiJS's own `containsPoint` (a Graphics by its shape, a Sprite or Text by its box) or its `hitArea`.
6345
+ * `eventMode: 'none'` and `interactiveChildren: false` are honoured; hidden, unrenderable and clear nodes are not hit. null: nothing of the scene is there (the point falls through).
6346
+ */
6347
+ pick2d(global) {
6348
+ const root = this._ctx?.root;
6349
+ if (!root || this._borrowed) return null;
6350
+ const hitIn = (node2) => {
6351
+ if (!node2.visible || !node2.renderable || node2.alpha <= 0 || node2.measurable === false) return null;
6352
+ const mode = node2.eventMode;
6353
+ if (mode === "none") return null;
6354
+ const local = node2.toLocal(global);
6355
+ const area = node2 === root ? null : node2.hitArea;
6356
+ if (area && !area.contains(local.x, local.y)) return null;
6357
+ if (node2.interactiveChildren !== false) {
6358
+ for (let i = node2.children.length - 1; i >= 0; i--) {
6359
+ const h = hitIn(node2.children[i]);
6360
+ if (h) return h;
6361
+ }
6362
+ }
6363
+ if (node2 === root) return null;
6364
+ if (area) return node2;
6365
+ const contains = node2.containsPoint;
6366
+ return typeof contains === "function" && contains.call(node2, new Point(local.x, local.y)) ? node2 : null;
6367
+ };
6368
+ const node = hitIn(root);
6369
+ if (!node) return null;
6370
+ let name = "";
6371
+ for (let n = node; n && n !== root; n = n.parent) {
6372
+ if (n.label && !DEFAULT_LABELS.has(n.label) && n.label !== n.constructor?.name) {
6373
+ name = n.label;
6374
+ break;
6375
+ }
6376
+ }
6377
+ const p = root.toLocal(global);
6378
+ return { object: name, node, point: [p.x, p.y] };
6379
+ }
6380
+ /** `hit.scene2d.grab()`: for a canvas point, where it is in the grabbed node's parent's pixels and how far that is from where it was grabbed (`node.x += delta[0]`). */
6381
+ dragFrom(node, global) {
6382
+ const space = node.parent ?? node;
6383
+ const from = space.toLocal(global);
6384
+ return (x, y) => {
6385
+ const p = space.toLocal({ x, y });
6386
+ return { point: [p.x, p.y], delta: [p.x - from.x, p.y - from.y] };
6387
+ };
6388
+ }
6389
+ /**
6390
+ * The determinism check (`check`, `movie.review()`): the scene set by `update` and drawn at a few moments in two orders, with one draw thrown away first, as the canvas and 3D
6391
+ * layers are. It draws the root alone into a texture of the box's size with PixiJS's renderer; the next real frame sets the scene again.
6392
+ */
6393
+ checkDeterminism(times) {
6394
+ const none = { differs: [], drawMs: 0, threw: [] };
6395
+ const ctx = this._ctx;
6396
+ const renderer = this.root.pixiRenderer;
6397
+ if (!ctx || !renderer || this._borrowed) return none;
6398
+ const root = ctx.root;
6399
+ const w = Math.max(1, Math.ceil(ctx.width)), h = Math.max(1, Math.ceil(ctx.height));
6400
+ const rt = RenderTexture.create({ width: w, height: h });
6401
+ const wasGroup = root.isRenderGroup;
6402
+ const keep = w * h * 4 * times.length <= 96e6;
6403
+ const hash = (d) => {
6404
+ let x = 2166136261;
6405
+ for (let i = 0; i < d.length; i++) {
6406
+ x ^= d[i];
6407
+ x = Math.imul(x, 16777619);
6408
+ }
6409
+ return x >>> 0;
6410
+ };
6411
+ const ms = [];
6412
+ const threw = /* @__PURE__ */ new Set();
6413
+ const update = this._spec.update;
6414
+ const once = (t, timed) => {
6415
+ const from = performance.now();
6416
+ let pixels = new Uint8Array(0);
6417
+ try {
6418
+ update?.(t, ctx);
6419
+ this._poseFlipbooks(t);
6420
+ renderer.render({ container: root, target: rt, clear: true, transform: new Matrix() });
6421
+ pixels = renderer.extract.pixels(rt).pixels;
6422
+ } catch {
6423
+ threw.add(t);
6424
+ }
6425
+ if (timed) ms.push(performance.now() - from);
6426
+ return pixels;
6427
+ };
6428
+ try {
6429
+ for (const t of times) once(t, false);
6430
+ const first = times.map((t) => {
6431
+ const d = once(t, true);
6432
+ return keep ? d.slice() : hash(d);
6433
+ });
6434
+ const second = [...times].reverse().map((t) => once(t, false)).reverse();
6435
+ const differs = [];
6436
+ times.forEach((t, i) => {
6437
+ const a = first[i], b = second[i];
6438
+ if (typeof a === "number") {
6439
+ if (a !== hash(b)) differs.push({ t, pixels: -1, maxDiff: -1 });
6440
+ return;
6441
+ }
6442
+ let pixels = 0, maxDiff = 0;
6443
+ for (let k = 0; k < a.length; k++) {
6444
+ const d = Math.abs(a[k] - b[k]);
6445
+ if (d) {
6446
+ pixels++;
6447
+ if (d > maxDiff) maxDiff = d;
6448
+ }
6449
+ }
6450
+ if (pixels) differs.push({ t, pixels, maxDiff });
6451
+ });
6452
+ ms.sort((x, y) => x - y);
6453
+ 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)) };
6454
+ } finally {
6455
+ rt.destroy(true);
6456
+ if (!wasGroup && root.isRenderGroup) root.disableRenderGroup();
6457
+ }
6458
+ }
6459
+ _resolvePath(path) {
6460
+ const segs = path.split(".");
6461
+ if (segs.length < 2) {
6462
+ this._warnPath(path, "needs at least <object>.<prop>");
6463
+ return null;
6464
+ }
6465
+ let obj = this._objects[segs[0]];
6466
+ if (obj == null) {
6467
+ this._warnPath(path, `unknown object "${segs[0]}" (known: ${Object.keys(this._objects).join(", ")}): expose it in setup's { objects }`);
6468
+ return null;
6469
+ }
6470
+ for (let i = 1; i < segs.length - 1; i++) {
6471
+ obj = obj[segs[i]];
6472
+ if (obj == null) {
6473
+ this._warnPath(path, `"${segs[i]}" is undefined along the path`);
6474
+ return null;
6475
+ }
6476
+ }
6477
+ const prop = segs[segs.length - 1];
6478
+ if (typeof obj !== "object" || !(prop in obj)) {
6479
+ this._warnPath(path, `no property "${prop}"`);
6480
+ return null;
6481
+ }
6482
+ return this._borrowed ? this._setupValues.view(obj, prop, () => this._borrowed !== null) : (this._setupValues.note(obj, prop), { target: obj, prop });
6483
+ }
6484
+ _warnPath(path, why) {
6485
+ this._say(`path:${path}`, `keyframe path scene2d.${path}: ${why}; skipped`);
6486
+ }
6487
+ destroy() {
6488
+ const kept = this._donated || this._borrowed !== null;
6489
+ if (!kept && this._ctx && this._spec.dispose) {
6490
+ try {
6491
+ this._spec.dispose(this._ctx);
6492
+ } catch (err) {
6493
+ console.warn(`${this._who()}: dispose() threw \u2014`, err);
6494
+ }
6495
+ }
6496
+ const box = this._box;
6497
+ this._box = null;
6498
+ if (this.target === box) this.target = null;
6499
+ try {
6500
+ box?.destroy({ children: true });
6501
+ } catch (err) {
6502
+ console.warn(`${this._who()}: destroying the scene threw \u2014`, err);
6503
+ }
6504
+ this._ctx = null;
6505
+ this._objects = {};
6506
+ this._flipbooks = [];
6507
+ this._borrowed = null;
6508
+ super.destroy();
6509
+ }
6510
+ };
6511
+ function textureOf(name) {
6512
+ if (Assets.cache.has(name)) {
6513
+ const t = Assets.get(name);
6514
+ if (t && typeof t.source === "object") return t;
6515
+ throw new Error(`asset "${name}" is not a picture (ctx.texture gives the texture of an image asset)`);
6516
+ }
6517
+ const known = [...Assets.cache._cache?.keys() ?? []].filter((k) => !/[/:.]/.test(k) && !k.startsWith("pixi-effects-"));
6518
+ throw new Error(`no asset named "${name}"${known.length ? ` (assets: ${known.join(", ")})` : ""}: list it in movie.init({ assets: [{ name, src }] })`);
6519
+ }
6520
+ function dim(v, scope) {
6521
+ if (v === void 0) return void 0;
6522
+ return typeof v === "number" ? v : evaluateExpr(v, scope);
6523
+ }
6524
+
6069
6525
  // src/core/Composition.ts
6070
6526
  var _CompositionSequence = null;
6071
6527
  async function getCompositionSequence() {
6072
6528
  if (!_CompositionSequence) {
6073
- _CompositionSequence = (await import('./Composition-5FKV2IBP.js')).CompositionSequence;
6529
+ _CompositionSequence = (await import('./Composition-GVWWLFDL.js')).CompositionSequence;
6074
6530
  }
6075
6531
  return _CompositionSequence;
6076
6532
  }
6077
6533
  var _SpansSequence = null;
6078
6534
  async function getSpansSequence() {
6079
- if (!_SpansSequence) _SpansSequence = (await import('./Spans-6A3VLHRH.js')).SpansSequence;
6535
+ if (!_SpansSequence) _SpansSequence = (await import('./Spans-3SEZSTQV.js')).SpansSequence;
6080
6536
  return _SpansSequence;
6081
6537
  }
6082
6538
  var staticTypes = {
@@ -6089,12 +6545,17 @@ var staticTypes = {
6089
6545
  light: LightSequence,
6090
6546
  shader: ShaderSequence,
6091
6547
  canvas: CanvasSequence,
6548
+ scene2d: Scene2DSequence,
6092
6549
  null: NullSequence
6093
6550
  };
6094
6551
  var registry2 = {};
6095
6552
  function registerSequenceType(type, ctor) {
6096
6553
  registry2[type] = ctor;
6097
6554
  }
6555
+ var OPTIONAL_ENTRIES = {
6556
+ scene3d: { from: "pixi-effects/3d", call: "register3D" },
6557
+ three: { from: "pixi-effects/three", call: "registerThree" }
6558
+ };
6098
6559
  async function buildSequenceTree(specs, parent, root, out = []) {
6099
6560
  for (let spec of specs) {
6100
6561
  let Cls = staticTypes[spec.type] ?? registry2[spec.type];
@@ -6106,7 +6567,9 @@ async function buildSequenceTree(specs, parent, root, out = []) {
6106
6567
  Cls = await getCompositionSequence();
6107
6568
  }
6108
6569
  if (!Cls) {
6109
- console.warn(`pixi-effects: unknown sequence type "${spec.type}"`);
6570
+ const type = spec.type;
6571
+ const entry = OPTIONAL_ENTRIES[type];
6572
+ console.warn(`pixi-effects: unknown sequence type "${type}"${entry ? `: import { ${entry.call} } from '${entry.from}' and call ${entry.call}() before movie.init` : ""}`);
6110
6573
  await root.onLayerBuilt?.();
6111
6574
  continue;
6112
6575
  }
@@ -6121,6 +6584,6 @@ async function buildSequenceTree(specs, parent, root, out = []) {
6121
6584
  return out;
6122
6585
  }
6123
6586
 
6124
- 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 };
6125
- //# sourceMappingURL=chunk-IVKI6CPH.js.map
6126
- //# sourceMappingURL=chunk-IVKI6CPH.js.map
6587
+ 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, NOT_PURE, NullSequence, SHADOW_TAPS, Sequence, SetupValues, 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 };
6588
+ //# sourceMappingURL=chunk-SSVHAF3Q.js.map
6589
+ //# sourceMappingURL=chunk-SSVHAF3Q.js.map