@textmode/document 0.0.0-stage → 1.0.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.
@@ -0,0 +1,357 @@
1
+ {
2
+ "$schema": "https://json-schema.org/draft/2020-12/schema",
3
+ "$id": "https://textmode.art/schemas/textmode-document-2.0.schema.json",
4
+ "title": "Textmode document 2.0",
5
+ "description": "Editable textmode cell snapshots and layer stacks.",
6
+ "oneOf": [
7
+ {
8
+ "$ref": "#/$defs/selectedDocument"
9
+ },
10
+ {
11
+ "$ref": "#/$defs/allDocument"
12
+ }
13
+ ],
14
+ "$defs": {
15
+ "positiveSafeInteger": {
16
+ "type": "integer",
17
+ "minimum": 1,
18
+ "maximum": 9007199254740991,
19
+ "description": "Positive integer in the interoperable JavaScript safe range."
20
+ },
21
+ "canvas": {
22
+ "type": "object",
23
+ "required": ["width", "height"],
24
+ "properties": {
25
+ "width": {
26
+ "$ref": "#/$defs/positiveSafeInteger",
27
+ "description": "Width in pixels; the decoder checks equality with the corresponding grid product."
28
+ },
29
+ "height": {
30
+ "$ref": "#/$defs/positiveSafeInteger",
31
+ "description": "Height in pixels; the decoder checks equality with the corresponding grid product."
32
+ }
33
+ },
34
+ "additionalProperties": true,
35
+ "description": "Legacy grid pixel extent. For selected documents this equals the grid extent; for all documents it equals the first layer grid extent. It is not a composite viewport. See docs/specification-2.0.md#canvas-field."
36
+ },
37
+ "grid": {
38
+ "type": "object",
39
+ "required": ["cols", "rows", "cellWidth", "cellHeight"],
40
+ "properties": {
41
+ "cols": {
42
+ "$ref": "#/$defs/positiveSafeInteger",
43
+ "description": "Positive number of columns."
44
+ },
45
+ "rows": {
46
+ "$ref": "#/$defs/positiveSafeInteger",
47
+ "description": "Positive number of rows."
48
+ },
49
+ "cellWidth": {
50
+ "$ref": "#/$defs/positiveSafeInteger",
51
+ "description": "Positive cell width in pixels."
52
+ },
53
+ "cellHeight": {
54
+ "$ref": "#/$defs/positiveSafeInteger",
55
+ "description": "Positive cell height in pixels."
56
+ }
57
+ },
58
+ "additionalProperties": true,
59
+ "description": "Logical cell count and pixel dimensions of each cell. Products must remain safe integers."
60
+ },
61
+ "rgba": {
62
+ "type": "object",
63
+ "required": ["r", "g", "b", "a"],
64
+ "properties": {
65
+ "r": {
66
+ "type": "integer",
67
+ "minimum": 0,
68
+ "maximum": 255,
69
+ "description": "Red channel."
70
+ },
71
+ "g": {
72
+ "type": "integer",
73
+ "minimum": 0,
74
+ "maximum": 255,
75
+ "description": "Green channel."
76
+ },
77
+ "b": {
78
+ "type": "integer",
79
+ "minimum": 0,
80
+ "maximum": 255,
81
+ "description": "Blue channel."
82
+ },
83
+ "a": {
84
+ "type": "integer",
85
+ "minimum": 0,
86
+ "maximum": 255,
87
+ "description": "Alpha: 0 is transparent and 255 is opaque."
88
+ }
89
+ },
90
+ "additionalProperties": true,
91
+ "description": "Unpremultiplied RGBA integer channels from 0 through 255."
92
+ },
93
+ "color": {
94
+ "oneOf": [
95
+ {
96
+ "type": "string",
97
+ "pattern": "^#[0-9A-Fa-f]{6}(?:[0-9A-Fa-f]{2})?$"
98
+ },
99
+ {
100
+ "$ref": "#/$defs/rgba"
101
+ }
102
+ ],
103
+ "description": "RGB or RGBA hexadecimal notation, or explicit RGBA channels. Six-digit notation implies alpha 255."
104
+ },
105
+ "transform": {
106
+ "type": "object",
107
+ "required": ["invert", "flipX", "flipY", "rotation"],
108
+ "properties": {
109
+ "invert": {
110
+ "type": "boolean",
111
+ "description": "Glyph inversion; alpha means this cannot generally be replaced by swapping colors."
112
+ },
113
+ "flipX": {
114
+ "type": "boolean",
115
+ "description": "Mirror the glyph horizontally."
116
+ },
117
+ "flipY": {
118
+ "type": "boolean",
119
+ "description": "Mirror the glyph vertically."
120
+ },
121
+ "rotation": {
122
+ "type": "number",
123
+ "description": "Cell rotation in degrees; normalized by the decoder to [0, 360)."
124
+ }
125
+ },
126
+ "additionalProperties": true,
127
+ "description": "Per-cell glyph transforms. Rotation is finite degrees; decoding normalizes it to [0, 360)."
128
+ },
129
+ "cell": {
130
+ "type": "object",
131
+ "required": ["x", "y", "character", "foreground", "background", "transform"],
132
+ "properties": {
133
+ "x": {
134
+ "type": "integer",
135
+ "minimum": 0,
136
+ "maximum": 9007199254740991,
137
+ "description": "Zero-based column index; must equal the position within its row."
138
+ },
139
+ "y": {
140
+ "type": "integer",
141
+ "minimum": 0,
142
+ "maximum": 9007199254740991,
143
+ "description": "Zero-based row index; must equal the row position."
144
+ },
145
+ "character": {
146
+ "type": "string",
147
+ "minLength": 1,
148
+ "maxLength": 64,
149
+ "description": "Nonempty Unicode glyph string, preserved without normalization. The decoder rejects unpaired surrogates and enforces a scalar-count budget."
150
+ },
151
+ "foreground": {
152
+ "$ref": "#/$defs/color",
153
+ "description": "Glyph color with alpha."
154
+ },
155
+ "background": {
156
+ "$ref": "#/$defs/color",
157
+ "description": "Cell background color with alpha. A space with a visible background remains meaningful."
158
+ },
159
+ "transform": {
160
+ "$ref": "#/$defs/transform",
161
+ "description": "Per-cell glyph inversion, flips, and rotation."
162
+ }
163
+ },
164
+ "additionalProperties": true,
165
+ "description": "One cell at its redundant zero-based row and column. Coordinates must match array position; this cross-field rule is checked by the decoder."
166
+ },
167
+ "cells": {
168
+ "type": "object",
169
+ "required": ["encoding", "rows"],
170
+ "properties": {
171
+ "encoding": {
172
+ "const": "object-rows-v1",
173
+ "description": "Tagged cell encoding; v2 supports only object-rows-v1."
174
+ },
175
+ "rows": {
176
+ "type": "array",
177
+ "items": {
178
+ "type": "array",
179
+ "items": {
180
+ "$ref": "#/$defs/cell"
181
+ }
182
+ },
183
+ "description": "Dense row-major arrays; row count and lengths must equal the owning grid. The decoder checks this invariant."
184
+ }
185
+ },
186
+ "additionalProperties": true,
187
+ "description": "Dense row-major cells, including transparent cells. Row count and lengths must equal the grid. See docs/specification-2.0.md#cell-encoding."
188
+ },
189
+ "metadata": {
190
+ "type": "object",
191
+ "required": ["createdAt", "generator"],
192
+ "properties": {
193
+ "createdAt": {
194
+ "type": "string",
195
+ "format": "date-time",
196
+ "pattern": "^[0-9]{4}-(0[1-9]|1[0-2])-(0[1-9]|[12][0-9]|3[01])T([01][0-9]|2[0-3]):[0-5][0-9]:[0-5][0-9](\\.[0-9]+)?(Z|[+-]([01][0-9]|2[0-3]):[0-5][0-9])$",
197
+ "description": "Real calendar date and time with uppercase T and timezone, required seconds, optional fractional seconds, and no leap seconds. Enable date-time format assertions in validators."
198
+ },
199
+ "generator": {
200
+ "type": "object",
201
+ "required": ["name", "version"],
202
+ "properties": {
203
+ "name": {
204
+ "type": "string",
205
+ "minLength": 1
206
+ },
207
+ "version": {
208
+ "type": "string",
209
+ "minLength": 1
210
+ }
211
+ },
212
+ "additionalProperties": true,
213
+ "description": "Producer identity; it does not select executable behavior."
214
+ }
215
+ },
216
+ "additionalProperties": true,
217
+ "description": "Optional informational creation and generator metadata. When present, both members are required."
218
+ },
219
+ "selectedLayer": {
220
+ "type": "object",
221
+ "required": ["id", "cells"],
222
+ "properties": {
223
+ "id": {
224
+ "type": "string",
225
+ "minLength": 1,
226
+ "description": "Nonempty informational source identifier. It is not a persistent cross-document identity; the decoder does not enforce uniqueness."
227
+ },
228
+ "cells": {
229
+ "$ref": "#/$defs/cells",
230
+ "description": "Complete dense cell rows."
231
+ }
232
+ },
233
+ "additionalProperties": true,
234
+ "description": "Informational source ID and cells. A selected snapshot does not carry layer presentation or font identity."
235
+ },
236
+ "stackLayer": {
237
+ "type": "object",
238
+ "required": ["id", "visible", "opacity", "blendMode", "offsetX", "offsetY", "rotationZ", "grid", "cells"],
239
+ "properties": {
240
+ "id": {
241
+ "type": "string",
242
+ "minLength": 1,
243
+ "description": "Nonempty informational source identifier. It is not a persistent cross-document identity; the decoder does not enforce uniqueness."
244
+ },
245
+ "visible": {
246
+ "type": "boolean",
247
+ "description": "Whether the layer participates in presentation. Hidden cells are still stored."
248
+ },
249
+ "opacity": {
250
+ "type": "number",
251
+ "minimum": 0,
252
+ "maximum": 1,
253
+ "description": "Layer opacity from 0 through 1, separate from cell alpha."
254
+ },
255
+ "blendMode": {
256
+ "type": "string",
257
+ "minLength": 1,
258
+ "description": "Nonempty blend mode name. The decoder preserves unknown names; apps decide which they can present."
259
+ },
260
+ "offsetX": {
261
+ "type": "number",
262
+ "description": "Horizontal compositing offset in pixels."
263
+ },
264
+ "offsetY": {
265
+ "type": "number",
266
+ "description": "Vertical compositing offset in pixels."
267
+ },
268
+ "rotationZ": {
269
+ "type": "number",
270
+ "description": "Layer rotation in degrees, clockwise about the layer center in textmode.js; preserved by the decoder."
271
+ },
272
+ "grid": {
273
+ "$ref": "#/$defs/grid",
274
+ "description": "Grid dimensions and cell metrics."
275
+ },
276
+ "cells": {
277
+ "$ref": "#/$defs/cells",
278
+ "description": "Complete dense cell rows."
279
+ }
280
+ },
281
+ "additionalProperties": true,
282
+ "description": "One ordered layer with independent grid, cells, and presentation values."
283
+ },
284
+ "selectedDocument": {
285
+ "type": "object",
286
+ "required": ["format", "formatVersion", "target", "canvas", "grid", "layer"],
287
+ "properties": {
288
+ "format": {
289
+ "const": "textmode.document",
290
+ "description": "Required format discriminator."
291
+ },
292
+ "formatVersion": {
293
+ "const": "2.0.0",
294
+ "description": "On-disk format version, independent of package versions."
295
+ },
296
+ "target": {
297
+ "const": "selected",
298
+ "description": "Shape discriminator: selected uses layer and root grid; all uses layers."
299
+ },
300
+ "metadata": {
301
+ "$ref": "#/$defs/metadata",
302
+ "description": "metadata"
303
+ },
304
+ "canvas": {
305
+ "$ref": "#/$defs/canvas",
306
+ "description": "Legacy grid pixel extent, not the final canvas or a composite viewport."
307
+ },
308
+ "grid": {
309
+ "$ref": "#/$defs/grid",
310
+ "description": "Grid dimensions and cell metrics."
311
+ },
312
+ "layer": {
313
+ "$ref": "#/$defs/selectedLayer",
314
+ "description": "One cell snapshot."
315
+ }
316
+ },
317
+ "additionalProperties": true,
318
+ "description": "Selected cell snapshot. All listed properties except metadata are required."
319
+ },
320
+ "allDocument": {
321
+ "type": "object",
322
+ "required": ["format", "formatVersion", "target", "canvas", "layers"],
323
+ "properties": {
324
+ "format": {
325
+ "const": "textmode.document",
326
+ "description": "Required format discriminator."
327
+ },
328
+ "formatVersion": {
329
+ "const": "2.0.0",
330
+ "description": "On-disk format version, independent of package versions."
331
+ },
332
+ "target": {
333
+ "const": "all",
334
+ "description": "Shape discriminator: selected uses layer and root grid; all uses layers."
335
+ },
336
+ "metadata": {
337
+ "$ref": "#/$defs/metadata",
338
+ "description": "metadata"
339
+ },
340
+ "canvas": {
341
+ "$ref": "#/$defs/canvas",
342
+ "description": "Legacy grid pixel extent, not the final canvas or a composite viewport."
343
+ },
344
+ "layers": {
345
+ "type": "array",
346
+ "minItems": 1,
347
+ "items": {
348
+ "$ref": "#/$defs/stackLayer"
349
+ },
350
+ "description": "Nonempty ordered layer stack, bottom first."
351
+ }
352
+ },
353
+ "additionalProperties": true,
354
+ "description": "One or more layers in bottom-to-top order. The decoder applies cumulative cell and layer budgets."
355
+ }
356
+ }
357
+ }