Skip to content

The Verify Loop

You write a .brep.ts part; brep runs it on a geometry kernel and reports what it measured. Judge the part by the report, not by how the code reads.

The loop (every part, in order)

  1. Brief. Convert the request into explicit parameters: dimensions (mm), datums, features, assumptions.
  2. Author .brep.ts. export default () => <shape> using the short API (box, cylinder, fuse, cut, fillet, …), with named constants at the top. Scaffold with brep init <name>. Edit source, never generated artifacts.
  3. Declare intent. Add an expected block from your brief, e.g. export const expected = { volume: 24000, tolerancePct: 1 }. Any of volume, area, bounds are optional; tolerancePct sets the match window. The CLI asserts it, catching a part that is valid but wrong-sized.
  4. Verify (type + geometry). brep verify part.brep.ts --check --json report.json. --check type-checks before running (catches wrong-API calls early); the JSON report is the source of truth. Iterate fast with brep watch part.brep.ts.
  5. Verify visually. Add --snapshot shots/ for iso/front/top/right PNGs. Review against the brief. A visual concern is not a conclusion: convert it to a measurement ("hole looks off-center → check bounds").
  6. Repair the smallest responsible section and re-run. Use the report's hints to guide the fix.
  7. Export + hand off. brep verify part.brep.ts --step part.step (STEP is the validated primary deliverable; GLB/STL are derived). Batch behind a validity gate with brep export part.brep.ts --all. Report the STEP path.

The commands above assume you've installed the package (npm i -D brepjs-cad) and call brep directly. Otherwise prefix every command with npx -y -p brepjs-cad to run it straight from npm.

Reading the report

Every command writes a single JSON document to stdout (diagnostics go to stderr):

jsonc
{
  "ok": false, // true only if no errors AND every check AND every assertion passes
  "shapeType": "Solid",
  "checks": [{ "name": "isValidSolid", "passed": false }],
  "measurements": {
    "volume": 31200,
    "area": 6800,
    "bounds": { "xMin": -20, "xMax": 20, "yMin": -10, "yMax": 10, "zMin": 0, "zMax": 10 },
  },
  "assertions": [{ "name": "volume", "expected": 24000, "actual": 31200, "passed": false }],
  "hints": [{ "code": "FILLET_NO_EDGES", "message": "…", "fix": "…", "nextStep": "…" }],
  "errorInfos": [{ "code": "…", "message": "…" }],
}
  • ok is the verdict. false → not done. With an expected block, ok also requires every assertion to pass.
  • checks = kernel validity (manifold solid, positive volume). A failed check means the geometry is broken, not wrong-sized.
  • measurements = the kernel's measured volume / area / bounding box.
  • assertions = your declared intent vs reality. A failed assertion means valid-but-wrong (off dimensions).
  • hints = an actionable fix + next step keyed on the error code. Read these before guessing.
  • errorInfos = the raw structured failures (code + message) the hints derive from (authoring, kernel, or export errors). Cite the code when repairing.

Trust the JSON over the render. The render shows shape; the JSON shows dimensions and validity.

Repair discipline

  • Change the smallest responsible section, re-verify, repeat. Don't rewrite the whole part on one failure.
  • Let the code/hints localize the cause:
    • INVALID_FILLET_RADIUS → reduce the radius relative to the local edge length.
    • *_NOT_3D → you passed a 2D shape to a 3D operation.
    • BOOLEAN_HAS_ERRORS → the inputs are overlap-degenerate.
  • A part that runs but reports ok: false is wrong, not done. Treat it like a crash.

What's reliable, what needs care

  • Reliable first-try: primitives, booleans (fuse/cut/intersect), 2D sketch → extrude, fillet/chamfer, shell/offset, transforms. Prefer these.
  • Advanced (verify carefully, expect iteration): sweeps, lofts, revolves, multi-section, assemblies, text. They fail more often (degenerate profiles, self-intersection); lean harder on the report and take small steps.

Hard rules

  • Edit source, not artifacts. STEP/STL/GLB derive from the .brep.ts.
  • Booleans and measureVolume/measureArea return Result: unwrap and check the Err branch before chaining.
  • fillet/chamfer need a valid solid; the signature is fillet(solid, edges, radius). Verify validity first.
  • box(width, depth, height): the 2nd arg is depth (Y), the 3rd is height (Z); the positioning option is at, not origin. Units are mm.
  • Author parts in an ESM context so the kernel loads. A CommonJS project needs "type": "module" or a .mts file.

Programmatic use

The same runtime is exported for scripts and your own harnesses:

ts
import { runPart, serializeReport } from 'brepjs-cad';

const { shape, report, step } = await runPart('part.brep.ts', { step: true, check: true });
console.log(serializeReport(report)); // { ok, shapeType, checks, measurements, assertions, hints, errorInfos, errors }

report.shape is a live WASM-backed handle. Release it (using / a DisposalScope) in long-running callers.

Next steps

Released under the Apache 2.0 License.