npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@forgent3d/cad-build

v0.4.1

Published

Portable Forgent3D CAD build capability for coding agents: build-check a build123d-dialect model.py — or an OpenSCAD .scad, evaluated by the bundled OpenSCAD and rebuilt as exact B-rep — and measure it with the same wasm engine (and the same report text)

Readme

@forgent3d/cad-build

The portable CAD build capability a coding agent (Claude Code / Codex) drives to author a Forgent3D model.py — or an OpenSCAD .scad, which the bundled OpenSCAD (the Forgent3D fork, wasm) renders. It bundles the same engine the product runs — @forgent3d/build-service's buildOne / probeOne over @forgent3d/cad-engine's wasm — and prints through the same formatter (formatRebuildSummary / formatProbeResult), so rebuild and check return byte-for-byte what the in-product CAD agent sees. No monorepo, no python, no OCCT install: the wasm + cadkit assets ship inside this package.

This is the engine behind the forgent3d skill (forgent3d/forgent3d-skills), which picks its build123d or OpenSCAD route per request; its bin/cad-build shells out to npx @forgent3d/cad-build@latest … (with a local-path fallback via FORGENT3D_CAD_BUILD_BIN).

Commands

cad-build rebuild    [file.py|file.scad]                # build-check + dimension report
cad-build check      [file.py] --code '…'               # one-off probe in the built model's namespace (.py only)
cad-build check      [file.py] --code-stdin < probe.py  # large snippet via stdin
cad-build knobs      [file.py|file.scad] [--params a,b]           # build every published #@ knob at its extremes
cad-build snapshot   [file.py|file.scad] [--view front] [--line N] [--line-art] [--xray]   # orthographic PNG; --line zooms onto one statement's faces
cad-build export     [file.py|file.scad] --format step            # step | stl | glb | obj | 3mf | brep
cad-build recipe     <outline|motion|pocket>
cad-build preview    [file.py|file.scad]                          # → shareable 3D link
cad-build feedback   --message '…' [file.py]            # report an engine/tool bug

The source file may be named anything; it defaults to ./model.py, else the sole *.py, else the sole *.scad in the directory. Its directory is the project root (so relative refs resolve exactly like the product's per-project workspace). cad-build help <command> has the details of each.

OpenSCAD

Every command but check takes a .scad in place of the .py, and the real OpenSCAD (shipped in dist/assets/openscad/, pointed at by OPENSCAD_WASM_DIR; Manifold backend) renders it — the same render the desktop's F5 shows and the browser workbench (/scad) previews, through @forgent3d/scad-transpile's render path. No model.py is derived and the B-rep kernel is not involved: every report reads OpenSCAD's own triangles.

  • rebuild reports the render's bbox, volume (the facets'), triangle count, what the file echo()ed and OpenSCAD's warnings at their .scad lines. check is refused: there is no namespace behind a render — echo() is the probe.

  • The file's folder is the project (--root <dir> mounts a larger one): every .scad and every data file OpenSCAD reads (import(), surface(), fonts) is mounted at its relative path, under the workbench's limits. MCAD, BOSL2 and Write.scad are built in.

  • knobs walks the Customizer parameters (// [min:max], // [a, b], true/false), writing each literal back into the source and re-rendering — never -D.

  • export writes stl (byte for byte the workbench's STL), 3mf, glb or obj from OpenSCAD's triangles. step is refused with the way out: the page behind preview converts the file to a STEP with exact surfaces.

  • preview hands out https://app.forgent3d.com/scad#code=<base64url>: the link carries the code, nothing is uploaded, and the page runs OpenSCAD on it with the parameters live and STEP/STL export. One link holds one file; a project that includes others is refused one and told to load the folder there.

  • rebuild — the product's rebuild_model: ok + bbox, volume, the cylinder census (each radius and where its axis runs), the planar faces (where every flat face sits), disjoint solids, per-body world bboxes, model.py's own print() output and the build diagnostics — or the first actionable error, with a non-zero exit.

  • check — the product's check_model: runs a --code snippet in model.py's namespace after it builds and prints what it print()s. Top-level def test_* functions run as isolated named checks (assert is allowed in the probe dialect only). Nothing is read from or written to the project; any failure exits non-zero.

  • knobs — does every published #@ knob survive its own range? Each is moved alone to its extremes — number range ends, the other switch state, every dropdown option — and rebuilt (broken / warns / inert / ok; warns = builds there but with a warning the default does not raise). Nothing else ever builds a non-default value.

  • snapshot — the 2×2 third-angle sheet by default; --view renders one view alone (left/back/bottom only exist that way); --line-art --xray is the product's compare dress — a line drawing with hidden edges dashed, the one to hold beside a drawing. --line N is the feature-level shot: the faces built by model.py line N (the same row the product's 说明书 shows) tinted orange, their edges dashed through material, the picture zoomed onto them — a 1×2 ALONG/ACROSS strip without --view, one view zoomed with it; the text names the faces, their box and per-view visibility. model.py only.

  • recipe — a focused reference bundled from the production *.recipe.ts (single source of truth), with the product's tool names translated to these commands.

  • export — writes the built model next to the source (--out to place it elsewhere). Entirely local; talks to no server.

  • preview — builds locally, then uploads model.py, the BREP, that build's scene.json (colours, materials, assembly poses) and the imports/ files model.py names (an STL a MeshRef shows, a STEP import_cad read — the page draws the mesh from the file, a remix rebuilds from it) to the anonymous preview endpoint and prints a share link. Anyone can open it, signed in or not: a 3D view of the part (in its colours — that is what the scene upload is for), and a browser editor where visitors can turn the #@ knobs, rebuilt in their own browser, but nothing is saved; remixing makes an editable copy in their own account. Nothing is built server-side. The secret that lets a later preview update the same link lives in .forgent3d-preview.json. Override the endpoint with FORGENT3D_PREVIEW_ENDPOINT.

Build

pnpm --filter @forgent3d/cad-build build   # regen cadkit snapshot + esbuild bundle + copy assets + gen recipes.json
pnpm --filter @forgent3d/cad-build smoke   # offline smoke of every command in an os-temp dir (preview against a mock server)

scripts/build.mjs regenerates cad-engine/src/cadkit-snapshot.json from cadkit/*.py (it is a gitignored generated file — copying whatever is on disk would ship a stale cadkit), bundles src/cli.ts → dist/cli.mjs with code splitting (BOSL2 and the Write.scad fonts land in dist/chunks/, loaded only by a file that uses them; web-tree-sitter and @forgent3d/openscad-wasm stay external), copies the runtime assets into dist/assets/ (tree-sitter*.wasm, occt-import-js.cjs + .wasm, cadkit-snapshot.json, and openscad/: the OpenSCAD full build — the render path never loads the slim one, so it is not shipped — its fonts and the GPL text from packages/openscad-wasm/dist), and generates recipes.json. pnpm typecheck runs tsc over src/. bin/cad-build.mjs points the engine at those assets via CAD_ENGINE_ASSETS_DIR / OCCT_WASM_JS / CAD_BUILD_ASSETS_DIR before loading the bundle.

Release

  1. build + smoke (above).
  2. Bump version, then npm publish from this directory (prepack rebuilds).
  3. Only then push skill text that uses new commands or flags: the skill's launcher runs @latest, so the CLI has to be on npm first.

Keep in sync

  • The report text is build-service's summary-format.ts, shared with cf-sandbox's rebuild_model / check_model — change it there and both surfaces move together.
  • recipes.json regenerates from packages/cloud/lib/aicad-agent/recipes/*.recipe.ts; a recipe that names a product-only tool fails the build (map it in TOOL_NAMES).

Relationship to the forgent3d skill

The skill (github.com/forgent3d/forgent3d-skills, mounted here as the forgent3d-skills submodule) is maintained independently — its SKILL.md is hand-written and evolves on its own. The only contract between the two lines is this CLI: the skill shells out to cad-build <cmd>, so the subcommand names, flags and output shape above are what must stay stable. Changing them is a breaking change for the skill.