@code3d/core 0.0.1-alpha.0 → 0.0.1-alpha.10
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +43 -807
- package/THIRD_PARTY.md +40 -0
- package/bld/THIRD_PARTY_NOTICES.txt +182 -0
- package/bld/chunks/chunk-5IP37Z5U.js +30 -0
- package/bld/chunks/chunk-5IP37Z5U.js.map +7 -0
- package/bld/chunks/chunk-7FIFPADJ.js +1 -0
- package/bld/chunks/chunk-7FIFPADJ.js.map +7 -0
- package/bld/chunks/chunk-HBRLIGQN.js +31 -0
- package/bld/chunks/chunk-HBRLIGQN.js.map +7 -0
- package/bld/chunks/chunk-IJHQ57VL.js +19 -0
- package/bld/chunks/chunk-IJHQ57VL.js.map +7 -0
- package/bld/chunks/chunk-TTJOM4DJ.js +26458 -0
- package/bld/chunks/chunk-TTJOM4DJ.js.map +7 -0
- package/bld/library/bound-solver.d.ts +29 -5
- package/bld/library/bound-solver.d.ts.map +1 -1
- package/bld/library/cached.d.ts +35 -0
- package/bld/library/cached.d.ts.map +1 -0
- package/bld/library/font.d.ts +39 -0
- package/bld/library/font.d.ts.map +1 -0
- package/bld/library/google-font.d.ts +14 -0
- package/bld/library/google-font.d.ts.map +1 -0
- package/bld/library/index.d.ts +10 -2
- package/bld/library/index.d.ts.map +1 -1
- package/bld/library/index.js +94 -3
- package/bld/library/index.js.map +7 -1
- package/bld/library/inspect.d.ts +98 -0
- package/bld/library/inspect.d.ts.map +1 -0
- package/bld/library/kernel-artifact-codec.d.ts.map +1 -1
- package/bld/library/kernel-cache.d.ts +28 -7
- package/bld/library/kernel-cache.d.ts.map +1 -1
- package/bld/library/loft.d.ts.map +1 -1
- package/bld/library/material.d.ts +1 -1
- package/bld/library/material.d.ts.map +1 -1
- package/bld/library/open-cascade.d.ts +4 -0
- package/bld/library/open-cascade.d.ts.map +1 -0
- package/bld/library/relation-solver.d.ts +19 -8
- package/bld/library/relation-solver.d.ts.map +1 -1
- package/bld/library/replicad.d.ts +3 -2
- package/bld/library/replicad.d.ts.map +1 -1
- package/bld/library/replicad.js +10 -24
- package/bld/library/replicad.js.map +7 -1
- package/bld/library/retained-memory.d.ts.map +1 -1
- package/bld/library/runtime.d.ts +518 -155
- package/bld/library/runtime.d.ts.map +1 -1
- package/bld/library/sketch-solver.d.ts +1 -1
- package/bld/library/sketch-solver.d.ts.map +1 -1
- package/bld/library/sketch.d.ts +21 -1
- package/bld/library/sketch.d.ts.map +1 -1
- package/bld/library/text.d.ts +53 -0
- package/bld/library/text.d.ts.map +1 -0
- package/bld/library/three.js +3 -3
- package/bld/library/three.js.map +7 -1
- package/bld/library/topology.d.ts +6 -2
- package/bld/library/topology.d.ts.map +1 -1
- package/bld/node/index.d.ts.map +1 -1
- package/bld/node/index.js +96 -14
- package/bld/node/index.js.map +7 -1
- package/bld/node/replicad.js +13 -3
- package/bld/node/replicad.js.map +7 -1
- package/bld/tooling/index.d.ts +18 -15
- package/bld/tooling/index.d.ts.map +1 -1
- package/bld/tooling/index.js +165 -19
- package/bld/tooling/index.js.map +7 -1
- package/docs/api.md +764 -0
- package/docs/custom-primitives.mdx +58 -0
- package/docs/local-coordinates.md +187 -0
- package/docs/origins-and-rotation.mdx +105 -0
- package/docs/relations.mdx +450 -0
- package/docs/runtime.md +297 -0
- package/docs/shells.mdx +70 -0
- package/docs/sketches.md +83 -0
- package/docs/text.md +23 -0
- package/docs/topology.md +152 -0
- package/docs/values.md +119 -0
- package/package.json +20 -7
- package/src/library/bound-solver.ts +103 -73
- package/src/library/cached.ts +153 -0
- package/src/library/font.ts +186 -0
- package/src/library/google-font.ts +97 -0
- package/src/library/index.ts +53 -5
- package/src/library/inspect.ts +176 -0
- package/src/library/kernel-artifact-codec.ts +129 -20
- package/src/library/kernel-cache.ts +175 -39
- package/src/library/loft.ts +9 -1
- package/src/library/material.ts +3 -4
- package/src/library/open-cascade.ts +13 -0
- package/src/library/relation-solver.ts +230 -113
- package/src/library/replicad.ts +5 -5
- package/src/library/retained-memory.ts +6 -1
- package/src/library/runtime.ts +3753 -1181
- package/src/library/shell.ts +3 -3
- package/src/library/sketch-solver.ts +3 -1
- package/src/library/sketch.ts +112 -13
- package/src/library/text.ts +477 -0
- package/src/library/topology.ts +61 -17
- package/src/library/tsconfig.json +2 -1
- package/src/node/index.ts +14 -3
- package/src/node/tsconfig.json +2 -1
- package/src/tooling/index.ts +64 -51
- package/src/tooling/tsconfig.json +2 -1
- package/bld/library/alignment-geometry.js +0 -322
- package/bld/library/alignment-geometry.js.map +0 -1
- package/bld/library/bound-solver.js +0 -252
- package/bld/library/bound-solver.js.map +0 -1
- package/bld/library/extrude.js +0 -28
- package/bld/library/extrude.js.map +0 -1
- package/bld/library/kernel-artifact-codec.js +0 -148
- package/bld/library/kernel-artifact-codec.js.map +0 -1
- package/bld/library/kernel-cache.js +0 -245
- package/bld/library/kernel-cache.js.map +0 -1
- package/bld/library/kernel-shapes.js +0 -108
- package/bld/library/kernel-shapes.js.map +0 -1
- package/bld/library/loft.js +0 -161
- package/bld/library/loft.js.map +0 -1
- package/bld/library/material.js +0 -176
- package/bld/library/material.js.map +0 -1
- package/bld/library/model-color.js +0 -36
- package/bld/library/model-color.js.map +0 -1
- package/bld/library/open-cascade-error.js +0 -22
- package/bld/library/open-cascade-error.js.map +0 -1
- package/bld/library/relation-solver.js +0 -258
- package/bld/library/relation-solver.js.map +0 -1
- package/bld/library/retained-memory.js +0 -27
- package/bld/library/retained-memory.js.map +0 -1
- package/bld/library/runtime.js +0 -2954
- package/bld/library/runtime.js.map +0 -1
- package/bld/library/shell.js +0 -221
- package/bld/library/shell.js.map +0 -1
- package/bld/library/sketch-curve-intersections.js +0 -117
- package/bld/library/sketch-curve-intersections.js.map +0 -1
- package/bld/library/sketch-curves.js +0 -89
- package/bld/library/sketch-curves.js.map +0 -1
- package/bld/library/sketch-drag-rules.js +0 -522
- package/bld/library/sketch-drag-rules.js.map +0 -1
- package/bld/library/sketch-face.js +0 -72
- package/bld/library/sketch-face.js.map +0 -1
- package/bld/library/sketch-incidence.js +0 -114
- package/bld/library/sketch-incidence.js.map +0 -1
- package/bld/library/sketch-precision.js +0 -55
- package/bld/library/sketch-precision.js.map +0 -1
- package/bld/library/sketch-regions.js +0 -193
- package/bld/library/sketch-regions.js.map +0 -1
- package/bld/library/sketch-solver.js +0 -578
- package/bld/library/sketch-solver.js.map +0 -1
- package/bld/library/sketch.js +0 -650
- package/bld/library/sketch.js.map +0 -1
- package/bld/library/spatial.js +0 -195
- package/bld/library/spatial.js.map +0 -1
- package/bld/library/topology-id.js +0 -67
- package/bld/library/topology-id.js.map +0 -1
- package/bld/library/topology-inspection.js +0 -267
- package/bld/library/topology-inspection.js.map +0 -1
- package/bld/library/topology.js +0 -455
- package/bld/library/topology.js.map +0 -1
package/docs/api.md
ADDED
|
@@ -0,0 +1,764 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: Modeling API
|
|
3
|
+
description: A curated map of the public core modeling operations.
|
|
4
|
+
sidebar:
|
|
5
|
+
order: 1
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
Import these functions from `@code3d/core`. The editor's TypeScript signatures
|
|
9
|
+
provide exact overloads and inferred model interfaces.
|
|
10
|
+
|
|
11
|
+
Types used by the authoring API are also exported, including generic constraints,
|
|
12
|
+
named-element result types, and capability interfaces. Use `import type` from
|
|
13
|
+
`@code3d/core` for types such as `ElementKind`, `ModelKind`, `ModelForKind`, `TopologyKind`,
|
|
14
|
+
`NamedElements`, `ExposedElements`, `Bound`, and `TopologyId`. Replicad builder types such as `Shape3D`
|
|
15
|
+
are available from `@code3d/core/replicad` alongside `definePrimitive`.
|
|
16
|
+
|
|
17
|
+
## Solid primitives
|
|
18
|
+
|
|
19
|
+
| Function | Meaning |
|
|
20
|
+
| -------------------------------------------- | --------------------------------- |
|
|
21
|
+
| `box(x, y, z)` | Box dimensions along X, Y, and Z |
|
|
22
|
+
| `cylinder(radius, y)` | Cylinder with its axis along Y |
|
|
23
|
+
| `sphere(radius)` | Sphere of the given radius |
|
|
24
|
+
| `frustum(bottomRadius, topRadius, y)` | Truncated cone |
|
|
25
|
+
| `regularPrism(radius, y, sides, rotation?)` | Regular polygonal prism |
|
|
26
|
+
| `tube(outerRadius, innerRadius, y)` | Straight tube with a through bore |
|
|
27
|
+
| `coil(coilRadius, wireRadius, pitch, turns)` | Circular-wire coil along Y |
|
|
28
|
+
|
|
29
|
+
Tubes are centered on Y; the inner radius must be smaller than the outer
|
|
30
|
+
radius. For coils, `coilRadius` is measured to the wire centerline and
|
|
31
|
+
`pitch` is the advance per turn. Fractional turns are supported; the wire
|
|
32
|
+
must fit inside the coil radius and neighboring turns must remain separated.
|
|
33
|
+
Use [`@code3d/screws`](../../screws/docs/assembly.mdx) for standard fasteners and matching hole tools.
|
|
34
|
+
|
|
35
|
+
To build a solid beyond these primitives, import `definePrimitive` and
|
|
36
|
+
`replicad` from `@code3d/core/replicad`. See
|
|
37
|
+
[custom primitives](custom-primitives.mdx) for a complete example.
|
|
38
|
+
|
|
39
|
+
## Profiles and curves
|
|
40
|
+
|
|
41
|
+
Planar profiles lie in the local XZ plane with a +Y normal.
|
|
42
|
+
|
|
43
|
+
| Function | Meaning |
|
|
44
|
+
| ------------------------------------------ | -------------------------------------------- |
|
|
45
|
+
| `circle(radius)` | Circular face |
|
|
46
|
+
| `ellipse(xRadius, zRadius)` | Elliptical face |
|
|
47
|
+
| `rectangle(x, z)` | Rectangular face |
|
|
48
|
+
| `regularPolygon(radius, sides, rotation?)` | Regular polygonal face |
|
|
49
|
+
| `point()` or `point([x, y, z])` | Vertex model |
|
|
50
|
+
| `line([x, y, z])` or `line(start, end)` | Straight edge |
|
|
51
|
+
| `arc(start, middle, end)` | Arc through three points |
|
|
52
|
+
| `bezier(points)` | Bézier curve |
|
|
53
|
+
| `spline(points)` | Interpolating spline |
|
|
54
|
+
| `loft(sections, options?)` | Solid through sections; optional curve spine |
|
|
55
|
+
| `extrude(faceOrFaces, distance)` | Solid extruded along one face's local normal |
|
|
56
|
+
|
|
57
|
+
See [local coordinates and placement](local-coordinates.md) for
|
|
58
|
+
the coordinate frame of a model, reference, or composition.
|
|
59
|
+
|
|
60
|
+
Position coordinates use arrays; dimensions, offsets and angles use scalar
|
|
61
|
+
arguments. `point([x, y, z])` equals `point().originOffset(-x, -y, -z)`.
|
|
62
|
+
`line([x, y, z])` starts at zero; the two-array form uses both supplied local
|
|
63
|
+
endpoints. Curve tangents do not redefine the model's XYZ axes.
|
|
64
|
+
|
|
65
|
+
Profiles and curves are model values that can be inspected and related to
|
|
66
|
+
other models.
|
|
67
|
+
|
|
68
|
+
Face models also support `face.extrude(distance)`. Both forms accept a finite,
|
|
69
|
+
non-zero signed distance and preserve the starting face's coordinates. For an
|
|
70
|
+
unrotated profile, positive distance extends along +Y; negative distance extends
|
|
71
|
+
along −Y. Rotating the face rotates its extrusion direction; changing its origin
|
|
72
|
+
does not recenter the result. The returned solid supports Boolean operations,
|
|
73
|
+
fillets, chamfers, and shells. `extrude(faces, distance)` accepts a readonly array
|
|
74
|
+
of profiles and returns a readonly array of solids in the same order, preserving
|
|
75
|
+
each face's placement. An empty input returns `[]`; a single face still returns
|
|
76
|
+
a single solid. Both overloads retain required TypeScript distances and use the
|
|
77
|
+
same runtime default of 10 while editing.
|
|
78
|
+
|
|
79
|
+
```ts
|
|
80
|
+
import {circle, extrude, rectangle} from '@code3d/core';
|
|
81
|
+
|
|
82
|
+
export const plate = rectangle(30, 20).extrude(3).fillet(0.5);
|
|
83
|
+
export const pin = extrude(circle(2), -10);
|
|
84
|
+
```
|
|
85
|
+
|
|
86
|
+
## Measurements
|
|
87
|
+
|
|
88
|
+
`distance(a, b, axis?)` returns a non-negative `number` from the models and
|
|
89
|
+
relations available at the call. It accepts vertex, edge, face and solid models,
|
|
90
|
+
non-empty groups, finite topology references, directional bounds, and point
|
|
91
|
+
anchors such as `center`, `start` and exposed mounting points.
|
|
92
|
+
|
|
93
|
+
| Axis | Result |
|
|
94
|
+
| ------------------------------- | ------------------------------------------------------------------------------------------- |
|
|
95
|
+
| Omitted | Shortest distance between the actual finite geometries |
|
|
96
|
+
| `'x'`, `'y'`, `'z'` | Gap between the geometries' projection intervals along a fixed solve-frame axis |
|
|
97
|
+
| `[x, y, z]` | The same projection gap along a finite, non-zero direction vector, normalized automatically |
|
|
98
|
+
| Straight edge or axis reference | Projection gap along that reference's solved direction |
|
|
99
|
+
|
|
100
|
+
Intersecting or touching geometries have zero shortest distance, including a
|
|
101
|
+
point inside a solid. A face measures its trimmed surface, including holes;
|
|
102
|
+
it does not represent the volume enclosed by its parent solid. Projected intervals
|
|
103
|
+
that overlap have zero gap, even if the geometries do not touch in space.
|
|
104
|
+
Groups measure their actual members; their projected interval spans the full
|
|
105
|
+
group, including spaces between disconnected members. Exchanging operands or
|
|
106
|
+
reversing an axis does not change the non-negative result. An axis's position
|
|
107
|
+
does not affect the measurement.
|
|
108
|
+
|
|
109
|
+
Queries solve the inputs' existing relationship closure without requiring
|
|
110
|
+
`group()`. Unrelated models use coincident origins and matching axes. String
|
|
111
|
+
and vector axes belong to that common solve frame, not the camera or implicitly
|
|
112
|
+
the first operand's local frame. A referenced axis carries its owning model's
|
|
113
|
+
solved orientation. For a specific assembled occurrence, expose its geometry
|
|
114
|
+
through the containing group and measure those references.
|
|
115
|
+
|
|
116
|
+
```ts
|
|
117
|
+
import {box, distance, group, offset} from '@code3d/core';
|
|
118
|
+
|
|
119
|
+
const left = box(8, 30, 32);
|
|
120
|
+
const right = box(8, 30, 32).relate(self => [
|
|
121
|
+
self.on(left.right),
|
|
122
|
+
offset(60, 0, 0),
|
|
123
|
+
]);
|
|
124
|
+
const length = distance(left.right, right.left, 'x');
|
|
125
|
+
const beam = box(length, 10, 24).relate(self => self.on(left.right));
|
|
126
|
+
export default group([left, right, beam]);
|
|
127
|
+
```
|
|
128
|
+
|
|
129
|
+
The result is an ordinary number. Later relations and derived model values do
|
|
130
|
+
not update an earlier measurement, and no reverse dependency is solved. Arrange
|
|
131
|
+
measurement and construction in source order; re-running the source computes
|
|
132
|
+
fresh values. Relations returned by a `relate` callback are attached only after
|
|
133
|
+
that callback returns. The query does not see constraints still being built in it.
|
|
134
|
+
|
|
135
|
+
Infinite reference planes and axes cannot be distance operands: select a finite
|
|
136
|
+
face or edge instead. A straight infinite axis is supported as the third argument.
|
|
137
|
+
An empty group, zero direction or curved axis reports an error. Geometric query
|
|
138
|
+
results reuse the shared computation cache; point-to-point measurements use
|
|
139
|
+
ordinary arithmetic.
|
|
140
|
+
|
|
141
|
+
Try the [fitted beam example](/examples/distance/) and
|
|
142
|
+
[measurement workflow](relations.mdx#measure-before-building-a-part).
|
|
143
|
+
|
|
144
|
+
## Independent placement transformations
|
|
145
|
+
|
|
146
|
+
`relate` callbacks return a `Constraint`, a `Transformation`, or a readonly array of both.
|
|
147
|
+
Independent constructors are `offset(x, y, z)`, `rotate(x, y, z)`,
|
|
148
|
+
`pivot([x, y, z]).rotate(x, y, z)`, `pivotVertex(id).rotate(x, y, z)`,
|
|
149
|
+
`pivotPoint(pointRef).rotate(x, y, z)`, `axisEdge(id).rotate(angle)`, and
|
|
150
|
+
`axisLine(lineRef).rotate(angle)`. Values can be built in helper functions and reused.
|
|
151
|
+
|
|
152
|
+
| Selector | Reference |
|
|
153
|
+
| ---------------------- | --------------------------------------- |
|
|
154
|
+
| `pivot([x, y, z])` | Coordinates in self |
|
|
155
|
+
| `pivotVertex(id)` | A vertex of self |
|
|
156
|
+
| `pivotPoint(pointRef)` | A local or external point reference |
|
|
157
|
+
| `axisEdge(id)` | A straight edge of self |
|
|
158
|
+
| `axisLine(lineRef)` | A local or external line/axis reference |
|
|
159
|
+
|
|
160
|
+
Point references change the rotation center while retaining self's XYZ axes.
|
|
161
|
+
External references use their owning model's solved placement in the composition.
|
|
162
|
+
Curved edges do not define a rotation axis.
|
|
163
|
+
|
|
164
|
+
Each independent transformation is one completed operation, with no further
|
|
165
|
+
chaining methods. Use an array to combine steps: `[offset(0, 8, 0), rotate(0, 25, 0)]`.
|
|
166
|
+
These five reference selectors return an unfinished selection with a
|
|
167
|
+
`rotate` method; its result is again a completed transformation.
|
|
168
|
+
Point selectors additionally accept one `pivotOffset(dx, dy, dz)`; axis selectors
|
|
169
|
+
accept one `axisOffset(dx, dy, dz)`. The resulting selector only exposes `rotate`.
|
|
170
|
+
Point offsets use self local axes. Axis offsets use the selected axis reference
|
|
171
|
+
frame, retaining its direction. Both retain the original point/axis reference.
|
|
172
|
+
|
|
173
|
+
Consecutive constraints form a joint solve segment. Transformations act after
|
|
174
|
+
its result; a subsequent constraint starts another segment and inherits the
|
|
175
|
+
previous pose in its free directions. Independent offset uses fixed composition
|
|
176
|
+
axes; rotation defaults to the current self origin and local XYZ axes. See
|
|
177
|
+
[the complete placement rules](relations.mdx#transform-a-joint-result).
|
|
178
|
+
|
|
179
|
+
## Runtime defaults while editing
|
|
180
|
+
|
|
181
|
+
The dimension-based primitives and numeric methods below keep their required TypeScript parameters,
|
|
182
|
+
but their implementations supply defaults for omitted or `undefined` arguments.
|
|
183
|
+
For example, `box()` previews a 10 × 10 × 10 box, while the editor still reports
|
|
184
|
+
the missing arguments; `box(20)` previews 20 × 10 × 10. Finish the arguments to
|
|
185
|
+
make the source type-correct. These defaults also apply in ordinary JavaScript
|
|
186
|
+
execution and do not depend on the App.
|
|
187
|
+
|
|
188
|
+
| Function | Runtime defaults, in parameter order |
|
|
189
|
+
| ---------------- | ------------------------------------ |
|
|
190
|
+
| `box` | `10, 10, 10` |
|
|
191
|
+
| `cylinder` | `5, 10` |
|
|
192
|
+
| `sphere` | `5` |
|
|
193
|
+
| `frustum` | `5, 3, 10` |
|
|
194
|
+
| `regularPrism` | `5, 10, 6, 0` |
|
|
195
|
+
| `tube` | `5, 3, 10` |
|
|
196
|
+
| `coil` | `5, 1, 3, 3` |
|
|
197
|
+
| `circle` | `5` |
|
|
198
|
+
| `ellipse` | `5, 3` |
|
|
199
|
+
| `rectangle` | `10, 10` |
|
|
200
|
+
| `regularPolygon` | `5, 6, 0` |
|
|
201
|
+
|
|
202
|
+
| Method or utility parameter | Runtime defaults |
|
|
203
|
+
| --------------------------------------------------- | ---------------- |
|
|
204
|
+
| Model/group `rotate` and independent/pivot `rotate` | `0, 0, 0` |
|
|
205
|
+
| Model/group `originOffset` and relation `offset` | `0, 0, 0` |
|
|
206
|
+
| Relation `pivot` | `[0, 0, 0]` |
|
|
207
|
+
| Selector `pivotOffset` and `axisOffset` | `0, 0, 0` |
|
|
208
|
+
| `axisLine(axis).rotate` | `0` |
|
|
209
|
+
| Geometric model `scaled` | `1` |
|
|
210
|
+
| Face `extrude` and the `extrude` utility's distance | `10` |
|
|
211
|
+
| Solid `fillet`, `chamfer` and `shell` | `1` |
|
|
212
|
+
|
|
213
|
+
For example, `box(20, 30, 40).rotate()` previews the unchanged body, and
|
|
214
|
+
`.rotate(30)` previews a 30-degree X rotation. Their missing-angle diagnostics
|
|
215
|
+
remain until all three arguments are supplied. Relation `offset()` translates
|
|
216
|
+
self from the relation's solution in the target reference axes. Like explicit
|
|
217
|
+
`offset(0, 0, 0)`, omitting its arguments preserves that solution and adds no
|
|
218
|
+
tangential constraints. `pivot()` selects self's local origin. Geometry IDs, reference axes and input
|
|
219
|
+
models still need explicit values.
|
|
220
|
+
|
|
221
|
+
Explicit arguments remain subject to their normal validation: `box(0)`, for
|
|
222
|
+
example, still reports an error. The parameter panel shows omitted defaults as
|
|
223
|
+
placeholders and only writes arguments when you edit them. See
|
|
224
|
+
[parameter defaults](../../web/src/content/docs/docs/guides/model-tools.mdx#describe-an-omitted-arguments-default).
|
|
225
|
+
|
|
226
|
+
Spatial controls use the rendered operation's position and frame, so omitted
|
|
227
|
+
arguments do not hide its translation arrows or rotation rings. Committing a
|
|
228
|
+
drag fills all remaining omitted defaults in that call: dragging the X ring of
|
|
229
|
+
`rotate()` writes `rotate(angle, 0, 0)`, and dragging `pivot()` writes all three
|
|
230
|
+
coordinates. This also applies when editing an existing or upstream parameter.
|
|
231
|
+
The parameter change and default completion form one undo step. Merely selecting a
|
|
232
|
+
tool, cancelling a drag or returning to its starting value leaves the source
|
|
233
|
+
unchanged. Existing editable expressions retain their normal editing behavior;
|
|
234
|
+
opaque inputs such as `pivot(coords)` or `rotate(...angles)` are replaced with
|
|
235
|
+
the current evaluated coordinates or angles when you commit the drag. Undo
|
|
236
|
+
restores the original expression.
|
|
237
|
+
|
|
238
|
+
## Editable sketch regions
|
|
239
|
+
|
|
240
|
+
Select a `sketch([...])` expression or variable to preview its points and curves
|
|
241
|
+
in 3D. Choose **Edit sketch** to open its 2D editor and **Finish sketch** to return
|
|
242
|
+
to the shared 3D scene.
|
|
243
|
+
Points, lines, circles and arcs use explicit layer-local entity IDs. `face()`
|
|
244
|
+
requires exactly one closed region, including holes; `faces()` returns all regions
|
|
245
|
+
as an ordinary readonly array. Use `map` for independent modeling operations:
|
|
246
|
+
|
|
247
|
+
```ts
|
|
248
|
+
import {sketch} from '@code3d/core';
|
|
249
|
+
|
|
250
|
+
const profile = sketch([
|
|
251
|
+
['point', 1, [0, 0]],
|
|
252
|
+
['circle', 2, [1, 12]],
|
|
253
|
+
['circle', 3, [1, 8]],
|
|
254
|
+
]);
|
|
255
|
+
const sleeve = profile.face().extrude(20);
|
|
256
|
+
const parts = profile.faces().map(face => face.extrude(10));
|
|
257
|
+
```
|
|
258
|
+
|
|
259
|
+
Geometry tuples store current data; the second argument's `constraints` array
|
|
260
|
+
specifies relations that must remain true. Constraints have no IDs and use
|
|
261
|
+
`['kind', target, value?]`. For local lines:
|
|
262
|
+
|
|
263
|
+
- `['horizontal', line]` and `['vertical', line]` set an axis direction;
|
|
264
|
+
`['length', line, distance]` sets a positive length.
|
|
265
|
+
- `['angle', line, degrees]` sets Orientation relative to +X.
|
|
266
|
+
- `['parallel', [line1, line2]]` and `['perpendicular', [line1, line2]]`
|
|
267
|
+
relate two lines without requiring their finite segments to intersect.
|
|
268
|
+
- `['angle', [line1, line2], degrees]` sets Angle between lines: the signed
|
|
269
|
+
rotation from the first line's authored start-to-end direction to the second,
|
|
270
|
+
positive counterclockwise and equivalent modulo 360.
|
|
271
|
+
|
|
272
|
+
In Select, an ordinary click or box selection replaces the selection, Ctrl
|
|
273
|
+
toggles elements, and Shift only adds them. Drag a box left-to-right for fully
|
|
274
|
+
enclosed geometry or right-to-left for intersecting geometry. A multi-selection
|
|
275
|
+
can remove any editable local constraint on its elements, while adding one
|
|
276
|
+
requires the entire selection to satisfy the tool's prerequisites. Parallel
|
|
277
|
+
accepts two or more local lines and creates pairwise relations; Perpendicular
|
|
278
|
+
and Angle between lines require exactly two. Rectangle tools still create
|
|
279
|
+
horizontal and vertical constraints by default.
|
|
280
|
+
|
|
281
|
+
Drag an arc endpoint to reshape it while preferring to keep its center in place.
|
|
282
|
+
Drag a circle or arc center to move it while preferring to keep its radius
|
|
283
|
+
unchanged. Hard constraints, expression-controlled values and read-only upstream
|
|
284
|
+
geometry take precedence; these preferences can keep the dragged point from
|
|
285
|
+
reaching the pointer. They apply only during the gesture and do not add persistent
|
|
286
|
+
fixed or radius constraints. To change an editable radius, drag the curve itself
|
|
287
|
+
or edit its source or dimension.
|
|
288
|
+
After the gesture-specific preferences, all other points prefer staying near
|
|
289
|
+
their gesture-start positions. This lowest-priority step only resolves remaining
|
|
290
|
+
freedom: it does not pull back a translated shape, weaken hard constraints or
|
|
291
|
+
add fixed-point constraints to the source.
|
|
292
|
+
|
|
293
|
+
Derived sketches include their read-only upstream boundaries. Separate contours
|
|
294
|
+
produce separate faces; nested contours alternate material, holes and islands.
|
|
295
|
+
Open, crossing, touching, overlapping and branched boundaries must be trimmed into
|
|
296
|
+
valid closed contours before creating faces. The editor leaves unfinished sketches
|
|
297
|
+
editable and previews valid regions without changing entity IDs.
|
|
298
|
+
|
|
299
|
+
Sketch `[x, y]` maps to model `[x, 0, -y]`, without recentering. `.extrude(distance)`
|
|
300
|
+
and `extrude(face, distance)` are equivalent single-face operations. Distance must
|
|
301
|
+
be finite and nonzero; positive follows the plane normal, negative reverses it.
|
|
302
|
+
Rotating the face rotates its extrusion direction too.
|
|
303
|
+
|
|
304
|
+
`loft` takes one face per section and preserves a single corresponding hole, with
|
|
305
|
+
or without a spine. Different hole counts or multiple unpaired holes report an
|
|
306
|
+
error rather than silently filling holes. Persistent region IDs and general
|
|
307
|
+
multi-hole correspondence are not available yet. Try `examples/sketches/regions.ts`
|
|
308
|
+
in the App for a plate, multiple cutting tools and a hollow loft.
|
|
309
|
+
|
|
310
|
+
### Sketch placement and model context
|
|
311
|
+
|
|
312
|
+
`sketch.relate(self => self.plane.align(target))` creates an immutable spatial
|
|
313
|
+
copy of the same local 2D definition. Empty and open sketches can relate before
|
|
314
|
+
`face()` is available. Targets include named model planes and planar
|
|
315
|
+
`model.surface(id)` references.
|
|
316
|
+
|
|
317
|
+
```ts
|
|
318
|
+
const host = box(40, 20, 30).rotate(0, 0, 25);
|
|
319
|
+
const profile = sketch([
|
|
320
|
+
['point', 1, [0, 0]],
|
|
321
|
+
['circle', 2, [1, 4]],
|
|
322
|
+
]);
|
|
323
|
+
const opening = profile.relate(s => s.plane.align(host.surface(4)));
|
|
324
|
+
const result = host.cut([opening.face().extrude(-20)]);
|
|
325
|
+
```
|
|
326
|
+
|
|
327
|
+
Derived layers, faces and extrusion inherit these relations. Plane alignment does
|
|
328
|
+
not center on a trimmed face or rewrite sketch coordinates. The relation binds
|
|
329
|
+
the referenced immutable host value; later creating another transformed host does
|
|
330
|
+
not redirect it. Use `align()`, not finite-bound `on()`, for the sketch's unbounded
|
|
331
|
+
reference plane.
|
|
332
|
+
|
|
333
|
+
Select `opening` and choose **Edit sketch** to edit with read-only model outlines in the sketch's
|
|
334
|
+
local plane, or `profile` for the original local view. Both write the same geometry
|
|
335
|
+
array. The outlines do not become snapping targets or external geometry constraints.
|
|
336
|
+
See `examples/sketches/mounting-plate.ts` for a slotted plate. Create the relation
|
|
337
|
+
in code; selecting a face does not automatically generate a related sketch.
|
|
338
|
+
|
|
339
|
+
## Composition and boolean operations
|
|
340
|
+
|
|
341
|
+
| Function | Result |
|
|
342
|
+
| ---------------------- | --------------------------------------------- |
|
|
343
|
+
| `group(models, name?)` | Composition that preserves its separate parts |
|
|
344
|
+
| `union(solids)` | Fused solid |
|
|
345
|
+
| `cut(stock, tools)` | Stock with the tool volumes removed |
|
|
346
|
+
| `intersect(solids)` | Shared solid volume |
|
|
347
|
+
|
|
348
|
+
`group()` accepts a `readonly Model[]`, including ordinary groups, empty groups,
|
|
349
|
+
and any depth of nested groups mixed with solids, faces, curves, or points. Each
|
|
350
|
+
nested group keeps its hierarchy. No type assertion or `expose()` call is needed
|
|
351
|
+
to compose it; use `expose()` when callers need named member references. Generic
|
|
352
|
+
helpers can use `ModelCapabilities<Elements, Kind>` and `ModelForKind<Elements, Kind>`
|
|
353
|
+
to preserve the concrete model kind and exposed members through chained calls.
|
|
354
|
+
|
|
355
|
+
Relations are resolved at composition and geometry evaluation boundaries.
|
|
356
|
+
`stock.cut(tools)` is equivalent to `cut(stock, tools)`. Arrays in booleans and
|
|
357
|
+
loft describe the inputs of one operation; they do not automatically map it.
|
|
358
|
+
`intersect()` requires a common solid volume across all inputs. Disjoint inputs
|
|
359
|
+
or inputs that only touch produce a diagnostic rather than an empty solid.
|
|
360
|
+
|
|
361
|
+
## Model operations
|
|
362
|
+
|
|
363
|
+
Available operations depend on the kind of geometry. TypeScript completion
|
|
364
|
+
shows which operations are supported by the value you hold.
|
|
365
|
+
|
|
366
|
+
- `.fillet(radius, edgeIds?)`: round selected edges, or all edges.
|
|
367
|
+
- `.chamfer(distance, edgeIds?)`: bevel selected edges, or all edges.
|
|
368
|
+
- `.shell(thickness, removedSurfaceIds?)`: hollow one connected solid. Positive
|
|
369
|
+
thickness offsets inward; negative thickness offsets outward. Selected surfaces
|
|
370
|
+
become openings; omission or `[]` creates an enclosed cavity. See
|
|
371
|
+
[making hollow parts](shells.mdx).
|
|
372
|
+
- `.scaled(factor)`: uniformly scale a geometric model about local coordinate zero.
|
|
373
|
+
- `.material(value)`: replace the complete material with a native Three.js material
|
|
374
|
+
or a CSS color shorthand; a group overrides every descendant's material.
|
|
375
|
+
- `.relate(self => constraint)` or `.relate(self => [first, second])`: attach
|
|
376
|
+
one or more relations for placement in a composition.
|
|
377
|
+
- `.expose({name: element})`: publish a typed named-element interface.
|
|
378
|
+
|
|
379
|
+
## Materials
|
|
380
|
+
|
|
381
|
+
Use [`@code3d/materials`](../../materials/docs/presets.md) for common plastic, metal, glass,
|
|
382
|
+
ceramic and paint presets, such as `.material(aluminum({finish: 'polished'}))`.
|
|
383
|
+
Each preset returns a native Three.js material and follows the same rules below.
|
|
384
|
+
|
|
385
|
+
```ts
|
|
386
|
+
import {box} from '@code3d/core';
|
|
387
|
+
import {MeshPhysicalMaterial} from '@code3d/core/three';
|
|
388
|
+
|
|
389
|
+
const part = box(20, 10, 12).material(
|
|
390
|
+
new MeshPhysicalMaterial({
|
|
391
|
+
color: '#eb633e',
|
|
392
|
+
roughness: 0.25,
|
|
393
|
+
clearcoat: 1,
|
|
394
|
+
}),
|
|
395
|
+
);
|
|
396
|
+
```
|
|
397
|
+
|
|
398
|
+
`@code3d/core/three` directly re-exports Core's native Three.js classes and types.
|
|
399
|
+
Use this entry in the model and its reusable packages to share the same instance.
|
|
400
|
+
Named imports and `import * as THREE from "@code3d/core/three"` both work in the
|
|
401
|
+
App and Node. Each `.material(value)` call captures a
|
|
402
|
+
complete material and its loaded texture pixels. It returns a new model;
|
|
403
|
+
subsequent changes to the original Three.js instance do not change that model.
|
|
404
|
+
Calling it again replaces everything, without merging fields. An outer group
|
|
405
|
+
replaces the material throughout its subtree; original parts used elsewhere
|
|
406
|
+
remain unchanged.
|
|
407
|
+
|
|
408
|
+
Use mesh materials for solids and surfaces, line materials for curves, and
|
|
409
|
+
`PointsMaterial` for vertices. Modeling emphasis uses preview copies; Render
|
|
410
|
+
mode and PNG images use the authored material. Loaded image, canvas, ImageBitmap,
|
|
411
|
+
data and cube textures are supported. Load images with `ImageBitmapLoader` in
|
|
412
|
+
the worker before assignment. Native face UVs are normalized to 0–1 per face;
|
|
413
|
+
texture `repeat`, `offset` and `rotation` control mapping. See
|
|
414
|
+
`/examples/materials.ts` in the App.
|
|
415
|
+
|
|
416
|
+
The transferable value follows Three.js's `toJSON()` / `MaterialLoader`
|
|
417
|
+
representation. Custom classes, callbacks such as `onBeforeCompile`, live
|
|
418
|
+
video/render-target textures, compressed/layered textures and manual mipmaps
|
|
419
|
+
are rejected. Material-local clipping, shadow-side and precision overrides are
|
|
420
|
+
not serialized by Three.js and are also rejected. Shader uniforms must be supported by Three.js JSON.
|
|
421
|
+
|
|
422
|
+
A CSS string replaces the whole material with the geometry's default material.
|
|
423
|
+
It accepts names, `#RGB`, `#RGBA`, `#RRGGBB`, `#RRGGBBAA`, `rgb(...)` and
|
|
424
|
+
`rgba(...)`. `.material('#f008')` equals `.material('#ff000088')`;
|
|
425
|
+
`.material('rgba(255, 0, 0, 0.5)')` and `.material('rgb(100% 0% 0% / 50%)')`
|
|
426
|
+
produce half-opaque red. Native materials use Three.js's `opacity` and
|
|
427
|
+
`transparent` settings. STEP and 3MF preserve base color and opacity, while
|
|
428
|
+
shaders and textures are rendered in PNG; STL contains geometry only.
|
|
429
|
+
|
|
430
|
+
## Scaling
|
|
431
|
+
|
|
432
|
+
Solids, faces, curves, and points support `.scaled(factor)`. The factor must be
|
|
433
|
+
positive and finite. For example, `box(20, 8, 12).scaled(0.5)` returns a new box
|
|
434
|
+
with dimensions 10, 4, and 6, leaving the original model unchanged.
|
|
435
|
+
|
|
436
|
+
Scaling uses local coordinate zero even after an origin edit. Geometry, named
|
|
437
|
+
anchors and the `center` anchor scale together; the model origin stays zero;
|
|
438
|
+
topology IDs are preserved. Groups do not provide `.scaled()`; scale their
|
|
439
|
+
geometric parts before composing them. To change only an exported file's unit
|
|
440
|
+
conversion, use the [export scale](../../web/src/content/docs/docs/guides/exporting.md#scale-and-orientation).
|
|
441
|
+
|
|
442
|
+
## Origins and rotation
|
|
443
|
+
|
|
444
|
+
Every model, including groups, has a `frame: FrameAnchor` coordinate reference.
|
|
445
|
+
`frame.origin: PointAnchor` references its zero point; `model.origin` returns
|
|
446
|
+
that same reference. These references have no geometry and cannot be added as
|
|
447
|
+
models to a group. A point model's geometry may be away from its own origin.
|
|
448
|
+
|
|
449
|
+
`self.origin.align(other.origin)` constrains only position.
|
|
450
|
+
`self.frame.align(other.frame)` constrains position and all three axis directions.
|
|
451
|
+
Use `.frame` explicitly: aligning curves or surfaces still refers to their
|
|
452
|
+
underlying geometry. Frames support `expose`, including `.origin` on the exposed
|
|
453
|
+
frame, and retain their occurrence and transform through composition.
|
|
454
|
+
|
|
455
|
+
All models provide `originPoint()`, `originOffset()` and `rotate()`. Solids, faces,
|
|
456
|
+
curves and points additionally provide vertex/center selection:
|
|
457
|
+
|
|
458
|
+
| Method | Behavior |
|
|
459
|
+
| --------------------------- | ------------------------------------------------------------- |
|
|
460
|
+
| `.originPoint(pointRef)` | Set the origin to a point reference, including a group member |
|
|
461
|
+
| `.originVertex(id)` | Set the origin to an input-model vertex |
|
|
462
|
+
| `.originCenter()` | Set the origin to the model's center anchor |
|
|
463
|
+
| `.originOffset(dx, dy, dz)` | Add a local-coordinate offset to the current origin |
|
|
464
|
+
| `.rotate(x, y, z)` | Rotate about the origin, in degrees, fixed X then Y then Z |
|
|
465
|
+
|
|
466
|
+
The origin is always zero in model coordinates. `originOffset(dx, dy, dz)`
|
|
467
|
+
re-expresses every local point as `p - [dx, dy, dz]`; offsets accumulate and can
|
|
468
|
+
cancel. `originVertex` and `originCenter` make the selected point local zero.
|
|
469
|
+
Geometry, named anchors and topology positions use the resulting coordinates;
|
|
470
|
+
directions and topology IDs are preserved. Old model values remain unchanged.
|
|
471
|
+
Rotation and scaling act about current local zero.
|
|
472
|
+
|
|
473
|
+
Every geometric model exposes `center`: its initial local bounding-box center,
|
|
474
|
+
carried along by subsequent transforms. Rotation does not recalculate it from
|
|
475
|
+
the rotated shape's axis-aligned bounds. Origin edits change its coordinates;
|
|
476
|
+
`.originCenter().originOffset(1, 0, 0)` leaves it at `[-1, 0, 0]`.
|
|
477
|
+
A group inherits the first member's solved local coordinate frame, including
|
|
478
|
+
its origin and axes, while preserving relative member placement. Nested groups
|
|
479
|
+
keep their own frames; an empty group uses the default origin and axes. Member
|
|
480
|
+
order can change the group's frame. Group origin
|
|
481
|
+
edits move the entire assembly's local coordinates together; they preserve its
|
|
482
|
+
internal relations. `rotate(x, y, z)` turns the solved assembly about its current
|
|
483
|
+
origin, including nested instances. `originPoint(part.center)` resolves the member's actual
|
|
484
|
+
placement; repeated sources need a specific instance reference. Groups do not
|
|
485
|
+
have aggregate vertex IDs, a geometric center or scaling.
|
|
486
|
+
See [group coordinates](local-coordinates.md#group-origins).
|
|
487
|
+
|
|
488
|
+
For a runnable example and
|
|
489
|
+
the vertex picker, origin arrows, and rotation rings, see
|
|
490
|
+
[choosing an origin and rotating a part](origins-and-rotation.mdx).
|
|
491
|
+
|
|
492
|
+
## Anchors and relations
|
|
493
|
+
|
|
494
|
+
Solid primitives expose `center` and `axis`; every model provides directional
|
|
495
|
+
bounds: `up` (+Y), `down` (−Y), `right` (+X), `left` (−X), `front` (+Z),
|
|
496
|
+
and `back` (−Z), in that model's local frame.
|
|
497
|
+
|
|
498
|
+
`geometry.on(target.up)` only translates. The source may be a model, point,
|
|
499
|
+
edge, or surface; its own finite extent is measured along the target direction.
|
|
500
|
+
Tangential position and orientation are preserved. Targets must be directional
|
|
501
|
+
bounds. Infinite reference lines and planes cannot supply a finite source extent.
|
|
502
|
+
|
|
503
|
+
Return an array from `relate()` to combine positional conditions. Inconsistent
|
|
504
|
+
positions report a conflict. `offset(x, y, z)` translates self from the original
|
|
505
|
+
solution in the target reference frame. Explicit zero changes nothing; use
|
|
506
|
+
point or axis alignment for centering. `bound.flip()` reverses contact
|
|
507
|
+
facing without changing geometry or reference axes.
|
|
508
|
+
|
|
509
|
+
`relate` returns a new model, represented by its callback parameter `self`.
|
|
510
|
+
Every returned constraint must involve that value, as in `self.on(base.up)`
|
|
511
|
+
or `base.on(self.up)`. External variables keep their original identity, including
|
|
512
|
+
the receiver of `relate`: `part.relate(self => self.on(part.right))` places a
|
|
513
|
+
new part against the original. Select the new part's topology and rotation
|
|
514
|
+
references through `self`; references selected from `part` belong to the original.
|
|
515
|
+
|
|
516
|
+
`pointOrCurveOrSurface.align(target)` solves geometric position and orientation.
|
|
517
|
+
Same-dimensional references coincide; a lower-dimensional reference lies on the
|
|
518
|
+
whole supporting geometry of the other. Edges use their underlying curves and
|
|
519
|
+
faces their underlying surfaces, ignoring trims and parameter origins. Supported
|
|
520
|
+
types are points, straight lines, circles, ellipses, planes, cylinders, and
|
|
521
|
+
spheres. Select a solid's center, axis, vertex, edge, or surface first.
|
|
522
|
+
|
|
523
|
+
Curve–curve alignment is directed; `lineReference.reverse()` selects the opposite
|
|
524
|
+
direction. Surface–surface alignment matches normal sense; `faceReference.flip()`
|
|
525
|
+
selects the opposite facing. Neither changes the reference axes or geometry.
|
|
526
|
+
Point membership ignores direction. Constraints expose no transformation methods.
|
|
527
|
+
Place independent transformations after the constraints in the `relate` array:
|
|
528
|
+
|
|
529
|
+
- `offset(x, y, z)`: move self along fixed composition axes.
|
|
530
|
+
- `rotate(x, y, z)`: rotate around self's origin and local XYZ axes.
|
|
531
|
+
- `pivot([x, y, z]).rotate(x, y, z)`: a pivot in self's local frame.
|
|
532
|
+
- `pivotVertex(id).rotate(x, y, z)`: a vertex belonging to self.
|
|
533
|
+
- `pivotPoint(pointRef).rotate(x, y, z)`: a local or external point.
|
|
534
|
+
- `axisEdge(id).rotate(angle)`: a straight edge belonging to self.
|
|
535
|
+
- `axisLine(lineRef).rotate(angle)`: a positioned local or external axis.
|
|
536
|
+
|
|
537
|
+
Angles are degrees; XYZ rotations apply X, then Y, then Z. Pivot/axis selections
|
|
538
|
+
must be completed with `rotate`. Consecutive constraints solve jointly, followed
|
|
539
|
+
by transformations in array order. A later constraint starts a new segment from
|
|
540
|
+
the preceding pose. Groups move their assembled children as rigid bodies.
|
|
541
|
+
Standalone geometry is unchanged.
|
|
542
|
+
|
|
543
|
+
## Topology
|
|
544
|
+
|
|
545
|
+
- `.vertex(id)`, `.edge(id)`, `.surface(id)`: one point, line, or face anchor.
|
|
546
|
+
- `.vertices(ids?)`, `.edges(ids?)`, `.surfaces(ids?)`: arrays of anchors.
|
|
547
|
+
|
|
548
|
+
These topology references expose readonly `kind` (`vertex`, `edge`, or
|
|
549
|
+
`surface`) and `id` properties. Use `model.edges().map(edge => edge.id)` to
|
|
550
|
+
collect edge IDs for an operation on that model. Plain named anchors such as
|
|
551
|
+
`model.up` do not have these topology properties.
|
|
552
|
+
|
|
553
|
+
IDs are model-local. See [topology selection](topology.md) for
|
|
554
|
+
selection behavior and derived-model identity.
|
|
555
|
+
|
|
556
|
+
`TopologyId` (also used by `VertexId`, `EdgeId`, and `SurfaceId`) is a
|
|
557
|
+
positive integer or a flat numeric source path. A loft cap can be selected with
|
|
558
|
+
`body.surface([1, 1])`; a mixed selection uses an outer list, such as
|
|
559
|
+
`body.surfaces([1, [1, 1], [2, 1]])`. Loft, extrusion and Boolean operations prefix
|
|
560
|
+
one-to-one inherited IDs with the one-based input index. Local edits (`fillet`,
|
|
561
|
+
`chamfer`, `shell`) preserve inherited IDs, including existing paths; their new
|
|
562
|
+
or ambiguous elements receive fresh numbers without reusing retired IDs.
|
|
563
|
+
Transforms preserve complete IDs.
|
|
564
|
+
|
|
565
|
+
A surface can query its edges and vertices; an edge can query its vertices.
|
|
566
|
+
These queries retain the source model's IDs and validate membership.
|
|
567
|
+
`.center` is a transformed local bounding-box center; edges also provide
|
|
568
|
+
`.start`, `.midpoint`, and `.end` at curve parameters 0, 0.5, and 1.
|
|
569
|
+
Calculated points are anchors, not topology vertices.
|
|
570
|
+
|
|
571
|
+
Model dimensions use a consistent coordinate scale. When
|
|
572
|
+
[exporting](../../web/src/content/docs/docs/guides/exporting.md#scale-and-orientation), choose how many
|
|
573
|
+
millimeters each model unit represents. This scales the output without changing
|
|
574
|
+
the source model.
|
|
575
|
+
|
|
576
|
+
## Cached computations
|
|
577
|
+
|
|
578
|
+
```ts
|
|
579
|
+
import {cache} from '@code3d/core';
|
|
580
|
+
|
|
581
|
+
function buildProfile(radius: number, sides: number) {
|
|
582
|
+
return Array.from({length: sides}, (_, index) => {
|
|
583
|
+
const angle = (index * 2 * Math.PI) / sides;
|
|
584
|
+
return [radius * Math.cos(angle), radius * Math.sin(angle)];
|
|
585
|
+
});
|
|
586
|
+
}
|
|
587
|
+
const profile = cache(buildProfile);
|
|
588
|
+
const points = cache(buildProfile, [10, 6]);
|
|
589
|
+
```
|
|
590
|
+
|
|
591
|
+
`cache(fn)` returns a memoized function; `cache(fn, args)` immediately returns
|
|
592
|
+
its result for the supplied argument tuple. Both forms preserve synchronous
|
|
593
|
+
parameter/result types and use the same definition and argument cache keys.
|
|
594
|
+
In the example, `profile(10, 6)` reuses the same cached result as `points`. An empty tuple `[]` immediately invokes
|
|
595
|
+
a computation with no arguments. The argument tuple is not part of the
|
|
596
|
+
compiler's function fingerprint: changing inputs selects another cache entry.
|
|
597
|
+
|
|
598
|
+
The API caches
|
|
599
|
+
ordinary data; use `definePrimitive()` for Replicad geometry so Core also owns
|
|
600
|
+
native resources and creates fresh model metadata. Treat cached results as
|
|
601
|
+
immutable. A memory hit returns the retained computed or decoded value directly,
|
|
602
|
+
without decoding, copying or freezing it.
|
|
603
|
+
|
|
604
|
+
The default persistent codec supports plain objects, arrays, scalar values
|
|
605
|
+
(including `undefined`, nonfinite numbers and bigint), Date, Map, Set, ArrayBuffer,
|
|
606
|
+
standard TypedArrays and DataView. Shared references, cycles, sparse arrays and
|
|
607
|
+
shared buffer views survive restoration. Arguments use the same data encoding;
|
|
608
|
+
changing dynamic state must be supplied as arguments. Functions, native handles
|
|
609
|
+
and application class instances are not ordinary data arguments.
|
|
610
|
+
|
|
611
|
+
For custom result types, supply both functions as
|
|
612
|
+
`cache(fn, undefined, {encoder: value => bytes, decoder: bytes => value})`.
|
|
613
|
+
For immediate evaluation, use `cache(fn, args, options)` with the same codec options.
|
|
614
|
+
The encoder runs when saving to disk; the decoder runs once when restoring an
|
|
615
|
+
entry into memory. A subsequent memory hit never calls either codec. Async
|
|
616
|
+
computations are excluded: incomplete work is not admitted to the cache.
|
|
617
|
+
|
|
618
|
+
New results are written to disk only when their computation reaches the configured
|
|
619
|
+
threshold, 1 ms by default. In the App, change **Disk cache threshold (ms)** under
|
|
620
|
+
**Settings → Cache**; fractional values are supported and 0 removes the time
|
|
621
|
+
threshold. Changes apply to new computations from the next model execution;
|
|
622
|
+
existing entries retain their disk eligibility.
|
|
623
|
+
Faster results still use the memory cache, and later memory hits do not promote
|
|
624
|
+
them to disk. The computation timer excludes the surrounding cache lookup,
|
|
625
|
+
argument hashing and persistence encoding. Batched snapshot queries use their
|
|
626
|
+
local or Worker computation time, excluding input restoration and transport.
|
|
627
|
+
Existing disk records remain readable; restoring a record preserves its disk
|
|
628
|
+
eligibility.
|
|
629
|
+
|
|
630
|
+
The model engine fingerprints static function definitions, their referenced
|
|
631
|
+
local declarations, imported implementation graphs and codec definitions. Aliases
|
|
632
|
+
and re-exports of Core cache factories are supported. Editing an unrelated local
|
|
633
|
+
binding, moving a definition or adding/removing `export` preserves its identity;
|
|
634
|
+
changing a referenced helper or dependency invalidates it. Functions supplied as parameters, dynamic factory results and closures capturing
|
|
635
|
+
enclosing function/loop bindings use memory-only object identity.
|
|
636
|
+
Outside the model engine, ordinary Node calls also use function object identity
|
|
637
|
+
and share the process-wide memory LRU. Authors do not provide cache IDs or versions.
|
|
638
|
+
|
|
639
|
+
Public cached computations, primitives, Core geometry, font parsing, glyph contours
|
|
640
|
+
and snapshot queries share one cache. The memory budget remains 2 GiB; browser
|
|
641
|
+
persistence shares the OPFS disk budget configured in App settings (2 GiB by default).
|
|
642
|
+
Cancellation and exceptions retain completed entries and editing history.
|
|
643
|
+
|
|
644
|
+
## Text
|
|
645
|
+
|
|
646
|
+
```ts
|
|
647
|
+
import {font, text, extrude, group} from '@code3d/core';
|
|
648
|
+
|
|
649
|
+
const sans = font(new URL('./fonts/DejaVuSans.ttf', import.meta.url));
|
|
650
|
+
const profiles = text('B8i', sans, 10);
|
|
651
|
+
export const lettering = group(extrude(profiles, 1));
|
|
652
|
+
```
|
|
653
|
+
|
|
654
|
+
`font()` synchronously returns an immutable font resource. The App prepares literal
|
|
655
|
+
`new URL('./font.ttf', import.meta.url)` assets before evaluating model code, including
|
|
656
|
+
assets in imported modules. Changing the font file invalidates the resource; equal
|
|
657
|
+
file contents reuse parsed fonts and geometry. Node reads file URLs directly.
|
|
658
|
+
`font()` also accepts `ArrayBuffer` or `Uint8Array` bytes, captured at the call.
|
|
659
|
+
The engine also prepares static HTTP(S) font URLs before model execution:
|
|
660
|
+
|
|
661
|
+
```ts
|
|
662
|
+
const remote = font(new URL('https://example.com/fonts/SomeFont.ttf'));
|
|
663
|
+
const label = text('AV', remote, 10, {letterSpacing: 0.5, kerning: true});
|
|
664
|
+
```
|
|
665
|
+
|
|
666
|
+
Use a direct font-file URL whose server permits CORS access from the App. The URL
|
|
667
|
+
must be a literal in `new URL(...)`, including when declared in an imported module;
|
|
668
|
+
no `await` is needed in model code. The engine decodes remote WOFF2 files to SFNT
|
|
669
|
+
before synchronous font parsing.
|
|
670
|
+
|
|
671
|
+
Google Fonts can instead be selected by name:
|
|
672
|
+
|
|
673
|
+
```ts
|
|
674
|
+
import {googleFont, text, extrude, group} from '@code3d/core';
|
|
675
|
+
|
|
676
|
+
const play = googleFont('Play');
|
|
677
|
+
const medium = googleFont('Roboto', {weight: 450, italic: true});
|
|
678
|
+
export default group(extrude(text('Hello', play, 10), 1));
|
|
679
|
+
```
|
|
680
|
+
|
|
681
|
+
`googleFont(family, options?)` synchronously returns a `Font`. Both `weight` and
|
|
682
|
+
`italic` are optional. Omitted axes are omitted from the Google request, leaving
|
|
683
|
+
the defaults to Google; explicit weights apply to variable fonts as well as static
|
|
684
|
+
faces. The App prepares the CSS and all of its Unicode subsets before execution,
|
|
685
|
+
then selects the appropriate subset for each character. No stylesheet is installed.
|
|
686
|
+
The family and options must be literals or static `const` values, including imports,
|
|
687
|
+
aliases, object properties and spreads. Computed calls are reported at their source.
|
|
688
|
+
Large families such as Chinese fonts require downloading all returned subsets on
|
|
689
|
+
the first use; changing the text subsequently reuses those font resources.
|
|
690
|
+
|
|
691
|
+
Network resources use an engine-owned 64 MiB memory LRU and the shared OPFS disk
|
|
692
|
+
journal, then the network. CSS, compressed font bytes and content-addressed decoded
|
|
693
|
+
bytes are retained. The disk budget is the smaller of 1 GiB and 10% of the browser's
|
|
694
|
+
origin quota, including compaction space, shared with geometry. Fresh resources
|
|
695
|
+
need no request across edits or Worker/page restarts. Expired resources revalidate
|
|
696
|
+
through the browser HTTP cache; `no-store` resources are not retained. Concurrent
|
|
697
|
+
requests share one download. Failed or cancelled builds preserve completed resources;
|
|
698
|
+
partial downloads are discarded and can retry. Without OPFS, memory caching remains.
|
|
699
|
+
The active build's resource references are outside the historical memory limit.
|
|
700
|
+
|
|
701
|
+
Parsed fonts are memory-only entries in the existing 2 GiB kernel cache budget.
|
|
702
|
+
CSS interpretation, normalized glyph contours, B-Rep, bounds and meshes reuse the
|
|
703
|
+
existing memory/disk artifact cache. Font contents and requested variations identify
|
|
704
|
+
these artifacts; changing text position or spacing can reuse unchanged glyphs.
|
|
705
|
+
HTTP resource records remain reusable when the geometry runtime changes.
|
|
706
|
+
|
|
707
|
+
For computed URLs or Node execution outside the App engine, download TTF/OTF bytes
|
|
708
|
+
first (decode WOFF2 before passing its bytes):
|
|
709
|
+
|
|
710
|
+
```ts
|
|
711
|
+
const response = await fetch(fontUrl);
|
|
712
|
+
if (!response.ok) throw new Error(`Font download failed: ${response.status}`);
|
|
713
|
+
const remote = font(await response.arrayBuffer());
|
|
714
|
+
```
|
|
715
|
+
|
|
716
|
+
TTF and OTF fonts are supported, including variable fonts and Chinese characters
|
|
717
|
+
when present in the font. HarfBuzz supplies glyph outlines, advances, kerning and
|
|
718
|
+
ligatures. Quadratic/cubic curves are preserved, and overlapping contours within
|
|
719
|
+
a glyph use the non-zero fill rule. Font collections (TTC), color glyph rendering,
|
|
720
|
+
full bidirectional/multiscript paragraph layout and multiline text are outside this
|
|
721
|
+
API. Missing glyphs report an error. Empty text and spaces create no faces; spaces
|
|
722
|
+
still advance subsequent characters.
|
|
723
|
+
|
|
724
|
+
`text(content, font, size, options?)` requires the first three arguments and returns connected planar
|
|
725
|
+
regions as ordinary readonly `FaceModel[]`: `B` has one face with two holes; `i` has
|
|
726
|
+
two faces. Size is the font em in model units, not the cap height. Coordinates are
|
|
727
|
+
+X right, -Z up, normal +Y, with all faces retaining the same baseline origin.
|
|
728
|
+
Faces are never individually centered,
|
|
729
|
+
so `group(extrude(...))`, origin operations and boolean tools preserve the layout.
|
|
730
|
+
Use positive/negative extrusion and `union`/`cut` for raised or engraved lettering.
|
|
731
|
+
Text is currently code-defined geometry rather than an editable sketch entity.
|
|
732
|
+
|
|
733
|
+
`options.letterSpacing` defaults to `0` and adds a finite distance in model units
|
|
734
|
+
between laid-out glyphs, including spaces. Negative values tighten the text. The
|
|
735
|
+
distance stays constant when size changes, and disconnected parts of one glyph move
|
|
736
|
+
together. `options.kerning` defaults to `true`; set it to `false` to disable the
|
|
737
|
+
font's pair adjustments. Extra letter spacing is added after kerning. Supported
|
|
738
|
+
ligatures remain single glyphs for spacing purposes.
|
|
739
|
+
|
|
740
|
+
## Geometry measurements
|
|
741
|
+
|
|
742
|
+
`model.bounds(relativeTo?)` returns readonly `minimum`, `maximum` and `size`
|
|
743
|
+
XYZ vectors for tight finite geometry bounds. By default it uses the model's
|
|
744
|
+
own local frame. An explicit reference includes solved placement and nested
|
|
745
|
+
member occurrences in that reference's frame. Empty groups have no finite
|
|
746
|
+
bounds; a source occurring more than once in the reference is ambiguous.
|
|
747
|
+
|
|
748
|
+
`model.position(relativeTo)` returns the model origin in the explicit reference's
|
|
749
|
+
local frame. A model's origin in its own frame is always `[0, 0, 0]`, including
|
|
750
|
+
point models whose geometry may be offset from that origin. Neither query
|
|
751
|
+
changes the model or its placement. These methods are available on every model
|
|
752
|
+
kind, including groups. As model members, `bounds` and `position` are reserved
|
|
753
|
+
names and cannot be used as exposed element names.
|
|
754
|
+
|
|
755
|
+
```ts
|
|
756
|
+
import {box, group, offset} from '@code3d/core';
|
|
757
|
+
|
|
758
|
+
const base = box(20, 4, 20);
|
|
759
|
+
const part = box(8, 12, 4).relate(self => [self.on(base.up), offset(20, 0, 0)]);
|
|
760
|
+
const size = part.bounds().size; // [8, 12, 4]
|
|
761
|
+
const origin = part.position(base); // [20, 8, 0]
|
|
762
|
+
const minimum = part.bounds(base).minimum; // [16, 2, -2]
|
|
763
|
+
export default group([base, part]);
|
|
764
|
+
```
|