dsh-cad — CAD Plugin for DeepSeek Harness
dsh-cad banner
English | 简体中文
A CAD plugin for DeepSeek Harness (dsh):
an embedded 3D/2D CAD viewer plus a native parametric modeling tool family
(OCCT kernel) in the Web UI, letting the agent build and inspect CAD geometry
step by step — "model while you watch".
Preview
A full modeling session, end to end: the agent builds a parametric assembly
from plain chat — a 120×80×8 base plate with R5 rounded corners, then four
bolt instances placed at the corners — while the resident CAD panel tracks
every step live (parts tree with per-instance colors, ViewCube, "装配体"
assembly tab, 5 instances · 1,740 triangles). The finished assembly exports
as a structured STEP document and the agent verifies it by reading the file
back — 2 solids, 3 products, 2 assembly usages, 1,125.00 mm³:
dsh-cad assembly session
Downloads
Cumulative downloads from the npm registry, refreshed daily by CI:
npm cumulative downloads
Feature Overview
| Capability | Description |
|---|
| ⚙️ Kernel chain: cadorange → occt.ts | Modeling goes through cadorange (the agent-native CAD runtime wrapping the occt.ts/OCCT WASM; public API + the supported cadorange/occt escape hatch for meshing/HLR/wire construction); the direct occt.ts adapter stays as the fallback tier — DSH_CAD_KERNEL pins one explicitly (the opencascade.js tier was removed in v0.15.1, −64MB install). The old "no editing after shell" seam is gone — fillet/chamfer/boolean keep working after shelling |
| 🔍 CAD viewing | STL / OBJ / STEP / IGES / BREP / DCPRT (3D), DXF / SVG (2D); interactive viewport in the resident right panel (orbit / zoom / wireframe / pan), with a one-line result row in the conversation |
| 🌗 Dark-mode surfaces | Every rendered surface follows the host theme — viewport slab, DXF/drawing strokes, the Three.js grid / XYZ triad / feature edges / default mesh color / sketch overlays, and the ViewCube plate; a theme flip restyles mounted viewers live. Overrides: --dsh-cad-bg, --dsh-cad-stroke, --dsh-cad-paper |
| 🧭 CAD editor interactions | Onshape-style ViewCube (26-zone click-to-orient), hover/click face & edge picking with live measurement (area mm² / length mm), Faces+Edges / Faces / Wireframe render modes, switchable BRep demo parts (bracket / flange / shaft) |
| 🏗️ Parametric modeling | Primitives, profile extrusion, loft, sweep, revolve, booleans, all-edge fillet/chamfer, shell, draft, patterns (linear/circular), transforms; profiles take curve segments (arcs/circles exact BRep; B-splines sampled approximation) — exact OCCT BRep, not a mesh approximation. cad_loft sections accept curves too: point loops, {through} splines or planar {profile} chains; smooth: true fits a periodic B-spline through point loops — one continuous B-spline lateral face instead of planar strips meeting at G0 creases |
| ✏️ Named sketches | Standalone named profiles (Sketch1…) kept in the document (cad_sketch_new / edit / list / delete); extrude/revolve/sweep reference them by name, and cad_sketch_edit rewrites the definition in place + replays the log, rebuilding every dependent feature — the parametric loop. Sketches render as Onshape-style in the viewport (refreshing live on edit), listed in a left-side (sketches + features, eye-toggle visibility, click-to-highlight bodies) over the Part tab |
Installation
The plugin is published to npm — one line:
dsh plugin --profile web add dsh-cad
The installer applies the bundled cordis.patch.yml (declared in the dsh.bundle manifest) automatically, so there is nothing to configure by hand.
Version requirements
- Node.js and dsh CLI (
@deepseek-ai/dsh): minimum versions live in
the badge row above and the engines field of package.json — kept out of
the prose so they never go stale
Install from source (dev mode)
git clone https://github.com/LAU-MARS/dsh-cad.git
cd dsh-cad
npm install && npm run build && npm test # deps include occt.ts (true-HLR drawing kernel, ~20MB wasm)
npm install -g @deepseek-ai/dsh pnpm
dsh web # let the first launch init the profile, then Ctrl-C
dsh plugin --profile web add /path/to/dsh-cad
dsh web
The patch insert ships as cordis.patch.yml in the package root and is applied by the installer via the same dsh.bundle manifest.
Set DEEPSEEK_API_KEY and you are ready — for example:
- “open bracket.stl” →
cad_view
- “model a 100×60×5 plate, punch a ⌀20 hole in the middle, R2 fillets on the four
corners, add a ⌀16 boss 20 tall, export plate.step”
→
cad_create_prim + cad_boolean + cad_fillet + cad_export, with the 3D tab
updating live at every step
- “build a snowman” → spheres + a cone nose + a cylinder hat (precise
at/axis placement)
- “add two more b1, one rotated 90 degrees” →
cad_assembly_insert + cad_assembly_move, the Assembly tab updates live
- “make an A3 drawing of b1 and export dxf” →
cad_drawing (three views + iso + dashed hidden lines + dimensions) → cad_export .dxf
Modeling Tool Family
| Tool | Description |
|---|
cad_view | Open a CAD file and render it in the viewer (resident panel) |
cad_info | Read-only geometry metadata (format / counts / bounding box / units / layers) |
cad_create_prim | Primitives (mm, Z-up); at for placement, axis for orientation (exact axis-angle rotation) |
cad_sketch_new | Create a named sketch (Sketch1…): {start, segments} / {circle} / flat points loop — referenced by name from the profile features |
cad_sketch_edit | Redefine a sketch (回改): the definition op is rewritten in place and the log replayed — every referencing feature rebuilds |
cad_sketch_list | List the document's sketches (name / form / size) |
cad_sketch_delete | Delete a sketch (refused while features still reference it) |
cad_extrude_profile | Extrude a closed XY-plane profile along +Z into a solid — inline points/segments/circle or a named sketch (sketch) |
cad_loft | Loft: skin a solid through successive closed sections (each a [x,y,z,…] loop in its own plane, or a curve/profile section); sections may differ in shape and point count; smooth fits a periodic B-spline through point loops for a crease-free skin; ruled for straight sides |
cad_revolve | Solid of revolution: revolve a closed profile around an axis (profile coords = (radius, height); curve segments supported — rounded rims exact); optional angle; accepts a named sketch |
cad_chamfer | Chamfer: bevel every sharp edge with one equal distance (mm) |
cad_pattern | Pattern: linear (delta spacing) or circular (principal axis + at point + sweep angle); creates copy bodies, fuse afterwards for one body |
cad_shell | Shell: hollow to a wall thickness (inward, outer skin preserved); open lists outward normals of the faces to open (empty = sealed). Runs on the occt.ts kernel; the result is a HOSTED body |
cad_draft |
After every modeling step: the chat result row updates in place (stable viewId +
versioned URL), and the resident panel's "Part" tab tracks the latest model in real time.
Connectors (roadmap)
Modeling runs on the occt.ts kernel via cadorange (OCCT in the browser —
zero install). The connectors below refer to external CAD engines acting as
executors for the same tool family, planned for future support:
| Connector | Suite | Platform | Status |
|---|
| Built-in kernel | CAD modeling kernel based on OCCT + WebGL, runs in the browser — zero install | All platforms (WebGL rendering) | ✅ Built-in |
| FreeCAD | open-source parametric suite — natural local executor via its Python API (console + GUI window modes) | Windows / macOS / Linux | ✅ Available (needs local install) |
| Fusion 360 | Autodesk CAD/CAM — resident add-in + spool bridge (no headless; the Fusion window doubles as a viewer) | Windows / macOS | 🧪 Experimental (cad_fusion) |
| SolidWorks | Dassault Systèmes industry-standard 3D CAD, COM/.NET automation | Windows only | 🚧 Windows demo scaffold (scripts/solidworks-bridge/) |
| Onshape | PTC cloud-native SaaS CAD, fully in the browser — signed REST API (cad.onshape.com or chamber hosts); every op compiles to a standard Onshape feature pushed into the Part Studio, results read back as per-part STL + mass properties, the cloud is the viewer | All platforms (browser) | ✅ Available (cad_onshape; set DSH_ONSHAPE_ACCESS_KEY / DSH_ONSHAPE_SECRET_KEY) |
| ZW3D(中望3D) | ZWSOFT all-in-one CAD/CAM | Windows / Linux | 🚧 Planned |
| GstarCAD 3D(浩辰3D) | Gstarsoft 3D CAD | Windows | 🚧 Planned |
All external engines implement the same GeometryExecutor contract (available() /
run(opProgram) → meshes), so the WebGL display layer never changes — swapping a
backend changes only the quality of the produced geometry.
Architecture
cad_view(path) modeling tools (cad_create_prim, …)
→ import worker (occt-import-js) → modeling worker (occt.ts WASM via cadorange)
→ CadScene JSON (base64-f32) → exact BRep geometry + meshing
→ GET /dsh-cad/scene/<id> → in-memory binary scene (f32/u32 packed)
→ GET /dsh-cad/bin/<docId>
↓ session presentationMeta (viewId + versioned URL) ↓
browser card + persistent "3D" tab (three.js / SVG, Z-up, XYZ axes)
- Two workers: import (occt-import-js, read-only STEP/IGES/BREP) and modeling
(cadorange over the occt.ts wasm) are separate, both lazily started
- Zero-copy pipeline: modeling scenes use zero base64 / zero large JSON arrays /
zero per-step disk writes (disk mirror debounced 1.5s, replayed only on service
restart);
cad_export is the only explicit file export
- Modeling document:
<workspace>/.dsh-cad/model.json operation log; all bodies
are restored by replay after a restart
- Drawing HLR kernel: hidden lines run on occt.ts (npm dependency,
npm i occt.ts) — true OCCT removal, no fallback engine, a missing kernel is
a hard error. Kernel APIs: hiddenLines() true hidden-line
removal, byte-level STEP/BRep readStep/readBrep/writeStep/writeBrep
without MEMFS, tessellation with built-in feature-edge extraction, and a
hasError()/lastError() error contract. Geometry crosses kernels as STEP
bytes and the projected segments are remapped into the sheet frame. Kernel
dist resolution: DSH_OCCTJS_DIST env var → Node's own resolution of the
occt.ts dependency (walks up every parent node_modules — npm/yarn flat and
pnpm symlink layouts all hit) → <repo>/../opencascade-ts/dist (sibling
checkout) → vendor/ → node_modules/opencascade-ts
- Constraint solving (Ansatz): the solver is the npm dependency
ansatz-wasm (a wasm-bindgen build, single package ~538KB, zero deps) —
installing dsh-cad pulls it automatically, and npm install ansatz-wasm alone
upgrades it. No Rust toolchain, no native binary, platform independent.
Resolution: the npm package (node_modules) → a DSH_ANSATZ_WASM directory → a
sibling Ansatz checkout's pkg-node. The solver speaks one JSON envelope
contract, with tool-layer errors (e.g. unsupported_constraint) surfaced
verbatim for the LLM. Assembly placements (translate + XYZ Euler
degrees) map bidirectionally to the solver's rigid3 poses (translate +
exponential-map rotation, radians). Solver capability is staged
(point-distance-to-origin today) — the plumbing contract is finished and needs
no changes as it grows
- Kernel chain: modeling goes through cadorange (agent-native CAD
runtime; public build123d-style API for prims/curve-segment profiles (TRUE
B-spline interpolation)/loft/sweep/revolve/booleans (cleaned by default)/
fillet/chamfer/shell/draft/native mirror/centroid, plus the supported
escape hatch for viewer tessellation, engineering-drawing
HLR (zero STEP hops, one wasm session) and wire construction); the direct
occt.ts adapter stays as the fallback tier ( pins one; see
docs/cadorange-integration.md for the verb-by-verb mapping). Editing after
shelling is seamless. Assembly STEP export writes a
(cadorange
): one root product plus one named, placed child
per instance — instance separation survives the file (STL stays a single
fused mesh). Instance separation stays in
the assembly scene/document for the fuse paths.
Face selection matches plane normals (outermost along ±normal)
Theming (dark mode)
The viewer follows the host appearance automatically. DSH publishes the theme as
color-scheme on <html> plus body[data-ds-dark-theme]; the plugin resolves
that (falling back to prefers-color-scheme) and themes every surface the host
tokens cannot reach:
- the viewport slab behind the transparent WebGL canvas and 2D scenes,
- default 2D entity strokes (DXF / engineering-drawing entities),
- the Three.js ground grid, XYZ axis triad/labels, feature edges, default mesh
color and sketch overlays,
- the ViewCube face plate (canvas texture).
A theme flip restyles mounted cards and the resident panel live — no reload and
no lost camera. Engineering drawings loaded as SVG keep a white sheet; in dark
mode it is framed as paper on the dark slab instead of filling the viewport.
Hosts can override the surfaces the plugin owns; an explicit definition wins in
either theme:
| CSS variable | Applies to | Default |
|---|
--dsh-cad-bg | viewport background (any CSS background value) | light #f5f6f8→#e9ecf0, dark #1b1b1c→#151517 |
--dsh-cad-stroke | default 2D entity stroke | #4c5561 light / #c8ced6 dark |
--dsh-cad-paper | drawing paper behind SVG sheets | #ffffff |
:root { --dsh-cad-bg: #0b0d10; } /* flat canvas in both themes */
Tests
npm test # full suite: converters / modeling worker (exact volume assertions) / DCPRT round-trip / FreeCAD + Onshape executors / image profiles / binary pipeline / document persistence
node test/route-check.mjs # JSON scene routing layer
node test/visual/serve.mjs # browser card/tab visual verification page (http://127.0.0.1:3987)
Representative assertions covered: the boolean-punched volume exactly equals the
analytic value (28429.20 mm³), L-shaped profile extrusion 3000 mm³, volumes and
bounding-box flips of sphere/cone/torus placed with at/axis, 8-byte alignment
of the binary packing, an STL export round-trip (export → read back by the
phase-1 parser), and a DCPRT document round-trip (serialize → replay on the
OCCT worker → exact bounds).
Known Limitations
- DWG (closed-source) is unsupported; DXF bulge arcs are approximated by chords;
glTF/3MF viewing is not implemented (the structure is reserved)
cad_fillet is all-edge constant-radius (per-edge selection is unstable under
embind); chamfer is not implemented
- Sketch extrusion supports polygon profiles only (arc profiles are constructed by
boolean combinations of cylinders/tori)
- dsh framework limitation: an already-mounted single slot (the right-side details
panel itself) does not respond to components registered later, so the persistent
view is provided as the "3D" view tab (a list slot, the official composition)
- The host reads CAD files via node:fs (the platform fs service supports UTF-8 text
only and cannot carry binary data)
Community
| QQ Group (🇨🇳 China) | Feishu (🇨🇳 China) | X / Twitter (🌍 International) | Discord (🌍 International) |
|---|
485038246 (join note: dsh-cad) | 🚧 Coming soon | 🚧 Coming soon | 🚧 Coming soon |
Contributors
Auto-generated from the commit history — thanks to everyone who has contributed!
Contributors
License
MIT