@code3d/core 0.0.1-alpha.0 → 0.0.1-alpha.11

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 (154) hide show
  1. package/README.md +43 -807
  2. package/THIRD_PARTY.md +40 -0
  3. package/bld/THIRD_PARTY_NOTICES.txt +182 -0
  4. package/bld/chunks/chunk-7FIFPADJ.js +1 -0
  5. package/bld/chunks/chunk-7FIFPADJ.js.map +7 -0
  6. package/bld/chunks/chunk-CL3E2DE4.js +19 -0
  7. package/bld/chunks/chunk-CL3E2DE4.js.map +7 -0
  8. package/bld/chunks/chunk-HZRQUHM2.js +30 -0
  9. package/bld/chunks/chunk-HZRQUHM2.js.map +7 -0
  10. package/bld/chunks/chunk-JBVIAMJ6.js +26474 -0
  11. package/bld/chunks/chunk-JBVIAMJ6.js.map +7 -0
  12. package/bld/chunks/chunk-QK6ZET47.js +31 -0
  13. package/bld/chunks/chunk-QK6ZET47.js.map +7 -0
  14. package/bld/library/bound-solver.d.ts +29 -5
  15. package/bld/library/bound-solver.d.ts.map +1 -1
  16. package/bld/library/cached.d.ts +35 -0
  17. package/bld/library/cached.d.ts.map +1 -0
  18. package/bld/library/font.d.ts +39 -0
  19. package/bld/library/font.d.ts.map +1 -0
  20. package/bld/library/google-font.d.ts +14 -0
  21. package/bld/library/google-font.d.ts.map +1 -0
  22. package/bld/library/index.d.ts +10 -2
  23. package/bld/library/index.d.ts.map +1 -1
  24. package/bld/library/index.js +94 -3
  25. package/bld/library/index.js.map +7 -1
  26. package/bld/library/inspect.d.ts +100 -0
  27. package/bld/library/inspect.d.ts.map +1 -0
  28. package/bld/library/kernel-artifact-codec.d.ts.map +1 -1
  29. package/bld/library/kernel-cache.d.ts +28 -7
  30. package/bld/library/kernel-cache.d.ts.map +1 -1
  31. package/bld/library/loft.d.ts.map +1 -1
  32. package/bld/library/material.d.ts +1 -1
  33. package/bld/library/material.d.ts.map +1 -1
  34. package/bld/library/open-cascade.d.ts +4 -0
  35. package/bld/library/open-cascade.d.ts.map +1 -0
  36. package/bld/library/relation-solver.d.ts +19 -8
  37. package/bld/library/relation-solver.d.ts.map +1 -1
  38. package/bld/library/replicad.d.ts +3 -2
  39. package/bld/library/replicad.d.ts.map +1 -1
  40. package/bld/library/replicad.js +10 -24
  41. package/bld/library/replicad.js.map +7 -1
  42. package/bld/library/retained-memory.d.ts.map +1 -1
  43. package/bld/library/runtime.d.ts +518 -155
  44. package/bld/library/runtime.d.ts.map +1 -1
  45. package/bld/library/sketch-solver.d.ts +1 -1
  46. package/bld/library/sketch-solver.d.ts.map +1 -1
  47. package/bld/library/sketch.d.ts +21 -1
  48. package/bld/library/sketch.d.ts.map +1 -1
  49. package/bld/library/text.d.ts +53 -0
  50. package/bld/library/text.d.ts.map +1 -0
  51. package/bld/library/three.js +3 -3
  52. package/bld/library/three.js.map +7 -1
  53. package/bld/library/topology.d.ts +6 -2
  54. package/bld/library/topology.d.ts.map +1 -1
  55. package/bld/node/index.d.ts.map +1 -1
  56. package/bld/node/index.js +96 -14
  57. package/bld/node/index.js.map +7 -1
  58. package/bld/node/replicad.js +13 -3
  59. package/bld/node/replicad.js.map +7 -1
  60. package/bld/tooling/index.d.ts +18 -15
  61. package/bld/tooling/index.d.ts.map +1 -1
  62. package/bld/tooling/index.js +165 -19
  63. package/bld/tooling/index.js.map +7 -1
  64. package/docs/api.md +764 -0
  65. package/docs/custom-primitives.mdx +58 -0
  66. package/docs/local-coordinates.md +187 -0
  67. package/docs/origins-and-rotation.mdx +105 -0
  68. package/docs/relations.mdx +450 -0
  69. package/docs/runtime.md +297 -0
  70. package/docs/shells.mdx +70 -0
  71. package/docs/sketches.md +83 -0
  72. package/docs/text.md +23 -0
  73. package/docs/topology.md +152 -0
  74. package/docs/values.md +119 -0
  75. package/package.json +20 -7
  76. package/src/library/bound-solver.ts +103 -73
  77. package/src/library/cached.ts +153 -0
  78. package/src/library/font.ts +186 -0
  79. package/src/library/google-font.ts +97 -0
  80. package/src/library/index.ts +53 -5
  81. package/src/library/inspect.ts +178 -0
  82. package/src/library/kernel-artifact-codec.ts +129 -20
  83. package/src/library/kernel-cache.ts +175 -39
  84. package/src/library/loft.ts +9 -1
  85. package/src/library/material.ts +3 -4
  86. package/src/library/open-cascade.ts +13 -0
  87. package/src/library/relation-solver.ts +230 -113
  88. package/src/library/replicad.ts +5 -5
  89. package/src/library/retained-memory.ts +6 -1
  90. package/src/library/runtime.ts +3769 -1178
  91. package/src/library/shell.ts +3 -3
  92. package/src/library/sketch-solver.ts +3 -1
  93. package/src/library/sketch.ts +112 -13
  94. package/src/library/text.ts +477 -0
  95. package/src/library/topology.ts +61 -17
  96. package/src/library/tsconfig.json +2 -1
  97. package/src/node/index.ts +14 -3
  98. package/src/node/tsconfig.json +2 -1
  99. package/src/tooling/index.ts +64 -51
  100. package/src/tooling/tsconfig.json +2 -1
  101. package/bld/library/alignment-geometry.js +0 -322
  102. package/bld/library/alignment-geometry.js.map +0 -1
  103. package/bld/library/bound-solver.js +0 -252
  104. package/bld/library/bound-solver.js.map +0 -1
  105. package/bld/library/extrude.js +0 -28
  106. package/bld/library/extrude.js.map +0 -1
  107. package/bld/library/kernel-artifact-codec.js +0 -148
  108. package/bld/library/kernel-artifact-codec.js.map +0 -1
  109. package/bld/library/kernel-cache.js +0 -245
  110. package/bld/library/kernel-cache.js.map +0 -1
  111. package/bld/library/kernel-shapes.js +0 -108
  112. package/bld/library/kernel-shapes.js.map +0 -1
  113. package/bld/library/loft.js +0 -161
  114. package/bld/library/loft.js.map +0 -1
  115. package/bld/library/material.js +0 -176
  116. package/bld/library/material.js.map +0 -1
  117. package/bld/library/model-color.js +0 -36
  118. package/bld/library/model-color.js.map +0 -1
  119. package/bld/library/open-cascade-error.js +0 -22
  120. package/bld/library/open-cascade-error.js.map +0 -1
  121. package/bld/library/relation-solver.js +0 -258
  122. package/bld/library/relation-solver.js.map +0 -1
  123. package/bld/library/retained-memory.js +0 -27
  124. package/bld/library/retained-memory.js.map +0 -1
  125. package/bld/library/runtime.js +0 -2954
  126. package/bld/library/runtime.js.map +0 -1
  127. package/bld/library/shell.js +0 -221
  128. package/bld/library/shell.js.map +0 -1
  129. package/bld/library/sketch-curve-intersections.js +0 -117
  130. package/bld/library/sketch-curve-intersections.js.map +0 -1
  131. package/bld/library/sketch-curves.js +0 -89
  132. package/bld/library/sketch-curves.js.map +0 -1
  133. package/bld/library/sketch-drag-rules.js +0 -522
  134. package/bld/library/sketch-drag-rules.js.map +0 -1
  135. package/bld/library/sketch-face.js +0 -72
  136. package/bld/library/sketch-face.js.map +0 -1
  137. package/bld/library/sketch-incidence.js +0 -114
  138. package/bld/library/sketch-incidence.js.map +0 -1
  139. package/bld/library/sketch-precision.js +0 -55
  140. package/bld/library/sketch-precision.js.map +0 -1
  141. package/bld/library/sketch-regions.js +0 -193
  142. package/bld/library/sketch-regions.js.map +0 -1
  143. package/bld/library/sketch-solver.js +0 -578
  144. package/bld/library/sketch-solver.js.map +0 -1
  145. package/bld/library/sketch.js +0 -650
  146. package/bld/library/sketch.js.map +0 -1
  147. package/bld/library/spatial.js +0 -195
  148. package/bld/library/spatial.js.map +0 -1
  149. package/bld/library/topology-id.js +0 -67
  150. package/bld/library/topology-id.js.map +0 -1
  151. package/bld/library/topology-inspection.js +0 -267
  152. package/bld/library/topology-inspection.js.map +0 -1
  153. package/bld/library/topology.js +0 -455
  154. package/bld/library/topology.js.map +0 -1
@@ -0,0 +1,58 @@
1
+ ---
2
+ title: Building custom primitives
3
+ description: Bring a Replicad solid into Code3D with normal model capabilities and parameter tools.
4
+ sidebar:
5
+ order: 10
6
+ ---
7
+
8
+ import ModelExample from '../../web/src/components/ModelExample.astro';
9
+
10
+ Start with the built-in [modeling operations](api.md) when they
11
+ fit the part. For other solid geometry, `definePrimitive` wraps a synchronous
12
+ Replicad builder as a normal Code3D model.
13
+
14
+ Import both `definePrimitive` and `replicad` from `@code3d/core/replicad`.
15
+ The builder returns one solid; the result supports the usual `material`,
16
+ `relate`, `expose`, fillet, and chamfer operations.
17
+
18
+ ## A twisted knob with a shaft bore
19
+
20
+ This example extrudes a hexagonal profile with a twist, cuts a D-shaped bore,
21
+ and places two instances on a base. Its `@code3d.param` annotations make the
22
+ dimensions and twist angle available in call-site panels.
23
+
24
+ <ModelExample id="custom-primitives" />
25
+
26
+ Open the example and place the cursor in either `twistKnob(...)` call to
27
+ adjust its inputs. The short knob supplies a twist of 30°; the tall one uses
28
+ the builder's default of 60°. The twist annotation also declares `default: 60`,
29
+ so the tall knob's panel shows that value as a placeholder. Typing a number
30
+ adds an explicit twist argument; simply opening the panel leaves it omitted.
31
+
32
+ ## Return a model, own the intermediate geometry
33
+
34
+ Returning the solid transfers it to Code3D. Do not delete, mutate, or return
35
+ that same shape again. Intermediate Replicad resources remain the builder's
36
+ responsibility; the example uses `localGC()` and `finally` to release them.
37
+ Some Replicad operations consume their inputs, so resource handling follows
38
+ the operations used.
39
+
40
+ Validate dimensions inside the builder. A single-solid aggregate from a
41
+ Replicad boolean can be normalized, but multiple solids, shells, or aggregates
42
+ with stray lower-dimensional geometry are rejected.
43
+
44
+ `definePrimitive()` caches deterministic construction by definition and arguments,
45
+ including validation, normalization, topology and bounds. A hit skips the builder
46
+ and creates a fresh model with its own shape handles and source tracing. Pass all
47
+ changing captured state as explicit arguments. The App fingerprints static
48
+ builders and their dependencies for persistent reuse; dynamic closures and
49
+ ordinary Node calls use function object identity for memory reuse.
50
+
51
+ Primitives share the same memory and disk budgets as Core computations and
52
+ Screws. Use [`cache()`](api.md#cached-computations) for ordinary
53
+ data computations; geometry needs `definePrimitive()` so Core manages its native
54
+ resources.
55
+
56
+ Your function stays ordinary TypeScript and can be exported for other modules.
57
+ See [adding tools to model functions](../../web/src/content/docs/docs/guides/model-tools.mdx) for annotation rules and
58
+ [reusable models](../../web/src/content/docs/docs/guides/reusable-models.mdx) for naming attachment points.
@@ -0,0 +1,187 @@
1
+ ---
2
+ title: Local coordinates and placement
3
+ description: Understand positions, origin offsets, model axes, and where a part sits in a composition.
4
+ sidebar:
5
+ order: 3
6
+ ---
7
+
8
+ Every model has its own local coordinates. Its origin is `[0, 0, 0]`.
9
+ The geometry can be away from that origin: a point at `[10, 0, 0]` still
10
+ belongs to a model whose origin is zero.
11
+
12
+ ## Positions, dimensions, and displacements
13
+
14
+ Use coordinate arrays for positions and separate numbers for dimensions,
15
+ displacements, and angles:
16
+
17
+ | Expression | Meaning |
18
+ | ------------------------------ | ---------------------------------------------------- |
19
+ | `box(10, 20, 30)` | Dimensions along local X, Y, and Z; centered at zero |
20
+ | `point()` | A point at local zero |
21
+ | `point([10, 2, -3])` | A point at the supplied local coordinates |
22
+ | `line([10, 0, 0])` | A line from zero to the supplied endpoint |
23
+ | `line([10, 0, 0], [20, 0, 0])` | A line between two local positions |
24
+ | `originOffset(10, 0, 0)` | Move the origin by a local displacement |
25
+ | `pivot([10, 0, 0])` | Choose a rotation center in self's local coordinates |
26
+ | `offset(10, 0, 0)` | Move a relate result along fixed composition axes |
27
+ | `rotate(0, 90, 0)` | Rotate geometry by 90° around local Y |
28
+
29
+ Curve control points use the returned model's local coordinates too. A common
30
+ offset in their coordinates is retained; the curve does not automatically move
31
+ its start or center to zero.
32
+
33
+ ## Default origin rules
34
+
35
+ Constructors define a local coordinate frame. Derived operations inherit their
36
+ main input's frame; they do not automatically recenter the resulting geometry.
37
+ Only an explicit origin operation chooses a different local zero.
38
+
39
+ | Constructor or operation | Origin and coordinate frame |
40
+ | ------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------ |
41
+ | `box`, `sphere`, `circle`, `ellipse`, `rectangle` | Geometry is constructed around local zero. |
42
+ | `cylinder`, `tube`, `frustum`, `regularPrism` | The central axis passes through zero; height is centered on Y. This is not a center-of-mass rule. |
43
+ | `regularPolygon` | The polygon's construction-circle center, which need not equal its bounding-box center. |
44
+ | `coil` | The helix axis passes through zero; the centerline's axial span is centered on Y. |
45
+ | `point`, `line`, `arc`, `bezier`, `spline` | Retain the supplied coordinates relative to zero; neither endpoints nor curve centers are automatically moved to zero. |
46
+ | Faces made from a sketch | Retain the sketch's local frame. |
47
+ | `text` | All returned faces share the text layout's baseline origin, including its glyph advances and offsets. Individual letters are not centered. |
48
+ | `definePrimitive` | Retain the frame used by the returned geometry; no automatic recentering. |
49
+ | `extrude` | Inherit the input face's frame, without centering the extrusion. |
50
+ | `union`, `intersect` | Inherit the first operand's frame. |
51
+ | `cut` | Inherit the stock's frame. |
52
+ | `loft` | Inherit the first section's frame. |
53
+ | `group` | Inherit the first member's frame after solving placement; an empty group uses the default frame. |
54
+ | `rotate`, `scaled`, `fillet`, `chamfer`, `shell` | Retain the input model's frame, even when its geometric bounds change. |
55
+ | `relate`, `material`, `expose` | Retain the model's local frame; relations describe its placement within a composition. |
56
+
57
+ For example, `point([10, 0, 0])` has geometry at X = 10 and an origin at zero.
58
+ Similarly, `rectangle(10, 10).extrude(20)` keeps its origin on the starting
59
+ plane, while `box(10, 20, 10)` is centered on its origin.
60
+
61
+ Explicit choices are `originOffset(dx, dy, dz)` for a displacement,
62
+ `originPoint(pointRef)` for a referenced point, `originVertex(id)` for an own
63
+ topology vertex, and `originCenter()` for the existing center anchor. The last
64
+ two require geometry and are not available on groups. A carried center anchor
65
+ is not necessarily the center of the current axis-aligned bounding box.
66
+
67
+ ## Coordinate references
68
+
69
+ Every model, including a group, provides `model.frame`, a reference to its local
70
+ coordinate system. `model.frame.origin` references that frame's zero point;
71
+ `model.origin` is the same reference. Neither is a geometric model.
72
+ For `point([10, 0, 0])`, the geometry is at X = 10 while its frame origin is zero.
73
+ Changing local geometry with `rotate()` does not rotate the model's coordinate
74
+ axes. Placement through `relate()` determines the frame's pose in a composition.
75
+
76
+ Use `self.origin.align(other.origin)` to coincide just the origins, or
77
+ `self.frame.align(other.frame)` to coincide both origins and all three axes.
78
+ Coordinate references can be named with `expose`; an exposed frame and its
79
+ `.origin` follow the selected occurrence through nested groups and transforms.
80
+ A newly read `model.origin` always references the current local zero. Previously
81
+ selected references retain their meaning through subsequent origin edits.
82
+
83
+ ## Changing the origin changes point coordinates
84
+
85
+ `originOffset(dx, dy, dz)` chooses a new origin at that displacement in the
86
+ input model. In the result, that origin is zero and each point has coordinates:
87
+
88
+ ```text
89
+ p_new = p_old - [dx, dy, dz]
90
+ ```
91
+
92
+ For example, the point in `point([10, 2, -3]).originOffset(4, 0, 0)` is at
93
+ `[6, 2, -3]`. Conversely, `point().originOffset(-10, -2, 3)` creates the same
94
+ local geometry as `point([10, 2, -3])`.
95
+
96
+ The shape and distances between points stay the same. Geometry, `center`,
97
+ named anchors, and topology positions use the new coordinates together.
98
+ Directions and normals keep their direction. The operation returns a new
99
+ model value and preserves topology IDs; earlier values and references retain
100
+ their meaning. Successive origin offsets add and opposite offsets cancel.
101
+
102
+ Use `originPoint(pointRef)` on any model to make a referenced point zero.
103
+ For geometric models, `originVertex(id)` selects an own topology vertex and
104
+ `originCenter()` selects the carried center anchor. The [origin and rotation guide](origins-and-rotation.mdx)
105
+ shows how to select and drag these in the viewport.
106
+
107
+ ## The origin, center, and axes have different roles
108
+
109
+ `line([10, 0, 0])` has its origin at zero and its midpoint at `[5, 0, 0]`.
110
+ Rotating it with `.rotate(0, 90, 0)` gives a line from zero to `[0, 0, -10]`.
111
+ Calling `.originCenter()` first puts the endpoints at `[-5, 0, 0]` and
112
+ `[5, 0, 0]`, so the same rotation now turns the line around its midpoint.
113
+
114
+ Geometric `rotate()` and `scaled()` act around the current local zero.
115
+ The `center` anchor follows these transformations; rotation does not replace
116
+ it with the center of the new axis-aligned bounding box.
117
+
118
+ The model's XYZ axes remain its local coordinate axes. `up` means local +Y
119
+ even after the geometry rotates. A line's tangent or a face's normal belongs
120
+ to that geometric reference and can point in a different direction. Relation
121
+ offsets use the target reference's axes; an explicit `pivot([x, y, z])` uses
122
+ self's model coordinates. See [relations](relations.mdx) for those
123
+ placement rules.
124
+
125
+ ## Placing a part in a composition
126
+
127
+ `relate()` describes placement relative to other parts. Inspect a related
128
+ part by itself to see its local geometry; inspect the relation or a consuming
129
+ composition to see the solved placement. An `originOffset()` changes the
130
+ part's local geometry coordinates, while a relation's `offset()` participates
131
+ in its placement conditions.
132
+
133
+ Several relations on one model are solved together. Their offsets belong to
134
+ those conditions, and any remaining freedom uses the solver's default result.
135
+ See [combining conditions](relations.mdx#combine-conditions) before
136
+ using an offset in a system with multiple relations.
137
+
138
+ New model values also have a coordinate frame:
139
+
140
+ - A boolean result uses the main operand's local coordinates.
141
+ - A loft uses its first section's local coordinates.
142
+ - A group uses its first member's local coordinates, retaining relative placement.
143
+ - `expose()` brings a reference into the outer model's local space. For a
144
+ repeated part, use the reference from its specific instance.
145
+
146
+ Export uses these same coordinates: a standalone part has local geometry,
147
+ and a composition includes its parts' resolved placement. The chosen output
148
+ scale and up axis are applied afterward. See [exporting models](../../web/src/content/docs/docs/guides/exporting.md).
149
+
150
+ ## Group origins
151
+
152
+ A group first solves the placement of its direct members, then expresses all
153
+ members in the **first member's local coordinate frame**, including its origin
154
+ and axes. This is the same reference rule used by `union`, `intersect`, and
155
+ `loft`; `cut` uses the stock's frame. Reordering members can change the group's
156
+ frame, while preserving their relative placement. A nested group is one member,
157
+ with its own existing frame. An empty group uses the default origin and axes.
158
+ A relation's rotation affects that solved member frame; rotating the member's
159
+ geometry directly with `.rotate()` does not redefine its local axes.
160
+
161
+ ```ts
162
+ import {box, group} from '@code3d/core';
163
+
164
+ const base = box(20, 4, 10).originOffset(0, 2, 0);
165
+ const lid = box(20, 2, 10).originOffset(0, -1, 0);
166
+ const assembly = group([base, lid]);
167
+ const mounted = assembly.originPoint(lid.center);
168
+ ```
169
+
170
+ Here the unrestrained member origins coincide at the contact plane. That point
171
+ becomes the group origin. `originPoint(lid.center)` chooses the lid's center in
172
+ the assembled coordinates; `originOffset()` can then shift it further. Both
173
+ operations re-express the whole group, preserving member spacing and internal
174
+ relations. The default is chosen once and does not overwrite explicit edits.
175
+
176
+ Changing the first member's origin before constructing a new group changes the
177
+ reference frame, even if constraints keep its physical geometry in place.
178
+ Changing a later member's origin does not select a different reference member;
179
+ its placement still follows the assembly constraints.
180
+ Within an existing model, origin edits also update its own stored relation
181
+ references, so a constraint on a selected geometric point still follows that
182
+ same point.
183
+
184
+ For repeated geometry, select an instance's named reference, such as
185
+ `assembly.originPoint(rightPart.body.center)`. A reference to the shared source
186
+ alone is ambiguous and is rejected. The same instance resolution applies to
187
+ `expose()`.
@@ -0,0 +1,105 @@
1
+ ---
2
+ title: Choosing an origin and rotating a part
3
+ description: Set a pivot, rotate geometry, and adjust both directly in the viewport.
4
+ sidebar:
5
+ order: 5
6
+ ---
7
+
8
+ import ModelExample from '../../web/src/components/ModelExample.astro';
9
+
10
+ The origin defines local coordinates and is always zero in the resulting model.
11
+ An origin offset `d` changes every point coordinate from `p` to `p - d`, preserving
12
+ the shape. `rotate` turns the geometry around that local zero; a
13
+ [relation](relations.mdx) places the resulting part in a composition. For
14
+ positions, dimensions, and reference axes, start with
15
+ [local coordinates and placement](local-coordinates.md).
16
+
17
+ <ModelExample id="rotate" />
18
+
19
+ The [rotation example](/examples/rotate/) focuses on `rotate` alone.
20
+ The companion [origin source](https://github.com/vilicvane/code3d/blob/main/packages/app/examples/operations/origin.ts)
21
+ lets you inspect the origin operations below independently.
22
+
23
+ ## Choose a pivot
24
+
25
+ Place the cursor in `blank.originVertex(3)`. Pick a vertex in the viewport to
26
+ use it as the origin. The ID belongs to the operation's input model, just like
27
+ other [topology selections](topology.md).
28
+
29
+ Use `.originPoint(pointRef)` to select a center, named point, or topology vertex
30
+ on any model, including a group member. Use `.originOffset(dx, dy, dz)` to move the origin by a displacement or `.originCenter()` to make
31
+ the body's center local zero. `originVertex()` similarly makes the chosen
32
+ vertex zero. These operations return new model values; `blank` is unchanged.
33
+
34
+ ## Fine-tune the origin
35
+
36
+ Move to `pivoted.originOffset(0, 2, 0)` and drag an axis arrow. The origin
37
+ marker moves against the snapshot captured at drag start. On release, the
38
+ geometry switches to the resulting coordinates and the marker returns to local
39
+ zero. Offsets accumulate across calls.
40
+
41
+ You can also drag the origin marker's arrows while inspecting `originPoint`, `originVertex`
42
+ or `originCenter`. The App adds or updates an `originOffset(...)` call so the
43
+ chosen vertex or center remains the starting point.
44
+
45
+ ## Rotate the part
46
+
47
+ In the rotation example, move to `blank.rotate(15, 35, 0)` and drag a rotation ring, or enter an angle
48
+ in the panel. Angles are in degrees, applied around fixed local X, then Y,
49
+ then Z axes. Each ring follows the effective axis of its angle parameter;
50
+ the rings need not line up with the world axes when other angles are nonzero.
51
+
52
+ Repeated `rotate` calls compose in source order. Named references
53
+ rotate with the shape, and topology IDs are preserved. Changing the origin
54
+ afterward does not undo an earlier rotation.
55
+
56
+ ## Recenter without undoing the rotation
57
+
58
+ After a rotation, `.originCenter()` recenters the result. The `center` anchor follows the body's
59
+ transforms; it is not recalculated from the rotated shape's axis-aligned
60
+ bounding box. A subsequent `originOffset(0, 2, 0)` moves the pivot beyond that center.
61
+
62
+ Applying `originOffset(0, -2, 0)` cancels that last offset. The center is again
63
+ local zero, and the shape retains its rotation.
64
+
65
+ ## Compose with other parts
66
+
67
+ Origin operations, `rotate()` and `scaled()` preview their own returned value.
68
+ Their ordinary preview does not add downstream consumers. Select the inputs of
69
+ `group`, `union`, `cut`, `intersect` or `loft` to inspect the context declared by
70
+ that operation's public inspector. A standalone model uses its local frame;
71
+ an ordinary collection retains its members' shared composition positions.
72
+
73
+ Inspectors can retain the pose at the selected operation, so later transformations
74
+ do not replace its geometry or stage. See [source inspection](runtime.md#source-inspection)
75
+ for the common rules and custom JSDoc callbacks.
76
+
77
+ A relation such as `companion.relate(part => part.on(rotated.up))` can place
78
+ a companion against a rotated part before grouping them. Inspecting the companion by itself uses its local
79
+ frame, without its assembly placement.
80
+
81
+ Origin edits update the local coordinates of geometry, bounds and named
82
+ references together. The model's `up` direction remains local +Y even after
83
+ geometry rotates. For a rotation that only affects composition, use a
84
+ [constraint pivot or axis](relations.mdx#choose-a-rotation-pivot-or-axis), with
85
+ coordinates written as `pivot([x, y, z])`.
86
+
87
+ ## Finish or cancel a drag
88
+
89
+ Dragging previews the change. Release to write it to source, or press `Esc`
90
+ before releasing to cancel. Cancellation keeps the panel and editor position;
91
+ move the cursor out of the call to leave its tool. Use Undo for an edit already
92
+ written to source.
93
+
94
+ When possible, a drag changes a unique safe upstream parameter. Otherwise it
95
+ adjusts the current expression by a numeric increment. Entering a number in a
96
+ panel can instead replace that expression: see
97
+ [what a panel can edit](../../web/src/content/docs/docs/guides/model-tools.mdx#what-a-panel-can-edit).
98
+
99
+ Solids, faces, curves, and points provide all these operations. Groups provide
100
+ `originPoint()`, `originOffset()` and `rotate()`; their default origin comes from the first member's local coordinate frame. See [group origins](local-coordinates.md#group-origins)
101
+ for direct assembly and instance selection. To rotate the whole assembly about
102
+ a member point, use `assembly.originPoint(part.center).rotate(0, 0, 30)`. Its
103
+ internal placements remain intact, including nested groups; angle inputs and
104
+ rotation rings work the same way as on a single part. See the [API reference](api.md#origins-and-rotation)
105
+ for the complete method list.