pixi-effects 0.9.0 → 0.11.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 (53) hide show
  1. package/CHANGELOG.md +36 -0
  2. package/README.md +6 -6
  3. package/ai/SKILL.md +4 -3
  4. package/ai/reference/cheatsheet.md +17 -6
  5. package/ai/reference/pitfalls.md +3 -3
  6. package/ai/reference/recipes.md +141 -11
  7. package/ai/template.html +11 -8
  8. package/ai/tools/render.mjs +14 -5
  9. package/dist/{Base-CSIulyIq.d.cts → Base-CwUxTfja.d.cts} +1 -1
  10. package/dist/{Base-DVgwyIUj.d.ts → Base-CyvSLoCP.d.ts} +1 -1
  11. package/dist/Composition-7TEKHZNQ.cjs +14 -0
  12. package/dist/{Composition-CM62XJKT.cjs.map → Composition-7TEKHZNQ.cjs.map} +1 -1
  13. package/dist/Composition-HIISJAX2.js +5 -0
  14. package/dist/{Composition-RJDSQYTV.js.map → Composition-HIISJAX2.js.map} +1 -1
  15. package/dist/Controller.cjs +34 -0
  16. package/dist/Controller.cjs.map +1 -1
  17. package/dist/Controller.d.cts +12 -2
  18. package/dist/Controller.d.ts +12 -2
  19. package/dist/Controller.js +34 -0
  20. package/dist/Controller.js.map +1 -1
  21. package/dist/{Movie-qGHp15c_.d.cts → Movie-DSSNOF3T.d.cts} +61 -2
  22. package/dist/{Movie-QMlFyHkf.d.ts → Movie-nzmWsxWX.d.ts} +61 -2
  23. package/dist/{chunk-O4AJYUPK.js → chunk-3IPDNC3E.js} +90 -14
  24. package/dist/chunk-3IPDNC3E.js.map +1 -0
  25. package/dist/{chunk-AGMNSJJH.cjs → chunk-6NWJLVCA.cjs} +196 -12
  26. package/dist/chunk-6NWJLVCA.cjs.map +1 -0
  27. package/dist/{chunk-FNKSXBKB.js → chunk-C6QHKYC5.js} +193 -14
  28. package/dist/chunk-C6QHKYC5.js.map +1 -0
  29. package/dist/{chunk-PDBDDGG5.cjs → chunk-F7NCHS6Q.cjs} +108 -32
  30. package/dist/chunk-F7NCHS6Q.cjs.map +1 -0
  31. package/dist/index.cjs +542 -38
  32. package/dist/index.cjs.map +1 -1
  33. package/dist/index.d.cts +303 -5
  34. package/dist/index.d.ts +303 -5
  35. package/dist/index.js +511 -27
  36. package/dist/index.js.map +1 -1
  37. package/dist/loader.css +110 -0
  38. package/dist/three.cjs +5 -5
  39. package/dist/three.d.cts +2 -2
  40. package/dist/three.d.ts +2 -2
  41. package/dist/three.js +1 -1
  42. package/dist/{types-oJijbn-K.d.ts → types-BXu28nJj.d.cts} +26 -2
  43. package/dist/{types-oJijbn-K.d.cts → types-BXu28nJj.d.ts} +26 -2
  44. package/docs/api.md +16 -1
  45. package/docs/dsl.md +137 -2
  46. package/llms-full.txt +318 -26
  47. package/package.json +5 -2
  48. package/dist/Composition-CM62XJKT.cjs +0 -14
  49. package/dist/Composition-RJDSQYTV.js +0 -5
  50. package/dist/chunk-AGMNSJJH.cjs.map +0 -1
  51. package/dist/chunk-FNKSXBKB.js.map +0 -1
  52. package/dist/chunk-O4AJYUPK.js.map +0 -1
  53. package/dist/chunk-PDBDDGG5.cjs.map +0 -1
@@ -1,8 +1,43 @@
1
1
  import { suggestName } from './chunk-DKGG7WD4.js';
2
2
  import * as PIXI from 'pixi.js';
3
- import { Rectangle, Container, Graphics, Assets, Texture, Sprite, Text, Filter, GlProgram, defaultFilterVert, GpuProgram, UniformGroup, FillGradient, Color, GraphicsPath } from 'pixi.js';
3
+ import { Rectangle, Container, GraphicsPath, Graphics, Assets, Texture, Sprite, Text, Filter, GlProgram, defaultFilterVert, GpuProgram, UniformGroup, FillGradient, Color } from 'pixi.js';
4
4
  import { gsap } from 'gsap';
5
5
 
6
+ // src/expr/random.ts
7
+ function mix(h) {
8
+ h = Math.imul(h ^ h >>> 16, 2246822507);
9
+ h = Math.imul(h ^ h >>> 13, 3266489909);
10
+ return (h ^ h >>> 16) >>> 0;
11
+ }
12
+ function fold(n) {
13
+ if (!Number.isFinite(n)) return 0;
14
+ const i = Math.floor(n);
15
+ const f = n - i;
16
+ return (i | 0) ^ Math.imul(Math.floor(f * 1048576), 2654435761);
17
+ }
18
+ function rand(seed) {
19
+ return mix(fold(seed) + 2654435769) / 4294967296;
20
+ }
21
+ function random(seed) {
22
+ let a = fold(seed) + 1831565813 | 0;
23
+ return () => {
24
+ a = a + 1831565813 | 0;
25
+ let t = Math.imul(a ^ a >>> 15, 1 | a);
26
+ t = t + Math.imul(t ^ t >>> 7, 61 | t) ^ t;
27
+ return ((t ^ t >>> 14) >>> 0) / 4294967296;
28
+ };
29
+ }
30
+ function noise(x, seed = 0) {
31
+ if (!Number.isFinite(x)) return 0;
32
+ const i = Math.floor(x);
33
+ const f = x - i;
34
+ const s = fold(seed) * 668265261;
35
+ const a = mix((i | 0) + s) / 2147483648 - 1;
36
+ const b = mix((i + 1 | 0) + s) / 2147483648 - 1;
37
+ const u = f * f * f * (f * (f * 6 - 15) + 10);
38
+ return a + (b - a) * u;
39
+ }
40
+
6
41
  // src/expr/Parser.ts
7
42
  var FUNCS = {
8
43
  min: Math.min,
@@ -15,8 +50,19 @@ var FUNCS = {
15
50
  pow: Math.pow,
16
51
  sin: Math.sin,
17
52
  cos: Math.cos,
18
- tan: Math.tan
53
+ tan: Math.tan,
54
+ rand: (seed) => rand(seed),
55
+ noise: (x, seed = 0) => noise(x, seed),
56
+ lerp: (a, b, t) => a + (b - a) * t,
57
+ clamp: (x, lo, hi) => Math.min(Math.max(x, lo), hi),
58
+ smoothstep: (a, b, x) => {
59
+ const u = Math.min(Math.max((x - a) / (b - a), 0), 1);
60
+ return u * u * (3 - 2 * u);
61
+ },
62
+ mod: (a, b) => (a % b + b) % b,
63
+ step: (edge, x) => x >= edge ? 1 : 0
19
64
  };
65
+ var CONSTS = { PI: Math.PI };
20
66
  function isDigit(c) {
21
67
  return c >= "0" && c <= "9";
22
68
  }
@@ -162,6 +208,7 @@ function evalNode(node, scope) {
162
208
  case "num":
163
209
  return node.value;
164
210
  case "var": {
211
+ if (node.name in CONSTS) return CONSTS[node.name];
165
212
  const v = scope[node.name];
166
213
  if (typeof v !== "number") throw new Error(`undefined variable: ${node.name}`);
167
214
  return v;
@@ -943,6 +990,12 @@ var Sequence = class {
943
990
  this.target = null;
944
991
  }
945
992
  };
993
+ var NullSequence = class extends Sequence {
994
+ async build() {
995
+ this.target = new Container();
996
+ this.buildFilters();
997
+ }
998
+ };
946
999
 
947
1000
  // src/space/specKeys.ts
948
1001
  function collectPropKeys(spec) {
@@ -2073,6 +2126,85 @@ function slice(line, a, b) {
2073
2126
  return out;
2074
2127
  }
2075
2128
 
2129
+ // src/sequences/morphPath.ts
2130
+ function resample(line, n) {
2131
+ const p = line.closed ? [...line.pts, line.pts[0], line.pts[1]] : line.pts;
2132
+ const cum = [0];
2133
+ for (let i = 2; i < p.length; i += 2) cum.push(cum[cum.length - 1] + Math.hypot(p[i] - p[i - 2], p[i + 1] - p[i - 1]));
2134
+ const total = cum[cum.length - 1];
2135
+ const out = [];
2136
+ if (!(total > 0)) {
2137
+ for (let i = 0; i < n; i++) out.push(p[0], p[1]);
2138
+ return out;
2139
+ }
2140
+ let seg = 1;
2141
+ for (let i = 0; i < n; i++) {
2142
+ const s = line.closed ? i * total / n : n === 1 ? 0 : i * total / (n - 1);
2143
+ while (seg < cum.length - 1 && cum[seg] < s) seg++;
2144
+ const len = cum[seg] - cum[seg - 1];
2145
+ const t = len > 0 ? (s - cum[seg - 1]) / len : 0;
2146
+ const k = seg * 2;
2147
+ out.push(p[k - 2] + (p[k] - p[k - 2]) * t, p[k - 1] + (p[k + 1] - p[k - 1]) * t);
2148
+ }
2149
+ return out;
2150
+ }
2151
+ var centroid = (pts) => {
2152
+ let x = 0, y = 0;
2153
+ for (let i = 0; i < pts.length; i += 2) {
2154
+ x += pts[i];
2155
+ y += pts[i + 1];
2156
+ }
2157
+ const n = pts.length / 2;
2158
+ return [x / n, y / n];
2159
+ };
2160
+ function align(a, b) {
2161
+ const n = a.length / 2;
2162
+ let best = b, bestCost = Infinity;
2163
+ for (const reversed of [false, true]) {
2164
+ for (let k = 0; k < n; k++) {
2165
+ let cost = 0;
2166
+ for (let i = 0; i < n && cost < bestCost; i++) {
2167
+ const j = reversed ? ((k - i) % n + n) % n : (k + i) % n;
2168
+ cost += (a[2 * i] - b[2 * j]) ** 2 + (a[2 * i + 1] - b[2 * j + 1]) ** 2;
2169
+ }
2170
+ if (cost < bestCost) {
2171
+ bestCost = cost;
2172
+ const out = [];
2173
+ for (let i = 0; i < n; i++) {
2174
+ const j = reversed ? ((k - i) % n + n) % n : (k + i) % n;
2175
+ out.push(b[2 * j], b[2 * j + 1]);
2176
+ }
2177
+ best = out;
2178
+ }
2179
+ }
2180
+ }
2181
+ return best;
2182
+ }
2183
+ function buildMorph(from, to, n = 128) {
2184
+ if (from.length === 0 || to.length === 0) return [];
2185
+ const pairs = [];
2186
+ const count = Math.max(from.length, to.length);
2187
+ for (let i = 0; i < count; i++) {
2188
+ const fa = from[i], fb = to[i];
2189
+ const closed = (fa?.closed ?? fb.closed) && (fb?.closed ?? fa.closed);
2190
+ const a = fa ? resample({ pts: fa.pts, closed }, n) : collapsed(resample({ pts: fb.pts, closed }, n));
2191
+ let b = fb ? resample({ pts: fb.pts, closed }, n) : collapsed(a);
2192
+ if (closed && fa && fb) b = align(a, b);
2193
+ pairs.push({ a, b, closed });
2194
+ }
2195
+ return pairs;
2196
+ }
2197
+ function collapsed(pts) {
2198
+ const [cx, cy] = centroid(pts);
2199
+ const out = [];
2200
+ for (let i = 0; i < pts.length; i += 2) out.push(cx, cy);
2201
+ return out;
2202
+ }
2203
+ function morphAt(pairs, t) {
2204
+ const u = Math.min(Math.max(t, 0), 1);
2205
+ return pairs.map(({ a, b, closed }) => ({ pts: a.map((v, i) => v + (b[i] - v) * u), closed }));
2206
+ }
2207
+
2076
2208
  // src/sequences/Shape.ts
2077
2209
  var STYLE_KEYS = ["fillColor", "fillAlpha", "strokeColor", "strokeAlpha", "strokeWidth"];
2078
2210
  var COLOR_KEYS = /* @__PURE__ */ new Set(["fillColor", "strokeColor"]);
@@ -2084,7 +2216,7 @@ var GEOMETRY_KEYS_BY_SHAPE = {
2084
2216
  arc: ["radius", "innerRadius", "startAngle", "endAngle"],
2085
2217
  line: [...TRIM_KEYS],
2086
2218
  polygon: [...TRIM_KEYS],
2087
- path: [...TRIM_KEYS]
2219
+ path: [...TRIM_KEYS, "morph"]
2088
2220
  };
2089
2221
  var ANCHORED_SHAPES = /* @__PURE__ */ new Set(["rect", "circle", "ellipse", "arc"]);
2090
2222
  var ShapeSequence = class extends Sequence {
@@ -2127,8 +2259,9 @@ var ShapeSequence = class extends Sequence {
2127
2259
  }
2128
2260
  const gradientSpec = this.spec.fillGradient ?? this.spec.initial?.fillGradient;
2129
2261
  if (gradientSpec) this._state.fillStyle = makeGradientFill(gradientSpec);
2130
- this._drawGeometry = makeDrawGeometry(this.spec, scope, this._state);
2131
- this._outline = makeOutline(this.spec, scope, this._state);
2262
+ const morph = this._setupMorph();
2263
+ this._drawGeometry = makeDrawGeometry(this.spec, scope, this._state, morph);
2264
+ this._outline = makeOutline(this.spec, scope, this._state, morph);
2132
2265
  const { trimStart, trimEnd } = this._state;
2133
2266
  this._state.trimStart = 0;
2134
2267
  this._state.trimEnd = 1;
@@ -2157,6 +2290,33 @@ var ShapeSequence = class extends Sequence {
2157
2290
  this._redraw();
2158
2291
  this.buildFilters();
2159
2292
  }
2293
+ /** The prepared morph between `d` and `morphTo`, or null (and a warning when the spec asked for one that cannot work). */
2294
+ _setupMorph() {
2295
+ const who = describeLayer(this.spec);
2296
+ const top = this.spec;
2297
+ const wanted = this.spec.shape === "path" && (this._state.morph !== void 0 || collectPropKeys(this.spec).has("morph"));
2298
+ if (this.spec.shape !== "path") {
2299
+ if ("morphTo" in top) console.warn(`pixi-effects: ${who}: morphTo only works on a path shape (shape: 'path'); ignored`);
2300
+ return null;
2301
+ }
2302
+ if (top.morphTo === void 0) {
2303
+ if (wanted) console.warn(`pixi-effects: ${who}: morph needs morphTo (the outline to morph into); ignored`);
2304
+ return null;
2305
+ }
2306
+ let points2 = 128;
2307
+ if (top.morphPoints !== void 0) {
2308
+ const n = Number(top.morphPoints);
2309
+ if (Number.isInteger(n) && n >= 8 && n <= 2048) points2 = n;
2310
+ else console.warn(`pixi-effects: ${who}: morphPoints must be a whole number from 8 to 2048, got ${String(top.morphPoints)}; using 128`);
2311
+ }
2312
+ const pairs = buildMorph(flattenSvgPath(this.spec.d), flattenSvgPath(String(top.morphTo)), points2);
2313
+ if (pairs.length === 0) {
2314
+ console.warn(`pixi-effects: ${who}: morphTo "${String(top.morphTo)}" (or d) draws nothing, so there is nothing to morph; ignored`);
2315
+ return null;
2316
+ }
2317
+ this._state.morph ??= 0;
2318
+ return { pairs, to: String(top.morphTo) };
2319
+ }
2160
2320
  _fresh = false;
2161
2321
  _outline = null;
2162
2322
  _redraw() {
@@ -2391,7 +2551,7 @@ var STATE_DRAWERS = {
2391
2551
  ellipse: drawEllipseFromState,
2392
2552
  arc: drawArcFromState
2393
2553
  };
2394
- function makeDrawGeometry(spec, scope, state) {
2554
+ function makeDrawGeometry(spec, scope, state, morph) {
2395
2555
  const stateDrawer = STATE_DRAWERS[spec.shape];
2396
2556
  if (stateDrawer) return (g) => stateDrawer(g, state);
2397
2557
  switch (spec.shape) {
@@ -2399,13 +2559,30 @@ function makeDrawGeometry(spec, scope, state) {
2399
2559
  return makeLineDraw(spec, scope);
2400
2560
  case "polygon":
2401
2561
  return makePolygonDraw(spec, scope);
2402
- case "path":
2403
- return makePathDraw(spec);
2562
+ case "path": {
2563
+ const plain = makePathDraw(spec);
2564
+ if (!morph) return plain;
2565
+ const last = makePathDraw({ ...spec, d: morph.to });
2566
+ return (g) => {
2567
+ const t = state.morph ?? 0;
2568
+ if (t <= 0) plain(g);
2569
+ else if (t >= 1) last(g);
2570
+ else for (const part of morphAt(morph.pairs, t)) drawPolyline(g, part);
2571
+ };
2572
+ }
2404
2573
  }
2405
2574
  return () => {
2406
2575
  };
2407
2576
  }
2408
- function makeOutline(spec, scope, s) {
2577
+ function drawPolyline(g, part) {
2578
+ if (part.closed) {
2579
+ g.poly(part.pts, true);
2580
+ return;
2581
+ }
2582
+ g.moveTo(part.pts[0], part.pts[1]);
2583
+ for (let i = 2; i < part.pts.length; i += 2) g.lineTo(part.pts[i], part.pts[i + 1]);
2584
+ }
2585
+ function makeOutline(spec, scope, s, morph) {
2409
2586
  switch (spec.shape) {
2410
2587
  case "rect":
2411
2588
  return () => {
@@ -2433,6 +2610,7 @@ function makeOutline(spec, scope, s) {
2433
2610
  return () => lines;
2434
2611
  }
2435
2612
  case "path": {
2613
+ if (morph) return () => morphAt(morph.pairs, s.morph ?? 0);
2436
2614
  let lines = null;
2437
2615
  return () => lines ??= flattenSvgPath(spec.d);
2438
2616
  }
@@ -2513,7 +2691,7 @@ function numOrZero(v, scope) {
2513
2691
  var _CompositionSequence = null;
2514
2692
  async function getCompositionSequence() {
2515
2693
  if (!_CompositionSequence) {
2516
- _CompositionSequence = (await import('./Composition-RJDSQYTV.js')).CompositionSequence;
2694
+ _CompositionSequence = (await import('./Composition-HIISJAX2.js')).CompositionSequence;
2517
2695
  }
2518
2696
  return _CompositionSequence;
2519
2697
  }
@@ -2523,7 +2701,8 @@ var staticTypes = {
2523
2701
  audio: AudioSequence,
2524
2702
  video: VideoSequence,
2525
2703
  shape: ShapeSequence,
2526
- camera: CameraSequence
2704
+ camera: CameraSequence,
2705
+ null: NullSequence
2527
2706
  };
2528
2707
  var registry2 = {};
2529
2708
  function registerSequenceType(type, ctor) {
@@ -2550,6 +2729,6 @@ async function buildSequenceTree(specs, parent, root) {
2550
2729
  return out;
2551
2730
  }
2552
2731
 
2553
- export { CameraSequence, DEFAULT_FOV, DEG, NEAR, Sequence, buildScope, buildSequenceTree, cameraBasis, collectPropKeys, describeLayer, ensureFilterLibrary, evaluateExpr, homeCamera, homeDistance, lintText, lintTiming, projectLayer, registerSequenceType, resolveAt, summarizeWarnings };
2554
- //# sourceMappingURL=chunk-FNKSXBKB.js.map
2555
- //# sourceMappingURL=chunk-FNKSXBKB.js.map
2732
+ export { CameraSequence, DEFAULT_FOV, DEG, NEAR, NullSequence, Sequence, buildScope, buildSequenceTree, cameraBasis, collectPropKeys, describeLayer, ensureFilterLibrary, evaluateExpr, flattenSvgPath, homeCamera, homeDistance, lintText, lintTiming, noise, projectLayer, rand, random, registerSequenceType, resolveAt, summarizeWarnings };
2733
+ //# sourceMappingURL=chunk-C6QHKYC5.js.map
2734
+ //# sourceMappingURL=chunk-C6QHKYC5.js.map