@richardmcquiston01/more-open-scad 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 (45) hide show
  1. package/CHANGELOG.md +37 -0
  2. package/LICENSE +21 -0
  3. package/README.md +101 -0
  4. package/dist/csg/boolean.d.ts +22 -0
  5. package/dist/csg/boolean.d.ts.map +1 -0
  6. package/dist/csg/bsp-tree.d.ts +70 -0
  7. package/dist/csg/bsp-tree.d.ts.map +1 -0
  8. package/dist/csg/split-polygon.d.ts +62 -0
  9. package/dist/csg/split-polygon.d.ts.map +1 -0
  10. package/dist/geometry/plane.d.ts +31 -0
  11. package/dist/geometry/plane.d.ts.map +1 -0
  12. package/dist/geometry/polygon.d.ts +24 -0
  13. package/dist/geometry/polygon.d.ts.map +1 -0
  14. package/dist/geometry/solid.d.ts +41 -0
  15. package/dist/geometry/solid.d.ts.map +1 -0
  16. package/dist/geometry/triangulate.d.ts +16 -0
  17. package/dist/geometry/triangulate.d.ts.map +1 -0
  18. package/dist/geometry/vertex.d.ts +20 -0
  19. package/dist/geometry/vertex.d.ts.map +1 -0
  20. package/dist/index.d.ts +20 -0
  21. package/dist/index.d.ts.map +1 -0
  22. package/dist/index.js +1016 -0
  23. package/dist/io/manifold-check.d.ts +20 -0
  24. package/dist/io/manifold-check.d.ts.map +1 -0
  25. package/dist/io/stl-ascii.d.ts +14 -0
  26. package/dist/io/stl-ascii.d.ts.map +1 -0
  27. package/dist/io/stl-binary.d.ts +13 -0
  28. package/dist/io/stl-binary.d.ts.map +1 -0
  29. package/dist/io/triangulate-solid.d.ts +25 -0
  30. package/dist/io/triangulate-solid.d.ts.map +1 -0
  31. package/dist/math/epsilon.d.ts +10 -0
  32. package/dist/math/epsilon.d.ts.map +1 -0
  33. package/dist/math/mat4.d.ts +75 -0
  34. package/dist/math/mat4.d.ts.map +1 -0
  35. package/dist/math/vec3.d.ts +43 -0
  36. package/dist/math/vec3.d.ts.map +1 -0
  37. package/dist/primitives/cube.d.ts +21 -0
  38. package/dist/primitives/cube.d.ts.map +1 -0
  39. package/dist/primitives/cylinder.d.ts +32 -0
  40. package/dist/primitives/cylinder.d.ts.map +1 -0
  41. package/dist/primitives/polyhedron.d.ts +36 -0
  42. package/dist/primitives/polyhedron.d.ts.map +1 -0
  43. package/dist/primitives/sphere.d.ts +35 -0
  44. package/dist/primitives/sphere.d.ts.map +1 -0
  45. package/package.json +62 -0
package/CHANGELOG.md ADDED
@@ -0,0 +1,37 @@
1
+ # CHANGELOG
2
+
3
+ All notable changes to this project will be documented in this file.
4
+
5
+ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/).
6
+
7
+ ## [0.2.0] - 2026-09-23
8
+
9
+ The first version actually published to npm.
10
+
11
+ ### Added
12
+
13
+ - CSG plane/polygon splitting (`src/csg/split-polygon.ts`): `splitPolygon`, the geometric core of the BSP-tree boolean operations below. Classifies a polygon against a plane (coplanar/front/back/spanning) and clips spanning polygons into front/back pieces, preserving winding. Not part of the public API.
14
+ - CSG BSP tree (`src/csg/bsp-tree.ts`): the classic Naylor/Thibault BSP-CSG tree (as popularized by csg.js), built on `splitPolygon` and adapted to this codebase's immutable conventions — `build`, `clipPolygons`, `clipTo`, `invert`, and `allPolygons` all return new trees rather than mutating one. Not part of the public API; `src/csg/boolean.ts` is the only consumer.
15
+ - CSG boolean operations: `union`, `difference`, and `intersect`, matching OpenSCAD's `union()`/`difference()`/`intersection()`. Each takes two `Solid`s and returns a new one; chain calls to combine more than two (`union(union(a, b), c)`).
16
+ - A tag-triggered npm publish workflow (`.github/workflows/publish.yml`): pushing a `v*.*.*` tag on `main` re-verifies typecheck/lint/test/build, then publishes.
17
+ - The standard "Buy Me a Coffee" donate section in the README.
18
+
19
+ ## [0.1.0] - 2026-07-24
20
+
21
+ Primitives, transforms, and STL export. Never published to npm — superseded by 0.2.0 before a release was cut.
22
+
23
+ ### Added
24
+
25
+ - Primitives: `cube`, `sphere`, `cylinder`, and `polyhedron` (the arbitrary-mesh escape hatch), matching OpenSCAD's semantics — see each function's docs for its options.
26
+ - Chainable transforms on `Solid`: `translate`, `rotate` (Euler angles), `rotateAxisAngle`, `scale` (uniform or per-axis), `mirror`, and `multmatrix` (arbitrary 4x4 transform). Normals transform correctly under non-uniform scale, and winding is automatically corrected for any handedness-flipping transform (e.g. `mirror`).
27
+ - STL export: `toBinarySTL` and `toASCIISTL`, plus `isManifold` for checking a solid is watertight before exporting, and `triangulateSolid` for consumers who want raw per-facet triangle data directly (e.g. to feed a WebGL renderer).
28
+ - The full `Vec3`/`Mat4` math toolkit and the underlying `Vertex`/`Polygon`/`Plane`/`Solid` geometry types, for consumers who want to inspect or hand-build geometry beyond what the primitives above cover.
29
+ - Project scaffolding: TypeScript build/typecheck/lint/test pipeline (`bun`-based) and GitHub Actions CI.
30
+
31
+ ### Fixed
32
+
33
+ - Removed `"sideEffects": false` from `package.json` — it was causing `bun build` to silently tree-shake away the entire bundled implementation behind the public barrel export (`src/index.ts`), shipping an empty package. Caught before publishing via an end-to-end smoke test against the actual built `dist/index.js`.
34
+
35
+ ### Changed
36
+
37
+ - Pinned `prettier` to the exact installed version (`3.9.6`, was `^3.4.2`) so `bun run format` no longer produces unrelated diffs from version drift.
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Richard McQuiston
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,101 @@
1
+ # MoreOpenSCAD
2
+
3
+ ## Overview
4
+
5
+ Framework agnostic TypeScript based package for generating STL files using commands similar to OpenSCAD. Distributable via NPM for inclusion in TypeScript projects.
6
+
7
+ ## Prerequisites
8
+
9
+ - [Node.js](https://nodejs.org/) 18+ or [Bun](https://bun.sh/) 1.0+
10
+ - TypeScript 5+ (for consuming projects that want type checking)
11
+
12
+ ## Installation
13
+
14
+ ```sh
15
+ bun add @richardmcquiston01/more-open-scad
16
+ # or
17
+ npm install @richardmcquiston01/more-open-scad
18
+ ```
19
+
20
+ ## Usage
21
+
22
+ Build a shape with a primitive, chain transforms onto it, then export it to STL.
23
+
24
+ ```ts
25
+ import { cube, Vec3, toBinarySTL } from '@richardmcquiston01/more-open-scad';
26
+
27
+ const shape = cube(20, { center: true })
28
+ .translate(Vec3.vec3(0, 0, 10))
29
+ .rotateAxisAngle(Vec3.vec3(0, 0, 1), Math.PI / 4);
30
+
31
+ const stl = toBinarySTL(shape); // Uint8Array
32
+ ```
33
+
34
+ ### Primitives
35
+
36
+ `cube(size, options?)`, `sphere(r, options?)`, `cylinder(h, options?)`, and `polyhedron(points, faces)` (the arbitrary-mesh escape hatch) each build a `Solid`, matching OpenSCAD's semantics for the same primitive. See each function's JSDoc for its options (`center`, `fn`, `r`/`r1`/`r2`, etc.).
37
+
38
+ ### Transforms
39
+
40
+ Every `Solid` has chainable, immutable transform methods: `translate`, `rotate` (Euler angles), `rotateAxisAngle`, `scale` (uniform or per-axis), `mirror`, and `multmatrix` (an arbitrary 4x4 transform, for anything the named methods don't cover). Each call returns a new `Solid` — none of them mutate the original.
41
+
42
+ ### Boolean operations
43
+
44
+ `union(a, b)`, `difference(a, b)`, and `intersect(a, b)` combine two solids into a new one, matching OpenSCAD's `union()`/`difference()`/`intersection()`:
45
+
46
+ ```ts
47
+ import { cube, difference, Vec3 } from '@richardmcquiston01/more-open-scad';
48
+
49
+ const block = cube(20, { center: true });
50
+ const hole = cube(8, { center: true }).translate(Vec3.vec3(0, 0, 6));
51
+
52
+ const blockWithHole = difference(block, hole);
53
+ ```
54
+
55
+ Neither input `Solid` is mutated; each call returns a new one. Combine more than two solids by chaining calls, e.g. `union(union(a, b), c)`.
56
+
57
+ ### Exporting to STL
58
+
59
+ `toBinarySTL(solid)` returns a `Uint8Array` (the binary STL format); `toASCIISTL(solid, name?)` returns a `string` (the ASCII STL format). Neither writes to disk — this package stays framework-agnostic by handing back bytes/text and leaving file I/O to you:
60
+
61
+ **Node.js:**
62
+
63
+ ```ts
64
+ import { writeFileSync } from 'node:fs';
65
+ import { cube, toBinarySTL } from '@richardmcquiston01/more-open-scad';
66
+
67
+ writeFileSync('cube.stl', toBinarySTL(cube(20, { center: true })));
68
+ ```
69
+
70
+ **Browser (trigger a download):**
71
+
72
+ ```ts
73
+ import { cube, toBinarySTL } from '@richardmcquiston01/more-open-scad';
74
+
75
+ const stl = toBinarySTL(cube(20, { center: true }));
76
+ const url = URL.createObjectURL(new Blob([stl], { type: 'model/stl' }));
77
+
78
+ const link = document.createElement('a');
79
+ link.href = url;
80
+ link.download = 'cube.stl';
81
+ link.click();
82
+ URL.revokeObjectURL(url);
83
+ ```
84
+
85
+ Before exporting, `isManifold(solid)` checks whether a `Solid` is watertight (every edge shared by exactly two triangles wound in opposite directions) — useful as a sanity check that geometry is 3D-print-ready.
86
+
87
+ ## License
88
+
89
+ [MIT](LICENSE)
90
+
91
+ ## Copyright
92
+
93
+ (c) 2026 Richard McQuiston.
94
+
95
+ ## Buy Me a Coffee
96
+
97
+ If this app, code, or repository has helped you or someone you know, please consider donating. I appreciate any help to offset the costs of development and/or AI Credits.
98
+
99
+ [**Donate via Stripe**](https://donate.stripe.com/00w5kD3Gj1Xo9v7gVOcs800), or scan:
100
+
101
+ [![Donate via Stripe](./donate.svg)](https://donate.stripe.com/00w5kD3Gj1Xo9v7gVOcs800)
@@ -0,0 +1,22 @@
1
+ import { Solid } from '../geometry/solid';
2
+ /**
3
+ * The three boolean operations below are the classic BSP-CSG algorithm
4
+ * (Naylor/Thibault, as popularized by csg.js), expressed with this
5
+ * codebase's immutable `Bsp` functions in place of the original's
6
+ * in-place `Node` mutations. Each op builds a tree per input solid, uses
7
+ * `clipTo`/`invert` to cut away the region that should not survive, then
8
+ * merges what's left of one tree into the other with `build` and reads
9
+ * the result back out with `allPolygons`.
10
+ *
11
+ * `difference`/`intersect` reduce to the same shape as `union` by
12
+ * inverting one or both solids first — inside-out, "the part of A not in
13
+ * B" is "the union of (inside-out A) and B, inside-out" — which is why
14
+ * every op ends by inverting back if it inverted going in.
15
+ */
16
+ /** The union of `a` and `b`: every point inside either solid. */
17
+ export declare function union(a: Solid, b: Solid): Solid;
18
+ /** `a` with the part it shares with `b` removed. */
19
+ export declare function difference(a: Solid, b: Solid): Solid;
20
+ /** The intersection of `a` and `b`: only the region inside both solids. */
21
+ export declare function intersect(a: Solid, b: Solid): Solid;
22
+ //# sourceMappingURL=boolean.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"boolean.d.ts","sourceRoot":"","sources":["../../src/csg/boolean.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,EAAE,MAAM,mBAAmB,CAAC;AAI1C;;;;;;;;;;;;;GAaG;AAEH,iEAAiE;AACjE,wBAAgB,KAAK,CAAC,CAAC,EAAE,KAAK,EAAE,CAAC,EAAE,KAAK,GAAG,KAAK,CAY/C;AAED,oDAAoD;AACpD,wBAAgB,UAAU,CAAC,CAAC,EAAE,KAAK,EAAE,CAAC,EAAE,KAAK,GAAG,KAAK,CAcpD;AAED,2EAA2E;AAC3E,wBAAgB,SAAS,CAAC,CAAC,EAAE,KAAK,EAAE,CAAC,EAAE,KAAK,GAAG,KAAK,CAanD"}
@@ -0,0 +1,70 @@
1
+ import type { Plane as PlaneType } from '../geometry/plane';
2
+ import type { Polygon as PolygonType } from '../geometry/polygon';
3
+ /**
4
+ * A node in a BSP (binary space partitioning) tree, à la the classic
5
+ * BSP-CSG algorithm (Naylor/Thibault, as popularized by csg.js), adapted
6
+ * to this codebase's immutable value-type conventions: every function
7
+ * below returns a new tree rather than mutating an existing one.
8
+ *
9
+ * `polygons` holds every polygon found to be exactly coplanar with `plane`
10
+ * while building the tree — both those facing the same direction as
11
+ * `plane.normal` and those facing the opposite way (the classic algorithm
12
+ * keeps both in one list; nothing downstream needs them told apart).
13
+ * Everything else lives in `front`/`back`, which partition the remaining
14
+ * space on either side of `plane`. `null` (used for `front`/`back`, and as
15
+ * the whole-tree result of building from zero polygons) represents an
16
+ * empty subtree — "no polygons, no constraint on this side of the plane".
17
+ */
18
+ export interface BspNode {
19
+ readonly plane: PlaneType;
20
+ readonly polygons: readonly PolygonType[];
21
+ readonly front: BspNode | null;
22
+ readonly back: BspNode | null;
23
+ }
24
+ /**
25
+ * Builds a BSP tree from `polygons`, optionally inserting them into an
26
+ * already-built `node` instead of starting fresh (the classic algorithm's
27
+ * `Node.build` serves both roles too: the first call establishes each
28
+ * node's splitting plane from its first polygon, and later calls partition
29
+ * new polygons through the existing planes, recursing into — or lazily
30
+ * creating — the `front`/`back` subtrees as needed).
31
+ *
32
+ * The splitting plane for a fresh node is `polygons[0]`'s own plane, so
33
+ * that polygon always lands in the returned node's `polygons` (as a
34
+ * `coplanarFront`, since a plane never disagrees with itself) rather than
35
+ * being recursed into a subtree.
36
+ */
37
+ export declare function build(polygons: readonly PolygonType[], node?: BspNode | null): BspNode | null;
38
+ /**
39
+ * Clips `polygons` against the solid volume `node` represents: every part
40
+ * of every polygon that lies in front of `node`'s planes survives (kept
41
+ * whole where possible, split where a polygon straddles a plane), and
42
+ * every part behind all of them — i.e. inside the volume — is discarded.
43
+ * A `null` node clips nothing away (there is no volume to be in front of),
44
+ * so every polygon survives unchanged.
45
+ *
46
+ * A polygon exactly coplanar with a node's plane is treated as `front` or
47
+ * `back` according to which way it's coplanar (matching `splitPolygon`'s
48
+ * `coplanarFront`/`coplanarBack` split), rather than being kept at that
49
+ * node the way `build` does — clipping only ever keeps or discards, it
50
+ * never needs to *store* a polygon at a particular node.
51
+ */
52
+ export declare function clipPolygons(node: BspNode | null, polygons: readonly PolygonType[]): PolygonType[];
53
+ /**
54
+ * Clips every polygon stored in `node` (at every level of the tree)
55
+ * against the solid volume `other` represents, returning the resulting
56
+ * tree. Used to remove the part of one solid that lies inside another,
57
+ * without discarding `node`'s own plane structure.
58
+ */
59
+ export declare function clipTo(node: BspNode | null, other: BspNode | null): BspNode | null;
60
+ /**
61
+ * Turns `node`'s solid inside-out: every plane and polygon is flipped
62
+ * (`Plane.flip`/`Polygon.flip`), and `front`/`back` are swapped, so the
63
+ * region the tree used to consider "inside" is now "outside" and vice
64
+ * versa. Boolean ops use this to re-express subtraction/intersection in
65
+ * terms of union (see `../csg/boolean.ts`).
66
+ */
67
+ export declare function invert(node: BspNode | null): BspNode | null;
68
+ /** Collects every polygon stored anywhere in `node`'s tree. */
69
+ export declare function allPolygons(node: BspNode | null): PolygonType[];
70
+ //# sourceMappingURL=bsp-tree.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"bsp-tree.d.ts","sourceRoot":"","sources":["../../src/csg/bsp-tree.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,KAAK,IAAI,SAAS,EAAE,MAAM,mBAAmB,CAAC;AAE5D,OAAO,KAAK,EAAE,OAAO,IAAI,WAAW,EAAE,MAAM,qBAAqB,CAAC;AAGlE;;;;;;;;;;;;;;GAcG;AACH,MAAM,WAAW,OAAO;IACtB,QAAQ,CAAC,KAAK,EAAE,SAAS,CAAC;IAC1B,QAAQ,CAAC,QAAQ,EAAE,SAAS,WAAW,EAAE,CAAC;IAC1C,QAAQ,CAAC,KAAK,EAAE,OAAO,GAAG,IAAI,CAAC;IAC/B,QAAQ,CAAC,IAAI,EAAE,OAAO,GAAG,IAAI,CAAC;CAC/B;AAED;;;;;;;;;;;;GAYG;AACH,wBAAgB,KAAK,CACnB,QAAQ,EAAE,SAAS,WAAW,EAAE,EAChC,IAAI,GAAE,OAAO,GAAG,IAAW,GAC1B,OAAO,GAAG,IAAI,CAqBhB;AAED;;;;;;;;;;;;;GAaG;AACH,wBAAgB,YAAY,CAC1B,IAAI,EAAE,OAAO,GAAG,IAAI,EACpB,QAAQ,EAAE,SAAS,WAAW,EAAE,GAC/B,WAAW,EAAE,CAiBf;AAED;;;;;GAKG;AACH,wBAAgB,MAAM,CACpB,IAAI,EAAE,OAAO,GAAG,IAAI,EACpB,KAAK,EAAE,OAAO,GAAG,IAAI,GACpB,OAAO,GAAG,IAAI,CAQhB;AAED;;;;;;GAMG;AACH,wBAAgB,MAAM,CAAC,IAAI,EAAE,OAAO,GAAG,IAAI,GAAG,OAAO,GAAG,IAAI,CAQ3D;AAED,+DAA+D;AAC/D,wBAAgB,WAAW,CAAC,IAAI,EAAE,OAAO,GAAG,IAAI,GAAG,WAAW,EAAE,CAO/D"}
@@ -0,0 +1,62 @@
1
+ import type { Plane as PlaneType } from '../geometry/plane';
2
+ import type { Polygon as PolygonType } from '../geometry/polygon';
3
+ /** Exactly on the plane, within `EPSILON`. */
4
+ export declare const COPLANAR = 0;
5
+ /** Strictly on the side the plane's normal points toward. */
6
+ export declare const FRONT = 1;
7
+ /** Strictly on the opposite side from the plane's normal. */
8
+ export declare const BACK = 2;
9
+ /** Both `Front` and `Back` — the polygon crosses the plane. */
10
+ export declare const SPANNING = 3;
11
+ /**
12
+ * How a vertex (or, bitwise-OR'd together, a whole polygon) sits relative
13
+ * to a splitting plane. `Spanning` is `Front | Back`: a polygon spans the
14
+ * plane exactly when it has at least one strictly-front and one
15
+ * strictly-back vertex.
16
+ */
17
+ export type Classification = typeof COPLANAR | typeof FRONT | typeof BACK | typeof SPANNING;
18
+ /**
19
+ * The result of splitting one polygon against one plane. A polygon lands
20
+ * in exactly one of the four buckets, except a `Spanning` polygon, which
21
+ * contributes one clipped piece to both `front` and `back` (or is dropped
22
+ * from a side entirely if clipping leaves fewer than 3 vertices on that
23
+ * side — see `splitPolygon`). Every field is an array purely for uniform,
24
+ * concatenation-friendly call sites (the BSP tree in later stages will
25
+ * accumulate many of these); for this library's always-convex `Polygon`,
26
+ * each field holds at most one polygon per call.
27
+ */
28
+ export interface SplitResult {
29
+ /** Coplanar with the plane, facing the same direction as its normal. */
30
+ readonly coplanarFront: readonly PolygonType[];
31
+ /** Coplanar with the plane, facing the opposite direction. */
32
+ readonly coplanarBack: readonly PolygonType[];
33
+ /** Strictly in front of the plane (or the front piece of a split). */
34
+ readonly front: readonly PolygonType[];
35
+ /** Strictly behind the plane (or the back piece of a split). */
36
+ readonly back: readonly PolygonType[];
37
+ }
38
+ /**
39
+ * Classifies `polygon` against `plane` and splits it if it spans the
40
+ * plane, à la the classic BSP-CSG algorithm (Naylor/Thibault, as
41
+ * popularized by csg.js).
42
+ *
43
+ * Each vertex is classified `Front`/`Back`/`Coplanar` by its signed
44
+ * distance to the plane (within `EPSILON`); the polygon's overall
45
+ * classification is the bitwise OR of its vertices' classifications.
46
+ * `Coplanar` polygons are further split into `coplanarFront`/
47
+ * `coplanarBack` by comparing their own plane's normal to the splitting
48
+ * plane's normal. A `Spanning` polygon is walked edge by edge: each
49
+ * vertex joins the front chain (if not strictly `Back`), the back chain
50
+ * (if not strictly `Front`) — so a `Coplanar` vertex joins both, forming
51
+ * the shared boundary — and any edge that strictly crosses the plane
52
+ * contributes one new vertex, interpolated at the crossing point, to
53
+ * both chains. A resulting chain becomes an output polygon only if it
54
+ * has at least 3 vertices (matching `Polygon`'s minimum).
55
+ *
56
+ * Because interpolated points are affine combinations of two points on
57
+ * the source polygon's plane, they remain exactly on that same plane, so
58
+ * each output polygon's freshly-derived plane matches the source
59
+ * polygon's orientation.
60
+ */
61
+ export declare function splitPolygon(plane: PlaneType, polygon: PolygonType): SplitResult;
62
+ //# sourceMappingURL=split-polygon.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"split-polygon.d.ts","sourceRoot":"","sources":["../../src/csg/split-polygon.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,KAAK,IAAI,SAAS,EAAE,MAAM,mBAAmB,CAAC;AAE5D,OAAO,KAAK,EAAE,OAAO,IAAI,WAAW,EAAE,MAAM,qBAAqB,CAAC;AAIlE,8CAA8C;AAC9C,eAAO,MAAM,QAAQ,IAAI,CAAC;AAC1B,6DAA6D;AAC7D,eAAO,MAAM,KAAK,IAAI,CAAC;AACvB,6DAA6D;AAC7D,eAAO,MAAM,IAAI,IAAI,CAAC;AACtB,+DAA+D;AAC/D,eAAO,MAAM,QAAQ,IAAI,CAAC;AAE1B;;;;;GAKG;AACH,MAAM,MAAM,cAAc,GACtB,OAAO,QAAQ,GACf,OAAO,KAAK,GACZ,OAAO,IAAI,GACX,OAAO,QAAQ,CAAC;AAEpB;;;;;;;;;GASG;AACH,MAAM,WAAW,WAAW;IAC1B,wEAAwE;IACxE,QAAQ,CAAC,aAAa,EAAE,SAAS,WAAW,EAAE,CAAC;IAC/C,8DAA8D;IAC9D,QAAQ,CAAC,YAAY,EAAE,SAAS,WAAW,EAAE,CAAC;IAC9C,sEAAsE;IACtE,QAAQ,CAAC,KAAK,EAAE,SAAS,WAAW,EAAE,CAAC;IACvC,gEAAgE;IAChE,QAAQ,CAAC,IAAI,EAAE,SAAS,WAAW,EAAE,CAAC;CACvC;AASD;;;;;;;;;;;;;;;;;;;;;;GAsBG;AACH,wBAAgB,YAAY,CAAC,KAAK,EAAE,SAAS,EAAE,OAAO,EAAE,WAAW,GAAG,WAAW,CAyDhF"}
@@ -0,0 +1,31 @@
1
+ import type { Vec3 as Vec3Type } from '../math/vec3';
2
+ /**
3
+ * An infinite plane, represented in Hessian normal form: a unit `normal`
4
+ * and the offset `w` such that a point `p` lies on the plane when
5
+ * `dot(normal, p) === w`.
6
+ */
7
+ export interface Plane {
8
+ readonly normal: Vec3Type;
9
+ readonly w: number;
10
+ }
11
+ /**
12
+ * Builds the plane through `a`, `b`, `c`. The three points must be ordered
13
+ * counter-clockwise when viewed from the side the resulting normal points
14
+ * toward (right-hand rule) — this matches the outward-facing winding
15
+ * convention used by primitives and STL export.
16
+ *
17
+ * If `a`, `b`, `c` are collinear or coincident, the cross product degenerates
18
+ * to the zero vector; per `Vec3.normalize`, this yields a plane with a zero
19
+ * normal rather than throwing or producing `NaN`.
20
+ */
21
+ export declare function fromPoints(a: Vec3Type, b: Vec3Type, c: Vec3Type): Plane;
22
+ /**
23
+ * The signed distance from `point` to `plane`: positive on the side the
24
+ * normal points toward, negative on the opposite side, zero on the plane.
25
+ */
26
+ export declare function signedDistance(plane: Plane, point: Vec3Type): number;
27
+ /** The plane with its normal (and therefore orientation) reversed. */
28
+ export declare function flip(plane: Plane): Plane;
29
+ /** Whether `a` and `b` represent the same plane within `tolerance`. */
30
+ export declare function equals(a: Plane, b: Plane, tolerance?: number): boolean;
31
+ //# sourceMappingURL=plane.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"plane.d.ts","sourceRoot":"","sources":["../../src/geometry/plane.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,IAAI,IAAI,QAAQ,EAAE,MAAM,cAAc,CAAC;AAErD;;;;GAIG;AACH,MAAM,WAAW,KAAK;IACpB,QAAQ,CAAC,MAAM,EAAE,QAAQ,CAAC;IAC1B,QAAQ,CAAC,CAAC,EAAE,MAAM,CAAC;CACpB;AAED;;;;;;;;;GASG;AACH,wBAAgB,UAAU,CAAC,CAAC,EAAE,QAAQ,EAAE,CAAC,EAAE,QAAQ,EAAE,CAAC,EAAE,QAAQ,GAAG,KAAK,CAGvE;AAED;;;GAGG;AACH,wBAAgB,cAAc,CAAC,KAAK,EAAE,KAAK,EAAE,KAAK,EAAE,QAAQ,GAAG,MAAM,CAEpE;AAED,sEAAsE;AACtE,wBAAgB,IAAI,CAAC,KAAK,EAAE,KAAK,GAAG,KAAK,CAExC;AAED,uEAAuE;AACvE,wBAAgB,MAAM,CAAC,CAAC,EAAE,KAAK,EAAE,CAAC,EAAE,KAAK,EAAE,SAAS,SAAU,GAAG,OAAO,CAKvE"}
@@ -0,0 +1,24 @@
1
+ import type { Plane as PlaneType } from './plane';
2
+ import type { Vertex as VertexType } from './vertex';
3
+ /**
4
+ * A planar, convex polygon with an arbitrary number of vertices (3+),
5
+ * wound counter-clockwise when viewed from the side its plane's normal
6
+ * points toward. Polygons are kept as-is (not pre-triangulated) so they
7
+ * can be split cleanly by the future BSP-tree CSG engine; triangulation
8
+ * happens only at STL-export time via `triangulate`.
9
+ */
10
+ export interface Polygon {
11
+ readonly vertices: readonly VertexType[];
12
+ readonly plane: PlaneType;
13
+ }
14
+ /**
15
+ * Creates a `Polygon` from `vertices`, deriving its plane from the first
16
+ * three. Throws if fewer than 3 vertices are given.
17
+ */
18
+ export declare function polygon(vertices: readonly VertexType[]): Polygon;
19
+ /**
20
+ * The polygon with its winding order reversed and its plane/vertex
21
+ * normals flipped to match — turns an outward-facing polygon inside out.
22
+ */
23
+ export declare function flip(p: Polygon): Polygon;
24
+ //# sourceMappingURL=polygon.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"polygon.d.ts","sourceRoot":"","sources":["../../src/geometry/polygon.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,KAAK,IAAI,SAAS,EAAE,MAAM,SAAS,CAAC;AAElD,OAAO,KAAK,EAAE,MAAM,IAAI,UAAU,EAAE,MAAM,UAAU,CAAC;AAErD;;;;;;GAMG;AACH,MAAM,WAAW,OAAO;IACtB,QAAQ,CAAC,QAAQ,EAAE,SAAS,UAAU,EAAE,CAAC;IACzC,QAAQ,CAAC,KAAK,EAAE,SAAS,CAAC;CAC3B;AAED;;;GAGG;AACH,wBAAgB,OAAO,CAAC,QAAQ,EAAE,SAAS,UAAU,EAAE,GAAG,OAAO,CAQhE;AAED;;;GAGG;AACH,wBAAgB,IAAI,CAAC,CAAC,EAAE,OAAO,GAAG,OAAO,CAKxC"}
@@ -0,0 +1,41 @@
1
+ import type { Mat4 as Mat4Type } from '../math/mat4';
2
+ import type { Vec3 as Vec3Type } from '../math/vec3';
3
+ import type { Polygon as PolygonType } from './polygon';
4
+ /**
5
+ * A solid 3D shape: an immutable collection of polygons.
6
+ *
7
+ * `Solid` is the primary value type primitives (Stage 3) produce and
8
+ * transforms (Stage 4) operate on. Unlike the rest of the geometry kernel
9
+ * (which favors plain interfaces + free functions), `Solid` is a class so
10
+ * that transforms can be chained as instance methods, e.g.
11
+ * `cube(10).translate(vec3(5, 0, 0)).rotate(vec3(0, 0, Math.PI / 4))`.
12
+ * Every transform method returns a new `Solid`; none mutate `this`.
13
+ */
14
+ export declare class Solid {
15
+ readonly polygons: readonly PolygonType[];
16
+ constructor(polygons: readonly PolygonType[]);
17
+ /** Translates every point of the solid by `offset`. */
18
+ translate(offset: Vec3Type): Solid;
19
+ /**
20
+ * Rotates the solid by Euler angles (in radians), applied in OpenSCAD's
21
+ * order: first around X, then Y, then Z.
22
+ */
23
+ rotate(radians: Vec3Type): Solid;
24
+ /** Rotates the solid by `radians` around `axis` (right-hand rule). */
25
+ rotateAxisAngle(axis: Vec3Type, radians: number): Solid;
26
+ /**
27
+ * Scales the solid. A single `number` scales all three axes uniformly;
28
+ * a `Vec3` scales each axis independently. A negative or zero factor on
29
+ * an odd number of axes flips handedness/degenerates the shape — winding
30
+ * is corrected automatically for the flip case, per `applyMatrix`.
31
+ */
32
+ scale(factor: number | Vec3Type): Solid;
33
+ /**
34
+ * Reflects the solid across the plane through the origin with normal
35
+ * `normal` (need not be pre-normalized).
36
+ */
37
+ mirror(normal: Vec3Type): Solid;
38
+ /** Applies an arbitrary 4x4 transform matrix to the solid. */
39
+ multmatrix(matrix: Mat4Type): Solid;
40
+ }
41
+ //# sourceMappingURL=solid.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"solid.d.ts","sourceRoot":"","sources":["../../src/geometry/solid.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,IAAI,IAAI,QAAQ,EAAE,MAAM,cAAc,CAAC;AAErD,OAAO,KAAK,EAAE,IAAI,IAAI,QAAQ,EAAE,MAAM,cAAc,CAAC;AAErD,OAAO,KAAK,EAAE,OAAO,IAAI,WAAW,EAAE,MAAM,WAAW,CAAC;AA4CxD;;;;;;;;;GASG;AACH,qBAAa,KAAK;IAChB,QAAQ,CAAC,QAAQ,EAAE,SAAS,WAAW,EAAE,CAAC;gBAE9B,QAAQ,EAAE,SAAS,WAAW,EAAE;IAI5C,uDAAuD;IACvD,SAAS,CAAC,MAAM,EAAE,QAAQ,GAAG,KAAK;IAIlC;;;OAGG;IACH,MAAM,CAAC,OAAO,EAAE,QAAQ,GAAG,KAAK;IAIhC,sEAAsE;IACtE,eAAe,CAAC,IAAI,EAAE,QAAQ,EAAE,OAAO,EAAE,MAAM,GAAG,KAAK;IAIvD;;;;;OAKG;IACH,KAAK,CAAC,MAAM,EAAE,MAAM,GAAG,QAAQ,GAAG,KAAK;IAMvC;;;OAGG;IACH,MAAM,CAAC,MAAM,EAAE,QAAQ,GAAG,KAAK;IAI/B,8DAA8D;IAC9D,UAAU,CAAC,MAAM,EAAE,QAAQ,GAAG,KAAK;CAGpC"}
@@ -0,0 +1,16 @@
1
+ import type { Polygon } from './polygon';
2
+ import type { Vertex } from './vertex';
3
+ /** Three vertices forming a triangle, wound the same way as their source. */
4
+ export type Triangle = readonly [Vertex, Vertex, Vertex];
5
+ /**
6
+ * Fan-triangulates a convex `Polygon` into `n - 2` triangles (for an
7
+ * `n`-vertex polygon), all sharing the first vertex. Winding is preserved:
8
+ * each triangle keeps the same vertex order as the source polygon, so its
9
+ * implied normal matches the polygon's plane.
10
+ *
11
+ * Triangulation happens only at STL-export time — `Polygon`/`Solid` keep
12
+ * their original (non-triangulated) vertices so the future CSG engine can
13
+ * split them cleanly.
14
+ */
15
+ export declare function triangulate(polygon: Polygon): Triangle[];
16
+ //# sourceMappingURL=triangulate.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"triangulate.d.ts","sourceRoot":"","sources":["../../src/geometry/triangulate.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AACzC,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,UAAU,CAAC;AAEvC,6EAA6E;AAC7E,MAAM,MAAM,QAAQ,GAAG,SAAS,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,CAAC;AAEzD;;;;;;;;;GASG;AACH,wBAAgB,WAAW,CAAC,OAAO,EAAE,OAAO,GAAG,QAAQ,EAAE,CAQxD"}
@@ -0,0 +1,20 @@
1
+ import type { Vec3 as Vec3Type } from '../math/vec3';
2
+ /** A polygon vertex: a position plus its shading normal. */
3
+ export interface Vertex {
4
+ readonly pos: Vec3Type;
5
+ readonly normal: Vec3Type;
6
+ }
7
+ /** Creates a `Vertex` from a position and normal. */
8
+ export declare function vertex(pos: Vec3Type, normal: Vec3Type): Vertex;
9
+ /**
10
+ * Linearly interpolates from `a` to `b` by `t` (0 = `a`, 1 = `b`),
11
+ * interpolating both position and normal. The interpolated normal is
12
+ * re-normalized, since a linear blend of two unit vectors is not itself
13
+ * unit length in general.
14
+ */
15
+ export declare function lerp(a: Vertex, b: Vertex, t: number): Vertex;
16
+ /** The vertex with its normal reversed, position unchanged. */
17
+ export declare function flip(v: Vertex): Vertex;
18
+ /** Whether `a` and `b` are equal within `tolerance` on both fields. */
19
+ export declare function equals(a: Vertex, b: Vertex, tolerance?: number): boolean;
20
+ //# sourceMappingURL=vertex.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"vertex.d.ts","sourceRoot":"","sources":["../../src/geometry/vertex.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,IAAI,IAAI,QAAQ,EAAE,MAAM,cAAc,CAAC;AAErD,4DAA4D;AAC5D,MAAM,WAAW,MAAM;IACrB,QAAQ,CAAC,GAAG,EAAE,QAAQ,CAAC;IACvB,QAAQ,CAAC,MAAM,EAAE,QAAQ,CAAC;CAC3B;AAED,qDAAqD;AACrD,wBAAgB,MAAM,CAAC,GAAG,EAAE,QAAQ,EAAE,MAAM,EAAE,QAAQ,GAAG,MAAM,CAE9D;AAED;;;;;GAKG;AACH,wBAAgB,IAAI,CAAC,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,MAAM,GAAG,MAAM,CAK5D;AAED,+DAA+D;AAC/D,wBAAgB,IAAI,CAAC,CAAC,EAAE,MAAM,GAAG,MAAM,CAEtC;AAED,uEAAuE;AACvE,wBAAgB,MAAM,CAAC,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,MAAM,EAAE,SAAS,CAAC,EAAE,MAAM,GAAG,OAAO,CAKxE"}
@@ -0,0 +1,20 @@
1
+ export { cube } from './primitives/cube';
2
+ export type { CubeOptions } from './primitives/cube';
3
+ export { sphere } from './primitives/sphere';
4
+ export type { SphereOptions } from './primitives/sphere';
5
+ export { cylinder } from './primitives/cylinder';
6
+ export type { CylinderOptions } from './primitives/cylinder';
7
+ export { polyhedron } from './primitives/polyhedron';
8
+ export { Solid } from './geometry/solid';
9
+ export * as Vertex from './geometry/vertex';
10
+ export * as Polygon from './geometry/polygon';
11
+ export * as Plane from './geometry/plane';
12
+ export { union, difference, intersect } from './csg/boolean';
13
+ export * as Vec3 from './math/vec3';
14
+ export * as Mat4 from './math/mat4';
15
+ export { toBinarySTL } from './io/stl-binary';
16
+ export { toASCIISTL } from './io/stl-ascii';
17
+ export { isManifold } from './io/manifold-check';
18
+ export { triangulateSolid } from './io/triangulate-solid';
19
+ export type { StlTriangle } from './io/triangulate-solid';
20
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,IAAI,EAAE,MAAM,mBAAmB,CAAC;AACzC,YAAY,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AACrD,OAAO,EAAE,MAAM,EAAE,MAAM,qBAAqB,CAAC;AAC7C,YAAY,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC;AACzD,OAAO,EAAE,QAAQ,EAAE,MAAM,uBAAuB,CAAC;AACjD,YAAY,EAAE,eAAe,EAAE,MAAM,uBAAuB,CAAC;AAC7D,OAAO,EAAE,UAAU,EAAE,MAAM,yBAAyB,CAAC;AAKrD,OAAO,EAAE,KAAK,EAAE,MAAM,kBAAkB,CAAC;AACzC,OAAO,KAAK,MAAM,MAAM,mBAAmB,CAAC;AAC5C,OAAO,KAAK,OAAO,MAAM,oBAAoB,CAAC;AAC9C,OAAO,KAAK,KAAK,MAAM,kBAAkB,CAAC;AAI1C,OAAO,EAAE,KAAK,EAAE,UAAU,EAAE,SAAS,EAAE,MAAM,eAAe,CAAC;AAI7D,OAAO,KAAK,IAAI,MAAM,aAAa,CAAC;AACpC,OAAO,KAAK,IAAI,MAAM,aAAa,CAAC;AAGpC,OAAO,EAAE,WAAW,EAAE,MAAM,iBAAiB,CAAC;AAC9C,OAAO,EAAE,UAAU,EAAE,MAAM,gBAAgB,CAAC;AAC5C,OAAO,EAAE,UAAU,EAAE,MAAM,qBAAqB,CAAC;AACjD,OAAO,EAAE,gBAAgB,EAAE,MAAM,wBAAwB,CAAC;AAC1D,YAAY,EAAE,WAAW,EAAE,MAAM,wBAAwB,CAAC"}