@idle-screens/schema 1.0.0 → 2.1.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 +135 -0
- package/dist/index.d.ts +167 -4
- package/dist/index.js +778 -200
- package/dist/index.js.map +1 -1
- package/package.json +9 -5
- package/saver-spec.schema.json +287 -0
package/FORMAT.md
ADDED
|
@@ -0,0 +1,135 @@
|
|
|
1
|
+
# SaverSpec — Format Specification (version 1)
|
|
2
|
+
|
|
3
|
+
The declarative, agent-authorable screensaver format compiled by
|
|
4
|
+
`@idle-screens/schema`. A spec describes a saver as **data** — a static
|
|
5
|
+
background plus layers of moving sprites — which `compileSaver()` turns into a
|
|
6
|
+
seeded, deterministic, flash-safe `SaverPlugin`. There is no code in a spec: no
|
|
7
|
+
scripting, no network access, no DOM access.
|
|
8
|
+
|
|
9
|
+
- **Machine-readable schema:** [`saver-spec.schema.json`](./saver-spec.schema.json)
|
|
10
|
+
(JSON Schema draft-07), importable as
|
|
11
|
+
`@idle-screens/schema/saver-spec.schema.json`.
|
|
12
|
+
- **Runtime validator:** `validateSpec(spec)` / `assertValidSpec(spec)` — used by
|
|
13
|
+
`compileSaver()`, which refuses to run an invalid spec.
|
|
14
|
+
|
|
15
|
+
## Versioning
|
|
16
|
+
|
|
17
|
+
The **format version** (`schemaVersion`, currently `1`) is independent of the
|
|
18
|
+
npm package version. The package may ship breaking API changes without bumping
|
|
19
|
+
the format; the format only bumps when existing specs would parse or render
|
|
20
|
+
differently. New *optional* fields may be added within a format version —
|
|
21
|
+
older runtimes ignore unknown fields (see Validation semantics).
|
|
22
|
+
|
|
23
|
+
Additions to version 1 so far, all optional and backward compatible:
|
|
24
|
+
`alpha`, `blend`, `pulse`, `region` (layer appearance/placement);
|
|
25
|
+
`static` motion, `position`, `key` (dashboard/HUD support);
|
|
26
|
+
`align`, `baseline`, `maxWidth` (text sprites).
|
|
27
|
+
|
|
28
|
+
## Safety invariants
|
|
29
|
+
|
|
30
|
+
These hold **by construction** — no spec can violate them:
|
|
31
|
+
|
|
32
|
+
1. **No flash primitive.** The background is static and entities are bounded
|
|
33
|
+
sprites, so a compiled spec cannot strobe the full field. Provable by
|
|
34
|
+
sampling any compiled spec through `@idle-screens/validator`.
|
|
35
|
+
2. **Pulse is bounded.** Opacity breathing amplitude is capped at 0.5 and its
|
|
36
|
+
period floored at 500 ms (2 Hz — under the WCAG 3 Hz flash threshold), and
|
|
37
|
+
every entity gets its own seeded phase, so a layer can never pulse in unison.
|
|
38
|
+
3. **Motion is bounded.** Speeds are capped at 4000 px/sec.
|
|
39
|
+
4. **Work is bounded.** ≤ 36 layers, ≤ 400 entities per layer, ≤ 800 total.
|
|
40
|
+
5. **Determinism.** All randomness comes from a seeded PRNG. Same spec + same
|
|
41
|
+
seed ⇒ identical entity streams and identical frames at any time `t`
|
|
42
|
+
(compiled savers expose `renderFrame(t, seed)`).
|
|
43
|
+
|
|
44
|
+
## Validation semantics
|
|
45
|
+
|
|
46
|
+
Two validators exist with deliberately different strictness:
|
|
47
|
+
|
|
48
|
+
| | unknown fields | everything else |
|
|
49
|
+
|---|---|---|
|
|
50
|
+
| `saver-spec.schema.json` | **rejected** (catches authoring typos) | identical |
|
|
51
|
+
| `validateSpec()` (runtime) | **ignored** (forward compatibility) | identical |
|
|
52
|
+
|
|
53
|
+
Author against the JSON Schema; ship through the runtime validator.
|
|
54
|
+
|
|
55
|
+
Two rules the JSON Schema cannot fully express (the runtime enforces them):
|
|
56
|
+
total entities across all layers ≤ 800, and every `[min, max]` range must
|
|
57
|
+
satisfy `min ≤ max`.
|
|
58
|
+
|
|
59
|
+
## Structure
|
|
60
|
+
|
|
61
|
+
```jsonc
|
|
62
|
+
{
|
|
63
|
+
"schemaVersion": 1,
|
|
64
|
+
"id": "snowfall", // unique kebab-case id
|
|
65
|
+
"label": "Snowfall",
|
|
66
|
+
"seed": 42, // optional; falls back to the host's seed
|
|
67
|
+
"motionIntensity": "calm", // optional: calm | moderate | energetic
|
|
68
|
+
"background": { ... }, // optional; defaults to black
|
|
69
|
+
"layers": [ { ... }, ... ] // 1..36, rendered back-to-front
|
|
70
|
+
}
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
### `background`
|
|
74
|
+
|
|
75
|
+
- `{ "type": "solid", "color": "#06060c" }`
|
|
76
|
+
- `{ "type": "gradient", "stops": [{ "at": 0, "color": "#06121e" }, { "at": 1, "color": "#0d2436" }], "band": { "color": "#3a2d18", "height": 90 } }`
|
|
77
|
+
— vertical gradient (`at` 0 = top → 1 = bottom); optional solid `band` at the
|
|
78
|
+
bottom (e.g. an aquarium seafloor). All colours are hex (`#rgb` / `#rrggbb`).
|
|
79
|
+
|
|
80
|
+
### `layers[]`
|
|
81
|
+
|
|
82
|
+
| Field | Type | Default | Meaning |
|
|
83
|
+
|---|---|---|---|
|
|
84
|
+
| `count` | int 1..400 | — | entities in this layer |
|
|
85
|
+
| `sprite` | SpriteSpec | — | what each entity looks like |
|
|
86
|
+
| `motion` | MotionSpec | — | how entities move |
|
|
87
|
+
| `size` | `[min,max]` px > 0 | sprite-dependent | font size for emoji/text; ignored for circle |
|
|
88
|
+
| `wrap` | boolean | `true` | wrap to the opposite edge when leaving the viewport |
|
|
89
|
+
| `flip` | boolean | `false` | mirror the sprite to face its heading |
|
|
90
|
+
| `alpha` | `[min,max]` 0..1 | `[1,1]` | per-entity opacity range |
|
|
91
|
+
| `blend` | `"lighter"` | source-over | additive compositing (glow stacking) |
|
|
92
|
+
| `region` | `{x?, y?}` ranges 0..1 | full viewport | fractional spawn window (placement only, not travel) |
|
|
93
|
+
| `pulse` | `{amp ≤ 0.5, period ≥ 500}` | none | seeded-phase opacity breathing |
|
|
94
|
+
| `key` | string | none | addressable name → `setParam("key.field", …)` |
|
|
95
|
+
| `position` | `{x, y}` 0..1 | none | exact placement; **requires `count: 1`**; overrides `region` |
|
|
96
|
+
|
|
97
|
+
### `sprite` (one of)
|
|
98
|
+
|
|
99
|
+
- `{ "kind": "emoji", "glyphs": ["🐟", "🐠"] }` — glyph picked per entity (seeded)
|
|
100
|
+
- `{ "kind": "text", "strings": ["HELLO"], "color": "#e6e8ef", "font": "bold 24px monospace", "align": "center", "baseline": "middle", "maxWidth": 300 }`
|
|
101
|
+
- `{ "kind": "circle", "radius": [1, 3], "color": "#ffffff", "soft": true }` —
|
|
102
|
+
`soft` renders a radial-falloff glow orb instead of a hard disc
|
|
103
|
+
|
|
104
|
+
### `motion` (one of)
|
|
105
|
+
|
|
106
|
+
- `{ "type": "drift", "speed": [20, 60], "angle": 0, "bidirectional": true, "bob": 4 }`
|
|
107
|
+
— heading in degrees (0 = right, 90 = down); `bidirectional` flips horizontal
|
|
108
|
+
direction per entity (fish); `bob` adds vertical wobble (px)
|
|
109
|
+
- `{ "type": "rise", "speed": [10, 30], "sway": 6 }` — upward, with horizontal sway (bubbles)
|
|
110
|
+
- `{ "type": "bounce", "speed": [120, 240] }` — diagonal, reflecting off edges
|
|
111
|
+
- `{ "type": "static" }` — stays exactly where placed (use with `position` for HUD text)
|
|
112
|
+
|
|
113
|
+
All speeds are px/sec ranges; each entity draws its own value (seeded).
|
|
114
|
+
|
|
115
|
+
## Determinism contract
|
|
116
|
+
|
|
117
|
+
Entity construction consumes the seeded RNG in a **fixed draw order** per layer.
|
|
118
|
+
New optional fields only consume RNG draws when present, so adding features to
|
|
119
|
+
the format never changes the entity stream of an existing spec — a spec authored
|
|
120
|
+
against an older runtime renders bit-identically on a newer one.
|
|
121
|
+
|
|
122
|
+
## Steering
|
|
123
|
+
|
|
124
|
+
Compiled specs accept live parameter changes via dot-paths —
|
|
125
|
+
`layers.0.count`, `background.stops.0.color`, or `key`-based paths like
|
|
126
|
+
`cpu-gauge.color` when layers declare `key`. Changes interpolate over a
|
|
127
|
+
control-track (`step` | `linear` | `smooth`). See `@idle-screens/core` for
|
|
128
|
+
`ControlTrack` and the idlescreens.com MCP `setParam` tool.
|
|
129
|
+
|
|
130
|
+
## Examples
|
|
131
|
+
|
|
132
|
+
Shipped working specs (also exposed as `EXAMPLE_SPECS`): `aquarium`, `rain`,
|
|
133
|
+
`snowfall`, `lanterns`, `sakura`, `dev-dashboard` — see
|
|
134
|
+
[`src/examples.ts`](./src/examples.ts). The dashboard exercises the static/HUD
|
|
135
|
+
subset at scale (34 layers of keyed, positioned text).
|
package/dist/index.d.ts
CHANGED
|
@@ -22,6 +22,8 @@ interface SaverSpec {
|
|
|
22
22
|
background?: BackgroundSpec;
|
|
23
23
|
layers: LayerSpec[];
|
|
24
24
|
motionIntensity?: 'calm' | 'moderate' | 'energetic';
|
|
25
|
+
/** Dimensional unit system. 'viewport' = all sizes/speeds/distances are fractions of min(w,h). */
|
|
26
|
+
units?: 'px' | 'viewport';
|
|
25
27
|
}
|
|
26
28
|
type BackgroundSpec = {
|
|
27
29
|
type: 'solid';
|
|
@@ -74,6 +76,20 @@ interface LayerSpec {
|
|
|
74
76
|
amp: number;
|
|
75
77
|
period: number;
|
|
76
78
|
};
|
|
79
|
+
/**
|
|
80
|
+
* Per-entity rotation speed in degrees/sec (positive = clockwise).
|
|
81
|
+
* Each entity gets a seeded starting angle. Composes with any motion type.
|
|
82
|
+
*/
|
|
83
|
+
spin?: number;
|
|
84
|
+
/**
|
|
85
|
+
* Sinusoidal size breathing, parallel to `pulse` for opacity. `amp` is a
|
|
86
|
+
* fraction of base size (0.3 = ±30 %). `period` in ms with the same
|
|
87
|
+
* flash-safety floor as pulse. Per-entity seeded phase.
|
|
88
|
+
*/
|
|
89
|
+
grow?: {
|
|
90
|
+
amp: number;
|
|
91
|
+
period: number;
|
|
92
|
+
};
|
|
77
93
|
/**
|
|
78
94
|
* Addressable name for this layer. Enables `setParam` to use `key.field` paths
|
|
79
95
|
* instead of `layers.N.field` indices. Also makes specs self-documenting.
|
|
@@ -87,10 +103,22 @@ interface LayerSpec {
|
|
|
87
103
|
x: number;
|
|
88
104
|
y: number;
|
|
89
105
|
};
|
|
106
|
+
/**
|
|
107
|
+
* Inter-entity links: draw lines to each entity's k nearest neighbors within maxDist.
|
|
108
|
+
* Capped at LIMITS.maxLinksK. Layer count must be <= LIMITS.maxLinkLayerCount when set.
|
|
109
|
+
*/
|
|
110
|
+
links?: {
|
|
111
|
+
k: number;
|
|
112
|
+
maxDist: number;
|
|
113
|
+
color?: string;
|
|
114
|
+
alpha?: number;
|
|
115
|
+
width?: number;
|
|
116
|
+
};
|
|
90
117
|
}
|
|
91
118
|
type SpriteSpec = {
|
|
92
119
|
kind: 'emoji';
|
|
93
120
|
glyphs: string[];
|
|
121
|
+
cycle?: CycleSpec;
|
|
94
122
|
} | {
|
|
95
123
|
kind: 'text';
|
|
96
124
|
strings: string[];
|
|
@@ -99,6 +127,7 @@ type SpriteSpec = {
|
|
|
99
127
|
align?: 'left' | 'center' | 'right';
|
|
100
128
|
baseline?: 'top' | 'middle' | 'bottom';
|
|
101
129
|
maxWidth?: number;
|
|
130
|
+
cycle?: CycleSpec;
|
|
102
131
|
}
|
|
103
132
|
/** `soft` renders a radial falloff (glow orb) instead of a hard disc. */
|
|
104
133
|
| {
|
|
@@ -106,7 +135,12 @@ type SpriteSpec = {
|
|
|
106
135
|
radius: [number, number];
|
|
107
136
|
color: string;
|
|
108
137
|
soft?: boolean;
|
|
138
|
+
colors?: string[];
|
|
109
139
|
};
|
|
140
|
+
/** Rotate through sprite variants over time. Each entity offsets by its seeded phase. */
|
|
141
|
+
interface CycleSpec {
|
|
142
|
+
period: number;
|
|
143
|
+
}
|
|
110
144
|
type MotionSpec =
|
|
111
145
|
/**
|
|
112
146
|
* Drift at a per-entity speed picked from `speed` (px/sec) along `angle` degrees
|
|
@@ -136,6 +170,20 @@ type MotionSpec =
|
|
|
136
170
|
/** Entity stays exactly where placed. No movement. Use with `position` for pinned elements. */
|
|
137
171
|
| {
|
|
138
172
|
type: 'static';
|
|
173
|
+
}
|
|
174
|
+
/**
|
|
175
|
+
* Orbit around a center point. Each entity gets a seeded radius from `radius`
|
|
176
|
+
* and a seeded phase. `speed` is angular velocity in degrees/sec. `center` is
|
|
177
|
+
* fractional {x, y} (default {0.5, 0.5} = viewport center).
|
|
178
|
+
*/
|
|
179
|
+
| {
|
|
180
|
+
type: 'orbit';
|
|
181
|
+
speed: [number, number];
|
|
182
|
+
radius: [number, number];
|
|
183
|
+
center?: {
|
|
184
|
+
x: number;
|
|
185
|
+
y: number;
|
|
186
|
+
};
|
|
139
187
|
};
|
|
140
188
|
/** A validation problem, pointing at a JSON path within the spec. */
|
|
141
189
|
interface SpecError {
|
|
@@ -146,6 +194,12 @@ interface ValidationResult {
|
|
|
146
194
|
valid: boolean;
|
|
147
195
|
errors: SpecError[];
|
|
148
196
|
}
|
|
197
|
+
/** An advisory warning (non-blocking). Returned by `adviseSpec`. */
|
|
198
|
+
interface SpecWarning {
|
|
199
|
+
path: string;
|
|
200
|
+
code: string;
|
|
201
|
+
message: string;
|
|
202
|
+
}
|
|
149
203
|
/** Perf/safety caps enforced by `validateSpec`. */
|
|
150
204
|
declare const LIMITS: {
|
|
151
205
|
readonly maxPerLayer: 400;
|
|
@@ -154,6 +208,13 @@ declare const LIMITS: {
|
|
|
154
208
|
readonly maxSpeed: 4000;
|
|
155
209
|
readonly maxPulseAmp: 0.5;
|
|
156
210
|
readonly minPulsePeriod: 500;
|
|
211
|
+
readonly maxSpin: 360;
|
|
212
|
+
readonly maxGrowAmp: 0.8;
|
|
213
|
+
readonly maxOrbitSpeed: 180;
|
|
214
|
+
readonly maxLinksK: 8;
|
|
215
|
+
readonly maxLinkLayerCount: 200;
|
|
216
|
+
readonly minCyclePeriod: 500;
|
|
217
|
+
readonly referenceViewport: 1080;
|
|
157
218
|
};
|
|
158
219
|
|
|
159
220
|
/**
|
|
@@ -175,12 +236,22 @@ interface Entity {
|
|
|
175
236
|
vx: number;
|
|
176
237
|
vy: number;
|
|
177
238
|
bob: number;
|
|
178
|
-
motion: 'drift' | 'rise' | 'bounce' | 'static';
|
|
239
|
+
motion: 'drift' | 'rise' | 'bounce' | 'static' | 'orbit';
|
|
179
240
|
headingLeft: boolean;
|
|
180
241
|
alpha: number;
|
|
181
242
|
pulseAmp: number;
|
|
182
243
|
pulsePeriod: number;
|
|
183
244
|
pulsePhase: number;
|
|
245
|
+
spinSpeed: number;
|
|
246
|
+
spinPhase: number;
|
|
247
|
+
growAmp: number;
|
|
248
|
+
growPeriod: number;
|
|
249
|
+
growPhase: number;
|
|
250
|
+
orbitR: number;
|
|
251
|
+
orbitCx: number;
|
|
252
|
+
orbitCy: number;
|
|
253
|
+
colorIndex: number;
|
|
254
|
+
cyclePeriod: number;
|
|
184
255
|
}
|
|
185
256
|
interface Placed {
|
|
186
257
|
x: number;
|
|
@@ -188,12 +259,25 @@ interface Placed {
|
|
|
188
259
|
flip: boolean;
|
|
189
260
|
}
|
|
190
261
|
declare function spriteVariants(sprite: SpriteSpec): number;
|
|
191
|
-
/** Deterministically place a layer's entities using the seeded RNG (never Math.random).
|
|
192
|
-
|
|
262
|
+
/** Deterministically place a layer's entities using the seeded RNG (never Math.random).
|
|
263
|
+
* `scale` multiplies every dimensional draw (default 1). Used for viewport units. */
|
|
264
|
+
declare function buildEntities(layer: LayerSpec, rng: Rng, w: number, h: number, scale?: number): Entity[];
|
|
193
265
|
/** Analytic opacity of an entity at logical time `t` (ms). Pure, clamped to 0..1. */
|
|
194
266
|
declare function alphaAt(e: Entity, t: number): number;
|
|
267
|
+
/** Analytic size multiplier at time `t` (ms). Pure, clamped to > 0. */
|
|
268
|
+
declare function sizeAt(e: Entity, t: number): number;
|
|
269
|
+
/** Analytic rotation angle at time `t` (ms) in radians. Pure. */
|
|
270
|
+
declare function rotationAt(e: Entity, t: number): number;
|
|
195
271
|
/** Analytic position of an entity at logical time `t` (ms). Pure & deterministic. */
|
|
196
272
|
declare function positionAt(e: Entity, t: number, w: number, h: number): Placed;
|
|
273
|
+
/** Time-varying sprite index for text/emoji cycling. Returns static index when cyclePeriod is 0. */
|
|
274
|
+
declare function spriteIndexAt(e: Entity, t: number, variants: number): number;
|
|
275
|
+
/** K-nearest-neighbor edge list. Deterministic tie-break: (dist, index).
|
|
276
|
+
* When `doWrap` is true, uses toroidal distance so links don't streak across wrap seams. */
|
|
277
|
+
declare function linkPairs(positions: Array<{
|
|
278
|
+
x: number;
|
|
279
|
+
y: number;
|
|
280
|
+
}>, k: number, maxDist: number, doWrap: boolean, w: number, h: number): Array<[number, number]>;
|
|
197
281
|
|
|
198
282
|
/** Derive a manifest so a compiled spec composes with @idle-screens/capabilities. */
|
|
199
283
|
declare function manifestFor(spec: SaverSpec): SaverManifest;
|
|
@@ -204,16 +288,73 @@ declare function manifestFor(spec: SaverSpec): SaverManifest;
|
|
|
204
288
|
*/
|
|
205
289
|
declare function compileSaver(spec: unknown): SaverPlugin;
|
|
206
290
|
|
|
291
|
+
/**
|
|
292
|
+
* Pure helpers for LIVE steering of compiled specs (setParam / applyTrack).
|
|
293
|
+
* A track's deltas address spec fields by dot-path ("layers.0.count",
|
|
294
|
+
* "background.stops.1.color") or layer key ("fireflies.count"). Steering
|
|
295
|
+
* changes existing values only — unknown paths are ignored (the server
|
|
296
|
+
* validates and rejects them; the runtime stays lenient).
|
|
297
|
+
*/
|
|
298
|
+
|
|
299
|
+
interface PathTarget {
|
|
300
|
+
parent: Record<string, unknown> | unknown[];
|
|
301
|
+
key: string | number;
|
|
302
|
+
}
|
|
303
|
+
/** Resolve a dot-path (key-aware) to its parent + final key; null if absent. */
|
|
304
|
+
declare function resolveSpecPath(spec: unknown, path: string): PathTarget | null;
|
|
305
|
+
/** A steering delta as carried on a channel control-track. */
|
|
306
|
+
interface SteerDelta {
|
|
307
|
+
t: number;
|
|
308
|
+
path: string;
|
|
309
|
+
value: unknown;
|
|
310
|
+
ease?: string;
|
|
311
|
+
dur?: number;
|
|
312
|
+
}
|
|
313
|
+
/** Apply deltas to a deep copy of the spec (last-wins, target values). */
|
|
314
|
+
declare function applyDeltasToSpec(spec: SaverSpec, deltas: SteerDelta[]): SaverSpec;
|
|
315
|
+
/**
|
|
316
|
+
* Interpolate between two structurally-similar specs at progress k (0..1).
|
|
317
|
+
* Numbers lerp, hex colours lerp per channel, everything else steps to the
|
|
318
|
+
* target immediately (k > 0). Layer counts round to integers.
|
|
319
|
+
*/
|
|
320
|
+
declare function lerpSpec(from: SaverSpec, to: SaverSpec, k: number): SaverSpec;
|
|
321
|
+
/** Smooth (ease-in-out) progress curve used for glides. */
|
|
322
|
+
declare function easeSmooth(k: number): number;
|
|
323
|
+
/**
|
|
324
|
+
* Fields that require re-seeding entities when they change (placement/motion
|
|
325
|
+
* are baked at build time). Colour/alpha/pulse-only changes redraw in place.
|
|
326
|
+
*/
|
|
327
|
+
declare function structuralSignature(spec: SaverSpec): string;
|
|
328
|
+
|
|
329
|
+
/**
|
|
330
|
+
* Non-blocking advisory warnings for a valid spec. Does NOT replace validateSpec —
|
|
331
|
+
* call advise only on specs that have already passed validation.
|
|
332
|
+
*/
|
|
333
|
+
declare function adviseSpec(spec: SaverSpec, viewport?: {
|
|
334
|
+
width: number;
|
|
335
|
+
height: number;
|
|
336
|
+
}): SpecWarning[];
|
|
337
|
+
|
|
207
338
|
/**
|
|
208
339
|
* Reproduces the hand-coded Fish Aquarium saver as pure DATA — the discriminating test
|
|
209
340
|
* that the schema is actually expressive: two layers (fish drifting both ways at varied
|
|
210
341
|
* speeds with a bob + flip, over a gradient with a seafloor band; bubbles rising with sway).
|
|
211
342
|
*/
|
|
212
343
|
declare const AQUARIUM_SPEC: SaverSpec;
|
|
344
|
+
|
|
345
|
+
/**
|
|
346
|
+
* Constellation: drifting stars connected by faint k-nearest links. Exercises
|
|
347
|
+
* colors[] (multi-hued stars), links (k-nearest neighbor lines), and cycle
|
|
348
|
+
* (emoji asterisms rotate glyphs). Stars are soft circles in pixel units.
|
|
349
|
+
*/
|
|
350
|
+
declare const CONSTELLATION_SPEC: SaverSpec;
|
|
351
|
+
|
|
213
352
|
/** Rain: dense text streaks falling straight down over a near-black sky. */
|
|
214
353
|
declare const RAIN_SPEC: SaverSpec;
|
|
354
|
+
|
|
215
355
|
/** Snowfall: three depth layers of white circles drifting down with horizontal bob. */
|
|
216
356
|
declare const SNOWFALL_SPEC: SaverSpec;
|
|
357
|
+
|
|
217
358
|
/**
|
|
218
359
|
* Night Lanterns (Yi Peng festival sky): depth from four correlated parallax cues —
|
|
219
360
|
* closer layers are LARGER, FASTER, SWAY WIDER, and glow WARMER/BRIGHTER. v2 of this
|
|
@@ -224,6 +365,7 @@ declare const SNOWFALL_SPEC: SaverSpec;
|
|
|
224
365
|
* the water line).
|
|
225
366
|
*/
|
|
226
367
|
declare const LANTERNS_SPEC: SaverSpec;
|
|
368
|
+
|
|
227
369
|
/**
|
|
228
370
|
* Sakura Drift: cherry-blossom petals carried on a spring twilight breeze. Five
|
|
229
371
|
* correlated-parallax layers build the depth — the far backdrop is a barely-moving
|
|
@@ -236,6 +378,7 @@ declare const LANTERNS_SPEC: SaverSpec;
|
|
|
236
378
|
* diagonal breeze, and from lanterns by falling rather than rising.
|
|
237
379
|
*/
|
|
238
380
|
declare const SAKURA_SPEC: SaverSpec;
|
|
381
|
+
|
|
239
382
|
/**
|
|
240
383
|
* Dev Dashboard: a dense ops-style HUD exercising static positioning, keyed layers,
|
|
241
384
|
* and text alignment at scale. Two ambient particle layers provide depth behind 28
|
|
@@ -243,6 +386,26 @@ declare const SAKURA_SPEC: SaverSpec;
|
|
|
243
386
|
* file list, and scrolling event log.
|
|
244
387
|
*/
|
|
245
388
|
declare const DASHBOARD_SPEC: SaverSpec;
|
|
389
|
+
|
|
390
|
+
/**
|
|
391
|
+
* Orrery: a mechanical solar system. Exercises orbit motion (concentric rings
|
|
392
|
+
* at different speeds), spin (planets rotate on their axes), and grow (the sun
|
|
393
|
+
* pulses). Soft glow circles with additive blending create the corona and
|
|
394
|
+
* planetary halos.
|
|
395
|
+
*/
|
|
396
|
+
declare const ORRERY_SPEC: SaverSpec;
|
|
397
|
+
|
|
398
|
+
/** Catalog entry for a bundled schema example. */
|
|
399
|
+
interface SchemaExample {
|
|
400
|
+
id: string;
|
|
401
|
+
label: string;
|
|
402
|
+
spec: SaverSpec;
|
|
403
|
+
}
|
|
404
|
+
/** Ordered catalog of bundled schema examples. Add new specs as standalone files, then register here. */
|
|
405
|
+
declare const SCHEMA_EXAMPLES: readonly SchemaExample[];
|
|
406
|
+
/** All example specs in catalog order (tests, batch compile). */
|
|
246
407
|
declare const EXAMPLE_SPECS: SaverSpec[];
|
|
408
|
+
/** Lookup by saver id. */
|
|
409
|
+
declare const EXAMPLE_BY_ID: Readonly<Record<string, SaverSpec>>;
|
|
247
410
|
|
|
248
|
-
export { AQUARIUM_SPEC, type BackgroundSpec, type BandSpec, DASHBOARD_SPEC, EXAMPLE_SPECS, type Entity, type GradientStop, LANTERNS_SPEC, LIMITS, type LayerSpec, type MotionSpec, type Placed, RAIN_SPEC, SAKURA_SPEC, SCHEMA_VERSION, SNOWFALL_SPEC, type SaverSpec, type SpecError, type SpriteSpec, type ValidationResult, alphaAt, assertValidSpec, buildEntities, compileSaver, manifestFor, positionAt, spriteVariants, validateSpec };
|
|
411
|
+
export { AQUARIUM_SPEC, type BackgroundSpec, type BandSpec, CONSTELLATION_SPEC, type CycleSpec, DASHBOARD_SPEC, EXAMPLE_BY_ID, EXAMPLE_SPECS, type Entity, type GradientStop, LANTERNS_SPEC, LIMITS, type LayerSpec, type MotionSpec, ORRERY_SPEC, type Placed, RAIN_SPEC, SAKURA_SPEC, SCHEMA_EXAMPLES, SCHEMA_VERSION, SNOWFALL_SPEC, type SaverSpec, type SchemaExample, type SpecError, type SpecWarning, type SpriteSpec, type SteerDelta, type ValidationResult, adviseSpec, alphaAt, applyDeltasToSpec, assertValidSpec, buildEntities, compileSaver, easeSmooth, lerpSpec, linkPairs, manifestFor, positionAt, resolveSpecPath, rotationAt, sizeAt, spriteIndexAt, spriteVariants, structuralSignature, validateSpec };
|