@pixerate/flair 0.32.0 → 0.34.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 (39) hide show
  1. package/CHANGELOG.md +15 -0
  2. package/README.md +3 -3
  3. package/dist/catalog/index.d.ts +4 -2
  4. package/dist/catalog/index.js +6 -2
  5. package/dist/{chunk-VLJPCY54.js → chunk-2O3RMSOE.js} +3 -3
  6. package/dist/{chunk-RS2S2K5C.js → chunk-IHUNCBMF.js} +1083 -33
  7. package/dist/chunk-IHUNCBMF.js.map +1 -0
  8. package/dist/{chunk-DA4UUSDO.js → chunk-JETRHCP3.js} +9 -277
  9. package/dist/chunk-JETRHCP3.js.map +1 -0
  10. package/dist/{chunk-AUH3PEFW.js → chunk-MOLJPWME.js} +5 -3
  11. package/dist/{chunk-AUH3PEFW.js.map → chunk-MOLJPWME.js.map} +1 -1
  12. package/dist/{chunk-X3C2VFTM.js → chunk-N5HXMQOK.js} +7 -7
  13. package/dist/{chunk-3NPBCKKO.js → chunk-UU4PHRVF.js} +6 -6
  14. package/dist/{chunk-ORAFCHX3.js → chunk-VKIDRHBG.js} +278 -2
  15. package/dist/chunk-VKIDRHBG.js.map +1 -0
  16. package/dist/cli.js +2 -2
  17. package/dist/editor/index.d.ts +1 -1
  18. package/dist/editor/index.js +13 -5
  19. package/dist/editor/index.js.map +1 -1
  20. package/dist/{effect-GGT2BUW2.js → effect-6VQS2CA5.js} +8 -8
  21. package/dist/embed/index.d.ts +1 -1
  22. package/dist/embed/index.js +4 -4
  23. package/dist/index.js +19 -19
  24. package/dist/node.d.ts +1 -1
  25. package/dist/node.js +7 -7
  26. package/dist/react/index.d.ts +1 -1
  27. package/dist/react/index.js +5 -5
  28. package/dist/svelte/index.d.ts +1 -1
  29. package/dist/svelte/index.js +5 -5
  30. package/dist/{types-c8cnPzuE.d.ts → types-B4Wjzde0.d.ts} +10 -1
  31. package/dist/vector/index.js +14 -14
  32. package/package.json +1 -1
  33. package/dist/chunk-DA4UUSDO.js.map +0 -1
  34. package/dist/chunk-ORAFCHX3.js.map +0 -1
  35. package/dist/chunk-RS2S2K5C.js.map +0 -1
  36. /package/dist/{chunk-VLJPCY54.js.map → chunk-2O3RMSOE.js.map} +0 -0
  37. /package/dist/{chunk-X3C2VFTM.js.map → chunk-N5HXMQOK.js.map} +0 -0
  38. /package/dist/{chunk-3NPBCKKO.js.map → chunk-UU4PHRVF.js.map} +0 -0
  39. /package/dist/{effect-GGT2BUW2.js.map → effect-6VQS2CA5.js.map} +0 -0
@@ -352,9 +352,285 @@ function pathPointAt(d, at) {
352
352
  return last ? [last[1][0], last[1][1]] : [first[0], first[1]];
353
353
  }
354
354
 
355
+ // src/vector/motion.ts
356
+ var EASES = {
357
+ linear: (t) => t,
358
+ "in-out": (t) => t < 0.5 ? 4 * t * t * t : 1 - (-2 * t + 2) ** 3 / 2,
359
+ out: (t) => 1 - (1 - t) ** 3
360
+ };
361
+ var STEP_MS = 800;
362
+ var clamp01 = (t) => t < 0 ? 0 : t > 1 ? 1 : t;
363
+ function stepStart(steps, step) {
364
+ if (step <= 0) return 0;
365
+ return steps[step - 1];
366
+ }
367
+ function stepProgress(steps, timeMs, step, options = {}) {
368
+ const start = stepStart(steps, step);
369
+ if (start === void 0) return 0;
370
+ const from = start + (options.delay ?? 0);
371
+ const ms = options.ms ?? STEP_MS;
372
+ const t = ms > 0 ? clamp01((timeMs - from) / ms) : timeMs >= from ? 1 : 0;
373
+ return EASES[options.ease ?? "in-out"](t);
374
+ }
375
+ var defaultDataKey = (item, index) => {
376
+ if (item && typeof item === "object") {
377
+ const o = item;
378
+ if (o.source !== void 0 && o.target !== void 0)
379
+ return `${String(o.source)}\u2192${String(o.target)}`;
380
+ for (const k of ["id", "key", "name", "label"])
381
+ if (typeof o[k] === "string" || typeof o[k] === "number") return String(o[k]);
382
+ }
383
+ return String(index);
384
+ };
385
+ function scaled(value, k) {
386
+ if (typeof value === "number") return value * k;
387
+ if (Array.isArray(value)) return value.map((v) => scaled(v, k));
388
+ if (value && typeof value === "object")
389
+ return Object.fromEntries(Object.entries(value).map(([key, v]) => [key, scaled(v, k)]));
390
+ return value;
391
+ }
392
+ function lerpData(a, b, u, keyOf = defaultDataKey) {
393
+ if (u <= 0) return a;
394
+ if (u >= 1) return b;
395
+ return blend(a, b, u, keyOf);
396
+ }
397
+ function blend(a, b, u, keyOf) {
398
+ if (typeof a === "number" && typeof b === "number") return a + (b - a) * u;
399
+ if (Array.isArray(a) && Array.isArray(b)) {
400
+ const before = new Map(a.map((item, i) => [keyOf(item, i), item]));
401
+ const after = new Set(b.map((item, i) => keyOf(item, i)));
402
+ const out = b.map((item, i) => {
403
+ const key = keyOf(item, i);
404
+ return before.has(key) ? blend(before.get(key), item, u, keyOf) : scaled(item, u);
405
+ });
406
+ a.forEach((item, i) => {
407
+ if (!after.has(keyOf(item, i))) out.push(scaled(item, 1 - u));
408
+ });
409
+ return out;
410
+ }
411
+ if (a && b && typeof a === "object" && typeof b === "object") {
412
+ const ao = a;
413
+ const bo = b;
414
+ return Object.fromEntries(
415
+ [.../* @__PURE__ */ new Set([...Object.keys(ao), ...Object.keys(bo)])].map((k) => [
416
+ k,
417
+ k in ao && k in bo ? blend(ao[k], bo[k], u, keyOf) : k in bo ? scaled(bo[k], u) : scaled(ao[k], 1 - u)
418
+ ])
419
+ );
420
+ }
421
+ return u < 0.5 ? a : b;
422
+ }
423
+ function stepData(states, steps, timeMs, options = {}) {
424
+ const last = Math.min(steps.length, states.length - 1);
425
+ const to = states[last];
426
+ if (last === 0) return to;
427
+ const u = stepProgress(steps, timeMs, last, options);
428
+ return lerpData(states[last - 1], to, u, options.keyOf);
429
+ }
430
+ var SCRAMBLE_MS = 50;
431
+ function writtenText(text, u, options = {}) {
432
+ const letters = Array.from(text);
433
+ const shown = Math.round(clamp01(u) * letters.length);
434
+ let out = letters.slice(0, shown).join("");
435
+ const pool = Array.from(options.scramble ?? "");
436
+ if (pool.length) {
437
+ const tick = Math.floor((options.timeMs ?? 0) / SCRAMBLE_MS);
438
+ for (let i = shown; i < letters.length; i++)
439
+ out += /\s/.test(letters[i]) ? letters[i] : pool[Math.floor(noise(i, tick) * pool.length)];
440
+ }
441
+ return shown < letters.length && options.caret ? out + options.caret : out;
442
+ }
443
+ function noise(i, tick) {
444
+ const x = Math.sin(i * 127.1 + tick * 311.7) * 43758.5453;
445
+ return x - Math.floor(x);
446
+ }
447
+ var SVG_PICTURE = "";
448
+ var NUMBER = /-?(?:\d+\.?\d*|\.\d+)(?:e[-+]?\d+)?/gi;
449
+ var HEX = /^#([0-9a-f]{3}|[0-9a-f]{6})$/i;
450
+ function rgb(hex) {
451
+ let h = hex.slice(1);
452
+ if (h.length === 3) h = [...h].map((c) => c + c).join("");
453
+ return [0, 2, 4].map((i) => parseInt(h.slice(i, i + 2), 16));
454
+ }
455
+ var round = (n) => Math.round(n * 1e3) / 1e3;
456
+ function lerpAttr(a, b, u) {
457
+ if (typeof a === "number" && typeof b === "number") return String(round(a + (b - a) * u));
458
+ const sa = String(a);
459
+ const sb = String(b);
460
+ if (HEX.test(sa) && HEX.test(sb)) {
461
+ const [ca, cb] = [rgb(sa), rgb(sb)];
462
+ return `#${ca.map(
463
+ (c, i) => Math.round(c + (cb[i] - c) * u).toString(16).padStart(2, "0")
464
+ ).join("")}`;
465
+ }
466
+ const na = sa.match(NUMBER) ?? [];
467
+ const nb = sb.match(NUMBER) ?? [];
468
+ if (na.length && na.length === nb.length && sa.replace(NUMBER, "#") === sb.replace(NUMBER, "#")) {
469
+ let i = 0;
470
+ return sa.replace(NUMBER, () => {
471
+ const v = Number(na[i]) + (Number(nb[i]) - Number(na[i])) * u;
472
+ i++;
473
+ return String(round(v));
474
+ });
475
+ }
476
+ return u < 0.5 ? sa : sb;
477
+ }
478
+ function formatCount(value, options = {}) {
479
+ const n = value.toFixed(options.decimals ?? 0);
480
+ return (options.format ?? "{n}").replace("{n}", n);
481
+ }
482
+ var startOf = (a, steps) => {
483
+ const s = stepStart(steps, a.step ?? 0);
484
+ return s === void 0 ? Infinity : s + (a.delay ?? 0);
485
+ };
486
+ function svgFrame(animations, steps, timeMs) {
487
+ const tracks = /* @__PURE__ */ new Map();
488
+ const add = (prop, anim, index) => {
489
+ const key = `${prop === "view" ? SVG_PICTURE : anim.id}\0${prop}`;
490
+ const list = tracks.get(key) ?? [];
491
+ list.push({ anim, start: startOf(anim, steps), index });
492
+ tracks.set(key, list);
493
+ };
494
+ animations.forEach((a, i) => {
495
+ for (const name of Object.keys(a.attrs ?? {})) add(`@${name}`, a, i);
496
+ if (a.draw) add("draw", a, i);
497
+ if (a.count) add("count", a, i);
498
+ if (a.write !== void 0) add("count", a, i);
499
+ if (a.solo !== void 0) add("solo", a, i);
500
+ if (a.view !== void 0) add("view", a, i);
501
+ if (a.along) add("along", a, i);
502
+ });
503
+ const frames = /* @__PURE__ */ new Map();
504
+ for (const [key, list] of tracks) {
505
+ list.sort((x, y) => x.start - y.start || x.index - y.index);
506
+ const [id, prop] = key.split("\0");
507
+ const started = list.filter((c) => c.start <= timeMs);
508
+ const current = started[started.length - 1];
509
+ const anim = (current ?? list[0]).anim;
510
+ const u = current ? stepProgress(steps, timeMs, anim.step ?? 0, {
511
+ delay: anim.delay,
512
+ ms: anim.ms,
513
+ ease: anim.ease
514
+ }) : 0;
515
+ const frame = frames.get(id) ?? { attrs: {} };
516
+ if (prop === "view") {
517
+ const before = current ? list[list.indexOf(current) - 1] : void 0;
518
+ frame.view = { from: before?.anim.view ?? null, to: anim.view, u };
519
+ } else if (prop === "along") {
520
+ const [a, b] = anim.at ?? [0, 1];
521
+ frame.along = { path: anim.along, at: a + (b - a) * u };
522
+ } else if (prop === "solo") {
523
+ frame.solo = anim.solo;
524
+ } else if (prop.startsWith("@")) {
525
+ const [a, b] = anim.attrs[prop.slice(1)];
526
+ frame.attrs[prop.slice(1)] = lerpAttr(a, b, u);
527
+ } else if (prop === "draw") {
528
+ const [a, b] = anim.draw === true ? [0, 1] : anim.draw;
529
+ frame.draw = a + (b - a) * u;
530
+ } else if (anim.write !== void 0) {
531
+ frame.text = writtenText(anim.write, u, { scramble: anim.scramble, caret: anim.caret, timeMs });
532
+ } else {
533
+ const [a, b] = anim.count;
534
+ frame.text = formatCount(a + (b - a) * u, anim);
535
+ }
536
+ frames.set(id, frame);
537
+ }
538
+ return frames;
539
+ }
540
+ function svgOpeningTag(markup) {
541
+ const end = markup.indexOf(">");
542
+ return end < 0 ? markup : markup.slice(0, end + 1);
543
+ }
544
+ function svgMotionIssues(motion) {
545
+ const issues = [];
546
+ const m = motion ?? {};
547
+ const svg = typeof m.svg === "string" ? m.svg.trim() : "";
548
+ if (!svg) return ["`svg` needs the picture's markup: one <svg> element"];
549
+ if (!/^<svg[\s>]/i.test(svg) || !svg.toLowerCase().endsWith("</svg>"))
550
+ issues.push("`svg` must be one <svg>\u2026</svg> element");
551
+ if (!/\sviewBox\s*=/i.test(svgOpeningTag(svg)))
552
+ issues.push("the <svg> needs a `viewBox`, so it scales to where it is placed");
553
+ if (/<script|<foreignObject|\son\w+\s*=/i.test(svg))
554
+ issues.push("`svg` cannot have scripts, event handlers or <foreignObject>");
555
+ if (/<(animate|animateTransform|animateMotion|set)[\s/>]/i.test(svg))
556
+ issues.push(
557
+ "`svg` cannot animate itself (<animate>, <animateTransform>, <animateMotion>, <set>): give changes in `animate`, so every frame is a function of time"
558
+ );
559
+ if (/(?:href|src)\s*=\s*["'](?!#|data:image\/)/i.test(svg))
560
+ issues.push("`svg` cannot link outside itself (only #ids and data:image URLs)");
561
+ const ids = new Set([...svg.matchAll(/\sid\s*=\s*["']([^"']+)["']/g)].map((x) => x[1]));
562
+ if (m.animate !== void 0 && !Array.isArray(m.animate)) issues.push("`animate` must be a list");
563
+ (Array.isArray(m.animate) ? m.animate : []).forEach((a, i) => {
564
+ const where = `animate[${i}]`;
565
+ if (!a || typeof a !== "object") return void issues.push(`${where} is not an animation`);
566
+ if (typeof a.id !== "string") {
567
+ if (a.view === void 0) return void issues.push(`${where} needs an \`id\``);
568
+ } else if (!ids.has(a.id))
569
+ issues.push(`${where}: there is no element with id "${a.id}" in the SVG`);
570
+ if (a.step !== void 0 && !(Number.isInteger(a.step) && a.step >= 0))
571
+ issues.push(`${where}: \`step\` is a whole number, 0 or more`);
572
+ if (a.ms !== void 0 && !(a.ms >= 0)) issues.push(`${where}: \`ms\` must be 0 or more`);
573
+ if (a.delay !== void 0 && !(a.delay >= 0))
574
+ issues.push(`${where}: \`delay\` must be 0 or more`);
575
+ if (a.ease !== void 0 && !(a.ease in EASES))
576
+ issues.push(`${where}: \`ease\` is one of ${Object.keys(EASES).join(", ")}`);
577
+ if (!a.attrs && !a.draw && !a.count && a.write === void 0 && a.view === void 0 && !a.along && a.solo === void 0)
578
+ issues.push(
579
+ `${where} changes nothing: give \`attrs\`, \`draw\`, \`count\`, \`write\`, \`view\`, \`along\` or \`solo\``
580
+ );
581
+ if (a.solo !== void 0 && !(Number.isInteger(a.solo) && a.solo >= 0))
582
+ issues.push(`${where}: \`solo\` is an index (whole number, 0 or more)`);
583
+ if (a.view !== void 0) {
584
+ const box = a.view;
585
+ if (typeof box === "string") {
586
+ if (!ids.has(box))
587
+ issues.push(`${where}: \`view\` frames "${box}", which is not an id in the SVG`);
588
+ } else if (!Array.isArray(box) || box.length !== 4 || !box.every((n) => Number.isFinite(n)) || !(box[2] > 0 && box[3] > 0))
589
+ issues.push(
590
+ `${where}: \`view\` is [x, y, width, height] (width and height above 0) or an element's id`
591
+ );
592
+ }
593
+ if (a.along !== void 0) {
594
+ if (typeof a.along !== "string" || !ids.has(a.along))
595
+ issues.push(`${where}: \`along\` is the id of a path in the SVG`);
596
+ if (typeof a.id !== "string")
597
+ issues.push(`${where}: \`along\` moves an element: give its \`id\``);
598
+ }
599
+ if (a.at !== void 0 && !(Array.isArray(a.at) && a.at.length === 2 && a.at.every((v) => v >= 0 && v <= 1)))
600
+ issues.push(`${where}: \`at\` is [from, to] between 0 and 1`);
601
+ for (const [name, pair] of Object.entries(a.attrs ?? {}))
602
+ if (!Array.isArray(pair) || pair.length !== 2)
603
+ issues.push(`${where}: \`attrs.${name}\` is [from, to]`);
604
+ if (Array.isArray(a.draw) && a.draw.some((v) => !(v >= 0 && v <= 1)))
605
+ issues.push(`${where}: \`draw\` is true or [from, to] between 0 and 1`);
606
+ if (a.count !== void 0 && !(Array.isArray(a.count) && a.count.length === 2))
607
+ issues.push(`${where}: \`count\` is [from, to]`);
608
+ if (a.write !== void 0 && typeof a.write !== "string")
609
+ issues.push(`${where}: \`write\` is the text to write`);
610
+ if ((a.scramble !== void 0 || a.caret !== void 0) && a.write === void 0)
611
+ issues.push(`${where}: \`scramble\` and \`caret\` go with \`write\``);
612
+ });
613
+ return issues;
614
+ }
615
+
355
616
  export {
356
617
  morphSequence,
357
618
  morphPaths,
358
- pathPointAt
619
+ pathPointAt,
620
+ EASES,
621
+ STEP_MS,
622
+ stepStart,
623
+ stepProgress,
624
+ defaultDataKey,
625
+ lerpData,
626
+ stepData,
627
+ SCRAMBLE_MS,
628
+ writtenText,
629
+ SVG_PICTURE,
630
+ lerpAttr,
631
+ formatCount,
632
+ svgFrame,
633
+ svgOpeningTag,
634
+ svgMotionIssues
359
635
  };
360
- //# sourceMappingURL=chunk-ORAFCHX3.js.map
636
+ //# sourceMappingURL=chunk-VKIDRHBG.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/vector/morph.ts","../src/vector/motion.ts"],"sourcesContent":["/**\n * Shape morphing: any SVG paths turned into paths with the same structure, so\n * an `attrs` change on `d` (see `SvgAnimation`) blends one into the other\n * point by point. Pure functions of their arguments, with no DOM.\n */\n\ntype Point = [number, number];\n\n/** One piece of a path: its outline as points, and whether it closes. */\ninterface Ring {\n points: Point[];\n closed: boolean;\n}\n\nexport interface MorphOptions {\n /** Points per piece of the shape (default 72): more follows curves more closely. */\n points?: number;\n /** Decimals in the numbers written (default 2). */\n decimals?: number;\n}\n\n/** Segments a curve is split into before resampling. */\nconst CURVE_STEPS = 24;\n\nconst TOKEN = /[MmLlHhVvCcSsQqTtAaZz]|-?(?:\\d+\\.?\\d*|\\.\\d+)(?:e[-+]?\\d+)?/gi;\n\n/** Arguments each command takes (repeated commands take them again). */\nconst ARGS: Record<string, number> = { m: 2, l: 2, h: 1, v: 1, c: 6, s: 4, q: 4, t: 2, a: 7, z: 0 };\n\n/**\n * The pieces of a path's `d` as outlines: lines kept, curves and arcs split\n * into short lines. Throws on a command it does not know.\n */\nfunction flatten(d: string): Ring[] {\n const stray = d.replace(TOKEN, \"\").replace(/[\\s,]+/g, \"\");\n if (stray) throw new Error(`\"${stray[0]}\" is not a path command`);\n const tokens = d.match(TOKEN) ?? [];\n const rings: Ring[] = [];\n // Typed by a cast: the helpers below assign it, which narrowing would miss.\n let ring = null as Ring | null;\n let x = 0;\n let y = 0;\n let startX = 0;\n let startY = 0;\n // The last control point, for S and T.\n let cx = 0;\n let cy = 0;\n let prev = \"\";\n let i = 0;\n let command = \"\";\n const add = (px: number, py: number) => ring!.points.push([px, py]);\n const begin = (px: number, py: number) => {\n if (ring && ring.points.length) rings.push(ring);\n ring = { points: [[px, py]], closed: false };\n };\n while (i < tokens.length) {\n if (/[a-z]/i.test(tokens[i]!)) command = tokens[i++]!;\n else if (!command) throw new Error(`\"${tokens[i]}\" needs a command (M, L, C, …) before it`);\n const lower = command.toLowerCase();\n if (!(lower in ARGS)) throw new Error(`Unknown path command \"${command}\"`);\n const rel = command !== command.toUpperCase();\n const n = ARGS[lower]!;\n const args = tokens.slice(i, i + n).map(Number);\n if (args.length < n || args.some((v) => Number.isNaN(v))) break;\n i += n;\n const ox = rel ? x : 0;\n const oy = rel ? y : 0;\n if (lower === \"z\") {\n if (ring) {\n ring.closed = true;\n rings.push(ring);\n ring = null;\n }\n x = startX;\n y = startY;\n prev = \"z\";\n // A Z takes no arguments: wait for the next command.\n command = \"\";\n continue;\n }\n if (!ring) begin(x, y);\n switch (lower) {\n case \"m\":\n x = ox + args[0]!;\n y = oy + args[1]!;\n startX = x;\n startY = y;\n begin(x, y);\n // Pairs after a moveto are linetos.\n command = rel ? \"l\" : \"L\";\n break;\n case \"l\":\n x = ox + args[0]!;\n y = oy + args[1]!;\n add(x, y);\n break;\n case \"h\":\n x = ox + args[0]!;\n add(x, y);\n break;\n case \"v\":\n y = (rel ? y : 0) + args[0]!;\n add(x, y);\n break;\n case \"c\":\n case \"s\": {\n let x1: number;\n let y1: number;\n let rest: number[];\n if (lower === \"c\") {\n x1 = ox + args[0]!;\n y1 = oy + args[1]!;\n rest = args.slice(2);\n } else {\n const smooth = prev === \"c\" || prev === \"s\";\n x1 = smooth ? 2 * x - cx : x;\n y1 = smooth ? 2 * y - cy : y;\n rest = args;\n }\n const x2 = ox + rest[0]!;\n const y2 = oy + rest[1]!;\n const ex = ox + rest[2]!;\n const ey = oy + rest[3]!;\n for (let k = 1; k <= CURVE_STEPS; k++) {\n const t = k / CURVE_STEPS;\n const u = 1 - t;\n add(\n u * u * u * x + 3 * u * u * t * x1 + 3 * u * t * t * x2 + t * t * t * ex,\n u * u * u * y + 3 * u * u * t * y1 + 3 * u * t * t * y2 + t * t * t * ey,\n );\n }\n cx = x2;\n cy = y2;\n x = ex;\n y = ey;\n break;\n }\n case \"q\":\n case \"t\": {\n let x1: number;\n let y1: number;\n let ex: number;\n let ey: number;\n if (lower === \"q\") {\n x1 = ox + args[0]!;\n y1 = oy + args[1]!;\n ex = ox + args[2]!;\n ey = oy + args[3]!;\n } else {\n const smooth = prev === \"q\" || prev === \"t\";\n x1 = smooth ? 2 * x - cx : x;\n y1 = smooth ? 2 * y - cy : y;\n ex = ox + args[0]!;\n ey = oy + args[1]!;\n }\n for (let k = 1; k <= CURVE_STEPS; k++) {\n const t = k / CURVE_STEPS;\n const u = 1 - t;\n add(u * u * x + 2 * u * t * x1 + t * t * ex, u * u * y + 2 * u * t * y1 + t * t * ey);\n }\n cx = x1;\n cy = y1;\n x = ex;\n y = ey;\n break;\n }\n case \"a\": {\n const ex = ox + args[5]!;\n const ey = oy + args[6]!;\n for (const p of arcPoints(x, y, args[0]!, args[1]!, args[2]!, args[3]! !== 0, args[4]! !== 0, ex, ey)) add(p[0], p[1]);\n x = ex;\n y = ey;\n break;\n }\n }\n prev = lower;\n }\n if (ring && ring.points.length) rings.push(ring);\n return rings\n .map((r) => {\n // A ring that ends where it starts is closed, Z or not.\n const [a, b] = [r.points[0]!, r.points[r.points.length - 1]!];\n const closes = r.points.length > 2 && Math.hypot(a[0] - b[0], a[1] - b[1]) < 1e-6;\n return { points: closes ? r.points.slice(0, -1) : r.points, closed: r.closed || closes };\n })\n .filter((r) => r.points.length > 1);\n}\n\n/** Points along an SVG arc (endpoint form), not including its start. */\nfunction arcPoints(\n x1: number,\n y1: number,\n rx: number,\n ry: number,\n angle: number,\n large: boolean,\n sweep: boolean,\n x2: number,\n y2: number,\n): Point[] {\n rx = Math.abs(rx);\n ry = Math.abs(ry);\n if (!rx || !ry || (x1 === x2 && y1 === y2)) return [[x2, y2]];\n const phi = (angle * Math.PI) / 180;\n const cos = Math.cos(phi);\n const sin = Math.sin(phi);\n const dx = (x1 - x2) / 2;\n const dy = (y1 - y2) / 2;\n const x1p = cos * dx + sin * dy;\n const y1p = -sin * dx + cos * dy;\n // Radii too small to reach are scaled up, as SVG says.\n const lambda = (x1p * x1p) / (rx * rx) + (y1p * y1p) / (ry * ry);\n if (lambda > 1) {\n rx *= Math.sqrt(lambda);\n ry *= Math.sqrt(lambda);\n }\n const num = rx * rx * ry * ry - rx * rx * y1p * y1p - ry * ry * x1p * x1p;\n const den = rx * rx * y1p * y1p + ry * ry * x1p * x1p;\n const k = (large === sweep ? -1 : 1) * Math.sqrt(Math.max(0, num / den));\n const cxp = (k * rx * y1p) / ry;\n const cyp = (-k * ry * x1p) / rx;\n const cx = cos * cxp - sin * cyp + (x1 + x2) / 2;\n const cy = sin * cxp + cos * cyp + (y1 + y2) / 2;\n const theta = (ux: number, uy: number, vx: number, vy: number) =>\n Math.atan2(ux * vy - uy * vx, ux * vx + uy * vy);\n const start = theta(1, 0, (x1p - cxp) / rx, (y1p - cyp) / ry);\n let delta = theta((x1p - cxp) / rx, (y1p - cyp) / ry, (-x1p - cxp) / rx, (-y1p - cyp) / ry);\n if (!sweep && delta > 0) delta -= 2 * Math.PI;\n if (sweep && delta < 0) delta += 2 * Math.PI;\n const steps = Math.max(2, Math.ceil((Math.abs(delta) / (Math.PI / 2)) * (CURVE_STEPS / 2)));\n const out: Point[] = [];\n for (let s = 1; s <= steps; s++) {\n const t = start + (delta * s) / steps;\n const px = rx * Math.cos(t);\n const py = ry * Math.sin(t);\n out.push([cos * px - sin * py + cx, sin * px + cos * py + cy]);\n }\n out[out.length - 1] = [x2, y2];\n return out;\n}\n\n/**\n * `n` points evenly spaced along a ring. A closed ring goes round once; an\n * open one (a stroke) is resampled as closed by going there and back, so it\n * can turn into a closed shape.\n */\nfunction resample(ring: Ring, n: number): Point[] {\n const pts = ring.closed ? [...ring.points, ring.points[0]!] : [...ring.points, ...ring.points.slice(0, -1).reverse()];\n const lengths = [0];\n for (let i = 1; i < pts.length; i++)\n lengths.push(lengths[i - 1]! + Math.hypot(pts[i]![0] - pts[i - 1]![0], pts[i]![1] - pts[i - 1]![1]));\n const total = lengths[lengths.length - 1]!;\n if (total === 0) return Array.from({ length: n }, () => [pts[0]![0], pts[0]![1]] as Point);\n const out: Point[] = [];\n let j = 1;\n for (let k = 0; k < n; k++) {\n const at = (k / n) * total;\n while (j < lengths.length - 1 && lengths[j]! < at) j++;\n const seg = lengths[j]! - lengths[j - 1]!;\n const t = seg > 0 ? (at - lengths[j - 1]!) / seg : 0;\n const a = pts[j - 1]!;\n const b = pts[j]!;\n out.push([a[0] + (b[0] - a[0]) * t, a[1] + (b[1] - a[1]) * t]);\n }\n return out;\n}\n\nconst signedArea = (pts: Point[]) => {\n let sum = 0;\n for (let i = 0; i < pts.length; i++) {\n const a = pts[i]!;\n const b = pts[(i + 1) % pts.length]!;\n sum += a[0] * b[1] - b[0] * a[1];\n }\n return sum / 2;\n};\n\nconst centroid = (pts: Point[]): Point => {\n let x = 0;\n let y = 0;\n for (const p of pts) {\n x += p[0];\n y += p[1];\n }\n return [x / pts.length, y / pts.length];\n};\n\n/** How big a piece is: its area, or for a stroke its length times a little. */\nfunction size(ring: Ring, pts: Point[]): number {\n const area = Math.abs(signedArea(pts));\n if (ring.closed && area > 0) return area;\n let length = 0;\n for (let i = 1; i < ring.points.length; i++)\n length += Math.hypot(ring.points[i]![0] - ring.points[i - 1]![0], ring.points[i]![1] - ring.points[i - 1]![1]);\n return length;\n}\n\ninterface Piece {\n pts: Point[];\n centre: Point;\n size: number;\n}\n\n/**\n * Pairs the pieces of one shape with the slots of the shape before it,\n * nearest and most alike first: a slot left over is empty (a piece that\n * shrinks away), and a piece left over takes an empty slot (it grows).\n */\nfunction assign(before: (Piece | null)[], pieces: Piece[], scale: number): (Piece | null)[] {\n const out: (Piece | null)[] = before.map(() => null);\n const pairs: { slot: number; piece: number; cost: number }[] = [];\n before.forEach((slot, s) => {\n if (!slot) return;\n pieces.forEach((p, i) => {\n const distance = Math.hypot(slot.centre[0] - p.centre[0], slot.centre[1] - p.centre[1]) / scale;\n const likeness = Math.abs(Math.log((slot.size + 1e-9) / (p.size + 1e-9)));\n pairs.push({ slot: s, piece: i, cost: distance + 0.5 * likeness });\n });\n });\n pairs.sort((a, b) => a.cost - b.cost);\n const used = new Set<number>();\n for (const { slot, piece } of pairs) {\n if (out[slot] || used.has(piece)) continue;\n out[slot] = pieces[piece]!;\n used.add(piece);\n }\n let free = 0;\n pieces.forEach((p, i) => {\n if (used.has(i)) return;\n while (out[free] || before[free]) free++;\n out[free] = p;\n });\n return out;\n}\n\n/** `pts` turned and started so it lines up with `ref` point by point (the shortest moves). */\nfunction align(ref: Point[], pts: Point[]): Point[] {\n const n = pts.length;\n let best = pts;\n let bestCost = Infinity;\n for (const candidate of [pts, [...pts].reverse()]) {\n for (let shift = 0; shift < n; shift++) {\n let cost = 0;\n for (let k = 0; k < n && cost < bestCost; k++) {\n const a = ref[k]!;\n const b = candidate[(k + shift) % n]!;\n cost += (a[0] - b[0]) ** 2 + (a[1] - b[1]) ** 2;\n }\n if (cost < bestCost) {\n bestCost = cost;\n best = candidate.slice(shift).concat(candidate.slice(0, shift));\n }\n }\n }\n return best;\n}\n\n/**\n * Paths with one structure for a sequence of shapes, so each blends into the\n * next (and the last into the first) with `attrs: { d: [a, b] }`. Any path\n * commands work, curves and arcs included, and shapes can have different\n * numbers of pieces (an icon's parts, a letter's holes): pieces are paired by\n * position and size, and one without a partner grows from or shrinks to a\n * point. Draw the results with `fill-rule=\"evenodd\"`, since a piece's\n * direction can change. Throws a sentence when a path cannot be read.\n */\nexport function morphSequence(paths: readonly string[], options: MorphOptions = {}): string[] {\n const n = Math.max(8, Math.round(options.points ?? 72));\n const decimals = options.decimals ?? 2;\n const shapes = paths.map((d, i) => {\n let rings: Ring[];\n try {\n rings = flatten(d);\n } catch (e) {\n throw new Error(`Path ${i + 1} cannot be read: ${(e as Error).message}`);\n }\n if (!rings.length) throw new Error(`Path ${i + 1} draws nothing: give it at least two points`);\n return rings.map((r): Piece => {\n const pts = resample(r, n);\n return { pts, centre: centroid(pts), size: size(r, pts) };\n });\n });\n if (!shapes.length) return [];\n const slots = Math.max(...shapes.map((s) => s.length));\n // How far apart counts as far, from the shapes' extent.\n const xs = shapes.flat().flatMap((p) => p.pts.map((q) => q[0]));\n const ys = shapes.flat().flatMap((p) => p.pts.map((q) => q[1]));\n const scale = Math.max(1e-6, Math.max(...xs) - Math.min(...xs), Math.max(...ys) - Math.min(...ys));\n // Biggest pieces first, so the main outlines keep the first slots.\n const first = [...shapes[0]!].sort((a, b) => b.size - a.size);\n const assigned: (Piece | null)[][] = [[...first, ...Array<null>(slots - first.length).fill(null)]];\n for (let i = 1; i < shapes.length; i++) assigned.push(assign(assigned[i - 1]!, shapes[i]!, scale));\n // An empty slot is a point: where the piece in that slot is in the nearest shape that has one.\n const resolved = assigned.map((shape, i) =>\n shape.map((piece, s): Point[] => {\n if (piece) return piece.pts;\n for (let k = 1; k < shapes.length; k++) {\n const near = assigned[(i + k) % shapes.length]![s] ?? assigned[(i - k + shapes.length) % shapes.length]![s];\n if (near) return Array.from({ length: n }, () => [near.centre[0], near.centre[1]] as Point);\n }\n return Array.from({ length: n }, () => [0, 0] as Point);\n }),\n );\n for (let i = 1; i < resolved.length; i++)\n resolved[i] = resolved[i]!.map((pts, s) => align(resolved[i - 1]![s]!, pts));\n const num = (v: number) => {\n const r = Number(v.toFixed(decimals));\n return String(Object.is(r, -0) ? 0 : r);\n };\n return resolved.map((shape) =>\n shape.map((pts) => `M${pts.map((p) => `${num(p[0])} ${num(p[1])}`).join(\" L\")} Z`).join(\" \"),\n );\n}\n\n/**\n * Two paths turned into paths with one structure, so `attrs: { d: [from, to] }`\n * blends one into the other (see {@link morphSequence}).\n */\nexport function morphPaths(from: string, to: string, options: MorphOptions = {}): [string, string] {\n const [a, b] = morphSequence([from, to], options);\n return [a!, b!];\n}\n\n/**\n * @internal The point `at` (0–1) of the way along a path's `d` by length, as\n * a browser's `getPointAtLength` finds it (moves between pieces not counted),\n * with curves split into short lines. Undefined when `d` does not parse.\n */\nexport function pathPointAt(d: string, at: number): [number, number] | undefined {\n let rings: Ring[];\n try {\n rings = flatten(d);\n } catch {\n return undefined;\n }\n const lines: [Point, Point, number][] = [];\n for (const ring of rings) {\n const pts = ring.closed ? [...ring.points, ring.points[0]!] : ring.points;\n for (let i = 1; i < pts.length; i++)\n lines.push([pts[i - 1]!, pts[i]!, Math.hypot(pts[i]![0] - pts[i - 1]![0], pts[i]![1] - pts[i - 1]![1])]);\n }\n const first = rings[0]?.points[0];\n if (!first) return undefined;\n let left = Math.min(Math.max(at, 0), 1) * lines.reduce((sum, l) => sum + l[2], 0);\n for (const [a, b, length] of lines) {\n if (left <= length && length > 0) return [a[0] + ((b[0] - a[0]) * left) / length, a[1] + ((b[1] - a[1]) * left) / length];\n left -= length;\n }\n const last = lines[lines.length - 1];\n return last ? [last[1][0], last[1][1]] : [first[0], first[1]];\n}\n","/**\n * Vector motion: animated SVG pictures described as data. A picture changes in\n * steps (step 0 when it starts, step n at `steps[n - 1]` ms), and everything\n * here is a pure function of its arguments, so a frame comes out the same\n * however it is reached (played, stepped for a recording, or seeked).\n */\n\n/** Easing curves by name. */\nexport const EASES = {\n linear: (t: number) => t,\n \"in-out\": (t: number) => (t < 0.5 ? 4 * t * t * t : 1 - (-2 * t + 2) ** 3 / 2),\n out: (t: number) => 1 - (1 - t) ** 3,\n} as const;\n\nexport type EaseName = keyof typeof EASES;\n\n/** How long a change takes by default, in ms. */\nexport const STEP_MS = 800;\n\nconst clamp01 = (t: number) => (t < 0 ? 0 : t > 1 ? 1 : t);\n\n/**\n * When `step` starts, in ms since the media started (step 0 at 0, step n at\n * `steps[n - 1]`), or undefined if it has not started yet.\n */\nexport function stepStart(steps: readonly number[], step: number): number | undefined {\n if (step <= 0) return 0;\n return steps[step - 1];\n}\n\n/**\n * How far a change that plays on `step` (after `delay` ms, over `ms`) has\n * got at `timeMs`, eased: 0 before it starts, 1 once it is over.\n */\nexport function stepProgress(\n steps: readonly number[],\n timeMs: number,\n step: number,\n options: { delay?: number; ms?: number; ease?: EaseName } = {},\n): number {\n const start = stepStart(steps, step);\n if (start === undefined) return 0;\n const from = start + (options.delay ?? 0);\n const ms = options.ms ?? STEP_MS;\n const t = ms > 0 ? clamp01((timeMs - from) / ms) : timeMs >= from ? 1 : 0;\n return EASES[options.ease ?? \"in-out\"](t);\n}\n\n/** The key an item in a list of data keeps from one state to the next. */\nexport type DataKey = (item: unknown, index: number) => string;\n\n/**\n * Keys items by their `id`, `key`, `name` or `label` (or a link's `source`\n * and `target`), else by position.\n */\nexport const defaultDataKey: DataKey = (item, index) => {\n if (item && typeof item === \"object\") {\n const o = item as Record<string, unknown>;\n if (o.source !== undefined && o.target !== undefined)\n return `${String(o.source)}→${String(o.target)}`;\n for (const k of [\"id\", \"key\", \"name\", \"label\"])\n if (typeof o[k] === \"string\" || typeof o[k] === \"number\") return String(o[k]);\n }\n return String(index);\n};\n\n/** Every number in `value` times `k`, so an item can grow from or shrink to nothing. */\nfunction scaled(value: unknown, k: number): unknown {\n if (typeof value === \"number\") return value * k;\n if (Array.isArray(value)) return value.map((v) => scaled(v, k));\n if (value && typeof value === \"object\")\n return Object.fromEntries(Object.entries(value).map(([key, v]) => [key, scaled(v, k)]));\n return value;\n}\n\n/**\n * Data between two states, `u` of the way from `a` to `b`. Numbers blend;\n * lists match their items by key (`keyOf`), so each keeps its identity and\n * moves rather than jumping, with items only in `b` growing from nothing and\n * items only in `a` shrinking away; objects blend field by field; anything\n * else changes halfway.\n */\nexport function lerpData<D>(a: D, b: D, u: number, keyOf: DataKey = defaultDataKey): D {\n if (u <= 0) return a;\n if (u >= 1) return b;\n return blend(a, b, u, keyOf) as D;\n}\n\nfunction blend(a: unknown, b: unknown, u: number, keyOf: DataKey): unknown {\n if (typeof a === \"number\" && typeof b === \"number\") return a + (b - a) * u;\n if (Array.isArray(a) && Array.isArray(b)) {\n const before = new Map(a.map((item, i) => [keyOf(item, i), item]));\n const after = new Set(b.map((item, i) => keyOf(item, i)));\n const out: unknown[] = b.map((item, i) => {\n const key = keyOf(item, i);\n return before.has(key) ? blend(before.get(key), item, u, keyOf) : scaled(item, u);\n });\n a.forEach((item, i) => {\n if (!after.has(keyOf(item, i))) out.push(scaled(item, 1 - u));\n });\n return out;\n }\n if (a && b && typeof a === \"object\" && typeof b === \"object\") {\n const ao = a as Record<string, unknown>;\n const bo = b as Record<string, unknown>;\n return Object.fromEntries(\n [...new Set([...Object.keys(ao), ...Object.keys(bo)])].map((k) => [\n k,\n k in ao && k in bo\n ? blend(ao[k], bo[k], u, keyOf)\n : k in bo\n ? scaled(bo[k], u)\n : scaled(ao[k], 1 - u),\n ]),\n );\n }\n return u < 0.5 ? a : b;\n}\n\n/**\n * The data to show at `timeMs`, for media whose data has a state per step:\n * `states[n]` is shown from step n (the last one stays), reached by moving\n * from the state before it over `ms`.\n */\nexport function stepData<D>(\n states: readonly D[],\n steps: readonly number[],\n timeMs: number,\n options: { ms?: number; ease?: EaseName; keyOf?: DataKey } = {},\n): D {\n const last = Math.min(steps.length, states.length - 1);\n const to = states[last]!;\n if (last === 0) return to;\n const u = stepProgress(steps, timeMs, last, options);\n return lerpData(states[last - 1]!, to, u, options.keyOf);\n}\n\n// ── SVG media ──────────────────────────────────────────────────────────\n\n/**\n * An animated SVG picture: markup plus changes to its elements. Draw it with\n * `SvgPlayer` (or `svgView`), or compute frames yourself with `svgFrame`.\n */\nexport interface SvgMotion {\n /** One self-contained `<svg>` with a `viewBox`: no scripts, no outside links. */\n svg: string;\n /** Changes to its elements, each on a step. */\n animate?: SvgAnimation[];\n}\n\n/** A box in an SVG's `viewBox` units: `[x, y, width, height]`. */\nexport type SvgBox = readonly [number, number, number, number];\n\n/** A change to one element of an {@link SvgMotion}, or (with `view`) to the whole picture. */\nexport interface SvgAnimation {\n /** The element's `id` in the SVG (not needed for `view`). */\n id?: string;\n /** The step it plays on: 0 (default) when the media starts, 1 with the next shot, and so on. */\n step?: number;\n /** Ms after the step starts. */\n delay?: number;\n /** How long it takes, in ms (default {@link STEP_MS}). */\n ms?: number;\n ease?: EaseName;\n /**\n * Attributes from one value to another: numbers, colours (`#rrggbb`), or\n * strings whose numbers change while the rest stays the same (a path's\n * `d`, a `transform`, `points`).\n */\n attrs?: Record<string, readonly [string | number, string | number]>;\n /** Draws a line or outline on along its length, from 0 to 1 (or between two fractions). */\n draw?: boolean | readonly [number, number];\n /**\n * Zooms and pans the whole picture to frame a box (`[x, y, width, height]`\n * in the `viewBox`'s units) or an element by id (with a margin round it),\n * from where the last `view` left it (at first, the whole `viewBox`).\n */\n view?: SvgBox | string;\n /**\n * Moves the element along a path (by id) from its start to its end, or\n * between the fractions in `at`; draw the element round (0, 0), like a\n * circle at `cx=\"0\" cy=\"0\"`.\n */\n along?: string;\n /** How far along the path `along` moves the element, from and to (default [0, 1]). */\n at?: readonly [number, number];\n /**\n * Sets the active child index in a solo container (data-solo group or element with multiple children).\n * Hides all siblings except the one at this index (0-based).\n */\n solo?: number;\n /** Counts the element's text from one number to the other. */\n count?: readonly [number, number];\n /** How a count is written: `{n}` stands for the number (\"{n}%\", \"$ {n}M\"). */\n format?: string;\n /** Decimals in a count (default 0). */\n decimals?: number;\n /**\n * Writes this text into the element letter by letter: none of it when the\n * change starts, all of it when it ends (a typewriter).\n */\n write?: string;\n /**\n * With `write`: letters not yet written show characters picked from this\n * string, changing every {@link SCRAMBLE_MS} ms, so the text decodes\n * rather than types. The same time always picks the same characters.\n */\n scramble?: string;\n /** With `write`: shown after the written letters while it writes (\"▌\", \"|\"). */\n caret?: string;\n}\n\n/** How often scrambled letters change, in ms (see `SvgAnimation.scramble`). */\nexport const SCRAMBLE_MS = 50;\n\n/**\n * `text` with `u` (0–1) of its letters written (see `SvgAnimation.write`):\n * the rest scrambled from `scramble` (picked by `timeMs`) or left off, then\n * the caret while it is unfinished. Letters are code points, so emoji and\n * accents are never split.\n */\nexport function writtenText(\n text: string,\n u: number,\n options: { scramble?: string; caret?: string; timeMs?: number } = {},\n): string {\n const letters = Array.from(text);\n const shown = Math.round(clamp01(u) * letters.length);\n let out = letters.slice(0, shown).join(\"\");\n const pool = Array.from(options.scramble ?? \"\");\n if (pool.length) {\n const tick = Math.floor((options.timeMs ?? 0) / SCRAMBLE_MS);\n for (let i = shown; i < letters.length; i++)\n out += /\\s/.test(letters[i]!) ? letters[i] : pool[Math.floor(noise(i, tick) * pool.length)];\n }\n return shown < letters.length && options.caret ? out + options.caret : out;\n}\n\n/** A repeatable 0–1 number for a letter at a tick. */\nfunction noise(i: number, tick: number): number {\n const x = Math.sin(i * 127.1 + tick * 311.7) * 43758.5453;\n return x - Math.floor(x);\n}\n\n/** What one element of an animated SVG shows at a time. */\nexport interface SvgElementFrame {\n attrs: Record<string, string>;\n /** How much of its length is drawn, 0–1. */\n draw?: number;\n text?: string;\n /** Active child index when targeting a solo container. */\n solo?: number;\n /** Where it is along a path: the path's id and the fraction of its length. */\n along?: { path: string; at: number };\n /**\n * The whole picture's framing (on the frame for {@link SVG_PICTURE}): `u`\n * of the way from one view to the next, `null` being the whole `viewBox`.\n */\n view?: { from: SvgBox | string | null; to: SvgBox | string; u: number };\n}\n\n/** The key of the whole picture's frame in {@link svgFrame}'s result (for `view`). */\nexport const SVG_PICTURE = \"\";\n\nconst NUMBER = /-?(?:\\d+\\.?\\d*|\\.\\d+)(?:e[-+]?\\d+)?/gi;\nconst HEX = /^#([0-9a-f]{3}|[0-9a-f]{6})$/i;\n\nfunction rgb(hex: string): [number, number, number] {\n let h = hex.slice(1);\n if (h.length === 3) h = [...h].map((c) => c + c).join(\"\");\n return [0, 2, 4].map((i) => parseInt(h.slice(i, i + 2), 16)) as [number, number, number];\n}\n\nconst round = (n: number) => Math.round(n * 1000) / 1000;\n\n/** A value `u` of the way between two attribute values (see `SvgAnimation.attrs`). */\nexport function lerpAttr(a: string | number, b: string | number, u: number): string {\n if (typeof a === \"number\" && typeof b === \"number\") return String(round(a + (b - a) * u));\n const sa = String(a);\n const sb = String(b);\n if (HEX.test(sa) && HEX.test(sb)) {\n const [ca, cb] = [rgb(sa), rgb(sb)];\n return `#${ca\n .map((c, i) =>\n Math.round(c + (cb[i]! - c) * u)\n .toString(16)\n .padStart(2, \"0\"),\n )\n .join(\"\")}`;\n }\n const na = sa.match(NUMBER) ?? [];\n const nb = sb.match(NUMBER) ?? [];\n if (na.length && na.length === nb.length && sa.replace(NUMBER, \"#\") === sb.replace(NUMBER, \"#\")) {\n let i = 0;\n return sa.replace(NUMBER, () => {\n const v = Number(na[i]) + (Number(nb[i]) - Number(na[i])) * u;\n i++;\n return String(round(v));\n });\n }\n return u < 0.5 ? sa : sb;\n}\n\n/** Formats a number for a count animation (`{n}` stands for the rounded number). */\nexport function formatCount(\n value: number,\n options: { decimals?: number; format?: string } = {},\n): string {\n const n = value.toFixed(options.decimals ?? 0);\n return (options.format ?? \"{n}\").replace(\"{n}\", n);\n}\n\nconst startOf = (a: SvgAnimation, steps: readonly number[]) => {\n const s = stepStart(steps, a.step ?? 0);\n return s === undefined ? Infinity : s + (a.delay ?? 0);\n};\n\n/**\n * What each animated element shows at `timeMs`. For each attribute (or\n * line, count or writing) the latest change to have started wins; before the first\n * one starts, the element shows that change's starting value, so something\n * that grows in later is hidden until then.\n */\nexport function svgFrame(\n animations: readonly SvgAnimation[],\n steps: readonly number[],\n timeMs: number,\n): Map<string, SvgElementFrame> {\n // Each property's changes in the order they start (ties: list order).\n const tracks = new Map<string, { anim: SvgAnimation; start: number; index: number }[]>();\n const add = (prop: string, anim: SvgAnimation, index: number) => {\n const key = `${prop === \"view\" ? SVG_PICTURE : anim.id}\\u0000${prop}`;\n const list = tracks.get(key) ?? [];\n list.push({ anim, start: startOf(anim, steps), index });\n tracks.set(key, list);\n };\n animations.forEach((a, i) => {\n for (const name of Object.keys(a.attrs ?? {})) add(`@${name}`, a, i);\n if (a.draw) add(\"draw\", a, i);\n if (a.count) add(\"count\", a, i);\n if (a.write !== undefined) add(\"count\", a, i);\n if (a.solo !== undefined) add(\"solo\", a, i);\n if (a.view !== undefined) add(\"view\", a, i);\n if (a.along) add(\"along\", a, i);\n });\n const frames = new Map<string, SvgElementFrame>();\n for (const [key, list] of tracks) {\n list.sort((x, y) => x.start - y.start || x.index - y.index);\n const [id, prop] = key.split(\"\\u0000\") as [string, string];\n const started = list.filter((c) => c.start <= timeMs);\n const current = started[started.length - 1];\n const anim = (current ?? list[0]!).anim;\n const u = current\n ? stepProgress(steps, timeMs, anim.step ?? 0, {\n delay: anim.delay,\n ms: anim.ms,\n ease: anim.ease,\n })\n : 0;\n const frame = frames.get(id) ?? { attrs: {} };\n if (prop === \"view\") {\n // From where the change before it left the picture.\n const before = current ? list[list.indexOf(current) - 1] : undefined;\n frame.view = { from: before?.anim.view ?? null, to: anim.view!, u };\n } else if (prop === \"along\") {\n const [a, b] = anim.at ?? [0, 1];\n frame.along = { path: anim.along!, at: a + (b - a) * u };\n } else if (prop === \"solo\") {\n frame.solo = anim.solo;\n } else if (prop.startsWith(\"@\")) {\n const [a, b] = anim.attrs![prop.slice(1)]!;\n frame.attrs[prop.slice(1)] = lerpAttr(a, b, u);\n } else if (prop === \"draw\") {\n const [a, b] = anim.draw === true ? [0, 1] : (anim.draw as readonly [number, number]);\n frame.draw = a + (b - a) * u;\n } else if (anim.write !== undefined) {\n frame.text = writtenText(anim.write, u, { scramble: anim.scramble, caret: anim.caret, timeMs });\n } else {\n const [a, b] = anim.count!;\n frame.text = formatCount(a + (b - a) * u, anim);\n }\n frames.set(id, frame);\n }\n return frames;\n}\n\n/**\n * The opening tag of the root element at the start of `markup` (up to its\n * first `>`), cut out without a regular expression, so checks on it stay\n * linear however long or odd the markup is.\n */\nexport function svgOpeningTag(markup: string): string {\n const end = markup.indexOf(\">\");\n return end < 0 ? markup : markup.slice(0, end + 1);\n}\n\n/** Problems with an {@link SvgMotion}, as sentences; none when it can be drawn. */\nexport function svgMotionIssues(motion: unknown): string[] {\n const issues: string[] = [];\n const m = (motion ?? {}) as Partial<SvgMotion>;\n const svg = typeof m.svg === \"string\" ? m.svg.trim() : \"\";\n if (!svg) return [\"`svg` needs the picture's markup: one <svg> element\"];\n if (!/^<svg[\\s>]/i.test(svg) || !svg.toLowerCase().endsWith(\"</svg>\"))\n issues.push(\"`svg` must be one <svg>…</svg> element\");\n if (!/\\sviewBox\\s*=/i.test(svgOpeningTag(svg)))\n issues.push(\"the <svg> needs a `viewBox`, so it scales to where it is placed\");\n if (/<script|<foreignObject|\\son\\w+\\s*=/i.test(svg))\n issues.push(\"`svg` cannot have scripts, event handlers or <foreignObject>\");\n if (/<(animate|animateTransform|animateMotion|set)[\\s/>]/i.test(svg))\n issues.push(\n \"`svg` cannot animate itself (<animate>, <animateTransform>, <animateMotion>, <set>): give changes in `animate`, so every frame is a function of time\",\n );\n if (/(?:href|src)\\s*=\\s*[\"'](?!#|data:image\\/)/i.test(svg))\n issues.push(\"`svg` cannot link outside itself (only #ids and data:image URLs)\");\n const ids = new Set([...svg.matchAll(/\\sid\\s*=\\s*[\"']([^\"']+)[\"']/g)].map((x) => x[1]));\n if (m.animate !== undefined && !Array.isArray(m.animate)) issues.push(\"`animate` must be a list\");\n (Array.isArray(m.animate) ? m.animate : []).forEach((a, i) => {\n const where = `animate[${i}]`;\n if (!a || typeof a !== \"object\") return void issues.push(`${where} is not an animation`);\n if (typeof a.id !== \"string\") {\n if (a.view === undefined) return void issues.push(`${where} needs an \\`id\\``);\n } else if (!ids.has(a.id))\n issues.push(`${where}: there is no element with id \"${a.id}\" in the SVG`);\n if (a.step !== undefined && !(Number.isInteger(a.step) && a.step >= 0))\n issues.push(`${where}: \\`step\\` is a whole number, 0 or more`);\n if (a.ms !== undefined && !(a.ms >= 0)) issues.push(`${where}: \\`ms\\` must be 0 or more`);\n if (a.delay !== undefined && !(a.delay >= 0))\n issues.push(`${where}: \\`delay\\` must be 0 or more`);\n if (a.ease !== undefined && !(a.ease in EASES))\n issues.push(`${where}: \\`ease\\` is one of ${Object.keys(EASES).join(\", \")}`);\n if (!a.attrs && !a.draw && !a.count && a.write === undefined && a.view === undefined && !a.along && a.solo === undefined)\n issues.push(\n `${where} changes nothing: give \\`attrs\\`, \\`draw\\`, \\`count\\`, \\`write\\`, \\`view\\`, \\`along\\` or \\`solo\\``,\n );\n if (a.solo !== undefined && !(Number.isInteger(a.solo) && a.solo >= 0))\n issues.push(`${where}: \\`solo\\` is an index (whole number, 0 or more)`);\n if (a.view !== undefined) {\n const box = a.view as unknown;\n if (typeof box === \"string\") {\n if (!ids.has(box))\n issues.push(`${where}: \\`view\\` frames \"${box}\", which is not an id in the SVG`);\n } else if (\n !Array.isArray(box) ||\n box.length !== 4 ||\n !box.every((n) => Number.isFinite(n)) ||\n !(box[2] > 0 && box[3] > 0)\n )\n issues.push(\n `${where}: \\`view\\` is [x, y, width, height] (width and height above 0) or an element's id`,\n );\n }\n if (a.along !== undefined) {\n if (typeof a.along !== \"string\" || !ids.has(a.along))\n issues.push(`${where}: \\`along\\` is the id of a path in the SVG`);\n if (typeof a.id !== \"string\")\n issues.push(`${where}: \\`along\\` moves an element: give its \\`id\\``);\n }\n if (\n a.at !== undefined &&\n !(Array.isArray(a.at) && a.at.length === 2 && a.at.every((v) => v >= 0 && v <= 1))\n )\n issues.push(`${where}: \\`at\\` is [from, to] between 0 and 1`);\n for (const [name, pair] of Object.entries(a.attrs ?? {}))\n if (!Array.isArray(pair) || pair.length !== 2)\n issues.push(`${where}: \\`attrs.${name}\\` is [from, to]`);\n if (Array.isArray(a.draw) && a.draw.some((v) => !(v >= 0 && v <= 1)))\n issues.push(`${where}: \\`draw\\` is true or [from, to] between 0 and 1`);\n if (a.count !== undefined && !(Array.isArray(a.count) && a.count.length === 2))\n issues.push(`${where}: \\`count\\` is [from, to]`);\n if (a.write !== undefined && typeof a.write !== \"string\")\n issues.push(`${where}: \\`write\\` is the text to write`);\n if ((a.scramble !== undefined || a.caret !== undefined) && a.write === undefined)\n issues.push(`${where}: \\`scramble\\` and \\`caret\\` go with \\`write\\``);\n });\n return issues;\n}\n"],"mappings":";AAsBA,IAAM,cAAc;AAEpB,IAAM,QAAQ;AAGd,IAAM,OAA+B,EAAE,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,EAAE;AAMlG,SAAS,QAAQ,GAAmB;AAClC,QAAM,QAAQ,EAAE,QAAQ,OAAO,EAAE,EAAE,QAAQ,WAAW,EAAE;AACxD,MAAI,MAAO,OAAM,IAAI,MAAM,IAAI,MAAM,CAAC,CAAC,yBAAyB;AAChE,QAAM,SAAS,EAAE,MAAM,KAAK,KAAK,CAAC;AAClC,QAAM,QAAgB,CAAC;AAEvB,MAAI,OAAO;AACX,MAAI,IAAI;AACR,MAAI,IAAI;AACR,MAAI,SAAS;AACb,MAAI,SAAS;AAEb,MAAI,KAAK;AACT,MAAI,KAAK;AACT,MAAI,OAAO;AACX,MAAI,IAAI;AACR,MAAI,UAAU;AACd,QAAM,MAAM,CAAC,IAAY,OAAe,KAAM,OAAO,KAAK,CAAC,IAAI,EAAE,CAAC;AAClE,QAAM,QAAQ,CAAC,IAAY,OAAe;AACxC,QAAI,QAAQ,KAAK,OAAO,OAAQ,OAAM,KAAK,IAAI;AAC/C,WAAO,EAAE,QAAQ,CAAC,CAAC,IAAI,EAAE,CAAC,GAAG,QAAQ,MAAM;AAAA,EAC7C;AACA,SAAO,IAAI,OAAO,QAAQ;AACxB,QAAI,SAAS,KAAK,OAAO,CAAC,CAAE,EAAG,WAAU,OAAO,GAAG;AAAA,aAC1C,CAAC,QAAS,OAAM,IAAI,MAAM,IAAI,OAAO,CAAC,CAAC,+CAA0C;AAC1F,UAAM,QAAQ,QAAQ,YAAY;AAClC,QAAI,EAAE,SAAS,MAAO,OAAM,IAAI,MAAM,yBAAyB,OAAO,GAAG;AACzE,UAAM,MAAM,YAAY,QAAQ,YAAY;AAC5C,UAAM,IAAI,KAAK,KAAK;AACpB,UAAM,OAAO,OAAO,MAAM,GAAG,IAAI,CAAC,EAAE,IAAI,MAAM;AAC9C,QAAI,KAAK,SAAS,KAAK,KAAK,KAAK,CAAC,MAAM,OAAO,MAAM,CAAC,CAAC,EAAG;AAC1D,SAAK;AACL,UAAM,KAAK,MAAM,IAAI;AACrB,UAAM,KAAK,MAAM,IAAI;AACrB,QAAI,UAAU,KAAK;AACjB,UAAI,MAAM;AACR,aAAK,SAAS;AACd,cAAM,KAAK,IAAI;AACf,eAAO;AAAA,MACT;AACA,UAAI;AACJ,UAAI;AACJ,aAAO;AAEP,gBAAU;AACV;AAAA,IACF;AACA,QAAI,CAAC,KAAM,OAAM,GAAG,CAAC;AACrB,YAAQ,OAAO;AAAA,MACb,KAAK;AACH,YAAI,KAAK,KAAK,CAAC;AACf,YAAI,KAAK,KAAK,CAAC;AACf,iBAAS;AACT,iBAAS;AACT,cAAM,GAAG,CAAC;AAEV,kBAAU,MAAM,MAAM;AACtB;AAAA,MACF,KAAK;AACH,YAAI,KAAK,KAAK,CAAC;AACf,YAAI,KAAK,KAAK,CAAC;AACf,YAAI,GAAG,CAAC;AACR;AAAA,MACF,KAAK;AACH,YAAI,KAAK,KAAK,CAAC;AACf,YAAI,GAAG,CAAC;AACR;AAAA,MACF,KAAK;AACH,aAAK,MAAM,IAAI,KAAK,KAAK,CAAC;AAC1B,YAAI,GAAG,CAAC;AACR;AAAA,MACF,KAAK;AAAA,MACL,KAAK,KAAK;AACR,YAAI;AACJ,YAAI;AACJ,YAAI;AACJ,YAAI,UAAU,KAAK;AACjB,eAAK,KAAK,KAAK,CAAC;AAChB,eAAK,KAAK,KAAK,CAAC;AAChB,iBAAO,KAAK,MAAM,CAAC;AAAA,QACrB,OAAO;AACL,gBAAM,SAAS,SAAS,OAAO,SAAS;AACxC,eAAK,SAAS,IAAI,IAAI,KAAK;AAC3B,eAAK,SAAS,IAAI,IAAI,KAAK;AAC3B,iBAAO;AAAA,QACT;AACA,cAAM,KAAK,KAAK,KAAK,CAAC;AACtB,cAAM,KAAK,KAAK,KAAK,CAAC;AACtB,cAAM,KAAK,KAAK,KAAK,CAAC;AACtB,cAAM,KAAK,KAAK,KAAK,CAAC;AACtB,iBAAS,IAAI,GAAG,KAAK,aAAa,KAAK;AACrC,gBAAM,IAAI,IAAI;AACd,gBAAM,IAAI,IAAI;AACd;AAAA,YACE,IAAI,IAAI,IAAI,IAAI,IAAI,IAAI,IAAI,IAAI,KAAK,IAAI,IAAI,IAAI,IAAI,KAAK,IAAI,IAAI,IAAI;AAAA,YACtE,IAAI,IAAI,IAAI,IAAI,IAAI,IAAI,IAAI,IAAI,KAAK,IAAI,IAAI,IAAI,IAAI,KAAK,IAAI,IAAI,IAAI;AAAA,UACxE;AAAA,QACF;AACA,aAAK;AACL,aAAK;AACL,YAAI;AACJ,YAAI;AACJ;AAAA,MACF;AAAA,MACA,KAAK;AAAA,MACL,KAAK,KAAK;AACR,YAAI;AACJ,YAAI;AACJ,YAAI;AACJ,YAAI;AACJ,YAAI,UAAU,KAAK;AACjB,eAAK,KAAK,KAAK,CAAC;AAChB,eAAK,KAAK,KAAK,CAAC;AAChB,eAAK,KAAK,KAAK,CAAC;AAChB,eAAK,KAAK,KAAK,CAAC;AAAA,QAClB,OAAO;AACL,gBAAM,SAAS,SAAS,OAAO,SAAS;AACxC,eAAK,SAAS,IAAI,IAAI,KAAK;AAC3B,eAAK,SAAS,IAAI,IAAI,KAAK;AAC3B,eAAK,KAAK,KAAK,CAAC;AAChB,eAAK,KAAK,KAAK,CAAC;AAAA,QAClB;AACA,iBAAS,IAAI,GAAG,KAAK,aAAa,KAAK;AACrC,gBAAM,IAAI,IAAI;AACd,gBAAM,IAAI,IAAI;AACd,cAAI,IAAI,IAAI,IAAI,IAAI,IAAI,IAAI,KAAK,IAAI,IAAI,IAAI,IAAI,IAAI,IAAI,IAAI,IAAI,IAAI,KAAK,IAAI,IAAI,EAAE;AAAA,QACtF;AACA,aAAK;AACL,aAAK;AACL,YAAI;AACJ,YAAI;AACJ;AAAA,MACF;AAAA,MACA,KAAK,KAAK;AACR,cAAM,KAAK,KAAK,KAAK,CAAC;AACtB,cAAM,KAAK,KAAK,KAAK,CAAC;AACtB,mBAAW,KAAK,UAAU,GAAG,GAAG,KAAK,CAAC,GAAI,KAAK,CAAC,GAAI,KAAK,CAAC,GAAI,KAAK,CAAC,MAAO,GAAG,KAAK,CAAC,MAAO,GAAG,IAAI,EAAE,EAAG,KAAI,EAAE,CAAC,GAAG,EAAE,CAAC,CAAC;AACrH,YAAI;AACJ,YAAI;AACJ;AAAA,MACF;AAAA,IACF;AACA,WAAO;AAAA,EACT;AACA,MAAI,QAAQ,KAAK,OAAO,OAAQ,OAAM,KAAK,IAAI;AAC/C,SAAO,MACJ,IAAI,CAAC,MAAM;AAEV,UAAM,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,OAAO,CAAC,GAAI,EAAE,OAAO,EAAE,OAAO,SAAS,CAAC,CAAE;AAC5D,UAAM,SAAS,EAAE,OAAO,SAAS,KAAK,KAAK,MAAM,EAAE,CAAC,IAAI,EAAE,CAAC,GAAG,EAAE,CAAC,IAAI,EAAE,CAAC,CAAC,IAAI;AAC7E,WAAO,EAAE,QAAQ,SAAS,EAAE,OAAO,MAAM,GAAG,EAAE,IAAI,EAAE,QAAQ,QAAQ,EAAE,UAAU,OAAO;AAAA,EACzF,CAAC,EACA,OAAO,CAAC,MAAM,EAAE,OAAO,SAAS,CAAC;AACtC;AAGA,SAAS,UACP,IACA,IACA,IACA,IACA,OACA,OACA,OACA,IACA,IACS;AACT,OAAK,KAAK,IAAI,EAAE;AAChB,OAAK,KAAK,IAAI,EAAE;AAChB,MAAI,CAAC,MAAM,CAAC,MAAO,OAAO,MAAM,OAAO,GAAK,QAAO,CAAC,CAAC,IAAI,EAAE,CAAC;AAC5D,QAAM,MAAO,QAAQ,KAAK,KAAM;AAChC,QAAM,MAAM,KAAK,IAAI,GAAG;AACxB,QAAM,MAAM,KAAK,IAAI,GAAG;AACxB,QAAM,MAAM,KAAK,MAAM;AACvB,QAAM,MAAM,KAAK,MAAM;AACvB,QAAM,MAAM,MAAM,KAAK,MAAM;AAC7B,QAAM,MAAM,CAAC,MAAM,KAAK,MAAM;AAE9B,QAAM,SAAU,MAAM,OAAQ,KAAK,MAAO,MAAM,OAAQ,KAAK;AAC7D,MAAI,SAAS,GAAG;AACd,UAAM,KAAK,KAAK,MAAM;AACtB,UAAM,KAAK,KAAK,MAAM;AAAA,EACxB;AACA,QAAM,MAAM,KAAK,KAAK,KAAK,KAAK,KAAK,KAAK,MAAM,MAAM,KAAK,KAAK,MAAM;AACtE,QAAM,MAAM,KAAK,KAAK,MAAM,MAAM,KAAK,KAAK,MAAM;AAClD,QAAM,KAAK,UAAU,QAAQ,KAAK,KAAK,KAAK,KAAK,KAAK,IAAI,GAAG,MAAM,GAAG,CAAC;AACvE,QAAM,MAAO,IAAI,KAAK,MAAO;AAC7B,QAAM,MAAO,CAAC,IAAI,KAAK,MAAO;AAC9B,QAAM,KAAK,MAAM,MAAM,MAAM,OAAO,KAAK,MAAM;AAC/C,QAAM,KAAK,MAAM,MAAM,MAAM,OAAO,KAAK,MAAM;AAC/C,QAAM,QAAQ,CAAC,IAAY,IAAY,IAAY,OACjD,KAAK,MAAM,KAAK,KAAK,KAAK,IAAI,KAAK,KAAK,KAAK,EAAE;AACjD,QAAM,QAAQ,MAAM,GAAG,IAAI,MAAM,OAAO,KAAK,MAAM,OAAO,EAAE;AAC5D,MAAI,QAAQ,OAAO,MAAM,OAAO,KAAK,MAAM,OAAO,KAAK,CAAC,MAAM,OAAO,KAAK,CAAC,MAAM,OAAO,EAAE;AAC1F,MAAI,CAAC,SAAS,QAAQ,EAAG,UAAS,IAAI,KAAK;AAC3C,MAAI,SAAS,QAAQ,EAAG,UAAS,IAAI,KAAK;AAC1C,QAAM,QAAQ,KAAK,IAAI,GAAG,KAAK,KAAM,KAAK,IAAI,KAAK,KAAK,KAAK,KAAK,MAAO,cAAc,EAAE,CAAC;AAC1F,QAAM,MAAe,CAAC;AACtB,WAAS,IAAI,GAAG,KAAK,OAAO,KAAK;AAC/B,UAAM,IAAI,QAAS,QAAQ,IAAK;AAChC,UAAM,KAAK,KAAK,KAAK,IAAI,CAAC;AAC1B,UAAM,KAAK,KAAK,KAAK,IAAI,CAAC;AAC1B,QAAI,KAAK,CAAC,MAAM,KAAK,MAAM,KAAK,IAAI,MAAM,KAAK,MAAM,KAAK,EAAE,CAAC;AAAA,EAC/D;AACA,MAAI,IAAI,SAAS,CAAC,IAAI,CAAC,IAAI,EAAE;AAC7B,SAAO;AACT;AAOA,SAAS,SAAS,MAAY,GAAoB;AAChD,QAAM,MAAM,KAAK,SAAS,CAAC,GAAG,KAAK,QAAQ,KAAK,OAAO,CAAC,CAAE,IAAI,CAAC,GAAG,KAAK,QAAQ,GAAG,KAAK,OAAO,MAAM,GAAG,EAAE,EAAE,QAAQ,CAAC;AACpH,QAAM,UAAU,CAAC,CAAC;AAClB,WAAS,IAAI,GAAG,IAAI,IAAI,QAAQ;AAC9B,YAAQ,KAAK,QAAQ,IAAI,CAAC,IAAK,KAAK,MAAM,IAAI,CAAC,EAAG,CAAC,IAAI,IAAI,IAAI,CAAC,EAAG,CAAC,GAAG,IAAI,CAAC,EAAG,CAAC,IAAI,IAAI,IAAI,CAAC,EAAG,CAAC,CAAC,CAAC;AACrG,QAAM,QAAQ,QAAQ,QAAQ,SAAS,CAAC;AACxC,MAAI,UAAU,EAAG,QAAO,MAAM,KAAK,EAAE,QAAQ,EAAE,GAAG,MAAM,CAAC,IAAI,CAAC,EAAG,CAAC,GAAG,IAAI,CAAC,EAAG,CAAC,CAAC,CAAU;AACzF,QAAM,MAAe,CAAC;AACtB,MAAI,IAAI;AACR,WAAS,IAAI,GAAG,IAAI,GAAG,KAAK;AAC1B,UAAM,KAAM,IAAI,IAAK;AACrB,WAAO,IAAI,QAAQ,SAAS,KAAK,QAAQ,CAAC,IAAK,GAAI;AACnD,UAAM,MAAM,QAAQ,CAAC,IAAK,QAAQ,IAAI,CAAC;AACvC,UAAM,IAAI,MAAM,KAAK,KAAK,QAAQ,IAAI,CAAC,KAAM,MAAM;AACnD,UAAM,IAAI,IAAI,IAAI,CAAC;AACnB,UAAM,IAAI,IAAI,CAAC;AACf,QAAI,KAAK,CAAC,EAAE,CAAC,KAAK,EAAE,CAAC,IAAI,EAAE,CAAC,KAAK,GAAG,EAAE,CAAC,KAAK,EAAE,CAAC,IAAI,EAAE,CAAC,KAAK,CAAC,CAAC;AAAA,EAC/D;AACA,SAAO;AACT;AAEA,IAAM,aAAa,CAAC,QAAiB;AACnC,MAAI,MAAM;AACV,WAAS,IAAI,GAAG,IAAI,IAAI,QAAQ,KAAK;AACnC,UAAM,IAAI,IAAI,CAAC;AACf,UAAM,IAAI,KAAK,IAAI,KAAK,IAAI,MAAM;AAClC,WAAO,EAAE,CAAC,IAAI,EAAE,CAAC,IAAI,EAAE,CAAC,IAAI,EAAE,CAAC;AAAA,EACjC;AACA,SAAO,MAAM;AACf;AAEA,IAAM,WAAW,CAAC,QAAwB;AACxC,MAAI,IAAI;AACR,MAAI,IAAI;AACR,aAAW,KAAK,KAAK;AACnB,SAAK,EAAE,CAAC;AACR,SAAK,EAAE,CAAC;AAAA,EACV;AACA,SAAO,CAAC,IAAI,IAAI,QAAQ,IAAI,IAAI,MAAM;AACxC;AAGA,SAAS,KAAK,MAAY,KAAsB;AAC9C,QAAM,OAAO,KAAK,IAAI,WAAW,GAAG,CAAC;AACrC,MAAI,KAAK,UAAU,OAAO,EAAG,QAAO;AACpC,MAAI,SAAS;AACb,WAAS,IAAI,GAAG,IAAI,KAAK,OAAO,QAAQ;AACtC,cAAU,KAAK,MAAM,KAAK,OAAO,CAAC,EAAG,CAAC,IAAI,KAAK,OAAO,IAAI,CAAC,EAAG,CAAC,GAAG,KAAK,OAAO,CAAC,EAAG,CAAC,IAAI,KAAK,OAAO,IAAI,CAAC,EAAG,CAAC,CAAC;AAC/G,SAAO;AACT;AAaA,SAAS,OAAO,QAA0B,QAAiB,OAAiC;AAC1F,QAAM,MAAwB,OAAO,IAAI,MAAM,IAAI;AACnD,QAAM,QAAyD,CAAC;AAChE,SAAO,QAAQ,CAAC,MAAM,MAAM;AAC1B,QAAI,CAAC,KAAM;AACX,WAAO,QAAQ,CAAC,GAAG,MAAM;AACvB,YAAM,WAAW,KAAK,MAAM,KAAK,OAAO,CAAC,IAAI,EAAE,OAAO,CAAC,GAAG,KAAK,OAAO,CAAC,IAAI,EAAE,OAAO,CAAC,CAAC,IAAI;AAC1F,YAAM,WAAW,KAAK,IAAI,KAAK,KAAK,KAAK,OAAO,SAAS,EAAE,OAAO,KAAK,CAAC;AACxE,YAAM,KAAK,EAAE,MAAM,GAAG,OAAO,GAAG,MAAM,WAAW,MAAM,SAAS,CAAC;AAAA,IACnE,CAAC;AAAA,EACH,CAAC;AACD,QAAM,KAAK,CAAC,GAAG,MAAM,EAAE,OAAO,EAAE,IAAI;AACpC,QAAM,OAAO,oBAAI,IAAY;AAC7B,aAAW,EAAE,MAAM,MAAM,KAAK,OAAO;AACnC,QAAI,IAAI,IAAI,KAAK,KAAK,IAAI,KAAK,EAAG;AAClC,QAAI,IAAI,IAAI,OAAO,KAAK;AACxB,SAAK,IAAI,KAAK;AAAA,EAChB;AACA,MAAI,OAAO;AACX,SAAO,QAAQ,CAAC,GAAG,MAAM;AACvB,QAAI,KAAK,IAAI,CAAC,EAAG;AACjB,WAAO,IAAI,IAAI,KAAK,OAAO,IAAI,EAAG;AAClC,QAAI,IAAI,IAAI;AAAA,EACd,CAAC;AACD,SAAO;AACT;AAGA,SAAS,MAAM,KAAc,KAAuB;AAClD,QAAM,IAAI,IAAI;AACd,MAAI,OAAO;AACX,MAAI,WAAW;AACf,aAAW,aAAa,CAAC,KAAK,CAAC,GAAG,GAAG,EAAE,QAAQ,CAAC,GAAG;AACjD,aAAS,QAAQ,GAAG,QAAQ,GAAG,SAAS;AACtC,UAAI,OAAO;AACX,eAAS,IAAI,GAAG,IAAI,KAAK,OAAO,UAAU,KAAK;AAC7C,cAAM,IAAI,IAAI,CAAC;AACf,cAAM,IAAI,WAAW,IAAI,SAAS,CAAC;AACnC,iBAAS,EAAE,CAAC,IAAI,EAAE,CAAC,MAAM,KAAK,EAAE,CAAC,IAAI,EAAE,CAAC,MAAM;AAAA,MAChD;AACA,UAAI,OAAO,UAAU;AACnB,mBAAW;AACX,eAAO,UAAU,MAAM,KAAK,EAAE,OAAO,UAAU,MAAM,GAAG,KAAK,CAAC;AAAA,MAChE;AAAA,IACF;AAAA,EACF;AACA,SAAO;AACT;AAWO,SAAS,cAAc,OAA0B,UAAwB,CAAC,GAAa;AAC5F,QAAM,IAAI,KAAK,IAAI,GAAG,KAAK,MAAM,QAAQ,UAAU,EAAE,CAAC;AACtD,QAAM,WAAW,QAAQ,YAAY;AACrC,QAAM,SAAS,MAAM,IAAI,CAAC,GAAG,MAAM;AACjC,QAAI;AACJ,QAAI;AACF,cAAQ,QAAQ,CAAC;AAAA,IACnB,SAAS,GAAG;AACV,YAAM,IAAI,MAAM,QAAQ,IAAI,CAAC,oBAAqB,EAAY,OAAO,EAAE;AAAA,IACzE;AACA,QAAI,CAAC,MAAM,OAAQ,OAAM,IAAI,MAAM,QAAQ,IAAI,CAAC,6CAA6C;AAC7F,WAAO,MAAM,IAAI,CAAC,MAAa;AAC7B,YAAM,MAAM,SAAS,GAAG,CAAC;AACzB,aAAO,EAAE,KAAK,QAAQ,SAAS,GAAG,GAAG,MAAM,KAAK,GAAG,GAAG,EAAE;AAAA,IAC1D,CAAC;AAAA,EACH,CAAC;AACD,MAAI,CAAC,OAAO,OAAQ,QAAO,CAAC;AAC5B,QAAM,QAAQ,KAAK,IAAI,GAAG,OAAO,IAAI,CAAC,MAAM,EAAE,MAAM,CAAC;AAErD,QAAM,KAAK,OAAO,KAAK,EAAE,QAAQ,CAAC,MAAM,EAAE,IAAI,IAAI,CAAC,MAAM,EAAE,CAAC,CAAC,CAAC;AAC9D,QAAM,KAAK,OAAO,KAAK,EAAE,QAAQ,CAAC,MAAM,EAAE,IAAI,IAAI,CAAC,MAAM,EAAE,CAAC,CAAC,CAAC;AAC9D,QAAM,QAAQ,KAAK,IAAI,MAAM,KAAK,IAAI,GAAG,EAAE,IAAI,KAAK,IAAI,GAAG,EAAE,GAAG,KAAK,IAAI,GAAG,EAAE,IAAI,KAAK,IAAI,GAAG,EAAE,CAAC;AAEjG,QAAM,QAAQ,CAAC,GAAG,OAAO,CAAC,CAAE,EAAE,KAAK,CAAC,GAAG,MAAM,EAAE,OAAO,EAAE,IAAI;AAC5D,QAAM,WAA+B,CAAC,CAAC,GAAG,OAAO,GAAG,MAAY,QAAQ,MAAM,MAAM,EAAE,KAAK,IAAI,CAAC,CAAC;AACjG,WAAS,IAAI,GAAG,IAAI,OAAO,QAAQ,IAAK,UAAS,KAAK,OAAO,SAAS,IAAI,CAAC,GAAI,OAAO,CAAC,GAAI,KAAK,CAAC;AAEjG,QAAM,WAAW,SAAS;AAAA,IAAI,CAAC,OAAO,MACpC,MAAM,IAAI,CAAC,OAAO,MAAe;AAC/B,UAAI,MAAO,QAAO,MAAM;AACxB,eAAS,IAAI,GAAG,IAAI,OAAO,QAAQ,KAAK;AACtC,cAAM,OAAO,UAAU,IAAI,KAAK,OAAO,MAAM,EAAG,CAAC,KAAK,UAAU,IAAI,IAAI,OAAO,UAAU,OAAO,MAAM,EAAG,CAAC;AAC1G,YAAI,KAAM,QAAO,MAAM,KAAK,EAAE,QAAQ,EAAE,GAAG,MAAM,CAAC,KAAK,OAAO,CAAC,GAAG,KAAK,OAAO,CAAC,CAAC,CAAU;AAAA,MAC5F;AACA,aAAO,MAAM,KAAK,EAAE,QAAQ,EAAE,GAAG,MAAM,CAAC,GAAG,CAAC,CAAU;AAAA,IACxD,CAAC;AAAA,EACH;AACA,WAAS,IAAI,GAAG,IAAI,SAAS,QAAQ;AACnC,aAAS,CAAC,IAAI,SAAS,CAAC,EAAG,IAAI,CAAC,KAAK,MAAM,MAAM,SAAS,IAAI,CAAC,EAAG,CAAC,GAAI,GAAG,CAAC;AAC7E,QAAM,MAAM,CAAC,MAAc;AACzB,UAAM,IAAI,OAAO,EAAE,QAAQ,QAAQ,CAAC;AACpC,WAAO,OAAO,OAAO,GAAG,GAAG,EAAE,IAAI,IAAI,CAAC;AAAA,EACxC;AACA,SAAO,SAAS;AAAA,IAAI,CAAC,UACnB,MAAM,IAAI,CAAC,QAAQ,IAAI,IAAI,IAAI,CAAC,MAAM,GAAG,IAAI,EAAE,CAAC,CAAC,CAAC,IAAI,IAAI,EAAE,CAAC,CAAC,CAAC,EAAE,EAAE,KAAK,IAAI,CAAC,IAAI,EAAE,KAAK,GAAG;AAAA,EAC7F;AACF;AAMO,SAAS,WAAW,MAAc,IAAY,UAAwB,CAAC,GAAqB;AACjG,QAAM,CAAC,GAAG,CAAC,IAAI,cAAc,CAAC,MAAM,EAAE,GAAG,OAAO;AAChD,SAAO,CAAC,GAAI,CAAE;AAChB;AAOO,SAAS,YAAY,GAAW,IAA0C;AAC/E,MAAI;AACJ,MAAI;AACF,YAAQ,QAAQ,CAAC;AAAA,EACnB,QAAQ;AACN,WAAO;AAAA,EACT;AACA,QAAM,QAAkC,CAAC;AACzC,aAAW,QAAQ,OAAO;AACxB,UAAM,MAAM,KAAK,SAAS,CAAC,GAAG,KAAK,QAAQ,KAAK,OAAO,CAAC,CAAE,IAAI,KAAK;AACnE,aAAS,IAAI,GAAG,IAAI,IAAI,QAAQ;AAC9B,YAAM,KAAK,CAAC,IAAI,IAAI,CAAC,GAAI,IAAI,CAAC,GAAI,KAAK,MAAM,IAAI,CAAC,EAAG,CAAC,IAAI,IAAI,IAAI,CAAC,EAAG,CAAC,GAAG,IAAI,CAAC,EAAG,CAAC,IAAI,IAAI,IAAI,CAAC,EAAG,CAAC,CAAC,CAAC,CAAC;AAAA,EAC3G;AACA,QAAM,QAAQ,MAAM,CAAC,GAAG,OAAO,CAAC;AAChC,MAAI,CAAC,MAAO,QAAO;AACnB,MAAI,OAAO,KAAK,IAAI,KAAK,IAAI,IAAI,CAAC,GAAG,CAAC,IAAI,MAAM,OAAO,CAAC,KAAK,MAAM,MAAM,EAAE,CAAC,GAAG,CAAC;AAChF,aAAW,CAAC,GAAG,GAAG,MAAM,KAAK,OAAO;AAClC,QAAI,QAAQ,UAAU,SAAS,EAAG,QAAO,CAAC,EAAE,CAAC,KAAM,EAAE,CAAC,IAAI,EAAE,CAAC,KAAK,OAAQ,QAAQ,EAAE,CAAC,KAAM,EAAE,CAAC,IAAI,EAAE,CAAC,KAAK,OAAQ,MAAM;AACxH,YAAQ;AAAA,EACV;AACA,QAAM,OAAO,MAAM,MAAM,SAAS,CAAC;AACnC,SAAO,OAAO,CAAC,KAAK,CAAC,EAAE,CAAC,GAAG,KAAK,CAAC,EAAE,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,GAAG,MAAM,CAAC,CAAC;AAC9D;;;AC1bO,IAAM,QAAQ;AAAA,EACnB,QAAQ,CAAC,MAAc;AAAA,EACvB,UAAU,CAAC,MAAe,IAAI,MAAM,IAAI,IAAI,IAAI,IAAI,KAAK,KAAK,IAAI,MAAM,IAAI;AAAA,EAC5E,KAAK,CAAC,MAAc,KAAK,IAAI,MAAM;AACrC;AAKO,IAAM,UAAU;AAEvB,IAAM,UAAU,CAAC,MAAe,IAAI,IAAI,IAAI,IAAI,IAAI,IAAI;AAMjD,SAAS,UAAU,OAA0B,MAAkC;AACpF,MAAI,QAAQ,EAAG,QAAO;AACtB,SAAO,MAAM,OAAO,CAAC;AACvB;AAMO,SAAS,aACd,OACA,QACA,MACA,UAA4D,CAAC,GACrD;AACR,QAAM,QAAQ,UAAU,OAAO,IAAI;AACnC,MAAI,UAAU,OAAW,QAAO;AAChC,QAAM,OAAO,SAAS,QAAQ,SAAS;AACvC,QAAM,KAAK,QAAQ,MAAM;AACzB,QAAM,IAAI,KAAK,IAAI,SAAS,SAAS,QAAQ,EAAE,IAAI,UAAU,OAAO,IAAI;AACxE,SAAO,MAAM,QAAQ,QAAQ,QAAQ,EAAE,CAAC;AAC1C;AASO,IAAM,iBAA0B,CAAC,MAAM,UAAU;AACtD,MAAI,QAAQ,OAAO,SAAS,UAAU;AACpC,UAAM,IAAI;AACV,QAAI,EAAE,WAAW,UAAa,EAAE,WAAW;AACzC,aAAO,GAAG,OAAO,EAAE,MAAM,CAAC,SAAI,OAAO,EAAE,MAAM,CAAC;AAChD,eAAW,KAAK,CAAC,MAAM,OAAO,QAAQ,OAAO;AAC3C,UAAI,OAAO,EAAE,CAAC,MAAM,YAAY,OAAO,EAAE,CAAC,MAAM,SAAU,QAAO,OAAO,EAAE,CAAC,CAAC;AAAA,EAChF;AACA,SAAO,OAAO,KAAK;AACrB;AAGA,SAAS,OAAO,OAAgB,GAAoB;AAClD,MAAI,OAAO,UAAU,SAAU,QAAO,QAAQ;AAC9C,MAAI,MAAM,QAAQ,KAAK,EAAG,QAAO,MAAM,IAAI,CAAC,MAAM,OAAO,GAAG,CAAC,CAAC;AAC9D,MAAI,SAAS,OAAO,UAAU;AAC5B,WAAO,OAAO,YAAY,OAAO,QAAQ,KAAK,EAAE,IAAI,CAAC,CAAC,KAAK,CAAC,MAAM,CAAC,KAAK,OAAO,GAAG,CAAC,CAAC,CAAC,CAAC;AACxF,SAAO;AACT;AASO,SAAS,SAAY,GAAM,GAAM,GAAW,QAAiB,gBAAmB;AACrF,MAAI,KAAK,EAAG,QAAO;AACnB,MAAI,KAAK,EAAG,QAAO;AACnB,SAAO,MAAM,GAAG,GAAG,GAAG,KAAK;AAC7B;AAEA,SAAS,MAAM,GAAY,GAAY,GAAW,OAAyB;AACzE,MAAI,OAAO,MAAM,YAAY,OAAO,MAAM,SAAU,QAAO,KAAK,IAAI,KAAK;AACzE,MAAI,MAAM,QAAQ,CAAC,KAAK,MAAM,QAAQ,CAAC,GAAG;AACxC,UAAM,SAAS,IAAI,IAAI,EAAE,IAAI,CAAC,MAAM,MAAM,CAAC,MAAM,MAAM,CAAC,GAAG,IAAI,CAAC,CAAC;AACjE,UAAM,QAAQ,IAAI,IAAI,EAAE,IAAI,CAAC,MAAM,MAAM,MAAM,MAAM,CAAC,CAAC,CAAC;AACxD,UAAM,MAAiB,EAAE,IAAI,CAAC,MAAM,MAAM;AACxC,YAAM,MAAM,MAAM,MAAM,CAAC;AACzB,aAAO,OAAO,IAAI,GAAG,IAAI,MAAM,OAAO,IAAI,GAAG,GAAG,MAAM,GAAG,KAAK,IAAI,OAAO,MAAM,CAAC;AAAA,IAClF,CAAC;AACD,MAAE,QAAQ,CAAC,MAAM,MAAM;AACrB,UAAI,CAAC,MAAM,IAAI,MAAM,MAAM,CAAC,CAAC,EAAG,KAAI,KAAK,OAAO,MAAM,IAAI,CAAC,CAAC;AAAA,IAC9D,CAAC;AACD,WAAO;AAAA,EACT;AACA,MAAI,KAAK,KAAK,OAAO,MAAM,YAAY,OAAO,MAAM,UAAU;AAC5D,UAAM,KAAK;AACX,UAAM,KAAK;AACX,WAAO,OAAO;AAAA,MACZ,CAAC,GAAG,oBAAI,IAAI,CAAC,GAAG,OAAO,KAAK,EAAE,GAAG,GAAG,OAAO,KAAK,EAAE,CAAC,CAAC,CAAC,EAAE,IAAI,CAAC,MAAM;AAAA,QAChE;AAAA,QACA,KAAK,MAAM,KAAK,KACZ,MAAM,GAAG,CAAC,GAAG,GAAG,CAAC,GAAG,GAAG,KAAK,IAC5B,KAAK,KACH,OAAO,GAAG,CAAC,GAAG,CAAC,IACf,OAAO,GAAG,CAAC,GAAG,IAAI,CAAC;AAAA,MAC3B,CAAC;AAAA,IACH;AAAA,EACF;AACA,SAAO,IAAI,MAAM,IAAI;AACvB;AAOO,SAAS,SACd,QACA,OACA,QACA,UAA6D,CAAC,GAC3D;AACH,QAAM,OAAO,KAAK,IAAI,MAAM,QAAQ,OAAO,SAAS,CAAC;AACrD,QAAM,KAAK,OAAO,IAAI;AACtB,MAAI,SAAS,EAAG,QAAO;AACvB,QAAM,IAAI,aAAa,OAAO,QAAQ,MAAM,OAAO;AACnD,SAAO,SAAS,OAAO,OAAO,CAAC,GAAI,IAAI,GAAG,QAAQ,KAAK;AACzD;AA8EO,IAAM,cAAc;AAQpB,SAAS,YACd,MACA,GACA,UAAkE,CAAC,GAC3D;AACR,QAAM,UAAU,MAAM,KAAK,IAAI;AAC/B,QAAM,QAAQ,KAAK,MAAM,QAAQ,CAAC,IAAI,QAAQ,MAAM;AACpD,MAAI,MAAM,QAAQ,MAAM,GAAG,KAAK,EAAE,KAAK,EAAE;AACzC,QAAM,OAAO,MAAM,KAAK,QAAQ,YAAY,EAAE;AAC9C,MAAI,KAAK,QAAQ;AACf,UAAM,OAAO,KAAK,OAAO,QAAQ,UAAU,KAAK,WAAW;AAC3D,aAAS,IAAI,OAAO,IAAI,QAAQ,QAAQ;AACtC,aAAO,KAAK,KAAK,QAAQ,CAAC,CAAE,IAAI,QAAQ,CAAC,IAAI,KAAK,KAAK,MAAM,MAAM,GAAG,IAAI,IAAI,KAAK,MAAM,CAAC;AAAA,EAC9F;AACA,SAAO,QAAQ,QAAQ,UAAU,QAAQ,QAAQ,MAAM,QAAQ,QAAQ;AACzE;AAGA,SAAS,MAAM,GAAW,MAAsB;AAC9C,QAAM,IAAI,KAAK,IAAI,IAAI,QAAQ,OAAO,KAAK,IAAI;AAC/C,SAAO,IAAI,KAAK,MAAM,CAAC;AACzB;AAoBO,IAAM,cAAc;AAE3B,IAAM,SAAS;AACf,IAAM,MAAM;AAEZ,SAAS,IAAI,KAAuC;AAClD,MAAI,IAAI,IAAI,MAAM,CAAC;AACnB,MAAI,EAAE,WAAW,EAAG,KAAI,CAAC,GAAG,CAAC,EAAE,IAAI,CAAC,MAAM,IAAI,CAAC,EAAE,KAAK,EAAE;AACxD,SAAO,CAAC,GAAG,GAAG,CAAC,EAAE,IAAI,CAAC,MAAM,SAAS,EAAE,MAAM,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;AAC7D;AAEA,IAAM,QAAQ,CAAC,MAAc,KAAK,MAAM,IAAI,GAAI,IAAI;AAG7C,SAAS,SAAS,GAAoB,GAAoB,GAAmB;AAClF,MAAI,OAAO,MAAM,YAAY,OAAO,MAAM,SAAU,QAAO,OAAO,MAAM,KAAK,IAAI,KAAK,CAAC,CAAC;AACxF,QAAM,KAAK,OAAO,CAAC;AACnB,QAAM,KAAK,OAAO,CAAC;AACnB,MAAI,IAAI,KAAK,EAAE,KAAK,IAAI,KAAK,EAAE,GAAG;AAChC,UAAM,CAAC,IAAI,EAAE,IAAI,CAAC,IAAI,EAAE,GAAG,IAAI,EAAE,CAAC;AAClC,WAAO,IAAI,GACR;AAAA,MAAI,CAAC,GAAG,MACP,KAAK,MAAM,KAAK,GAAG,CAAC,IAAK,KAAK,CAAC,EAC5B,SAAS,EAAE,EACX,SAAS,GAAG,GAAG;AAAA,IACpB,EACC,KAAK,EAAE,CAAC;AAAA,EACb;AACA,QAAM,KAAK,GAAG,MAAM,MAAM,KAAK,CAAC;AAChC,QAAM,KAAK,GAAG,MAAM,MAAM,KAAK,CAAC;AAChC,MAAI,GAAG,UAAU,GAAG,WAAW,GAAG,UAAU,GAAG,QAAQ,QAAQ,GAAG,MAAM,GAAG,QAAQ,QAAQ,GAAG,GAAG;AAC/F,QAAI,IAAI;AACR,WAAO,GAAG,QAAQ,QAAQ,MAAM;AAC9B,YAAM,IAAI,OAAO,GAAG,CAAC,CAAC,KAAK,OAAO,GAAG,CAAC,CAAC,IAAI,OAAO,GAAG,CAAC,CAAC,KAAK;AAC5D;AACA,aAAO,OAAO,MAAM,CAAC,CAAC;AAAA,IACxB,CAAC;AAAA,EACH;AACA,SAAO,IAAI,MAAM,KAAK;AACxB;AAGO,SAAS,YACd,OACA,UAAkD,CAAC,GAC3C;AACR,QAAM,IAAI,MAAM,QAAQ,QAAQ,YAAY,CAAC;AAC7C,UAAQ,QAAQ,UAAU,OAAO,QAAQ,OAAO,CAAC;AACnD;AAEA,IAAM,UAAU,CAAC,GAAiB,UAA6B;AAC7D,QAAM,IAAI,UAAU,OAAO,EAAE,QAAQ,CAAC;AACtC,SAAO,MAAM,SAAY,WAAW,KAAK,EAAE,SAAS;AACtD;AAQO,SAAS,SACd,YACA,OACA,QAC8B;AAE9B,QAAM,SAAS,oBAAI,IAAoE;AACvF,QAAM,MAAM,CAAC,MAAc,MAAoB,UAAkB;AAC/D,UAAM,MAAM,GAAG,SAAS,SAAS,cAAc,KAAK,EAAE,KAAS,IAAI;AACnE,UAAM,OAAO,OAAO,IAAI,GAAG,KAAK,CAAC;AACjC,SAAK,KAAK,EAAE,MAAM,OAAO,QAAQ,MAAM,KAAK,GAAG,MAAM,CAAC;AACtD,WAAO,IAAI,KAAK,IAAI;AAAA,EACtB;AACA,aAAW,QAAQ,CAAC,GAAG,MAAM;AAC3B,eAAW,QAAQ,OAAO,KAAK,EAAE,SAAS,CAAC,CAAC,EAAG,KAAI,IAAI,IAAI,IAAI,GAAG,CAAC;AACnE,QAAI,EAAE,KAAM,KAAI,QAAQ,GAAG,CAAC;AAC5B,QAAI,EAAE,MAAO,KAAI,SAAS,GAAG,CAAC;AAC9B,QAAI,EAAE,UAAU,OAAW,KAAI,SAAS,GAAG,CAAC;AAC5C,QAAI,EAAE,SAAS,OAAW,KAAI,QAAQ,GAAG,CAAC;AAC1C,QAAI,EAAE,SAAS,OAAW,KAAI,QAAQ,GAAG,CAAC;AAC1C,QAAI,EAAE,MAAO,KAAI,SAAS,GAAG,CAAC;AAAA,EAChC,CAAC;AACD,QAAM,SAAS,oBAAI,IAA6B;AAChD,aAAW,CAAC,KAAK,IAAI,KAAK,QAAQ;AAChC,SAAK,KAAK,CAAC,GAAG,MAAM,EAAE,QAAQ,EAAE,SAAS,EAAE,QAAQ,EAAE,KAAK;AAC1D,UAAM,CAAC,IAAI,IAAI,IAAI,IAAI,MAAM,IAAQ;AACrC,UAAM,UAAU,KAAK,OAAO,CAAC,MAAM,EAAE,SAAS,MAAM;AACpD,UAAM,UAAU,QAAQ,QAAQ,SAAS,CAAC;AAC1C,UAAM,QAAQ,WAAW,KAAK,CAAC,GAAI;AACnC,UAAM,IAAI,UACN,aAAa,OAAO,QAAQ,KAAK,QAAQ,GAAG;AAAA,MAC1C,OAAO,KAAK;AAAA,MACZ,IAAI,KAAK;AAAA,MACT,MAAM,KAAK;AAAA,IACb,CAAC,IACD;AACJ,UAAM,QAAQ,OAAO,IAAI,EAAE,KAAK,EAAE,OAAO,CAAC,EAAE;AAC5C,QAAI,SAAS,QAAQ;AAEnB,YAAM,SAAS,UAAU,KAAK,KAAK,QAAQ,OAAO,IAAI,CAAC,IAAI;AAC3D,YAAM,OAAO,EAAE,MAAM,QAAQ,KAAK,QAAQ,MAAM,IAAI,KAAK,MAAO,EAAE;AAAA,IACpE,WAAW,SAAS,SAAS;AAC3B,YAAM,CAAC,GAAG,CAAC,IAAI,KAAK,MAAM,CAAC,GAAG,CAAC;AAC/B,YAAM,QAAQ,EAAE,MAAM,KAAK,OAAQ,IAAI,KAAK,IAAI,KAAK,EAAE;AAAA,IACzD,WAAW,SAAS,QAAQ;AAC1B,YAAM,OAAO,KAAK;AAAA,IACpB,WAAW,KAAK,WAAW,GAAG,GAAG;AAC/B,YAAM,CAAC,GAAG,CAAC,IAAI,KAAK,MAAO,KAAK,MAAM,CAAC,CAAC;AACxC,YAAM,MAAM,KAAK,MAAM,CAAC,CAAC,IAAI,SAAS,GAAG,GAAG,CAAC;AAAA,IAC/C,WAAW,SAAS,QAAQ;AAC1B,YAAM,CAAC,GAAG,CAAC,IAAI,KAAK,SAAS,OAAO,CAAC,GAAG,CAAC,IAAK,KAAK;AACnD,YAAM,OAAO,KAAK,IAAI,KAAK;AAAA,IAC7B,WAAW,KAAK,UAAU,QAAW;AACnC,YAAM,OAAO,YAAY,KAAK,OAAO,GAAG,EAAE,UAAU,KAAK,UAAU,OAAO,KAAK,OAAO,OAAO,CAAC;AAAA,IAChG,OAAO;AACL,YAAM,CAAC,GAAG,CAAC,IAAI,KAAK;AACpB,YAAM,OAAO,YAAY,KAAK,IAAI,KAAK,GAAG,IAAI;AAAA,IAChD;AACA,WAAO,IAAI,IAAI,KAAK;AAAA,EACtB;AACA,SAAO;AACT;AAOO,SAAS,cAAc,QAAwB;AACpD,QAAM,MAAM,OAAO,QAAQ,GAAG;AAC9B,SAAO,MAAM,IAAI,SAAS,OAAO,MAAM,GAAG,MAAM,CAAC;AACnD;AAGO,SAAS,gBAAgB,QAA2B;AACzD,QAAM,SAAmB,CAAC;AAC1B,QAAM,IAAK,UAAU,CAAC;AACtB,QAAM,MAAM,OAAO,EAAE,QAAQ,WAAW,EAAE,IAAI,KAAK,IAAI;AACvD,MAAI,CAAC,IAAK,QAAO,CAAC,qDAAqD;AACvE,MAAI,CAAC,cAAc,KAAK,GAAG,KAAK,CAAC,IAAI,YAAY,EAAE,SAAS,QAAQ;AAClE,WAAO,KAAK,6CAAwC;AACtD,MAAI,CAAC,iBAAiB,KAAK,cAAc,GAAG,CAAC;AAC3C,WAAO,KAAK,iEAAiE;AAC/E,MAAI,sCAAsC,KAAK,GAAG;AAChD,WAAO,KAAK,8DAA8D;AAC5E,MAAI,uDAAuD,KAAK,GAAG;AACjE,WAAO;AAAA,MACL;AAAA,IACF;AACF,MAAI,6CAA6C,KAAK,GAAG;AACvD,WAAO,KAAK,kEAAkE;AAChF,QAAM,MAAM,IAAI,IAAI,CAAC,GAAG,IAAI,SAAS,8BAA8B,CAAC,EAAE,IAAI,CAAC,MAAM,EAAE,CAAC,CAAC,CAAC;AACtF,MAAI,EAAE,YAAY,UAAa,CAAC,MAAM,QAAQ,EAAE,OAAO,EAAG,QAAO,KAAK,0BAA0B;AAChG,GAAC,MAAM,QAAQ,EAAE,OAAO,IAAI,EAAE,UAAU,CAAC,GAAG,QAAQ,CAAC,GAAG,MAAM;AAC5D,UAAM,QAAQ,WAAW,CAAC;AAC1B,QAAI,CAAC,KAAK,OAAO,MAAM,SAAU,QAAO,KAAK,OAAO,KAAK,GAAG,KAAK,sBAAsB;AACvF,QAAI,OAAO,EAAE,OAAO,UAAU;AAC5B,UAAI,EAAE,SAAS,OAAW,QAAO,KAAK,OAAO,KAAK,GAAG,KAAK,kBAAkB;AAAA,IAC9E,WAAW,CAAC,IAAI,IAAI,EAAE,EAAE;AACtB,aAAO,KAAK,GAAG,KAAK,kCAAkC,EAAE,EAAE,cAAc;AAC1E,QAAI,EAAE,SAAS,UAAa,EAAE,OAAO,UAAU,EAAE,IAAI,KAAK,EAAE,QAAQ;AAClE,aAAO,KAAK,GAAG,KAAK,yCAAyC;AAC/D,QAAI,EAAE,OAAO,UAAa,EAAE,EAAE,MAAM,GAAI,QAAO,KAAK,GAAG,KAAK,4BAA4B;AACxF,QAAI,EAAE,UAAU,UAAa,EAAE,EAAE,SAAS;AACxC,aAAO,KAAK,GAAG,KAAK,+BAA+B;AACrD,QAAI,EAAE,SAAS,UAAa,EAAE,EAAE,QAAQ;AACtC,aAAO,KAAK,GAAG,KAAK,wBAAwB,OAAO,KAAK,KAAK,EAAE,KAAK,IAAI,CAAC,EAAE;AAC7E,QAAI,CAAC,EAAE,SAAS,CAAC,EAAE,QAAQ,CAAC,EAAE,SAAS,EAAE,UAAU,UAAa,EAAE,SAAS,UAAa,CAAC,EAAE,SAAS,EAAE,SAAS;AAC7G,aAAO;AAAA,QACL,GAAG,KAAK;AAAA,MACV;AACF,QAAI,EAAE,SAAS,UAAa,EAAE,OAAO,UAAU,EAAE,IAAI,KAAK,EAAE,QAAQ;AAClE,aAAO,KAAK,GAAG,KAAK,kDAAkD;AACxE,QAAI,EAAE,SAAS,QAAW;AACxB,YAAM,MAAM,EAAE;AACd,UAAI,OAAO,QAAQ,UAAU;AAC3B,YAAI,CAAC,IAAI,IAAI,GAAG;AACd,iBAAO,KAAK,GAAG,KAAK,sBAAsB,GAAG,kCAAkC;AAAA,MACnF,WACE,CAAC,MAAM,QAAQ,GAAG,KAClB,IAAI,WAAW,KACf,CAAC,IAAI,MAAM,CAAC,MAAM,OAAO,SAAS,CAAC,CAAC,KACpC,EAAE,IAAI,CAAC,IAAI,KAAK,IAAI,CAAC,IAAI;AAEzB,eAAO;AAAA,UACL,GAAG,KAAK;AAAA,QACV;AAAA,IACJ;AACA,QAAI,EAAE,UAAU,QAAW;AACzB,UAAI,OAAO,EAAE,UAAU,YAAY,CAAC,IAAI,IAAI,EAAE,KAAK;AACjD,eAAO,KAAK,GAAG,KAAK,4CAA4C;AAClE,UAAI,OAAO,EAAE,OAAO;AAClB,eAAO,KAAK,GAAG,KAAK,+CAA+C;AAAA,IACvE;AACA,QACE,EAAE,OAAO,UACT,EAAE,MAAM,QAAQ,EAAE,EAAE,KAAK,EAAE,GAAG,WAAW,KAAK,EAAE,GAAG,MAAM,CAAC,MAAM,KAAK,KAAK,KAAK,CAAC;AAEhF,aAAO,KAAK,GAAG,KAAK,wCAAwC;AAC9D,eAAW,CAAC,MAAM,IAAI,KAAK,OAAO,QAAQ,EAAE,SAAS,CAAC,CAAC;AACrD,UAAI,CAAC,MAAM,QAAQ,IAAI,KAAK,KAAK,WAAW;AAC1C,eAAO,KAAK,GAAG,KAAK,aAAa,IAAI,kBAAkB;AAC3D,QAAI,MAAM,QAAQ,EAAE,IAAI,KAAK,EAAE,KAAK,KAAK,CAAC,MAAM,EAAE,KAAK,KAAK,KAAK,EAAE;AACjE,aAAO,KAAK,GAAG,KAAK,kDAAkD;AACxE,QAAI,EAAE,UAAU,UAAa,EAAE,MAAM,QAAQ,EAAE,KAAK,KAAK,EAAE,MAAM,WAAW;AAC1E,aAAO,KAAK,GAAG,KAAK,2BAA2B;AACjD,QAAI,EAAE,UAAU,UAAa,OAAO,EAAE,UAAU;AAC9C,aAAO,KAAK,GAAG,KAAK,kCAAkC;AACxD,SAAK,EAAE,aAAa,UAAa,EAAE,UAAU,WAAc,EAAE,UAAU;AACrE,aAAO,KAAK,GAAG,KAAK,gDAAgD;AAAA,EACxE,CAAC;AACD,SAAO;AACT;","names":[]}
package/dist/cli.js CHANGED
@@ -183,7 +183,7 @@ var collect = (value, previous) => [...previous, value];
183
183
  program.command("effects").description("List catalog effects with what they take (image, video, svg, text, mask, path) and how they answer the pointer").option("--accepts <inputs>", "Only effects that take all of these (image, video, svg, text, mask, path; comma-separated or repeated)", collect, []).option("--interaction <ways>", "Only effects that answer the pointer in one of these ways (hover, press, click, trail, pointer)", collect, []).option("--category <category>", "Only this category").option("--kind <kind>", "shader or vector").option("--search <words>", "Words to look for in the id, name, description and tags").option("--json", "Output JSON (id, name, kind, category, description, inputs, presets)", false).action(async (options) => {
184
184
  try {
185
185
  const { findEffects, effectInputs } = await import("./catalog/index.js");
186
- const { effectQueryFromFlags, describeEffect } = await import("./effect-GGT2BUW2.js");
186
+ const { effectQueryFromFlags, describeEffect } = await import("./effect-6VQS2CA5.js");
187
187
  const effects = findEffects(effectQueryFromFlags(options));
188
188
  if (options.json) {
189
189
  console.log(JSON.stringify(effects.map((e) => ({ id: e.id, name: e.name, kind: e.kind, category: e.category, description: e.description, inputs: effectInputs(e), presets: e.presets?.map((p) => p.name) ?? [] })), null, 2));
@@ -204,7 +204,7 @@ ${effects.length} effect${effects.length === 1 ? "" : "s"}. Render one with: fla
204
204
  program.command("render <effect>").description("Render a catalog effect, applied to a subject, to .mp4, .webm, .mov, .gif, .svg (vector effects) or .png frames").option("--image <path>", "A picture (file path or URL); repeat for effects that take two", collect, []).option("--svg <path>", "An SVG (file path, URL or markup)", collect, []).option("--text <text>", "Words, for a text effect or a text mask", collect, []).option("--font <family>", "CSS font family for --text drawn into a shader").option("--weight <weight>", "Font weight for --text drawn into a shader").option("--path <d>", "SVG path data, for a shape control", collect, []).option("--video <path>", "A video file, decoded to frames with ffmpeg", collect, []).option("--preset <name>", "A preset by name").option("--set <name=value>", "A control value (repeatable): --set uSpeed=2 --set uTint=#ff0080", collect, []).option("--size <WxH>", "Pixels, like 1280x720").option("--fps <fps>", "Frames per second", "30").option("--duration <seconds>", "Seconds (default: the effect's loop or play-through)").option("--alpha", "Keep transparency (webm, mov, gif, png, svg)", false).option("--background <css>", "Colour under transparent pixels without --alpha").option("--no-pointer", "Leave the pointer still (interactive effects otherwise get a scripted pointer)").option("-o, --out <outputPath>", "Output: .mp4, .webm, .mov, .gif, .svg, a .png pattern (out_%04d.png) or a folder").action(async (effectId, options) => {
205
205
  try {
206
206
  if (!options.out) throw new Error("Say where to write it: -o out.mp4 (or .webm, .mov, .gif, .svg, out_%04d.png, a folder/).");
207
- const { exportEffect, parseSets, parseSize, resolveEffect, subjectsFromFlags } = await import("./effect-GGT2BUW2.js");
207
+ const { exportEffect, parseSets, parseSize, resolveEffect, subjectsFromFlags } = await import("./effect-6VQS2CA5.js");
208
208
  const effect = resolveEffect(effectId);
209
209
  const subjects = subjectsFromFlags(options);
210
210
  const size = options.size ? parseSize(options.size) : void 0;
@@ -1,4 +1,4 @@
1
- import { g as VectorControl, d as EffectPreset, E as EffectDefinition } from '../types-c8cnPzuE.js';
1
+ import { i as VectorControl, f as EffectPreset, E as EffectDefinition } from '../types-B4Wjzde0.js';
2
2
  import { C as ControlValue, a as ControlDef, b as ControlType } from '../controls-Ec6P0Vpy.js';
3
3
  import { S as SvgMotion, C as Clock } from '../svg-DaKRPA9v.js';
4
4
  import { AnimationEasingPreset, AnimationEasing, AnimationTrack, AnimationKeyframe, cubicBezierAt as cubicBezierAt$1, evaluateEasing as evaluateEasing$1 } from '@pixerate/editor/animation';
@@ -6,6 +6,7 @@ import {
6
6
  } from "../chunk-HDYBY3PQ.js";
7
7
  import {
8
8
  EFFECT_CATEGORIES,
9
+ EFFECT_CATEGORY_GROUPS,
9
10
  EFFECT_INPUTS,
10
11
  EFFECT_INTERACTIONS,
11
12
  VIDEO_USES,
@@ -15,7 +16,7 @@ import {
15
16
  renderVectorEffect,
16
17
  vectorControlIssues,
17
18
  vectorEffectControls
18
- } from "../chunk-RS2S2K5C.js";
19
+ } from "../chunk-IHUNCBMF.js";
19
20
  import "../chunk-EHDJ3CPJ.js";
20
21
  import {
21
22
  checkControlValue,
@@ -23,13 +24,15 @@ import {
23
24
  parseControls
24
25
  } from "../chunk-VYOMXE6I.js";
25
26
  import {
26
- svgMotionIssues,
27
+ svgDuration,
27
28
  svgView
28
- } from "../chunk-DA4UUSDO.js";
29
+ } from "../chunk-JETRHCP3.js";
29
30
  import {
30
31
  realClock
31
32
  } from "../chunk-WMZQCUFJ.js";
32
- import "../chunk-ORAFCHX3.js";
33
+ import {
34
+ svgMotionIssues
35
+ } from "../chunk-VKIDRHBG.js";
33
36
 
34
37
  // src/editor/timeline.ts
35
38
  import {
@@ -114,7 +117,7 @@ function createEffectDocument(from) {
114
117
  },
115
118
  values: {},
116
119
  tracks: {},
117
- duration: effect.kind === "shader" && effect.loop ? Math.round(effect.loop * 1e3) : DEFAULT_DURATION,
120
+ duration: effect.kind === "vector" ? Math.round(svgDuration(effect.motion) + (effect.hold ?? 600)) : effect.loop ? Math.round(effect.loop * 1e3) : DEFAULT_DURATION,
118
121
  loop: true,
119
122
  presets: (effect.presets ?? []).map((p) => ({ name: p.name, values: { ...p.values } }))
120
123
  };
@@ -277,6 +280,11 @@ function effectCommands() {
277
280
  properties: {
278
281
  text: { type: "string", description: "Words to look for (all must match)." },
279
282
  category: { type: "string", enum: EFFECT_CATEGORIES },
283
+ group: {
284
+ type: "string",
285
+ enum: EFFECT_CATEGORY_GROUPS.map((g) => g.name),
286
+ description: `A set of related categories: ${EFFECT_CATEGORY_GROUPS.map((g) => `${g.name} (${g.categories.join(", ")})`).join("; ")}.`
287
+ },
280
288
  kind: { type: "string", enum: ["shader", "vector"] },
281
289
  video: {
282
290
  type: "array",