@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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@idle-screens/schema",
3
- "version": "2.0.0",
3
+ "version": "2.2.0",
4
4
  "description": "Declarative, agent-authorable saver format for idle-screens: validate a data spec, then compile it into a runnable, seeded, flash-safe SaverPlugin.",
5
5
  "license": "MIT",
6
6
  "author": "Shawn Partridge",
@@ -12,6 +12,7 @@
12
12
  "label": { "type": "string", "minLength": 1, "pattern": "\\S", "description": "Human-readable name." },
13
13
  "seed": { "type": "number", "description": "Deterministic RNG seed. Same spec + same seed = identical frames. Falls back to the host's seed." },
14
14
  "motionIntensity": { "enum": ["calm", "moderate", "energetic"], "description": "Advisory intensity for capability/reduced-motion gating." },
15
+ "units": { "enum": ["px", "viewport"], "description": "Dimensional unit system. 'viewport' = all sizes/speeds/distances are fractions of min(w,h)." },
15
16
  "background": { "$ref": "#/definitions/background" },
16
17
  "layers": {
17
18
  "type": "array",
@@ -87,6 +88,16 @@
87
88
  "color": { "$ref": "#/definitions/hexColor" },
88
89
  "height": { "type": "number", "exclusiveMinimum": 0, "description": "Band height in px (e.g. an aquarium seafloor)." }
89
90
  }
91
+ },
92
+ "drift": {
93
+ "type": "object",
94
+ "required": ["period"],
95
+ "additionalProperties": false,
96
+ "properties": {
97
+ "period": { "type": "number", "minimum": 10000, "description": "Full cycle period in ms. Floor of 10 s." },
98
+ "amount": { "type": "number", "exclusiveMinimum": 0, "maximum": 0.3, "description": "How far stops shift (fraction of 0..1 range). Default 0.15, max 0.3." }
99
+ },
100
+ "description": "Slow oscillation of gradient stop positions — makes the background feel alive."
90
101
  }
91
102
  }
92
103
  }
@@ -124,6 +135,17 @@
124
135
  },
125
136
  "description": "Sinusoidal opacity breathing. Per-entity seeded phase — a layer can never strobe in unison."
126
137
  },
138
+ "spin": { "type": "number", "minimum": -360, "maximum": 360, "description": "Per-entity rotation speed in degrees/sec (positive = clockwise). Each entity gets a seeded starting angle." },
139
+ "grow": {
140
+ "type": "object",
141
+ "required": ["amp", "period"],
142
+ "additionalProperties": false,
143
+ "properties": {
144
+ "amp": { "type": "number", "exclusiveMinimum": 0, "maximum": 0.8, "description": "Size breathing amplitude as fraction of base size (0.3 = ±30%)." },
145
+ "period": { "type": "number", "minimum": 500, "description": "Breathing period in ms; same flash-safety floor as pulse." }
146
+ },
147
+ "description": "Sinusoidal size breathing. Per-entity seeded phase. Composes with any sprite kind."
148
+ },
127
149
  "key": { "type": "string", "minLength": 1, "pattern": "\\S", "description": "Addressable name so setParam can use key.field paths." },
128
150
  "position": {
129
151
  "type": "object",
@@ -134,6 +156,29 @@
134
156
  "y": { "type": "number", "minimum": 0, "maximum": 1 }
135
157
  },
136
158
  "description": "Exact fractional position for a single entity. Requires count: 1. Overrides region scatter."
159
+ },
160
+ "trail": {
161
+ "type": "object",
162
+ "required": ["length"],
163
+ "additionalProperties": false,
164
+ "properties": {
165
+ "length": { "type": "number", "exclusiveMinimum": 0, "maximum": 5000, "description": "Trail duration in ms. How far back the afterglow extends." },
166
+ "fade": { "type": "number", "minimum": 0, "maximum": 1, "description": "Opacity fade factor along the trail. 1 = full fade to 0 (default), 0 = uniform opacity." }
167
+ },
168
+ "description": "Afterglow trail behind moving entities. Sampled analytically — no state, fully deterministic."
169
+ },
170
+ "links": {
171
+ "type": "object",
172
+ "required": ["k", "maxDist"],
173
+ "additionalProperties": false,
174
+ "properties": {
175
+ "k": { "type": "integer", "minimum": 1, "maximum": 8, "description": "Connect to the k nearest neighbors." },
176
+ "maxDist": { "type": "number", "exclusiveMinimum": 0, "description": "Maximum link distance (px or viewport-units)." },
177
+ "color": { "$ref": "#/definitions/hexColor", "description": "Link color. Defaults to per-entity color." },
178
+ "alpha": { "type": "number", "minimum": 0, "maximum": 1, "description": "Link opacity. Defaults to entity alpha." },
179
+ "width": { "type": "number", "exclusiveMinimum": 0, "description": "Stroke width (px or viewport-units). Default 1." }
180
+ },
181
+ "description": "Draw lines to each entity's k nearest neighbors within maxDist. The layer's entity count (count field) must be <= 200 for performance."
137
182
  }
138
183
  },
139
184
  "if": { "required": ["position"] },
@@ -147,7 +192,8 @@
147
192
  "additionalProperties": false,
148
193
  "properties": {
149
194
  "kind": { "const": "emoji" },
150
- "glyphs": { "type": "array", "minItems": 1, "items": { "type": "string" }, "description": "Emoji picked per entity (seeded)." }
195
+ "glyphs": { "type": "array", "minItems": 1, "items": { "type": "string" }, "description": "Emoji picked per entity (seeded)." },
196
+ "cycle": { "$ref": "#/definitions/cycle" }
151
197
  }
152
198
  },
153
199
  {
@@ -161,7 +207,8 @@
161
207
  "font": { "type": "string", "description": "CSS font shorthand, e.g. 'bold 24px monospace'." },
162
208
  "align": { "enum": ["left", "center", "right"] },
163
209
  "baseline": { "enum": ["top", "middle", "bottom"] },
164
- "maxWidth": { "type": "number", "exclusiveMinimum": 0 }
210
+ "maxWidth": { "type": "number", "exclusiveMinimum": 0 },
211
+ "cycle": { "$ref": "#/definitions/cycle" }
165
212
  }
166
213
  },
167
214
  {
@@ -172,11 +219,21 @@
172
219
  "kind": { "const": "circle" },
173
220
  "radius": { "$ref": "#/definitions/positiveRange" },
174
221
  "color": { "$ref": "#/definitions/hexColor" },
175
- "soft": { "type": "boolean", "description": "Radial falloff (glow orb) instead of a hard disc." }
222
+ "soft": { "type": "boolean", "description": "Radial falloff (glow orb) instead of a hard disc." },
223
+ "colors": { "type": "array", "minItems": 1, "items": { "$ref": "#/definitions/hexColor" }, "description": "Per-entity color palette (seeded pick). Falls back to color." }
176
224
  }
177
225
  }
178
226
  ]
179
227
  },
228
+ "cycle": {
229
+ "type": "object",
230
+ "required": ["period"],
231
+ "additionalProperties": false,
232
+ "properties": {
233
+ "period": { "type": "number", "minimum": 500, "description": "Cycling period in ms; floor of 500 (flash-safety)." }
234
+ },
235
+ "description": "Rotate through sprite variants over time. Each entity offsets by its seeded phase."
236
+ },
180
237
  "motion": {
181
238
  "oneOf": [
182
239
  {
@@ -217,6 +274,32 @@
217
274
  "properties": {
218
275
  "type": { "const": "static", "description": "Entity stays exactly where placed. Use with position for pinned elements." }
219
276
  }
277
+ },
278
+ {
279
+ "type": "object",
280
+ "required": ["type", "speed", "radius"],
281
+ "additionalProperties": false,
282
+ "properties": {
283
+ "type": { "const": "orbit" },
284
+ "speed": {
285
+ "type": "array",
286
+ "items": { "type": "number", "minimum": 0, "maximum": 180 },
287
+ "minItems": 2,
288
+ "maxItems": 2,
289
+ "description": "[min, max] angular velocity in degrees/sec, capped at 180."
290
+ },
291
+ "radius": { "$ref": "#/definitions/positiveRange", "description": "[min, max] orbit radius in px." },
292
+ "center": {
293
+ "type": "object",
294
+ "required": ["x", "y"],
295
+ "additionalProperties": false,
296
+ "properties": {
297
+ "x": { "type": "number", "minimum": 0, "maximum": 1 },
298
+ "y": { "type": "number", "minimum": 0, "maximum": 1 }
299
+ },
300
+ "description": "Orbit center as fractional viewport position. Default {0.5, 0.5}."
301
+ }
302
+ }
220
303
  }
221
304
  ]
222
305
  }