@mylasertools/kerfscript 0.0.0-stage → 0.2.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 +42 -0
- package/CLA.md +73 -0
- package/COMMERCIAL-LICENSE.md +68 -0
- package/LANGUAGE.md +295 -0
- package/LICENSE +661 -0
- package/README.md +148 -2
- package/THIRD-PARTY-NOTICES.md +69 -0
- package/TRADEMARKS.md +39 -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 +19226 -0
- package/dist/customizer.d.cts +19 -0
- package/dist/customizer.d.ts +19 -0
- package/dist/evaluator.d.cts +106 -0
- package/dist/evaluator.d.ts +106 -0
- package/dist/export/dxf.d.cts +3 -0
- package/dist/export/dxf.d.ts +3 -0
- package/dist/export/svg.d.cts +13 -0
- package/dist/export/svg.d.ts +13 -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 +57 -0
- package/dist/render.d.ts +57 -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 +61 -0
- package/docs/compatibility.md +89 -0
- package/docs/customizer.md +62 -0
- package/docs/getting-started.md +98 -0
- package/docs/javascript.md +98 -0
- package/docs/kerf.md +70 -0
- package/docs/layers.md +74 -0
- package/docs/openscad.md +67 -0
- package/docs/parts-and-sheets.md +68 -0
- package/docs/versions.md +43 -0
- package/package.json +85 -4
package/CHANGELOG.md
ADDED
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
## 0.2.0 (2026-10-28)
|
|
4
|
+
|
|
5
|
+
First public release.
|
|
6
|
+
|
|
7
|
+
- `render()` returns `paths` (path data per layer), `width` and `height`, and
|
|
8
|
+
every sheet has `paths`, so host apps can draw layers without parsing SVG.
|
|
9
|
+
Each layer path has `d` (everything), `regions` (closed outlines, filled
|
|
10
|
+
even-odd on fill layers) and `lines` (open lines, always stroked).
|
|
11
|
+
- `margin` render option and `--margin` flag: space between the parts and
|
|
12
|
+
the sheet edge, separate from `gap` between parts (defaults to `gap`).
|
|
13
|
+
- Errors from a missing font carry `missingFonts`, so a host can load the
|
|
14
|
+
fonts and render again.
|
|
15
|
+
- `parameters()` gives list settings `"type": "number"` with a list
|
|
16
|
+
`initial`, the same as OpenSCAD's parameter JSON (was `"vector"`).
|
|
17
|
+
- Every setting has `span`, the source offsets of its value, so an editor
|
|
18
|
+
can change the value without touching anything else.
|
|
19
|
+
- A setting's caption comes only from a comment on its own line above it,
|
|
20
|
+
not from the end-of-line comment of the setting before.
|
|
21
|
+
- `text_width()` and `text_metrics()` errors report their line and column.
|
|
22
|
+
- A warning when kerf compensation closes a hole narrower than the kerf.
|
|
23
|
+
- `kerf check` lists every sheet with its material, thickness and pieces;
|
|
24
|
+
`kerf render` warns when several sheets are stacked in one SVG, and
|
|
25
|
+
`kerf --version` shows the language version too.
|
|
26
|
+
- Guides in `docs/`, calibration square and kerf test examples, and
|
|
27
|
+
`npm run compat`, which checks SVG and DXF output in Inkscape.
|
|
28
|
+
|
|
29
|
+
## 0.1.0 (not published)
|
|
30
|
+
|
|
31
|
+
First version of the KerfScript language (language version 0.1).
|
|
32
|
+
|
|
33
|
+
- Language: numbers, strings, lists, ranges, functions and closures, list
|
|
34
|
+
comprehensions, modules with children, dynamic `$` variables, `use` and
|
|
35
|
+
`include`, customizer comments.
|
|
36
|
+
- Shapes: rect, circle, ellipse, regular_polygon, star, polygon, SVG path,
|
|
37
|
+
text, line, polyline, arc.
|
|
38
|
+
- Booleans, hull, offset, stroke, outline and transforms.
|
|
39
|
+
- Laser layers (cut, score, engrave, guide, custom), parts, materials, kerf
|
|
40
|
+
compensation, inner cuts first, sheet packing.
|
|
41
|
+
- Joinery: finger_rect, finger_holes, tslot, living_hinge; `kerf/box`.
|
|
42
|
+
- SVG and DXF output, `kerf` command line tool.
|
package/CLA.md
ADDED
|
@@ -0,0 +1,73 @@
|
|
|
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
|
+
By submitting a Contribution (a pull request, patch, issue attachment or any
|
|
11
|
+
other material you intentionally send us for inclusion in KerfScript) you
|
|
12
|
+
("You") agree to the following for that Contribution and every later one.
|
|
13
|
+
|
|
14
|
+
## 1. Copyright licence
|
|
15
|
+
|
|
16
|
+
You grant us and recipients of software we distribute a perpetual, worldwide,
|
|
17
|
+
non-exclusive, no-charge, royalty-free, irrevocable licence to reproduce,
|
|
18
|
+
prepare derivative works of, publicly display, publicly perform, sublicense
|
|
19
|
+
and distribute Your Contributions and derivative works.
|
|
20
|
+
|
|
21
|
+
This licence includes the right for us to license Your Contribution, alone or
|
|
22
|
+
as part of KerfScript, under **any terms we choose**, including open source
|
|
23
|
+
licences other than the AGPL and proprietary or commercial licences, and to
|
|
24
|
+
sell such licences.
|
|
25
|
+
|
|
26
|
+
## 2. Patent licence
|
|
27
|
+
|
|
28
|
+
You grant us and recipients of software we distribute a perpetual, worldwide,
|
|
29
|
+
non-exclusive, no-charge, royalty-free, irrevocable patent licence to make,
|
|
30
|
+
have made, use, offer to sell, sell, import and otherwise transfer Your
|
|
31
|
+
Contribution, where the licence covers patent claims You can license that are
|
|
32
|
+
necessarily infringed by Your Contribution alone or combined with KerfScript.
|
|
33
|
+
If anyone starts patent litigation claiming KerfScript or a Contribution
|
|
34
|
+
infringes a patent, the patent licences granted to them under this agreement
|
|
35
|
+
end on the date the litigation is filed.
|
|
36
|
+
|
|
37
|
+
## 3. Your promises
|
|
38
|
+
|
|
39
|
+
- Each Contribution is Your original work, or You have the right to submit it
|
|
40
|
+
under this agreement and You identify any third-party parts and their
|
|
41
|
+
licences.
|
|
42
|
+
- If Your employer has rights in what You create, You have permission to make
|
|
43
|
+
the Contribution on its behalf, or Your employer has waived those rights.
|
|
44
|
+
- You will tell us if any of these promises stops being true.
|
|
45
|
+
|
|
46
|
+
## 4. What we promise
|
|
47
|
+
|
|
48
|
+
We will keep publishing KerfScript under an OSI-approved open source licence
|
|
49
|
+
alongside any commercial licence, for as long as we publish it at all. The
|
|
50
|
+
version that includes Your Contribution stays available under the licence it
|
|
51
|
+
was released with.
|
|
52
|
+
|
|
53
|
+
## 5. No other obligations
|
|
54
|
+
|
|
55
|
+
You provide Contributions "as is", without warranties or conditions of any
|
|
56
|
+
kind. We are not required to use Your Contribution.
|
|
57
|
+
|
|
58
|
+
## 6. Trademarks
|
|
59
|
+
|
|
60
|
+
This agreement does not grant either party rights in the other's names or
|
|
61
|
+
trademarks.
|
|
62
|
+
|
|
63
|
+
## How to sign
|
|
64
|
+
|
|
65
|
+
Add this line to your first pull request description, using your legal name:
|
|
66
|
+
|
|
67
|
+
```text
|
|
68
|
+
I have read the KerfScript CLA 1.0 and agree to it for my contributions.
|
|
69
|
+
Name: <your name> GitHub: <your handle> Date: <YYYY-MM-DD>
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
If You contribute on behalf of a company, contact julia@mylasertools.com for
|
|
73
|
+
the company version first.
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
# Licensing
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 MyLaserTools. All rights reserved except as granted below.
|
|
4
|
+
|
|
5
|
+
KerfScript is dual licensed. You can use it under **either**:
|
|
6
|
+
|
|
7
|
+
1. **The GNU Affero General Public License, version 3 only** (`AGPL-3.0-only`,
|
|
8
|
+
full text in [LICENSE](LICENSE)), together with the additional permission
|
|
9
|
+
below, or
|
|
10
|
+
2. **A commercial licence** from MyLaserTools.
|
|
11
|
+
|
|
12
|
+
## What the AGPL means for you
|
|
13
|
+
|
|
14
|
+
Free, under the AGPL, when you:
|
|
15
|
+
|
|
16
|
+
- write KerfScript programs and cut, sell or share what you make with them
|
|
17
|
+
- use the `kerf` command line tool, or the library inside software you only run
|
|
18
|
+
for yourself
|
|
19
|
+
- build open source software on KerfScript and publish its complete source code
|
|
20
|
+
under the AGPL
|
|
21
|
+
|
|
22
|
+
You need a commercial licence when you:
|
|
23
|
+
|
|
24
|
+
- ship KerfScript inside a closed source app, plugin, machine or firmware
|
|
25
|
+
- run KerfScript (or a modified copy) behind a website or online service and do
|
|
26
|
+
not want to publish that service's complete source code under the AGPL
|
|
27
|
+
- want to change KerfScript without sharing your changes
|
|
28
|
+
|
|
29
|
+
The AGPL treats letting people use the software over a network like
|
|
30
|
+
distributing it: if you modify KerfScript or build it into a service that
|
|
31
|
+
others use, you must offer those users the complete corresponding source code
|
|
32
|
+
of the whole program under the AGPL.
|
|
33
|
+
|
|
34
|
+
## Additional permission: your designs are yours
|
|
35
|
+
|
|
36
|
+
As an additional permission under section 7 of the AGPL, MyLaserTools grants
|
|
37
|
+
that:
|
|
38
|
+
|
|
39
|
+
1. KerfScript programs you write (`.kerf` files), including programs that
|
|
40
|
+
`use` or `include` the KerfScript standard library in `lib/`, are not
|
|
41
|
+
considered a work based on KerfScript, and you may license and sell them on
|
|
42
|
+
any terms you choose.
|
|
43
|
+
2. Files that KerfScript produces from your programs (SVG, DXF, JSON and
|
|
44
|
+
others) belong to you and are not covered by the AGPL.
|
|
45
|
+
|
|
46
|
+
This permission covers your programs and their output only. It does not cover
|
|
47
|
+
the KerfScript interpreter, its tools, or modified copies of the standard
|
|
48
|
+
library, which remain under the AGPL.
|
|
49
|
+
|
|
50
|
+
## Commercial licences
|
|
51
|
+
|
|
52
|
+
A commercial licence replaces the AGPL obligations with ordinary commercial
|
|
53
|
+
terms: closed source use, use in hosted services, private modifications and
|
|
54
|
+
support options. Terms and pricing are set per agreement.
|
|
55
|
+
|
|
56
|
+
Contact: julia@mylasertools.com
|
|
57
|
+
|
|
58
|
+
## Trademarks
|
|
59
|
+
|
|
60
|
+
"KerfScript" and the KerfScript logo are trademarks of MyLaserTools and are not
|
|
61
|
+
licensed by the AGPL or by the commercial licence unless that licence says so.
|
|
62
|
+
See [TRADEMARKS.md](TRADEMARKS.md).
|
|
63
|
+
|
|
64
|
+
## Contributions
|
|
65
|
+
|
|
66
|
+
MyLaserTools accepts contributions under the
|
|
67
|
+
[Contributor License Agreement](CLA.md), which lets MyLaserTools keep offering
|
|
68
|
+
KerfScript under both licences.
|
package/LANGUAGE.md
ADDED
|
@@ -0,0 +1,295 @@
|
|
|
1
|
+
# KerfScript language reference
|
|
2
|
+
|
|
3
|
+
Language version 0.1. Copyright (c) 2026 MyLaserTools. This document is
|
|
4
|
+
licensed under [CC BY-ND 4.0](https://creativecommons.org/licenses/by-nd/4.0/).
|
|
5
|
+
"KerfScript" is a trademark of MyLaserTools, see [TRADEMARKS.md](TRADEMARKS.md).
|
|
6
|
+
|
|
7
|
+
KerfScript describes flat parts for laser cutting. A program is a list of
|
|
8
|
+
statements that build 2D shapes, put them on **layers** (cut, score, engrave),
|
|
9
|
+
group them into **parts**, and the renderer compensates for the **kerf**, packs
|
|
10
|
+
parts onto **sheets** and writes SVG or DXF.
|
|
11
|
+
|
|
12
|
+
Units are millimetres and degrees. The y axis points up.
|
|
13
|
+
|
|
14
|
+
```kerf
|
|
15
|
+
// A coaster with a hole, an engraved ring and a scored border.
|
|
16
|
+
|
|
17
|
+
size = 90; // [60:5:120]
|
|
18
|
+
|
|
19
|
+
difference() {
|
|
20
|
+
circle(d = size);
|
|
21
|
+
circle(d = 6);
|
|
22
|
+
}
|
|
23
|
+
engrave() difference() { circle(d = size - 16); circle(d = size - 22); }
|
|
24
|
+
score() circle(d = size - 6);
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
## Lexical structure
|
|
28
|
+
|
|
29
|
+
- Comments: `// line` and `/* block */`.
|
|
30
|
+
- Numbers: `12`, `0.5`, `.5`, `1e3`.
|
|
31
|
+
- Strings: `"text"` with `\n`, `\t`, `\"`, `\\` and `\uXXXX` escapes.
|
|
32
|
+
- Names: letters, digits and `_`, not starting with a digit. Names starting
|
|
33
|
+
with `$` are **special variables** (see Scope).
|
|
34
|
+
- Keywords: `module function if else for let each use include true false undef`.
|
|
35
|
+
|
|
36
|
+
## Values
|
|
37
|
+
|
|
38
|
+
| Type | Examples |
|
|
39
|
+
| -------- | ------------------------------------------------------------ |
|
|
40
|
+
| number | `3`, `-0.25`, `PI` |
|
|
41
|
+
| string | `"Oak"` |
|
|
42
|
+
| boolean | `true`, `false` |
|
|
43
|
+
| undef | `undef`, a missing argument, an index past the end of a list |
|
|
44
|
+
| list | `[1, 2]`, `[[0, 0], [10, 0], [5, 8]]` |
|
|
45
|
+
| range | `[0:5]` (0 to 5 step 1), `[0:2:10]` (0 to 10 step 2) |
|
|
46
|
+
| function | `function(x) x * 2` |
|
|
47
|
+
|
|
48
|
+
Points are lists `[x, y]`. `p.x` and `p.y` read the first two items.
|
|
49
|
+
|
|
50
|
+
## Expressions
|
|
51
|
+
|
|
52
|
+
From lowest to highest precedence:
|
|
53
|
+
|
|
54
|
+
| Operator | Meaning |
|
|
55
|
+
| ------------------- | -------------------------------------------------------------------------------------------------------------- |
|
|
56
|
+
| `c ? a : b` | conditional |
|
|
57
|
+
| `\|\|` | or |
|
|
58
|
+
| `&&` | and |
|
|
59
|
+
| `==` `!=` | equality, lists compare item by item |
|
|
60
|
+
| `<` `<=` `>` `>=` | compare numbers or strings |
|
|
61
|
+
| `+` `-` | add or subtract numbers or equal length lists; `+` joins strings |
|
|
62
|
+
| `*` `/` `%` | multiply, divide, remainder; list times number scales; list times list is the dot product; matrix times vector |
|
|
63
|
+
| `-x` `!x` | negate, not |
|
|
64
|
+
| `a ^ b` | power, right associative and tighter than unary minus |
|
|
65
|
+
| `f(x)` `a[i]` `a.x` | call, index, member |
|
|
66
|
+
|
|
67
|
+
Mixing types an operator can't handle (a list plus a number, `undef + 1`)
|
|
68
|
+
stops the program with an error naming the line. Truthiness: `false`, `0`,
|
|
69
|
+
`""`, `[]` and `undef` are false.
|
|
70
|
+
|
|
71
|
+
`let (a = 1, b = a + 1) expr` binds names for one expression.
|
|
72
|
+
|
|
73
|
+
### List comprehensions
|
|
74
|
+
|
|
75
|
+
```kerf
|
|
76
|
+
squares = [for (i = [1:5]) i * i];
|
|
77
|
+
odd = [for (i = [1:9]) if (i % 2) i];
|
|
78
|
+
grid = [for (x = [0:2], y = [0:2]) [x * 10, y * 10]];
|
|
79
|
+
flat = [each [1, 2], 3];
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
## Statements
|
|
83
|
+
|
|
84
|
+
```kerf
|
|
85
|
+
name = expr; // assignment
|
|
86
|
+
function name(a, b = 2) = expr; // function
|
|
87
|
+
module name(a, b = 2) { ... } // module (makes shapes)
|
|
88
|
+
name(args) child; // module call with one child
|
|
89
|
+
name(args) { child; child; } // module call with a block of children
|
|
90
|
+
for (i = range_or_list, j = ...) ... // repeats, combined as a union
|
|
91
|
+
if (cond) ... else ...
|
|
92
|
+
let (a = 1) ...
|
|
93
|
+
use <path> // import modules and functions
|
|
94
|
+
include <path> // run another file in place
|
|
95
|
+
```
|
|
96
|
+
|
|
97
|
+
Arguments can be positional or named: `rect([20, 10], r = 2)`.
|
|
98
|
+
|
|
99
|
+
### Scope
|
|
100
|
+
|
|
101
|
+
- Assignments run **in order**. A later assignment to the same name replaces
|
|
102
|
+
the earlier one from that point on.
|
|
103
|
+
- `module` and `function` definitions are visible in their whole block, so you
|
|
104
|
+
can call them before they are defined.
|
|
105
|
+
- Blocks, loops and module bodies have their own scope.
|
|
106
|
+
- **Special variables** (`$name`) are dynamically scoped: a value set by a
|
|
107
|
+
caller is seen by everything it calls. Pass them as arguments too:
|
|
108
|
+
`circle(5, $fn = 6)`.
|
|
109
|
+
- Top-level assignments are the program's **parameters**. Renderers override
|
|
110
|
+
them by name (`kerf render -D width=200`).
|
|
111
|
+
|
|
112
|
+
### Modifiers
|
|
113
|
+
|
|
114
|
+
Put before a module call: `*` disables it, `#` and `%` move it to the guide
|
|
115
|
+
layer so you can see it without cutting it.
|
|
116
|
+
|
|
117
|
+
### children()
|
|
118
|
+
|
|
119
|
+
Inside a module, `children()` renders the statements the module was called
|
|
120
|
+
with, `children(i)` renders only the i-th one, and `$children` is their count.
|
|
121
|
+
|
|
122
|
+
```kerf
|
|
123
|
+
module hang_hole(d = 5) {
|
|
124
|
+
difference() { children(); translate([0, -d * 1.5]) circle(d = d); }
|
|
125
|
+
}
|
|
126
|
+
```
|
|
127
|
+
|
|
128
|
+
## Special variables
|
|
129
|
+
|
|
130
|
+
| Name | Default | Meaning |
|
|
131
|
+
| ----------------- | ------------- | -------------------------------------------------------------------------- |
|
|
132
|
+
| `$thickness` | `3` | material thickness, used by joinery and stored on parts |
|
|
133
|
+
| `$kerf` | `0` | beam width; cut outlines are offset by half of it |
|
|
134
|
+
| `$material` | `"material"` | material name; parts are packed per material and thickness |
|
|
135
|
+
| `$sheet` | `[600, 400]` | sheet size for packing |
|
|
136
|
+
| `$gap` | `3` | space between packed parts and around the sheet edge |
|
|
137
|
+
| `$layout` | `"pack"` | `"pack"` packs parts onto sheets, `"none"` keeps your placement |
|
|
138
|
+
| `$fn` `$fa` `$fs` | `0` `2` `0.2` | curve resolution: fixed segment count, or max angle and max segment length |
|
|
139
|
+
| `$font` | | default font name for `text()` |
|
|
140
|
+
|
|
141
|
+
## Layers
|
|
142
|
+
|
|
143
|
+
Every shape is on a layer. Shapes not wrapped in a layer module are on `cut`.
|
|
144
|
+
|
|
145
|
+
| Layer | Mode | Colour | What happens |
|
|
146
|
+
| --------- | ----- | --------- | ---------------------------------------------------- |
|
|
147
|
+
| `engrave` | fill | `#000000` | the area is engraved |
|
|
148
|
+
| `score` | line | `#0000ff` | lines and shape outlines are marked, not cut through |
|
|
149
|
+
| `cut` | cut | `#ff0000` | outlines are cut through, with kerf compensation |
|
|
150
|
+
| `guide` | guide | `#00a0ff` | shown only when guides are requested |
|
|
151
|
+
|
|
152
|
+
```kerf
|
|
153
|
+
cut() ... engrave() ... score() ... guide() ...
|
|
154
|
+
layer("pocket", mode = "fill", color = "#00aa00") ...
|
|
155
|
+
```
|
|
156
|
+
|
|
157
|
+
`layer(name, mode, color)` defines a layer. Modes are `"cut"`, `"line"`,
|
|
158
|
+
`"fill"` and `"guide"`. Output lists layers as engrave, custom layers, score,
|
|
159
|
+
cut, guide, so machines engrave before cutting.
|
|
160
|
+
|
|
161
|
+
Rules applied when a part is finished:
|
|
162
|
+
|
|
163
|
+
- The part's **material** is the union of its cut layer shapes.
|
|
164
|
+
- Engrave, score and custom layers are clipped to the material, so nothing is
|
|
165
|
+
marked inside holes or off the part. Score outlines become lines first.
|
|
166
|
+
- Cut lines (from `line()`, `living_hinge()` and similar) are clipped to the
|
|
167
|
+
material.
|
|
168
|
+
- If the material breaks into more than one piece, the renderer warns.
|
|
169
|
+
- In the output, holes and inner cuts come before outer outlines.
|
|
170
|
+
|
|
171
|
+
## Parts and sheets
|
|
172
|
+
|
|
173
|
+
```kerf
|
|
174
|
+
material(thickness = 4, kerf = 0.12, name = "birch") {
|
|
175
|
+
part("side", qty = 2) finger_rect([100, 60], "out");
|
|
176
|
+
part("base") rect([100, 100]);
|
|
177
|
+
}
|
|
178
|
+
```
|
|
179
|
+
|
|
180
|
+
- `part(name, qty = 1) { ... }` makes a named part. It records `$thickness`,
|
|
181
|
+
`$kerf` and `$material` where it is called.
|
|
182
|
+
- Shapes outside any part form one part named `part`.
|
|
183
|
+
- `material(thickness, kerf, name) { ... }` sets those special variables for
|
|
184
|
+
its children.
|
|
185
|
+
- With `$layout = "pack"` parts are grouped by material and thickness, copied
|
|
186
|
+
`qty` times, rotated 90° if that makes them fit, and shelf-packed onto
|
|
187
|
+
sheets of `$sheet`. Parts larger than the sheet are reported.
|
|
188
|
+
|
|
189
|
+
## Built-in modules
|
|
190
|
+
|
|
191
|
+
### Shapes
|
|
192
|
+
|
|
193
|
+
| Module | Notes |
|
|
194
|
+
| ---------------------------------------------------------- | ---------------------------------------------------------------------------- |
|
|
195
|
+
| `rect(size, center = false, r = 0)` | `size` is a number or `[w, h]`; `r` rounds the corners. `square` is an alias |
|
|
196
|
+
| `circle(r)` or `circle(d = ...)` | |
|
|
197
|
+
| `ellipse([rx, ry])` | |
|
|
198
|
+
| `regular_polygon(n, r)` | corner radius `r` |
|
|
199
|
+
| `star(n, r, inner)` | |
|
|
200
|
+
| `polygon(points, paths)` | even-odd fill, `paths` lists point indexes per outline |
|
|
201
|
+
| `path(d, fill = "evenodd")` | SVG path data; closed subpaths become shapes, open ones lines |
|
|
202
|
+
| `text(text, size = 10, font, halign, valign, spacing = 1)` | `halign`: left, center, right; `valign`: baseline, top, center, bottom |
|
|
203
|
+
| `line(from, to)` | a line, not an area |
|
|
204
|
+
| `polyline(points, closed = false)` | |
|
|
205
|
+
| `arc(r, start = 0, end = 90)` | arc line, angles in degrees |
|
|
206
|
+
|
|
207
|
+
### Transforms
|
|
208
|
+
|
|
209
|
+
`translate([x, y])`, `rotate(a, center = [x, y])`, `scale(s)` or
|
|
210
|
+
`scale([sx, sy])`, `mirror([nx, ny])` (mirror across the line through the
|
|
211
|
+
origin with that normal), `multmatrix(m)` with a 2x3 matrix.
|
|
212
|
+
|
|
213
|
+
### Combining
|
|
214
|
+
|
|
215
|
+
| Module | Notes |
|
|
216
|
+
| ---------------------------------------------- | -------------------------------------------------------------------------- |
|
|
217
|
+
| `union()` / `group()` | joins children |
|
|
218
|
+
| `difference()` | removes every later child's area from every layer of the first child |
|
|
219
|
+
| `intersection()` | keeps only the area common to all children, layers of the first child kept |
|
|
220
|
+
| `hull()` | convex hull |
|
|
221
|
+
| `offset(r)` / `offset(delta, chamfer = false)` | grow (positive) or shrink areas; `r` rounds corners |
|
|
222
|
+
| `stroke(width)` | turns lines into areas of that width, for cutting single line art |
|
|
223
|
+
| `outline()` | turns areas into their outline lines |
|
|
224
|
+
|
|
225
|
+
### Joinery
|
|
226
|
+
|
|
227
|
+
| Module | Notes |
|
|
228
|
+
| ---------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
229
|
+
| `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 |
|
|
230
|
+
| `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) |
|
|
231
|
+
| `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 |
|
|
232
|
+
| `living_hinge(size, spacing = 1.5, bridge = 3, cut)` | straight-line flex pattern as cut lines filling `[w, h]` |
|
|
233
|
+
|
|
234
|
+
### Other
|
|
235
|
+
|
|
236
|
+
`echo(...)` prints values, `assert(cond, message)` stops with the message when
|
|
237
|
+
`cond` is false, `children(i)`.
|
|
238
|
+
|
|
239
|
+
## Built-in functions
|
|
240
|
+
|
|
241
|
+
Math (degrees): `abs sign floor ceil round sqrt pow exp ln log sin cos tan
|
|
242
|
+
asin acos atan atan2 min max clamp lerp norm cross`.
|
|
243
|
+
|
|
244
|
+
Lists and strings: `len concat reverse sum slice str chr ord upper lower split
|
|
245
|
+
join search contains lookup`.
|
|
246
|
+
|
|
247
|
+
Types: `is_num is_string is_bool is_list is_undef is_function type_of`.
|
|
248
|
+
|
|
249
|
+
Random: `rands(min, max, count, seed)` is repeatable for the same seed.
|
|
250
|
+
|
|
251
|
+
Text: `text_width(text, size, font)` returns the advance width;
|
|
252
|
+
`text_metrics(text, size, font)` returns `[advance, [[x0, y0], [x1, y1]], ascent, descent]`.
|
|
253
|
+
|
|
254
|
+
Joinery: `finger_count(length, finger)` returns the finger count
|
|
255
|
+
`finger_rect` uses for that edge.
|
|
256
|
+
|
|
257
|
+
## Customizer comments
|
|
258
|
+
|
|
259
|
+
Top-level assignments with a plain value (number, string, boolean or list of
|
|
260
|
+
numbers) are listed as parameters by `kerf params` and by editors:
|
|
261
|
+
|
|
262
|
+
```kerf
|
|
263
|
+
/* [Size] */ // group for the following parameters
|
|
264
|
+
// Outer width <- caption: the comment line above
|
|
265
|
+
width = 120; // [40:5:400] min:step:max
|
|
266
|
+
depth = 80; // [200] max
|
|
267
|
+
shape = "round"; // [round:Round, square:Square] choices with labels
|
|
268
|
+
count = 3; // [2, 3, 4] choices
|
|
269
|
+
/* [Hidden] */ // not listed
|
|
270
|
+
```
|
|
271
|
+
|
|
272
|
+
The format matches OpenSCAD customizer comments, so existing editors can show
|
|
273
|
+
KerfScript parameters.
|
|
274
|
+
|
|
275
|
+
## Standard library
|
|
276
|
+
|
|
277
|
+
`use <kerf/box>`:
|
|
278
|
+
|
|
279
|
+
- `box([w, d, h], lid = false, finger)` makes the six (or five) panels of a
|
|
280
|
+
finger-jointed box as parts `bottom`, `lid`, `front`, `back`, `left`,
|
|
281
|
+
`right`. Sizes are outer sizes.
|
|
282
|
+
- `divider([w, h], finger)` makes a divider with finger tabs on both sides.
|
|
283
|
+
|
|
284
|
+
## Output
|
|
285
|
+
|
|
286
|
+
- **SVG**: millimetre units, one Inkscape layer group per KerfScript layer,
|
|
287
|
+
colours as above, 0.1 mm hairline strokes, `data-part` on every path.
|
|
288
|
+
- **DXF**: R12 (AC1009) polylines on layers named after KerfScript layers,
|
|
289
|
+
with matching AutoCAD colours.
|
|
290
|
+
|
|
291
|
+
## Limits
|
|
292
|
+
|
|
293
|
+
Renderers stop programs that recurse deeper than about a thousand calls, loop
|
|
294
|
+
over more than a million items, or run more than five million steps, with an
|
|
295
|
+
error instead of hanging.
|