@idle-screens/schema 1.0.0 → 2.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -292,6 +292,99 @@ function positionAt(e, t, w, h) {
292
292
  import {
293
293
  createRng
294
294
  } from "@idle-screens/core";
295
+
296
+ // src/steer.ts
297
+ var UNSAFE_KEYS = /* @__PURE__ */ new Set(["__proto__", "constructor", "prototype"]);
298
+ function resolveSpecPath(spec, path) {
299
+ if (!spec || typeof spec !== "object" || !path) return null;
300
+ const parts = path.split(".");
301
+ if (parts.some((p) => UNSAFE_KEYS.has(p))) return null;
302
+ const s = spec;
303
+ if (parts[0] !== "layers" && parts[0] !== "background" && Array.isArray(s.layers)) {
304
+ const idx = s.layers.findIndex((l) => l && l.key === parts[0]);
305
+ if (idx === -1) return null;
306
+ parts.splice(0, 1, "layers", String(idx));
307
+ }
308
+ let node = spec;
309
+ for (let i = 0; i < parts.length - 1; i++) {
310
+ if (node === null || typeof node !== "object") return null;
311
+ node = node[parts[i]];
312
+ }
313
+ if (node === null || typeof node !== "object") return null;
314
+ const last = parts[parts.length - 1];
315
+ const key = Array.isArray(node) ? Number(last) : last;
316
+ const exists = Array.isArray(node) ? Number.isInteger(key) && key >= 0 && key < node.length : last in node;
317
+ return exists ? { parent: node, key } : null;
318
+ }
319
+ function applyDeltasToSpec(spec, deltas) {
320
+ const copy = JSON.parse(JSON.stringify(spec));
321
+ for (const d of deltas) {
322
+ const loc = resolveSpecPath(copy, d.path);
323
+ if (loc) loc.parent[loc.key] = d.value;
324
+ }
325
+ return copy;
326
+ }
327
+ var HEX2 = /^#([0-9a-fA-F]{3}|[0-9a-fA-F]{6})$/;
328
+ function hexToRgb(hex) {
329
+ const h = hex.length === 4 ? `#${hex[1]}${hex[1]}${hex[2]}${hex[2]}${hex[3]}${hex[3]}` : hex;
330
+ const n = parseInt(h.slice(1), 16);
331
+ return [n >> 16 & 255, n >> 8 & 255, n & 255];
332
+ }
333
+ function lerpHex(a, b, k) {
334
+ const ca = hexToRgb(a);
335
+ const cb = hexToRgb(b);
336
+ const mix = ca.map((v, i) => Math.round(v + (cb[i] - v) * k));
337
+ return `#${mix.map((v) => v.toString(16).padStart(2, "0")).join("")}`;
338
+ }
339
+ function lerpSpec(from, to, k) {
340
+ const kk = Math.max(0, Math.min(1, k));
341
+ const walk = (a, b, key) => {
342
+ if (typeof a === "number" && typeof b === "number") {
343
+ const v = a + (b - a) * kk;
344
+ return key === "count" ? Math.max(1, Math.round(v)) : v;
345
+ }
346
+ if (typeof a === "string" && typeof b === "string" && HEX2.test(a) && HEX2.test(b)) {
347
+ return lerpHex(a, b, kk);
348
+ }
349
+ if (Array.isArray(a) && Array.isArray(b) && a.length === b.length) {
350
+ return b.map((bv, i) => walk(a[i], bv, i));
351
+ }
352
+ if (a && b && typeof a === "object" && typeof b === "object" && !Array.isArray(a) && !Array.isArray(b)) {
353
+ const out = {};
354
+ for (const kName of Object.keys(b)) {
355
+ out[kName] = walk(a[kName], b[kName], kName);
356
+ }
357
+ return out;
358
+ }
359
+ return kk > 0 ? b : a;
360
+ };
361
+ return walk(from, to);
362
+ }
363
+ function easeSmooth(k) {
364
+ const c = Math.max(0, Math.min(1, k));
365
+ return c * c * (3 - 2 * c);
366
+ }
367
+ function structuralSignature(spec) {
368
+ return JSON.stringify(
369
+ spec.layers.map((l) => [
370
+ l.count,
371
+ l.size,
372
+ l.region,
373
+ l.position,
374
+ l.motion,
375
+ l.wrap,
376
+ l.flip,
377
+ l.alpha,
378
+ l.pulse,
379
+ l.sprite.kind,
380
+ l.sprite.kind === "circle" ? l.sprite.radius : void 0,
381
+ l.sprite.kind === "emoji" ? l.sprite.glyphs.length : l.sprite.kind === "text" ? l.sprite.strings.length : void 0
382
+ ])
383
+ );
384
+ }
385
+
386
+ // src/compile.ts
387
+ var DEFAULT_STEER_DUR = 1e3;
295
388
  function hexToRgba(hex, alpha) {
296
389
  const h = hex.length === 4 ? `#${hex[1]}${hex[1]}${hex[2]}${hex[2]}${hex[3]}${hex[3]}` : hex;
297
390
  const n = parseInt(h.slice(1), 16);
@@ -310,12 +403,14 @@ function manifestFor(spec) {
310
403
  reducedMotionFallback: "static",
311
404
  // Flash-safe by construction: static background + bounded sprites, no strobe
312
405
  // primitive. Proven by sampling a compiled spec through @idle-screens/validator.
313
- a11y: { flashSafe: true }
406
+ a11y: { flashSafe: true },
407
+ workerReady: true
314
408
  };
315
409
  }
316
410
  var SpecInstance = class {
317
411
  constructor(spec, ctx) {
318
412
  this.spec = spec;
413
+ this.effSpec = spec;
319
414
  this.saverCtx = ctx;
320
415
  this.seed = (spec.seed ?? ctx.seed) >>> 0 || 1;
321
416
  let canvas;
@@ -354,6 +449,11 @@ var SpecInstance = class {
354
449
  baseT = 0;
355
450
  // elapsed logical time carried across pause/resume
356
451
  lastT = 0;
452
+ /** The spec currently being rendered (base spec + any applied steering). */
453
+ effSpec;
454
+ /** Active glide between two resolved specs (live setParam/applyTrack). */
455
+ transition = null;
456
+ lastStructural = "";
357
457
  sizeCanvas() {
358
458
  const dpr = Math.min(this.saverCtx.dpr, 2);
359
459
  this.canvas.width = Math.max(1, Math.round(this.w * dpr));
@@ -363,7 +463,8 @@ var SpecInstance = class {
363
463
  /** (Re)seed and place all entities — deterministic for the seed + size. */
364
464
  rebuild() {
365
465
  const rng = createRng(this.seed);
366
- this.layers = this.spec.layers.map((layer) => ({ layer, entities: buildEntities(layer, rng, this.w, this.h) }));
466
+ this.layers = this.effSpec.layers.map((layer) => ({ layer, entities: buildEntities(layer, rng, this.w, this.h) }));
467
+ this.lastStructural = structuralSignature(this.effSpec);
367
468
  }
368
469
  start() {
369
470
  if (this.frameId !== null || typeof requestAnimationFrame === "undefined") return;
@@ -385,7 +486,7 @@ var SpecInstance = class {
385
486
  }
386
487
  drawBackground() {
387
488
  const { ctx, w, h } = this;
388
- const bg = this.spec.background;
489
+ const bg = this.effSpec.background;
389
490
  if (!bg || bg.type === "solid") {
390
491
  ctx.fillStyle = bg?.color ?? "#05050a";
391
492
  ctx.fillRect(0, 0, w, h);
@@ -440,8 +541,47 @@ var SpecInstance = class {
440
541
  }
441
542
  ctx.restore();
442
543
  }
544
+ /** Advance any live steering glide; rebuild entities on structural change. */
545
+ stepTransition(t) {
546
+ const tr = this.transition;
547
+ if (!tr) return;
548
+ const k = tr.dur <= 0 ? 1 : (t - tr.startT) / tr.dur;
549
+ this.effSpec = k >= 1 ? tr.to : lerpSpec(tr.from, tr.to, easeSmooth(k));
550
+ if (k >= 1) this.transition = null;
551
+ const sig = structuralSignature(this.effSpec);
552
+ if (sig !== this.lastStructural) this.rebuild();
553
+ else this.layers.forEach((b, i) => {
554
+ b.layer = this.effSpec.layers[i] ?? b.layer;
555
+ });
556
+ }
557
+ /**
558
+ * Live steering: glide from what's currently rendered to the track's target
559
+ * state (deltas applied last-wins). Duration = the longest delta `dur`.
560
+ */
561
+ applyTrack(track) {
562
+ const deltas = track?.deltas ?? [];
563
+ const target = applyDeltasToSpec(this.effSpec, deltas);
564
+ if (!validateSpec(target).valid) return;
565
+ const dur = deltas.length ? deltas.reduce((m, d) => Math.max(m, d.dur ?? DEFAULT_STEER_DUR), 0) : DEFAULT_STEER_DUR;
566
+ this.transition = {
567
+ from: JSON.parse(JSON.stringify(this.effSpec)),
568
+ to: target,
569
+ startT: this.lastT,
570
+ dur
571
+ };
572
+ if (this.paused) {
573
+ this.transition = null;
574
+ this.effSpec = target;
575
+ if (structuralSignature(this.effSpec) !== this.lastStructural) this.rebuild();
576
+ else this.layers.forEach((b, i) => {
577
+ b.layer = this.effSpec.layers[i] ?? b.layer;
578
+ });
579
+ this.renderFrame(this.lastT, this.seed);
580
+ }
581
+ }
443
582
  /** Deterministic, frame-addressable render (shared by the rAF loop). */
444
583
  renderFrame(t, _seed) {
584
+ this.stepTransition(t);
445
585
  const { ctx } = this;
446
586
  ctx.globalAlpha = 1;
447
587
  ctx.globalCompositeOperation = "source-over";
@@ -483,7 +623,7 @@ function compileSaver(spec) {
483
623
  };
484
624
  }
485
625
 
486
- // src/examples.ts
626
+ // src/examples/aquarium.ts
487
627
  var AQUARIUM_SPEC = {
488
628
  schemaVersion: 1,
489
629
  id: "aquarium",
@@ -514,185 +654,8 @@ var AQUARIUM_SPEC = {
514
654
  }
515
655
  ]
516
656
  };
517
- var RAIN_SPEC = {
518
- schemaVersion: 1,
519
- id: "rain",
520
- label: "Rain",
521
- seed: 7,
522
- motionIntensity: "moderate",
523
- background: { type: "solid", color: "#05070a" },
524
- layers: [
525
- {
526
- count: 140,
527
- sprite: { kind: "text", strings: ["\u2502"], color: "#9fd0ff" },
528
- size: [12, 26],
529
- motion: { type: "drift", angle: 90, speed: [520, 900] }
530
- }
531
- ]
532
- };
533
- var SNOWFALL_SPEC = {
534
- schemaVersion: 1,
535
- id: "snowfall",
536
- label: "Snowfall",
537
- seed: 12,
538
- motionIntensity: "calm",
539
- background: {
540
- type: "gradient",
541
- stops: [
542
- { at: 0, color: "#0a1628" },
543
- { at: 0.7, color: "#0d1f3c" },
544
- { at: 1, color: "#121212" }
545
- ]
546
- },
547
- layers: [
548
- {
549
- count: 50,
550
- sprite: { kind: "circle", radius: [1, 2.5], color: "#8899aa" },
551
- motion: { type: "drift", angle: 90, speed: [15, 40], bob: 3 }
552
- },
553
- {
554
- count: 35,
555
- sprite: { kind: "circle", radius: [2, 4.5], color: "#c0cdd8" },
556
- motion: { type: "drift", angle: 85, speed: [35, 80], bob: 6 }
557
- },
558
- {
559
- count: 15,
560
- sprite: { kind: "circle", radius: [3.5, 7], color: "#e8eff5" },
561
- motion: { type: "drift", angle: 82, speed: [55, 120], bob: 10 }
562
- }
563
- ]
564
- };
565
- var LANTERNS_SPEC = {
566
- schemaVersion: 1,
567
- id: "lanterns",
568
- label: "Night Lanterns",
569
- seed: 88,
570
- motionIntensity: "calm",
571
- background: {
572
- type: "gradient",
573
- stops: [
574
- { at: 0, color: "#04060f" },
575
- { at: 0.55, color: "#0b1026" },
576
- { at: 0.85, color: "#251731" },
577
- { at: 1, color: "#472518" }
578
- ]
579
- },
580
- layers: [
581
- {
582
- count: 60,
583
- sprite: { kind: "circle", radius: [0.5, 1.4], color: "#8fa0c8" },
584
- alpha: [0.35, 1],
585
- region: { y: [0, 0.62] },
586
- motion: { type: "drift", speed: [0.5, 2], bob: 1 }
587
- },
588
- {
589
- count: 36,
590
- sprite: {
591
- kind: "circle",
592
- radius: [1.5, 3],
593
- color: "#b06a2a",
594
- soft: true
595
- },
596
- alpha: [0.5, 0.9],
597
- blend: "lighter",
598
- pulse: { amp: 0.18, period: 2800 },
599
- motion: { type: "rise", speed: [6, 14], sway: 4 }
600
- },
601
- {
602
- count: 14,
603
- sprite: {
604
- kind: "circle",
605
- radius: [3.5, 6.5],
606
- color: "#e08a34",
607
- soft: true
608
- },
609
- alpha: [0.6, 1],
610
- blend: "lighter",
611
- pulse: { amp: 0.22, period: 3400 },
612
- motion: { type: "rise", speed: [16, 28], sway: 7 }
613
- },
614
- {
615
- count: 8,
616
- sprite: { kind: "emoji", glyphs: ["\u{1F3EE}"] },
617
- size: [26, 44],
618
- alpha: [0.85, 1],
619
- motion: { type: "rise", speed: [30, 48], sway: 10 }
620
- },
621
- {
622
- count: 4,
623
- sprite: { kind: "emoji", glyphs: ["\u{1F3EE}"] },
624
- size: [58, 84],
625
- motion: { type: "rise", speed: [52, 74], sway: 14 }
626
- },
627
- {
628
- count: 12,
629
- sprite: { kind: "circle", radius: [2, 5], color: "#e08a34", soft: true },
630
- alpha: [0.12, 0.35],
631
- blend: "lighter",
632
- region: { y: [0.93, 1] },
633
- pulse: { amp: 0.1, period: 2200 },
634
- motion: { type: "drift", speed: [2, 6], bob: 2 }
635
- }
636
- ]
637
- };
638
- var SAKURA_SPEC = {
639
- schemaVersion: 1,
640
- id: "sakura",
641
- label: "Sakura Drift",
642
- seed: 314,
643
- motionIntensity: "calm",
644
- background: {
645
- type: "gradient",
646
- stops: [
647
- { at: 0, color: "#1b1d38" },
648
- { at: 0.45, color: "#3a2645" },
649
- { at: 0.8, color: "#7d3d4e" },
650
- { at: 1, color: "#0f140d" }
651
- ],
652
- band: { color: "#0c140d", height: 44 }
653
- },
654
- layers: [
655
- {
656
- count: 60,
657
- sprite: { kind: "circle", radius: [0.6, 1.6], color: "#ffe3ec", soft: true },
658
- alpha: [0.3, 0.9],
659
- blend: "lighter",
660
- region: { y: [0, 0.72] },
661
- pulse: { amp: 0.22, period: 3e3 },
662
- motion: { type: "drift", speed: [0.3, 1.2], bob: 1 }
663
- },
664
- {
665
- count: 28,
666
- sprite: { kind: "emoji", glyphs: ["\u{1F338}"] },
667
- size: [13, 20],
668
- alpha: [0.5, 0.8],
669
- motion: { type: "drift", speed: [12, 26], angle: 100, bob: 3 }
670
- },
671
- {
672
- count: 18,
673
- sprite: { kind: "emoji", glyphs: ["\u{1F338}"] },
674
- size: [20, 32],
675
- alpha: [0.7, 0.95],
676
- motion: { type: "drift", speed: [24, 44], angle: 100, bob: 6 }
677
- },
678
- {
679
- count: 10,
680
- sprite: { kind: "emoji", glyphs: ["\u{1F338}"] },
681
- size: [34, 54],
682
- alpha: [0.85, 1],
683
- motion: { type: "drift", speed: [42, 68], angle: 100, bob: 11 }
684
- },
685
- {
686
- count: 16,
687
- sprite: { kind: "circle", radius: [1.5, 4], color: "#ff9bb5", soft: true },
688
- alpha: [0.1, 0.3],
689
- blend: "lighter",
690
- region: { y: [0.9, 1] },
691
- pulse: { amp: 0.15, period: 2600 },
692
- motion: { type: "drift", speed: [0.3, 1.5], angle: 180, bob: 1 }
693
- }
694
- ]
695
- };
657
+
658
+ // src/examples/dev-dashboard.ts
696
659
  var DASHBOARD_SPEC = {
697
660
  schemaVersion: 1,
698
661
  id: "dev-dashboard",
@@ -1154,7 +1117,7 @@ var DASHBOARD_SPEC = {
1154
1117
  position: { x: 0.06, y: 0.92 },
1155
1118
  sprite: {
1156
1119
  kind: "text",
1157
- strings: ["14:03 Edit examples.ts +84 -1"],
1120
+ strings: ["14:03 Edit examples/dev-dashboard.ts +84 -1"],
1158
1121
  color: "#445544",
1159
1122
  font: "10px monospace",
1160
1123
  align: "left",
@@ -1180,31 +1143,231 @@ var DASHBOARD_SPEC = {
1180
1143
  }
1181
1144
  ]
1182
1145
  };
1183
- var EXAMPLE_SPECS = [
1184
- AQUARIUM_SPEC,
1185
- RAIN_SPEC,
1186
- SNOWFALL_SPEC,
1187
- LANTERNS_SPEC,
1188
- SAKURA_SPEC,
1189
- DASHBOARD_SPEC
1146
+
1147
+ // src/examples/lanterns.ts
1148
+ var LANTERNS_SPEC = {
1149
+ schemaVersion: 1,
1150
+ id: "lanterns",
1151
+ label: "Night Lanterns",
1152
+ seed: 88,
1153
+ motionIntensity: "calm",
1154
+ background: {
1155
+ type: "gradient",
1156
+ stops: [
1157
+ { at: 0, color: "#04060f" },
1158
+ { at: 0.55, color: "#0b1026" },
1159
+ { at: 0.85, color: "#251731" },
1160
+ { at: 1, color: "#472518" }
1161
+ ]
1162
+ },
1163
+ layers: [
1164
+ {
1165
+ count: 60,
1166
+ sprite: { kind: "circle", radius: [0.5, 1.4], color: "#8fa0c8" },
1167
+ alpha: [0.35, 1],
1168
+ region: { y: [0, 0.62] },
1169
+ motion: { type: "drift", speed: [0.5, 2], bob: 1 }
1170
+ },
1171
+ {
1172
+ count: 36,
1173
+ sprite: {
1174
+ kind: "circle",
1175
+ radius: [1.5, 3],
1176
+ color: "#b06a2a",
1177
+ soft: true
1178
+ },
1179
+ alpha: [0.5, 0.9],
1180
+ blend: "lighter",
1181
+ pulse: { amp: 0.18, period: 2800 },
1182
+ motion: { type: "rise", speed: [6, 14], sway: 4 }
1183
+ },
1184
+ {
1185
+ count: 14,
1186
+ sprite: {
1187
+ kind: "circle",
1188
+ radius: [3.5, 6.5],
1189
+ color: "#e08a34",
1190
+ soft: true
1191
+ },
1192
+ alpha: [0.6, 1],
1193
+ blend: "lighter",
1194
+ pulse: { amp: 0.22, period: 3400 },
1195
+ motion: { type: "rise", speed: [16, 28], sway: 7 }
1196
+ },
1197
+ {
1198
+ count: 8,
1199
+ sprite: { kind: "emoji", glyphs: ["\u{1F3EE}"] },
1200
+ size: [26, 44],
1201
+ alpha: [0.85, 1],
1202
+ motion: { type: "rise", speed: [30, 48], sway: 10 }
1203
+ },
1204
+ {
1205
+ count: 4,
1206
+ sprite: { kind: "emoji", glyphs: ["\u{1F3EE}"] },
1207
+ size: [58, 84],
1208
+ motion: { type: "rise", speed: [52, 74], sway: 14 }
1209
+ },
1210
+ {
1211
+ count: 12,
1212
+ sprite: { kind: "circle", radius: [2, 5], color: "#e08a34", soft: true },
1213
+ alpha: [0.12, 0.35],
1214
+ blend: "lighter",
1215
+ region: { y: [0.93, 1] },
1216
+ pulse: { amp: 0.1, period: 2200 },
1217
+ motion: { type: "drift", speed: [2, 6], bob: 2 }
1218
+ }
1219
+ ]
1220
+ };
1221
+
1222
+ // src/examples/rain.ts
1223
+ var RAIN_SPEC = {
1224
+ schemaVersion: 1,
1225
+ id: "rain",
1226
+ label: "Rain",
1227
+ seed: 7,
1228
+ motionIntensity: "moderate",
1229
+ background: { type: "solid", color: "#05070a" },
1230
+ layers: [
1231
+ {
1232
+ count: 140,
1233
+ sprite: { kind: "text", strings: ["\u2502"], color: "#9fd0ff" },
1234
+ size: [12, 26],
1235
+ motion: { type: "drift", angle: 90, speed: [520, 900] }
1236
+ }
1237
+ ]
1238
+ };
1239
+
1240
+ // src/examples/sakura.ts
1241
+ var SAKURA_SPEC = {
1242
+ schemaVersion: 1,
1243
+ id: "sakura",
1244
+ label: "Sakura Drift",
1245
+ seed: 314,
1246
+ motionIntensity: "calm",
1247
+ background: {
1248
+ type: "gradient",
1249
+ stops: [
1250
+ { at: 0, color: "#1b1d38" },
1251
+ { at: 0.45, color: "#3a2645" },
1252
+ { at: 0.8, color: "#7d3d4e" },
1253
+ { at: 1, color: "#0f140d" }
1254
+ ],
1255
+ band: { color: "#0c140d", height: 44 }
1256
+ },
1257
+ layers: [
1258
+ {
1259
+ count: 60,
1260
+ sprite: { kind: "circle", radius: [0.6, 1.6], color: "#ffe3ec", soft: true },
1261
+ alpha: [0.3, 0.9],
1262
+ blend: "lighter",
1263
+ region: { y: [0, 0.72] },
1264
+ pulse: { amp: 0.22, period: 3e3 },
1265
+ motion: { type: "drift", speed: [0.3, 1.2], bob: 1 }
1266
+ },
1267
+ {
1268
+ count: 28,
1269
+ sprite: { kind: "emoji", glyphs: ["\u{1F338}"] },
1270
+ size: [13, 20],
1271
+ alpha: [0.5, 0.8],
1272
+ motion: { type: "drift", speed: [12, 26], angle: 100, bob: 3 }
1273
+ },
1274
+ {
1275
+ count: 18,
1276
+ sprite: { kind: "emoji", glyphs: ["\u{1F338}"] },
1277
+ size: [20, 32],
1278
+ alpha: [0.7, 0.95],
1279
+ motion: { type: "drift", speed: [24, 44], angle: 100, bob: 6 }
1280
+ },
1281
+ {
1282
+ count: 10,
1283
+ sprite: { kind: "emoji", glyphs: ["\u{1F338}"] },
1284
+ size: [34, 54],
1285
+ alpha: [0.85, 1],
1286
+ motion: { type: "drift", speed: [42, 68], angle: 100, bob: 11 }
1287
+ },
1288
+ {
1289
+ count: 16,
1290
+ sprite: { kind: "circle", radius: [1.5, 4], color: "#ff9bb5", soft: true },
1291
+ alpha: [0.1, 0.3],
1292
+ blend: "lighter",
1293
+ region: { y: [0.9, 1] },
1294
+ pulse: { amp: 0.15, period: 2600 },
1295
+ motion: { type: "drift", speed: [0.3, 1.5], angle: 180, bob: 1 }
1296
+ }
1297
+ ]
1298
+ };
1299
+
1300
+ // src/examples/snowfall.ts
1301
+ var SNOWFALL_SPEC = {
1302
+ schemaVersion: 1,
1303
+ id: "snowfall",
1304
+ label: "Snowfall",
1305
+ seed: 12,
1306
+ motionIntensity: "calm",
1307
+ background: {
1308
+ type: "gradient",
1309
+ stops: [
1310
+ { at: 0, color: "#0a1628" },
1311
+ { at: 0.7, color: "#0d1f3c" },
1312
+ { at: 1, color: "#121212" }
1313
+ ]
1314
+ },
1315
+ layers: [
1316
+ {
1317
+ count: 50,
1318
+ sprite: { kind: "circle", radius: [1, 2.5], color: "#8899aa" },
1319
+ motion: { type: "drift", angle: 90, speed: [15, 40], bob: 3 }
1320
+ },
1321
+ {
1322
+ count: 35,
1323
+ sprite: { kind: "circle", radius: [2, 4.5], color: "#c0cdd8" },
1324
+ motion: { type: "drift", angle: 85, speed: [35, 80], bob: 6 }
1325
+ },
1326
+ {
1327
+ count: 15,
1328
+ sprite: { kind: "circle", radius: [3.5, 7], color: "#e8eff5" },
1329
+ motion: { type: "drift", angle: 82, speed: [55, 120], bob: 10 }
1330
+ }
1331
+ ]
1332
+ };
1333
+
1334
+ // src/examples/index.ts
1335
+ var SCHEMA_EXAMPLES = [
1336
+ { id: "aquarium", label: "Aquarium", spec: AQUARIUM_SPEC },
1337
+ { id: "rain", label: "Rain", spec: RAIN_SPEC },
1338
+ { id: "snowfall", label: "Snowfall", spec: SNOWFALL_SPEC },
1339
+ { id: "lanterns", label: "Night Lanterns", spec: LANTERNS_SPEC },
1340
+ { id: "sakura", label: "Sakura Drift", spec: SAKURA_SPEC },
1341
+ { id: "dev-dashboard", label: "Dev Dashboard", spec: DASHBOARD_SPEC }
1190
1342
  ];
1343
+ var EXAMPLE_SPECS = SCHEMA_EXAMPLES.map((e) => e.spec);
1344
+ var EXAMPLE_BY_ID = Object.fromEntries(
1345
+ SCHEMA_EXAMPLES.map((e) => [e.id, e.spec])
1346
+ );
1191
1347
  export {
1192
1348
  AQUARIUM_SPEC,
1193
1349
  DASHBOARD_SPEC,
1350
+ EXAMPLE_BY_ID,
1194
1351
  EXAMPLE_SPECS,
1195
1352
  LANTERNS_SPEC,
1196
1353
  LIMITS,
1197
1354
  RAIN_SPEC,
1198
1355
  SAKURA_SPEC,
1356
+ SCHEMA_EXAMPLES,
1199
1357
  SCHEMA_VERSION,
1200
1358
  SNOWFALL_SPEC,
1201
1359
  alphaAt,
1360
+ applyDeltasToSpec,
1202
1361
  assertValidSpec,
1203
1362
  buildEntities,
1204
1363
  compileSaver,
1364
+ easeSmooth,
1365
+ lerpSpec,
1205
1366
  manifestFor,
1206
1367
  positionAt,
1368
+ resolveSpecPath,
1207
1369
  spriteVariants,
1370
+ structuralSignature,
1208
1371
  validateSpec
1209
1372
  };
1210
1373
  //# sourceMappingURL=index.js.map