@idle-screens/schema 3.5.0 → 3.6.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/FORMAT.md +114 -13
- package/dist/index.d.ts +316 -3
- package/dist/index.js +1012 -49
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
- package/saver-spec.schema.json +230 -35
package/FORMAT.md
CHANGED
|
@@ -32,7 +32,11 @@ sprites, `colorWeights`, `pulse.wave`, `layout` (grid), `life`,
|
|
|
32
32
|
`links.mode/falloff/closed`, `blend: screen|multiply`, orbit layer-parents
|
|
33
33
|
(2026-07-21 — "the v1 ceiling");
|
|
34
34
|
`textBlock` sprite — deterministic multi-line text with viewport-unit sizing;
|
|
35
|
-
`textBlock.reveal` — animated typing/deleting via one steerable paint param
|
|
35
|
+
`textBlock.reveal` — animated typing/deleting via one steerable paint param;
|
|
36
|
+
`emit` (sparse events), `clock` (phase-lock), `motion.ease` (settle / buoyant)
|
|
37
|
+
(2026-09-05 — time structure); `polygon` / `stroke` sprites and `rect.feather`
|
|
38
|
+
(2026-09-05 — shape glyphs); `layout: list | table` and the `bar` sprite
|
|
39
|
+
(2026-09-05 — data layout).
|
|
36
40
|
|
|
37
41
|
## Safety invariants
|
|
38
42
|
|
|
@@ -48,7 +52,10 @@ These hold **by construction** — no spec can violate them:
|
|
|
48
52
|
so a layer will generally not pulse in unison (edge case: if spawn positions
|
|
49
53
|
alias the wavelength, phases may coincide). `ghosting` only *smooths* luminance
|
|
50
54
|
changes (it composites frames over a faded copy of the last), never sharpens
|
|
51
|
-
them.
|
|
55
|
+
them. `clock` deliberately removes the per-entity phase, so the validator
|
|
56
|
+
floors a clocked layer's periods at 1000 ms (1 Hz) instead — a layer in
|
|
57
|
+
unison breathes, it never flashes. `emit` events are floored at one per
|
|
58
|
+
second per entity and always ride a smooth envelope, never a cut.
|
|
52
59
|
3. **Motion is bounded.** Speeds are capped (4000 px/sec; warp at 1.5
|
|
53
60
|
depth-units/sec; orbit at 180 deg/sec; path laps at ≥ 2 s).
|
|
54
61
|
4. **Work is bounded.** ≤ 36 layers, ≤ 400 entities per layer, ≤ 800 total,
|
|
@@ -72,7 +79,10 @@ Author against the JSON Schema; ship through the runtime validator.
|
|
|
72
79
|
|
|
73
80
|
Rules the JSON Schema cannot fully express (the runtime enforces them):
|
|
74
81
|
total entities across all layers ≤ 800; every `[min, max]` range must satisfy
|
|
75
|
-
`min ≤ max`; `colorWeights` length must match `colors`;
|
|
82
|
+
`min ≤ max`; `colorWeights` length must match `colors`; `emit.life ≤
|
|
83
|
+
emit.every`; a `clock`ed layer's `pulse`/`grow`/`cycle` period must satisfy
|
|
84
|
+
`period / rate ≥ 1000`; a `polygon` takes `sides` or `points`, not both (the
|
|
85
|
+
JSON Schema enforces this one too); orbit layer-parents
|
|
76
86
|
must exist, have `count: 1`, and not themselves orbit a layer.
|
|
77
87
|
|
|
78
88
|
## Structure
|
|
@@ -84,6 +94,7 @@ must exist, have `count: 1`, and not themselves orbit a layer.
|
|
|
84
94
|
"label": "Snowfall",
|
|
85
95
|
"seed": 42, // optional; falls back to the host's seed
|
|
86
96
|
"motionIntensity": "calm", // optional: calm | moderate | energetic
|
|
97
|
+
"density": "normal", // optional: sparse | normal | dense — declared intent, see below
|
|
87
98
|
"units": "viewport", // optional: viewport (default) | px
|
|
88
99
|
"referenceViewport": 1080, // optional; design resolution for density scaling
|
|
89
100
|
"ghosting": 0.9, // optional 0..0.95; frame-persistence smear
|
|
@@ -102,6 +113,16 @@ use that CSS font verbatim and do not scale with the viewport.
|
|
|
102
113
|
clearing: moving entities leave decaying after-images (Mystify smears, Matrix
|
|
103
114
|
trails, long-exposure light). 0.85–0.95 is the useful range; 0 (default) is off.
|
|
104
115
|
|
|
116
|
+
`density` declares what the emptiness or the crowding means. `sparse` says
|
|
117
|
+
the scene is *meant* to be almost empty — one faint mark on a dark ground,
|
|
118
|
+
long silences — so `adviseSpec` withholds `sparse-scene` and a scorer that
|
|
119
|
+
gates on coverage should read the declaration before calling a faithful
|
|
120
|
+
scene broken. `dense` withholds `dense-scene` the same way. The declaration
|
|
121
|
+
is checked, not trusted: a `sparse` scene whose alpha-weighted coverage
|
|
122
|
+
exceeds 2 %, or a `dense` one that would have tripped `sparse-scene`, gets a
|
|
123
|
+
`density-mismatch` advisory instead. Omitted means `normal`. Like
|
|
124
|
+
`motionIntensity`, it is a hint — it changes no pixel.
|
|
125
|
+
|
|
105
126
|
### `background`
|
|
106
127
|
|
|
107
128
|
- `{ "type": "solid", "color": "#06060c" }`
|
|
@@ -129,10 +150,12 @@ trails, long-exposure light). 0.85–0.95 is the useful range; 0 (default) is of
|
|
|
129
150
|
| `grow` | `{amp ≤ 0.8, period ≥ 500}` | none | size breathing (seeded phase) |
|
|
130
151
|
| `trail` | `{length ≤ 5000, fade?}` | none | analytic afterglow trail; `length` is **milliseconds** of history (max 5000), `fade` a number 0..1 (not a boolean — `links.falloff` in the next row is the boolean) |
|
|
131
152
|
| `links` | see below | none | inter-entity lines |
|
|
132
|
-
| `layout` | `{type: "grid", columns?, jitter?}` | scatter | grid
|
|
153
|
+
| `layout` | `{type: "grid", columns?, jitter?}` \| `{type: "list", gap?}` \| `{type: "table", columns, gap?}` | scatter | `grid`: cells fill `region`, `jitter` scalar or `{x?, y?}` 0..1 per axis. **`list` / `table`: data layouts** — entities in reading order from `position` (any count) or centred in `region`, `gap` apart (viewport units of `min(w,h)`, default 0.06); text/emoji take `strings[i]` / `glyphs[i]` and palettes `colors[i]` **in order**, so N labels are one layer |
|
|
133
154
|
| `life` | `{enter?, exit?, fade?}` ms | always on | act structure: fade the layer in at `enter`, out at `exit` |
|
|
155
|
+
| `emit` | `{every ≥ 1000, life ≥ 500, jitter?, grow?}` (`life ≤ every`) | always lit | **sparse events**: each entity is dark except a `life`-ms window every `every` ms, fading in fast and out slow; `jitter` 0 staggers entities evenly (one event at a time while `life ≤ every / count`), 1 scatters the offsets (a fixed sequence, not seeded — declaring `emit` disturbs no other draw); `grow: [from, to]` scales size across the window — expansion rather than travel |
|
|
156
|
+
| `clock` | `{phase?, rate?}` | seeded phases | **phase-lock**: `pulse`, `grow` and `cycle` share one phase (turns, 0..1) and run at `rate` × time; two layers with the same clock breathe in step. Clocked periods must satisfy `period / rate ≥ 1000` |
|
|
134
157
|
| `key` | string | none | addressable name → `setParam("key.field", …)` |
|
|
135
|
-
| `position` | `{x, y}` 0..1 | none | exact placement; **requires `count: 1
|
|
158
|
+
| `position` | `{x, y}` 0..1 | none | exact placement; **requires `count: 1`** — except with a `list`/`table` layout, where it anchors the block's top-left; overrides `region` |
|
|
136
159
|
|
|
137
160
|
`links`: `{ k: 1..8, maxDist, color?, alpha?, width?, mode?, falloff?, closed? }`.
|
|
138
161
|
`mode: "nearest"` (default) wires each entity to its k nearest neighbors within
|
|
@@ -155,8 +178,31 @@ with distance, removing pop-in at the cutoff.
|
|
|
155
178
|
- `{ "kind": "streak", "length": [0.01, 0.03], "color": "#cfd8ff", "width": 0.002 }` —
|
|
156
179
|
a line oriented along the entity's analytic heading with a faded tail
|
|
157
180
|
(rain that reads as rain, shooting stars, warp stars)
|
|
158
|
-
- `{ "kind": "rect", "width": [0.012, 0.02], "aspect": [1.3, 1.7], "color": "#ffb347" }` —
|
|
159
|
-
rectangle; `aspect` is the height/width ratio range (rotates with `spin`)
|
|
181
|
+
- `{ "kind": "rect", "width": [0.012, 0.02], "aspect": [1.3, 1.7], "color": "#ffb347", "feather": 0.6 }` —
|
|
182
|
+
rectangle; `aspect` is the height/width ratio range (rotates with `spin`);
|
|
183
|
+
`feather` 0..1 softens the edges — that fraction of the half-size fades out
|
|
184
|
+
toward the border (Rothko's block at 0.5–0.8)
|
|
185
|
+
- `{ "kind": "bar", "values": [82, 64, 91], "max": 100, "length": 0.5, "thickness": 0.02, "color": "#17e8c8", "direction": "right" }` —
|
|
186
|
+
a data bar: entity *i* draws `length × values[i] / max` (viewport units),
|
|
187
|
+
`thickness` thick, growing from its position toward `direction` (`right`
|
|
188
|
+
default, `left`, `up`, `down`). `values` are **paint**: `setParam("bars.values", […])`
|
|
189
|
+
glides every bar. With `layout: { type: "list" }` a chart is one layer and
|
|
190
|
+
its labels another — the dashboard genre stops needing one layer per number
|
|
191
|
+
- `{ "kind": "polygon", "radius": [0.02, 0.05], "sides": 3, "color": "#f2e8c9", "soft": false }` —
|
|
192
|
+
regular n-gon of the seeded circumradius, point up (`sides` 3..12, default
|
|
193
|
+
6); or `"points": [[-1, 0.9], [0.2, -1], [1, 0.4]]` — 3..24 unit
|
|
194
|
+
coordinates in −1..1 scaled by the radius — for any facet (a Picasso shard,
|
|
195
|
+
a Kandinsky triangle, a Mondrian plane). `soft` feathers the fill from the
|
|
196
|
+
centre. Rotates with `spin`. `points` are paint, so two polygons with the
|
|
197
|
+
same point count `morph` into each other
|
|
198
|
+
- `{ "kind": "stroke", "length": [0.08, 0.18], "points": [[-1, 0.3], [-0.5, -0.6], [0.3, -0.7], [1, 0.1]], "width": 0.004, "taper": true, "color": "#f2e8c9" }` —
|
|
199
|
+
a freehand mark: a path through 2..24 unit-coordinate points, scaled so the
|
|
200
|
+
unit box spans the seeded `length`, stroked `width` wide with round joins.
|
|
201
|
+
`curve: "smooth"` (default) is a Catmull-Rom spline, `"linear"` a polyline;
|
|
202
|
+
`taper` thins the mark to almost nothing at both ends (a brush stroke rather
|
|
203
|
+
than a line); `orient: true` turns the path's +x along the entity's heading,
|
|
204
|
+
like `streak`. Rotates with `spin`. Van Gogh's stroke, Hokusai's contour,
|
|
205
|
+
O'Keeffe's petal, Basquiat's scrawl
|
|
160
206
|
- `{ "kind": "textBlock", "text": "Multi-line text with wrapping.", "maxWidth": 0.8, "fontSize": 0.04, "lineHeight": 1.4, "align": "left", "color": "#e6e8ef" }` —
|
|
161
207
|
multi-line text block with deterministic line-breaking. All dimensions are
|
|
162
208
|
viewport fractions (of `min(w,h)`), not px — `units: "px"` specs reject
|
|
@@ -196,9 +242,20 @@ with distance, removing pop-in at the cutoff.
|
|
|
196
242
|
glide `reveal.progress` to 0, swap `text` while nothing is visible, glide
|
|
197
243
|
back to 1.
|
|
198
244
|
|
|
199
|
-
`circle`, `ring`, `streak`,
|
|
200
|
-
per-entity palette pick) and `colorWeights: [...]`
|
|
201
|
-
length — "mostly cool tones, occasional ember").
|
|
245
|
+
`circle`, `ring`, `streak`, `rect`, `bar`, `polygon` and `stroke` all accept
|
|
246
|
+
`colors: [...]` (seeded per-entity palette pick) and `colorWeights: [...]`
|
|
247
|
+
(relative weights, same length — "mostly cool tones, occasional ember").
|
|
248
|
+
|
|
249
|
+
**Drawing a shape out of sprites.** Overlapping sprites merge into one seamless
|
|
250
|
+
silhouette under exactly one set of conditions: a single flat colour, `alpha`
|
|
251
|
+
of `[1, 1]`, no `blend`, no `pulse`, and hard edges (no `soft`, no
|
|
252
|
+
`rect.feather`). Anything else leaves every overlap visible as an internal edge,
|
|
253
|
+
so the layer reads as a pile of sprites rather than a form — `soft` in
|
|
254
|
+
particular reads as smoke, not mass. Depth then comes from *layer order* and a
|
|
255
|
+
different flat colour per layer, painting back to front, and a later layer can
|
|
256
|
+
be used to cut a clean edge across an earlier one. `layerCohesion` measures
|
|
257
|
+
which of the two you got; `overlap-seams` warns when you asked for the first
|
|
258
|
+
and configured the second.
|
|
202
259
|
|
|
203
260
|
### `motion` (one of)
|
|
204
261
|
|
|
@@ -228,6 +285,26 @@ length — "mostly cool tones, occasional ember").
|
|
|
228
285
|
|
|
229
286
|
All speeds are ranges; each entity draws its own value (seeded).
|
|
230
287
|
|
|
288
|
+
`drift`, `rise` and `wander` also accept **`ease`** — closed-form velocity
|
|
289
|
+
shaping, no integration state:
|
|
290
|
+
`{ "ease": { "type": "settle", "tau": 2500 } }` starts at the entity's speed
|
|
291
|
+
and decelerates to rest with time constant `tau` ms (it travels `speed × tau`
|
|
292
|
+
and stops — a mark flung and coming to rest); `"buoyant"` starts at rest and
|
|
293
|
+
approaches the speed over `tau` (a bubble reaching terminal velocity). With
|
|
294
|
+
`emit`, the eased travel restarts from the spawn point on every event. For
|
|
295
|
+
`wander` only the base velocity eases — the harmonic meander keeps breathing,
|
|
296
|
+
so a settled wanderer hovers rather than freezes.
|
|
297
|
+
|
|
298
|
+
**Time structure, composed.** `emit` is how a scene does *almost nothing,
|
|
299
|
+
almost never*: one ring every twelve seconds that expands and fades
|
|
300
|
+
(`emit: { every: 12000, life: 5000, jitter: 0, grow: [0.15, 2.4] }`) reads as
|
|
301
|
+
an event, where the same ring pulsing forever reads as wallpaper. Long
|
|
302
|
+
`every`, low `count`, `jitter: 0` for a metronome, `1` for weather; pair with
|
|
303
|
+
`ease: settle` so a mark is flung and comes to rest before it fades ("expand,
|
|
304
|
+
drift a little, settle, fade" is one layer). `clock` is the other half: two
|
|
305
|
+
layers on the same clock are a duet, not a coincidence. The shipped `pings`
|
|
306
|
+
example is the whole idea in two layers.
|
|
307
|
+
|
|
231
308
|
## Determinism contract
|
|
232
309
|
|
|
233
310
|
Entity construction consumes the seeded RNG in a **fixed draw order** per layer.
|
|
@@ -293,6 +370,17 @@ trade-offs for a zero-dependency, renderer-free analysis tool.
|
|
|
293
370
|
line-salience boost so they aren't crushed by filled discs.
|
|
294
371
|
- `motionStats(spec, opts)` — per-layer mean/max on-screen speed from analytic
|
|
295
372
|
displacement — choreography as numbers.
|
|
373
|
+
- `layerCohesion(spec, opts)` — **does a layer read as one form or as N marks?**
|
|
374
|
+
The luminance maps measure ink, not edges, so a layer whose sprites merged
|
|
375
|
+
into a silhouette and one that stayed a pile of discs are identical in every
|
|
376
|
+
other channel. Two independent facts, both reported (also on
|
|
377
|
+
`perceiveScene().form`): `overlap` is geometry — the mean fraction of an
|
|
378
|
+
entity's outline buried inside a sibling (shipped particle fields measure
|
|
379
|
+
≤ 0.154; a packed silhouette measures 0.79–0.85; `null` for lines, glyphs and
|
|
380
|
+
text, where a merged silhouette is not a meaningful idea). `seamless` is
|
|
381
|
+
paint — whether those overlaps vanish or draw an internal edge, with
|
|
382
|
+
`seamCause` naming the field to change. `reads` combines them into `mass`,
|
|
383
|
+
`seamed` or `marks`.
|
|
296
384
|
- `textSprites(spec, opts)` — the literal strings and rendered sizes of every
|
|
297
385
|
text layer. Glyphs are invisible in the luminance maps, so this is the only
|
|
298
386
|
way to confirm *what words* are on screen and how big. (Also on
|
|
@@ -305,6 +393,16 @@ trade-offs for a zero-dependency, renderer-free analysis tool.
|
|
|
305
393
|
textBlock line-breaker uses, so they are estimates of the renderer's own
|
|
306
394
|
layout — a caption that fails these will look wrong on the wall; one that
|
|
307
395
|
passes may still sit a few px off.
|
|
396
|
+
`overlap-seams` catches the trap the other channels are blind to: a layer
|
|
397
|
+
whose entities bury each other (so it was drawn as one shape) but whose paint
|
|
398
|
+
settings make every overlap visible. It is gated to stay off deliberate
|
|
399
|
+
washes — it needs at least 6 entities and a mean base alpha of 0.45, and
|
|
400
|
+
never fires under `blend: lighter` / `screen`. No shipped example trips it.
|
|
401
|
+
The two density advisories read the spec's declared `density` first:
|
|
402
|
+
`sparse-scene` is withheld under `density: "sparse"` and `dense-scene`
|
|
403
|
+
under `"dense"`, and `density-mismatch` fires instead when the measured
|
|
404
|
+
coverage contradicts the declaration (a "sparse" scene covering more than
|
|
405
|
+
2 % of the frame, a "dense" one that would have read as empty).
|
|
308
406
|
- `diffScenes(a, b, opts)` — **relative sight**: coverage/luminance deltas,
|
|
309
407
|
visual-balance shift, 3×3 region deltas, dominance-rank movement, and
|
|
310
408
|
advisory codes added/removed. Agents judge "is B better than A" far more
|
|
@@ -400,6 +498,9 @@ Shipped working specs (also exposed as `EXAMPLE_SPECS` /
|
|
|
400
498
|
showcases — `aurora` (wander + coherence + ghosting + pulse.wave),
|
|
401
499
|
`warp-tunnel` (warp + streaks), `polygons` (chain links + heavy ghosting),
|
|
402
500
|
`matrix-rain` (grid layout + glyph cycle + ghosting), and `procession`
|
|
403
|
-
(path + layer-parented orbit + life staging + ring/rect sprites)
|
|
404
|
-
|
|
405
|
-
|
|
501
|
+
(path + layer-parented orbit + life staging + ring/rect sprites);
|
|
502
|
+
`nostalghia-candle` and `haiku` (restraint and text); and the 2026-09 trio —
|
|
503
|
+
`pings` (emit + grow + ease: one event at a time), `facets` (polygon, stroke
|
|
504
|
+
and feathered rect) and `relay-board` (list layout + bar: a chart in five
|
|
505
|
+
layers). See [`src/examples/`](./src/examples/). The dashboard exercises the
|
|
506
|
+
static/HUD subset at scale (34 layers of keyed, positioned text).
|
package/dist/index.d.ts
CHANGED
|
@@ -22,6 +22,16 @@ interface SaverSpec {
|
|
|
22
22
|
background?: BackgroundSpec;
|
|
23
23
|
layers: LayerSpec[];
|
|
24
24
|
motionIntensity?: 'calm' | 'moderate' | 'energetic';
|
|
25
|
+
/**
|
|
26
|
+
* Declared density intent. `sparse` says the emptiness is the point (one
|
|
27
|
+
* mark on a dark ground, long silences): `adviseSpec` withholds
|
|
28
|
+
* `sparse-scene`, and scorers that gate on coverage should read this before
|
|
29
|
+
* calling a faithful scene broken. `dense` withholds `dense-scene` the same
|
|
30
|
+
* way. Either declaration is checked against the measured coverage and a
|
|
31
|
+
* `density-mismatch` advisory fires when the scene contradicts it. Omitted
|
|
32
|
+
* means `normal`. A hint only — it changes no pixel.
|
|
33
|
+
*/
|
|
34
|
+
density?: 'sparse' | 'normal' | 'dense';
|
|
25
35
|
/**
|
|
26
36
|
* Frame persistence (0..1, capped at LIMITS.maxGhosting). Instead of fully clearing,
|
|
27
37
|
* each frame the background is painted at reduced alpha so moving entities leave
|
|
@@ -137,7 +147,8 @@ interface LayerSpec {
|
|
|
137
147
|
key?: string;
|
|
138
148
|
/**
|
|
139
149
|
* Exact fractional position {x, y} for a single entity (0 = left/top, 1 = right/bottom).
|
|
140
|
-
* Only valid when `count` is 1
|
|
150
|
+
* Only valid when `count` is 1 — or, with a `list` / `table` layout, as the
|
|
151
|
+
* top-left anchor of the whole block. Overrides `region` scatter placement.
|
|
141
152
|
*/
|
|
142
153
|
position?: {
|
|
143
154
|
x: number;
|
|
@@ -185,6 +196,26 @@ interface LayerSpec {
|
|
|
185
196
|
x?: number;
|
|
186
197
|
y?: number;
|
|
187
198
|
};
|
|
199
|
+
}
|
|
200
|
+
/**
|
|
201
|
+
* Data layouts — entities in READING ORDER, no scatter. `list` stacks them
|
|
202
|
+
* in one column `gap` apart (viewport units of min(w,h), default 0.06);
|
|
203
|
+
* `table` fills `columns` row-major with `gap` `{x, y}` (one number = both).
|
|
204
|
+
* Text and emoji sprites take `strings[i]` / `glyphs[i]` in order instead of
|
|
205
|
+
* a seeded pick, and palette `colors[i]` likewise, so N labels or N bars are
|
|
206
|
+
* ONE layer. `position` (with any count) is the block's top-left anchor;
|
|
207
|
+
* without it the block is centred in `region`.
|
|
208
|
+
*/
|
|
209
|
+
| {
|
|
210
|
+
type: 'list';
|
|
211
|
+
gap?: number;
|
|
212
|
+
} | {
|
|
213
|
+
type: 'table';
|
|
214
|
+
columns: number;
|
|
215
|
+
gap?: number | {
|
|
216
|
+
x?: number;
|
|
217
|
+
y?: number;
|
|
218
|
+
};
|
|
188
219
|
};
|
|
189
220
|
/**
|
|
190
221
|
* Layer lifecycle for act structure — a pure function of t, no state. Alpha is 0
|
|
@@ -196,6 +227,56 @@ interface LayerSpec {
|
|
|
196
227
|
exit?: number;
|
|
197
228
|
fade?: number;
|
|
198
229
|
};
|
|
230
|
+
/**
|
|
231
|
+
* Sparse events — marks that appear, expand and fade in place, one at a time,
|
|
232
|
+
* with long silences between (the "one ping" primitive). Each entity is dark
|
|
233
|
+
* except for a window of `life` ms that recurs every `every` ms at a
|
|
234
|
+
* per-entity offset: `jitter` 1 (default) scatters the offsets (a fixed
|
|
235
|
+
* low-discrepancy sequence — not seeded, so declaring `emit` disturbs no
|
|
236
|
+
* other draw and the same spec times its events identically under every
|
|
237
|
+
* seed), 0 spreads the entities evenly across the period — a metronome, one
|
|
238
|
+
* event at a time as long as `life ≤ every / count`.
|
|
239
|
+
* Inside a window the entity fades in over the first quarter and out over
|
|
240
|
+
* the rest; `grow` scales its size from `grow[0]` to `grow[1]` across the
|
|
241
|
+
* window — expansion rather than travel. A pure function of t. Flash safety:
|
|
242
|
+
* `every` ≥ 1000 ms and `life` ≥ 500 ms, so no entity fires more than once a
|
|
243
|
+
* second and never as a hard cut. Composes with `pulse`, `life`, `trail` and
|
|
244
|
+
* every motion; with `motion.ease` the eased travel restarts on every event.
|
|
245
|
+
*/
|
|
246
|
+
emit?: {
|
|
247
|
+
every: number;
|
|
248
|
+
life: number;
|
|
249
|
+
jitter?: number;
|
|
250
|
+
grow?: [number, number];
|
|
251
|
+
};
|
|
252
|
+
/**
|
|
253
|
+
* Phase-lock. Replaces the seeded per-entity phases of `pulse`, `grow` and
|
|
254
|
+
* `cycle` with one shared phase (`phase` in turns, 0..1, default 0) and runs
|
|
255
|
+
* those three at `rate` × scene time (default 1). Two layers declaring the
|
|
256
|
+
* same clock breathe in step; different phases give a fixed offset (call and
|
|
257
|
+
* response). `pulse.wave` still adds its position-derived phase on top, so a
|
|
258
|
+
* clocked wave stays a wave. Because a clocked layer moves in unison, its
|
|
259
|
+
* `pulse`/`grow` periods must satisfy `period / rate ≥ 1000 ms` (1 Hz).
|
|
260
|
+
*/
|
|
261
|
+
clock?: {
|
|
262
|
+
phase?: number;
|
|
263
|
+
rate?: number;
|
|
264
|
+
};
|
|
265
|
+
}
|
|
266
|
+
/**
|
|
267
|
+
* Closed-form velocity easing for `drift`, `rise` and `wander`. `settle`
|
|
268
|
+
* starts at the entity's speed and decelerates to rest with time constant
|
|
269
|
+
* `tau` ms — it travels `speed × tau` and stops, a mark flung and coming to
|
|
270
|
+
* rest. `buoyant` starts at rest and approaches the speed over `tau` — a
|
|
271
|
+
* bubble reaching terminal velocity. Position stays an analytic function of
|
|
272
|
+
* t (no integration state). With `emit`, the eased travel restarts from the
|
|
273
|
+
* spawn point on every event. For `wander` only the base velocity eases —
|
|
274
|
+
* the harmonic meander keeps breathing, so a settled wanderer hovers rather
|
|
275
|
+
* than freezes.
|
|
276
|
+
*/
|
|
277
|
+
interface MotionEase {
|
|
278
|
+
type: 'settle' | 'buoyant';
|
|
279
|
+
tau: number;
|
|
199
280
|
}
|
|
200
281
|
type SpriteSpec = {
|
|
201
282
|
kind: 'emoji';
|
|
@@ -248,6 +329,8 @@ type SpriteSpec = {
|
|
|
248
329
|
/**
|
|
249
330
|
* Axis-aligned rectangle (rotates with `spin`). `width` is the horizontal size
|
|
250
331
|
* range; `aspect` the height/width ratio range (default [1,1] = squares).
|
|
332
|
+
* `feather` (0..1) softens the edges: that fraction of the half-size fades
|
|
333
|
+
* out toward the border — Rothko's soft-edged block at 0.5–0.8.
|
|
251
334
|
* Mondrian blocks, confetti, city lights.
|
|
252
335
|
*/
|
|
253
336
|
| {
|
|
@@ -255,6 +338,63 @@ type SpriteSpec = {
|
|
|
255
338
|
width: [number, number];
|
|
256
339
|
aspect?: [number, number];
|
|
257
340
|
color: string;
|
|
341
|
+
feather?: number;
|
|
342
|
+
colors?: string[];
|
|
343
|
+
colorWeights?: number[];
|
|
344
|
+
}
|
|
345
|
+
/**
|
|
346
|
+
* A data bar. Entity i draws a bar `length × values[i] / max` long (viewport
|
|
347
|
+
* units of min(w,h)), `thickness` thick, growing from its position toward
|
|
348
|
+
* `direction` (default 'right'). `values` are PAINT — steer
|
|
349
|
+
* `layers.N.sprite.values` and the bars glide; `max` defaults to the largest
|
|
350
|
+
* value. Pair with a `list` layout: a chart is one layer, labels another.
|
|
351
|
+
*/
|
|
352
|
+
| {
|
|
353
|
+
kind: 'bar';
|
|
354
|
+
values: number[];
|
|
355
|
+
length: number;
|
|
356
|
+
thickness: number;
|
|
357
|
+
color: string;
|
|
358
|
+
max?: number;
|
|
359
|
+
direction?: 'right' | 'left' | 'up' | 'down';
|
|
360
|
+
colors?: string[];
|
|
361
|
+
colorWeights?: number[];
|
|
362
|
+
}
|
|
363
|
+
/**
|
|
364
|
+
* Regular or custom polygon. `sides` (3..12, default 6) draws a regular
|
|
365
|
+
* n-gon of the seeded `radius` (circumradius), point up; `points` (3..24
|
|
366
|
+
* unit coordinates in −1..1, scaled by the radius) draws any facet — a
|
|
367
|
+
* Picasso shard, a Kandinsky triangle, a Mondrian plane. `soft` feathers
|
|
368
|
+
* the fill from the centre like a soft circle. Rotates with `spin`.
|
|
369
|
+
*/
|
|
370
|
+
| {
|
|
371
|
+
kind: 'polygon';
|
|
372
|
+
radius: [number, number];
|
|
373
|
+
color: string;
|
|
374
|
+
sides?: number;
|
|
375
|
+
points?: Array<[number, number]>;
|
|
376
|
+
soft?: boolean;
|
|
377
|
+
colors?: string[];
|
|
378
|
+
colorWeights?: number[];
|
|
379
|
+
}
|
|
380
|
+
/**
|
|
381
|
+
* A freehand mark: a path through `points` (2..24 unit coordinates in
|
|
382
|
+
* −1..1, scaled by the seeded `length`) stroked `width` wide with round
|
|
383
|
+
* joins. `curve: 'smooth'` (default) runs a Catmull-Rom spline through the
|
|
384
|
+
* points, `'linear'` a polyline. `taper` thins the mark to almost nothing at
|
|
385
|
+
* both ends — a brush stroke rather than a line. `orient` turns the path's
|
|
386
|
+
* +x along the entity's heading (like `streak`). Rotates with `spin`. Van
|
|
387
|
+
* Gogh's stroke, Hokusai's contour, O'Keeffe's petal, Basquiat's scrawl.
|
|
388
|
+
*/
|
|
389
|
+
| {
|
|
390
|
+
kind: 'stroke';
|
|
391
|
+
length: [number, number];
|
|
392
|
+
points: Array<[number, number]>;
|
|
393
|
+
color: string;
|
|
394
|
+
width?: number;
|
|
395
|
+
curve?: 'smooth' | 'linear';
|
|
396
|
+
taper?: boolean;
|
|
397
|
+
orient?: boolean;
|
|
258
398
|
colors?: string[];
|
|
259
399
|
colorWeights?: number[];
|
|
260
400
|
}
|
|
@@ -338,12 +478,14 @@ type MotionSpec =
|
|
|
338
478
|
angle?: number;
|
|
339
479
|
bidirectional?: boolean;
|
|
340
480
|
bob?: number;
|
|
481
|
+
ease?: MotionEase;
|
|
341
482
|
}
|
|
342
483
|
/** Rise upward (px/sec) with an optional horizontal sway amplitude (px) — bubbles. */
|
|
343
484
|
| {
|
|
344
485
|
type: 'rise';
|
|
345
486
|
speed: [number, number];
|
|
346
487
|
sway?: number;
|
|
488
|
+
ease?: MotionEase;
|
|
347
489
|
}
|
|
348
490
|
/** Bounce diagonally at a per-entity speed, reflecting off the edges (px/sec). */
|
|
349
491
|
| {
|
|
@@ -388,6 +530,7 @@ type MotionSpec =
|
|
|
388
530
|
angle?: number;
|
|
389
531
|
meander?: number;
|
|
390
532
|
coherence?: number;
|
|
533
|
+
ease?: MotionEase;
|
|
391
534
|
}
|
|
392
535
|
/**
|
|
393
536
|
* Perspective starfield: entities live on a depth axis and stream toward the
|
|
@@ -477,6 +620,20 @@ declare const LIMITS: {
|
|
|
477
620
|
readonly minSegmentDuration: 1000;
|
|
478
621
|
readonly maxTransitionDur: 5000;
|
|
479
622
|
readonly minTransitionDur: 200;
|
|
623
|
+
readonly minEmitEvery: 1000;
|
|
624
|
+
readonly maxEmitEvery: 600000;
|
|
625
|
+
readonly minEmitLife: 500;
|
|
626
|
+
readonly maxEmitGrow: 8;
|
|
627
|
+
readonly minClockedPeriod: 1000;
|
|
628
|
+
readonly minClockRate: 0.1;
|
|
629
|
+
readonly maxClockRate: 4;
|
|
630
|
+
readonly defaultListGap: 0.06;
|
|
631
|
+
readonly defaultListGapPx: 40;
|
|
632
|
+
readonly minPolygonSides: 3;
|
|
633
|
+
readonly maxPolygonSides: 12;
|
|
634
|
+
readonly maxShapePoints: 24;
|
|
635
|
+
readonly minEaseTau: 100;
|
|
636
|
+
readonly maxEaseTau: 120000;
|
|
480
637
|
};
|
|
481
638
|
type SequenceTransition = {
|
|
482
639
|
type: 'cut';
|
|
@@ -554,8 +711,12 @@ interface Entity {
|
|
|
554
711
|
orbitCy: number;
|
|
555
712
|
colorIndex: number;
|
|
556
713
|
cyclePeriod: number;
|
|
557
|
-
/** Rect sprite second dimension (height px). Only set for rect sprites. */
|
|
714
|
+
/** Rect sprite second dimension (height px), or bar thickness. Only set for rect / bar sprites. */
|
|
558
715
|
size2?: number;
|
|
716
|
+
/** Reading-order index into `bar.values`. Only set for bar sprites. */
|
|
717
|
+
barIndex?: number;
|
|
718
|
+
/** Placed by a list/table layout: variants cycle from the ordered base index, in step. Only set for data layouts. */
|
|
719
|
+
ordered?: true;
|
|
559
720
|
/** Orbit parent layer key (motion.center = { layer }). Center resolved at render time. */
|
|
560
721
|
orbitParent?: string;
|
|
561
722
|
/** Harmonic drift params. Only set for wander motion. */
|
|
@@ -574,6 +735,23 @@ interface Entity {
|
|
|
574
735
|
cx: number;
|
|
575
736
|
cy: number;
|
|
576
737
|
};
|
|
738
|
+
/** Sparse-event window. Only set when `layer.emit` is declared. `phase` ms offset. */
|
|
739
|
+
emit?: {
|
|
740
|
+
every: number;
|
|
741
|
+
life: number;
|
|
742
|
+
phase: number;
|
|
743
|
+
growFrom: number;
|
|
744
|
+
growTo: number;
|
|
745
|
+
};
|
|
746
|
+
/** Shared-clock time multiplier for pulse/grow/cycle. Only set when `layer.clock` is declared. */
|
|
747
|
+
clockRate?: number;
|
|
748
|
+
/** Shared cycle phase (radians). Only set when `layer.clock` is declared. */
|
|
749
|
+
cyclePhase?: number;
|
|
750
|
+
/** Velocity easing. Only set when the motion declares `ease`. */
|
|
751
|
+
ease?: {
|
|
752
|
+
type: 'settle' | 'buoyant';
|
|
753
|
+
tau: number;
|
|
754
|
+
};
|
|
577
755
|
/** Spline params (pts in px, shared per layer). Only set for path motion. */
|
|
578
756
|
path?: {
|
|
579
757
|
pts: Array<{
|
|
@@ -598,6 +776,14 @@ declare function spriteVariants(sprite: SpriteSpec): number;
|
|
|
598
776
|
* `scale` multiplies every dimensional draw (default 1). Used for viewport units.
|
|
599
777
|
* `countScale` multiplies entity count for density-aware scaling (default 1). */
|
|
600
778
|
declare function buildEntities(layer: LayerSpec, rng: Rng, w: number, h: number, scale?: number, countScale?: number): Entity[];
|
|
779
|
+
/**
|
|
780
|
+
* Where entity `e` sits in its current emit window at time `t`: 0..1 across
|
|
781
|
+
* the visible `life` ms, or null while dark (or when the layer has no `emit`).
|
|
782
|
+
* Pure — the window index is `floor((t - phase) / every)`, no state.
|
|
783
|
+
*/
|
|
784
|
+
declare function emitWindow(e: Entity, t: number): number | null;
|
|
785
|
+
/** Alpha envelope across an emit window: fast smooth attack, slow smooth decay. */
|
|
786
|
+
declare function emitEnvelope(u: number): number;
|
|
601
787
|
/** Analytic opacity of an entity at logical time `t` (ms). Pure, clamped to 0..1. */
|
|
602
788
|
declare function alphaAt(e: Entity, t: number): number;
|
|
603
789
|
/** Analytic size multiplier at time `t` (ms). Pure, clamped to > 0. */
|
|
@@ -762,6 +948,16 @@ declare function structuralSignature(spec: SaverSpec): string;
|
|
|
762
948
|
declare function adviseSpec(spec: SaverSpec, viewport?: {
|
|
763
949
|
width: number;
|
|
764
950
|
height: number;
|
|
951
|
+
},
|
|
952
|
+
/**
|
|
953
|
+
* Sample point. `perceiveScene` forwards its own `t`/`seed` so the advisories
|
|
954
|
+
* describe the same scene its other channels do — without them a caller
|
|
955
|
+
* perceiving at t = 30 s would get `form` for that instant beside an
|
|
956
|
+
* `overlap-seams` advisory computed for a different one.
|
|
957
|
+
*/
|
|
958
|
+
opts?: {
|
|
959
|
+
t?: number;
|
|
960
|
+
seed?: number;
|
|
765
961
|
}): SpecWarning[];
|
|
766
962
|
/**
|
|
767
963
|
* Non-blocking advisory warnings for a validated sequence envelope.
|
|
@@ -772,6 +968,82 @@ declare function adviseSequence(seq: IdleSequence, viewport?: {
|
|
|
772
968
|
height: number;
|
|
773
969
|
}): SpecWarning[];
|
|
774
970
|
|
|
971
|
+
/**
|
|
972
|
+
* Layer cohesion — does a layer read as ONE form, or as N separate marks?
|
|
973
|
+
*
|
|
974
|
+
* The gap this closes: every other perception channel reports a heavily
|
|
975
|
+
* overlapping layer identically whether its sprites merge into a silhouette or
|
|
976
|
+
* stay legible as individual discs. Luminance, coverage, dominance and the
|
|
977
|
+
* braille map are all blind to it, because they measure ink, not edges. An
|
|
978
|
+
* agent drawing a *shape* out of sprites therefore cannot tell success from
|
|
979
|
+
* failure without publishing and looking at real pixels.
|
|
980
|
+
*
|
|
981
|
+
* Two independent facts decide it, so both are reported:
|
|
982
|
+
*
|
|
983
|
+
* - `overlap` — geometry. What fraction of a typical entity's outline is buried
|
|
984
|
+
* inside a sibling. Scattered fields sit near 0; a deliberate mass sits high.
|
|
985
|
+
* - `seamless` — paint. Whether an overlap between two of this layer's entities
|
|
986
|
+
* paints as an invisible join. Only a hard-edged, fully opaque, single-colour,
|
|
987
|
+
* un-blended layer merges; anything else shows every internal edge.
|
|
988
|
+
*
|
|
989
|
+
* Both are analytic, deterministic and renderer-free, like the rest of
|
|
990
|
+
* `perceive.ts`.
|
|
991
|
+
*/
|
|
992
|
+
|
|
993
|
+
/**
|
|
994
|
+
* Sample time for a spec-level cohesion read, matching `perceiveScene`'s own
|
|
995
|
+
* default so the advisory and the reported numbers agree on the usual call.
|
|
996
|
+
* Past all typical `life.enter` staging; `grow` has had time to breathe.
|
|
997
|
+
*/
|
|
998
|
+
declare const COHESION_T = 5000;
|
|
999
|
+
/** What a layer will read as on the wall. */
|
|
1000
|
+
type CohesionRead =
|
|
1001
|
+
/** Entities merge into a single silhouette — the layer draws a shape. */
|
|
1002
|
+
'mass'
|
|
1003
|
+
/** Entities overlap heavily but every overlap paints a visible edge. */
|
|
1004
|
+
| 'seamed'
|
|
1005
|
+
/** Entities stand alone — a field of marks, which most layers are. */
|
|
1006
|
+
| 'marks';
|
|
1007
|
+
interface LayerCohesion {
|
|
1008
|
+
layerIndex: number;
|
|
1009
|
+
key: string | undefined;
|
|
1010
|
+
/**
|
|
1011
|
+
* Mean fraction of an entity's outline covered by a same-layer sibling, 0..1.
|
|
1012
|
+
* `null` for sprite kinds where a merged silhouette is not a meaningful idea
|
|
1013
|
+
* (lines, glyphs and text: ring, streak, stroke, bar, emoji, text, textBlock).
|
|
1014
|
+
*/
|
|
1015
|
+
overlap: number | null;
|
|
1016
|
+
/** Do this layer's overlaps paint as invisible joins? */
|
|
1017
|
+
seamless: boolean;
|
|
1018
|
+
/** Why not, when not — the field to act on. `null` when seamless. */
|
|
1019
|
+
seamCause: string | null;
|
|
1020
|
+
/** The verdict. `null` when `overlap` is null. */
|
|
1021
|
+
reads: CohesionRead | null;
|
|
1022
|
+
}
|
|
1023
|
+
/**
|
|
1024
|
+
* Why this layer's overlaps paint a visible edge, or null when they vanish.
|
|
1025
|
+
*
|
|
1026
|
+
* Opacity is judged over the whole timeline, not this instant: a layer that
|
|
1027
|
+
* breathes with `pulse` is translucent at some point in every cycle, so its
|
|
1028
|
+
* seams appear even if the sampled frame happens to catch it at full alpha.
|
|
1029
|
+
*/
|
|
1030
|
+
declare function seamCauseOf(layer: LayerSpec): string | null;
|
|
1031
|
+
/**
|
|
1032
|
+
* Per-layer cohesion for an already-built scene. Takes entities rather than a
|
|
1033
|
+
* spec so `perceiveScene` and `adviseSpec` can each pass the scene they already
|
|
1034
|
+
* built instead of building a third one.
|
|
1035
|
+
*/
|
|
1036
|
+
declare function cohesionOf(layers: Array<{
|
|
1037
|
+
layer: LayerSpec;
|
|
1038
|
+
entities: Entity[];
|
|
1039
|
+
}>, t: number, w: number, h: number): LayerCohesion[];
|
|
1040
|
+
/**
|
|
1041
|
+
* True when a `seamed` layer is worth warning about: dense enough to be
|
|
1042
|
+
* deliberate, and opaque enough that it cannot be an atmospheric wash. Keeps
|
|
1043
|
+
* the advisory off the soft low-alpha glow fields the playbook recommends.
|
|
1044
|
+
*/
|
|
1045
|
+
declare function seamsWorthWarning(layer: LayerSpec, c: LayerCohesion, entityCount: number): boolean;
|
|
1046
|
+
|
|
775
1047
|
interface LayerSnapshot {
|
|
776
1048
|
key: string | undefined;
|
|
777
1049
|
count: number;
|
|
@@ -918,6 +1190,13 @@ interface DominanceEntry {
|
|
|
918
1190
|
* ribbons, so a comet layer is ranked by its comet, not just its head.
|
|
919
1191
|
*/
|
|
920
1192
|
declare function dominanceRanking(spec: SaverSpec, opts?: PerceiveOptions): DominanceEntry[];
|
|
1193
|
+
/**
|
|
1194
|
+
* Does each layer read as one merged form or as separate marks? The one thing
|
|
1195
|
+
* the luminance maps cannot answer — they measure ink, not edges, so a layer
|
|
1196
|
+
* that merged into a silhouette and one that stayed a pile of discs look
|
|
1197
|
+
* identical in every other channel. See `cohesion.ts`.
|
|
1198
|
+
*/
|
|
1199
|
+
declare function layerCohesion(spec: SaverSpec, opts?: PerceiveOptions): LayerCohesion[];
|
|
921
1200
|
interface LayerMotionStats {
|
|
922
1201
|
layerIndex: number;
|
|
923
1202
|
key: string | undefined;
|
|
@@ -995,6 +1274,8 @@ interface ScenePerception {
|
|
|
995
1274
|
colProfile: number[];
|
|
996
1275
|
dominance: DominanceEntry[];
|
|
997
1276
|
motion: LayerMotionStats[];
|
|
1277
|
+
/** Per layer: merged silhouette, seamed overlap, or separate marks. */
|
|
1278
|
+
form: LayerCohesion[];
|
|
998
1279
|
/** Literal strings + sizes of any text layers (glyphs don't show in the maps). */
|
|
999
1280
|
text: TextSpriteInfo[];
|
|
1000
1281
|
advisories: ReturnType<typeof adviseSpec>;
|
|
@@ -1157,6 +1438,38 @@ declare const MATRIX_RAIN_SPEC: SaverSpec;
|
|
|
1157
1438
|
*/
|
|
1158
1439
|
declare const NOSTALGHIA_CANDLE_SPEC: SaverSpec;
|
|
1159
1440
|
|
|
1441
|
+
/**
|
|
1442
|
+
* Pings — almost nothing, almost never.
|
|
1443
|
+
* A near-black ground and one teal hue. Three rings take turns: each one
|
|
1444
|
+
* appears, grows sixteenfold (0.15× → 2.4× its radius) and fades over four
|
|
1445
|
+
* seconds, then the frame is empty until the next — `emit` with `jitter: 0`
|
|
1446
|
+
* spaces them evenly, one event every four seconds, and `life` is kept at
|
|
1447
|
+
* the stagger so no two rings are ever lit together. Underneath, a few motes rise,
|
|
1448
|
+
* `settle` to rest and fade on their own, longer, seeded schedule. Nothing
|
|
1449
|
+
* travels; everything grows and goes. The house style Fathom describes this
|
|
1450
|
+
* exactly and, before `emit`, could not be authored.
|
|
1451
|
+
*/
|
|
1452
|
+
declare const PINGS_SPEC: SaverSpec;
|
|
1453
|
+
|
|
1454
|
+
/**
|
|
1455
|
+
* Facets — a composition in the manner of the early abstractionists: three
|
|
1456
|
+
* soft-edged colour planes (feathered `rect`) breathing slowly behind a field
|
|
1457
|
+
* of tumbling triangular facets (custom `polygon`), tapered brush arcs
|
|
1458
|
+
* (`stroke`) drifting across, and a few glowing hexagons (soft regular
|
|
1459
|
+
* `polygon`). Every glyph here is a path, not a disc — the shape family nine
|
|
1460
|
+
* of the fifteen style profiles asked for.
|
|
1461
|
+
*/
|
|
1462
|
+
declare const FACETS_SPEC: SaverSpec;
|
|
1463
|
+
|
|
1464
|
+
/**
|
|
1465
|
+
* Relay Board — a six-row status chart in five layers instead of twenty-five.
|
|
1466
|
+
* One `list` of labels, one `list` of `bar`s whose lengths are the numbers,
|
|
1467
|
+
* one `list` of readouts, a title block, and a slow dust field behind so the
|
|
1468
|
+
* board reads as a live wall, not a document. Steer `bars.values` and the
|
|
1469
|
+
* bars glide to the new figures; the labels never move.
|
|
1470
|
+
*/
|
|
1471
|
+
declare const RELAY_BOARD_SPEC: SaverSpec;
|
|
1472
|
+
|
|
1160
1473
|
/**
|
|
1161
1474
|
* Polygons: the classic Mystify-style bouncing-polygon saver, expressed as chain links + heavy
|
|
1162
1475
|
* ghosting. Showcases `links.mode: 'chain'` with `closed` (vertices wired in order
|
|
@@ -1193,4 +1506,4 @@ declare const EXAMPLE_SPECS: SaverSpec[];
|
|
|
1193
1506
|
/** Lookup by saver id. */
|
|
1194
1507
|
declare const EXAMPLE_BY_ID: Readonly<Record<string, SaverSpec>>;
|
|
1195
1508
|
|
|
1196
|
-
export { AQUARIUM_SPEC, AURORA_SPEC, type BackgroundDrift, type BackgroundSpec, type BandSpec, COMETS_SPEC, CONSTELLATION_SPEC, type CycleSpec, DASHBOARD_SPEC, type DominanceEntry, EXAMPLE_BY_ID, EXAMPLE_SPECS, type Entity, type GradientStop, HAIKU_SPEC, type IdleSequence, LANTERNS_SPEC, LIMITS, type LayerMotionStats, type LayerSnapshot, type LayerSpec, type LinkEdge, type LuminanceGrid, type LuminanceGridOptions, MATRIX_RAIN_SPEC, type MotionSpec, NOSTALGHIA_CANDLE_SPEC, ORRERY_SPEC, POLYGONS_SPEC, PROCESSION_SPEC, type PerceiveOptions, type Placed, RAIN_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, compileSaver, compileSequence, describeScene, diffScenes, dominanceRanking, easeSmooth, graphemeClusters, headingAt, lerpSpec, lifeAlphaAt, linkEdges, linkPairs, luminanceGrid, manifestFor, motionStats, perceiveScene, positionAt, renderBrailleMap, renderDensityMap, resolveSegment, resolveSpecPath, revealState, rotationAt, segmentStart, sizeAt, spriteIndexAt, spriteVariants, steerablePaths, structuralSignature, textSprites, textWidthEm, validateSequence, validateSpec };
|
|
1509
|
+
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 };
|