lbrnts 0.0.19 → 0.0.22
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/README.md +28 -0
- package/dist/index.d.ts +25 -1
- package/dist/index.js +167 -2
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -20,6 +20,32 @@ const project = LightBurnProject.parse(fs.readFileSync("project.lbrn2", "utf8"))
|
|
|
20
20
|
console.log(project.children)
|
|
21
21
|
```
|
|
22
22
|
|
|
23
|
+
### Offsetting Project Content
|
|
24
|
+
|
|
25
|
+
```tsx
|
|
26
|
+
import {
|
|
27
|
+
applyOffsetToLbrn,
|
|
28
|
+
LightBurnBaseElement,
|
|
29
|
+
LightBurnProject,
|
|
30
|
+
} from "lbrnts"
|
|
31
|
+
|
|
32
|
+
const source = fs.readFileSync("project.lbrn2", "utf8")
|
|
33
|
+
const project = LightBurnBaseElement.parse(source)
|
|
34
|
+
|
|
35
|
+
if (project instanceof LightBurnProject) {
|
|
36
|
+
applyOffsetToLbrn({
|
|
37
|
+
lbrnProject: project,
|
|
38
|
+
xOffset: 10,
|
|
39
|
+
yOffset: -5,
|
|
40
|
+
})
|
|
41
|
+
|
|
42
|
+
const shifted = project.getString()
|
|
43
|
+
}
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
This mutates the parsed project by offsetting top-level shape transforms. Call
|
|
47
|
+
`getString()` when you need LightBurn XML output.
|
|
48
|
+
|
|
23
49
|
### Creating Projects from Scratch
|
|
24
50
|
|
|
25
51
|
You can programmatically create LightBurn projects by constructing the project and its elements. Below is a table of all constructible classes with links to their documentation:
|
|
@@ -132,6 +158,8 @@ new CutSetting(init?: {
|
|
|
132
158
|
angle?: number // Scan angle
|
|
133
159
|
overScanning?: number // Over-scanning distance
|
|
134
160
|
lineAngle?: number // Line angle for fill
|
|
161
|
+
wobbleEnable?: boolean // Enable wobble for scan fills
|
|
162
|
+
anglePerPass?: number // Hatch angle increment per pass
|
|
135
163
|
})
|
|
136
164
|
```
|
|
137
165
|
|
package/dist/index.d.ts
CHANGED
|
@@ -92,6 +92,8 @@ interface CutSettingInit {
|
|
|
92
92
|
overScanning?: number;
|
|
93
93
|
lineAngle?: number;
|
|
94
94
|
crossHatch?: boolean;
|
|
95
|
+
wobbleEnable?: boolean;
|
|
96
|
+
anglePerPass?: number;
|
|
95
97
|
frequency?: number;
|
|
96
98
|
qPulseWidth?: number;
|
|
97
99
|
}
|
|
@@ -119,6 +121,8 @@ declare class CutSetting extends LightBurnBaseElement {
|
|
|
119
121
|
private _overScanning?;
|
|
120
122
|
private _lineAngle?;
|
|
121
123
|
private _crossHatch?;
|
|
124
|
+
private _wobbleEnable?;
|
|
125
|
+
private _anglePerPass?;
|
|
122
126
|
private _frequency?;
|
|
123
127
|
private _qPulseWidth?;
|
|
124
128
|
constructor(init?: CutSettingInit);
|
|
@@ -168,6 +172,10 @@ declare class CutSetting extends LightBurnBaseElement {
|
|
|
168
172
|
set lineAngle(value: number | undefined);
|
|
169
173
|
get crossHatch(): boolean | undefined;
|
|
170
174
|
set crossHatch(value: boolean | undefined);
|
|
175
|
+
get wobbleEnable(): boolean | undefined;
|
|
176
|
+
set wobbleEnable(value: boolean | undefined);
|
|
177
|
+
get anglePerPass(): number | undefined;
|
|
178
|
+
set anglePerPass(value: number | undefined);
|
|
171
179
|
get frequency(): number | undefined;
|
|
172
180
|
set frequency(value: number | undefined);
|
|
173
181
|
get qPulseWidth(): number | undefined;
|
|
@@ -373,6 +381,22 @@ interface GenerateSvgOptions {
|
|
|
373
381
|
|
|
374
382
|
declare function generateLightBurnSvg(root: LightBurnBaseElement | LightBurnBaseElement[], options?: GenerateSvgOptions): string;
|
|
375
383
|
|
|
384
|
+
interface SplitLightBurnProjectFile {
|
|
385
|
+
fileName: string;
|
|
386
|
+
content: string;
|
|
387
|
+
cutIndex: number;
|
|
388
|
+
cutSettingName: string;
|
|
389
|
+
shapeCount: number;
|
|
390
|
+
}
|
|
391
|
+
declare function splitLightBurnProjectByCutSetting(input: string | LightBurnProject, originalFileName?: string): SplitLightBurnProjectFile[];
|
|
392
|
+
|
|
393
|
+
interface ApplyOffsetToLbrnParams {
|
|
394
|
+
lbrnProject: LightBurnProject;
|
|
395
|
+
xOffset: number;
|
|
396
|
+
yOffset: number;
|
|
397
|
+
}
|
|
398
|
+
declare function applyOffsetToLbrn(params: ApplyOffsetToLbrnParams): LightBurnProject;
|
|
399
|
+
|
|
376
400
|
declare const parseXml: (xml: string) => XmlJson;
|
|
377
401
|
|
|
378
|
-
export { LightBurnBaseElement as BaseLightBurnElement, CutSetting, type CutSettingInit, type GenerateSvgOptions, LightBurnBaseElement, LightBurnProject, type LightBurnProjectInit, type Mat, Notes, type Prim, ShapeBase, ShapeBitmap, ShapeEllipse, ShapeGroup, ShapePath, type ShapePathInit, ShapeRect, ShapeText, Thumbnail, UIPrefs, VariableText, type Vert, generateLightBurnSvg, parseXml };
|
|
402
|
+
export { type ApplyOffsetToLbrnParams, LightBurnBaseElement as BaseLightBurnElement, CutSetting, type CutSettingInit, type GenerateSvgOptions, LightBurnBaseElement, LightBurnProject, type LightBurnProjectInit, type Mat, Notes, type Prim, ShapeBase, ShapeBitmap, ShapeEllipse, ShapeGroup, ShapePath, type ShapePathInit, ShapeRect, ShapeText, type SplitLightBurnProjectFile, Thumbnail, UIPrefs, VariableText, type Vert, applyOffsetToLbrn, generateLightBurnSvg, parseXml, splitLightBurnProjectByCutSetting };
|
package/dist/index.js
CHANGED
|
@@ -294,6 +294,8 @@ var CutSetting = class _CutSetting extends LightBurnBaseElement {
|
|
|
294
294
|
_overScanning;
|
|
295
295
|
_lineAngle;
|
|
296
296
|
_crossHatch;
|
|
297
|
+
_wobbleEnable;
|
|
298
|
+
_anglePerPass;
|
|
297
299
|
_frequency;
|
|
298
300
|
_qPulseWidth;
|
|
299
301
|
constructor(init) {
|
|
@@ -325,6 +327,10 @@ var CutSetting = class _CutSetting extends LightBurnBaseElement {
|
|
|
325
327
|
this._overScanning = init.overScanning;
|
|
326
328
|
if (init.lineAngle !== void 0) this._lineAngle = init.lineAngle;
|
|
327
329
|
if (init.crossHatch !== void 0) this._crossHatch = init.crossHatch;
|
|
330
|
+
if (init.wobbleEnable !== void 0)
|
|
331
|
+
this._wobbleEnable = init.wobbleEnable;
|
|
332
|
+
if (init.anglePerPass !== void 0)
|
|
333
|
+
this._anglePerPass = init.anglePerPass;
|
|
328
334
|
if (init.frequency !== void 0) this._frequency = init.frequency;
|
|
329
335
|
if (init.qPulseWidth !== void 0) this._qPulseWidth = init.qPulseWidth;
|
|
330
336
|
}
|
|
@@ -467,6 +473,18 @@ var CutSetting = class _CutSetting extends LightBurnBaseElement {
|
|
|
467
473
|
set crossHatch(value) {
|
|
468
474
|
this._crossHatch = value;
|
|
469
475
|
}
|
|
476
|
+
get wobbleEnable() {
|
|
477
|
+
return this._wobbleEnable;
|
|
478
|
+
}
|
|
479
|
+
set wobbleEnable(value) {
|
|
480
|
+
this._wobbleEnable = value;
|
|
481
|
+
}
|
|
482
|
+
get anglePerPass() {
|
|
483
|
+
return this._anglePerPass;
|
|
484
|
+
}
|
|
485
|
+
set anglePerPass(value) {
|
|
486
|
+
this._anglePerPass = value;
|
|
487
|
+
}
|
|
470
488
|
get frequency() {
|
|
471
489
|
return this._frequency;
|
|
472
490
|
}
|
|
@@ -509,6 +527,8 @@ var CutSetting = class _CutSetting extends LightBurnBaseElement {
|
|
|
509
527
|
"overScanning",
|
|
510
528
|
"lineAngle",
|
|
511
529
|
"crossHatch",
|
|
530
|
+
"wobbleEnable",
|
|
531
|
+
"anglePerPass",
|
|
512
532
|
"frequency",
|
|
513
533
|
"qPulseWidth"
|
|
514
534
|
];
|
|
@@ -551,6 +571,8 @@ var CutSetting = class _CutSetting extends LightBurnBaseElement {
|
|
|
551
571
|
cs.overScanning = num(getChildValue("overScanning"), void 0);
|
|
552
572
|
cs.lineAngle = num(getChildValue("lineAngle"), void 0);
|
|
553
573
|
cs.crossHatch = boolish(getChildValue("crossHatch"), void 0);
|
|
574
|
+
cs.wobbleEnable = boolish(getChildValue("wobbleEnable"), void 0);
|
|
575
|
+
cs.anglePerPass = num(getChildValue("anglePerPass"), void 0);
|
|
554
576
|
cs.frequency = num(getChildValue("frequency"), void 0);
|
|
555
577
|
cs.qPulseWidth = num(getChildValue("QPulseWidth"), void 0);
|
|
556
578
|
return cs;
|
|
@@ -566,7 +588,7 @@ var CutSettingPropertyElement = class extends LightBurnBaseElement {
|
|
|
566
588
|
this.propValue = propValue;
|
|
567
589
|
}
|
|
568
590
|
formatValue(value) {
|
|
569
|
-
if (this.propName === "crossHatch" && typeof value === "boolean") {
|
|
591
|
+
if ((this.propName === "crossHatch" || this.propName === "wobbleEnable") && typeof value === "boolean") {
|
|
570
592
|
return value ? "1" : "0";
|
|
571
593
|
}
|
|
572
594
|
if (typeof value === "number") {
|
|
@@ -1948,6 +1970,147 @@ function generateLightBurnSvg(root, options) {
|
|
|
1948
1970
|
const svgTree = assembleSvg(nodes, layout, []);
|
|
1949
1971
|
return stringify(svgTree);
|
|
1950
1972
|
}
|
|
1973
|
+
|
|
1974
|
+
// lib/split-by-cut-setting.ts
|
|
1975
|
+
function parseProject(input) {
|
|
1976
|
+
if (input instanceof LightBurnProject) return input;
|
|
1977
|
+
const parsed = LightBurnBaseElement.parse(input);
|
|
1978
|
+
if (!(parsed instanceof LightBurnProject)) {
|
|
1979
|
+
throw new Error("Expected a LightBurnProject XML document");
|
|
1980
|
+
}
|
|
1981
|
+
return parsed;
|
|
1982
|
+
}
|
|
1983
|
+
function fileBaseName(name, cutIndex) {
|
|
1984
|
+
return name.trim().toLowerCase().replace(/[<>:"/\\|?*\x00-\x1F]/g, "").replace(/\s+/g, "-").replace(/-+/g, "-").replace(/^-|-$/g, "") || `cut-index-${cutIndex}`;
|
|
1985
|
+
}
|
|
1986
|
+
function uniqueFileName(baseName, usedFileNames) {
|
|
1987
|
+
let fileName = `${baseName}.lbrn2`;
|
|
1988
|
+
let suffix = 2;
|
|
1989
|
+
while (usedFileNames.has(fileName)) {
|
|
1990
|
+
fileName = `${baseName}-${suffix}.lbrn2`;
|
|
1991
|
+
suffix += 1;
|
|
1992
|
+
}
|
|
1993
|
+
usedFileNames.add(fileName);
|
|
1994
|
+
return fileName;
|
|
1995
|
+
}
|
|
1996
|
+
function folderNameForFile(fileName) {
|
|
1997
|
+
if (!fileName) return void 0;
|
|
1998
|
+
const baseName = fileName.split(/[\\/]/).pop() ?? fileName;
|
|
1999
|
+
return fileBaseName(baseName.replace(/\.lbrn2?$/i, ""), 0);
|
|
2000
|
+
}
|
|
2001
|
+
function cloneGroup(group, children) {
|
|
2002
|
+
const clone = Object.assign(
|
|
2003
|
+
Object.create(Object.getPrototypeOf(group)),
|
|
2004
|
+
group
|
|
2005
|
+
);
|
|
2006
|
+
clone.children = children;
|
|
2007
|
+
return clone;
|
|
2008
|
+
}
|
|
2009
|
+
function countShapes(element) {
|
|
2010
|
+
if (element instanceof ShapeGroup) {
|
|
2011
|
+
return element.children.reduce((sum, child) => sum + countShapes(child), 0);
|
|
2012
|
+
}
|
|
2013
|
+
return element instanceof ShapeBase ? 1 : 0;
|
|
2014
|
+
}
|
|
2015
|
+
function filterShapeForCutIndex(element, cutIndex) {
|
|
2016
|
+
if (element instanceof ShapeGroup) {
|
|
2017
|
+
if (element.cutIndex === cutIndex) {
|
|
2018
|
+
return {
|
|
2019
|
+
shape: cloneGroup(element, [...element.children]),
|
|
2020
|
+
count: countShapes(element)
|
|
2021
|
+
};
|
|
2022
|
+
}
|
|
2023
|
+
const children = [];
|
|
2024
|
+
let count = 0;
|
|
2025
|
+
for (const child of element.children) {
|
|
2026
|
+
const result = filterShapeForCutIndex(child, cutIndex);
|
|
2027
|
+
if (result.shape) children.push(result.shape);
|
|
2028
|
+
count += result.count;
|
|
2029
|
+
}
|
|
2030
|
+
return children.length > 0 ? { shape: cloneGroup(element, children), count } : { count };
|
|
2031
|
+
}
|
|
2032
|
+
if (element instanceof ShapeBase && element.cutIndex === cutIndex) {
|
|
2033
|
+
return { shape: element, count: 1 };
|
|
2034
|
+
}
|
|
2035
|
+
return { count: 0 };
|
|
2036
|
+
}
|
|
2037
|
+
function projectForCutSetting(project, cutSetting) {
|
|
2038
|
+
const children = [];
|
|
2039
|
+
const cutIndex = cutSetting.index;
|
|
2040
|
+
let shapeCount = 0;
|
|
2041
|
+
for (const child of project.children) {
|
|
2042
|
+
if (child instanceof CutSetting) {
|
|
2043
|
+
if (child === cutSetting) children.push(child);
|
|
2044
|
+
continue;
|
|
2045
|
+
}
|
|
2046
|
+
if (child instanceof ShapeBase) {
|
|
2047
|
+
const result = filterShapeForCutIndex(child, cutIndex);
|
|
2048
|
+
if (result.shape) children.push(result.shape);
|
|
2049
|
+
shapeCount += result.count;
|
|
2050
|
+
continue;
|
|
2051
|
+
}
|
|
2052
|
+
children.push(child);
|
|
2053
|
+
}
|
|
2054
|
+
return {
|
|
2055
|
+
project: new LightBurnProject({
|
|
2056
|
+
appVersion: project.appVersion,
|
|
2057
|
+
formatVersion: project.formatVersion,
|
|
2058
|
+
materialHeight: project.materialHeight,
|
|
2059
|
+
mirrorX: project.mirrorX,
|
|
2060
|
+
mirrorY: project.mirrorY,
|
|
2061
|
+
children
|
|
2062
|
+
}),
|
|
2063
|
+
shapeCount
|
|
2064
|
+
};
|
|
2065
|
+
}
|
|
2066
|
+
function splitLightBurnProjectByCutSetting(input, originalFileName) {
|
|
2067
|
+
const project = parseProject(input);
|
|
2068
|
+
const folderName = folderNameForFile(originalFileName);
|
|
2069
|
+
const usedFileNames = /* @__PURE__ */ new Set();
|
|
2070
|
+
const files = [];
|
|
2071
|
+
for (const cutSetting of project.children) {
|
|
2072
|
+
if (!(cutSetting instanceof CutSetting) || cutSetting.index === void 0) {
|
|
2073
|
+
continue;
|
|
2074
|
+
}
|
|
2075
|
+
const cutIndex = cutSetting.index;
|
|
2076
|
+
const cutSettingName = cutSetting.name ?? `CutIndex ${cutIndex}`;
|
|
2077
|
+
const split = projectForCutSetting(project, cutSetting);
|
|
2078
|
+
const fileName = uniqueFileName(
|
|
2079
|
+
fileBaseName(cutSettingName, cutIndex),
|
|
2080
|
+
usedFileNames
|
|
2081
|
+
);
|
|
2082
|
+
files.push({
|
|
2083
|
+
fileName: folderName ? `${folderName}/${fileName}` : fileName,
|
|
2084
|
+
content: split.project.getString(),
|
|
2085
|
+
cutIndex,
|
|
2086
|
+
cutSettingName,
|
|
2087
|
+
shapeCount: split.shapeCount
|
|
2088
|
+
});
|
|
2089
|
+
}
|
|
2090
|
+
return files;
|
|
2091
|
+
}
|
|
2092
|
+
|
|
2093
|
+
// lib/apply-offset.ts
|
|
2094
|
+
function assertFiniteOffset(name, value) {
|
|
2095
|
+
if (!Number.isFinite(value)) {
|
|
2096
|
+
throw new Error(`${name} must be a finite number`);
|
|
2097
|
+
}
|
|
2098
|
+
}
|
|
2099
|
+
function applyOffsetToShape(shape, xOffset, yOffset) {
|
|
2100
|
+
const [a, b, c, d, tx, ty] = shape.xform;
|
|
2101
|
+
shape.xform = [a, b, c, d, tx + xOffset, ty + yOffset];
|
|
2102
|
+
}
|
|
2103
|
+
function applyOffsetToLbrn(params) {
|
|
2104
|
+
const { lbrnProject, xOffset, yOffset } = params;
|
|
2105
|
+
assertFiniteOffset("xOffset", xOffset);
|
|
2106
|
+
assertFiniteOffset("yOffset", yOffset);
|
|
2107
|
+
for (const child of lbrnProject.children) {
|
|
2108
|
+
if (child instanceof ShapeBase) {
|
|
2109
|
+
applyOffsetToShape(child, xOffset, yOffset);
|
|
2110
|
+
}
|
|
2111
|
+
}
|
|
2112
|
+
return lbrnProject;
|
|
2113
|
+
}
|
|
1951
2114
|
export {
|
|
1952
2115
|
LightBurnBaseElement as BaseLightBurnElement,
|
|
1953
2116
|
CutSetting,
|
|
@@ -1964,6 +2127,8 @@ export {
|
|
|
1964
2127
|
Thumbnail,
|
|
1965
2128
|
UIPrefs,
|
|
1966
2129
|
VariableText,
|
|
2130
|
+
applyOffsetToLbrn,
|
|
1967
2131
|
generateLightBurnSvg,
|
|
1968
|
-
parseXml
|
|
2132
|
+
parseXml,
|
|
2133
|
+
splitLightBurnProjectByCutSetting
|
|
1969
2134
|
};
|