Click a face in /viewer and it highlights — the whole face, not the triangle under your cursor. That distinction is the difference between a mesh viewer and a CAD viewer, and it's the first feature here that uses real B-rep data.
The mapping
occt-import-js doesn't just return triangle soup — each mesh comes with
brep_faces, an array of { first, last } ranges. The ranges index into the
triangle buffer: face 2 of a body might be triangles 22–57 of that mesh's
index array.
So picking is three lookups, no geometric detective work:
click → raycast → hit.faceIndex (which triangle)
→ find range in brep_faces containing it (which B-rep face)
→ rebuild a highlight mesh from that index subrange (draw it)
The highlight geometry shares the part's position/normal buffers and takes a
subarray view of the index — the whole selection is zero-copy:
geometry.setAttribute('position', src.attributes.position);
geometry.setAttribute('normal', src.attributes.normal);
geometry.setIndex(new THREE.BufferAttribute(
part.index.subarray(face.first * 3, (face.last + 1) * 3), 1,
));
const mesh = new THREE.Mesh(geometry, highlightMaterial);
Accent color, polygonOffset to win the depth test, gone when you click
empty space.
The detail that took the longest
Raycasts and orbit drags both start with a mouse press. Selection only fires on clicks under 5px of pointer movement — anything more is an orbit. Invisible details like that are most of the work in a tool that feels right.
Also: the status line now reports face area, computed by summing triangle cross-products. mm² or cm² depending on magnitude — a small taste of the measurement features to come.