cad

GitHub

用于3D参数化CAD建模、编辑、装配组织及多格式导出。支持几何测量、动画生成及现有文件审查,基于Python build123d实现文本驱动的设计与验证。

skills/cad/SKILL.md earthtojake/text-to-cad

Trigger Scenarios

创建或编辑3D零件/装配体 导出STEP/STL等CAD文件 几何尺寸测量与检查 生成机械运动动画 查看或审查现有CAD模型

Install

npx skills add earthtojake/text-to-cad --skill cad -g -y
More Options

Use without installing

npx skills use earthtojake/text-to-cad@cad

指定 Agent (Claude Code)

npx skills add earthtojake/text-to-cad --skill cad -a claude-code -g -y

安装 repo 全部 skill

npx skills add earthtojake/text-to-cad --all -g -y

预览 repo 内 skill

npx skills add earthtojake/text-to-cad --list

SKILL.md

Frontmatter
{
    "name": "cad",
    "license": "MIT",
    "metadata": {
        "repository": "earthtojake\/text-to-cad"
    },
    "description": "Creates and edits parametric CAD parts and assemblies as Python build123d models that text-to-cad's server builds and the CAD Viewer shows live; exports STEP, STL, 3MF, GLB and xbf files on request; resolves prompt references, measures geometry, and articulates or animates assemblies. Use for 3D CAD modeling, editing a model script (any change to a part's or assembly's `.py`), organizing a CAD project, exporting or converting CAD files, Quick Edit prompts, mechanisms, and explode or showcase animations. Opens and reviews existing XBF, STEP\/STP, STL, 3MF and GLB files in the CAD Viewer. Covers 3D parts and assemblies, including the part a 2D drawing projects, not the 2D DXF drawing itself or URDF, SRDF and SDF robot descriptions."
}

CAD modeling and inspection

A model is a Python function; running its script rebuilds it in text-to-cad's warm server, and the page the person has open updates. Files are exports, made when asked.

Start with the task

Task Start with Reference
Create or edit a part or assembly The project's model script, or a new one (below). Models, build123d, positioning
Organize a CAD project The project's existing layout. Project layout
Export STEP, STL, 3MF, GLB or xbf cad export <id> <file>. Exports
Use a vendor STEP, an xbf or a scan in a model read_step, read_xbf or read_mesh in the body. Inputs
Resolve a reference from a prompt cad inspect <id> '<ref>'. References
Measure or check geometry A check script that calls the model. Inspection
See a model, a view or a pose cad snapshot <id> out.png. Snapshots
Articulate a mechanism build123d joints in the body, then cad.ap242. Kinematics
Explode, reveal or showcase a model cad.gltf's animation() in the body. Animation
Open an existing XBF, STEP/STP, STL, 3MF or GLB Show it to the user. Show the model

Setup and paths

Run the cad command (~/.local/bin/cad where ~/.local/bin is not on your PATH, or where a project's environment puts its own cad first; cad.cmd on Windows). If cad is not found and the CAD app was only just added, its server may still be starting: wait five seconds and run the command again, for up to a minute, before anything else. Otherwise install text-to-cad, outside a sandbox or with its permission:

curl -fsSL https://texttocad.dev/install.sh | sh

On Windows, in PowerShell: irm https://www.texttocad.dev/install.ps1 | iex. Any other failure says what to do, and cad doctor explains the installation.

One server runs for the installation: the first run starts it, every run and every command goes through it, and it serves the viewer. cad status lists its workers and the documents it holds; cad stop stops it. A build cut off by the shell's time limit keeps running in the server; run the same command again and it waits for that build and replays it (cad status shows it). Give a cold build of a large model the shell tool's longest timeout, or run it in the background.

Build every model with cad run. It needs nothing set up: it runs a script in the server's own environment, which holds the library and build123d. A model that needs another package names it at the top of its script, and cad run installs it beside the kernel once, in an environment it keeps for the runs after:

# /// script
# dependencies = ["pandas>=2"]
# ///

For a one-off, cad run --with pandas src/plate.py (repeat --with, or separate requirements with commas; a local folder or wheel works too, its path relative to the working directory, or in the block to the script's folder, and the next run installs it again after an edit). What cannot be installed beside the kernel is refused in one line with uv's reason: change the requirement it names, or, where the network is needed once, run it outside a sandbox or with its permission. In Windows PowerShell, put a version constraint (>=, <) in the block, not on the command line: PowerShell hands it to cad.cmd unquoted, and cmd reads > as a redirection.

Command-line paths, and the paths read_step, read_xbf, read_mesh and export take, are relative to the working directory, as are a model's own file reads. Anchor them on __file__ in code that must run from any folder.

Write a model and run it

A part or an assembly is a function with no parameters, decorated @model (or with its file decorators, never both), that returns a build123d shape. Its dimensions are the arguments of a plain helper function, and each configuration is a @model of its own, with its own id and page; constants several models share live in a module they import. A call builds it and returns its document: a handle with .id, .url, .shape (the built shape) and .export(...). For example, src/bracket.py:

import build123d as bd
from cad import model


def bracket_body(width, thickness, bore):
    body = bd.Box(width, 20, thickness)
    hole = bd.Cylinder(bore / 2, thickness)
    body = body - hole
    body.label = "bracket"
    body.color = "#4a6fa5"
    return body


@model
def bracket():
    return bracket_body(40, 6, 8)


@model
def bracket_wide():
    return bracket_body(60, 6, 8)


if __name__ == "__main__":
    bracket()
    bracket_wide()
cad run src/bracket.py
built src/bracket.py::bracket cold in 2.61s: bodies 1 run; 6 misses, 0 hits; body 0.01s, names 0.00s, document 0.00s
  parts 1 · bounds 40 × 20 × 6 mm · joints 0 · sequences 0
  id: 0dc50a92-a21f-5895-a245-ebdeb5352f3b
  view: http://127.0.0.1:54360/0dc50a92-a21f-5895-a245-ebdeb5352f3b?token=...
built src/bracket.py::bracket_wide warm in 0.01s: bodies 1 run; 6 misses, 0 hits; body 0.01s, names 0.00s, document 0.00s
  parts 1 · bounds 60 × 20 × 6 mm · joints 0 · sequences 0
  id: 966d03a5-7b43-5bed-b75c-eb67d56c72d2
  view: http://127.0.0.1:54360/966d03a5-7b43-5bed-b75c-eb67d56c72d2?token=...

Each call the script's __main__ makes prints how its model built, the delta under it (parts, bounds, joints and sequences), its document's id: and its page, view: (the handle's .id and .url). An unchanged rerun prints took ... nothing ran instead. Give the user the page once (Show the model) and use the id for every command after it. The id comes from the script's path and the function's name, or the script's folder and an explicit @model(name="..."), so it is the same run after run, and the open page follows every run. A model's name is its identity within its namespace, the function's name by default, name= gives it another. The namespace is the script's folder; two explicit names in it must differ.

  • Running the script is the rebuild. It writes no file. The server's warm worker for the script replays every operation an edit did not reach, so a comment re-runs nothing and a dimension edit re-runs what reads it (what a run runs). Decoration only declares: keep the calls under if __name__ == "__main__": so other scripts can import the models.
  • @memo marks stages, never parts. The server already replays every kernel call, so mark only a function holding seconds of kernel work that an edit elsewhere leaves alone, such as a whole sub-assembly stage; never a part, never a helper called many times (@memo).
  • An assembly calls its parts. Its body calls each part model and composes its shape (plate().shape), places and labels it, and returns a Compound. Each child builds in the same run and keeps its own document and id. Running a child's script alone leaves the assemblies that use it as they were: run the assembly.
  • import build123d as bd, and use it attribute-style (bd.Box). The import is lazy: the kernel loads on first use, in the worker. from build123d import Box, or a module-level bd.Color(...) or bd.Align default, loads it at that line instead.
  • Colours are sRGB, as a person picks them: part.color = "#4a6fa5", or 0-255 integers. Import metals from bd_materials; assign a native material with part.material = metals.aluminum() (colour and materials).
  • Inputs are read_step, read_xbf and read_mesh in the body, and any file its Python opens, each tracked by its bytes. The clock, environment variables and randomness are not seen: a body is a function of its code and its inputs. Compose project models by calling them, never by reading a file the project exported.
  • References to faces, edges and parts come from cad inspect <id> [ref], and the body picks the same element with build123d's selectors; verify with a snapshot when in doubt (references).
  • A shape with no function (a notebook cell, a REPL) is handed over: model(shape, name="plate") returns the same handle, and no command builds it again.
  • The server never reruns code. A restart reopens every document from the server's cache, as last built. When the cache holds no file of one (deleted by hand, or never saved), the page, cad inspect <id> and cad_show print the command that brings it back (cad run src/bracket.py). Run it.
  • Model units are millimetres, +Z up.
  • An image without a scale sets no fit dimension, and a drawing's units, projection and revision decide how its numbers read. A missing or conflicting dimension that changes the result is the person's to settle; a value chosen in its place is an assumption.

Files, when asked

A file is an action on the document the server holds, never part of the model: no code change and no rebuild, written at once. It holds what the document held when it was written, so a change made after it is in the file only once it is written again. Write one when the person asks for it:

cad export "$ID" STEP/bracket.step STL/bracket.stl GLB/bracket.glb 3MF/bracket.3mf

A project with standing deliverables gets an exports.py that imports its models and calls export(x, path, ...) on each (x a model call's handle); running it rewrites every deliverable (exports). An export takes a document and its destinations, and nothing else: a posed file is a model that returns the posed assembly (posed(arm(), "folded")), and a part on its own is the part's own model.

The xbf, text-to-cad's own document, is Save As: export one only to share a model without its code, or to compose it in another project with read_xbf. A restart needs none: the server's own cache reopens every document it built, as last built. A vendor STEP is converted to an xbf once (cad export vendor/motor.step vendor/motor.xbf) and read with read_xbf, many times faster than parsing the STEP.

Projects built around exported files

A project can instead revolve around its exported files, but only when the person asks to iterate on the exported file itself or the project already does: an exports.py, a consumer that reads the files (a robot description, a slicer, a drawing pipeline), or a 0.7-era layout, whose runs wrote files. The loop is three steps. The script writes the file on each run, by a file decorator in place of @model (@step("../STEP/bracket.step"), relative to the script), or exports.py or cad export follows the run. Show the file's page, not the model's: it follows the file on disk, updating when a run rewrites the file. Verification reads the file: cad snapshot or cad inspect with its path, or read_step in a check. The costs keep the default the default: each iteration pays the file's translation and the page's re-read, a STEP parsed again; a file names no model, so a ref picked on its page has no made_by and a Quick Edit from it no way back into the code; and the model's page stays the better place to look while editing. Exports tables the triggers and costs.

Pictures

After every run, read its line and the delta under it; a contradiction with what you intended is fixed before anything else. A number the person gave is checked by an assert inside the model's body on what the geometry measures, a bound, a distance or a volume, or by cad inspect, never by restating the constant, and never by code after the call in the model's script (inspection). A derived number they asked for is a check script; neither is ever read off a picture. A structural or appearance change, new parts, placements, colours or a mechanism, gets the snapshots it takes to judge it, usually one from the angle that shows the change, more when a view leaves the question open, and a posed one for a mechanism state; never several angles by habit. For a large assembly, isolate the parts the edit touched or hide what covers them and frame them, instead of drawing the whole model. Resolve a reference with cad inspect only when a prompt names one.

cad snapshot "$ID" tmp/review.png
cad snapshot "$ID" tmp/top.png --camera top --display hidden-line
cad snapshot "$ID" tmp/open.png --pose open

A snapshot draws the document as the viewer does, rendered by OCCT, and writes nothing but the PNG. Its options say how the picture is drawn: camera (--camera top), display, grid, pose (--pose open) and size. It shows arrangement and appearance, not dimensions (snapshots).

Prompt references and inspection

A reference such as 0dc50a92-a21f-5895-a245-ebdeb5352f3b#bracket/face 7 names geometry in a document by the server's own names: the document (a model's id, or a file's absolute path), #, a part or an assembly by the labels on its way from the root (hand/finger.2 is the second component labelled finger in hand), then, after a slash, one element by its name (f:, e:, v:) or its number (face 7). The CAD viewer copies them. When a prompt names one, resolve it with cad inspect:

cad inspect "$ID" "bracket/face 7"

It answers in JSON what the ref names, placed where its occurrence stands: an element's canonical ref, kind, ordinal and name, the kernel's facts (a face's area, centroid, surface, box, radius; an edge's length and endpoints) and made_by, the function, file and line of the code that made it; a part's or an assembly's volume and mass. Edit the code made_by names, or pick the element in the body with build123d's selectors (body.faces().sort_by(bd.Axis.Z)[-1]) matching those facts. A ref resolves in the document as the latest run left it; one that names nothing, or several things where it names one, is refused with what it could mean. The grammar is in references.

A Quick Edit prompt names its document under File: (a path or an id), selected entities under References:, and a snapshot packet as inline JSON or a .snapshot.json path. Save inline JSON to a temporary .snapshot.json, and draw the view the person drew their ink in, ink included:

cad snapshot "$ID" tmp/quick_edit.png --annotation tmp/bracket.snapshot.json --camera authored

Inspect supplied annotations before editing. Without annotations, the captured view is optional context; render it when useful to the request. After editing, run the script and draw it again to check the change (annotations and Quick Edit views).

A reference into a file that is not a document names what the viewer picked in it, in that file's own terms (none is a ref cad inspect resolves):

File Reference Means
URDF, SRDF, SDF /work/arm/arm.urdf#upper_arm the link upper_arm
GLB /work/out/model.glb#n12 the glTF node nodes[12] (0-based, the file's own index)
3MF /work/out/plate.3mf#o2.1 the 2nd <build><item>'s 1st <component> (1-based); #o3 is the 3rd build item
STL the file alone, on File: one mesh: nothing in it is picked

Check the design

A check is a Python script that calls the model and measures what it returns, so it tests the model as it is now. Write one only when the person asks for a dimension, a fit or a mass, or when the change is numeric and the number matters (Pictures):

Copy world_parts and find_part from Opening geometry into the check first. They accumulate parent placements; raw .leaves do not.

from cad.geometry import closest_points

from assembly import assembly

kit = assembly().shape                       # rebuilt (replayed), returned as a tree
plate = find_part(kit, "plate")               # copied into world coordinates
post = find_part(kit, "standoff_left")        # refuses missing or repeated labels
print(plate.bounding_box().size)              # the envelope: not a hole's diameter or a wall's thickness
print(closest_points(plate, post).distance)   # 0: the standoff sits on the plate
  • Measuring is what shows a request's dimensions and clearances. In an assembly, nothing interferes when overlap_volume is 0 for every pair of solids apart from fits named on purpose, and a part meant to rest on another touches it when their closest_points distance is 0. Both describe the parts as built, not a pose (measurements).
  • cad inspect "$ID" <assembly label> weighs an assembly (the label it was given, which is also the root name inspect "$ID" prints): each part's volume times its material's density, and the parts that have no material.
  • A check that fails or cannot decide has shown nothing about the design.
  • A retry that leaves out or shrinks a specified feature (a fillet skipped, a radius reduced) builds a different design from the one asked for.

Hand off

The reply is the person's record of the work: the models made or changed, the files written, the checks run and what they showed, the requirements no check covered, and every assumption or departure from the request.

Show the model

Show the user each model you create or change, and any model or file they ask to see. A file you export is a download: give its path, do not open it. Snapshots and validation don't replace this. Never screenshot the viewer to confirm your own work; review with cad snapshot.

  • If your tools include cad_show (your host may prefix it), call it with the model's id or the file's absolute path, and follow its description for when to call it again. The other tools depend on the host. A host that draws CAD cards or tabs (Claude Desktop, the Codex app) also has cad_view, which reads what the user selected, and cad_screenshot, which shows you what they see, both of a card or tab that is open, for when they ask about it. A text host (Claude Code in a terminal, codex exec) draws nothing: its cad_show opens the model's page in the user's browser and answers with the URL to give them, and it has no view to read. cad_inspect, cad_snapshot and cad_export are on every host. Call only the tools you have, and never say a card shows a model when your host drew none.

  • Otherwise give the user the page's link once: a model's page is the view: line its run prints. For a file, run the CAD Viewer, from any folder:

    cad viewer --json FILE [FILE ...]
    

    The command ensures this installation's server, registers each file and prints its page, /<id>, then exits. Read each file's url from documents in its one JSON line (never guess the port); the URL carries its token query. A page follows every later run of its model and every rewrite of its file, so share it once. Return that link to the user. If it fails to launch, say so.

Exact selection and measurement need a model's document, an .xbf or a STEP; mesh viewers measure approximately, on triangles.

Version History

  • 5efa85a Current 2026-11-02 19:24

    版本升级至0.10.0,重构为单一环境三种分发形式;简化技能配置,移除旧版setup指南;统一使用cad run构建模型,优化包依赖管理及Windows/macOS兼容性。

  • 284827c 2026-10-19 02:43

    版本0.7.23更新:修复URDF网格错误、多面引用复制解析问题、Windows字体缺失导致导入失败的问题,以及SDF视频验证和CI配置修正。

  • 4eaf745 2026-09-22 08:13

    将CLI几何检查替换为Python脚本原生形状检查,移除旧版inspect CLI;新增read_scene缓存与引用选择功能,简化技能文档结构。

  • d0e4cb6 2026-09-09 02:39

    cadgen升级至0.5.0版本:重构模型图与构建流程,引入内容寻址树与缓存;简化装饰器逻辑,分离动画渲染;重写cad技能以符合新契约;优化发布流程与资源管理。

  • 0.4.12 2026-08-16 02:06

    修复CLI中缺失的--lock-timeout和-i参数,解决文档与实现不一致问题。

  • 0.3.9 2026-07-24 11:54

Same Skill Collection

plugins/cad/skills/bambu-labs/SKILL.md
plugins/cad/skills/cad-viewer/SKILL.md
plugins/cad/skills/cad/SKILL.md
plugins/cad/skills/dxf/SKILL.md
plugins/cad/skills/gcode/SKILL.md
plugins/cad/skills/implicit-cad/SKILL.md
plugins/cad/skills/sdf/SKILL.md
plugins/cad/skills/sendcutsend/SKILL.md
skills/bambu-labs/SKILL.md
skills/cad-viewer/SKILL.md
skills/dfam-check/SKILL.md
skills/dfm/SKILL.md
skills/dxf/SKILL.md
skills/engineering-drawing/SKILL.md
skills/gcode/SKILL.md
skills/implicit-cad/SKILL.md
skills/sdf/SKILL.md
skills/sendcutsend/SKILL.md
skills/srdf/SKILL.md
skills/urdf/SKILL.md
plugins/cad/skills/srdf/SKILL.md
plugins/cad/skills/step-parts/SKILL.md
plugins/cad/skills/urdf/SKILL.md
skills/step-parts/SKILL.md

Metadata

Files
0
Version
5efa85a
Hash
2c822d8e
Indexed
2026-07-24 11:54

Accueil - Wiki
Copyright © 2011-2026 iteam. Current version is 2.155.2. UTC+08:00, 2026-11-03 04:23
浙ICP备14020137号-1