@mylasertools/kerfscript 0.0.0-stage → 0.2.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 +60 -0
- package/CLA.md +76 -0
- package/COMMERCIAL-LICENSE.md +63 -0
- package/LANGUAGE.md +398 -0
- package/LICENSE +661 -0
- package/README.md +187 -2
- package/THIRD-PARTY-NOTICES.md +124 -0
- package/TRADEMARKS.md +45 -0
- package/dist/ast.d.cts +160 -0
- package/dist/ast.d.ts +160 -0
- package/dist/cli.d.cts +1 -0
- package/dist/cli.d.ts +1 -0
- package/dist/cli.js +19416 -0
- package/dist/customizer.d.cts +19 -0
- package/dist/customizer.d.ts +19 -0
- package/dist/evaluator.d.cts +129 -0
- package/dist/evaluator.d.ts +129 -0
- package/dist/export/dxf.d.cts +3 -0
- package/dist/export/dxf.d.ts +3 -0
- package/dist/export/svg.d.cts +15 -0
- package/dist/export/svg.d.ts +15 -0
- package/dist/functions.d.cts +4 -0
- package/dist/functions.d.ts +4 -0
- package/dist/geometry.d.cts +44 -0
- package/dist/geometry.d.ts +44 -0
- package/dist/index.cjs +44 -0
- package/dist/index.d.cts +10 -0
- package/dist/index.d.ts +10 -0
- package/dist/index.js +44 -0
- package/dist/joinery.d.cts +7 -0
- package/dist/joinery.d.ts +7 -0
- package/dist/lexer.d.cts +28 -0
- package/dist/lexer.d.ts +28 -0
- package/dist/parser.d.cts +6 -0
- package/dist/parser.d.ts +6 -0
- package/dist/paths.d.cts +28 -0
- package/dist/paths.d.ts +28 -0
- package/dist/render.d.cts +58 -0
- package/dist/render.d.ts +58 -0
- package/dist/stdlib.d.cts +1 -0
- package/dist/stdlib.d.ts +1 -0
- package/dist/text.d.cts +36 -0
- package/dist/text.d.ts +36 -0
- package/dist/values.d.cts +25 -0
- package/dist/values.d.ts +25 -0
- package/docs/cli.md +76 -0
- package/docs/compatibility.md +64 -0
- package/docs/customizer.md +74 -0
- package/docs/getting-started.md +115 -0
- package/docs/javascript.md +153 -0
- package/docs/kerf.md +67 -0
- package/docs/layers.md +108 -0
- package/docs/openscad.md +71 -0
- package/docs/parts-and-sheets.md +82 -0
- package/docs/versions.md +33 -0
- package/package.json +86 -4
package/CHANGELOG.md
ADDED
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
## 0.2.1
|
|
4
|
+
|
|
5
|
+
- Memory limits, so a program cannot make a browser tab run out of memory:
|
|
6
|
+
part copies, circle segments and polygon corners, list and string sizes,
|
|
7
|
+
all list items together, `text()` length, shape points, exported points
|
|
8
|
+
and sheets. Each stops the program with an error that says what to change.
|
|
9
|
+
Defaults are in `DEFAULT_LIMITS` and the `limits` render option changes
|
|
10
|
+
them. Every example stays well under them.
|
|
11
|
+
- A list or string that grows past what JavaScript can hold now gives a
|
|
12
|
+
KerfScript error instead of a `RangeError`.
|
|
13
|
+
- Lists are checked while they are built, so `each` in a long loop, list
|
|
14
|
+
arithmetic and matrix products stop at the limit instead of first filling
|
|
15
|
+
memory. Strings joined with `+`, strings from functions and `echo()` text
|
|
16
|
+
count toward `maxListItems` too, and a repeated unknown argument warning
|
|
17
|
+
is shown once.
|
|
18
|
+
- The commercial licence for closed-source apps and services is free: email
|
|
19
|
+
hi@mylasertools.com.
|
|
20
|
+
|
|
21
|
+
## 0.2.0 (2026-10-28)
|
|
22
|
+
|
|
23
|
+
First public release.
|
|
24
|
+
|
|
25
|
+
- `render()` returns `paths` (path data per layer), `width` and `height`, and
|
|
26
|
+
every sheet has `paths`, so host apps can draw layers without parsing SVG.
|
|
27
|
+
Each layer path has `d` (everything), `regions` (closed outlines, filled
|
|
28
|
+
even-odd on fill layers) and `lines` (open lines, always stroked).
|
|
29
|
+
- `margin` render option and `--margin` flag: space between the parts and
|
|
30
|
+
the sheet edge, separate from `gap` between parts (defaults to `gap`).
|
|
31
|
+
- Errors from a missing font carry `missingFonts`, so a host can load the
|
|
32
|
+
fonts and render again.
|
|
33
|
+
- `parameters()` gives list settings `"type": "number"` with a list
|
|
34
|
+
`initial`, the same as OpenSCAD's parameter JSON (was `"vector"`).
|
|
35
|
+
- Every setting has `span`, the source offsets of its value, so an editor
|
|
36
|
+
can change the value without touching anything else.
|
|
37
|
+
- A setting's caption comes only from a comment on its own line above it,
|
|
38
|
+
not from the end-of-line comment of the setting before.
|
|
39
|
+
- `text_width()` and `text_metrics()` errors report their line and column.
|
|
40
|
+
- A warning when kerf compensation closes a hole narrower than the kerf.
|
|
41
|
+
- `kerf check` lists every sheet with its material, thickness and pieces;
|
|
42
|
+
`kerf render` warns when several sheets are stacked in one SVG, and
|
|
43
|
+
`kerf --version` shows the language version too.
|
|
44
|
+
- Guides in `docs/`, calibration square and kerf test examples, and
|
|
45
|
+
`npm run compat`, which checks SVG and DXF output in Inkscape.
|
|
46
|
+
|
|
47
|
+
## 0.1.0 (not published)
|
|
48
|
+
|
|
49
|
+
First version of the KerfScript language (language version 0.1).
|
|
50
|
+
|
|
51
|
+
- Language: numbers, strings, lists, ranges, functions and closures, list
|
|
52
|
+
comprehensions, modules with children, dynamic `$` variables, `use` and
|
|
53
|
+
`include`, customizer comments.
|
|
54
|
+
- Shapes: rect, circle, ellipse, regular_polygon, star, polygon, SVG path,
|
|
55
|
+
text, line, polyline, arc.
|
|
56
|
+
- Booleans, hull, offset, stroke, outline and transforms.
|
|
57
|
+
- Laser layers (cut, score, engrave, guide, custom), parts, materials, kerf
|
|
58
|
+
compensation, inner cuts first, sheet packing.
|
|
59
|
+
- Joinery: finger_rect, finger_holes, tslot, living_hinge; `kerf/box`.
|
|
60
|
+
- SVG and DXF output, `kerf` command line tool.
|
package/CLA.md
ADDED
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
# KerfScript Contributor License Agreement
|
|
2
|
+
|
|
3
|
+
Version 1.0
|
|
4
|
+
|
|
5
|
+
Thank you for contributing to KerfScript. This agreement lets MyLaserTools
|
|
6
|
+
("we", "us") keep offering KerfScript as open source under the AGPL and under
|
|
7
|
+
commercial licences, including licences we may sell. You keep the copyright in
|
|
8
|
+
your contribution.
|
|
9
|
+
|
|
10
|
+
This agreement applies to a Contribution when you add the signature
|
|
11
|
+
statement below to the pull request that contains it. A Contribution is
|
|
12
|
+
material you intentionally submit in that signed pull request for inclusion
|
|
13
|
+
in KerfScript. Issue reports, ideas, unsigned pull requests and other
|
|
14
|
+
communications do not grant rights under this agreement. Sign each pull
|
|
15
|
+
request you want us to consider for inclusion.
|
|
16
|
+
|
|
17
|
+
## 1. Copyright licence
|
|
18
|
+
|
|
19
|
+
You grant us and recipients of software we distribute a perpetual, worldwide,
|
|
20
|
+
non-exclusive, no-charge, royalty-free, irrevocable licence to reproduce,
|
|
21
|
+
prepare derivative works of, publicly display, publicly perform, sublicense
|
|
22
|
+
and distribute Your Contributions and derivative works.
|
|
23
|
+
|
|
24
|
+
This licence includes the right for us to license Your Contribution, alone or
|
|
25
|
+
as part of KerfScript, under **any terms we choose**, including open source
|
|
26
|
+
licences other than the AGPL and proprietary or commercial licences, and to
|
|
27
|
+
sell such licences.
|
|
28
|
+
|
|
29
|
+
## 2. Patent licence
|
|
30
|
+
|
|
31
|
+
You grant us and recipients of software we distribute a perpetual, worldwide,
|
|
32
|
+
non-exclusive, no-charge, royalty-free, irrevocable patent licence to make,
|
|
33
|
+
have made, use, offer to sell, sell, import and otherwise transfer Your
|
|
34
|
+
Contribution, where the licence covers patent claims You can license that are
|
|
35
|
+
necessarily infringed by Your Contribution alone or combined with KerfScript.
|
|
36
|
+
If anyone starts patent litigation claiming KerfScript or a Contribution
|
|
37
|
+
infringes a patent, the patent licences granted to them under this agreement
|
|
38
|
+
end on the date the litigation is filed.
|
|
39
|
+
|
|
40
|
+
## 3. Your promises
|
|
41
|
+
|
|
42
|
+
- Each Contribution is Your original work, or You have the right to submit it
|
|
43
|
+
under this agreement and You identify any third-party parts and their
|
|
44
|
+
licences.
|
|
45
|
+
- If Your employer has rights in what You create, You have permission to make
|
|
46
|
+
the Contribution on its behalf, or Your employer has waived those rights.
|
|
47
|
+
- You will tell us if any of these promises stops being true.
|
|
48
|
+
|
|
49
|
+
## 4. What we promise
|
|
50
|
+
|
|
51
|
+
We will keep publishing KerfScript under an OSI-approved open source licence
|
|
52
|
+
alongside any commercial licence, for as long as we publish it at all. The
|
|
53
|
+
version that includes Your Contribution stays available under the licence it
|
|
54
|
+
was released with.
|
|
55
|
+
|
|
56
|
+
## 5. No other obligations
|
|
57
|
+
|
|
58
|
+
You provide Contributions "as is", without warranties or conditions of any
|
|
59
|
+
kind. We are not required to use Your Contribution.
|
|
60
|
+
|
|
61
|
+
## 6. Trademarks
|
|
62
|
+
|
|
63
|
+
This agreement does not grant either party rights in the other's names or
|
|
64
|
+
trademarks.
|
|
65
|
+
|
|
66
|
+
## How to sign
|
|
67
|
+
|
|
68
|
+
Add this statement to each pull request description, using your legal name:
|
|
69
|
+
|
|
70
|
+
```text
|
|
71
|
+
I have read the KerfScript CLA 1.0 and agree to it for my contributions.
|
|
72
|
+
Name: <your name> GitHub: <your handle> Date: <YYYY-MM-DD>
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
If You contribute on behalf of a company, contact hi@mylasertools.com for
|
|
76
|
+
the company version first.
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
# Licensing
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 MyLaserTools.
|
|
4
|
+
|
|
5
|
+
**KerfScript is free to use, including for commercial work.** Write programs,
|
|
6
|
+
cut and sell what you make, and sell your `.kerf` designs and the files they
|
|
7
|
+
produce. You don't need to ask us for any of that.
|
|
8
|
+
|
|
9
|
+
KerfScript is dual licensed. You can use it under **either**:
|
|
10
|
+
|
|
11
|
+
1. **The GNU Affero General Public License, version 3 only** (`AGPL-3.0-only`,
|
|
12
|
+
full text in [LICENSE](LICENSE)), together with the additional permission
|
|
13
|
+
below, or
|
|
14
|
+
2. **A commercial licence** from MyLaserTools, which is **free**.
|
|
15
|
+
|
|
16
|
+
## Free commercial licence
|
|
17
|
+
|
|
18
|
+
Want to build KerfScript into a closed-source app, plugin, machine, firmware
|
|
19
|
+
or online service? The commercial licence costs nothing. Just email
|
|
20
|
+
hi@mylasertools.com with your name or company and what you are building, and
|
|
21
|
+
we will send it to you.
|
|
22
|
+
|
|
23
|
+
## Additional permission: your designs are yours
|
|
24
|
+
|
|
25
|
+
As an additional permission under section 7 of the AGPL, MyLaserTools grants
|
|
26
|
+
that:
|
|
27
|
+
|
|
28
|
+
1. KerfScript programs you write (`.kerf` files), including programs that
|
|
29
|
+
`use` or `include` the KerfScript standard library in `lib/`, are not
|
|
30
|
+
considered a work based on KerfScript, and you may license and sell them on
|
|
31
|
+
any terms you choose.
|
|
32
|
+
2. Files that KerfScript produces from your programs (SVG, DXF, JSON and
|
|
33
|
+
others) belong to you and are not covered by the AGPL.
|
|
34
|
+
|
|
35
|
+
This permission covers your programs and their output only. It does not cover
|
|
36
|
+
the KerfScript interpreter, its tools, or modified copies of the standard
|
|
37
|
+
library, which remain under the AGPL unless you have the commercial licence.
|
|
38
|
+
|
|
39
|
+
## What the AGPL means for you
|
|
40
|
+
|
|
41
|
+
Under the AGPL you can:
|
|
42
|
+
|
|
43
|
+
- write KerfScript programs and cut, sell or share what you make with them
|
|
44
|
+
- run the interpreter, including a modified copy, privately or in internal
|
|
45
|
+
tools without publishing those private changes
|
|
46
|
+
- use an unmodified copy on a server
|
|
47
|
+
- distribute software that includes KerfScript, as long as you share its
|
|
48
|
+
source code under the AGPL
|
|
49
|
+
|
|
50
|
+
If you would rather not share your source code, ask for the free commercial
|
|
51
|
+
licence.
|
|
52
|
+
|
|
53
|
+
## Trademarks
|
|
54
|
+
|
|
55
|
+
"KerfScript" and the KerfScript logo are trademarks of MyLaserTools and are not
|
|
56
|
+
licensed by the AGPL or by the commercial licence unless that licence says so.
|
|
57
|
+
See [TRADEMARKS.md](TRADEMARKS.md).
|
|
58
|
+
|
|
59
|
+
## Contributions
|
|
60
|
+
|
|
61
|
+
MyLaserTools accepts contributions under the
|
|
62
|
+
[Contributor License Agreement](CLA.md), which lets MyLaserTools keep offering
|
|
63
|
+
KerfScript under both licences.
|
package/LANGUAGE.md
ADDED
|
@@ -0,0 +1,398 @@
|
|
|
1
|
+
# KerfScript language reference
|
|
2
|
+
|
|
3
|
+
Language version 0.1. Copyright (c) 2026 MyLaserTools. This document is
|
|
4
|
+
licensed under [CC BY 4.0](https://creativecommons.org/licenses/by/4.0/).
|
|
5
|
+
"KerfScript" is a trademark of MyLaserTools, see [TRADEMARKS.md](TRADEMARKS.md).
|
|
6
|
+
|
|
7
|
+
This reference covers KerfScript syntax, built-in modules and functions.
|
|
8
|
+
For a first project, follow [Getting started](docs/getting-started.md).
|
|
9
|
+
|
|
10
|
+
Programs build 2D shapes, assign them to cut, score or engrave layers, and
|
|
11
|
+
group them into parts. Rendering applies kerf compensation, arranges the
|
|
12
|
+
parts on sheets and produces SVG or DXF files.
|
|
13
|
+
|
|
14
|
+
Lengths are in millimetres and angles are in degrees. Positive x points
|
|
15
|
+
right; positive y points up.
|
|
16
|
+
|
|
17
|
+
```kerf
|
|
18
|
+
// A coaster with a hole, an engraved ring and a scored border.
|
|
19
|
+
|
|
20
|
+
size = 90; // [60:5:120]
|
|
21
|
+
|
|
22
|
+
difference() {
|
|
23
|
+
circle(d = size);
|
|
24
|
+
circle(d = 6);
|
|
25
|
+
}
|
|
26
|
+
engrave() difference() { circle(d = size - 16); circle(d = size - 22); }
|
|
27
|
+
score() circle(d = size - 6);
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
## Lexical structure
|
|
31
|
+
|
|
32
|
+
- Comments: `// line` and `/* block */`.
|
|
33
|
+
- Numbers: `12`, `0.5`, `.5`, `1e3`.
|
|
34
|
+
- Strings: `"text"` with `\n`, `\t`, `\"`, `\\` and `\uXXXX` escapes.
|
|
35
|
+
- Names: letters, digits and `_`, not starting with a digit. Names starting
|
|
36
|
+
with `$` are **special variables** (see Scope).
|
|
37
|
+
- Keywords: `module function if else for let each use include true false undef`.
|
|
38
|
+
|
|
39
|
+
## Values
|
|
40
|
+
|
|
41
|
+
| Type | Examples |
|
|
42
|
+
| -------- | ------------------------------------------------------------ |
|
|
43
|
+
| number | `3`, `-0.25`, `PI` |
|
|
44
|
+
| string | `"Oak"` |
|
|
45
|
+
| boolean | `true`, `false` |
|
|
46
|
+
| undef | `undef`, a missing argument, an index past the end of a list |
|
|
47
|
+
| list | `[1, 2]`, `[[0, 0], [10, 0], [5, 8]]` |
|
|
48
|
+
| range | `[0:5]` (0 to 5 step 1), `[0:2:10]` (0 to 10 step 2) |
|
|
49
|
+
| function | `function(x) x * 2` |
|
|
50
|
+
|
|
51
|
+
Points are lists `[x, y]`. `p.x` and `p.y` read the first two items.
|
|
52
|
+
|
|
53
|
+
## Expressions
|
|
54
|
+
|
|
55
|
+
Operators are listed from lowest to highest precedence. Use parentheses
|
|
56
|
+
to change the order of evaluation.
|
|
57
|
+
|
|
58
|
+
| Operator | Meaning |
|
|
59
|
+
| ------------------- | -------------------------------------------------------------------------------------------------------------- |
|
|
60
|
+
| `c ? a : b` | conditional |
|
|
61
|
+
| `\|\|` | or |
|
|
62
|
+
| `&&` | and |
|
|
63
|
+
| `==` `!=` | equality, lists compare item by item |
|
|
64
|
+
| `<` `<=` `>` `>=` | compare numbers or strings |
|
|
65
|
+
| `+` `-` | add or subtract numbers or equal length lists; `+` joins strings |
|
|
66
|
+
| `*` `/` `%` | multiply, divide, remainder; list times number scales; list times list is the dot product; matrix times vector |
|
|
67
|
+
| `-x` `!x` | negate, not |
|
|
68
|
+
| `a ^ b` | power, right associative and tighter than unary minus |
|
|
69
|
+
| `f(x)` `a[i]` `a.x` | call, index, member |
|
|
70
|
+
|
|
71
|
+
Unsupported combinations, such as a list plus a number or `undef + 1`,
|
|
72
|
+
produce an error at the source line.
|
|
73
|
+
|
|
74
|
+
In conditions, `false`, `0`, `""`, `[]` and `undef` count as false.
|
|
75
|
+
|
|
76
|
+
Use `let (a = 1, b = a + 1) expr` to define names for one expression.
|
|
77
|
+
Each binding can use the ones before it.
|
|
78
|
+
|
|
79
|
+
### List comprehensions
|
|
80
|
+
|
|
81
|
+
Build a list with `for`, filter items with `if`, or insert the contents of
|
|
82
|
+
another list with `each`:
|
|
83
|
+
|
|
84
|
+
```kerf
|
|
85
|
+
squares = [for (i = [1:5]) i * i];
|
|
86
|
+
odd = [for (i = [1:9]) if (i % 2) i];
|
|
87
|
+
grid = [for (x = [0:2], y = [0:2]) [x * 10, y * 10]];
|
|
88
|
+
flat = [each [1, 2], 3];
|
|
89
|
+
```
|
|
90
|
+
|
|
91
|
+
## Statements
|
|
92
|
+
|
|
93
|
+
Assignments and function definitions end with a semicolon. Modules create
|
|
94
|
+
geometry and can receive child statements. In the syntax below, `...`
|
|
95
|
+
stands for the body of a statement:
|
|
96
|
+
|
|
97
|
+
```kerf
|
|
98
|
+
name = expr; // assignment
|
|
99
|
+
function name(a, b = 2) = expr; // function
|
|
100
|
+
module name(a, b = 2) { ... } // module (makes shapes)
|
|
101
|
+
name(args) child; // module call with one child
|
|
102
|
+
name(args) { child; child; } // module call with a block of children
|
|
103
|
+
for (i = range_or_list, j = ...) ... // repeats, combined as a union
|
|
104
|
+
if (cond) ... else ...
|
|
105
|
+
let (a = 1) ...
|
|
106
|
+
use <path> // import modules and functions
|
|
107
|
+
include <path> // run another file in place
|
|
108
|
+
```
|
|
109
|
+
|
|
110
|
+
Arguments can be positional or named: `rect([20, 10], r = 2)`.
|
|
111
|
+
|
|
112
|
+
### Scope
|
|
113
|
+
|
|
114
|
+
- Assignments run **in order**. A later assignment to the same name replaces
|
|
115
|
+
the earlier one from that point on.
|
|
116
|
+
- `module` and `function` definitions are visible in their whole block, so you
|
|
117
|
+
can call them before they are defined.
|
|
118
|
+
- Blocks, loops and module bodies have their own scope.
|
|
119
|
+
- **Special variables** (`$name`) are dynamically scoped: a value set by a
|
|
120
|
+
caller is seen by everything it calls. Pass them as arguments too:
|
|
121
|
+
`circle(5, $fn = 6)`.
|
|
122
|
+
- Top-level assignments are the program's **parameters**. Renderers override
|
|
123
|
+
them by name (`kerf render -D width=200`).
|
|
124
|
+
|
|
125
|
+
### Modifiers
|
|
126
|
+
|
|
127
|
+
Place `*` before a module call to disable it. Use `#` or `%` to move its
|
|
128
|
+
geometry to the guide layer. Guides are included only when requested in
|
|
129
|
+
the render options.
|
|
130
|
+
|
|
131
|
+
### children()
|
|
132
|
+
|
|
133
|
+
Inside a module, `children()` renders all child statements passed by the
|
|
134
|
+
caller. `children(i)` selects one child, using a zero-based index.
|
|
135
|
+
`$children` is the number of children.
|
|
136
|
+
|
|
137
|
+
```kerf
|
|
138
|
+
module hang_hole(d = 5) {
|
|
139
|
+
difference() { children(); translate([0, -d * 1.5]) circle(d = d); }
|
|
140
|
+
}
|
|
141
|
+
```
|
|
142
|
+
|
|
143
|
+
## Special variables
|
|
144
|
+
|
|
145
|
+
| Name | Default | Meaning |
|
|
146
|
+
| ----------------- | ------------- | -------------------------------------------------------------------------- |
|
|
147
|
+
| `$thickness` | `3` | material thickness, used by joinery and stored on parts |
|
|
148
|
+
| `$kerf` | `0` | beam width; cut outlines are offset by half of it |
|
|
149
|
+
| `$material` | `"material"` | material name; parts are packed per material and thickness |
|
|
150
|
+
| `$sheet` | `[600, 400]` | sheet size for packing |
|
|
151
|
+
| `$gap` | `3` | space between packed parts and around the sheet edge |
|
|
152
|
+
| `$layout` | `"pack"` | `"pack"` packs parts onto sheets, `"none"` keeps your placement |
|
|
153
|
+
| `$fn` `$fa` `$fs` | `0` `2` `0.2` | curve resolution: fixed segment count, or max angle and max segment length |
|
|
154
|
+
| `$font` | | default font name for `text()` |
|
|
155
|
+
|
|
156
|
+
## Layers
|
|
157
|
+
|
|
158
|
+
Every shape is on a layer. Shapes not wrapped in a layer module are on `cut`.
|
|
159
|
+
|
|
160
|
+
| Layer | Mode | Colour | Intended operation |
|
|
161
|
+
| --------- | ----- | --------- | ---------------------------------------------------- |
|
|
162
|
+
| `engrave` | fill | `#000000` | the area is engraved |
|
|
163
|
+
| `score` | line | `#0000ff` | lines and shape outlines are marked, not cut through |
|
|
164
|
+
| `cut` | cut | `#ff0000` | outlines are cut through, with kerf compensation |
|
|
165
|
+
| `guide` | guide | `#00a0ff` | shown only when guides are requested |
|
|
166
|
+
|
|
167
|
+
```kerf
|
|
168
|
+
cut() ... engrave() ... score() ... guide() ...
|
|
169
|
+
layer("pocket", mode = "fill", color = "#00aa00") ...
|
|
170
|
+
```
|
|
171
|
+
|
|
172
|
+
Use `layer(name, mode, color)` to define a custom layer. Its mode is
|
|
173
|
+
`"cut"`, `"line"`, `"fill"` or `"guide"`.
|
|
174
|
+
|
|
175
|
+
Files list layers in this order: engrave, custom layers, score, cut, guide.
|
|
176
|
+
Set the actual operation order, power and speed in your laser software.
|
|
177
|
+
See [Laser software](docs/compatibility.md) for import details.
|
|
178
|
+
|
|
179
|
+
When a part is rendered:
|
|
180
|
+
|
|
181
|
+
- The part's **material** is the union of its cut layer shapes.
|
|
182
|
+
- Engrave, score and custom layers are clipped to the material, so nothing is
|
|
183
|
+
marked inside holes or off the part. Score outlines become lines first.
|
|
184
|
+
- Cut lines (from `line()`, `living_hinge()` and similar) are clipped to the
|
|
185
|
+
material.
|
|
186
|
+
- If the material breaks into more than one piece, the renderer warns.
|
|
187
|
+
- In the output, holes and inner cuts come before outer outlines.
|
|
188
|
+
|
|
189
|
+
## Parts and sheets
|
|
190
|
+
|
|
191
|
+
Use `part()` to name a component and set its quantity. Wrap parts in
|
|
192
|
+
`material()` when they share a thickness, kerf and material name:
|
|
193
|
+
|
|
194
|
+
```kerf
|
|
195
|
+
material(thickness = 4, kerf = 0.12, name = "birch") {
|
|
196
|
+
part("side", qty = 2) finger_rect([100, 60], "out");
|
|
197
|
+
part("base") rect([100, 100]);
|
|
198
|
+
}
|
|
199
|
+
```
|
|
200
|
+
|
|
201
|
+
- `part(name, qty = 1) { ... }` makes a named part. It records `$thickness`,
|
|
202
|
+
`$kerf` and `$material` where it is called.
|
|
203
|
+
- Shapes outside any part form one part named `part`.
|
|
204
|
+
- `material(thickness, kerf, name) { ... }` sets those special variables for
|
|
205
|
+
its children.
|
|
206
|
+
- With `$layout = "pack"`, parts are grouped by material and thickness and
|
|
207
|
+
repeated `qty` times. They are arranged in rows on sheets of `$sheet` and
|
|
208
|
+
may be rotated 90° to fit. Parts larger than the sheet produce a warning.
|
|
209
|
+
|
|
210
|
+
See [Parts and sheets](docs/parts-and-sheets.md) for spacing, layout and
|
|
211
|
+
export examples.
|
|
212
|
+
|
|
213
|
+
## Built-in modules
|
|
214
|
+
|
|
215
|
+
### Shapes
|
|
216
|
+
|
|
217
|
+
| Module | Notes |
|
|
218
|
+
| ---------------------------------------------------------- | ---------------------------------------------------------------------------- |
|
|
219
|
+
| `rect(size, center = false, r = 0)` | `size` is a number or `[w, h]`; `r` rounds the corners. `square` is an alias |
|
|
220
|
+
| `circle(r)` or `circle(d = ...)` | |
|
|
221
|
+
| `ellipse([rx, ry])` | |
|
|
222
|
+
| `regular_polygon(n, r)` | corner radius `r` |
|
|
223
|
+
| `star(n, r, inner)` | |
|
|
224
|
+
| `polygon(points, paths)` | even-odd fill, `paths` lists point indexes per outline |
|
|
225
|
+
| `path(d, fill = "evenodd")` | SVG path data; closed subpaths become shapes, open ones lines |
|
|
226
|
+
| `text(text, size = 10, font, halign, valign, spacing = 1)` | `halign`: left, center, right; `valign`: baseline, top, center, bottom |
|
|
227
|
+
| `line(from, to)` | a line, not an area |
|
|
228
|
+
| `polyline(points, closed = false)` | |
|
|
229
|
+
| `arc(r, start = 0, end = 90)` | arc line, angles in degrees |
|
|
230
|
+
|
|
231
|
+
Supply geometry as children of a shape-processing module, for example
|
|
232
|
+
`translate([10, 0]) circle(d = 5);`. Fonts used by `text()` must be supplied
|
|
233
|
+
by the application or through the [command line](docs/cli.md).
|
|
234
|
+
|
|
235
|
+
### Transforms
|
|
236
|
+
|
|
237
|
+
| Module | Effect |
|
|
238
|
+
| --- | --- |
|
|
239
|
+
| `translate([x, y])` | Move geometry by x and y |
|
|
240
|
+
| `rotate(a, center = [x, y])` | Rotate by `a` degrees around a point; the default centre is the origin |
|
|
241
|
+
| `scale(s)` | Scale both axes by the same factor |
|
|
242
|
+
| `scale([sx, sy])` | Scale each axis separately |
|
|
243
|
+
| `mirror([nx, ny])` | Reflect across a line through the origin, perpendicular to this vector |
|
|
244
|
+
| `multmatrix(m)` | Apply a 2 × 3 transformation matrix |
|
|
245
|
+
|
|
246
|
+
### Combining
|
|
247
|
+
|
|
248
|
+
| Module | Notes |
|
|
249
|
+
| ---------------------------------------------- | -------------------------------------------------------------------------- |
|
|
250
|
+
| `union()` / `group()` | joins children |
|
|
251
|
+
| `difference()` | removes every later child's area from every layer of the first child |
|
|
252
|
+
| `intersection()` | keeps only the area common to all children, layers of the first child kept |
|
|
253
|
+
| `hull()` | convex hull |
|
|
254
|
+
| `offset(r)` / `offset(delta, chamfer = false)` | grow (positive) or shrink areas; `r` rounds corners |
|
|
255
|
+
| `stroke(width)` | turns lines into areas of that width, for cutting single line art |
|
|
256
|
+
| `outline()` | turns areas into their outline lines |
|
|
257
|
+
|
|
258
|
+
### Joinery
|
|
259
|
+
|
|
260
|
+
| Module | Notes |
|
|
261
|
+
| ---------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
262
|
+
| `finger_rect(size, edges, finger)` | rectangle with finger joints. `edges` is one value or `[bottom, right, top, left]`, each `"out"`, `"in"` or `"flat"`. An `"out"` edge keeps its corners, an `"in"` edge notches them; join an `"out"` edge to an `"in"` edge of the same length. Notch depth is `$thickness`; `finger` defaults to `max(3 * $thickness, 6)` and the count is always odd |
|
|
263
|
+
| `finger_holes(length, edge = "out", finger)` | row of slots along x, centred on y = 0, that an `edge` finger edge of the same length plugs into (for shelves and dividers) |
|
|
264
|
+
| `tslot(d = 3, length = 12, nut = [w, h], nut_at)` | T-slot for a screw and nut, opening at y = 0 and running up; subtract it from a panel edge |
|
|
265
|
+
| `living_hinge(size, spacing = 1.5, bridge = 3, cut)` | straight-line flex pattern as cut lines filling `[w, h]` |
|
|
266
|
+
|
|
267
|
+
### Other
|
|
268
|
+
|
|
269
|
+
| Module | Effect |
|
|
270
|
+
| --- | --- |
|
|
271
|
+
| `echo(...)` | Report values without creating geometry |
|
|
272
|
+
| `assert(cond, message)` | Stop with `message` when `cond` is false |
|
|
273
|
+
| `children(i)` | Render a child passed to the current module; omit `i` to render all children |
|
|
274
|
+
|
|
275
|
+
## Built-in functions
|
|
276
|
+
|
|
277
|
+
Functions return values. The examples below use positional arguments.
|
|
278
|
+
|
|
279
|
+
### Numbers and vectors
|
|
280
|
+
|
|
281
|
+
| Function | Result |
|
|
282
|
+
| --- | --- |
|
|
283
|
+
| `abs(x)`, `sign(x)` | Absolute value, or sign as -1, 0 or 1 |
|
|
284
|
+
| `floor(x)`, `ceil(x)`, `round(x)` | Round down, up or to the nearest integer |
|
|
285
|
+
| `sqrt(x)`, `pow(x, y)` | Square root, or x raised to y |
|
|
286
|
+
| `exp(x)`, `ln(x)` | Exponential with base e, or natural logarithm |
|
|
287
|
+
| `log(x)`, `log(base, x)` | Base-10 logarithm, or logarithm with a chosen base |
|
|
288
|
+
| `sin(a)`, `cos(a)`, `tan(a)` | Trigonometric functions with angles in degrees |
|
|
289
|
+
| `asin(x)`, `acos(x)`, `atan(x)`, `atan2(y, x)` | Inverse trigonometric functions, returning degrees |
|
|
290
|
+
| `min(values)`, `max(values)` | Minimum or maximum of a list; also accept separate values |
|
|
291
|
+
| `clamp(x, low, high)` | Limit x to the given interval |
|
|
292
|
+
| `lerp(a, b, t)` | Interpolate between numbers or vectors; t = 0 gives a, t = 1 gives b |
|
|
293
|
+
| `norm(v)` | Length of a vector |
|
|
294
|
+
| `cross(a, b)` | Cross product; a scalar for 2D vectors or a vector for 3D vectors |
|
|
295
|
+
|
|
296
|
+
### Lists and strings
|
|
297
|
+
|
|
298
|
+
| Function | Result |
|
|
299
|
+
| --- | --- |
|
|
300
|
+
| `len(value)` | Number of items in a list or characters in a string |
|
|
301
|
+
| `concat(...)` | Join lists and individual values into one list |
|
|
302
|
+
| `reverse(value)` | Reverse a list or string |
|
|
303
|
+
| `sum(values)` | Sum a list of numbers |
|
|
304
|
+
| `slice(value, start = 0, end)` | Extract part of a list or string; `end` is exclusive and defaults to its length |
|
|
305
|
+
| `str(...)` | Convert values to text and join them |
|
|
306
|
+
| `chr(...)`, `ord(text)` | Convert Unicode code points to text, or read the first character's code point |
|
|
307
|
+
| `upper(text)`, `lower(text)` | Change letter case |
|
|
308
|
+
| `split(text, separator = " ")` | Split text into a list of strings |
|
|
309
|
+
| `join(values, separator = "")` | Join values into a string |
|
|
310
|
+
| `search(value, list)` | Index of the first equal item, or `undef` if absent; also searches characters in strings |
|
|
311
|
+
| `contains(value, item)` | Whether a list contains an item or a string contains a substring |
|
|
312
|
+
| `lookup(x, table)` | Interpolate in a table of `[x, y]` pairs; use the nearest endpoint outside the table's range |
|
|
313
|
+
|
|
314
|
+
### Types
|
|
315
|
+
|
|
316
|
+
`is_num(value)`, `is_string(value)`, `is_bool(value)`, `is_list(value)`,
|
|
317
|
+
`is_undef(value)` and `is_function(value)` return a boolean.
|
|
318
|
+
`type_of(value)` returns the type name as a string.
|
|
319
|
+
|
|
320
|
+
### Random values
|
|
321
|
+
|
|
322
|
+
`rands(min, max, count, seed = 1)` returns a list of numbers between the
|
|
323
|
+
bounds. The same seed gives the same sequence.
|
|
324
|
+
|
|
325
|
+
### Text measurements
|
|
326
|
+
|
|
327
|
+
`text_width(text, size, font)` returns the advance width, including glyph
|
|
328
|
+
spacing. `text_metrics(text, size, font)` returns
|
|
329
|
+
`[advance, [[x0, y0], [x1, y1]], ascent, descent]`.
|
|
330
|
+
|
|
331
|
+
Both require the font to be available to the renderer, just like `text()`.
|
|
332
|
+
|
|
333
|
+
### Joint dimensions
|
|
334
|
+
|
|
335
|
+
`finger_count(length, finger)` returns the odd finger count used by
|
|
336
|
+
`finger_rect()` for an edge of that length.
|
|
337
|
+
|
|
338
|
+
## Customizer comments
|
|
339
|
+
|
|
340
|
+
Top-level assignments with a literal number, string, boolean or numeric
|
|
341
|
+
list can appear as editable settings. Comments supply captions, ranges,
|
|
342
|
+
choices and groups:
|
|
343
|
+
|
|
344
|
+
```kerf
|
|
345
|
+
/* [Size] */ // group for the following parameters
|
|
346
|
+
// Outer width <- caption: the comment line above
|
|
347
|
+
width = 120; // [40:5:400] min:step:max
|
|
348
|
+
depth = 80; // [200] max
|
|
349
|
+
shape = "round"; // [round:Round, square:Square] choices with labels
|
|
350
|
+
count = 3; // [2, 3, 4] choices
|
|
351
|
+
/* [Hidden] */ // not listed
|
|
352
|
+
```
|
|
353
|
+
|
|
354
|
+
These comments follow OpenSCAD's customizer format. Read
|
|
355
|
+
[Settings](docs/customizer.md) for supported controls, or use `kerf params`
|
|
356
|
+
to inspect the settings in a file.
|
|
357
|
+
|
|
358
|
+
## Standard library
|
|
359
|
+
|
|
360
|
+
Load the box modules with `use <kerf/box>`:
|
|
361
|
+
|
|
362
|
+
- `box([w, d, h], lid = false, finger)` makes the six (or five) panels of a
|
|
363
|
+
finger-jointed box as parts `bottom`, `lid`, `front`, `back`, `left`,
|
|
364
|
+
`right`. Sizes are outer sizes.
|
|
365
|
+
- `divider([w, h], finger)` makes a divider with finger tabs on both sides.
|
|
366
|
+
|
|
367
|
+
## Output
|
|
368
|
+
|
|
369
|
+
- **SVG**: millimetre units, one Inkscape layer group per KerfScript layer,
|
|
370
|
+
colours as above, 0.1 mm hairline strokes, `data-part` on every path.
|
|
371
|
+
- **DXF**: R12 (AC1009) polylines on layers named after KerfScript layers,
|
|
372
|
+
with matching AutoCAD colours.
|
|
373
|
+
|
|
374
|
+
## Limits
|
|
375
|
+
|
|
376
|
+
The interpreter limits call depth to 1,000 for modules and 2,000 for
|
|
377
|
+
functions. Expanded ranges are limited to 1,000,000 items. The default
|
|
378
|
+
evaluation limit is 5,000,000 steps; applications can change it with
|
|
379
|
+
`maxSteps`. Exceeding a limit stops evaluation with an error.
|
|
380
|
+
|
|
381
|
+
Programs are also limited in how much memory they can ask for:
|
|
382
|
+
|
|
383
|
+
| Limit | Default | What it counts |
|
|
384
|
+
| --- | --- | --- |
|
|
385
|
+
| `maxParts` | 10,000 | copies of all parts, adding up every `qty` |
|
|
386
|
+
| `maxSegments` | 10,000 | segments in one circle, ellipse or arc, and corners in one polygon |
|
|
387
|
+
| `maxListLength` | 1,000,000 | items in one list, or characters in one string |
|
|
388
|
+
| `maxListItems` | 3,000,000 | items in all lists the program builds, plus 4 for each list, one for every 8 characters of the strings it builds or echoes |
|
|
389
|
+
| `maxTextLength` | 2,000 | characters in one `text()` |
|
|
390
|
+
| `maxPoints` | 2,000,000 | points in all shapes the modules make, plus 100 for each shape |
|
|
391
|
+
| `maxOutputPoints` | 1,000,000 | points in the exported files, counting every copy |
|
|
392
|
+
| `maxSheets` | 200 | sheets in the layout |
|
|
393
|
+
|
|
394
|
+
Applications can change them with the `limits` render option.
|
|
395
|
+
|
|
396
|
+
Geometry operations also take time. Applications that render user programs
|
|
397
|
+
should run them in a worker with a timeout; see the
|
|
398
|
+
[JavaScript API](docs/javascript.md#running-untrusted-code).
|