Post #4 ended with an admission: the section plane cuts the model open but leaves it hollow — you look through the walls into empty space. That gap is closed. Check section in /viewer and the cut surface now renders as a solid face, colored to match each part.
The algorithm, honestly stated
No B-rep Booleans — that's kernel territory. This is the mesh-level version, four steps:
triangles ∩ plane → segments → weld endpoints → closed loops → earcut
For every triangle, find where the plane crosses it (two points = one
segment). Weld segment endpoints so adjacent pieces share nodes. Chain
segments into closed loops. Flatten each loop onto the plane's 2D basis and
triangulate with earcut — which natively supports hole indices, so a boss
inside a cut region fills correctly around it.
The bug that took the longest
First version produced zero caps on the rounded-cube sample. Cause: two straddling triangles had a vertex exactly on the plane, so the strict "two sign-changes" test found only one intersection point and emitted no segment — an open chain, silently dropped. The fix treats on-plane vertices as section points, and emits coplanar edges whose third vertex sits on the clipped side:
if (Math.abs(da) < EPS) pts.push(vpos(a)); // vertex on the plane
if (Math.abs(da) < EPS && Math.abs(db) < EPS && dc < -EPS)
pts.push(vpos(a), vpos(b)); // coplanar boundary edge
Degenerate plane-alignment cases are where mesh cap algorithms live or die.
Honest limits
- Caps are sampled at tessellation density — a coarse model gives a coarse cap polygon.
- Open chains (a cut that ends in genuinely open geometry) get dropped, not closed with a guessed chord.
- Holes one level deep are handled; exotic nested containment is not.
- Rebuild runs debounced off the slider (~150 ms) — it recomputes after you stop dragging, not per pixel of drag.
The full pipeline — intersect, weld, chain, project, nest, triangulate — is
about 200 lines in viewer/section-cap.js, renderer-agnostic, works
identically on WebGPU and the WebGL2 fallback.