@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.
Files changed (56) hide show
  1. package/CHANGELOG.md +42 -0
  2. package/CLA.md +73 -0
  3. package/COMMERCIAL-LICENSE.md +68 -0
  4. package/LANGUAGE.md +295 -0
  5. package/LICENSE +661 -0
  6. package/README.md +148 -2
  7. package/THIRD-PARTY-NOTICES.md +69 -0
  8. package/TRADEMARKS.md +39 -0
  9. package/dist/ast.d.cts +160 -0
  10. package/dist/ast.d.ts +160 -0
  11. package/dist/cli.d.cts +1 -0
  12. package/dist/cli.d.ts +1 -0
  13. package/dist/cli.js +19226 -0
  14. package/dist/customizer.d.cts +19 -0
  15. package/dist/customizer.d.ts +19 -0
  16. package/dist/evaluator.d.cts +106 -0
  17. package/dist/evaluator.d.ts +106 -0
  18. package/dist/export/dxf.d.cts +3 -0
  19. package/dist/export/dxf.d.ts +3 -0
  20. package/dist/export/svg.d.cts +13 -0
  21. package/dist/export/svg.d.ts +13 -0
  22. package/dist/functions.d.cts +4 -0
  23. package/dist/functions.d.ts +4 -0
  24. package/dist/geometry.d.cts +44 -0
  25. package/dist/geometry.d.ts +44 -0
  26. package/dist/index.cjs +44 -0
  27. package/dist/index.d.cts +10 -0
  28. package/dist/index.d.ts +10 -0
  29. package/dist/index.js +44 -0
  30. package/dist/joinery.d.cts +7 -0
  31. package/dist/joinery.d.ts +7 -0
  32. package/dist/lexer.d.cts +28 -0
  33. package/dist/lexer.d.ts +28 -0
  34. package/dist/parser.d.cts +6 -0
  35. package/dist/parser.d.ts +6 -0
  36. package/dist/paths.d.cts +28 -0
  37. package/dist/paths.d.ts +28 -0
  38. package/dist/render.d.cts +57 -0
  39. package/dist/render.d.ts +57 -0
  40. package/dist/stdlib.d.cts +1 -0
  41. package/dist/stdlib.d.ts +1 -0
  42. package/dist/text.d.cts +36 -0
  43. package/dist/text.d.ts +36 -0
  44. package/dist/values.d.cts +25 -0
  45. package/dist/values.d.ts +25 -0
  46. package/docs/cli.md +61 -0
  47. package/docs/compatibility.md +89 -0
  48. package/docs/customizer.md +62 -0
  49. package/docs/getting-started.md +98 -0
  50. package/docs/javascript.md +98 -0
  51. package/docs/kerf.md +70 -0
  52. package/docs/layers.md +74 -0
  53. package/docs/openscad.md +67 -0
  54. package/docs/parts-and-sheets.md +68 -0
  55. package/docs/versions.md +43 -0
  56. 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.