@richardmcquiston01/unofficial-xcs-writer 0.6.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 +36 -0
- package/README.md +41 -8
- package/dist/index.cjs +182 -12
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +121 -15
- package/dist/index.d.ts +121 -15
- package/dist/index.js +181 -12
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -5,6 +5,42 @@ 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
|
+
|
|
30
|
+
## [0.7.0] - 2026-09-21
|
|
31
|
+
|
|
32
|
+
### Added
|
|
33
|
+
|
|
34
|
+
- **`.xs` processing-profile support**: `.addText()`/`.addPath()`/`.addBitmap()` accept a new
|
|
35
|
+
`processing: { processingType, values }` option (`src/builder.ts`), which `.toXsBytes()`
|
|
36
|
+
(`src/xs.ts`'s `buildXsArchive`, now taking an optional `XsProcessingBinding[]`) turns into a
|
|
37
|
+
real `profiles.json` entry plus a matching `LASER_PLANE`-mode binding in
|
|
38
|
+
`devices/device-<id>.json`. Displays given identical `processingType`+`values` are merged into
|
|
39
|
+
one shared profile/binding, matching how real xTool Studio exports dedupe identical settings.
|
|
40
|
+
`.toBytes()` (`.xcs` output) ignores this option -- `.xcs`'s own per-display processing format
|
|
41
|
+
is structurally different and much less understood, so it isn't implemented (see `CLAUDE.md`'s
|
|
42
|
+
Open Issues).
|
|
43
|
+
|
|
8
44
|
## [0.6.0] - 2026-09-21
|
|
9
45
|
|
|
10
46
|
### Added
|
package/README.md
CHANGED
|
@@ -93,15 +93,46 @@ const project = createXCS('P2S')
|
|
|
93
93
|
fontSize: 18,
|
|
94
94
|
layout: layoutCurvedGlyphText(font, 'Arch Text', 6, 90, 60, 20, 'center'),
|
|
95
95
|
})
|
|
96
|
-
.addPath('M0 0L10 0L10 10L0 10Z', 0, 60, 10, 10
|
|
96
|
+
.addPath('M0 0L10 0L10 10L0 10Z', 0, 60, 10, 10, {
|
|
97
|
+
// Only affects .toXsBytes() output -- see below.
|
|
98
|
+
processing: { processingType: 'VECTOR_CUTTING', values: { power: 80, speed: 10 } },
|
|
99
|
+
})
|
|
97
100
|
.toBytes(); // Uint8Array, ready to write to a .xcs file
|
|
98
101
|
```
|
|
99
102
|
|
|
100
103
|
Call `.toXsBytes()` instead of `.toBytes()` to export the same project as a `.xs` (v2 workspace)
|
|
101
|
-
archive — same chainable builder, same display objects, different container.
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
104
|
+
archive — same chainable builder, same display objects, different container.
|
|
105
|
+
|
|
106
|
+
Pass `processing: { processingType, values }` to `.addText()`/`.addPath()`/`.addBitmap()`'s
|
|
107
|
+
options to set that display's power/speed/etc. in the exported `.xs` file's `profiles.json` +
|
|
108
|
+
device bindings — `.xcs` output (`.toBytes()`) ignores this option; its own per-display
|
|
109
|
+
processing format is different and not supported yet. Displays given identical settings share
|
|
110
|
+
one profile/binding automatically. `processingType`/`values`' exact shape is xTool Studio's own
|
|
111
|
+
and undocumented beyond real exports — see `xs_samples/*.xs`'s `profiles.json` for examples
|
|
112
|
+
(`VECTOR_ENGRAVING`, `VECTOR_CUTTING`, `FILL_VECTOR_ENGRAVING`). Displays with no `processing`
|
|
113
|
+
option behave as before: a generated `.xs` file's power/speed may need to be set manually in
|
|
114
|
+
xTool Studio before cutting/engraving.
|
|
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.
|
|
105
136
|
|
|
106
137
|
## API
|
|
107
138
|
|
|
@@ -165,9 +196,9 @@ Packages an already-`generate()`d project (see Building, below) into a `.xs` v2
|
|
|
165
196
|
|
|
166
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.
|
|
167
198
|
|
|
168
|
-
### Building (`src/builder.ts`, `src/layout.ts`)
|
|
199
|
+
### Building (`src/builder.ts`, `src/layout.ts`, `src/machines.ts`)
|
|
169
200
|
|
|
170
|
-
`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:
|
|
171
202
|
|
|
172
203
|
| Method | Adds |
|
|
173
204
|
|--------|------|
|
|
@@ -176,7 +207,9 @@ Lower-level glyph-extraction primitives everything else in this library is built
|
|
|
176
207
|
| `.addBitmap(pngBase64, x, y, widthMm, heightMm, originWidthPx, originHeightPx, options?)` | An embedded PNG, physically sized in mm. |
|
|
177
208
|
| `.addLayer(color, name, order)` | A named, colored layer (one `#00befe` "Cyan" layer exists by default). |
|
|
178
209
|
|
|
179
|
-
|
|
210
|
+
`.addText()`/`.addPath()`/`.addBitmap()` all also accept a `processing: { processingType, values }` option — see "Building a project from scratch" above; it only affects `.toXsBytes()` output.
|
|
211
|
+
|
|
212
|
+
Then `.generate()` (the plain `XCSFile` object), `.toJSON()` (string), `.toBytes()` (`Uint8Array`, matching `renderXcsFile`'s output type, as `.xcs`), or `.toXsBytes()` (`Uint8Array`, matching `renderXsFile`'s output type, as `.xs`).
|
|
180
213
|
|
|
181
214
|
Text layout — build the `layout` option for `.addText()` with one of:
|
|
182
215
|
|
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,
|
|
@@ -362,6 +363,36 @@ function renderXsFile(buffer, variables, values, fonts) {
|
|
|
362
363
|
function encodeJson(value) {
|
|
363
364
|
return new TextEncoder().encode(JSON.stringify(value));
|
|
364
365
|
}
|
|
366
|
+
function generateXsId(prefix) {
|
|
367
|
+
const uuid = typeof crypto !== "undefined" && crypto.randomUUID ? crypto.randomUUID() : "xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx".replace(/[xy]/g, (c) => {
|
|
368
|
+
const r = Math.random() * 16 | 0;
|
|
369
|
+
const v = c === "x" ? r : r & 3 | 8;
|
|
370
|
+
return v.toString(16);
|
|
371
|
+
});
|
|
372
|
+
return `${prefix}:${uuid}`;
|
|
373
|
+
}
|
|
374
|
+
function buildProcessing(canvasId, bindings) {
|
|
375
|
+
const profiles = {};
|
|
376
|
+
const profileRefs = [];
|
|
377
|
+
const deviceBindings = [];
|
|
378
|
+
for (const binding of bindings) {
|
|
379
|
+
const profileId = generateXsId("profile");
|
|
380
|
+
profiles[profileId] = {
|
|
381
|
+
id: profileId,
|
|
382
|
+
processingType: binding.processingType,
|
|
383
|
+
values: binding.values
|
|
384
|
+
};
|
|
385
|
+
profileRefs.push(profileId);
|
|
386
|
+
deviceBindings.push({
|
|
387
|
+
bindingId: generateXsId("binding"),
|
|
388
|
+
canvasId,
|
|
389
|
+
mode: "LASER_PLANE",
|
|
390
|
+
baseProfileId: profileId,
|
|
391
|
+
displayIds: binding.displayIds
|
|
392
|
+
});
|
|
393
|
+
}
|
|
394
|
+
return { profiles, profileRefs, deviceBindings };
|
|
395
|
+
}
|
|
365
396
|
function decodeDataUrl(dataUrl) {
|
|
366
397
|
const match = /^data:([^;]+);base64,(.*)$/.exec(dataUrl);
|
|
367
398
|
if (!match) return null;
|
|
@@ -386,11 +417,15 @@ function coverResourceEntries(coverDataUrl) {
|
|
|
386
417
|
})
|
|
387
418
|
};
|
|
388
419
|
}
|
|
389
|
-
function buildXsArchive(file) {
|
|
420
|
+
function buildXsArchive(file, processingBindings = [], deviceCode = file.device.id) {
|
|
390
421
|
const canvas = file.canvas[0];
|
|
391
422
|
if (!canvas) {
|
|
392
423
|
throw new Error("Cannot build a .xs archive from a project with no canvas.");
|
|
393
424
|
}
|
|
425
|
+
const { profiles, profileRefs, deviceBindings } = buildProcessing(
|
|
426
|
+
canvas.id,
|
|
427
|
+
processingBindings
|
|
428
|
+
);
|
|
394
429
|
return (0, import_fflate.zipSync)({
|
|
395
430
|
".format": new TextEncoder().encode("v2"),
|
|
396
431
|
"meta/persistence-meta.json": encodeJson({
|
|
@@ -421,7 +456,7 @@ function buildXsArchive(file) {
|
|
|
421
456
|
cover: "resources/project-cover.png",
|
|
422
457
|
customProjectData: { projectTraceID: file.projectTraceID }
|
|
423
458
|
}),
|
|
424
|
-
"profiles.json": encodeJson({ profiles
|
|
459
|
+
"profiles.json": encodeJson({ profiles }),
|
|
425
460
|
[`canvases/${canvas.id}.json`]: encodeJson({
|
|
426
461
|
id: canvas.id,
|
|
427
462
|
title: canvas.title,
|
|
@@ -444,7 +479,7 @@ function buildXsArchive(file) {
|
|
|
444
479
|
}),
|
|
445
480
|
[`devices/device-${file.device.id}.json`]: encodeJson({
|
|
446
481
|
id: file.device.id,
|
|
447
|
-
deviceCode
|
|
482
|
+
deviceCode,
|
|
448
483
|
extId: file.extId,
|
|
449
484
|
extName: file.extName,
|
|
450
485
|
power: [file.device.power],
|
|
@@ -468,9 +503,9 @@ function buildXsArchive(file) {
|
|
|
468
503
|
focalLen: null,
|
|
469
504
|
focalLength: null
|
|
470
505
|
},
|
|
471
|
-
profileRefs
|
|
506
|
+
profileRefs,
|
|
472
507
|
patches: {},
|
|
473
|
-
bindings:
|
|
508
|
+
bindings: deviceBindings
|
|
474
509
|
}
|
|
475
510
|
}
|
|
476
511
|
}
|
|
@@ -732,6 +767,101 @@ function layoutCurvedGlyphText(font, text, emSizeMm, curveDeg, boxWidthMm, boxHe
|
|
|
732
767
|
};
|
|
733
768
|
}
|
|
734
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
|
+
|
|
735
865
|
// src/builder.ts
|
|
736
866
|
var XCSGenerator = class {
|
|
737
867
|
canvasId;
|
|
@@ -739,10 +869,20 @@ var XCSGenerator = class {
|
|
|
739
869
|
displays = [];
|
|
740
870
|
layers = /* @__PURE__ */ new Map();
|
|
741
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;
|
|
876
|
+
/** Keyed by `JSON.stringify([processingType, values])` to merge displays sharing identical settings into one profile. */
|
|
877
|
+
processingBindings = /* @__PURE__ */ new Map();
|
|
742
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;
|
|
743
883
|
this.options = {
|
|
744
|
-
deviceId
|
|
745
|
-
devicePower: options.devicePower || 55,
|
|
884
|
+
deviceId,
|
|
885
|
+
devicePower: options.devicePower || machine?.defaultPower || 55,
|
|
746
886
|
canvasWidth: options.canvasWidth || 400,
|
|
747
887
|
canvasHeight: options.canvasHeight || 400
|
|
748
888
|
};
|
|
@@ -750,6 +890,11 @@ var XCSGenerator = class {
|
|
|
750
890
|
this.canvas = this.createCanvas();
|
|
751
891
|
this.addLayer("#00befe", "{Cyan}", 1);
|
|
752
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
|
+
}
|
|
753
898
|
/**
|
|
754
899
|
* Add a text object to the canvas. Pass `layout` (built via
|
|
755
900
|
* `layoutGlyphText`/`layoutMultilineGlyphText`/`layoutCurvedGlyphText`
|
|
@@ -760,6 +905,7 @@ var XCSGenerator = class {
|
|
|
760
905
|
addText(text, x, y, options = {}) {
|
|
761
906
|
const textObj = this.createTextObject(text, x, y, options);
|
|
762
907
|
this.displays.push(textObj);
|
|
908
|
+
this.registerProcessing(textObj.id, options.processing);
|
|
763
909
|
return this;
|
|
764
910
|
}
|
|
765
911
|
/**
|
|
@@ -768,6 +914,7 @@ var XCSGenerator = class {
|
|
|
768
914
|
addPath(pathData, x, y, width, height, options = {}) {
|
|
769
915
|
const pathObj = this.createPathObject(pathData, x, y, width, height, options);
|
|
770
916
|
this.displays.push(pathObj);
|
|
917
|
+
this.registerProcessing(pathObj.id, options.processing);
|
|
771
918
|
return this;
|
|
772
919
|
}
|
|
773
920
|
/**
|
|
@@ -851,6 +998,7 @@ var XCSGenerator = class {
|
|
|
851
998
|
opacity: 1
|
|
852
999
|
};
|
|
853
1000
|
this.displays.push(bitmap);
|
|
1001
|
+
this.registerProcessing(bitmap.id, options.processing);
|
|
854
1002
|
return this;
|
|
855
1003
|
}
|
|
856
1004
|
/**
|
|
@@ -875,7 +1023,7 @@ var XCSGenerator = class {
|
|
|
875
1023
|
canvasId: this.canvasId,
|
|
876
1024
|
canvas: [this.canvas],
|
|
877
1025
|
extId: this.options.deviceId,
|
|
878
|
-
extName: this.
|
|
1026
|
+
extName: this.extName,
|
|
879
1027
|
device: {
|
|
880
1028
|
id: this.options.deviceId,
|
|
881
1029
|
power: this.options.devicePower,
|
|
@@ -913,13 +1061,34 @@ var XCSGenerator = class {
|
|
|
913
1061
|
}
|
|
914
1062
|
/**
|
|
915
1063
|
* Export as a `.xs` (v2 workspace) ZIP archive instead of `.xcs` --
|
|
916
|
-
* see `buildXsArchive` in `src/xs.ts` for the container format
|
|
917
|
-
* its limitations (no processing profiles/device bindings yet).
|
|
1064
|
+
* see `buildXsArchive` in `src/xs.ts` for the container format.
|
|
918
1065
|
* Display objects themselves carry over unchanged; only the
|
|
919
|
-
* 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.
|
|
920
1070
|
*/
|
|
921
1071
|
toXsBytes() {
|
|
922
|
-
return buildXsArchive(
|
|
1072
|
+
return buildXsArchive(
|
|
1073
|
+
this.generate(),
|
|
1074
|
+
Array.from(this.processingBindings.values()),
|
|
1075
|
+
this.deviceCode
|
|
1076
|
+
);
|
|
1077
|
+
}
|
|
1078
|
+
/** Merges a display into an existing profile when another display already shares its exact `processing` settings, else starts a new one. */
|
|
1079
|
+
registerProcessing(displayId, processing) {
|
|
1080
|
+
if (!processing) return;
|
|
1081
|
+
const key = JSON.stringify([processing.processingType, processing.values]);
|
|
1082
|
+
const existing = this.processingBindings.get(key);
|
|
1083
|
+
if (existing) {
|
|
1084
|
+
existing.displayIds.push(displayId);
|
|
1085
|
+
return;
|
|
1086
|
+
}
|
|
1087
|
+
this.processingBindings.set(key, {
|
|
1088
|
+
processingType: processing.processingType,
|
|
1089
|
+
values: processing.values,
|
|
1090
|
+
displayIds: [displayId]
|
|
1091
|
+
});
|
|
923
1092
|
}
|
|
924
1093
|
createCanvas() {
|
|
925
1094
|
return {
|
|
@@ -1154,6 +1323,7 @@ function createXCS(deviceId = "P2S") {
|
|
|
1154
1323
|
// Annotate the CommonJS export names for ESM import in node:
|
|
1155
1324
|
0 && (module.exports = {
|
|
1156
1325
|
XCSGenerator,
|
|
1326
|
+
XTOOL_MACHINES,
|
|
1157
1327
|
assertXcsFormat,
|
|
1158
1328
|
assertXsFormat,
|
|
1159
1329
|
buildXsArchive,
|