textmode.export.js 1.9.0-beta.2 → 1.9.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.
Files changed (27) hide show
  1. package/README.md +1 -5
  2. package/dist/textmode.export.esm.js +1 -1
  3. package/dist/textmode.export.umd.js +1 -1
  4. package/dist/types/exporters/base/LayerTarget.d.ts +1 -1
  5. package/dist/types/exporters/json/JSONExporter.d.ts +2 -1
  6. package/dist/types/exporters/json/index.d.ts +1 -2
  7. package/dist/types/exporters/json/types.d.ts +10 -5
  8. package/dist/types/index.d.ts +1 -3
  9. package/dist/types/types.d.ts +7 -4
  10. package/package.json +5 -38
  11. package/dist/textmode.document.esm.js +0 -1
  12. package/dist/types/document/constants.d.ts +0 -32
  13. package/dist/types/document/decode-shapes.d.ts +0 -4
  14. package/dist/types/document/decode.d.ts +0 -5
  15. package/dist/types/document/index.d.ts +0 -13
  16. package/dist/types/document/parse.d.ts +0 -3
  17. package/dist/types/document/types.d.ts +0 -209
  18. package/dist/types/document/validation.d.ts +0 -37
  19. package/protocol/textmode-document/2.0/SPECIFICATION.md +0 -233
  20. package/protocol/textmode-document/2.0/fixture.d.ts +0 -3
  21. package/protocol/textmode-document/2.0/fixtures/textmode-document-all-v2.json +0 -94
  22. package/protocol/textmode-document/2.0/fixtures/textmode-document-create-integration-v2.json +0 -112
  23. package/protocol/textmode-document/2.0/fixtures/textmode-document-selected-v2.json +0 -86
  24. package/protocol/textmode-document/2.0/fixtures/textmode-layer-all-v1.1.json +0 -46
  25. package/protocol/textmode-document/2.0/fixtures/textmode-layer-selected-v1.json +0 -38
  26. package/protocol/textmode-document/2.0/textmode-document-2.0.schema.d.ts +0 -3
  27. package/protocol/textmode-document/2.0/textmode-document-2.0.schema.json +0 -171
@@ -1,233 +0,0 @@
1
- # Textmode document format 2.0
2
-
3
- ## Status
4
-
5
- This document defines `textmode.document` version `2.0.0`. The JSON Schema is
6
- published beside this specification and through the `textmode.export.js/schema`
7
- and `textmode.export.js/document/schema/2.0` package subpaths. The schema's
8
- `$id` is a stable identifier, not a hosted download URL. The runtime codec is
9
- available from the ESM-only `textmode.export.js/document` subpath. The five
10
- canonical JSON fixtures in this directory are available through subpaths such
11
- as `textmode.export.js/document/fixtures/2.0/textmode-document-selected-v2.json`.
12
- Use the JSON import mechanism required by your runtime or bundler.
13
-
14
- The format represents editable cell data. It does not represent final rendered
15
- pixels, post-processing, an editor project, or authored animation.
16
-
17
- ## Encoding
18
-
19
- A textmode document is a UTF-8 JSON object. Producers should follow the I-JSON
20
- profile in RFC 7493:
21
-
22
- - object member names are unique;
23
- - integers remain within the interoperable safe range;
24
- - non-finite numbers are not emitted;
25
- - timestamps use an uppercase, timezone-qualified RFC 3339 representation.
26
-
27
- The media type is `application/json`. `.textmode.json` is a suggested filename
28
- suffix; existing exporter downloads use `.json` by default. Extensions and
29
- media types are discovery hints; consumers must route a decoded object using
30
- its `format` member.
31
-
32
- ## Root discriminator
33
-
34
- Every v2 document contains:
35
-
36
- ```json
37
- {
38
- "format": "textmode.document",
39
- "formatVersion": "2.0.0",
40
- "target": "selected"
41
- }
42
- ```
43
-
44
- `target` is an on-disk shape discriminator:
45
-
46
- - `selected` contains one cell snapshot in `layer`;
47
- - `all` contains a layer stack in `layers`.
48
-
49
- It is not an instruction to an exporter and must not be extended with temporal
50
- values such as `animation`. Authored animation requires a distinct document or
51
- container format.
52
-
53
- ## Version compatibility
54
-
55
- The version is SemVer-shaped for release communication. Version 2 does not
56
- define reader negotiation or a formal extension mechanism. Consumers therefore
57
- accept only explicitly tested versions and migrations; they must not assume an
58
- unknown `2.x` version is compatible.
59
-
60
- For a supported version, consumers ignore unknown ordinary object members.
61
- They reject unknown values of tagged members such as `format`, `target`, and
62
- `encoding` because those values change interpretation.
63
-
64
- Version 2 does not define `extensionsUsed`, `extensionsRequired`, extension
65
- namespacing, or an extension registry. A later revision must define those
66
- rules before claiming extension compatibility.
67
-
68
- ## Selected cell snapshot
69
-
70
- The `selected` shape contains:
71
-
72
- - legacy grid pixel extent in `canvas`;
73
- - logical grid dimensions and cell metrics in `grid`;
74
- - an informational source ID and complete cell rows in `layer`.
75
-
76
- This shape is a cell snapshot, not a lossless layer document. It does not carry
77
- visibility, opacity, blend mode, offsets, layer rotation, or font identity.
78
-
79
- ## Layer stack
80
-
81
- The `all` shape contains one or more layers. Each layer includes:
82
-
83
- - informational ID;
84
- - visibility and opacity;
85
- - blend mode name;
86
- - x/y offsets and z rotation;
87
- - logical grid and cell metrics;
88
- - complete cell rows.
89
-
90
- The order of `layers` is the stack order emitted by the producer.
91
-
92
- ## Canvas field
93
-
94
- The v2 field named `canvas` is the grid pixel extent, not necessarily the HTML
95
- canvas or final output surface. Its values obey:
96
-
97
- ```text
98
- canvas.width = grid.cols × grid.cellWidth
99
- canvas.height = grid.rows × grid.cellHeight
100
- ```
101
-
102
- For an `all` document, the root extent is derived from the first layer's grid.
103
- Consumers must not infer composite placement or clipping from this field.
104
-
105
- A future major format may replace this legacy name with `gridPixelSize`; v2
106
- semantics must not be changed in place.
107
-
108
- ## Cell encoding
109
-
110
- Version 2 defines one encoding:
111
-
112
- ```json
113
- {
114
- "encoding": "object-rows-v1",
115
- "rows": []
116
- }
117
- ```
118
-
119
- The encoding is dense and row-major:
120
-
121
- - `rows.length` equals `grid.rows`;
122
- - every row length equals `grid.cols`;
123
- - a cell's `x` equals its array index within the row;
124
- - a cell's `y` equals the row index;
125
- - every grid coordinate is present, including transparent cells.
126
-
127
- Consumers reject coordinate disagreement rather than silently repairing or
128
- reordering cells.
129
-
130
- ## Glyph identity
131
-
132
- `character` contains a non-empty, bounded, well-formed Unicode glyph string.
133
- Vector fonts commonly use one Unicode scalar, while tileset maps may use an
134
- extended grapheme cluster containing combining marks, variation selectors, or
135
- zero-width joiners. Unpaired surrogates are invalid. The default codec budget
136
- is 64 Unicode scalar values per glyph string.
137
-
138
- No Unicode normalization is implied. Consumers preserve the string exactly and
139
- apply product-specific representability rules after protocol decoding.
140
-
141
- ## Colors
142
-
143
- Foreground and background colors use either:
144
-
145
- - `#RRGGBB`, whose alpha is implicitly 255;
146
- - `#RRGGBBAA`;
147
- - `{ "r": 0, "g": 0, "b": 0, "a": 255 }` with integer channels from
148
- 0 through 255.
149
-
150
- The canonical decoder normalizes colors to RGBA channel objects.
151
-
152
- A cell is visually empty only when both foreground and background alpha are
153
- zero. A space with a visible background remains meaningful cell data.
154
-
155
- ## Transforms
156
-
157
- Every cell contains:
158
-
159
- - `invert`: boolean;
160
- - `flipX`: boolean;
161
- - `flipY`: boolean;
162
- - `rotation`: finite degrees.
163
-
164
- The canonical decoder normalizes rotation into `[0, 360)`. It therefore
165
- normalizes both `360` and `-360` to `0` and `-90` to `270`.
166
-
167
- Consumers must reject unsupported meaningful transforms instead of
168
- approximating them. In particular, swapping foreground and background is not a
169
- general replacement for inversion when alpha is present.
170
-
171
- ## Metadata
172
-
173
- Metadata is optional and informational:
174
-
175
- ```json
176
- {
177
- "createdAt": "2026-08-28T12:00:00.000Z",
178
- "generator": {
179
- "name": "textmode.export.js",
180
- "version": "1.8.1"
181
- }
182
- }
183
- ```
184
-
185
- `generator.name` identifies the producer and is not restricted to
186
- `textmode.export.js`. If metadata is present, `createdAt` must be a real
187
- calendar date and time in the uppercase, timezone-qualified RFC 3339 profile:
188
- seconds are required, fractional seconds are optional, and leap seconds are
189
- not supported in version 2. The decoder preserves valid timestamps as written.
190
-
191
- Consumers must not use metadata to select executable behavior, fetch resources,
192
- or bypass document validation.
193
-
194
- ## Safety limits
195
-
196
- The shared codec enforces structural safety limits and accepts caller-supplied
197
- budgets. Product-specific policy belongs to the product. For example,
198
- `create.textmode.art` may accept fewer cells than another document consumer.
199
-
200
- Consumers should:
201
-
202
- - check file bytes before reading;
203
- - cap total layers and total decoded cells;
204
- - use checked multiplication for grid dimensions;
205
- - bound identifiers and metadata strings;
206
- - parse large files away from latency-sensitive UI work;
207
- - abort work when the owning import session is cancelled.
208
-
209
- Documents never authorize URL fetching, font installation, or code execution.
210
-
211
- ## Legacy migration
212
-
213
- The compatibility decoder recognizes:
214
-
215
- - `textmode.layer@1.0.0` as a selected cell snapshot;
216
- - `textmode.layer@1.1.0` as a layer stack.
217
-
218
- Both migrate to the canonical v2 union and return a migration warning. Callers
219
- may disable legacy decoding.
220
-
221
- ## JSON Schema and runtime decoder
222
-
223
- The JSON Schema describes the portable structure and is suitable for
224
- documentation and general tooling. The runtime decoder remains authoritative
225
- for:
226
-
227
- - cross-field row and grid invariants;
228
- - grid pixel extent equality;
229
- - total resource budgets;
230
- - well-formed and bounded glyph-string validation;
231
- - rotation and color normalization;
232
- - legacy migration;
233
- - stable error codes and JSON paths.
@@ -1,3 +0,0 @@
1
- declare const fixture: unknown;
2
-
3
- export default fixture;
@@ -1,94 +0,0 @@
1
- {
2
- "format": "textmode.document",
3
- "formatVersion": "2.0.0",
4
- "target": "all",
5
- "canvas": {
6
- "width": 8,
7
- "height": 8
8
- },
9
- "layers": [
10
- {
11
- "id": "base",
12
- "visible": true,
13
- "opacity": 1,
14
- "blendMode": "normal",
15
- "offsetX": 0,
16
- "offsetY": 0,
17
- "rotationZ": 0,
18
- "grid": {
19
- "cols": 1,
20
- "rows": 1,
21
- "cellWidth": 8,
22
- "cellHeight": 8
23
- },
24
- "cells": {
25
- "encoding": "object-rows-v1",
26
- "rows": [
27
- [
28
- {
29
- "x": 0,
30
- "y": 0,
31
- "character": "B",
32
- "foreground": "#ffffffff",
33
- "background": "#000000ff",
34
- "transform": {
35
- "invert": true,
36
- "flipX": false,
37
- "flipY": false,
38
- "rotation": -90
39
- }
40
- }
41
- ]
42
- ]
43
- }
44
- },
45
- {
46
- "id": "accent",
47
- "visible": false,
48
- "opacity": 0.5,
49
- "blendMode": "multiply",
50
- "offsetX": -2,
51
- "offsetY": 3,
52
- "rotationZ": 15,
53
- "grid": {
54
- "cols": 2,
55
- "rows": 1,
56
- "cellWidth": 4,
57
- "cellHeight": 8
58
- },
59
- "cells": {
60
- "encoding": "object-rows-v1",
61
- "rows": [
62
- [
63
- {
64
- "x": 0,
65
- "y": 0,
66
- "character": "C",
67
- "foreground": "#ff000080",
68
- "background": "#00000000",
69
- "transform": {
70
- "invert": false,
71
- "flipX": true,
72
- "flipY": false,
73
- "rotation": 45
74
- }
75
- },
76
- {
77
- "x": 1,
78
- "y": 0,
79
- "character": " ",
80
- "foreground": "#00000000",
81
- "background": "#123456ff",
82
- "transform": {
83
- "invert": false,
84
- "flipX": false,
85
- "flipY": true,
86
- "rotation": 0
87
- }
88
- }
89
- ]
90
- ]
91
- }
92
- }
93
- ]
94
- }
@@ -1,112 +0,0 @@
1
- {
2
- "format": "textmode.document",
3
- "formatVersion": "2.0.0",
4
- "target": "selected",
5
- "metadata": {
6
- "createdAt": "2026-09-21T12:00:00.000Z",
7
- "generator": {
8
- "name": "textmode.export.js",
9
- "version": "1.8.1"
10
- }
11
- },
12
- "canvas": {
13
- "width": 24,
14
- "height": 16
15
- },
16
- "grid": {
17
- "cols": 3,
18
- "rows": 2,
19
- "cellWidth": 8,
20
- "cellHeight": 8
21
- },
22
- "layer": {
23
- "id": "base",
24
- "cells": {
25
- "encoding": "object-rows-v1",
26
- "rows": [
27
- [
28
- {
29
- "x": 0,
30
- "y": 0,
31
- "character": "A",
32
- "foreground": "#ff000080",
33
- "background": "#00000000",
34
- "transform": {
35
- "invert": false,
36
- "flipX": false,
37
- "flipY": false,
38
- "rotation": 0
39
- }
40
- },
41
- {
42
- "x": 1,
43
- "y": 0,
44
- "character": "😀",
45
- "foreground": { "r": 0, "g": 255, "b": 0, "a": 255 },
46
- "background": { "r": 0, "g": 0, "b": 255, "a": 96 },
47
- "transform": {
48
- "invert": false,
49
- "flipX": true,
50
- "flipY": false,
51
- "rotation": 360
52
- }
53
- },
54
- {
55
- "x": 2,
56
- "y": 0,
57
- "character": "é",
58
- "foreground": "#ffffffff",
59
- "background": "#223344cc",
60
- "transform": {
61
- "invert": false,
62
- "flipX": true,
63
- "flipY": true,
64
- "rotation": 45
65
- }
66
- }
67
- ],
68
- [
69
- {
70
- "x": 0,
71
- "y": 1,
72
- "character": " ",
73
- "foreground": "#00000000",
74
- "background": "#123456ff",
75
- "transform": {
76
- "invert": false,
77
- "flipX": false,
78
- "flipY": true,
79
- "rotation": 90
80
- }
81
- },
82
- {
83
- "x": 1,
84
- "y": 1,
85
- "character": "X",
86
- "foreground": "#00000000",
87
- "background": "#00000000",
88
- "transform": {
89
- "invert": false,
90
- "flipX": false,
91
- "flipY": false,
92
- "rotation": 0
93
- }
94
- },
95
- {
96
- "x": 2,
97
- "y": 1,
98
- "character": "Z",
99
- "foreground": "#abcdef40",
100
- "background": "#10203020",
101
- "transform": {
102
- "invert": false,
103
- "flipX": false,
104
- "flipY": true,
105
- "rotation": 270
106
- }
107
- }
108
- ]
109
- ]
110
- }
111
- }
112
- }
@@ -1,86 +0,0 @@
1
- {
2
- "format": "textmode.document",
3
- "formatVersion": "2.0.0",
4
- "target": "selected",
5
- "metadata": {
6
- "createdAt": "2026-08-28T12:00:00.000Z",
7
- "generator": {
8
- "name": "textmode.export.js",
9
- "version": "1.8.1"
10
- }
11
- },
12
- "canvas": {
13
- "width": 16,
14
- "height": 16
15
- },
16
- "grid": {
17
- "cols": 2,
18
- "rows": 2,
19
- "cellWidth": 8,
20
- "cellHeight": 8
21
- },
22
- "layer": {
23
- "id": "base",
24
- "cells": {
25
- "encoding": "object-rows-v1",
26
- "rows": [
27
- [
28
- {
29
- "x": 0,
30
- "y": 0,
31
- "character": "A",
32
- "foreground": "#ff0000ff",
33
- "background": "#000000ff",
34
- "transform": {
35
- "invert": false,
36
- "flipX": false,
37
- "flipY": false,
38
- "rotation": 0
39
- }
40
- },
41
- {
42
- "x": 1,
43
- "y": 0,
44
- "character": "😀",
45
- "foreground": { "r": 0, "g": 255, "b": 0, "a": 255 },
46
- "background": { "r": 0, "g": 0, "b": 255, "a": 128 },
47
- "transform": {
48
- "invert": false,
49
- "flipX": true,
50
- "flipY": false,
51
- "rotation": 360
52
- }
53
- }
54
- ],
55
- [
56
- {
57
- "x": 0,
58
- "y": 1,
59
- "character": " ",
60
- "foreground": "#00000000",
61
- "background": "#123456ff",
62
- "transform": {
63
- "invert": false,
64
- "flipX": false,
65
- "flipY": true,
66
- "rotation": 90
67
- }
68
- },
69
- {
70
- "x": 1,
71
- "y": 1,
72
- "character": "X",
73
- "foreground": "#00000000",
74
- "background": "#00000000",
75
- "transform": {
76
- "invert": false,
77
- "flipX": false,
78
- "flipY": false,
79
- "rotation": 0
80
- }
81
- }
82
- ]
83
- ]
84
- }
85
- }
86
- }
@@ -1,46 +0,0 @@
1
- {
2
- "$schema": "https://textmode.art/schemas/textmode-layer-1.0.schema.json",
3
- "format": "textmode.layer",
4
- "formatVersion": "1.1.0",
5
- "canvas": {
6
- "width": 8,
7
- "height": 8
8
- },
9
- "layers": [
10
- {
11
- "id": "base",
12
- "visible": true,
13
- "opacity": 1,
14
- "blendMode": "normal",
15
- "offsetX": 0,
16
- "offsetY": 0,
17
- "rotationZ": 0,
18
- "grid": {
19
- "cols": 1,
20
- "rows": 1,
21
- "cellWidth": 8,
22
- "cellHeight": 8
23
- },
24
- "cells": {
25
- "encoding": "object-rows-v1",
26
- "rows": [
27
- [
28
- {
29
- "x": 0,
30
- "y": 0,
31
- "character": "A",
32
- "foreground": "#ffffffff",
33
- "background": "#000000ff",
34
- "transform": {
35
- "invert": false,
36
- "flipX": false,
37
- "flipY": false,
38
- "rotation": 0
39
- }
40
- }
41
- ]
42
- ]
43
- }
44
- }
45
- ]
46
- }
@@ -1,38 +0,0 @@
1
- {
2
- "$schema": "https://textmode.art/schemas/textmode-layer-1.0.schema.json",
3
- "format": "textmode.layer",
4
- "formatVersion": "1.0.0",
5
- "canvas": {
6
- "width": 8,
7
- "height": 8
8
- },
9
- "grid": {
10
- "cols": 1,
11
- "rows": 1,
12
- "cellWidth": 8,
13
- "cellHeight": 8
14
- },
15
- "layer": {
16
- "id": "base",
17
- "cells": {
18
- "encoding": "object-rows-v1",
19
- "rows": [
20
- [
21
- {
22
- "x": 0,
23
- "y": 0,
24
- "character": "A",
25
- "foreground": "#ffffffff",
26
- "background": "#000000ff",
27
- "transform": {
28
- "invert": false,
29
- "flipX": false,
30
- "flipY": false,
31
- "rotation": 0
32
- }
33
- }
34
- ]
35
- ]
36
- }
37
- }
38
- }
@@ -1,3 +0,0 @@
1
- declare const schema: Readonly<Record<string, unknown>>;
2
-
3
- export default schema;