← cad viewer

CAD viewer · #2

First triangle: STEP in, pixels out

The viewer scaffold is live at /viewer. Drop a .step file on it and it renders. Nothing gets uploaded — the entire parse happens in your browser tab.

The pipeline

file drop → ArrayBuffer → web worker → OCCT (WASM) → triangle soup → Three.js

Three pieces, each deliberately boring:

  • Parsing: occt-import-js — OpenCascade compiled to WASM. We hand it the file as a Uint8Array, it hands back tessellated meshes: positions, normals, indices per body. The tessellation tolerances are the interesting knob — linearDeflection controls how far the triangle soup can deviate from the real surface. We're using a bounding-box-ratio deflection so small parts don't get over-tessellated. We'll write a whole post on this once we have screenshots worth looking at.

  • The worker: parsing a 50 MB STEP file freezes the main thread for seconds. The OCCT call lives in a web worker from day one — results come back as transferred Float32Array/Uint32Array buffers, so there's no structured-clone copying cost either:

for (const mesh of result.meshes) {
  const position = new Float32Array(mesh.attributes.position.array);
  const index = new Uint32Array(mesh.index.array);
  meshes.push({ name: mesh.name, position, index, faces: mesh.brep_faces });
  transfer.push(position.buffer, index.buffer);
}
self.postMessage({ ok: true, meshes }, transfer);
  • Rendering: plain WebGLRenderer + OrbitControls for now. Yes, we said WebGPU last week — still the plan, but "load a file and see it spin" was the milestone worth shipping first. WebGL2 covers it today.

What's deliberately missing

Face picking, exploded view, section cuts, measurements, progressive tessellation. All post-v1. Right now it does exactly one thing: prove the parse-to-pixels path works on real files.

If you have a STEP file lying around, try it — if it fails to render your file, that's exactly the kind of bug report we want (Contact link, bottom right).