@idle-screens/schema 3.6.1 → 3.7.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.d.ts CHANGED
@@ -1,4 +1,4 @@
1
- import { Rng, SaverPlugin, SaverManifest } from '@idle-screens/core';
1
+ import { Rng, SaverContext, SaverPlugin, SaverManifest } from '@idle-screens/core';
2
2
 
3
3
  /**
4
4
  * Declarative, agent-authorable saver format. A `SaverSpec` describes a saver as DATA
@@ -291,6 +291,8 @@ type SpriteSpec = {
291
291
  baseline?: 'top' | 'middle' | 'bottom';
292
292
  maxWidth?: number;
293
293
  cycle?: CycleSpec;
294
+ /** See `TextRole`. Absent ⇒ no legibility advisories, no pixel change. */
295
+ role?: TextRole;
294
296
  }
295
297
  /** `soft` renders a radial falloff (glow orb) instead of a hard disc.
296
298
  * `colorWeights` (same length as `colors`) biases the seeded per-entity pick —
@@ -409,13 +411,49 @@ type SpriteSpec = {
409
411
  | {
410
412
  kind: 'textBlock';
411
413
  text: string;
414
+ /** Wrap width as a fraction of `min(w,h)` (up to 2.0 — `text-off-screen` catches overflow). */
412
415
  maxWidth: number;
413
416
  fontSize: number;
414
417
  lineHeight?: number;
418
+ /** Moves the painted lines inside the wrap width (ragged edge); never the block. */
415
419
  align?: 'left' | 'center' | 'right';
416
420
  color?: string;
417
421
  reveal?: TextRevealSpec;
422
+ /**
423
+ * Which point of the rendered text (widest line × lines·lineHeight, as
424
+ * `align` lays it out) `position` names. Absent: today's behaviour —
425
+ * `position` is the top-left of the `maxWidth` layout box. With
426
+ * `'center'` the block is centred at `position` on every aspect ratio.
427
+ * Placement, so it is in the structural signature.
428
+ */
429
+ anchor?: TextBlockAnchor;
430
+ /**
431
+ * CSS font family and/or weight/style only (`"bold monospace"`,
432
+ * `"300 'Inter', sans-serif"`). A size inside it is rejected —
433
+ * `fontSize` owns size. Absent: `system-ui, sans-serif`.
434
+ */
435
+ font?: string;
436
+ /**
437
+ * 0..1 multiplier on the block's paint alpha (default 1). Paint, not
438
+ * carpentry: excluded from the structural signature, so steering it
439
+ * with `dur` glides the block in or out without a rebuild. Declare it
440
+ * (`"opacity": 1`) to make the path steerable.
441
+ */
442
+ opacity?: number;
443
+ /** See `TextRole`. Absent ⇒ no legibility advisories, no pixel change. */
444
+ role?: TextRole;
418
445
  };
446
+ /**
447
+ * What a text layer is *for* — a declaration, not a pixel. `read` says the
448
+ * words must be readable from across the room and opts the layer into
449
+ * `adviseSpec`'s legibility advisories (`text-legibility`, `text-safe-area`).
450
+ * `atmosphere` says the text is texture (a haiku fading in a corner, dim
451
+ * labels on a wall board) and is the same as absent: silent. Changes no
452
+ * pixel anywhere, on any client; never part of the structural signature.
453
+ */
454
+ type TextRole = 'read' | 'atmosphere';
455
+ /** Compass points of a `textBlock`'s rendered box that `position` may name. */
456
+ type TextBlockAnchor = 'top-left' | 'top' | 'top-right' | 'left' | 'center' | 'right' | 'bottom-left' | 'bottom' | 'bottom-right';
419
457
  /**
420
458
  * Animated typing/deleting for `textBlock`. Layout always runs on the FULL
421
459
  * text — reveal only masks which glyphs are painted, so lines never reflow
@@ -582,6 +620,20 @@ interface SpecWarning {
582
620
  path: string;
583
621
  code: string;
584
622
  message: string;
623
+ /**
624
+ * Viewport-fraction boxes (`x`, `y`, `w`, `h` of `width`/`height`) the
625
+ * warning is about — `text-overlap` carries the two text boxes so an agent
626
+ * can move one without re-deriving the layout. Present only where a
627
+ * warning has geometry to report.
628
+ */
629
+ boxes?: WarningBox[];
630
+ }
631
+ /** A rectangle in viewport fractions (x/w of width, y/h of height). */
632
+ interface WarningBox {
633
+ x: number;
634
+ y: number;
635
+ w: number;
636
+ h: number;
585
637
  }
586
638
  /** Perf/safety caps enforced by `validateSpec`. */
587
639
  declare const LIMITS: {
@@ -613,7 +665,7 @@ declare const LIMITS: {
613
665
  readonly maxTextBlockLength: 2000;
614
666
  readonly minTextBlockFontSize: 0.01;
615
667
  readonly maxTextBlockFontSize: 0.2;
616
- readonly maxTextBlockMaxWidth: 1;
668
+ readonly maxTextBlockMaxWidth: 2;
617
669
  readonly maxRevealSpeed: 120;
618
670
  readonly maxCaretBlinkHz: 3;
619
671
  readonly maxSegments: 24;
@@ -637,9 +689,30 @@ declare const LIMITS: {
637
689
  };
638
690
  type SequenceTransition = {
639
691
  type: 'cut';
640
- } | {
692
+ }
693
+ /**
694
+ * Interpolate numbers and hex colours into the next (structurally
695
+ * identical) segment over `dur` ms. Strings step on the first frame —
696
+ * unless `text: 'crossfade'`, which draws each `text` / `textBlock` layer
697
+ * whose string(s) differ twice for the window: the outgoing string at
698
+ * `1 − k`, the incoming at `k` (k = the morph's eased progress). Default
699
+ * `'step'`, today's behaviour, byte for byte.
700
+ */
701
+ | {
641
702
  type: 'morph';
642
703
  dur: number;
704
+ text?: 'step' | 'crossfade';
705
+ }
706
+ /**
707
+ * Cross-fade into the next segment over `dur` ms: the outgoing segment
708
+ * stays alive on its own canvas and is composited over the incoming one
709
+ * at `1 − easeSmooth(localT / dur)`. Works between unlike segments (no
710
+ * structural requirement). Hosts on the `basic`/`minimal` capability tier
711
+ * render it as `cut` (see `SequenceMountContext.capabilityTier`).
712
+ */
713
+ | {
714
+ type: 'fade';
715
+ dur: number;
643
716
  };
644
717
  interface SequenceSegment {
645
718
  key: string;
@@ -657,6 +730,25 @@ interface IdleSequence {
657
730
  label: string;
658
731
  seed?: number;
659
732
  loop: boolean;
733
+ /**
734
+ * What the sequence clock is anchored to. `mount` (default — today's
735
+ * behaviour): every viewer starts at T = 0 when it mounts, so a joiner sees
736
+ * segment 0 (pre-roll semantics). `epoch`: a viewer handed `sequenceBaseT`
737
+ * on its mount context (the host's `Date.now() − epoch`) starts its clock
738
+ * there, so every screen in a room shows the same segment — a late joiner
739
+ * lands mid-loop. `advance: 'input'` holds stay armed under either mode.
740
+ */
741
+ sync?: 'mount' | 'epoch';
742
+ /**
743
+ * A scene drawn under every segment on the sequence's **global** clock —
744
+ * the ground that does not reset at a boundary or under a `sequence.segment`
745
+ * steer. Segments render over it transparently (their `background` and
746
+ * `ghosting` are ignored; the bed may declare its own). Its entities count
747
+ * toward the perf cap together with the largest segment's, since the two
748
+ * are live at once. Steer it with `bed.<path>`. Absent ⇒ every segment
749
+ * paints its own ground, exactly as before the field existed.
750
+ */
751
+ bed?: SaverSpec;
660
752
  segments: SequenceSegment[];
661
753
  }
662
754
 
@@ -673,6 +765,8 @@ declare function assertValidSequence(seq: unknown): IdleSequence;
673
765
 
674
766
  /** Near plane for warp motion. z lives in [WARP_NEAR, 1]; screen scale is 1/z. */
675
767
  declare const WARP_NEAR = 0.08;
768
+ /** Cap on the 1/z size multiplier so near stars don't blow out. */
769
+ declare const WARP_MAX_SCALE = 8;
676
770
  /** One axis-pair of seeded harmonic octaves for wander motion (amps px, freqs rad/ms). */
677
771
  interface WanderOsc {
678
772
  ax: number[];
@@ -835,8 +929,26 @@ declare function linkPairs(positions: Array<{
835
929
  x: number;
836
930
  y: number;
837
931
  }>, k: number, maxDist: number, doWrap: boolean, w: number, h: number): Array<[number, number]>;
838
- /** Em-width of a string under the same character-class table `breakTextBlock` uses. */
839
- declare function textWidthEm(str: string): number;
932
+ /**
933
+ * Which advance table the line-breaker uses. `proportional` is the
934
+ * character-class table below (the default, and the only table until
935
+ * `textBlock.font` existed); `mono` is a uniform 0.6 em advance — the classic
936
+ * monospace cell (Courier, Menlo, SF Mono all sit within a percent of it).
937
+ */
938
+ type TextMetricsClass = 'proportional' | 'mono';
939
+ /**
940
+ * Metrics class for a `textBlock.font` string: `mono` when the family names
941
+ * a monospace face (the generic `monospace`, or a well-known fixed-pitch
942
+ * family), else `proportional`. Absent font ⇒ proportional, as before.
943
+ */
944
+ declare function textMetricsClassFor(font?: string): TextMetricsClass;
945
+ /**
946
+ * Em-width of a string under the same character-class table `breakTextBlock`
947
+ * uses. `mono` counts grapheme clusters, not UTF-16 code units — an emoji or
948
+ * combining/ZWJ sequence is one advance-width cell, matching what's painted,
949
+ * not one cell per surrogate half or combining mark.
950
+ */
951
+ declare function textWidthEm(str: string, metrics?: TextMetricsClass): number;
840
952
  interface TextBlockLine {
841
953
  text: string;
842
954
  widthEm: number;
@@ -846,7 +958,24 @@ interface TextBlockLine {
846
958
  * whitespace; a single word wider than the limit gets its own line unbroken.
847
959
  * Explicit `\n` always forces a break. Pure, deterministic, no canvas needed.
848
960
  */
849
- declare function breakTextBlock(text: string, maxWidthEm: number): TextBlockLine[];
961
+ declare function breakTextBlock(text: string, maxWidthEm: number, metrics?: TextMetricsClass): TextBlockLine[];
962
+ /**
963
+ * Where an anchored textBlock's layout origin sits relative to `position`:
964
+ * the (dx, dy) to ADD to `position` so that the named point of the rendered
965
+ * text lands on it. The rendered box is the widest line wide (placed inside
966
+ * the `maxWidth` box by `align`) and `lines × lineHeight` tall — so `anchor`
967
+ * says where the block sits and `align` only shapes its ragged edge. Absent
968
+ * anchor ⇒ (0, 0): `position` stays the layout box's top-left, exactly as
969
+ * before the field existed. Renderer, perception and advisories all call
970
+ * this, so their boxes agree by construction.
971
+ */
972
+ declare function textBlockAnchorOffset(s: {
973
+ anchor?: TextBlockAnchor;
974
+ align?: 'left' | 'center' | 'right';
975
+ }, maxWPx: number, maxLineW: number, totalH: number): {
976
+ dx: number;
977
+ dy: number;
978
+ };
850
979
  /**
851
980
  * Split a string into paint-safe grapheme clusters: surrogate pairs stay
852
981
  * whole, combining marks / variation selectors / skin tones attach to their
@@ -893,6 +1022,25 @@ declare function manifestFor(spec: SaverSpec): SaverManifest;
893
1022
  * deterministic, `renderFrame(t,seed)`-addressable, and flash-safe by construction.
894
1023
  */
895
1024
  declare function compileSaver(spec: unknown): SaverPlugin;
1025
+ /**
1026
+ * Mount context for a compiled sequence. A plain `SaverContext` works — the
1027
+ * clock starts at 0, as every SaverPlugin's does. `sequenceBaseT` is read
1028
+ * only when the sequence declares `sync: 'epoch'`; hosts pass the shared
1029
+ * clock's elapsed ms (idlescreens.com: `Date.now() − scene.epoch`) so every
1030
+ * viewer of that sequence resolves the same segment.
1031
+ */
1032
+ interface SequenceMountContext extends SaverContext {
1033
+ /** ms already elapsed on the shared sequence clock. Ignored unless `sync: 'epoch'`. */
1034
+ sequenceBaseT?: number;
1035
+ /**
1036
+ * The device's compute tier (`computeTier` from `@idle-screens/capabilities`;
1037
+ * the string union is repeated here so schema does not depend on that
1038
+ * package). A `fade` transition keeps two segments live for `dur`, which
1039
+ * `basic` (canvas2d only) and `minimal` cannot afford: on those tiers fade
1040
+ * renders as `cut`. Absent ⇒ fade enabled.
1041
+ */
1042
+ capabilityTier?: 'minimal' | 'basic' | 'standard' | 'high';
1043
+ }
896
1044
  declare function compileSequence(spec: unknown): SaverPlugin;
897
1045
 
898
1046
  /**
@@ -925,6 +1073,20 @@ declare function applyDeltasToSpec(spec: SaverSpec, deltas: SteerDelta[]): Saver
925
1073
  * target immediately (k > 0). Layer counts round to integers.
926
1074
  */
927
1075
  declare function lerpSpec(from: SaverSpec, to: SaverSpec, k: number): SaverSpec;
1076
+ /**
1077
+ * The string(s) a text layer paints — `strings` of a `text` sprite, `text`
1078
+ * of a `textBlock` — or null for every other sprite.
1079
+ */
1080
+ declare function textStringsOf(sprite: SpriteSpec): string[] | null;
1081
+ /**
1082
+ * Whether the text layer at index `i` paints different words in `a` and
1083
+ * `b` — the layers a morph `text: 'crossfade'` draws twice. False for
1084
+ * non-text layers and when the strings match.
1085
+ */
1086
+ declare function textStringsDiffer(a: SaverSpec, b: SaverSpec, i: number): boolean;
1087
+ declare function morphNothingMorphable(a: SaverSpec, b: SaverSpec, opts?: {
1088
+ textCrossfade?: boolean;
1089
+ }): boolean;
928
1090
  /**
929
1091
  * Enumerate all steerable leaf paths in a (resolved) spec. Returns dot-paths
930
1092
  * like "layers.0.count", "background.stops.1.color", etc. Metadata fields
@@ -935,6 +1097,14 @@ declare function lerpSpec(from: SaverSpec, to: SaverSpec, k: number): SaverSpec;
935
1097
  * Consumers can map to key-based paths via resolveSpecPath if needed.
936
1098
  */
937
1099
  declare function steerablePaths(spec: unknown): string[];
1100
+ /**
1101
+ * Every path a sequence accepts on its track: `sequence.segment` (the
1102
+ * clicker), the bed's paths under the `bed.` prefix, and the union of every
1103
+ * segment's paths (a segment path lands on whichever segment owns it — see
1104
+ * `SequenceInstance.applyTrack`). Deduplicated, numeric layer indices as in
1105
+ * `steerablePaths`.
1106
+ */
1107
+ declare function sequenceSteerablePaths(seq: IdleSequence): string[];
938
1108
  /** Smooth (ease-in-out) progress curve used for glides. */
939
1109
  declare function easeSmooth(k: number): number;
940
1110
  /**
@@ -1289,6 +1459,58 @@ interface ScenePerception {
1289
1459
  * Intended as the payload behind an MCP previewScene.
1290
1460
  */
1291
1461
  declare function perceiveScene(spec: SaverSpec, opts?: LuminanceGridOptions): ScenePerception;
1462
+ interface SequenceFramePerception extends ScenePerception {
1463
+ /** Which segment the global time `T` resolved to, and where in it. */
1464
+ segment: {
1465
+ index: number;
1466
+ key: string;
1467
+ localT: number;
1468
+ held?: true;
1469
+ };
1470
+ /** True when a bed was composed under the segment. */
1471
+ bed: boolean;
1472
+ }
1473
+ interface PerceiveSequenceOptions extends Omit<LuminanceGridOptions, 't'> {
1474
+ /** Holds released by the clicker so far — see `ResolveOptions.releasedBelow`. */
1475
+ releasedBelow?: number;
1476
+ }
1477
+ /**
1478
+ * Perceive one frame of a sequence at global time `T`: resolve the segment,
1479
+ * then — when the sequence has a `bed` — compose the bed at `T` (its clock
1480
+ * never resets) under the segment's ink at `localT`, the segment's own
1481
+ * background dropped, exactly as the renderer stacks them. The luminance maps
1482
+ * add the two grids (clamped), so coverage, centroid and the profiles are of
1483
+ * the composite; dominance ranks bed and segment layers together by their raw
1484
+ * weights, bed layers keyed `bed:<key|index>`; text, motion and form list bed
1485
+ * layers first with the same prefix. Bed and segment are assumed to share
1486
+ * `units`/`referenceViewport`, as the renderer's shared canvas assumes. The
1487
+ * bed and segment seeds come from `segmentRenderSeed`/`bedRenderSeed`
1488
+ * (`./sequence`) — the same derivation `SequenceInstance` uses, chain roots
1489
+ * and zero-seed normalization included — so the composed frame matches what
1490
+ * the renderer actually draws at `T`, not just what the raw specs would show.
1491
+ * Without a bed this is `perceiveScene(segment, localT)` plus the `segment`
1492
+ * field. Intended as the payload behind a sequence-aware previewScene.
1493
+ *
1494
+ * Two known approximations, both accepted for a coarse, cheap, renderer-free
1495
+ * tool rather than fixed here:
1496
+ * - **The transition WINDOW isn't composed.** During a live `fade` or `morph`
1497
+ * (i.e. `localT < transition.dur`) the renderer also paints the outgoing
1498
+ * (or interpolating) segment, but this only ever perceives the segment
1499
+ * `resolveSegment` resolves to — call it at a `T` outside the transition's
1500
+ * `dur` for an accurate read. (Outside that window, a morph-chained
1501
+ * segment's entities and seed ARE correct — `segmentRenderSeed` already
1502
+ * resolves the chain root.) Composing the live window properly needs the
1503
+ * same capability-tier gate `SequenceInstance` uses to decide whether
1504
+ * `fade` even plays; this analytical path has no such context.
1505
+ * - **Ink composites onto the bed by addition, not by blend mode.** This
1506
+ * matches a plain `source-over`, opaque-ink segment (the common case), but
1507
+ * a segment layer with `blend: 'multiply'`/`'screen'`/etc. or partial alpha
1508
+ * composites directionally differently on the real canvas than adding
1509
+ * luminance values ever can (`multiply` darkens; addition only brightens).
1510
+ * The per-cell grids don't retain per-layer blend/alpha to composite
1511
+ * correctly at this resolution.
1512
+ */
1513
+ declare function perceiveSequenceFrame(seq: IdleSequence, T: number, opts?: PerceiveSequenceOptions): SequenceFramePerception;
1292
1514
 
1293
1515
  interface ResolvedSegment {
1294
1516
  index: number;
@@ -1333,6 +1555,33 @@ declare function segmentStart(seq: IdleSequence, index: number): number;
1333
1555
  * mode (validated elsewhere).
1334
1556
  */
1335
1557
  declare function resolveSegment(seq: IdleSequence, T: number, opts?: ResolveOptions): ResolvedSegment;
1558
+ /** Whether the boundary from `from` to `from + 1` morphs: same scene structure, `morph` transition. */
1559
+ declare function canMorph(seq: IdleSequence, from: number): boolean;
1560
+ /**
1561
+ * Walk back through consecutive `morph` boundaries to the chain's origin. A
1562
+ * morph-chained segment's entities are never re-seeded at the boundary —
1563
+ * they're the same stream continued from wherever the chain started — so its
1564
+ * actual render seed (see `segmentRenderSeed`) is always the chain root's,
1565
+ * never its own index's.
1566
+ */
1567
+ declare function morphChainRoot(seq: IdleSequence, index: number): number;
1568
+ /** `SpecInstance`'s seed normalization: 0 is falsy, so a valid `seed: 0` lands on 1. */
1569
+ declare function normalizeSeed(seed: number): number;
1570
+ /**
1571
+ * The seed segment `index`'s entities actually render with — its chain
1572
+ * root's own seed, else `seq.seed + ` the chain root's index, normalized
1573
+ * exactly like `SpecInstance`. `undefined` when neither is set: the same
1574
+ * "unknowable ahead of time" case a bare `SaverSpec` has via `ctx.seed`,
1575
+ * which callers fall back to their own default for (as `perceiveScene` does).
1576
+ */
1577
+ declare function segmentRenderSeed(seq: IdleSequence, index: number): number | undefined;
1578
+ /**
1579
+ * The seed the bed's entities actually render with — its own seed, else
1580
+ * `seq.seed + LIMITS.maxSegments` (past every segment's `seq.seed + index`,
1581
+ * so a bed and segment 0 never share a stream), normalized like
1582
+ * `SpecInstance`. `undefined` when there's no bed or no derivable seed.
1583
+ */
1584
+ declare function bedRenderSeed(seq: IdleSequence): number | undefined;
1336
1585
 
1337
1586
  /**
1338
1587
  * Reproduces the hand-coded Fish Aquarium saver as pure DATA — the discriminating test
@@ -1372,6 +1621,23 @@ declare const SNOWFALL_SPEC: SaverSpec;
1372
1621
  */
1373
1622
  declare const LANTERNS_SPEC: SaverSpec;
1374
1623
 
1624
+ /**
1625
+ * Lobby Talk — one screen of a "quarter in review" that runs on a lobby wall
1626
+ * between meetings: a five-row adoption chart over the same slow haze and
1627
+ * dust the whole talk shares. The words are the point, so every text layer
1628
+ * declares `role: 'read'` — the opt-in that turns on `adviseSpec`'s
1629
+ * legibility advisories (`text-legibility` against the ground *and* the
1630
+ * brightest additive layer that can sit under a line, `text-safe-area` for
1631
+ * the bezel zone). Tuned to zero advisories: the haze is bright enough to
1632
+ * matter and dim enough to leave every label above 4.5:1 at its peak.
1633
+ *
1634
+ * Schema exercises: `role: 'read'` on both `textBlock` and `text`, a
1635
+ * `list`-laid chart in three layers (labels, `bar`s, readouts), additive
1636
+ * atmosphere (`lighter` soft circles with `pulse`) under readable copy.
1637
+ * Steer `bars.sprite.values` to change the numbers live.
1638
+ */
1639
+ declare const LOBBY_TALK_SPEC: SaverSpec;
1640
+
1375
1641
  /**
1376
1642
  * Sakura Drift: cherry-blossom petals carried on a spring twilight breeze.
1377
1643
  * Glow-up pass (v1-ceiling features): petals ride `wander` harmonics with shared
@@ -1467,7 +1733,7 @@ declare const FACETS_SPEC: SaverSpec;
1467
1733
  * Relay Board — a six-row status chart in five layers instead of twenty-five.
1468
1734
  * One `list` of labels, one `list` of `bar`s whose lengths are the numbers,
1469
1735
  * one `list` of readouts, a title block, and a slow dust field behind so the
1470
- * board reads as a live wall, not a document. Steer `bars.values` and the
1736
+ * board reads as a live wall, not a document. Steer `bars.sprite.values` and the
1471
1737
  * bars glide to the new figures; the labels never move.
1472
1738
  */
1473
1739
  declare const RELAY_BOARD_SPEC: SaverSpec;
@@ -1508,4 +1774,4 @@ declare const EXAMPLE_SPECS: SaverSpec[];
1508
1774
  /** Lookup by saver id. */
1509
1775
  declare const EXAMPLE_BY_ID: Readonly<Record<string, SaverSpec>>;
1510
1776
 
1511
- export { AQUARIUM_SPEC, AURORA_SPEC, type BackgroundDrift, type BackgroundSpec, type BandSpec, COHESION_T, COMETS_SPEC, CONSTELLATION_SPEC, type CohesionRead, type CycleSpec, DASHBOARD_SPEC, type DominanceEntry, EXAMPLE_BY_ID, EXAMPLE_SPECS, type Entity, FACETS_SPEC, type GradientStop, HAIKU_SPEC, type IdleSequence, LANTERNS_SPEC, LIMITS, type LayerCohesion, type LayerMotionStats, type LayerSnapshot, type LayerSpec, type LinkEdge, type LuminanceGrid, type LuminanceGridOptions, MATRIX_RAIN_SPEC, type MotionEase, type MotionSpec, NOSTALGHIA_CANDLE_SPEC, ORRERY_SPEC, PINGS_SPEC, POLYGONS_SPEC, PROCESSION_SPEC, type PerceiveOptions, type Placed, RAIN_SPEC, RELAY_BOARD_SPEC, type ResolveOptions, type ResolvedSegment, type RevealState, SAKURA_SPEC, SCHEMA_EXAMPLES, SCHEMA_VERSION, SNOWFALL_SPEC, type SaverSpec, type SceneDescription, type SceneDiff, type ScenePerception, type SceneSnapshot, type SchemaExample, type SequenceSegment, type SequenceTransition, type SpecError, type SpecWarning, type SpriteSpec, type SteerDelta, type TextBlockLine, type TextRevealInput, type TextRevealSpec, type TextSpriteInfo, type ValidationResult, WARP_NEAR, WARP_TUNNEL_SPEC, type WanderOsc, adviseSequence, adviseSpec, alphaAt, applyDeltasToSpec, assertValidSequence, assertValidSpec, breakTextBlock, buildEntities, cohesionOf, compileSaver, compileSequence, describeScene, diffScenes, dominanceRanking, easeSmooth, emitEnvelope, emitWindow, graphemeClusters, headingAt, layerCohesion, lerpSpec, lifeAlphaAt, linkEdges, linkPairs, luminanceGrid, manifestFor, motionStats, perceiveScene, positionAt, renderBrailleMap, renderDensityMap, resolveSegment, resolveSpecPath, revealState, rotationAt, seamCauseOf, seamsWorthWarning, segmentStart, sizeAt, spriteIndexAt, spriteVariants, steerablePaths, structuralSignature, textSprites, textWidthEm, validateSequence, validateSpec };
1777
+ export { AQUARIUM_SPEC, AURORA_SPEC, type BackgroundDrift, type BackgroundSpec, type BandSpec, COHESION_T, COMETS_SPEC, CONSTELLATION_SPEC, type CohesionRead, type CycleSpec, DASHBOARD_SPEC, type DominanceEntry, EXAMPLE_BY_ID, EXAMPLE_SPECS, type Entity, FACETS_SPEC, type GradientStop, HAIKU_SPEC, type IdleSequence, LANTERNS_SPEC, LIMITS, LOBBY_TALK_SPEC, type LayerCohesion, type LayerMotionStats, type LayerSnapshot, type LayerSpec, type LinkEdge, type LuminanceGrid, type LuminanceGridOptions, MATRIX_RAIN_SPEC, type MotionEase, type MotionSpec, NOSTALGHIA_CANDLE_SPEC, ORRERY_SPEC, PINGS_SPEC, POLYGONS_SPEC, PROCESSION_SPEC, type PerceiveOptions, type PerceiveSequenceOptions, type Placed, RAIN_SPEC, RELAY_BOARD_SPEC, type ResolveOptions, type ResolvedSegment, type RevealState, SAKURA_SPEC, SCHEMA_EXAMPLES, SCHEMA_VERSION, SNOWFALL_SPEC, type SaverSpec, type SceneDescription, type SceneDiff, type ScenePerception, type SceneSnapshot, type SchemaExample, type SequenceFramePerception, type SequenceMountContext, type SequenceSegment, type SequenceTransition, type SpecError, type SpecWarning, type SpriteSpec, type SteerDelta, type TextBlockAnchor, type TextBlockLine, type TextMetricsClass, type TextRevealInput, type TextRevealSpec, type TextRole, type TextSpriteInfo, type ValidationResult, WARP_MAX_SCALE, WARP_NEAR, WARP_TUNNEL_SPEC, type WanderOsc, type WarningBox, adviseSequence, adviseSpec, alphaAt, applyDeltasToSpec, assertValidSequence, assertValidSpec, bedRenderSeed, breakTextBlock, buildEntities, canMorph, cohesionOf, compileSaver, compileSequence, describeScene, diffScenes, dominanceRanking, easeSmooth, emitEnvelope, emitWindow, graphemeClusters, headingAt, layerCohesion, lerpSpec, lifeAlphaAt, linkEdges, linkPairs, luminanceGrid, manifestFor, morphChainRoot, morphNothingMorphable, motionStats, normalizeSeed, perceiveScene, perceiveSequenceFrame, positionAt, renderBrailleMap, renderDensityMap, resolveSegment, resolveSpecPath, revealState, rotationAt, seamCauseOf, seamsWorthWarning, segmentRenderSeed, segmentStart, sequenceSteerablePaths, sizeAt, spriteIndexAt, spriteVariants, steerablePaths, structuralSignature, textBlockAnchorOffset, textMetricsClassFor, textSprites, textStringsDiffer, textStringsOf, textWidthEm, validateSequence, validateSpec };