forgecad 0.9.5 → 0.9.7

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 (86) hide show
  1. package/dist/assets/{AdminPage-uTtcSXtn.js → AdminPage-DX0mpSZT.js} +1 -1
  2. package/dist/assets/{BlogPage-DYJMjWx3.js → BlogPage-CI_P0_Pf.js} +1 -1
  3. package/dist/assets/{DocsPage-C58f0K5v.js → DocsPage-DLhIIZyJ.js} +3 -3
  4. package/dist/assets/EditorApp-BujZvuwX.js +12874 -0
  5. package/dist/assets/{EditorApp-DS0AIUrZ.css → EditorApp-DfFT2Dn8.css} +1 -0
  6. package/dist/assets/{EmbedViewer-CMXWA2LX.js → EmbedViewer-0S0qXKog.js} +2 -2
  7. package/dist/assets/{LandingPageProofDriven-CAu2OZFn.js → LandingPageProofDriven-O_yMtAri.js} +1 -1
  8. package/dist/assets/{PricingPage-BIgW7m3X.js → PricingPage-DGkX3Ahr.js} +1 -1
  9. package/dist/assets/{SettingsPage-N1l1tMXO.js → SettingsPage-DBsqTB_y.js} +82 -22
  10. package/dist/assets/{app-CFy7g5WP.js → app-BE2nD6Yz.js} +1246 -191
  11. package/dist/assets/cli/{render-BrVVdj_T.js → render-iP9qh475.js} +841 -586
  12. package/dist/assets/{evalWorker-c_SB9gg3.js → evalWorker-Ds5U4xtN.js} +2732 -112
  13. package/dist/assets/inspectWorker-Dll4eVyD.js +12620 -0
  14. package/dist/assets/{manifold-Dp6pvFr6.js → manifold-Bk26ViCr.js} +1 -1
  15. package/dist/assets/{manifold-CRoBhJKH.js → manifold-DjYsd7A_.js} +2 -2
  16. package/dist/assets/{manifold-Cjk7WhRs.js → manifold-sJ-axdXM.js} +1 -1
  17. package/dist/assets/{renderSceneState-3DfsSASX.js → renderSceneState-Bngp5MrQ.js} +1 -1
  18. package/dist/assets/{reportWorker-BLkuIoS8.js → reportWorker-CU8RZ4O0.js} +2715 -112
  19. package/dist/assets/{sectionPlaneMath-CykEnkvQ.js → sectionPlaneMath-BdTjyVfs.js} +3213 -252
  20. package/dist/cli/render.html +1 -1
  21. package/dist/docs/index.html +1 -1
  22. package/dist/docs-raw/AI/usage.md +7 -2
  23. package/dist/docs-raw/CLI.md +82 -53
  24. package/dist/docs-raw/beta-operations.md +9 -0
  25. package/dist/docs-raw/coding.md +1 -1
  26. package/dist/docs-raw/deployment.md +38 -23
  27. package/dist/docs-raw/generated/concepts.md +141 -7
  28. package/dist/docs-raw/generated/core.md +206 -1
  29. package/dist/docs-raw/generated/curves.md +97 -5
  30. package/dist/docs-raw/generated/lib.md +17 -1
  31. package/dist/docs-raw/generated/sketch.md +9 -1
  32. package/dist/docs-raw/generated/viewport.md +1 -1
  33. package/dist/docs-raw/guides/inspection-bundles.md +45 -16
  34. package/dist/docs-raw/platform/auth.md +2 -0
  35. package/dist/docs-raw/platform/google-oauth-setup.md +4 -0
  36. package/dist/docs-raw/runbook.md +3 -3
  37. package/dist/docs-raw/skills/forgecad-make-a-model.md +87 -8
  38. package/dist/docs-raw/skills/forgecad-prepare-prompt.md +14 -6
  39. package/dist/docs-raw/skills/forgecad-render-inspect.md +1 -1
  40. package/dist/docs-raw/skills/index.md +2 -2
  41. package/dist/index.html +1 -1
  42. package/dist/sitemap.xml +6 -6
  43. package/dist-cli/forgecad.js +8725 -4747
  44. package/dist-cli/forgecad.js.map +1 -1
  45. package/dist-skill/CONTEXT.md +375 -25
  46. package/dist-skill/docs/CLI.md +82 -53
  47. package/dist-skill/docs/generated/core.md +206 -1
  48. package/dist-skill/docs/generated/curves.md +97 -5
  49. package/dist-skill/docs/generated/lib.md +17 -1
  50. package/dist-skill/docs/generated/sketch.md +9 -1
  51. package/dist-skill/docs/generated/viewport.md +1 -1
  52. package/dist-skill/docs/guides/inspection-bundles.md +45 -16
  53. package/dist-skill/docs-dev/CLI.md +82 -53
  54. package/dist-skill/docs-dev/coding.md +1 -1
  55. package/dist-skill/docs-dev/generated/core.md +206 -1
  56. package/dist-skill/docs-dev/generated/curves.md +97 -5
  57. package/dist-skill/docs-dev/generated/lib.md +17 -1
  58. package/dist-skill/docs-dev/generated/sketch.md +9 -1
  59. package/dist-skill/docs-dev/generated/viewport.md +1 -1
  60. package/dist-skill/docs-dev/guides/inspection-bundles.md +45 -16
  61. package/dist-skill/library/forgecad-make-a-model/SKILL.md +87 -8
  62. package/dist-skill/library/forgecad-prepare-prompt/SKILL.md +14 -6
  63. package/dist-skill/library/forgecad-prepare-prompt/references/default-profiles.md +5 -3
  64. package/dist-skill/library/forgecad-prepare-prompt/references/master-prompt.md +7 -5
  65. package/dist-skill/library/forgecad-render-inspect/SKILL.md +1 -1
  66. package/examples/api/bolted-service-cover.forge.js +17 -0
  67. package/examples/api/cable-gland-anchor.forge.js +14 -0
  68. package/examples/api/captured-cartridge-guide.forge.js +14 -0
  69. package/examples/api/captured-linear-slide.forge.js +13 -0
  70. package/examples/api/clevis-pin-joint.forge.js +13 -0
  71. package/examples/api/datum-enclosure.forge.js +16 -0
  72. package/examples/api/guided-loft-olive-oil-bottle.forge.js +135 -0
  73. package/examples/api/hose-barb-port.forge.js +14 -0
  74. package/examples/api/intentional-overlap-overmold.forge.js +16 -0
  75. package/examples/api/knuckled-hinge-assembly.forge.js +15 -0
  76. package/examples/api/living-hinge-cover.forge.js +14 -0
  77. package/examples/api/pcb-terminal-block.forge.js +22 -0
  78. package/examples/api/pinned-lever-pivot-stack.forge.js +14 -0
  79. package/examples/api/retained-shaft-knob-stack.forge.js +15 -0
  80. package/examples/api/routed-tube-clip.forge.js +15 -0
  81. package/examples/api/seated-bearing-stack.forge.js +30 -0
  82. package/examples/api/snap-latch-cover.forge.js +14 -0
  83. package/examples/api/static-assembly-connectors.forge.js +14 -16
  84. package/examples/api/thumb-screw-clamp.forge.js +15 -0
  85. package/package.json +20 -2
  86. package/dist/assets/EditorApp-DNH1TEz1.js +0 -12729
@@ -366,7 +366,7 @@ Mock objects appear in the viewport and spatial analysis when you run a file dir
366
366
 
367
367
  The shape is returned unchanged, so you can reference it for alignment, dimensioning, and `verify` checks.
368
368
 
369
- Mock objects participate in `forgecad run` collision detection and spatial analysis. Their names appear with a `(mock)` suffix in reports.
369
+ Mock objects participate in `forgecad run --spatial bounded|exact` collision detection and spatial analysis. Their names appear with a `(mock)` suffix in reports.
370
370
 
371
371
  In the viewport, mock objects render at reduced opacity so they are visually distinct from real geometry.
372
372
 
@@ -26,7 +26,7 @@ cross-sections.
26
26
  forgecad render inspect examples/api/static-assembly-connectors.forge.js --channels rgb,mask
27
27
  forgecad render inspect model.forge.js out/model-inspect --channels rgb,section --force
28
28
  forgecad render inspect model.forge.js --channels rgb,mask,section
29
- forgecad render inspect model.forge.js --channels collisions --focus Bench
29
+ forgecad render inspect model.forge.js --channels collisions --focus "Bench.*"
30
30
  forgecad render inspect model.forge.js --channels rgb,mask --hide "Bench.Slat0,Bench.Slat1"
31
31
  forgecad render inspect model.forge.js --channels thickness --min-thickness 1.2 --warn-thickness 2.0
32
32
  forgecad render inspect channels
@@ -43,7 +43,9 @@ question so heavy analyses do not run unnecessarily.
43
43
  `--focus` and `--hide` use the same object-name filtering semantics as
44
44
  `forgecad run` and `forgecad render 3d`. A bare `--focus` hides mock objects;
45
45
  `--focus name1,name2` emits only matching objects; `--hide name1,name2` removes
46
- matching objects from an otherwise visible scene.
46
+ matching objects from an otherwise visible scene. Matching is case-insensitive
47
+ and supports `*` / `?` globs, so grouped child objects are usually best matched
48
+ with patterns such as `Bench.*`.
47
49
 
48
50
  ## Bundle Layout
49
51
 
@@ -148,6 +150,12 @@ defects. Use this channel to spot spiky tessellation, accidental faceting,
148
150
  jagged boolean residue, and dense sharp-corner regions without losing the
149
151
  silhouette of otherwise smooth surfaces.
150
152
 
153
+ The channel also writes `channels/roughness/point-cloud.json`. Each point sample
154
+ stores object identity, object-local position, normal, dihedral angle, class,
155
+ RGB color, and represented surface area. The PNG renders those samples over
156
+ muted source geometry so the visual evidence stays point-level instead of
157
+ painting a whole object.
158
+
151
159
  `mask` emits one object-color image per view. Black is background. Non-black
152
160
  pixels resolve through `manifest.channels.mask.objects`, which includes object
153
161
  index, RGB color, object id, name, group, tree path, and mock flag. Edge pixels
@@ -161,9 +169,9 @@ background. Non-black pixels resolve through
161
169
  Connectivity is computed from visible scene objects:
162
170
 
163
171
  ```text
164
- bbox overlap edge = bbox interiors overlap
165
- touching edge = bbox contact gap <= 0.05 model units
166
- component = transitive closure over overlap/touching edges
172
+ bbox candidate = bbox interiors overlap or bbox contact gap <= 0.05 model units
173
+ overlap edge = exact boolean intersection volume > 0.1 model units^3
174
+ component = transitive closure over exact overlap edges
167
175
  ```
168
176
 
169
177
  The manifest stores the edge list, component list, per-object body counts, and
@@ -172,8 +180,11 @@ multiple disconnected kernel bodies and the caller supplied a body count, the
172
180
  manifest reports `bodyCount > 1` but the PNG cannot color those internal bodies
173
181
  separately yet.
174
182
 
175
- Connectivity is a fast bbox-neighborhood graph. Use the `collisions` channel
176
- when you need exact positive-volume boolean overlap evidence.
183
+ Connectivity uses bbox only as a broadphase. Bbox contact is not enough to merge
184
+ separate scene objects, which keeps concave assemblies such as cages and captive
185
+ balls from being falsely colored as one component. Use the `collisions` channel
186
+ when you need positive-volume overlap evidence as a defect report rather than a
187
+ component grouping.
177
188
 
178
189
  `distance` emits one rooted physical-component-distance heatmap per view. Black
179
190
  is background. Non-black pixels resolve through
@@ -190,9 +201,15 @@ root = largest component by body count, object count, then bbox volume
190
201
  rootDistance = shortest accumulated gap distance from root component
191
202
  ```
192
203
 
204
+ For large scenes the manifest does not materialize the complete component gap
205
+ graph, because that graph is quadratic in the number of components. The
206
+ `gapEdgeCount` field reports the logical complete-graph edge count used by the
207
+ analysis. `gapEdges` stores a compact evidence subset containing nearest-gap
208
+ and root-parent edges.
209
+
193
210
  The PNG colors components from green at the root/near distances through yellow to
194
211
  red at the farthest rooted component. The manifest stores the root component,
195
- maximum rooted distance, complete component gap edge list, nearest-gap data, and
212
+ maximum rooted distance, compact gap edge evidence, nearest-gap data, and
196
213
  shortest-path parent fields. The current v1 metric is bbox-based: it measures air
197
214
  gaps between component bounding boxes, not exact closest mesh-surface distance.
198
215
 
@@ -209,16 +226,17 @@ collision = boolean intersection volume > 0.1mm^3
209
226
  ```
210
227
 
211
228
  The manifest stores the inspected objects, collision pair names/ids, overlap
212
- volume, warnings, render style, and each collision finding's `groupIndex`,
213
- `color`, and `hex`. Exact interior pixels can be matched against
229
+ volume, broadphase counters, warnings, render style, and each collision finding's
230
+ `groupIndex`, `color`, and `hex`. Exact interior pixels can be matched against
214
231
  `manifest.channels.collisions.collisions[].color`; antialiased edges may blend
215
232
  with the ghosted source geometry. If `--focus PartA,PartB` is used, everything
216
233
  except those objects is hidden, `PartA` and `PartB` are ghosted, and their
217
234
  overlap volume is highlighted if present.
218
235
 
219
- `thickness` emits one local wall-thickness heatmap per view. The renderer
220
- samples visible mesh triangles, casts through the object along each triangle
221
- normal, and colors the surface by the first opposite-surface distance:
236
+ `thickness` emits one local wall-thickness heatmap per view. The renderer places
237
+ deterministic area-weighted point samples across visible mesh surfaces, casts
238
+ through the object along each sample normal, and colors each point by the first
239
+ opposite-surface distance:
222
240
 
223
241
  ```text
224
242
  red = thickness <= minThickness
@@ -231,7 +249,7 @@ gray = unresolved sample
231
249
  The default thresholds are `minThickness=1.2`, `warnThickness=2.0`, and
232
250
  `maxThickness=6.0` model units. Override them with `--min-thickness`,
233
251
  `--warn-thickness`, and `--max-thickness`. Use `--thickness-samples` to raise or
234
- lower the maximum sampled triangles per object.
252
+ lower the maximum thickness point samples per object.
235
253
 
236
254
  The manifest stores the method, thresholds, palette, object list, per-object
237
255
  triangle counts, sampled-triangle counts, minimum, p05, median, mean, maximum,
@@ -239,6 +257,17 @@ critical-area percentage, warning-area percentage, below-warning percentage, and
239
257
  unresolved-area percentage. This makes the PNG useful for visual debugging while
240
258
  the manifest remains the machine-readable source of truth.
241
259
 
260
+ The channel also writes `channels/thickness/point-cloud.json`. Each point sample
261
+ stores object identity, object-local position, normal, measured thickness,
262
+ class, RGB color, and represented surface area. The PNG renders those samples
263
+ over muted source geometry, so local evidence survives even when neighboring
264
+ triangles have very different values.
265
+
266
+ `roughness` uses the same area-weighted point placement. Point colors are local
267
+ to nearby physical feature edges: smooth tessellation diagonals do not become
268
+ visible roughness lines. Use `--roughness-samples` to raise or lower the maximum
269
+ roughness point samples per object.
270
+
242
271
  `section` emits five interior slices per principal plane. The current slicing
243
272
  policy is:
244
273
 
@@ -276,8 +305,8 @@ per-view depth ranges, and object-mask mappings live.
276
305
  not infer identity from object order alone.
277
306
  - Connectivity is object-level. It reports disconnected kernel bodies in the
278
307
  manifest, but the PNG does not split a single scene object into per-body colors.
279
- - Bbox contact is intentionally simple and may over-connect concave shapes whose
280
- bounding boxes touch while surfaces do not. Boolean-overlap edges are exact.
308
+ - Bbox contact is only broadphase evidence and does not merge separate scene
309
+ objects by default. Boolean-overlap edges are exact.
281
310
  - Distance is a physical-component bbox-gap metric in v1, not exact nearest
282
311
  mesh-surface distance. Concave components and loose bounding boxes can make the
283
312
  reported gap smaller than the real closest-surface distance.
@@ -75,6 +75,8 @@ FORGECAD_TOKEN=fc_pat_... forgecad project push
75
75
 
76
76
  Passing the token directly as `forgecad login --token fc_pat_...` is accepted for non-interactive setup, but the interactive prompt is preferred so tokens do not land in shell history.
77
77
 
78
+ For local development or self-hosted experiments, `forgecad login --server <url>` accepts a clean server origin only. Use HTTPS for remote servers; plain HTTP is accepted only for localhost. License activation remains tied to forgecad.io accounts.
79
+
78
80
  ---
79
81
 
80
82
  ## API Endpoints
@@ -39,6 +39,10 @@ This is what users see when they click "Sign in with Google."
39
39
 
40
40
  ## 3. Create OAuth Credentials
41
41
 
42
+ Use the Google Auth Platform / Credentials page for ForgeCAD web sign-in.
43
+ The `gcloud iam oauth-clients` command is for IAM/IAP OAuth application
44
+ resources and is not the right client type for this app's Google Sign-In flow.
45
+
42
46
  1. In the left sidebar: **APIs & Services → Credentials**
43
47
  2. Click **+ Create Credentials → OAuth client ID**
44
48
  3. **Application type**: Web application
@@ -25,7 +25,7 @@ For platform feature docs (auth, projects, sharing, admin, email) see [platform/
25
25
  | SSH to production | `ssh hetzner` |
26
26
  | Open observability UI | Connect to Tailscale, then open `http://100.118.68.93:3000` |
27
27
  | Check observability stack | `bash scripts/prod/observability-status.sh` |
28
- | Roll back bad web deploy | `kamal rollback <VERSION>` |
28
+ | Roll back bad web deploy | `npm run prod:rollback -- <VERSION>` |
29
29
  | Verify npm tarball in Docker | `npm run release:docker:all` |
30
30
 
31
31
  ---
@@ -375,13 +375,13 @@ user flows, roll back to the previous healthy web version immediately:
375
375
 
376
376
  ```bash
377
377
  ssh hetzner 'docker ps -a --format "{{.Names}}\t{{.Status}}" | grep "^forgecad-web-" | sed -E "s/^forgecad-web-([a-f0-9]+)(_replaced_[^[:space:]]+)?\t/\1\t/"'
378
- kamal rollback <VERSION>
378
+ npm run prod:rollback -- <VERSION>
379
379
  ```
380
380
 
381
381
  Example:
382
382
 
383
383
  ```bash
384
- kamal rollback db9c49b058aaa379d9d622456cb249f9b0ddc335
384
+ npm run prod:rollback -- db9c49b058aaa379d9d622456cb249f9b0ddc335
385
385
  ```
386
386
 
387
387
  After rollback, verify a real user-facing path, not just `/api/health`. For
@@ -1,6 +1,6 @@
1
1
  # forgecad-make-a-model
2
2
 
3
- Create new ForgeCAD (.forge.js) models in the active CAD project. Handles file placement, invokes the forgecad skill for API guidance, and validates the result.
3
+ Create manufacture-realistic prototype ForgeCAD (.forge.js) models in the active CAD project. Handles file placement, invokes the forgecad skill for API guidance, and validates the result.
4
4
 
5
5
  | Field | Value |
6
6
  | --- | --- |
@@ -13,6 +13,17 @@ Create new ForgeCAD (.forge.js) models in the active CAD project. Handles file p
13
13
 
14
14
  Create new ForgeCAD models in the user's active ForgeCAD project.
15
15
 
16
+ ### Default Output Standard
17
+
18
+ Unless the user explicitly asks for a rough blockout, toy, pure visual study, mass-production release package, or specific manufacturing process, the output is a **manufacture-realistic prototype**.
19
+
20
+ That means the model should look and behave like a serious prototype someone could fabricate, buy parts for, assemble, inspect, and iterate in a real shop or product lab. It is not a casual concept sketch, not a universal 3D-printing exercise, and not a claim of certified production readiness.
21
+
22
+ - Choose processes that fit the artifact: machined, sheet-metal, tube, wood/composite, laser-cut, molded-look prototype, printed, or hybrid purchased-hardware construction as appropriate.
23
+ - Include prototype-real features: wall thickness, fastener stacks, bosses, ribs, flanges, bends, seats, bushings, gaskets, cable exits, service access, toleranced clearances, and believable purchased parts.
24
+ - Use production cues only when they help prototype realism. Do not invent expensive production tooling details, certification claims, or safety ratings unless the user asked for that level.
25
+ - If the user asks for `production-realistic`, push toward manufacturing DFM and production-intent materials. If they ask for `printable`, make the selected printed parts honest. If they ask for `visual-CAD`, keep it clearly visual rather than pretending it is build-ready.
26
+
16
27
  ### File Placement
17
28
 
18
29
  All new `.forge.js` files go under the date-based directory structure:
@@ -40,6 +51,7 @@ Use today's date for the directory. Use the user's current ForgeCAD project when
40
51
  1. Load the ForgeCAD skill — always invoke the `forgecad` skill first to get API docs and authoring guidance. Read at minimum the Core API reference. If any two parts are intended to touch or mate in the final model, read the positioning guide immediately and default to connectors + `matchTo()`.
41
52
  2. Create the directory — `mkdir -p YYYY/MM/DD/[folder]` as needed.
42
53
  3. Write the model — create the `.forge.js` file(s) following ForgeCAD conventions:
54
+ - Treat the default build profile as `manufacture-realistic prototype`; choose and encode the artifact's manufacturing/process cues before adding styling detail
43
55
  - Declare `param()` / `boolParam()` for all tunable dimensions
44
56
  - If the model is split across files, use `main.forge.js` as the primary entry point, import renderable parts from neighboring `.forge.js` files, and keep only pure helpers/constants in plain `.js` modules
45
57
  - When there are multiple versions of the same object, expose the version as a choice parameter and render one selected version at a time
@@ -52,12 +64,12 @@ Use today's date for the directory. Use the user's current ForgeCAD project when
52
64
  - Return the final geometry (single shape, array, or named objects array)
53
65
  - Treat `fillet(shape, r)` and `chamfer(shape, r)` as experimental edge treatments: Manifold can produce incorrect results and OCCT can be very slow. Prefer simpler primitive profiles, lower segment counts, targeted edge selectors, and inspection before relying on the result.
54
66
  4. Validate — run `forgecad run <file>` to check for errors. For multi-file projects, always validate `main.forge.js`.
55
- 5. Verify geometry — render the result, run `forgecad run --connectivity` when the model has multiple returned objects or visible attachments, and run `forgecad render inspect` with the relevant channels for the task (see Final Acceptance Gate and Render-Verify Loop below). For multi-file projects, render and inspect `main.forge.js`.
67
+ 5. Verify geometry — render the result, run `forgecad run --connectivity` when the model has multiple returned objects or visible attachments, run `forgecad debug assembly --fail-on warning` when the script uses `assembly()`, run `forgecad inspect mechanical-integrity <project-or-file> --collisions` before sharing generated mechanical work, and run `forgecad render inspect` with the relevant channels for the task (see Final Acceptance Gate and Render-Verify Loop below). For multi-file projects, render and inspect `main.forge.js`.
56
68
 
57
69
  ### Manufacturing Process Is Not Assumed
58
70
 
59
71
  Do not interpret every ForgeCAD model as a printable object.
60
- Choose the manufacturing/process cues that fit the artifact unless the user explicitly asked for a specific process.
72
+ Choose the manufacturing/process cues that fit the artifact unless the user explicitly asked for a specific process. A manufacture-realistic prototype can be CNC-machined, bent sheet, tube-and-plate, wood/composite, molded-look low-volume, printed, or hybrid; the right answer depends on the load path and operating story.
61
73
 
62
74
  - For rideable products such as scooters, bikes, skateboards, carts, or mobility-adjacent devices, use realistic metal/composite/wood structural members, purchased wheels/bearings/axles/brakes/grips, and standard hardware unless the user asked for a printable toy/model.
63
75
  - For furniture and load-bearing structures, consider wood, sheet goods, tube, metal brackets, conventional joinery, and printed parts only where they are honest secondary components.
@@ -109,6 +121,52 @@ Do not reveal hidden structure by permanently cutting away the production geomet
109
121
 
110
122
  When internals are hidden by the final exterior, verify them with exploration tools instead of changing the artifact: render underside or alternate camera views, use `render inspect` section channels, use viewer-only cut planes or explode controls, temporarily make a shell transparent, or add named ghost objects for fit checks. Those views are diagnostic/presentation modes; they must not replace the real model unless the user explicitly asked for a cutaway teaching model.
111
123
 
124
+ ### Mechanical Assembly Contract
125
+
126
+ For mechanical models, a ForgeCAD script is not done when it merely looks assembled. Every visible piece must have a believable physical reason to be where it is: fused material, contact faces, a screw stack, a pin in a bore, a tab in a slot, a gasket on a land, a bearing in a seat, a cable in a channel, or a named intentional ghost.
127
+
128
+ - For bespoke fixed assemblies that do not match an existing `lib.*` helper, start from `examples/api/static-assembly-connectors.forge.js`: build each part in local coordinates, pick one root part, place every other touching part with `matchTo()`, and verify the mate with `verify.connectorDistance(...)`. Do not use final `translate()` calls as assembly contracts.
129
+ - If you use `assembly().addPart()`, do not treat `addFixed()`, `addRevolute()`, or `addPrismatic()` with a manual `frame: Transform.identity().translate(...)` as a physical contract. Manual joint frames are acceptable only as a temporary scaffold. Before delivery, convert mating interfaces to connectors with `connect()` / `match()` where the interfaces physically meet, or prove the manual joint with `forgecad debug assembly --fail-on warning` and documented geometry.
130
+ - A named assembly part should not contain unintentional disconnected bodies. If a "cover plate" contains floating pull tabs, loose screw heads, or a separate gasket, either boolean-join the manufactured features, model the fasteners/seals as separate named parts, or provide the receiving holes/lands that explain the separation.
131
+ - Screws are not decoration. A screw needs a clearance/counterbore in the cover, a receiving threaded hole/boss or through stack in the parent, enough material around both, and aligned axes from one shared bolt pattern.
132
+ - Handles and levers need a load path. Model the hub-to-arm connection, pivot pin/bore, thrust washers or shoulders, stops/detents where relevant, and the connected follower/contact surface. A handle tangent to a hub is a failed mechanism.
133
+ - Covers, doors, cartridges, and service panels need seats. Model ledges, gasket grooves, bosses, snap hooks, tabs, or hinge barrels, then show how the removable part is retained.
134
+ - Cables, wires, and tubes need receiving geometry. Model a gland, grommet, clamp, socket, ferrule, routed channel, or hose barb; do not let a cylinder end in open space.
135
+ - Purchased loose parts may remain separate bodies, but they should be named as purchased hardware or consumables and should sit in believable sockets, bores, races, guides, or fastener stacks.
136
+ - Encode interface intent with `verify.*`, not only comments. Use `verify.clearanceBetween("cover is seated on gasket", cover, gasket, -0.01, 0.05)` for contact/seated fits and clearance bands, `verify.minClearance(...)` or `verify.notColliding(...)` for keep-out/running gaps, and `verify.connectorDistance(...)` for connector-authored mates. Part counts and generic dimensions are useful supporting checks, but they do not prove an interface by themselves.
137
+
138
+ For ordinary removable covers, prefer `lib.boltedServiceCover(...)` before hand-placing plates, tabs, screw heads, gaskets, and holes. It creates the parent ledge, gasket, cover plate with fused pull tabs, shared bolt pattern, and installed screws as one mechanically accountable interface.
139
+
140
+ For electronics boxes, backplates, service-stack housings, and camera/monitor enclosures, prefer `lib.datumEnclosureAssembly(...)` before independently placing panels, ribs, bosses, ports, covers, and screws. It creates the tray, ledges, standoffs, ribs, service port, gasket, cover, and screws from one shared datum system.
141
+
142
+ For PCB-mounted terminal blocks, thermostat backplates, control boards, and wire-entry electronics panels, prefer `lib.pcbTerminalBlockAssembly(...)` before placing a loose green block near a board or cover. It creates the backplate, fused standoffs, PCB mounting screws, PCB pin holes, terminal pins, and seated purchased terminal block from one shared datum system.
143
+
144
+ For snap-retained covers, cartridges, small clasps, and housings, prefer `lib.snapLatchCoverAssembly(...)` before drawing decorative snap tabs. It creates latch windows, underside catch lands, fused snap hooks, barbs, and clearance checks so the cover is retained by real geometry.
145
+
146
+ For ordinary pinned handles, cam levers, release levers, and latch arms, prefer `lib.pinnedLeverAssembly(...)` before hand-placing a hub, arm, washers, and pin. It creates a fused lever body, aligned pivot bore, retained pin, thrust washers, support land, and low stop land as one mechanically accountable pivot stack.
147
+
148
+ For trunnions, side knobs, adjustable pivots, and clamp shafts, prefer `lib.retainedShaftAssembly(...)` before hand-placing rods, washers, and knobs. It creates bored support cheeks, a through shaft, thrust washers, knobs, retaining heads, and shared bore dimensions as one mechanically accountable stack.
149
+
150
+ For thumb screws, desk clamps, vise screws, capo pressure screws, and small fixture hold-downs, prefer `lib.thumbScrewClampAssembly(...)` before hand-placing a knob, screw cylinder, pressure pad, and bracket jaw. It creates the C-frame, threaded boss/bore, captive pressure pad, hand knob, and seated workpiece contact from one shared datum system.
151
+
152
+ For drawer slides, quick-release plates, and guided linear carriages, prefer `lib.capturedLinearSlide(...)` before hand-placing rails and a block. It creates a U-channel rail with return lips, end stops, a captured carriage, and explicit travel/clearance dimensions.
153
+
154
+ For pump cartridges, filter cassettes, battery cartridges, skeg cassettes, and removable slide-in modules, prefer `lib.capturedCartridgeGuideAssembly(...)` before placing a loose tray and block. It creates return lips, a rear stop, a captured cartridge flange, pull tab, insertion travel, and explicit clearance dimensions.
155
+
156
+ For molded flexible battery doors, sample covers, blister latches, and polypropylene-style service flaps, prefer `lib.livingHingeCoverAssembly(...)` before drawing two plates with a decorative hinge strip. It creates one fused molded strip with fixed leaf, thin flexible web, moving cover leaf, pull lip, snap barb, catch land, and web-thickness checks.
157
+
158
+ For doors, barn-door leaves, lids, locket leaves, and small hinged access panels, prefer `lib.knuckledHingeAssembly(...)` before hand-placing barrels and a pin. It creates alternating fused knuckles, two leaves, a shared bore, and a retained pin as one mechanically accountable hinge.
159
+
160
+ For crank links, damper rod ends, crossheads, and clevis-yoke pivots, prefer `lib.clevisPinJointAssembly(...)` before hand-placing an eyelet and pin. It creates bored clevis ears, a captured center link eye, a rear bridge, and a retained pin as one mechanically accountable load path.
161
+
162
+ For bearings, rollers, burr cartridges, spindle supports, and purchased radial bearings, prefer `lib.seatedBearingAssembly(...)` before hand-placing a ring and shaft near a block. It creates a bored housing, counterbore pocket, bearing shoulder, seated bearing, shaft, collars, and shared clearance dimensions as one mechanically accountable support.
163
+
164
+ For cables, wires, hoses, pump tubes, and panel pass-throughs, prefer `lib.cableGlandAnchorAssembly(...)` before hand-placing a loose cylinder near a wall. It creates the panel clearance hole, hollow gland body, compression nut, and routed cable/tube as one mechanically accountable pass-through.
165
+
166
+ For routed cables, wires, hoses, pump tubes, and sensor leads that run along a surface, prefer `lib.routedTubeClipAssembly(...)` before drawing a tube that floats between endpoints. It creates a base panel, saddle clip bores, clip screw holes, installed screws, and the retained tube route from one shared datum system.
167
+
168
+ For fluid hoses, pump inlets/outlets, filter ports, and lab tubing, prefer `lib.hoseBarbPortAssembly(...)` before drawing a tube that stops at a block. It creates the bored receiver, raised boss, hollow barbed fitting, installed hose, and clamp band as one accountable hose-port interface.
169
+
112
170
  ### Final Geometry Should Be Physically Plausible
113
171
 
114
172
  Treat each returned part as real matter occupying space. In the final build, separate parts should not intersect unless the intersection is the actual manufacturing intent, such as a welded/fused region, an overmolded insert, or a boolean-unioned solid that is no longer a separate part.
@@ -117,7 +175,9 @@ Do not use final interpenetration as a placement shortcut. For joints and interf
117
175
 
118
176
  Temporary collisions during construction are fine when they are part of how the model is made or verified: oversized cutter solids before `difference()`, overlapping primitives before `union()`, transparent ghost parts for fit checks, or exploratory joint layouts. Those temporary bodies should be consumed, hidden, named as ghosts, or isolated with inspection filters so final collision findings stay meaningful.
119
177
 
120
- Before delivery on any multi-part, internal, or mechanical model, run the collision inspection, read the collision channel PNGs, and check `manifest.json`. Fix unexpected overlaps. If a collision is intentional, document it in the model naming/comments or isolate that inspection with `--focus` / `--hide` so the remaining collision report proves the final assembly is real.
178
+ If a final overlap is real manufacturing intent, document the exact visible object pair with `verify.intentionalOverlap("rubber grip is overmolded on handle core", rubberGrip, handleCore, "overmolded bonded grip")`. Use this only for welded, fused, overmolded, cast-in, potted, or bonded matter. The mechanical-integrity gate honors it only when the same visible object pair has a confirmed exact collision; unused or non-visible declarations still fail.
179
+
180
+ Before delivery on any multi-part, internal, or mechanical model, run the collision inspection, read the collision channel PNGs, and check `manifest.json`. Fix unexpected overlaps. If a collision is intentional, declare the exact visible pair with `verify.intentionalOverlap(...)` or isolate that inspection with `--focus` / `--hide` so the remaining collision report proves the final assembly is real.
121
181
 
122
182
  ### Final Acceptance Gate
123
183
 
@@ -131,6 +191,24 @@ Before telling the user the model is done, prove both technical validity and vis
131
191
 
132
192
  The reported component count must match the design intent. Treat unexpected islands, accidental fusion, or bbox-only "touching" that does not make physical sense as model bugs.
133
193
 
194
+ If the script uses `assembly()`, also run:
195
+
196
+ ```bash
197
+ forgecad debug assembly model.forge.js --fail-on warning
198
+ ```
199
+
200
+ Fix warnings about multiple roots, manual joint contracts, disconnected bodies inside parts, unused connectors, solve warnings, and collisions before delivery. If a warning is truly intentional, rename the part or add a short code comment so a reviewer can see the physical reason.
201
+
202
+ For generated mechanical projects or batches, also run:
203
+
204
+ ```bash
205
+ forgecad inspect mechanical-integrity . --collisions
206
+ ```
207
+
208
+ This is the shareability gate. It fails on missing `verify.*` checks, missing mechanical-interface verification, fragmented named groups, uncontracted manual assemblies, positive-volume object collisions, timeouts, and runtime failures. Do not share a generated mechanical model while this gate is red unless the user explicitly asked for a rough concept/blockout.
209
+
210
+ The model should include at least one verification that proves a mechanical interface, not just object count. Prefer checks such as `verify.clearanceBetween("bearing is seated in pocket", bearing, housing, -0.01, 0.1)`, `verify.minClearance("carriage clears rail", carriage, rail, 0.15)`, `verify.notColliding("cover screw clears parent hole", screw, parent)`, or `verify.connectorDistance("leg connector is seated", bench, "Rail.leg_0", "Leg0.head", 0, 0.01)`.
211
+
134
212
  2. Run a collision bundle and read both the manifest and images:
135
213
 
136
214
  ```bash
@@ -245,13 +323,14 @@ return [
245
323
 
246
324
  This immediately reveals: does it fit? Does it collide with walls? Does the shaft clear the opening?
247
325
 
248
- #### Use console.log for dimension checks
326
+ #### Use verify for acceptance, console.log for traces
249
327
 
250
- Print derived dimensions and clearances to verify arithmetic before rendering:
328
+ Use `verify.*` for dimensions and clearances that decide whether the model is acceptable. Use `console.log()` only for explanatory traces that help you read the run output.
251
329
 
252
330
  ```js
253
- console.log("wall remaining:", ((outerW - slotW) / 2).toFixed(1)); // must be > 0
254
- console.log("hole clearance from edge:", (flangeW/2 - holeX - holeDia/2).toFixed(1));
331
+ verify.greaterThan("wall remains around slot", (outerW - slotW) / 2, 1.6);
332
+ verify.greaterThan("hole clears flange edge", flangeW / 2 - holeX - holeDia / 2, 2.0);
333
+ console.log("wall remaining:", ((outerW - slotW) / 2).toFixed(1));
255
334
  ```
256
335
 
257
336
  Output appears under "Script output:" in `forgecad run`.
@@ -1,6 +1,6 @@
1
1
  # forgecad-prepare-prompt
2
2
 
3
- Turn a fuzzy physical product, mechanism, or CAD artifact request into a concrete ForgeCAD build brief and a single master prompt for the modeling pass. Use when the engineering brief is incomplete, manufacturing/process choice is underspecified, or the work needs a specific operating story to avoid generic toy solutions.
3
+ Turn a fuzzy physical product, mechanism, or CAD artifact request into a concrete manufacture-realistic prototype ForgeCAD build brief and a single master prompt for the modeling pass. Use when the engineering brief is incomplete, manufacturing/process choice is underspecified, or the work needs a specific operating story to avoid generic toy solutions.
4
4
 
5
5
  | Field | Value |
6
6
  | --- | --- |
@@ -11,7 +11,7 @@ Turn a fuzzy physical product, mechanism, or CAD artifact request into a concret
11
11
 
12
12
  ## Prepare ForgeCAD Prompt
13
13
 
14
- Use this skill before modeling when the user wants something physically real, manufacturing-aware, and buildable, but their request sounds like:
14
+ Use this skill before modeling when the user wants something physically real, manufacturing-aware, and buildable as a manufacture-realistic prototype, but their request sounds like:
15
15
 
16
16
  - "make me a robot gripper"
17
17
  - "design a real mechanism"
@@ -30,6 +30,10 @@ Choose the manufacturing/process stack from the artifact family, load path, scal
30
30
  For example: scooters, bikes, skateboards, and rideable vehicles usually point toward metal/composite frames, wood/composite decks, urethane/rubber wheels, bearings, brakes, and standard hardware; furniture often points toward wood, sheet goods, tube, metal brackets, or conventional joinery; enclosures may point toward injection molding, sheet metal, CNC, or printing depending on quantity and ruggedness; fixtures may be machined, laser-cut, welded, printed, or hybrid.
31
31
  If the user asks for "printable", "3D printed", "laser cut", "CNC", or another process, honor that process while still warning when it is unsafe or dishonest for the duty.
32
32
 
33
+ The default output posture is **manufacture-realistic prototype** unless the user asks for a different posture.
34
+ This means a serious prototype build candidate with real manufacturing cues, purchased-part boundaries, assembly logic, and validation loops. It is stronger than a visual concept or hobby sketch, but it does not claim final production tooling, certification, rider safety, medical compliance, or release-ready DFM.
35
+ Use `production-realistic` only when the user wants production intent, `printable` only when printing is actually the selected process, and `visual-CAD` only for visual/form studies.
36
+
33
37
  Do not let the modeling prompt sound like a casual hobby sketch when the requested artifact belongs to a serious product domain.
34
38
  Give the model a specific operating story: a named company or lab, named program, named prototype/revision, review moment, test setting, and concrete reason the part matters.
35
39
  If the user did not provide this story, invent plausible non-famous names and details.
@@ -66,6 +70,7 @@ By the end of this skill, there should be:
66
70
  - an artifact family classification
67
71
  - an assumption bundle with units
68
72
  - a clear build profile and manufacturing/process stack
73
+ - a stated output posture, defaulting to manufacture-realistic prototype unless the user chose otherwise
69
74
  - a specific operating story
70
75
  - a motion / load / size target
71
76
  - a BOM boundary
@@ -129,8 +134,9 @@ By the end of this skill, there should be:
129
134
 
130
135
  4. Choose manufacturing/process posture.
131
136
  Treat process selection as part of the brief.
132
- Use `production-realistic`, `prototype-realistic`, `printable`, `visual-CAD`, or a more specific process such as `sheet-metal`, `CNC-machined`, `laser-cut`, `welded tube`, `injection-molded`, `cast`, or `hybrid purchased-hardware`.
133
- Default to the posture that is honest for the artifact rather than the easiest CAD surface to make.
137
+ Default to `manufacture-realistic prototype`.
138
+ Use `production-realistic`, `prototype-realistic`, `printable`, `visual-CAD`, or a more specific process such as `sheet-metal`, `CNC-machined`, `laser-cut`, `welded tube`, `injection-molded`, `cast`, or `hybrid purchased-hardware` only when the brief justifies that more specific posture.
139
+ Choose the posture that is honest for the artifact rather than the easiest CAD surface to make.
134
140
 
135
141
  5. Pick qualitative levers, not raw numbers.
136
142
  Start from:
@@ -146,7 +152,7 @@ By the end of this skill, there should be:
146
152
  - for a gripper: object style, opening band, cost/performance posture
147
153
  - for a table: use style, span band, load style
148
154
  - for an enclosure: electronics size, ruggedness, cooling posture
149
- - for an underspecified product: production-realistic, prototype-realistic, printable, or visual-CAD posture
155
+ - for an underspecified product: manufacture-realistic prototype, production-realistic, printable, or visual-CAD posture
150
156
 
151
157
  7. Convert choices into an engineering brief.
152
158
  The brief must include:
@@ -156,6 +162,7 @@ By the end of this skill, there should be:
156
162
  - production reason
157
163
  - test setting
158
164
  - what generic output would miss
165
+ - output posture, defaulting to manufacture-realistic prototype unless changed by the user
159
166
  - intended objects / loads
160
167
  - rough size envelope
161
168
  - motion style and degrees of freedom
@@ -189,7 +196,7 @@ Good:
189
196
  - "Which target feels closest: a light desk demo, a useful hobby tool, or a sturdier bench mechanism?"
190
197
  - "Will it mostly handle soft/light things, mixed household parts, or rigid/tool-like objects?"
191
198
  - "Should we bias for cheapest parts, balanced practicality, or stronger hardware?"
192
- - "Should this be production-realistic, prototype-realistic, printable, or just a visual CAD study?"
199
+ - "Should this be a manufacture-realistic prototype, production-realistic, printable, or just a visual CAD study?"
193
200
  - "Is this more like a gripper, a fixture, an enclosure, a chassis, or furniture?"
194
201
  - "Will the table mostly hold decor, laptop-and-books, or workshop abuse?"
195
202
 
@@ -206,6 +213,7 @@ If the user says "I don't know" or gives only a broad goal:
206
213
  - infer the nearest artifact family from the request
207
214
  - invent a specific operating story for the artifact
208
215
  - infer the manufacturing/process stack from the artifact family and operating story
216
+ - default the output posture to `manufacture-realistic prototype`
209
217
  - choose `general-duty`
210
218
  - choose `medium`
211
219
  - choose `balanced`
@@ -163,7 +163,7 @@ PNG review order:
163
163
  ### Interpretation Rules
164
164
 
165
165
  - Collision findings are positive-volume boolean overlaps. Face-touching is not a collision.
166
- - Connectivity is a fast bbox-neighborhood component graph. Concave shapes can over-connect through bounding boxes; use the collisions channel for exact overlap evidence.
166
+ - Connectivity uses bbox as a broadphase, then exact overlap evidence for component grouping. Bbox-only contact does not merge separate scene objects by default; use the collisions channel for positive-volume overlap evidence.
167
167
  - Distance is a bbox-gap metric between physical components, not exact closest surface distance.
168
168
  - Thickness is a mesh/raycast approximation. Gray or high unresolved area means the visual heatmap is incomplete, not that the model is safe.
169
169
  - Depth is a visual heatmap, not raw floating-point depth data.
@@ -14,8 +14,8 @@ forgecad skill install
14
14
  | [forgecad-high-level-spec](/docs/skills/forgecad-high-level-spec) | `forgecad skill install` | Write a high-level design document (HLD) for a model, mechanism, or assembly before detailed specification or coding. Use when starting a new design, rethinking an existing one, or when the user asks to spec out, plan, or think through a model at a high level. Works backwards from requirements — defines the problem, explores alternatives, records decisions. Produces a right-sized design document for review and iteration. |
15
15
  | [forgecad-image-replicator](/docs/skills/forgecad-image-replicator) | `forgecad skill install` | Build real ForgeCAD geometry from one or more reference images by treating images as evidence, inferring the object, then validating against both reference-matched and canonical views. |
16
16
  | [forgecad-lld](/docs/skills/forgecad-lld) | `forgecad skill install` | Write a Low-Level Design (LLD) for a CAD model — exact dimensions, constraints, parameters, and verification criteria. Use after a High-Level Design (HLD) exists and decisions are locked, or for simple parts that don't need an HLD. The detailed design document that code implements. |
17
- | [forgecad-make-a-model](/docs/skills/forgecad-make-a-model) | `forgecad skill install` | Create new ForgeCAD (.forge.js) models in the active CAD project. Handles file placement, invokes the forgecad skill for API guidance, and validates the result. |
18
- | [forgecad-prepare-prompt](/docs/skills/forgecad-prepare-prompt) | `forgecad skill install` | Turn a fuzzy physical product, mechanism, or CAD artifact request into a concrete ForgeCAD build brief and a single master prompt for the modeling pass. Use when the engineering brief is incomplete, manufacturing/process choice is underspecified, or the work needs a specific operating story to avoid generic toy solutions. |
17
+ | [forgecad-make-a-model](/docs/skills/forgecad-make-a-model) | `forgecad skill install` | Create manufacture-realistic prototype ForgeCAD (.forge.js) models in the active CAD project. Handles file placement, invokes the forgecad skill for API guidance, and validates the result. |
18
+ | [forgecad-prepare-prompt](/docs/skills/forgecad-prepare-prompt) | `forgecad skill install` | Turn a fuzzy physical product, mechanism, or CAD artifact request into a concrete manufacture-realistic prototype ForgeCAD build brief and a single master prompt for the modeling pass. Use when the engineering brief is incomplete, manufacturing/process choice is underspecified, or the work needs a specific operating story to avoid generic toy solutions. |
19
19
  | [forgecad-project](/docs/skills/forgecad-project) | `forgecad skill install` | ForgeCAD project CLI workflow — creating, managing, syncing projects and files on forgecad.io. Covers init, push, pull, file operations, member management, publishing, and sharing. |
20
20
  | [forgecad-render-inspect](/docs/skills/forgecad-render-inspect) | `forgecad skill install` | Run and interpret ForgeCAD `render inspect` bundles for model verification. Use when asked to inspect a ForgeCAD model, analyze an inspection bundle, validate collisions, wall thickness, connectivity, sections, masks, depth, normals, or choose inspection channels. |
21
21
  | [forgecad-visual-spec](/docs/skills/forgecad-visual-spec) | `forgecad skill install` | Turn a concrete ForgeCAD artifact, build brief, HLD, or existing model into builder-honest image prompts for AI image models. Use when the user wants visual-spec renders that show the final product while keeping mechanisms, seams, hardware, and build cues visible instead of drifting into concept art. |
package/dist/index.html CHANGED
@@ -55,7 +55,7 @@
55
55
  * { margin: 0; padding: 0; box-sizing: border-box; }
56
56
  html, body, #root { width: 100%; min-height: 100%; background: var(--fc-bg); color: var(--fc-text); font-family: system-ui, -apple-system, sans-serif; }
57
57
  </style>
58
- <script type="module" crossorigin src="/assets/app-CFy7g5WP.js"></script>
58
+ <script type="module" crossorigin src="/assets/app-BE2nD6Yz.js"></script>
59
59
  <link rel="stylesheet" crossorigin href="/assets/app-CsHnaBWt.css">
60
60
  </head>
61
61
  <body>
package/dist/sitemap.xml CHANGED
@@ -2,37 +2,37 @@
2
2
  <urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">
3
3
  <url>
4
4
  <loc>https://forgecad.io/</loc>
5
- <lastmod>2026-05-16</lastmod>
5
+ <lastmod>2026-05-19</lastmod>
6
6
  <changefreq>weekly</changefreq>
7
7
  <priority>1.0</priority>
8
8
  </url>
9
9
  <url>
10
10
  <loc>https://forgecad.io/docs</loc>
11
- <lastmod>2026-05-16</lastmod>
11
+ <lastmod>2026-05-19</lastmod>
12
12
  <changefreq>weekly</changefreq>
13
13
  <priority>0.8</priority>
14
14
  </url>
15
15
  <url>
16
16
  <loc>https://forgecad.io/blog</loc>
17
- <lastmod>2026-05-16</lastmod>
17
+ <lastmod>2026-05-19</lastmod>
18
18
  <changefreq>weekly</changefreq>
19
19
  <priority>0.7</priority>
20
20
  </url>
21
21
  <url>
22
22
  <loc>https://forgecad.io/pricing</loc>
23
- <lastmod>2026-05-16</lastmod>
23
+ <lastmod>2026-05-19</lastmod>
24
24
  <changefreq>monthly</changefreq>
25
25
  <priority>0.6</priority>
26
26
  </url>
27
27
  <url>
28
28
  <loc>https://forgecad.io/examples</loc>
29
- <lastmod>2026-05-16</lastmod>
29
+ <lastmod>2026-05-19</lastmod>
30
30
  <changefreq>weekly</changefreq>
31
31
  <priority>0.6</priority>
32
32
  </url>
33
33
  <url>
34
34
  <loc>https://forgecad.io/blog/hello-forgecad-io</loc>
35
- <lastmod>2026-05-16</lastmod>
35
+ <lastmod>2026-05-19</lastmod>
36
36
  <changefreq>monthly</changefreq>
37
37
  <priority>0.5</priority>
38
38
  </url>