textmode.export.js 1.9.0-beta.1 → 1.9.0-beta.2

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 (32) hide show
  1. package/README.md +4 -0
  2. package/dist/textmode.document.esm.js +1 -0
  3. package/dist/textmode.export.esm.js +1 -1
  4. package/dist/textmode.export.umd.js +1 -1
  5. package/dist/types/document/constants.d.ts +32 -0
  6. package/dist/types/document/decode-shapes.d.ts +4 -0
  7. package/dist/types/document/decode.d.ts +5 -0
  8. package/dist/types/document/index.d.ts +13 -0
  9. package/dist/types/document/parse.d.ts +3 -0
  10. package/dist/types/document/types.d.ts +209 -0
  11. package/dist/types/document/validation.d.ts +37 -0
  12. package/dist/types/exporters/base/LayerTarget.d.ts +0 -2
  13. package/dist/types/exporters/gif/types.d.ts +0 -4
  14. package/dist/types/exporters/image/types.d.ts +0 -2
  15. package/dist/types/exporters/json/types.d.ts +14 -204
  16. package/dist/types/exporters/svg/types.d.ts +1 -3
  17. package/dist/types/exporters/txt/types.d.ts +0 -2
  18. package/dist/types/exporters/video/types.d.ts +0 -20
  19. package/dist/types/exporters/zip/errors.d.ts +0 -1
  20. package/dist/types/exporters/zip/types.d.ts +0 -7
  21. package/dist/types/index.d.ts +3 -27
  22. package/dist/types/types.d.ts +0 -28
  23. package/package.json +46 -10
  24. package/protocol/textmode-document/2.0/SPECIFICATION.md +233 -0
  25. package/protocol/textmode-document/2.0/fixture.d.ts +3 -0
  26. package/protocol/textmode-document/2.0/fixtures/textmode-document-all-v2.json +94 -0
  27. package/protocol/textmode-document/2.0/fixtures/textmode-document-create-integration-v2.json +112 -0
  28. package/protocol/textmode-document/2.0/fixtures/textmode-document-selected-v2.json +86 -0
  29. package/protocol/textmode-document/2.0/fixtures/textmode-layer-all-v1.1.json +46 -0
  30. package/protocol/textmode-document/2.0/fixtures/textmode-layer-selected-v1.json +38 -0
  31. package/protocol/textmode-document/2.0/textmode-document-2.0.schema.d.ts +3 -0
  32. package/protocol/textmode-document/2.0/textmode-document-2.0.schema.json +171 -0
package/README.md CHANGED
@@ -24,6 +24,10 @@ Choose a compact still, structured document data, or a complete animation to sui
24
24
  - **Controlled animation capture** - Configure frames, frame rate, scale, GIF repetition, video encoding, transparency, progress, and more
25
25
  - **ZIP frame sequences** - Archive deterministic PNG, JPEG, WebP, SVG, JSON, or TXT frames with a versioned manifest
26
26
 
27
+ The [textmode document 2.0 specification](./protocol/textmode-document/2.0/SPECIFICATION.md) defines the editable
28
+ JSON format, its schema, and the published compatibility fixtures. The dependency-free decoder is available from the
29
+ ESM-only `textmode.export.js/document` entry point.
30
+
27
31
  ## Try it online first
28
32
 
29
33
  Open [editor.textmode.art](https://editor.textmode.art/), a browser-based live-coding environment for the
@@ -0,0 +1 @@
1
+ var e="textmode.document",t="2.0.0",r="textmode.layer",n="1.0.0",a="1.1.0",o="object-rows-v1",i={maxCells:16777216,maxLayers:4096,maxLayerIdLength:1024,maxCharacterLength:64,maxMetadataStringLength:4096},s=class extends Error{detail;constructor(e){super(e.message),this.detail=e}};function c(e,t){if("string"==typeof e){const r=/^#([0-9a-f]{6}|[0-9a-f]{8})$/i.exec(e);r||b("INVALID_DOCUMENT","Expected #RRGGBB or #RRGGBBAA color notation.",t);const n=r[1];return{r:Number.parseInt(n.slice(0,2),16),g:Number.parseInt(n.slice(2,4),16),b:Number.parseInt(n.slice(4,6),16),a:8===n.length?Number.parseInt(n.slice(6,8),16):255}}const r=I(e,t);return{r:T(r.r,`${t}.r`),g:T(r.g,`${t}.g`),b:T(r.b,`${t}.b`),a:T(r.a,`${t}.a`)}}function l(e,t){const r=I(e,t);return{width:A(r.width,`${t}.width`),height:A(r.height,`${t}.height`)}}function m(e,t){const r=I(e,t);return{cols:A(r.cols,`${t}.cols`),rows:A(r.rows,`${t}.rows`),cellWidth:A(r.cellWidth,`${t}.cellWidth`),cellHeight:A(r.cellHeight,`${t}.cellHeight`)}}function d(e,t,r){const n=I(e,t),a=I(n.generator,`${t}.generator`),o=N(a.name,`${t}.generator.name`,r.maxMetadataStringLength),i=N(n.createdAt,`${t}.createdAt`,r.maxMetadataStringLength);return function(e,t){const r=u.exec(e);r||b("INVALID_DOCUMENT","Expected an uppercase RFC 3339 timestamp with seconds and a timezone.",t);const n=Number(r[1]),a=Number(r[2]);Number(r[3])>[31,n%4!=0||n%100==0&&n%400!=0?28:29,31,30,31,30,31,31,30,31,30,31][a-1]&&b("INVALID_DOCUMENT","Timestamp contains an invalid calendar date.",t)}(i,`${t}.createdAt`),{createdAt:i,generator:{name:o,version:N(a.version,`${t}.generator.version`,r.maxMetadataStringLength)}}}var u=/^([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])$/;function g(e,t,r){return N(e,t,r.maxLayerIdLength)}function f(e,t,r){const n=$(t.cols,t.cellWidth,`${r}.width`),a=$(t.rows,t.cellHeight,`${r}.height`);e.width===n&&e.height===a||b("INVALID_DOCUMENT",`Canvas must equal the grid pixel extent ${n}x${a}.`,r)}function h(e,t,r){if(void 0===e)return t;if(!Number.isSafeInteger(e)||e<=0)throw new TypeError(`${r} must be a positive safe integer.`);return e}function $(e,t,r){const n=e*t;return Number.isSafeInteger(n)||b("LIMIT_EXCEEDED","Numeric dimensions exceed the safe integer range.",r),n}function x(e){const t=(e%360+360)%360;return Object.is(t,-0)?0:t}function I(e,t){return("object"!=typeof e||null===e||Array.isArray(e))&&b("INVALID_DOCUMENT","Expected an object.",t),e}function E(e,t){return Array.isArray(e)||b("INVALID_DOCUMENT","Expected an array.",t),e}function p(e,t){return"string"!=typeof e&&b("INVALID_DOCUMENT","Expected a string.",t),e}function N(e,t,r){const n=p(e,t);return 0===n.length&&b("INVALID_DOCUMENT","Expected a non-empty string.",t),n.length>r&&b("LIMIT_EXCEEDED",`String length exceeds the configured limit ${r}.`,t),n}function L(e,t,r){const n=p(e,t);return 0===n.length&&b("INVALID_DOCUMENT","Expected a non-empty glyph string.",t),function(e,t){for(let r=0;r<e.length;r++){const n=e.charCodeAt(r);if(n>=55296&&n<=56319){const n=e.charCodeAt(r+1);(!Number.isInteger(n)||n<56320||n>57343)&&b("INVALID_DOCUMENT","Glyph strings must not contain unpaired surrogates.",t),r++;continue}n>=56320&&n<=57343&&b("INVALID_DOCUMENT","Glyph strings must not contain unpaired surrogates.",t)}}(n,t),Array.from(n).length>r.maxCharacterLength&&b("LIMIT_EXCEEDED",`Glyph string scalar count exceeds the configured limit ${r.maxCharacterLength}.`,t),n}function D(e,t){return"boolean"!=typeof e&&b("INVALID_DOCUMENT","Expected a boolean.",t),e}function y(e,t){return"number"==typeof e&&Number.isFinite(e)||b("INVALID_DOCUMENT","Expected a finite number.",t),e}function C(e,t,r,n){const a=y(e,t);return(a<r||a>n)&&b("INVALID_DOCUMENT",`Expected a number from ${r} through ${n}.`,t),a}function M(e,t){return"number"==typeof e&&Number.isSafeInteger(e)||b("INVALID_DOCUMENT","Expected a safe integer.",t),e}function A(e,t){const r=M(e,t);return r<=0&&b("INVALID_DOCUMENT","Expected a positive safe integer.",t),r}function T(e,t){const r=M(e,t);return(r<0||r>255)&&b("INVALID_DOCUMENT","Expected an integer from 0 through 255.",t),r}function b(e,t,r){throw new s({code:e,message:t,...r?{path:r}:{}})}function v(r,n){const a=l(r.canvas,"$.canvas"),o=m(r.grid,"$.grid");f(a,o,"$.canvas");const i=I(r.layer,"$.layer");return{format:e,formatVersion:t,target:"selected",...void 0===r.metadata?{}:{metadata:d(r.metadata,"$.metadata",n.limits)},canvas:a,grid:o,layer:{id:g(i.id,"$.layer.id",n.limits),cells:O(i.cells,o,"$.layer.cells",n)}}}function U(r,n){const a=l(r.canvas,"$.canvas"),o=E(r.layers,"$.layers");0===o.length&&b("INVALID_DOCUMENT","A layer-stack document must contain at least one layer.","$.layers"),o.length>n.limits.maxLayers&&b("LIMIT_EXCEEDED",`Layer count ${o.length} exceeds the configured limit ${n.limits.maxLayers}.`,"$.layers");const i=o.map((e,t)=>function(e,t,r){const n=I(e,t),a=m(n.grid,`${t}.grid`);return{id:g(n.id,`${t}.id`,r.limits),visible:D(n.visible,`${t}.visible`),opacity:C(n.opacity,`${t}.opacity`,0,1),blendMode:N(n.blendMode,`${t}.blendMode`,r.limits.maxMetadataStringLength),offsetX:y(n.offsetX,`${t}.offsetX`),offsetY:y(n.offsetY,`${t}.offsetY`),rotationZ:y(n.rotationZ,`${t}.rotationZ`),grid:a,cells:O(n.cells,a,`${t}.cells`,r)}}(e,`$.layers[${t}]`,n));return f(a,i[0].grid,"$.canvas"),{format:e,formatVersion:t,target:"all",...void 0===r.metadata?{}:{metadata:d(r.metadata,"$.metadata",n.limits)},canvas:a,layers:i}}function O(e,t,r,n){const a=I(e,r),i=p(a.encoding,`${r}.encoding`);"object-rows-v1"!==i&&b("UNSUPPORTED_ENCODING",`Unsupported cell encoding: ${i}.`,`${r}.encoding`);const s=$(t.cols,t.rows,`${r}.rows`);s>n.remainingCells&&b("LIMIT_EXCEEDED",`Document cell count exceeds the configured limit ${n.limits.maxCells}.`,`${r}.rows`),n.remainingCells-=s;const l=E(a.rows,`${r}.rows`);return l.length!==t.rows&&b("INVALID_DOCUMENT",`Expected ${t.rows} cell rows, received ${l.length}.`,`${r}.rows`),{encoding:o,rows:l.map((e,a)=>{const o=`${r}.rows[${a}]`,i=E(e,o);return i.length!==t.cols&&b("INVALID_DOCUMENT",`Expected ${t.cols} cells, received ${i.length}.`,o),i.map((e,t)=>function(e,t,r,n,a){const o=I(e,n),i=M(o.x,`${n}.x`),s=M(o.y,`${n}.y`);i===t&&s===r||b("INVALID_DOCUMENT",`Cell coordinates must match their row position (${t}, ${r}).`,n);const l=I(o.transform,`${n}.transform`);return{x:i,y:s,character:L(o.character,`${n}.character`,a.limits),foreground:c(o.foreground,`${n}.foreground`),background:c(o.background,`${n}.background`),transform:{invert:D(l.invert,`${n}.transform.invert`),flipX:D(l.flipX,`${n}.transform.flipX`),flipY:D(l.flipY,`${n}.transform.flipY`),rotation:x(y(l.rotation,`${n}.transform.rotation`))}}}(e,t,a,`${o}[${t}]`,n))})}}function _(e){try{return{ok:!0,value:JSON.parse(e)}}catch(t){return{ok:!1,error:{code:"INVALID_JSON",message:t instanceof Error?t.message:"The file is not valid JSON."}}}}function V(e,t={}){try{const r=function(e){return{maxCells:h(e?.maxCells,i.maxCells,"maxCells"),maxLayers:h(e?.maxLayers,i.maxLayers,"maxLayers"),maxLayerIdLength:h(e?.maxLayerIdLength,i.maxLayerIdLength,"maxLayerIdLength"),maxCharacterLength:h(e?.maxCharacterLength,i.maxCharacterLength,"maxCharacterLength"),maxMetadataStringLength:h(e?.maxMetadataStringLength,i.maxMetadataStringLength,"maxMetadataStringLength")}}(t.limits),n={limits:r,remainingCells:r.maxCells},a=I(e,"$"),o=p(a.format,"$.format");return"textmode.document"===o?{ok:!0,document:S(a,n),warnings:[]}:"textmode.layer"===o&&(t.acceptLegacy??!0)?{ok:!0,document:R(a,n),warnings:[{code:"LEGACY_DOCUMENT_MIGRATED",message:"Migrated a legacy textmode.layer document to textmode.document 2.0.0."}]}:{ok:!1,error:{code:"UNSUPPORTED_FORMAT",message:`Unsupported textmode document format: ${o}.`,..."$.format"?{path:"$.format"}:{}}}}catch(r){if(r instanceof s)return{ok:!1,error:r.detail};throw r}}function w(e,t={}){const r=_(e);return r.ok?V(r.value,t):r}function S(e,t){const r=p(e.formatVersion,"$.formatVersion");"2.0.0"!==r&&b("UNSUPPORTED_VERSION",`Unsupported textmode.document version: ${r}.`,"$.formatVersion");const n=p(e.target,"$.target");return"selected"===n?v(e,t):"all"===n?U(e,t):void b("UNSUPPORTED_TARGET",`Unsupported textmode document target: ${n}.`,"$.target")}function R(e,t){const r=p(e.formatVersion,"$.formatVersion");return"1.0.0"===r?v(e,t):"1.1.0"===r?U(e,t):void b("UNSUPPORTED_VERSION",`Unsupported legacy textmode.layer version: ${r}.`,"$.formatVersion")}export{i as DEFAULT_TEXTMODE_DOCUMENT_LIMITS,a as LEGACY_TEXTMODE_ALL_VERSION,r as LEGACY_TEXTMODE_LAYER_FORMAT,n as LEGACY_TEXTMODE_SELECTED_VERSION,e as TEXTMODE_DOCUMENT_FORMAT,t as TEXTMODE_DOCUMENT_FORMAT_VERSION,o as TEXTMODE_OBJECT_ROWS_ENCODING,V as decodeTextmodeDocument,_ as parseJSON,w as parseTextmodeDocumentJSON};