@richardmcquiston01/unofficial-xcs-writer 0.3.1 → 0.4.1
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/CHANGELOG.md +37 -0
- package/README.md +59 -3
- package/dist/index.cjs +680 -2
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +330 -1
- package/dist/index.d.ts +330 -1
- package/dist/index.js +671 -1
- package/dist/index.js.map +1 -1
- package/package.json +2 -2
package/CHANGELOG.md
CHANGED
|
@@ -5,6 +5,43 @@ All notable changes to this project will be documented in this file.
|
|
|
5
5
|
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
|
|
6
6
|
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
7
7
|
|
|
8
|
+
## [0.4.1] - 2026-09-19
|
|
9
|
+
|
|
10
|
+
### Changed
|
|
11
|
+
|
|
12
|
+
- Version bump only — 0.4.0 itself was never published to npm (only consumed
|
|
13
|
+
ahead of release via a git dependency from `maker-toolkit`'s `apps/desktop`,
|
|
14
|
+
which pointed at this repo's `dist` branch as a workaround). No code changes
|
|
15
|
+
from 0.4.0; this is the first published release carrying the generation API
|
|
16
|
+
and curved-text layout described below.
|
|
17
|
+
|
|
18
|
+
## [0.4.0] - 2026-09-19
|
|
19
|
+
|
|
20
|
+
### Added
|
|
21
|
+
|
|
22
|
+
- **Generation API** (`src/builder.ts`): `XCSGenerator`/`createXCS` build a `.xcs` project from
|
|
23
|
+
scratch — canvas, layers, and `TEXT`/`PATH`/`BITMAP` displays — ported from `maker-toolkit`'s
|
|
24
|
+
previously-duplicated hand-rolled generator. Chainable `.addText()`/`.addPath()`/
|
|
25
|
+
`.addBitmap()`/`.addLayer()`, then `.generate()`/`.toJSON()`/`.toBytes()`.
|
|
26
|
+
- **Curved text layout** (`src/layout.ts`): `layoutCurvedGlyphText` lays a single line of text
|
|
27
|
+
out along a circular arc, baking each character's rotated position and glyph shape directly
|
|
28
|
+
(same approach `renderXcsFile` already uses for straight substituted text — xTool Studio only
|
|
29
|
+
trusts stored glyph shapes). Uses the same arc-geometry convention (chord width, sweep angle,
|
|
30
|
+
up/down sign, align-driven start offset) as SVG `<textPath>`/canvas curved-text editors, so a
|
|
31
|
+
document renders consistently across export formats. Not yet visually verified against real
|
|
32
|
+
xTool Studio output — see `CLAUDE.md`'s "Open Issues".
|
|
33
|
+
- `layoutGlyphText`/`layoutMultilineGlyphText`/`translateGlyphLayout`/`fontSizePoints`
|
|
34
|
+
(`src/layout.ts`): the higher-level, real-world-scaled/positioned layout helpers built on
|
|
35
|
+
`glyphs.ts`'s `layoutText`, also ported from `maker-toolkit` (previously duplicated
|
|
36
|
+
consumer-side). `effectiveCurveDeg` clamps/normalizes a curve angle (±355°, treats <1° as
|
|
37
|
+
straight).
|
|
38
|
+
|
|
39
|
+
### Changed
|
|
40
|
+
|
|
41
|
+
- README's substitution "Known limitation" note narrowed to `renderXcsFile` specifically — it
|
|
42
|
+
still can't decode an existing curved display's `style.curveX`/`curveY`, but the new building
|
|
43
|
+
API doesn't have that problem (the caller supplies the angle directly).
|
|
44
|
+
|
|
8
45
|
## [0.3.1] - 2026-08-17
|
|
9
46
|
|
|
10
47
|
### Changed
|
package/README.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# unofficial-xcs-writer
|
|
2
2
|
|
|
3
|
-
A framework-agnostic TypeScript library for reading, writing, and applying variable substitution to `.xcs` files produced by [xTool Creative Space](https://www.xtool.com/pages/software). Not affiliated with xTool.
|
|
3
|
+
A framework-agnostic TypeScript library for reading, writing, building, and applying variable substitution to `.xcs` files produced by [xTool Creative Space](https://www.xtool.com/pages/software). Not affiliated with xTool.
|
|
4
4
|
|
|
5
5
|
## What is an XCS file?
|
|
6
6
|
|
|
@@ -9,6 +9,7 @@ An `.xcs` file is a plain UTF-8 JSON document exported by xTool Creative Space.
|
|
|
9
9
|
- **Read** an XCS file and inspect its contents
|
|
10
10
|
- **Extract** `{{token}}` template placeholders from text objects
|
|
11
11
|
- **Render** a filled-in copy by substituting values for those placeholders
|
|
12
|
+
- **Build** a new `.xcs` project from scratch — text (straight, multi-line, or curved), paths, and embedded images
|
|
12
13
|
|
|
13
14
|
## Installation
|
|
14
15
|
|
|
@@ -45,6 +46,38 @@ const values = { FirstName: 'Jane', LastName: 'Smith' };
|
|
|
45
46
|
const output: Uint8Array = renderXcsFile(buffer, variables, values);
|
|
46
47
|
```
|
|
47
48
|
|
|
49
|
+
### Building a project from scratch
|
|
50
|
+
|
|
51
|
+
```ts
|
|
52
|
+
import {
|
|
53
|
+
createXCS,
|
|
54
|
+
loadDefaultFont,
|
|
55
|
+
layoutGlyphText,
|
|
56
|
+
layoutCurvedGlyphText,
|
|
57
|
+
} from '@richardmcquiston01/unofficial-xcs-writer';
|
|
58
|
+
|
|
59
|
+
const font = loadDefaultFont();
|
|
60
|
+
|
|
61
|
+
const project = createXCS('P2S')
|
|
62
|
+
// Straight text needs a real glyph layout so xTool Studio renders
|
|
63
|
+
// actual outlines instead of placeholder blocks.
|
|
64
|
+
.addText('Hello', 10, 10, {
|
|
65
|
+
fontFamily: 'Arial',
|
|
66
|
+
fontSize: 24,
|
|
67
|
+
layout: layoutGlyphText(font, 'Hello', 8, 10, 10),
|
|
68
|
+
})
|
|
69
|
+
// Curved text: same idea, via layoutCurvedGlyphText -- the curve
|
|
70
|
+
// is baked into each character's own glyph shape and position, the
|
|
71
|
+
// way substituted text already bakes straight shapes.
|
|
72
|
+
.addText('Arch Text', 0, 40, {
|
|
73
|
+
fontFamily: 'Arial',
|
|
74
|
+
fontSize: 18,
|
|
75
|
+
layout: layoutCurvedGlyphText(font, 'Arch Text', 6, 90, 60, 20, 'center'),
|
|
76
|
+
})
|
|
77
|
+
.addPath('M0 0L10 0L10 10L0 10Z', 0, 60, 10, 10)
|
|
78
|
+
.toBytes(); // Uint8Array, ready to write to a .xcs file
|
|
79
|
+
```
|
|
80
|
+
|
|
48
81
|
## API
|
|
49
82
|
|
|
50
83
|
### `assertXcsFormat(buffer: ArrayBuffer): void`
|
|
@@ -74,7 +107,7 @@ renderXcsFile(buffer, variables, values, { Arial: arialBuffer });
|
|
|
74
107
|
|
|
75
108
|
Any `fontFamily` not present in `fonts` falls back to a bundled default (Arimo, Apache-2.0, metric-compatible with Arial) — so the fix works out of the box with no font files required, just with shapes drawn from Arimo rather than the exact requested typeface.
|
|
76
109
|
|
|
77
|
-
**Known limitation:** only straight horizontal-baseline layout
|
|
110
|
+
**Known limitation:** `renderXcsFile` only reproduces straight horizontal-baseline layout when substituting into an *existing* TEXT display. xTool Studio's `style.curveX`/`curveY` curved-text formula is undocumented and can't be reverse-decoded from a file alone, so a curved display's substituted text gets correctly-shaped glyphs laid out straight instead of on the original curve. This doesn't apply to the *building* API below — there, you supply the curve angle yourself (see `layoutCurvedGlyphText`), so there's nothing to decode.
|
|
78
111
|
|
|
79
112
|
### `XcsVariable`
|
|
80
113
|
|
|
@@ -87,7 +120,30 @@ interface XcsVariable {
|
|
|
87
120
|
|
|
88
121
|
### `loadFont(buffer: ArrayBuffer)` / `loadDefaultFont()` / `layoutText(font, text, originX, originY)`
|
|
89
122
|
|
|
90
|
-
Lower-level glyph-extraction primitives
|
|
123
|
+
Lower-level glyph-extraction primitives everything else in this library is built on, exported for direct use. See `src/glyphs.ts` for the exact xTool JSON conventions these were reverse-engineered against.
|
|
124
|
+
|
|
125
|
+
### Building (`src/builder.ts`, `src/layout.ts`)
|
|
126
|
+
|
|
127
|
+
`createXCS(deviceId?)` / `new XCSGenerator(options?)` — starts a new project (one canvas, one default layer). Chainable methods:
|
|
128
|
+
|
|
129
|
+
| Method | Adds |
|
|
130
|
+
|--------|------|
|
|
131
|
+
| `.addText(text, x, y, options?)` | A `TEXT` display. Pass `options.layout` (see below) for real glyph outlines — without it, text renders as placeholder blocks in xTool Studio. |
|
|
132
|
+
| `.addPath(pathData, x, y, width, height, options?)` | A `PATH` display from SVG path data. |
|
|
133
|
+
| `.addBitmap(pngBase64, x, y, widthMm, heightMm, originWidthPx, originHeightPx, options?)` | An embedded PNG, physically sized in mm. |
|
|
134
|
+
| `.addLayer(color, name, order)` | A named, colored layer (one `#00befe` "Cyan" layer exists by default). |
|
|
135
|
+
|
|
136
|
+
Then `.generate()` (the plain `XCSFile` object), `.toJSON()` (string), or `.toBytes()` (`Uint8Array`, matching `renderXcsFile`'s output type).
|
|
137
|
+
|
|
138
|
+
Text layout — build the `layout` option for `.addText()` with one of:
|
|
139
|
+
|
|
140
|
+
| Function | Layout |
|
|
141
|
+
|----------|--------|
|
|
142
|
+
| `layoutGlyphText(font, text, emSizeMm, xMm, yMm, letterSpacingMm?)` | Single-line, straight, anchored so the ink box's top-left lands at `(xMm, yMm)`. |
|
|
143
|
+
| `layoutMultilineGlyphText(font, text, emSizeMm, letterSpacingMm, lineHeightMult, align)` | Multi-line (`\n`-separated), straight, each line aligned and vertically stacked. |
|
|
144
|
+
| `layoutCurvedGlyphText(font, text, emSizeMm, curveDeg, boxWidthMm, boxHeightMm, align?, letterSpacingMm?)` | Single-line, curved along an arc spanning `curveDeg` degrees across a `boxWidthMm`-wide box (positive arches the apex upward, negative bows it downward — same convention as SVG `<textPath>`/canvas curved-text editors). Multi-line curved text isn't supported (matches typical curved-text editors, which also flatten multi-line curved text to one line). **Not yet visually verified against real xTool Studio rendering** (there's no way to check outside the application itself) — the geometry is self-consistent and unit-tested, but treat curved output as best-effort until you've spot-checked it. |
|
|
145
|
+
|
|
146
|
+
All three return `GlyphTextLayout | null` (`null` for empty/whitespace-only text). `translateGlyphLayout(layout, dxMm, dyMm)` cheaply shifts an already-built layout without relaying out the font.
|
|
91
147
|
|
|
92
148
|
## Development
|
|
93
149
|
|