@idle-screens/schema 3.6.0 → 3.7.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/FORMAT.md +396 -41
- package/dist/index.d.ts +276 -8
- package/dist/index.js +881 -99
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
- package/saver-spec.schema.json +126 -5
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@idle-screens/schema",
|
|
3
|
-
"version": "3.
|
|
3
|
+
"version": "3.7.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",
|
package/saver-spec.schema.json
CHANGED
|
@@ -49,6 +49,57 @@
|
|
|
49
49
|
"maxItems": 2,
|
|
50
50
|
"description": "[min, max] px/sec, capped at 4000 so nothing teleports."
|
|
51
51
|
},
|
|
52
|
+
"textReveal": {
|
|
53
|
+
"type": "object",
|
|
54
|
+
"additionalProperties": false,
|
|
55
|
+
"properties": {
|
|
56
|
+
"progress": {
|
|
57
|
+
"type": "number",
|
|
58
|
+
"minimum": 0,
|
|
59
|
+
"maximum": 1
|
|
60
|
+
},
|
|
61
|
+
"mode": {
|
|
62
|
+
"enum": [
|
|
63
|
+
"typewriter",
|
|
64
|
+
"word",
|
|
65
|
+
"line",
|
|
66
|
+
"glyphFade"
|
|
67
|
+
]
|
|
68
|
+
},
|
|
69
|
+
"speed": {
|
|
70
|
+
"type": "number",
|
|
71
|
+
"minimum": 0,
|
|
72
|
+
"maximum": 120
|
|
73
|
+
},
|
|
74
|
+
"caret": {
|
|
75
|
+
"oneOf": [
|
|
76
|
+
{
|
|
77
|
+
"type": "boolean"
|
|
78
|
+
},
|
|
79
|
+
{
|
|
80
|
+
"type": "object",
|
|
81
|
+
"additionalProperties": false,
|
|
82
|
+
"properties": {
|
|
83
|
+
"blink": {
|
|
84
|
+
"type": "number",
|
|
85
|
+
"exclusiveMinimum": 0,
|
|
86
|
+
"maximum": 3
|
|
87
|
+
},
|
|
88
|
+
"color": {
|
|
89
|
+
"$ref": "#/definitions/hexColor"
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
]
|
|
94
|
+
},
|
|
95
|
+
"fade": {
|
|
96
|
+
"type": "number",
|
|
97
|
+
"exclusiveMinimum": 0,
|
|
98
|
+
"maximum": 1
|
|
99
|
+
}
|
|
100
|
+
},
|
|
101
|
+
"description": "Animated reveal controls for a text block."
|
|
102
|
+
},
|
|
52
103
|
"background": {
|
|
53
104
|
"oneOf": [
|
|
54
105
|
{
|
|
@@ -631,6 +682,9 @@
|
|
|
631
682
|
},
|
|
632
683
|
"cycle": {
|
|
633
684
|
"$ref": "#/definitions/cycle"
|
|
685
|
+
},
|
|
686
|
+
"role": {
|
|
687
|
+
"$ref": "#/definitions/textRole"
|
|
634
688
|
}
|
|
635
689
|
}
|
|
636
690
|
},
|
|
@@ -873,8 +927,8 @@
|
|
|
873
927
|
"maxWidth": {
|
|
874
928
|
"type": "number",
|
|
875
929
|
"exclusiveMinimum": 0,
|
|
876
|
-
"maximum":
|
|
877
|
-
"description": "
|
|
930
|
+
"maximum": 2.0,
|
|
931
|
+
"description": "Wrap width as a viewport fraction of min(w,h), up to 2.0 (wider than the frame is legal; the text-off-screen advisory reports overflow)."
|
|
878
932
|
},
|
|
879
933
|
"fontSize": {
|
|
880
934
|
"type": "number",
|
|
@@ -898,12 +952,51 @@
|
|
|
898
952
|
},
|
|
899
953
|
"color": {
|
|
900
954
|
"$ref": "#/definitions/hexColor"
|
|
955
|
+
},
|
|
956
|
+
"reveal": {
|
|
957
|
+
"$ref": "#/definitions/textReveal"
|
|
958
|
+
},
|
|
959
|
+
"anchor": {
|
|
960
|
+
"enum": [
|
|
961
|
+
"top-left",
|
|
962
|
+
"top",
|
|
963
|
+
"top-right",
|
|
964
|
+
"left",
|
|
965
|
+
"center",
|
|
966
|
+
"right",
|
|
967
|
+
"bottom-left",
|
|
968
|
+
"bottom",
|
|
969
|
+
"bottom-right"
|
|
970
|
+
],
|
|
971
|
+
"description": "Which point of the rendered text (widest line × lines·lineHeight, as align lays it out) position names. Absent: position is the top-left of the maxWidth layout box (today's behaviour). 'center' centres the block at position on every aspect ratio. Placement (structural). Native clients without anchor render as absent."
|
|
972
|
+
},
|
|
973
|
+
"font": {
|
|
974
|
+
"type": "string",
|
|
975
|
+
"minLength": 1,
|
|
976
|
+
"pattern": "^(?!.*\\d(?:px|pt|pc|em|rem|ex|ch|vw|vh|vmin|vmax|%)).*$",
|
|
977
|
+
"description": "CSS font family and/or weight/style only, e.g. 'bold monospace' or \"300 'Inter', sans-serif\" — a size inside it is rejected (fontSize owns size). A monospace family switches the line-breaker to a uniform advance. Default 'system-ui, sans-serif'; native clients fall back to the system face."
|
|
978
|
+
},
|
|
979
|
+
"opacity": {
|
|
980
|
+
"type": "number",
|
|
981
|
+
"minimum": 0,
|
|
982
|
+
"maximum": 1,
|
|
983
|
+
"description": "Paint-level alpha multiplier for the block (default 1). Not structural — steer it with dur to fade the block in or out without a rebuild. Declare it to make the path steerable. Native clients without it render at 1."
|
|
984
|
+
},
|
|
985
|
+
"role": {
|
|
986
|
+
"$ref": "#/definitions/textRole"
|
|
901
987
|
}
|
|
902
988
|
},
|
|
903
|
-
"description": "Multi-line text block with deterministic line-breaking. All dimensions are viewport fractions. Use with count: 1, static motion, and position."
|
|
989
|
+
"description": "Multi-line text block with deterministic line-breaking. All dimensions are viewport fractions. Use with count: 1, static motion, and position; add anchor: 'center' to centre the block at position."
|
|
904
990
|
}
|
|
905
991
|
]
|
|
906
992
|
},
|
|
993
|
+
"textRole": {
|
|
994
|
+
"enum": [
|
|
995
|
+
"read",
|
|
996
|
+
"atmosphere"
|
|
997
|
+
],
|
|
998
|
+
"description": "What the text is for. 'read' opts the layer into the legibility advisories (text-legibility: WCAG ratio below 4.5:1 against the background at the box centre or against the brightest additive layer over it; text-safe-area: box within 5% of an edge). 'atmosphere' (or absent) keeps it silent. A declaration only — changes no pixel on any client."
|
|
999
|
+
},
|
|
907
1000
|
"colorWeights": {
|
|
908
1001
|
"type": "array",
|
|
909
1002
|
"minItems": 1,
|
|
@@ -1047,7 +1140,7 @@
|
|
|
1047
1140
|
"type": "array",
|
|
1048
1141
|
"items": {
|
|
1049
1142
|
"type": "number",
|
|
1050
|
-
"minimum":
|
|
1143
|
+
"minimum": -180,
|
|
1051
1144
|
"maximum": 180
|
|
1052
1145
|
},
|
|
1053
1146
|
"minItems": 2,
|
|
@@ -1369,6 +1462,17 @@
|
|
|
1369
1462
|
"type": "boolean",
|
|
1370
1463
|
"description": "When true, global time wraps over the sum of segment durations. Requires every segment to have a duration."
|
|
1371
1464
|
},
|
|
1465
|
+
"sync": {
|
|
1466
|
+
"enum": [
|
|
1467
|
+
"mount",
|
|
1468
|
+
"epoch"
|
|
1469
|
+
],
|
|
1470
|
+
"description": "What the sequence clock is anchored to. 'mount' (default): every viewer starts at T = 0 when it mounts — a joiner sees segment 0 (pre-roll semantics). 'epoch': a viewer handed sequenceBaseT on its mount context (the host's Date.now() − epoch) starts its clock there, so every screen shows the same segment; a late joiner lands mid-loop. advance: 'input' holds stay armed under either. Native clients that anchor at their own mount behave as 'mount'."
|
|
1471
|
+
},
|
|
1472
|
+
"bed": {
|
|
1473
|
+
"$ref": "#/definitions/saverSpec",
|
|
1474
|
+
"description": "A scene drawn under every segment on the sequence's global clock — the ground that does not reset at a boundary or under a sequence.segment steer. Segments render over it transparently (their background and ghosting are ignored; validateSequence warns bed-hides-segment-background). Its entities plus the largest segment's must stay within the 800 cap (enforced by validateSequence). Steer it with bed.<path>. Native clients that ignore it render segments with their own backgrounds."
|
|
1475
|
+
},
|
|
1372
1476
|
"segments": {
|
|
1373
1477
|
"type": "array",
|
|
1374
1478
|
"minItems": 1,
|
|
@@ -1409,7 +1513,7 @@
|
|
|
1409
1513
|
"input",
|
|
1410
1514
|
"either"
|
|
1411
1515
|
],
|
|
1412
|
-
"description": "How the segment advances.
|
|
1516
|
+
"description": "How the segment advances. 'auto' (default) and 'either' advance on the timer; 'input' holds a timed segment at the end of its duration (the scene keeps animating) until a sequence.segment steer releases it — the clicker. A durationless final segment holds regardless."
|
|
1413
1517
|
},
|
|
1414
1518
|
"transition": {
|
|
1415
1519
|
"type": "object",
|
|
@@ -1431,6 +1535,23 @@
|
|
|
1431
1535
|
"minimum": 200,
|
|
1432
1536
|
"maximum": 5000,
|
|
1433
1537
|
"description": "Morph glide duration in ms. Requires structurally identical adjacent segments."
|
|
1538
|
+
},
|
|
1539
|
+
"text": {
|
|
1540
|
+
"enum": ["step", "crossfade"],
|
|
1541
|
+
"description": "How text / textBlock strings change during the morph. 'step' (default, today's behaviour): the incoming string shows from the first frame. 'crossfade': each text layer whose string(s) differ is drawn twice for dur — the outgoing words at 1 − k, the incoming at k (k = the eased progress). Native clients step (tvOS already cross-fades whole frames on a segment change)."
|
|
1542
|
+
}
|
|
1543
|
+
},
|
|
1544
|
+
"required": ["type", "dur"],
|
|
1545
|
+
"additionalProperties": false
|
|
1546
|
+
},
|
|
1547
|
+
{
|
|
1548
|
+
"properties": {
|
|
1549
|
+
"type": { "const": "fade" },
|
|
1550
|
+
"dur": {
|
|
1551
|
+
"type": "number",
|
|
1552
|
+
"minimum": 200,
|
|
1553
|
+
"maximum": 5000,
|
|
1554
|
+
"description": "Cross-fade duration in ms: the outgoing segment keeps animating on its own canvas and is composited over the incoming one at 1 − easeSmooth(localT / dur). No structural requirement. Hosts on the 'basic' or 'minimal' capability tier render it as cut."
|
|
1434
1555
|
}
|
|
1435
1556
|
},
|
|
1436
1557
|
"required": ["type", "dur"],
|