@idle-screens/schema 3.8.0 → 3.9.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -246,7 +246,9 @@ function steerablePaths(spec) {
246
246
  if (prefix) out.push(prefix);
247
247
  };
248
248
  walk(spec, "", "");
249
- return out;
249
+ const ignored = ignoredPropertyPaths(spec);
250
+ if (ignored.length === 0) return out;
251
+ return out.filter((p) => !ignored.some((ig) => p === ig || p.startsWith(`${ig}.`)));
250
252
  }
251
253
  function sequenceSteerablePaths(seq) {
252
254
  const out = /* @__PURE__ */ new Set(["sequence.segment"]);
@@ -361,6 +363,16 @@ var LAYER_PROPS_ON_SPRITE = /* @__PURE__ */ new Set(["blend", "trail", "alpha",
361
363
  function unknownKeys(obj, known) {
362
364
  return Object.keys(obj).filter((k) => !known.has(k));
363
365
  }
366
+ function dimUnit(spec) {
367
+ return isObj(spec) && spec.units === "px" ? "px" : "fractions of min(width, height)";
368
+ }
369
+ function rangeMsg(spec, note) {
370
+ return `must be a [min,max] range of positive ${dimUnit(spec)}${note ? ` (${note})` : ""}`;
371
+ }
372
+ function positiveScalar(v, path, err, msg = "must be > 0") {
373
+ if (Array.isArray(v)) err(path, "must be a single number > 0, not a [min,max] range");
374
+ else if (!isNum(v) || v <= 0) err(path, msg);
375
+ }
364
376
  function normalizeColors(spec) {
365
377
  if (!isObj(spec) || !Array.isArray(spec.layers)) return;
366
378
  for (const layer of spec.layers) {
@@ -375,6 +387,13 @@ function normalizeColors(spec) {
375
387
  }
376
388
  function validateSpec(spec) {
377
389
  normalizeColors(spec);
390
+ return validateSpecCore(spec);
391
+ }
392
+ function ignoredPropertyPaths(spec) {
393
+ if (!isObj(spec)) return [];
394
+ return (validateSpecCore(spec).warnings ?? []).filter((w) => w.code === "unknown-property" || w.code === "misplaced-property").map((w) => w.path.replace(/\[(\d+)\]/g, ".$1"));
395
+ }
396
+ function validateSpecCore(spec) {
378
397
  const errors = [];
379
398
  const warnings = [];
380
399
  const err = (path, message) => void errors.push({ path, message });
@@ -471,7 +490,7 @@ function validateBackground(bg, err, warn) {
471
490
  if (!isObj(bg.band)) err("background.band", "must be an object");
472
491
  else {
473
492
  color(bg.band.color, "background.band.color", err);
474
- if (!isNum(bg.band.height) || bg.band.height <= 0) err("background.band.height", "must be > 0");
493
+ positiveScalar(bg.band.height, "background.band.height", err);
475
494
  }
476
495
  }
477
496
  for (const k of unknownKeys(bg, KNOWN_BG_GRADIENT)) {
@@ -537,7 +556,7 @@ function validateLayer(layer, path, err, warn, spec) {
537
556
  err(`${path}.count`, `at most ${LIMITS.maxPerLayer} per layer`);
538
557
  }
539
558
  if (layer.size !== void 0 && (!isRange(layer.size) || layer.size[0] <= 0)) {
540
- err(`${path}.size`, "must be a [min,max] range of positive px");
559
+ err(`${path}.size`, rangeMsg(spec));
541
560
  }
542
561
  if (layer.wrap !== void 0 && typeof layer.wrap !== "boolean") err(`${path}.wrap`, "must be a boolean");
543
562
  if (layer.flip !== void 0 && typeof layer.flip !== "boolean") err(`${path}.flip`, "must be a boolean");
@@ -634,16 +653,12 @@ function validateLayer(layer, path, err, warn, spec) {
634
653
  if (!isNum(layer.links.k) || !Number.isInteger(layer.links.k) || layer.links.k < 1 || layer.links.k > LIMITS.maxLinksK) {
635
654
  err(`${path}.links.k`, `must be an integer 1..${LIMITS.maxLinksK}`);
636
655
  }
637
- if (!isNum(layer.links.maxDist) || layer.links.maxDist <= 0) {
638
- err(`${path}.links.maxDist`, "must be > 0");
639
- }
656
+ positiveScalar(layer.links.maxDist, `${path}.links.maxDist`, err);
640
657
  if (layer.links.color !== void 0) color(layer.links.color, `${path}.links.color`, err);
641
658
  if (layer.links.alpha !== void 0 && (!isNum(layer.links.alpha) || layer.links.alpha < 0 || layer.links.alpha > 1)) {
642
659
  err(`${path}.links.alpha`, "must be 0..1");
643
660
  }
644
- if (layer.links.width !== void 0 && (!isNum(layer.links.width) || layer.links.width <= 0)) {
645
- err(`${path}.links.width`, "must be > 0");
646
- }
661
+ if (layer.links.width !== void 0) positiveScalar(layer.links.width, `${path}.links.width`, err);
647
662
  if (layer.links.mode !== void 0 && !["nearest", "chain", "random"].includes(layer.links.mode)) {
648
663
  err(`${path}.links.mode`, "must be 'nearest' | 'chain' | 'random'");
649
664
  }
@@ -797,10 +812,10 @@ function validateLayer(layer, path, err, warn, spec) {
797
812
  }
798
813
  }
799
814
  }
800
- validateSprite(layer.sprite, `${path}.sprite`, err, warn);
815
+ validateSprite(layer.sprite, `${path}.sprite`, err, warn, spec);
801
816
  validateMotion(layer.motion, `${path}.motion`, err, warn, spec);
802
817
  }
803
- function validateSprite(sprite, path, err, warn) {
818
+ function validateSprite(sprite, path, err, warn, spec) {
804
819
  if (!isObj(sprite)) return err(path, "must be an object");
805
820
  let knownSet;
806
821
  if (sprite.kind === "emoji") {
@@ -824,32 +839,30 @@ function validateSprite(sprite, path, err, warn) {
824
839
  if (sprite.baseline !== void 0 && !["top", "middle", "bottom"].includes(sprite.baseline)) {
825
840
  err(`${path}.baseline`, "must be top | middle | bottom");
826
841
  }
827
- if (sprite.maxWidth !== void 0 && (!isNum(sprite.maxWidth) || sprite.maxWidth <= 0)) {
828
- err(`${path}.maxWidth`, "must be a positive number");
829
- }
842
+ if (sprite.maxWidth !== void 0) positiveScalar(sprite.maxWidth, `${path}.maxWidth`, err, "must be a positive number");
830
843
  validateTextRole(sprite, path, err);
831
844
  validateCycle(sprite, path, err);
832
845
  } else if (sprite.kind === "circle") {
833
846
  knownSet = KNOWN_CIRCLE;
834
- if (!isRange(sprite.radius) || sprite.radius[0] <= 0) err(`${path}.radius`, "must be a [min,max] range of positive px");
847
+ if (!isRange(sprite.radius) || sprite.radius[0] <= 0) err(`${path}.radius`, rangeMsg(spec));
835
848
  color(sprite.color, `${path}.color`, err);
836
849
  if (sprite.soft !== void 0 && typeof sprite.soft !== "boolean") err(`${path}.soft`, "must be a boolean");
837
850
  validatePalette(sprite, path, err);
838
851
  } else if (sprite.kind === "ring") {
839
852
  knownSet = KNOWN_RING;
840
- if (!isRange(sprite.radius) || sprite.radius[0] <= 0) err(`${path}.radius`, "must be a [min,max] range of positive px");
853
+ if (!isRange(sprite.radius) || sprite.radius[0] <= 0) err(`${path}.radius`, rangeMsg(spec));
841
854
  color(sprite.color, `${path}.color`, err);
842
- if (sprite.width !== void 0 && (!isNum(sprite.width) || sprite.width <= 0)) err(`${path}.width`, "must be > 0");
855
+ if (sprite.width !== void 0) positiveScalar(sprite.width, `${path}.width`, err);
843
856
  validatePalette(sprite, path, err);
844
857
  } else if (sprite.kind === "streak") {
845
858
  knownSet = KNOWN_STREAK;
846
- if (!isRange(sprite.length) || sprite.length[0] <= 0) err(`${path}.length`, "must be a [min,max] range of positive px");
859
+ if (!isRange(sprite.length) || sprite.length[0] <= 0) err(`${path}.length`, rangeMsg(spec));
847
860
  color(sprite.color, `${path}.color`, err);
848
- if (sprite.width !== void 0 && (!isNum(sprite.width) || sprite.width <= 0)) err(`${path}.width`, "must be > 0");
861
+ if (sprite.width !== void 0) positiveScalar(sprite.width, `${path}.width`, err);
849
862
  validatePalette(sprite, path, err);
850
863
  } else if (sprite.kind === "rect") {
851
864
  knownSet = KNOWN_RECT;
852
- if (!isRange(sprite.width) || sprite.width[0] <= 0) err(`${path}.width`, "must be a [min,max] range of positive px");
865
+ if (!isRange(sprite.width) || sprite.width[0] <= 0) err(`${path}.width`, rangeMsg(spec));
853
866
  if (sprite.aspect !== void 0 && (!isRange(sprite.aspect) || sprite.aspect[0] <= 0)) {
854
867
  err(`${path}.aspect`, "must be a [min,max] range of positive height/width ratios");
855
868
  }
@@ -863,9 +876,9 @@ function validateSprite(sprite, path, err, warn) {
863
876
  if (!Array.isArray(sprite.values) || sprite.values.length === 0 || sprite.values.length > LIMITS.maxPerLayer || !sprite.values.every((v) => isNum(v) && v >= 0)) {
864
877
  err(`${path}.values`, `must be 1..${LIMITS.maxPerLayer} numbers >= 0`);
865
878
  }
866
- if (!isNum(sprite.length) || sprite.length <= 0) err(`${path}.length`, "must be > 0 (full-scale bar length)");
867
- if (!isNum(sprite.thickness) || sprite.thickness <= 0) err(`${path}.thickness`, "must be > 0");
868
- if (sprite.max !== void 0 && (!isNum(sprite.max) || sprite.max <= 0)) err(`${path}.max`, "must be > 0");
879
+ positiveScalar(sprite.length, `${path}.length`, err, "must be > 0 (full-scale bar length)");
880
+ positiveScalar(sprite.thickness, `${path}.thickness`, err);
881
+ if (sprite.max !== void 0) positiveScalar(sprite.max, `${path}.max`, err);
869
882
  if (sprite.direction !== void 0 && !["right", "left", "up", "down"].includes(sprite.direction)) {
870
883
  err(`${path}.direction`, "must be 'right' | 'left' | 'up' | 'down'");
871
884
  }
@@ -873,7 +886,7 @@ function validateSprite(sprite, path, err, warn) {
873
886
  validatePalette(sprite, path, err);
874
887
  } else if (sprite.kind === "polygon") {
875
888
  knownSet = KNOWN_POLYGON;
876
- if (!isRange(sprite.radius) || sprite.radius[0] <= 0) err(`${path}.radius`, "must be a [min,max] range of positive px (circumradius)");
889
+ if (!isRange(sprite.radius) || sprite.radius[0] <= 0) err(`${path}.radius`, rangeMsg(spec, "circumradius"));
877
890
  if (sprite.sides !== void 0 && sprite.points !== void 0) {
878
891
  err(`${path}.sides`, "use sides (a regular polygon) or points (a custom one), not both");
879
892
  }
@@ -886,9 +899,9 @@ function validateSprite(sprite, path, err, warn) {
886
899
  validatePalette(sprite, path, err);
887
900
  } else if (sprite.kind === "stroke") {
888
901
  knownSet = KNOWN_STROKE;
889
- if (!isRange(sprite.length) || sprite.length[0] <= 0) err(`${path}.length`, "must be a [min,max] range of positive px (the mark's bounding size)");
902
+ if (!isRange(sprite.length) || sprite.length[0] <= 0) err(`${path}.length`, rangeMsg(spec, "the mark's bounding size"));
890
903
  validateShapePoints(sprite.points, `${path}.points`, 2, err);
891
- if (sprite.width !== void 0 && (!isNum(sprite.width) || sprite.width <= 0)) err(`${path}.width`, "must be > 0");
904
+ if (sprite.width !== void 0) positiveScalar(sprite.width, `${path}.width`, err);
892
905
  if (sprite.curve !== void 0 && sprite.curve !== "smooth" && sprite.curve !== "linear") err(`${path}.curve`, "must be 'smooth' | 'linear'");
893
906
  if (sprite.taper !== void 0 && typeof sprite.taper !== "boolean") err(`${path}.taper`, "must be a boolean");
894
907
  if (sprite.orient !== void 0 && typeof sprite.orient !== "boolean") err(`${path}.orient`, "must be a boolean");
@@ -901,10 +914,14 @@ function validateSprite(sprite, path, err, warn) {
901
914
  } else if (sprite.text.length > LIMITS.maxTextBlockLength) {
902
915
  err(`${path}.text`, `must be at most ${LIMITS.maxTextBlockLength} characters`);
903
916
  }
904
- if (!isNum(sprite.maxWidth) || sprite.maxWidth <= 0 || sprite.maxWidth > LIMITS.maxTextBlockMaxWidth) {
917
+ if (Array.isArray(sprite.maxWidth)) {
918
+ err(`${path}.maxWidth`, "must be a single number (viewport fraction), not a [min,max] range");
919
+ } else if (!isNum(sprite.maxWidth) || sprite.maxWidth <= 0 || sprite.maxWidth > LIMITS.maxTextBlockMaxWidth) {
905
920
  err(`${path}.maxWidth`, `must be a positive number up to ${LIMITS.maxTextBlockMaxWidth} (viewport fraction)`);
906
921
  }
907
- if (!isNum(sprite.fontSize) || sprite.fontSize < LIMITS.minTextBlockFontSize || sprite.fontSize > LIMITS.maxTextBlockFontSize) {
922
+ if (Array.isArray(sprite.fontSize)) {
923
+ err(`${path}.fontSize`, "must be a single number (viewport fraction), not a [min,max] range");
924
+ } else if (!isNum(sprite.fontSize) || sprite.fontSize < LIMITS.minTextBlockFontSize || sprite.fontSize > LIMITS.maxTextBlockFontSize) {
908
925
  err(`${path}.fontSize`, `must be between ${LIMITS.minTextBlockFontSize} and ${LIMITS.maxTextBlockFontSize} (viewport fraction)`);
909
926
  }
910
927
  if (sprite.lineHeight !== void 0 && (!isNum(sprite.lineHeight) || sprite.lineHeight < 0.5 || sprite.lineHeight > 4)) {
@@ -1052,7 +1069,7 @@ function validateMotion(motion, path, err, warn, spec) {
1052
1069
  warn(`${path}.speed`, "near-zero-speed", `orbit speed is near zero \u2014 entities will appear frozen. Typical range: 5\u201360 deg/sec`);
1053
1070
  }
1054
1071
  }
1055
- if (!isRange(motion.radius) || motion.radius[0] <= 0) err(`${path}.radius`, "must be a [min,max] range of positive px");
1072
+ if (!isRange(motion.radius) || motion.radius[0] <= 0) err(`${path}.radius`, rangeMsg(spec));
1056
1073
  if (motion.center !== void 0) {
1057
1074
  if (!isObj(motion.center)) {
1058
1075
  err(`${path}.center`, "must be {x, y} (0..1) or { layer: key }");
@@ -2233,7 +2250,7 @@ function fieldAt(u, v, t, cfg, seed) {
2233
2250
  }
2234
2251
  function hexToRgb255(hex) {
2235
2252
  const h = hex.length === 4 ? `#${hex[1]}${hex[1]}${hex[2]}${hex[2]}${hex[3]}${hex[3]}` : hex;
2236
- const n = parseInt(h.slice(1), 16);
2253
+ const n = /^#[0-9a-f]{6}$/i.test(h) ? parseInt(h.slice(1), 16) : NaN;
2237
2254
  if (Number.isNaN(n)) return [128, 128, 128];
2238
2255
  return [n >> 16 & 255, n >> 8 & 255, n & 255];
2239
2256
  }
@@ -2475,8 +2492,16 @@ function bedRenderSeed(seq) {
2475
2492
  const raw = seq.bed.seed ?? (seq.seed !== void 0 ? seq.seed + LIMITS.maxSegments : void 0);
2476
2493
  return raw === void 0 ? void 0 : normalizeSeed(raw);
2477
2494
  }
2495
+ function sequenceWantsFinish(seq) {
2496
+ return seq.finish !== void 0 || seq.segments.some((s) => s.scene.finish !== void 0);
2497
+ }
2478
2498
  function sequenceSwapCompatible(prev, next) {
2479
2499
  if (prev.segments.length !== next.segments.length) return false;
2500
+ if (prev.finish !== void 0 || next.finish !== void 0) {
2501
+ if (prev.seed === void 0 !== (next.seed === void 0)) return false;
2502
+ if (prev.seed !== void 0 && next.seed !== void 0 && normalizeSeed(prev.seed) !== normalizeSeed(next.seed)) return false;
2503
+ }
2504
+ if (sequenceWantsFinish(prev) !== sequenceWantsFinish(next)) return false;
2480
2505
  if (prev.loop !== next.loop) return false;
2481
2506
  if ((prev.sync ?? "mount") !== (next.sync ?? "mount")) return false;
2482
2507
  if (!!prev.bed !== !!next.bed) return false;
@@ -2851,7 +2876,7 @@ var SpecInstance = class {
2851
2876
  }
2852
2877
  if (sprite.kind === "streak") {
2853
2878
  const resolvedColor = sprite.colors?.[e.colorIndex] ?? sprite.color;
2854
- const heading = headingAt(e, t, this.w, this.h) ?? 0;
2879
+ const heading = (headingAt(e, t, this.w, this.h) ?? 0) + rot;
2855
2880
  const tailX = p.x - Math.cos(heading) * sz;
2856
2881
  const tailY = p.y - Math.sin(heading) * sz;
2857
2882
  const g = ctx.createLinearGradient(tailX, tailY, p.x, p.y);
@@ -3425,8 +3450,7 @@ var SequenceInstance = class {
3425
3450
  this.canvas = canvas;
3426
3451
  this.seed = (seq.seed ?? ctx.seed ?? 0) >>> 0 || 1;
3427
3452
  this.animateFinish = capabilityTier !== "basic" && capabilityTier !== "minimal";
3428
- const wantsFinish = seq.finish !== void 0 || seq.segments.some((s) => s.scene.finish !== void 0);
3429
- if (wantsFinish && surface) {
3453
+ if (sequenceWantsFinish(seq) && surface) {
3430
3454
  const pass = createFinishPass(surface, this.seed);
3431
3455
  if (pass) {
3432
3456
  this.finishPass = pass;
@@ -3950,13 +3974,14 @@ function legibilityRatio(a, b) {
3950
3974
  const lo = Math.min(la, lb);
3951
3975
  return (hi + 0.05) / (lo + 0.05);
3952
3976
  }
3953
- function backgroundRgbAt(spec, yPx, h, unit, xPx, w, seed) {
3977
+ function backgroundRgbAt(spec, yPx, h, unit, xPx, w, seed, t = 0) {
3954
3978
  const bg = spec.background;
3955
3979
  if (!bg || bg.type === "solid") return hexRgb(bg?.color ?? "#05050a");
3956
3980
  if (bg.type === "field") {
3957
3981
  if (xPx === void 0 || w === void 0) return backgroundRgb(spec);
3958
3982
  const short = Math.max(1, Math.min(w, h));
3959
- const c = fieldRgbAt(xPx / short, yPx / short, 0, bg, seed ?? spec.seed ?? 42);
3983
+ const ft = fieldSampleTime(bg, t);
3984
+ const c = fieldRgbAt(xPx / short, yPx / short, ft, bg, seed ?? spec.seed ?? 42);
3960
3985
  return { r: c[0] / 255, g: c[1] / 255, b: c[2] / 255 };
3961
3986
  }
3962
3987
  if (bg.band) {
@@ -4512,7 +4537,7 @@ function adviseSpec(spec, viewport = { width: 1920, height: 1080 }, opts = {}) {
4512
4537
  for (const box of boxes) {
4513
4538
  const cy = (box.y0 + box.y1) / 2;
4514
4539
  const cx = (box.x0 + box.x1) / 2;
4515
- const groundRgb = backgroundRgbAt(spec, cy, h, scale, cx, w, opts.backgroundSeed ?? opts.seed);
4540
+ const groundRgb = backgroundRgbAt(spec, cy, h, scale, cx, w, opts.backgroundSeed ?? opts.seed, opts.t ?? COHESION_T);
4516
4541
  const ground = legibilityRatio(textPlate(groundRgb, box.alpha), groundRgb);
4517
4542
  const lit = brightestAdditivePlate(spec, allEntities, groundRgb, box, w, h);
4518
4543
  const plate = lit ? legibilityRatio(textPlate(lit.rgb, box.alpha), lit.rgb) : Infinity;
@@ -4762,7 +4787,7 @@ var LINE_SALIENCE = 3.5;
4762
4787
  var GHOST_TAPS = 12;
4763
4788
  function buildScene(spec, opts) {
4764
4789
  const { width: w, height: h } = opts.viewport ?? { width: 1920, height: 1080 };
4765
- const seed = opts.seed ?? spec.seed ?? 42;
4790
+ const seed = normalizeSeed(opts.seed ?? spec.seed ?? 42);
4766
4791
  const scale = spec.units === "px" ? 1 : Math.min(w, h);
4767
4792
  const refVp = spec.referenceViewport ?? LIMITS.referenceViewport;
4768
4793
  let countScale = scale > 1 ? Math.min(w, h) / refVp : 1;
@@ -4774,7 +4799,7 @@ function buildScene(spec, opts) {
4774
4799
  const layers = spec.layers.map((layer) => ({ layer, entities: buildEntities(layer, rng, w, h, scale, countScale) }));
4775
4800
  const byKey = /* @__PURE__ */ new Map();
4776
4801
  for (const { layer, entities } of layers) if (layer.key) byKey.set(layer.key, entities);
4777
- return { w, h, scale, layers, byKey };
4802
+ return { w, h, scale, seed, layers, byKey };
4778
4803
  }
4779
4804
  function posOf(scene, e, t) {
4780
4805
  const p = positionAt(e, t, scene.w, scene.h);
@@ -4854,7 +4879,7 @@ function luminanceGrid(spec, opts = {}) {
4854
4879
  } else if (bg.type === "field") {
4855
4880
  bgCells = new Array(cols * rows);
4856
4881
  const short = Math.max(1, Math.min(w, h));
4857
- const seed = opts.seed ?? spec.seed ?? 42;
4882
+ const seed = scene.seed;
4858
4883
  const ft = fieldSampleTime(bg, t);
4859
4884
  for (let r = 0; r < rows; r++) {
4860
4885
  let rowSum = 0;
@@ -4980,7 +5005,7 @@ function luminanceGrid(spec, opts = {}) {
4980
5005
  continue;
4981
5006
  }
4982
5007
  if (s.kind === "streak") {
4983
- const heading = headingAt(e, tPass, w, h) ?? 0;
5008
+ const heading = (headingAt(e, tPass, w, h) ?? 0) + rotationAt(e, tPass);
4984
5009
  const steps = Math.max(2, Math.ceil(sz / Math.min(cellW, cellH)));
4985
5010
  const wgt = Math.min(1, (s.width ?? (scale === 1 ? 2 : 2e-3)) * scale / cellH);
4986
5011
  for (let i = 0; i <= steps; i++) {
@@ -6186,6 +6211,616 @@ var DASHBOARD_SPEC = {
6186
6211
  ]
6187
6212
  };
6188
6213
 
6214
+ // src/examples/sparse-night.ts
6215
+ var SPARSE_NIGHT_SPEC = {
6216
+ schemaVersion: 1,
6217
+ id: "sparse-night",
6218
+ label: "Sparse Night",
6219
+ seed: 101,
6220
+ motionIntensity: "calm",
6221
+ density: "sparse",
6222
+ background: { type: "solid", color: "#02030a" },
6223
+ layers: [
6224
+ {
6225
+ key: "grain",
6226
+ count: 110,
6227
+ sprite: {
6228
+ kind: "circle",
6229
+ radius: [3e-4, 9e-4],
6230
+ color: "#c9d4e6"
6231
+ },
6232
+ motion: { type: "static" },
6233
+ alpha: [0.05, 0.3],
6234
+ pulse: { amp: 0.08, period: 7e3 }
6235
+ },
6236
+ {
6237
+ key: "figure",
6238
+ count: 5,
6239
+ sprite: {
6240
+ kind: "circle",
6241
+ radius: [16e-4, 22e-4],
6242
+ color: "#dfe8f2"
6243
+ },
6244
+ motion: { type: "drift", speed: [4e-4, 9e-4] },
6245
+ alpha: [0.4, 0.7],
6246
+ region: { x: [0.36, 0.64], y: [0.32, 0.62] },
6247
+ links: {
6248
+ k: 2,
6249
+ maxDist: 0.09,
6250
+ color: "#7f97b8",
6251
+ alpha: 0.16,
6252
+ width: 4e-4,
6253
+ mode: "chain",
6254
+ closed: true
6255
+ }
6256
+ },
6257
+ {
6258
+ key: "satellite",
6259
+ count: 1,
6260
+ sprite: {
6261
+ kind: "circle",
6262
+ radius: [24e-4, 24e-4],
6263
+ color: "#e8b04a",
6264
+ soft: true
6265
+ },
6266
+ motion: { type: "orbit", speed: [3, 3], radius: [0.34, 0.4] },
6267
+ alpha: [0.85, 0.85],
6268
+ blend: "lighter",
6269
+ emit: { every: 18e3, life: 3e3, jitter: 0, grow: [0.5, 1.6] }
6270
+ }
6271
+ ]
6272
+ };
6273
+
6274
+ // src/examples/signal-board.ts
6275
+ var SIGNAL_BOARD_SPEC = {
6276
+ schemaVersion: 1,
6277
+ id: "signal-board",
6278
+ label: "Signal Board",
6279
+ seed: 707,
6280
+ motionIntensity: "calm",
6281
+ background: { type: "solid", color: "#0d0b08" },
6282
+ layers: [
6283
+ {
6284
+ key: "readout",
6285
+ count: 9,
6286
+ sprite: {
6287
+ kind: "bar",
6288
+ values: [62, 38, 84, 21, 55, 91, 44, 70, 29],
6289
+ max: 100,
6290
+ // Cell pitch is the table's authored `gap` (0.07), so a full-value
6291
+ // bar must stay under that or neighboring cells' bars overlap.
6292
+ // 0.06 leaves a hairline margin.
6293
+ length: 0.06,
6294
+ thickness: 0.013,
6295
+ color: "#ffb000",
6296
+ direction: "right"
6297
+ },
6298
+ motion: { type: "static" },
6299
+ layout: { type: "table", columns: 3, gap: 0.07 },
6300
+ region: { x: [0.1, 0.9], y: [0.34, 0.78] },
6301
+ alpha: [0.5, 0.62]
6302
+ },
6303
+ {
6304
+ key: "labels",
6305
+ count: 9,
6306
+ sprite: {
6307
+ kind: "text",
6308
+ strings: [
6309
+ "A-01",
6310
+ "A-02",
6311
+ "A-03",
6312
+ "B-01",
6313
+ "B-02",
6314
+ "B-03",
6315
+ "C-01",
6316
+ "C-02",
6317
+ "C-03"
6318
+ ],
6319
+ color: "#b08a3a",
6320
+ font: "monospace",
6321
+ align: "left"
6322
+ },
6323
+ motion: { type: "static" },
6324
+ size: [0.011, 0.011],
6325
+ layout: { type: "table", columns: 3, gap: 0.07 },
6326
+ region: { x: [0.1, 0.9], y: [0.28, 0.72] },
6327
+ alpha: [0.55, 0.55]
6328
+ },
6329
+ {
6330
+ key: "caption",
6331
+ count: 1,
6332
+ sprite: {
6333
+ kind: "textBlock",
6334
+ text: "STATION 7 \u2014 QUIET HOURS",
6335
+ maxWidth: 0.6,
6336
+ fontSize: 0.022,
6337
+ lineHeight: 1.4,
6338
+ align: "left",
6339
+ anchor: "top-left",
6340
+ font: "bold monospace",
6341
+ color: "#c8862a"
6342
+ },
6343
+ motion: { type: "static" },
6344
+ position: { x: 0.1, y: 0.14 },
6345
+ alpha: [0.8, 0.8]
6346
+ },
6347
+ {
6348
+ key: "sweep",
6349
+ count: 1,
6350
+ sprite: {
6351
+ kind: "stroke",
6352
+ length: [1.4, 1.4],
6353
+ points: [
6354
+ [-1, 0],
6355
+ [1, 0]
6356
+ ],
6357
+ width: 16e-4,
6358
+ color: "#33ff66"
6359
+ },
6360
+ motion: { type: "drift", speed: [0.012, 0.012], angle: 90 },
6361
+ alpha: [0.22, 0.22],
6362
+ blend: "screen"
6363
+ }
6364
+ ]
6365
+ };
6366
+
6367
+ // src/examples/phase-duet.ts
6368
+ var PHASE_DUET_SPEC = {
6369
+ schemaVersion: 1,
6370
+ id: "phase-duet",
6371
+ label: "Phase Duet",
6372
+ seed: 88,
6373
+ motionIntensity: "calm",
6374
+ background: {
6375
+ type: "gradient",
6376
+ stops: [
6377
+ { at: 0, color: "#0a0f1c" },
6378
+ { at: 0.6, color: "#101b2e" },
6379
+ { at: 1, color: "#07141a" }
6380
+ ]
6381
+ },
6382
+ layers: [
6383
+ {
6384
+ key: "ripple",
6385
+ count: 60,
6386
+ sprite: {
6387
+ kind: "circle",
6388
+ radius: [18e-4, 3e-3],
6389
+ color: "#6fd3c7",
6390
+ colors: ["#6fd3c7", "#9fb8d8"],
6391
+ colorWeights: [2, 1]
6392
+ },
6393
+ motion: { type: "static" },
6394
+ layout: { type: "grid", columns: 10, jitter: 0 },
6395
+ alpha: [0.3, 0.55],
6396
+ pulse: { amp: 0.35, period: 6e3, wave: { wavelength: 0.7, angle: 25 } },
6397
+ clock: { phase: 0, rate: 1 }
6398
+ },
6399
+ {
6400
+ key: "rings",
6401
+ count: 3,
6402
+ sprite: {
6403
+ kind: "ring",
6404
+ radius: [0.05, 0.09],
6405
+ width: 12e-4,
6406
+ color: "#6fd3c7"
6407
+ },
6408
+ motion: { type: "static" },
6409
+ alpha: [0.25, 0.35],
6410
+ blend: "lighter",
6411
+ grow: { amp: 0.5, period: 6e3 },
6412
+ clock: { phase: 0, rate: 1 }
6413
+ },
6414
+ {
6415
+ key: "heart",
6416
+ count: 1,
6417
+ sprite: {
6418
+ kind: "circle",
6419
+ radius: [0.11, 0.11],
6420
+ color: "#9fb8d8",
6421
+ soft: true
6422
+ },
6423
+ motion: { type: "static" },
6424
+ position: { x: 0.5, y: 0.5 },
6425
+ alpha: [0.22, 0.22],
6426
+ blend: "lighter",
6427
+ grow: { amp: 0.25, period: 6e3 },
6428
+ clock: { phase: 0, rate: 1 }
6429
+ }
6430
+ ]
6431
+ };
6432
+
6433
+ // src/examples/web-work.ts
6434
+ var WEB_WORK_SPEC = {
6435
+ schemaVersion: 1,
6436
+ id: "web-work",
6437
+ label: "Web Work",
6438
+ seed: 31,
6439
+ motionIntensity: "calm",
6440
+ background: { type: "solid", color: "#04070c" },
6441
+ layers: [
6442
+ {
6443
+ key: "nodes",
6444
+ count: 44,
6445
+ sprite: {
6446
+ kind: "circle",
6447
+ radius: [18e-4, 34e-4],
6448
+ color: "#8fb4d8",
6449
+ colors: ["#8fb4d8", "#c9d8e6"],
6450
+ colorWeights: [2, 1]
6451
+ },
6452
+ motion: {
6453
+ type: "drift",
6454
+ speed: [2e-3, 6e-3],
6455
+ angle: 0,
6456
+ bidirectional: true
6457
+ },
6458
+ alpha: [0.45, 0.8],
6459
+ links: {
6460
+ k: 3,
6461
+ maxDist: 0.3,
6462
+ color: "#5f7f9f",
6463
+ alpha: 0.16,
6464
+ width: 5e-4,
6465
+ mode: "random",
6466
+ falloff: true
6467
+ }
6468
+ },
6469
+ {
6470
+ key: "flags",
6471
+ count: 22,
6472
+ sprite: {
6473
+ kind: "stroke",
6474
+ length: [0.02, 0.045],
6475
+ points: [
6476
+ [-1, 0.2],
6477
+ [-0.2, -0.5],
6478
+ [0.6, -0.3],
6479
+ [1, 0.1]
6480
+ ],
6481
+ width: 16e-4,
6482
+ taper: true,
6483
+ orient: true,
6484
+ color: "#6f93b8",
6485
+ colors: ["#6f93b8", "#9fb8d8"]
6486
+ },
6487
+ motion: {
6488
+ type: "drift",
6489
+ speed: [0.01, 0.03],
6490
+ angle: 0,
6491
+ bidirectional: true
6492
+ },
6493
+ alpha: [0.3, 0.6]
6494
+ }
6495
+ ]
6496
+ };
6497
+
6498
+ // src/examples/shard-fall.ts
6499
+ var SHARD_FALL_SPEC = {
6500
+ schemaVersion: 1,
6501
+ id: "shard-fall",
6502
+ label: "Shard Fall",
6503
+ seed: 214,
6504
+ motionIntensity: "moderate",
6505
+ background: {
6506
+ type: "gradient",
6507
+ stops: [
6508
+ { at: 0, color: "#efe6d6" },
6509
+ { at: 0.55, color: "#e6d6bd" },
6510
+ { at: 1, color: "#d9c39f" }
6511
+ ]
6512
+ },
6513
+ layers: [
6514
+ {
6515
+ key: "shards",
6516
+ count: 26,
6517
+ sprite: {
6518
+ kind: "polygon",
6519
+ points: [
6520
+ [-1, 0.35],
6521
+ [-0.25, -1],
6522
+ [0.85, -0.4],
6523
+ [0.4, 0.9]
6524
+ ],
6525
+ radius: [0.012, 0.03],
6526
+ color: "#b4593a",
6527
+ colors: ["#b4593a", "#7f8a5e", "#5a6b7d", "#8a5a3c"],
6528
+ colorWeights: [2, 2, 1, 2]
6529
+ },
6530
+ motion: { type: "drift", speed: [0.012, 0.032], angle: 90 },
6531
+ alpha: [0.85, 0.95],
6532
+ rotate: [-180, 180],
6533
+ spin: [-35, 35]
6534
+ },
6535
+ {
6536
+ key: "shadows",
6537
+ count: 2,
6538
+ sprite: {
6539
+ kind: "circle",
6540
+ radius: [0.18, 0.22],
6541
+ color: "#5a4a34",
6542
+ soft: true
6543
+ },
6544
+ motion: {
6545
+ type: "wander",
6546
+ speed: [3e-3, 5e-3],
6547
+ meander: 0.04,
6548
+ coherence: 0.6
6549
+ },
6550
+ alpha: [0.2, 0.28],
6551
+ blend: "multiply"
6552
+ }
6553
+ ]
6554
+ };
6555
+
6556
+ // src/examples/murmur.ts
6557
+ var MURMUR_SPEC = {
6558
+ schemaVersion: 1,
6559
+ id: "murmur",
6560
+ label: "Murmur",
6561
+ seed: 512,
6562
+ motionIntensity: "moderate",
6563
+ density: "dense",
6564
+ background: {
6565
+ type: "gradient",
6566
+ stops: [
6567
+ { at: 0, color: "#151a26" },
6568
+ { at: 0.5, color: "#232c3d" },
6569
+ { at: 1, color: "#3a3f52" }
6570
+ ]
6571
+ },
6572
+ layers: [
6573
+ {
6574
+ key: "flock-a",
6575
+ count: 260,
6576
+ sprite: {
6577
+ kind: "streak",
6578
+ length: [4e-3, 0.012],
6579
+ width: 12e-4,
6580
+ color: "#c9d4e6",
6581
+ colors: ["#c9d4e6", "#8fa6c4"],
6582
+ colorWeights: [2, 1]
6583
+ },
6584
+ motion: {
6585
+ type: "wander",
6586
+ speed: [0.015, 0.06],
6587
+ meander: 0.05,
6588
+ coherence: 0.95
6589
+ },
6590
+ alpha: [0.25, 0.6],
6591
+ blend: "screen"
6592
+ },
6593
+ {
6594
+ // The cap is 400 per layer, so a flock above it is two registers of the
6595
+ // same body — slightly different speed and length ranges read as depth.
6596
+ key: "flock-b",
6597
+ count: 260,
6598
+ sprite: {
6599
+ kind: "streak",
6600
+ length: [6e-3, 0.014],
6601
+ width: 12e-4,
6602
+ color: "#8fa6c4",
6603
+ colors: ["#8fa6c4", "#c9d4e6"],
6604
+ colorWeights: [2, 1]
6605
+ },
6606
+ motion: {
6607
+ type: "wander",
6608
+ speed: [0.02, 0.05],
6609
+ meander: 0.045,
6610
+ coherence: 0.93
6611
+ },
6612
+ alpha: [0.2, 0.5],
6613
+ blend: "screen"
6614
+ },
6615
+ {
6616
+ key: "grain",
6617
+ count: 100,
6618
+ sprite: { kind: "circle", radius: [5e-4, 12e-4], color: "#c9d4e6" },
6619
+ motion: { type: "static" },
6620
+ alpha: [0.06, 0.2]
6621
+ }
6622
+ ]
6623
+ };
6624
+
6625
+ // src/examples/three-movements.ts
6626
+ var THREE_MOVEMENTS_SEQUENCE = {
6627
+ format: "idle-sequence",
6628
+ schemaVersion: 1,
6629
+ id: "three-movements",
6630
+ label: "Three Movements",
6631
+ seed: 404,
6632
+ loop: false,
6633
+ sync: "mount",
6634
+ finish: { grain: 0.3, dither: 0.12 },
6635
+ bed: {
6636
+ schemaVersion: 1,
6637
+ id: "three-movements-bed",
6638
+ label: "Three Movements \u2014 bed",
6639
+ background: {
6640
+ type: "field",
6641
+ scale: 2,
6642
+ octaves: 3,
6643
+ warp: 0.4,
6644
+ quantize: 0,
6645
+ bands: ["#0a0d18", "#141c2e", "#233046"],
6646
+ drift: { period: 6e4, amount: 0.25 }
6647
+ },
6648
+ layers: [
6649
+ {
6650
+ key: "motes",
6651
+ count: 12,
6652
+ sprite: {
6653
+ kind: "circle",
6654
+ radius: [12e-4, 3e-3],
6655
+ color: "#9fb8d8",
6656
+ soft: true
6657
+ },
6658
+ motion: { type: "drift", speed: [2e-3, 6e-3], angle: 90 },
6659
+ alpha: [0.1, 0.25]
6660
+ }
6661
+ ]
6662
+ },
6663
+ segments: [
6664
+ {
6665
+ key: "cold-open",
6666
+ duration: 8e3,
6667
+ transition: { type: "morph", dur: 2500, text: "crossfade" },
6668
+ scene: {
6669
+ schemaVersion: 1,
6670
+ id: "three-movements-cold-open",
6671
+ label: "Cold Open",
6672
+ seed: 11,
6673
+ layers: [
6674
+ {
6675
+ key: "caption",
6676
+ count: 1,
6677
+ sprite: {
6678
+ kind: "textBlock",
6679
+ text: "COLD OPEN.\nThe room before anyone arrives.",
6680
+ maxWidth: 0.6,
6681
+ fontSize: 0.028,
6682
+ lineHeight: 1.5,
6683
+ align: "left",
6684
+ anchor: "top-left",
6685
+ font: "monospace",
6686
+ color: "#9fb8d8",
6687
+ opacity: 0.9,
6688
+ reveal: {
6689
+ progress: 1,
6690
+ mode: "typewriter",
6691
+ speed: 12,
6692
+ caret: { blink: 1.1 }
6693
+ }
6694
+ },
6695
+ motion: { type: "static" },
6696
+ position: { x: 0.1, y: 0.4 },
6697
+ alpha: [0.9, 0.9]
6698
+ },
6699
+ {
6700
+ key: "sparks",
6701
+ count: 30,
6702
+ sprite: {
6703
+ kind: "circle",
6704
+ radius: [12e-4, 26e-4],
6705
+ color: "#c9d8e6"
6706
+ },
6707
+ motion: { type: "static" },
6708
+ alpha: [0.15, 0.45],
6709
+ pulse: { amp: 0.12, period: 6e3 }
6710
+ }
6711
+ ]
6712
+ }
6713
+ },
6714
+ {
6715
+ key: "kindle",
6716
+ duration: 9e3,
6717
+ transition: { type: "fade", dur: 3e3 },
6718
+ scene: {
6719
+ schemaVersion: 1,
6720
+ id: "three-movements-kindle",
6721
+ label: "Kindle",
6722
+ seed: 12,
6723
+ layers: [
6724
+ {
6725
+ key: "caption",
6726
+ count: 1,
6727
+ sprite: {
6728
+ kind: "textBlock",
6729
+ text: "KINDLE.\nOne lamp, and then another.",
6730
+ maxWidth: 0.6,
6731
+ fontSize: 0.028,
6732
+ lineHeight: 1.5,
6733
+ align: "left",
6734
+ anchor: "top-left",
6735
+ font: "monospace",
6736
+ color: "#e8b878",
6737
+ opacity: 0.9,
6738
+ reveal: {
6739
+ progress: 1,
6740
+ mode: "typewriter",
6741
+ speed: 12,
6742
+ caret: { blink: 1.1 }
6743
+ }
6744
+ },
6745
+ motion: { type: "static" },
6746
+ position: { x: 0.1, y: 0.4 },
6747
+ alpha: [0.9, 0.9]
6748
+ },
6749
+ {
6750
+ key: "sparks",
6751
+ count: 30,
6752
+ sprite: {
6753
+ kind: "circle",
6754
+ radius: [12e-4, 26e-4],
6755
+ color: "#e8b878"
6756
+ },
6757
+ motion: { type: "static" },
6758
+ alpha: [0.15, 0.45],
6759
+ pulse: { amp: 0.12, period: 6e3 }
6760
+ }
6761
+ ]
6762
+ }
6763
+ },
6764
+ {
6765
+ key: "dusk",
6766
+ scene: {
6767
+ schemaVersion: 1,
6768
+ id: "three-movements-dusk",
6769
+ label: "Dusk",
6770
+ seed: 13,
6771
+ layers: [
6772
+ {
6773
+ key: "bloom",
6774
+ count: 3,
6775
+ sprite: {
6776
+ kind: "circle",
6777
+ radius: [0.09, 0.14],
6778
+ color: "#7a4a5e",
6779
+ colors: ["#7a4a5e", "#b06a4a"],
6780
+ soft: true
6781
+ },
6782
+ motion: {
6783
+ type: "wander",
6784
+ speed: [1e-3, 2e-3],
6785
+ meander: 0.04,
6786
+ coherence: 0.7
6787
+ },
6788
+ alpha: [0.25, 0.4],
6789
+ blend: "lighter",
6790
+ grow: { amp: 0.3, period: 14e3 }
6791
+ },
6792
+ {
6793
+ key: "strokes",
6794
+ count: 8,
6795
+ sprite: {
6796
+ kind: "stroke",
6797
+ length: [0.1, 0.2],
6798
+ points: [
6799
+ [-1, 0.2],
6800
+ [-0.3, -0.6],
6801
+ [0.5, -0.4],
6802
+ [1, 0.2]
6803
+ ],
6804
+ width: 4e-3,
6805
+ taper: true,
6806
+ color: "#c2447a",
6807
+ colors: ["#c2447a", "#8f2c58"]
6808
+ },
6809
+ motion: {
6810
+ type: "drift",
6811
+ speed: [3e-3, 8e-3],
6812
+ angle: 20,
6813
+ bidirectional: true
6814
+ },
6815
+ alpha: [0.3, 0.5],
6816
+ rotate: [-30, 30]
6817
+ }
6818
+ ]
6819
+ }
6820
+ }
6821
+ ]
6822
+ };
6823
+
6189
6824
  // src/examples/facets.ts
6190
6825
  var FACETS_SPEC = {
6191
6826
  schemaVersion: 1,
@@ -7177,6 +7812,71 @@ var WARP_TUNNEL_SPEC = {
7177
7812
  ]
7178
7813
  };
7179
7814
 
7815
+ // src/examples/typed-cue.ts
7816
+ var TYPED_CUE_SPEC = {
7817
+ schemaVersion: 1,
7818
+ id: "typed-cue",
7819
+ label: "Typed Cue",
7820
+ seed: 19,
7821
+ motionIntensity: "calm",
7822
+ background: { type: "solid", color: "#050608" },
7823
+ layers: [
7824
+ {
7825
+ key: "scan",
7826
+ count: 1,
7827
+ sprite: { kind: "rect", width: [1, 1], aspect: [0.02, 0.02], color: "#16241f", feather: 0.9 },
7828
+ motion: { type: "drift", speed: [0.014, 0.014], angle: 90 },
7829
+ alpha: [0.5, 0.5],
7830
+ blend: "screen"
7831
+ },
7832
+ {
7833
+ key: "headline",
7834
+ count: 1,
7835
+ sprite: {
7836
+ kind: "textBlock",
7837
+ text: "THE SCREEN IS AWAKE.\nWORDS ARRIVE ON THEIR OWN CLOCK.",
7838
+ maxWidth: 0.84,
7839
+ fontSize: 0.03,
7840
+ lineHeight: 1.5,
7841
+ align: "left",
7842
+ anchor: "top-left",
7843
+ font: "bold monospace",
7844
+ color: "#e6e8ef",
7845
+ opacity: 0.94,
7846
+ reveal: {
7847
+ progress: 1,
7848
+ mode: "typewriter",
7849
+ speed: 10,
7850
+ caret: { blink: 1.1, color: "#e6e8ef" }
7851
+ }
7852
+ },
7853
+ motion: { type: "static" },
7854
+ position: { x: 0.08, y: 0.16 },
7855
+ alpha: [0.95, 0.95]
7856
+ },
7857
+ {
7858
+ key: "aside",
7859
+ count: 1,
7860
+ sprite: {
7861
+ kind: "textBlock",
7862
+ text: "and leaves the same way \u2014\na dissolve, not a delete.",
7863
+ maxWidth: 0.5,
7864
+ fontSize: 0.022,
7865
+ lineHeight: 1.5,
7866
+ align: "left",
7867
+ anchor: "bottom-right",
7868
+ font: "monospace",
7869
+ color: "#8f96a3",
7870
+ opacity: 0.85,
7871
+ reveal: { progress: 1, mode: "glyphFade", speed: 6, fade: 0.4 }
7872
+ },
7873
+ motion: { type: "static" },
7874
+ position: { x: 0.92, y: 0.86 },
7875
+ alpha: [0.9, 0.9]
7876
+ }
7877
+ ]
7878
+ };
7879
+
7180
7880
  // src/examples/index.ts
7181
7881
  var SCHEMA_EXAMPLES = [
7182
7882
  { id: "aquarium", label: "Aquarium", spec: AQUARIUM_SPEC },
@@ -7199,7 +7899,17 @@ var SCHEMA_EXAMPLES = [
7199
7899
  { id: "facets", label: "Facets", spec: FACETS_SPEC },
7200
7900
  { id: "relay-board", label: "Relay Board", spec: RELAY_BOARD_SPEC },
7201
7901
  { id: "lobby-talk", label: "Lobby Talk", spec: LOBBY_TALK_SPEC },
7202
- { id: "thermal-field", label: "Thermal Field", spec: THERMAL_FIELD_SPEC }
7902
+ { id: "thermal-field", label: "Thermal Field", spec: THERMAL_FIELD_SPEC },
7903
+ { id: "sparse-night", label: "Sparse Night", spec: SPARSE_NIGHT_SPEC },
7904
+ { id: "typed-cue", label: "Typed Cue", spec: TYPED_CUE_SPEC },
7905
+ { id: "signal-board", label: "Signal Board", spec: SIGNAL_BOARD_SPEC },
7906
+ { id: "phase-duet", label: "Phase Duet", spec: PHASE_DUET_SPEC },
7907
+ { id: "web-work", label: "Web Work", spec: WEB_WORK_SPEC },
7908
+ { id: "shard-fall", label: "Shard Fall", spec: SHARD_FALL_SPEC },
7909
+ { id: "murmur", label: "Murmur", spec: MURMUR_SPEC }
7910
+ ];
7911
+ var EXAMPLE_SEQUENCES = [
7912
+ { id: "three-movements", label: "Three Movements", sequence: THREE_MOVEMENTS_SEQUENCE }
7203
7913
  ];
7204
7914
  var EXAMPLE_SPECS = SCHEMA_EXAMPLES.map((e) => e.spec);
7205
7915
  var EXAMPLE_BY_ID = Object.fromEntries(
@@ -7215,6 +7925,7 @@ export {
7215
7925
  DITHER_ALPHA,
7216
7926
  DITHER_TILE,
7217
7927
  EXAMPLE_BY_ID,
7928
+ EXAMPLE_SEQUENCES,
7218
7929
  EXAMPLE_SPECS,
7219
7930
  FACETS_SPEC,
7220
7931
  FIELD_BUCKET_MS,
@@ -7229,8 +7940,10 @@ export {
7229
7940
  LIMITS,
7230
7941
  LOBBY_TALK_SPEC,
7231
7942
  MATRIX_RAIN_SPEC,
7943
+ MURMUR_SPEC,
7232
7944
  NOSTALGHIA_CANDLE_SPEC,
7233
7945
  ORRERY_SPEC,
7946
+ PHASE_DUET_SPEC,
7234
7947
  PINGS_SPEC,
7235
7948
  POLYGONS_SPEC,
7236
7949
  PROCESSION_SPEC,
@@ -7239,11 +7952,17 @@ export {
7239
7952
  SAKURA_SPEC,
7240
7953
  SCHEMA_EXAMPLES,
7241
7954
  SCHEMA_VERSION,
7955
+ SHARD_FALL_SPEC,
7956
+ SIGNAL_BOARD_SPEC,
7242
7957
  SNOWFALL_SPEC,
7958
+ SPARSE_NIGHT_SPEC,
7243
7959
  THERMAL_FIELD_SPEC,
7960
+ THREE_MOVEMENTS_SEQUENCE,
7961
+ TYPED_CUE_SPEC,
7244
7962
  WARP_MAX_SCALE,
7245
7963
  WARP_NEAR,
7246
7964
  WARP_TUNNEL_SPEC,
7965
+ WEB_WORK_SPEC,
7247
7966
  adviseSequence,
7248
7967
  adviseSpec,
7249
7968
  alphaAt,
@@ -7279,6 +7998,7 @@ export {
7279
7998
  hasHotSwapSequence,
7280
7999
  headingAt,
7281
8000
  hexToRgb255,
8001
+ ignoredPropertyPaths,
7282
8002
  latticeHash,
7283
8003
  layerCohesion,
7284
8004
  lerpSpec,
@@ -7309,6 +8029,7 @@ export {
7309
8029
  segmentStart,
7310
8030
  sequenceSteerablePaths,
7311
8031
  sequenceSwapCompatible,
8032
+ sequenceWantsFinish,
7312
8033
  sizeAt,
7313
8034
  spriteIndexAt,
7314
8035
  spriteVariants,