@idle-screens/schema 2.0.0 → 2.2.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 +201 -5
- package/dist/index.js +869 -44
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
- package/saver-spec.schema.json +86 -3
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';
|
|
@@ -30,6 +32,7 @@ type BackgroundSpec = {
|
|
|
30
32
|
type: 'gradient';
|
|
31
33
|
stops: GradientStop[];
|
|
32
34
|
band?: BandSpec;
|
|
35
|
+
drift?: BackgroundDrift;
|
|
33
36
|
};
|
|
34
37
|
/** A vertical gradient stop (`at` 0 = top, 1 = bottom). */
|
|
35
38
|
interface GradientStop {
|
|
@@ -42,6 +45,13 @@ interface BandSpec {
|
|
|
42
45
|
/** Band height in px. */
|
|
43
46
|
height: number;
|
|
44
47
|
}
|
|
48
|
+
/** Slow oscillation of gradient stop positions — makes the background feel alive. */
|
|
49
|
+
interface BackgroundDrift {
|
|
50
|
+
/** Full cycle period in ms. Floor: LIMITS.minDriftPeriod (10 s). */
|
|
51
|
+
period: number;
|
|
52
|
+
/** How far stops shift (fraction of the 0..1 range). Default 0.15, max 0.3. */
|
|
53
|
+
amount?: number;
|
|
54
|
+
}
|
|
45
55
|
interface LayerSpec {
|
|
46
56
|
count: number;
|
|
47
57
|
sprite: SpriteSpec;
|
|
@@ -74,6 +84,20 @@ interface LayerSpec {
|
|
|
74
84
|
amp: number;
|
|
75
85
|
period: number;
|
|
76
86
|
};
|
|
87
|
+
/**
|
|
88
|
+
* Per-entity rotation speed in degrees/sec (positive = clockwise).
|
|
89
|
+
* Each entity gets a seeded starting angle. Composes with any motion type.
|
|
90
|
+
*/
|
|
91
|
+
spin?: number;
|
|
92
|
+
/**
|
|
93
|
+
* Sinusoidal size breathing, parallel to `pulse` for opacity. `amp` is a
|
|
94
|
+
* fraction of base size (0.3 = ±30 %). `period` in ms with the same
|
|
95
|
+
* flash-safety floor as pulse. Per-entity seeded phase.
|
|
96
|
+
*/
|
|
97
|
+
grow?: {
|
|
98
|
+
amp: number;
|
|
99
|
+
period: number;
|
|
100
|
+
};
|
|
77
101
|
/**
|
|
78
102
|
* Addressable name for this layer. Enables `setParam` to use `key.field` paths
|
|
79
103
|
* instead of `layers.N.field` indices. Also makes specs self-documenting.
|
|
@@ -87,10 +111,30 @@ interface LayerSpec {
|
|
|
87
111
|
x: number;
|
|
88
112
|
y: number;
|
|
89
113
|
};
|
|
114
|
+
/**
|
|
115
|
+
* Inter-entity links: draw lines to each entity's k nearest neighbors within maxDist.
|
|
116
|
+
* Capped at LIMITS.maxLinksK. Layer count must be <= LIMITS.maxLinkLayerCount when set.
|
|
117
|
+
*/
|
|
118
|
+
links?: {
|
|
119
|
+
k: number;
|
|
120
|
+
maxDist: number;
|
|
121
|
+
color?: string;
|
|
122
|
+
alpha?: number;
|
|
123
|
+
width?: number;
|
|
124
|
+
};
|
|
125
|
+
/**
|
|
126
|
+
* Afterglow trail behind moving entities. Samples past positions analytically
|
|
127
|
+
* (no state, fully deterministic). `length` in ms, `fade` 0..1 (default 1 = full fade).
|
|
128
|
+
*/
|
|
129
|
+
trail?: {
|
|
130
|
+
length: number;
|
|
131
|
+
fade?: number;
|
|
132
|
+
};
|
|
90
133
|
}
|
|
91
134
|
type SpriteSpec = {
|
|
92
135
|
kind: 'emoji';
|
|
93
136
|
glyphs: string[];
|
|
137
|
+
cycle?: CycleSpec;
|
|
94
138
|
} | {
|
|
95
139
|
kind: 'text';
|
|
96
140
|
strings: string[];
|
|
@@ -99,6 +143,7 @@ type SpriteSpec = {
|
|
|
99
143
|
align?: 'left' | 'center' | 'right';
|
|
100
144
|
baseline?: 'top' | 'middle' | 'bottom';
|
|
101
145
|
maxWidth?: number;
|
|
146
|
+
cycle?: CycleSpec;
|
|
102
147
|
}
|
|
103
148
|
/** `soft` renders a radial falloff (glow orb) instead of a hard disc. */
|
|
104
149
|
| {
|
|
@@ -106,7 +151,12 @@ type SpriteSpec = {
|
|
|
106
151
|
radius: [number, number];
|
|
107
152
|
color: string;
|
|
108
153
|
soft?: boolean;
|
|
154
|
+
colors?: string[];
|
|
109
155
|
};
|
|
156
|
+
/** Rotate through sprite variants over time. Each entity offsets by its seeded phase. */
|
|
157
|
+
interface CycleSpec {
|
|
158
|
+
period: number;
|
|
159
|
+
}
|
|
110
160
|
type MotionSpec =
|
|
111
161
|
/**
|
|
112
162
|
* Drift at a per-entity speed picked from `speed` (px/sec) along `angle` degrees
|
|
@@ -136,6 +186,20 @@ type MotionSpec =
|
|
|
136
186
|
/** Entity stays exactly where placed. No movement. Use with `position` for pinned elements. */
|
|
137
187
|
| {
|
|
138
188
|
type: 'static';
|
|
189
|
+
}
|
|
190
|
+
/**
|
|
191
|
+
* Orbit around a center point. Each entity gets a seeded radius from `radius`
|
|
192
|
+
* and a seeded phase. `speed` is angular velocity in degrees/sec. `center` is
|
|
193
|
+
* fractional {x, y} (default {0.5, 0.5} = viewport center).
|
|
194
|
+
*/
|
|
195
|
+
| {
|
|
196
|
+
type: 'orbit';
|
|
197
|
+
speed: [number, number];
|
|
198
|
+
radius: [number, number];
|
|
199
|
+
center?: {
|
|
200
|
+
x: number;
|
|
201
|
+
y: number;
|
|
202
|
+
};
|
|
139
203
|
};
|
|
140
204
|
/** A validation problem, pointing at a JSON path within the spec. */
|
|
141
205
|
interface SpecError {
|
|
@@ -145,6 +209,14 @@ interface SpecError {
|
|
|
145
209
|
interface ValidationResult {
|
|
146
210
|
valid: boolean;
|
|
147
211
|
errors: SpecError[];
|
|
212
|
+
/** Non-blocking warnings about unknown/misplaced properties or likely authoring mistakes. */
|
|
213
|
+
warnings?: SpecWarning[];
|
|
214
|
+
}
|
|
215
|
+
/** An advisory warning (non-blocking). Returned by `adviseSpec`. */
|
|
216
|
+
interface SpecWarning {
|
|
217
|
+
path: string;
|
|
218
|
+
code: string;
|
|
219
|
+
message: string;
|
|
148
220
|
}
|
|
149
221
|
/** Perf/safety caps enforced by `validateSpec`. */
|
|
150
222
|
declare const LIMITS: {
|
|
@@ -154,11 +226,25 @@ declare const LIMITS: {
|
|
|
154
226
|
readonly maxSpeed: 4000;
|
|
155
227
|
readonly maxPulseAmp: 0.5;
|
|
156
228
|
readonly minPulsePeriod: 500;
|
|
229
|
+
readonly maxSpin: 360;
|
|
230
|
+
readonly maxGrowAmp: 0.8;
|
|
231
|
+
readonly maxOrbitSpeed: 180;
|
|
232
|
+
readonly maxLinksK: 8;
|
|
233
|
+
readonly maxLinkLayerCount: 200;
|
|
234
|
+
readonly minCyclePeriod: 500;
|
|
235
|
+
readonly referenceViewport: 1080;
|
|
236
|
+
readonly maxTrailLength: 5000;
|
|
237
|
+
readonly maxTrailSamples: 24;
|
|
238
|
+
readonly minDriftPeriod: 10000;
|
|
239
|
+
readonly maxDriftAmount: 0.3;
|
|
157
240
|
};
|
|
158
241
|
|
|
159
242
|
/**
|
|
160
243
|
* Validate an untrusted (agent- or JSON-authored) spec structurally + semantically.
|
|
161
|
-
* Returns typed errors; never throws. `compileSaver` refuses to run an invalid spec.
|
|
244
|
+
* Returns typed errors and warnings; never throws. `compileSaver` refuses to run an invalid spec.
|
|
245
|
+
*
|
|
246
|
+
* Warnings are non-blocking advisories about unknown/misplaced properties and
|
|
247
|
+
* near-zero speeds. They don't prevent compilation but indicate likely authoring mistakes.
|
|
162
248
|
*/
|
|
163
249
|
declare function validateSpec(spec: unknown): ValidationResult;
|
|
164
250
|
/** Narrowing helper: validate + cast. Throws with a joined message when invalid. */
|
|
@@ -175,12 +261,22 @@ interface Entity {
|
|
|
175
261
|
vx: number;
|
|
176
262
|
vy: number;
|
|
177
263
|
bob: number;
|
|
178
|
-
motion: 'drift' | 'rise' | 'bounce' | 'static';
|
|
264
|
+
motion: 'drift' | 'rise' | 'bounce' | 'static' | 'orbit';
|
|
179
265
|
headingLeft: boolean;
|
|
180
266
|
alpha: number;
|
|
181
267
|
pulseAmp: number;
|
|
182
268
|
pulsePeriod: number;
|
|
183
269
|
pulsePhase: number;
|
|
270
|
+
spinSpeed: number;
|
|
271
|
+
spinPhase: number;
|
|
272
|
+
growAmp: number;
|
|
273
|
+
growPeriod: number;
|
|
274
|
+
growPhase: number;
|
|
275
|
+
orbitR: number;
|
|
276
|
+
orbitCx: number;
|
|
277
|
+
orbitCy: number;
|
|
278
|
+
colorIndex: number;
|
|
279
|
+
cyclePeriod: number;
|
|
184
280
|
}
|
|
185
281
|
interface Placed {
|
|
186
282
|
x: number;
|
|
@@ -188,12 +284,26 @@ interface Placed {
|
|
|
188
284
|
flip: boolean;
|
|
189
285
|
}
|
|
190
286
|
declare function spriteVariants(sprite: SpriteSpec): number;
|
|
191
|
-
/** Deterministically place a layer's entities using the seeded RNG (never Math.random).
|
|
192
|
-
|
|
287
|
+
/** Deterministically place a layer's entities using the seeded RNG (never Math.random).
|
|
288
|
+
* `scale` multiplies every dimensional draw (default 1). Used for viewport units.
|
|
289
|
+
* `countScale` multiplies entity count for density-aware scaling (default 1). */
|
|
290
|
+
declare function buildEntities(layer: LayerSpec, rng: Rng, w: number, h: number, scale?: number, countScale?: number): Entity[];
|
|
193
291
|
/** Analytic opacity of an entity at logical time `t` (ms). Pure, clamped to 0..1. */
|
|
194
292
|
declare function alphaAt(e: Entity, t: number): number;
|
|
293
|
+
/** Analytic size multiplier at time `t` (ms). Pure, clamped to > 0. */
|
|
294
|
+
declare function sizeAt(e: Entity, t: number): number;
|
|
295
|
+
/** Analytic rotation angle at time `t` (ms) in radians. Pure. */
|
|
296
|
+
declare function rotationAt(e: Entity, t: number): number;
|
|
195
297
|
/** Analytic position of an entity at logical time `t` (ms). Pure & deterministic. */
|
|
196
298
|
declare function positionAt(e: Entity, t: number, w: number, h: number): Placed;
|
|
299
|
+
/** Time-varying sprite index for text/emoji cycling. Returns static index when cyclePeriod is 0. */
|
|
300
|
+
declare function spriteIndexAt(e: Entity, t: number, variants: number): number;
|
|
301
|
+
/** K-nearest-neighbor edge list. Deterministic tie-break: (dist, index).
|
|
302
|
+
* When `doWrap` is true, uses toroidal distance so links don't streak across wrap seams. */
|
|
303
|
+
declare function linkPairs(positions: Array<{
|
|
304
|
+
x: number;
|
|
305
|
+
y: number;
|
|
306
|
+
}>, k: number, maxDist: number, doWrap: boolean, w: number, h: number): Array<[number, number]>;
|
|
197
307
|
|
|
198
308
|
/** Derive a manifest so a compiled spec composes with @idle-screens/capabilities. */
|
|
199
309
|
declare function manifestFor(spec: SaverSpec): SaverManifest;
|
|
@@ -234,6 +344,16 @@ declare function applyDeltasToSpec(spec: SaverSpec, deltas: SteerDelta[]): Saver
|
|
|
234
344
|
* target immediately (k > 0). Layer counts round to integers.
|
|
235
345
|
*/
|
|
236
346
|
declare function lerpSpec(from: SaverSpec, to: SaverSpec, k: number): SaverSpec;
|
|
347
|
+
/**
|
|
348
|
+
* Enumerate all steerable leaf paths in a (resolved) spec. Returns dot-paths
|
|
349
|
+
* like "layers.0.count", "background.stops.1.color", etc. Metadata fields
|
|
350
|
+
* (id, label, schemaVersion, seed, units, kind, type, key) are excluded —
|
|
351
|
+
* they describe structure, not tuneable values.
|
|
352
|
+
*
|
|
353
|
+
* Layer keys are NOT substituted: paths always use numeric indices.
|
|
354
|
+
* Consumers can map to key-based paths via resolveSpecPath if needed.
|
|
355
|
+
*/
|
|
356
|
+
declare function steerablePaths(spec: unknown): string[];
|
|
237
357
|
/** Smooth (ease-in-out) progress curve used for glides. */
|
|
238
358
|
declare function easeSmooth(k: number): number;
|
|
239
359
|
/**
|
|
@@ -242,6 +362,60 @@ declare function easeSmooth(k: number): number;
|
|
|
242
362
|
*/
|
|
243
363
|
declare function structuralSignature(spec: SaverSpec): string;
|
|
244
364
|
|
|
365
|
+
/**
|
|
366
|
+
* Non-blocking advisory warnings for a valid spec. Does NOT replace validateSpec —
|
|
367
|
+
* call advise only on specs that have already passed validation.
|
|
368
|
+
*/
|
|
369
|
+
declare function adviseSpec(spec: SaverSpec, viewport?: {
|
|
370
|
+
width: number;
|
|
371
|
+
height: number;
|
|
372
|
+
}): SpecWarning[];
|
|
373
|
+
|
|
374
|
+
interface LayerSnapshot {
|
|
375
|
+
key: string | undefined;
|
|
376
|
+
count: number;
|
|
377
|
+
centroid: {
|
|
378
|
+
x: number;
|
|
379
|
+
y: number;
|
|
380
|
+
};
|
|
381
|
+
coverage: number;
|
|
382
|
+
meanAlpha: number;
|
|
383
|
+
linksDrawn: number | null;
|
|
384
|
+
linksExpected: number | null;
|
|
385
|
+
connectedComponents: number | null;
|
|
386
|
+
isolatedNodes: number | null;
|
|
387
|
+
}
|
|
388
|
+
interface SceneSnapshot {
|
|
389
|
+
t: number;
|
|
390
|
+
viewport: {
|
|
391
|
+
w: number;
|
|
392
|
+
h: number;
|
|
393
|
+
};
|
|
394
|
+
layers: LayerSnapshot[];
|
|
395
|
+
warnings: string[];
|
|
396
|
+
}
|
|
397
|
+
interface SceneDescription {
|
|
398
|
+
spec: {
|
|
399
|
+
id: string;
|
|
400
|
+
label: string;
|
|
401
|
+
units: string;
|
|
402
|
+
};
|
|
403
|
+
snapshots: SceneSnapshot[];
|
|
404
|
+
}
|
|
405
|
+
/**
|
|
406
|
+
* Deterministic scene analysis at one or more time values. Reuses `buildEntities`
|
|
407
|
+
* and `linkPairs` — no render needed. Returns structured data a non-vision model
|
|
408
|
+
* can use to understand what a spec looks like when rendered.
|
|
409
|
+
*/
|
|
410
|
+
declare function describeScene(spec: SaverSpec, options?: {
|
|
411
|
+
viewport?: {
|
|
412
|
+
width: number;
|
|
413
|
+
height: number;
|
|
414
|
+
};
|
|
415
|
+
seed?: number;
|
|
416
|
+
times?: number[];
|
|
417
|
+
}): SceneDescription;
|
|
418
|
+
|
|
245
419
|
/**
|
|
246
420
|
* Reproduces the hand-coded Fish Aquarium saver as pure DATA — the discriminating test
|
|
247
421
|
* that the schema is actually expressive: two layers (fish drifting both ways at varied
|
|
@@ -249,6 +423,20 @@ declare function structuralSignature(spec: SaverSpec): string;
|
|
|
249
423
|
*/
|
|
250
424
|
declare const AQUARIUM_SPEC: SaverSpec;
|
|
251
425
|
|
|
426
|
+
/**
|
|
427
|
+
* Comet Shower: showcases trails (afterglow behind moving entities) and background
|
|
428
|
+
* drift (gradient stops breathing slowly). Three layers: a static star field, fast
|
|
429
|
+
* comets with long trails, and slow fireflies with short trails and pulse.
|
|
430
|
+
*/
|
|
431
|
+
declare const COMETS_SPEC: SaverSpec;
|
|
432
|
+
|
|
433
|
+
/**
|
|
434
|
+
* Constellation: drifting stars connected by faint k-nearest links. Exercises
|
|
435
|
+
* colors[] (multi-hued stars), links (k-nearest neighbor lines), and cycle
|
|
436
|
+
* (emoji asterisms rotate glyphs). Stars are soft circles in pixel units.
|
|
437
|
+
*/
|
|
438
|
+
declare const CONSTELLATION_SPEC: SaverSpec;
|
|
439
|
+
|
|
252
440
|
/** Rain: dense text streaks falling straight down over a near-black sky. */
|
|
253
441
|
declare const RAIN_SPEC: SaverSpec;
|
|
254
442
|
|
|
@@ -287,6 +475,14 @@ declare const SAKURA_SPEC: SaverSpec;
|
|
|
287
475
|
*/
|
|
288
476
|
declare const DASHBOARD_SPEC: SaverSpec;
|
|
289
477
|
|
|
478
|
+
/**
|
|
479
|
+
* Orrery: a mechanical solar system. Exercises orbit motion (concentric rings
|
|
480
|
+
* at different speeds), spin (planets rotate on their axes), and grow (the sun
|
|
481
|
+
* pulses). Soft glow circles with additive blending create the corona and
|
|
482
|
+
* planetary halos.
|
|
483
|
+
*/
|
|
484
|
+
declare const ORRERY_SPEC: SaverSpec;
|
|
485
|
+
|
|
290
486
|
/** Catalog entry for a bundled schema example. */
|
|
291
487
|
interface SchemaExample {
|
|
292
488
|
id: string;
|
|
@@ -300,4 +496,4 @@ declare const EXAMPLE_SPECS: SaverSpec[];
|
|
|
300
496
|
/** Lookup by saver id. */
|
|
301
497
|
declare const EXAMPLE_BY_ID: Readonly<Record<string, SaverSpec>>;
|
|
302
498
|
|
|
303
|
-
export { AQUARIUM_SPEC, type BackgroundSpec, type BandSpec, DASHBOARD_SPEC, EXAMPLE_BY_ID, EXAMPLE_SPECS, type Entity, type GradientStop, LANTERNS_SPEC, LIMITS, type LayerSpec, type MotionSpec, type Placed, RAIN_SPEC, SAKURA_SPEC, SCHEMA_EXAMPLES, SCHEMA_VERSION, SNOWFALL_SPEC, type SaverSpec, type SchemaExample, type SpecError, type SpriteSpec, type SteerDelta, type ValidationResult, alphaAt, applyDeltasToSpec, assertValidSpec, buildEntities, compileSaver, easeSmooth, lerpSpec, manifestFor, positionAt, resolveSpecPath, spriteVariants, structuralSignature, validateSpec };
|
|
499
|
+
export { AQUARIUM_SPEC, type BackgroundDrift, type BackgroundSpec, type BandSpec, COMETS_SPEC, CONSTELLATION_SPEC, type CycleSpec, DASHBOARD_SPEC, EXAMPLE_BY_ID, EXAMPLE_SPECS, type Entity, type GradientStop, LANTERNS_SPEC, LIMITS, type LayerSnapshot, type LayerSpec, type MotionSpec, ORRERY_SPEC, type Placed, RAIN_SPEC, SAKURA_SPEC, SCHEMA_EXAMPLES, SCHEMA_VERSION, SNOWFALL_SPEC, type SaverSpec, type SceneDescription, type SceneSnapshot, type SchemaExample, type SpecError, type SpecWarning, type SpriteSpec, type SteerDelta, type ValidationResult, adviseSpec, alphaAt, applyDeltasToSpec, assertValidSpec, buildEntities, compileSaver, describeScene, easeSmooth, lerpSpec, linkPairs, manifestFor, positionAt, resolveSpecPath, rotationAt, sizeAt, spriteIndexAt, spriteVariants, steerablePaths, structuralSignature, validateSpec };
|