@richardmcquiston01/unofficial-xcs-writer 0.7.0 → 0.8.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/CHANGELOG.md +22 -0
- package/README.md +23 -2
- package/dist/index.cjs +125 -9
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +80 -8
- package/dist/index.d.ts +80 -8
- package/dist/index.js +124 -9
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -5,6 +5,28 @@ 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
|
+
## [Unreleased]
|
|
9
|
+
|
|
10
|
+
## [0.8.0] - 2026-09-21
|
|
11
|
+
|
|
12
|
+
### Added
|
|
13
|
+
|
|
14
|
+
- **Machine catalog** (`src/machines.ts`): `XCSGeneratorOptions.deviceId`/`createXCS`'s argument
|
|
15
|
+
now accepts a `XTOOL_MACHINES` key -- currently 13 machines verified from real exports in this
|
|
16
|
+
repo (`P2S`, `F2 Ultra UV`, `S1`, `P3`, `M2`, `F2`, `F2 Ultra (Single)`, `F2 Ultra`, `M1 Ultra`,
|
|
17
|
+
`F1`, `F1 Lite`, `F1 Ultra`, `MetalFab`) -- and resolves that machine's real `extId`/`extName`/
|
|
18
|
+
`deviceCode` (`.xs` only)/default power, instead of reusing whatever string you pass for all of
|
|
19
|
+
them. A `MachineProfile` object can also be supplied directly for a machine not yet in the
|
|
20
|
+
catalog. Existing raw device id strings still behave exactly as before (unaffected, since they
|
|
21
|
+
simply don't match a catalog key).
|
|
22
|
+
|
|
23
|
+
### Changed
|
|
24
|
+
|
|
25
|
+
- `createXCS()`/`new XCSGenerator()` with no `deviceId` (defaulting to `"P2S"`) now embeds the
|
|
26
|
+
real `deviceCode: "ZY013"` in `.toXsBytes()` output, instead of the previous placeholder
|
|
27
|
+
(`file.device.id`, i.e. `"P2S"`). `.xcs` output (`.toBytes()`) is unaffected -- it has no
|
|
28
|
+
`deviceCode` field.
|
|
29
|
+
|
|
8
30
|
## [0.7.0] - 2026-09-21
|
|
9
31
|
|
|
10
32
|
### Added
|
package/README.md
CHANGED
|
@@ -113,6 +113,27 @@ and undocumented beyond real exports — see `xs_samples/*.xs`'s `profiles.json`
|
|
|
113
113
|
option behave as before: a generated `.xs` file's power/speed may need to be set manually in
|
|
114
114
|
xTool Studio before cutting/engraving.
|
|
115
115
|
|
|
116
|
+
`createXCS('P2S')`'s argument (and `XCSGeneratorOptions.deviceId`) accepts a known machine name
|
|
117
|
+
from `XTOOL_MACHINES` — currently 13 machines verified from real exports in this repo (`"P2S"`,
|
|
118
|
+
`"F2 Ultra UV"`, `"S1"`, `"P3"`, `"M2"`, `"F2"`, `"F2 Ultra (Single)"`, `"F2 Ultra"`,
|
|
119
|
+
`"M1 Ultra"`, `"F1"`, `"F1 Lite"`, `"F1 Ultra"`, `"MetalFab"`) — and resolves the real
|
|
120
|
+
`extId`/`extName`/`deviceCode` (`.xs` only)/default power for that machine, instead of reusing
|
|
121
|
+
whatever string you pass for all of them. Export the same design for multiple machines by
|
|
122
|
+
building it once and calling `.toXsBytes()`/`.toBytes()` once per `createXCS(machineName)`:
|
|
123
|
+
|
|
124
|
+
```ts
|
|
125
|
+
import { createXCS, XTOOL_MACHINES } from '@richardmcquiston01/unofficial-xcs-writer';
|
|
126
|
+
|
|
127
|
+
for (const machine of Object.keys(XTOOL_MACHINES)) {
|
|
128
|
+
const bytes = createXCS(machine).addPath('M0 0L10 0L10 10L0 10Z', 0, 0, 10, 10).toXsBytes();
|
|
129
|
+
// write `bytes` to e.g. `design-${machine}.xs`
|
|
130
|
+
}
|
|
131
|
+
```
|
|
132
|
+
|
|
133
|
+
A device id not in the catalog still works exactly as before (no `.xs` `deviceCode`, `extId`/
|
|
134
|
+
`extName`/`device.id` all set to that string, default power `55`); you can also pass a
|
|
135
|
+
`MachineProfile` object directly for a machine not yet in the catalog.
|
|
136
|
+
|
|
116
137
|
## API
|
|
117
138
|
|
|
118
139
|
### `assertXcsFormat(buffer: ArrayBuffer): void`
|
|
@@ -175,9 +196,9 @@ Packages an already-`generate()`d project (see Building, below) into a `.xs` v2
|
|
|
175
196
|
|
|
176
197
|
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.
|
|
177
198
|
|
|
178
|
-
### Building (`src/builder.ts`, `src/layout.ts`)
|
|
199
|
+
### Building (`src/builder.ts`, `src/layout.ts`, `src/machines.ts`)
|
|
179
200
|
|
|
180
|
-
`createXCS(deviceId?)` / `new XCSGenerator(options?)` — starts a new project (one canvas, one default layer). Chainable methods:
|
|
201
|
+
`createXCS(deviceId?)` / `new XCSGenerator(options?)` — starts a new project (one canvas, one default layer). `deviceId` (and `options.deviceId`) accepts a `XTOOL_MACHINES` key, a `MachineProfile` object, or a raw device id string — see "Building a project from scratch" above. Chainable methods:
|
|
181
202
|
|
|
182
203
|
| Method | Adds |
|
|
183
204
|
|--------|------|
|
package/dist/index.cjs
CHANGED
|
@@ -31,6 +31,7 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
|
|
|
31
31
|
var index_exports = {};
|
|
32
32
|
__export(index_exports, {
|
|
33
33
|
XCSGenerator: () => XCSGenerator,
|
|
34
|
+
XTOOL_MACHINES: () => XTOOL_MACHINES,
|
|
34
35
|
assertXcsFormat: () => assertXcsFormat,
|
|
35
36
|
assertXsFormat: () => assertXsFormat,
|
|
36
37
|
buildXsArchive: () => buildXsArchive,
|
|
@@ -416,7 +417,7 @@ function coverResourceEntries(coverDataUrl) {
|
|
|
416
417
|
})
|
|
417
418
|
};
|
|
418
419
|
}
|
|
419
|
-
function buildXsArchive(file, processingBindings = []) {
|
|
420
|
+
function buildXsArchive(file, processingBindings = [], deviceCode = file.device.id) {
|
|
420
421
|
const canvas = file.canvas[0];
|
|
421
422
|
if (!canvas) {
|
|
422
423
|
throw new Error("Cannot build a .xs archive from a project with no canvas.");
|
|
@@ -478,7 +479,7 @@ function buildXsArchive(file, processingBindings = []) {
|
|
|
478
479
|
}),
|
|
479
480
|
[`devices/device-${file.device.id}.json`]: encodeJson({
|
|
480
481
|
id: file.device.id,
|
|
481
|
-
deviceCode
|
|
482
|
+
deviceCode,
|
|
482
483
|
extId: file.extId,
|
|
483
484
|
extName: file.extName,
|
|
484
485
|
power: [file.device.power],
|
|
@@ -766,6 +767,101 @@ function layoutCurvedGlyphText(font, text, emSizeMm, curveDeg, boxWidthMm, boxHe
|
|
|
766
767
|
};
|
|
767
768
|
}
|
|
768
769
|
|
|
770
|
+
// src/machines.ts
|
|
771
|
+
var XTOOL_MACHINES = {
|
|
772
|
+
P2S: {
|
|
773
|
+
name: "P2S",
|
|
774
|
+
extId: "P2S",
|
|
775
|
+
extName: "P2S",
|
|
776
|
+
deviceCode: "ZY013",
|
|
777
|
+
defaultPower: 55
|
|
778
|
+
},
|
|
779
|
+
"F2 Ultra UV": {
|
|
780
|
+
name: "F2 Ultra UV",
|
|
781
|
+
extId: "GS009-CLASS-4",
|
|
782
|
+
extName: "F2 Ultra UV",
|
|
783
|
+
deviceCode: "GS009-CLASS-4",
|
|
784
|
+
defaultPower: 5
|
|
785
|
+
},
|
|
786
|
+
S1: {
|
|
787
|
+
name: "S1",
|
|
788
|
+
extId: "S1",
|
|
789
|
+
extName: "S1",
|
|
790
|
+
deviceCode: "MD2",
|
|
791
|
+
defaultPower: 40
|
|
792
|
+
},
|
|
793
|
+
P3: {
|
|
794
|
+
name: "P3",
|
|
795
|
+
extId: "P3",
|
|
796
|
+
extName: "P3",
|
|
797
|
+
deviceCode: "ZY015",
|
|
798
|
+
defaultPower: 80
|
|
799
|
+
},
|
|
800
|
+
M2: {
|
|
801
|
+
name: "M2",
|
|
802
|
+
extId: "JS002",
|
|
803
|
+
extName: "M2",
|
|
804
|
+
deviceCode: "JS002",
|
|
805
|
+
defaultPower: 10
|
|
806
|
+
},
|
|
807
|
+
F2: {
|
|
808
|
+
name: "F2",
|
|
809
|
+
extId: "GS006",
|
|
810
|
+
extName: "F2",
|
|
811
|
+
deviceCode: "GS006",
|
|
812
|
+
defaultPower: 5
|
|
813
|
+
},
|
|
814
|
+
"F2 Ultra (Single)": {
|
|
815
|
+
name: "F2 Ultra (Single)",
|
|
816
|
+
extId: "GS007-CLASS-4",
|
|
817
|
+
extName: "F2 Ultra (Single)",
|
|
818
|
+
deviceCode: "GS007-CLASS-4",
|
|
819
|
+
defaultPower: 60
|
|
820
|
+
},
|
|
821
|
+
"F2 Ultra": {
|
|
822
|
+
name: "F2 Ultra",
|
|
823
|
+
extId: "GS004-CLASS-4",
|
|
824
|
+
extName: "F2 Ultra",
|
|
825
|
+
deviceCode: "GS004-CLASS-4",
|
|
826
|
+
defaultPower: 60
|
|
827
|
+
},
|
|
828
|
+
"M1 Ultra": {
|
|
829
|
+
name: "M1 Ultra",
|
|
830
|
+
extId: "M1Ultra",
|
|
831
|
+
extName: "M1 Ultra",
|
|
832
|
+
deviceCode: "ZH009",
|
|
833
|
+
defaultPower: 20
|
|
834
|
+
},
|
|
835
|
+
F1: {
|
|
836
|
+
name: "F1",
|
|
837
|
+
extId: "F1",
|
|
838
|
+
extName: "F1",
|
|
839
|
+
deviceCode: "MF1",
|
|
840
|
+
defaultPower: 10
|
|
841
|
+
},
|
|
842
|
+
"F1 Lite": {
|
|
843
|
+
name: "F1 Lite",
|
|
844
|
+
extId: "GS005",
|
|
845
|
+
extName: "F1 Lite",
|
|
846
|
+
deviceCode: "GS005",
|
|
847
|
+
defaultPower: 10
|
|
848
|
+
},
|
|
849
|
+
"F1 Ultra": {
|
|
850
|
+
name: "F1 Ultra",
|
|
851
|
+
extId: "F1Ultra",
|
|
852
|
+
extName: "F1 Ultra",
|
|
853
|
+
deviceCode: "GS002",
|
|
854
|
+
defaultPower: 20
|
|
855
|
+
},
|
|
856
|
+
MetalFab: {
|
|
857
|
+
name: "MetalFab",
|
|
858
|
+
extId: "HJ003",
|
|
859
|
+
extName: "MetalFab CNC Cutter",
|
|
860
|
+
deviceCode: "HJ003",
|
|
861
|
+
defaultPower: 1200
|
|
862
|
+
}
|
|
863
|
+
};
|
|
864
|
+
|
|
769
865
|
// src/builder.ts
|
|
770
866
|
var XCSGenerator = class {
|
|
771
867
|
canvasId;
|
|
@@ -773,12 +869,20 @@ var XCSGenerator = class {
|
|
|
773
869
|
displays = [];
|
|
774
870
|
layers = /* @__PURE__ */ new Map();
|
|
775
871
|
options;
|
|
872
|
+
/** From `XTOOL_MACHINES`/a supplied `MachineProfile`; `deviceId` itself when the machine isn't known. */
|
|
873
|
+
extName;
|
|
874
|
+
/** `.xs`-only; unset when the machine's real `deviceCode` isn't verified (see `src/machines.ts`). */
|
|
875
|
+
deviceCode;
|
|
776
876
|
/** Keyed by `JSON.stringify([processingType, values])` to merge displays sharing identical settings into one profile. */
|
|
777
877
|
processingBindings = /* @__PURE__ */ new Map();
|
|
778
878
|
constructor(options = {}) {
|
|
879
|
+
const machine = this.resolveMachine(options.deviceId);
|
|
880
|
+
const deviceId = machine?.extId ?? (typeof options.deviceId === "string" ? options.deviceId : "P2S");
|
|
881
|
+
this.extName = machine?.extName ?? deviceId;
|
|
882
|
+
this.deviceCode = machine?.deviceCode;
|
|
779
883
|
this.options = {
|
|
780
|
-
deviceId
|
|
781
|
-
devicePower: options.devicePower || 55,
|
|
884
|
+
deviceId,
|
|
885
|
+
devicePower: options.devicePower || machine?.defaultPower || 55,
|
|
782
886
|
canvasWidth: options.canvasWidth || 400,
|
|
783
887
|
canvasHeight: options.canvasHeight || 400
|
|
784
888
|
};
|
|
@@ -786,6 +890,11 @@ var XCSGenerator = class {
|
|
|
786
890
|
this.canvas = this.createCanvas();
|
|
787
891
|
this.addLayer("#00befe", "{Cyan}", 1);
|
|
788
892
|
}
|
|
893
|
+
/** Looks `deviceId` up in `XTOOL_MACHINES` by name, passes a supplied `MachineProfile` through, or returns `undefined` for a raw/unknown device id (including the "no option given" default of `"P2S"`). */
|
|
894
|
+
resolveMachine(deviceId) {
|
|
895
|
+
if (typeof deviceId === "object") return deviceId;
|
|
896
|
+
return XTOOL_MACHINES[deviceId ?? "P2S"];
|
|
897
|
+
}
|
|
789
898
|
/**
|
|
790
899
|
* Add a text object to the canvas. Pass `layout` (built via
|
|
791
900
|
* `layoutGlyphText`/`layoutMultilineGlyphText`/`layoutCurvedGlyphText`
|
|
@@ -914,7 +1023,7 @@ var XCSGenerator = class {
|
|
|
914
1023
|
canvasId: this.canvasId,
|
|
915
1024
|
canvas: [this.canvas],
|
|
916
1025
|
extId: this.options.deviceId,
|
|
917
|
-
extName: this.
|
|
1026
|
+
extName: this.extName,
|
|
918
1027
|
device: {
|
|
919
1028
|
id: this.options.deviceId,
|
|
920
1029
|
power: this.options.devicePower,
|
|
@@ -952,13 +1061,19 @@ var XCSGenerator = class {
|
|
|
952
1061
|
}
|
|
953
1062
|
/**
|
|
954
1063
|
* Export as a `.xs` (v2 workspace) ZIP archive instead of `.xcs` --
|
|
955
|
-
* see `buildXsArchive` in `src/xs.ts` for the container format
|
|
956
|
-
* its limitations (no processing profiles/device bindings yet).
|
|
1064
|
+
* see `buildXsArchive` in `src/xs.ts` for the container format.
|
|
957
1065
|
* Display objects themselves carry over unchanged; only the
|
|
958
|
-
* container differs from `toBytes()`.
|
|
1066
|
+
* container differs from `toBytes()`. `deviceCode` comes from
|
|
1067
|
+
* `XTOOL_MACHINES`/a supplied `MachineProfile` (see
|
|
1068
|
+
* `XCSGeneratorOptions.deviceId`) when known, else `buildXsArchive`
|
|
1069
|
+
* falls back to the device id itself, as before.
|
|
959
1070
|
*/
|
|
960
1071
|
toXsBytes() {
|
|
961
|
-
return buildXsArchive(
|
|
1072
|
+
return buildXsArchive(
|
|
1073
|
+
this.generate(),
|
|
1074
|
+
Array.from(this.processingBindings.values()),
|
|
1075
|
+
this.deviceCode
|
|
1076
|
+
);
|
|
962
1077
|
}
|
|
963
1078
|
/** Merges a display into an existing profile when another display already shares its exact `processing` settings, else starts a new one. */
|
|
964
1079
|
registerProcessing(displayId, processing) {
|
|
@@ -1208,6 +1323,7 @@ function createXCS(deviceId = "P2S") {
|
|
|
1208
1323
|
// Annotate the CommonJS export names for ESM import in node:
|
|
1209
1324
|
0 && (module.exports = {
|
|
1210
1325
|
XCSGenerator,
|
|
1326
|
+
XTOOL_MACHINES,
|
|
1211
1327
|
assertXcsFormat,
|
|
1212
1328
|
assertXsFormat,
|
|
1213
1329
|
buildXsArchive,
|