robertcoop/openscad-mcp/openscad-design
Claude Code and agent skill by robertcoop/openscad-mcp
- community
Checking that the SKILL.md file is still in the repository.
Design, modify, and verify 3D-printable parts and assemblies in OpenSCAD through the openscad-mcp tools. Use when the user asks for a bracket, enclosure, adapter, jig, or other parametric part, or wants an existing .scad file changed, measured, fit-checked, or exported for printing.
Install
npx vskill@latest install robertcoop/openscad-mcp/openscad-designSKILL.md
OpenSCAD design loop
One rule sits above the rest: numbers decide, pictures confirm. A render is a low-bandwidth summary of geometry. Vision models routinely rate a broken model as fine, because a missing internal wall, a 0.02 mm gap, or a non-manifold seam looks identical to a correct part at 800x600. Never conclude "that looks right" from an image. Conclude it from measure and validate, then use the image to catch the class of error numbers miss: wrong orientation, a feature on the wrong face, a part that is inside-out.
The loop
1. State assumptions before writing code
Say these out loud in one or two lines, because they are invisible in the source and wrong in half of all first attempts:
- Units: OpenSCAD is unitless; everything here is millimetres.
- Orientation: which axis is up, and which face sits on the print bed.
- Datum: where the origin is. Corner-at-origin and centred-on-origin are both
fine, but say which, and keep it consistent across parts of an assembly.
- Print process: FDM layer height and nozzle width if the user has not said,
because they set minimum wall and minimum feature size.
2. Declare key dimensions as variables
Every number that the user might change, or that appears more than once, becomes a named variable at the top of the file. Derive the rest with expressions rather than retyping arithmetic. This is what makes step 6 cheap: an iteration becomes one variable edit, not a search-and-replace through solid geometry.
3. validate(mode="syntax") first
Before any render or export. OpenSCAD's exit code is not a success signal: a failed assert(), an unknown module, a missing include, and an unclosed polyhedron all exit 0 while printing to stderr. validate parses that stream. Read errors, warnings, and hints on the response. Fix everything in errors before moving on and read every warning, since "Ignoring unknown module" means a whole feature is silently absent from the geometry you are about to measure.
4. measure before you trust any picture
measure(mode="model") exports the mesh and returns exact numbers: bounding box, dimensions, volume, surface area, component count, watertightness. Compare those against the dimensions you intended. A bounding box 0.4 mm larger than expected is a clearance bug you would never see in a render.
measure also accepts an existing STL through mesh=, so you can measure a file the user already has without re-rendering it.
Modes: model for the whole thing, parts for per-solid numbers and the solid count, section for a cut plane, mass for volume-times-density estimates. The rest — probe, features, printability, orientation, anchors — are in the tool reference at the end.
5. render(grounded=true), one to three views
Only after the numbers agree. Ask for the smallest number of views that answers the open question, usually one isometric plus one orthographic view of the face in question. More images degrade the model's own counting and comparison, so a four-view contact sheet is worse than one well-chosen view, not better.
Modes: views for standard camera positions, section for a cut, parts for per-part colouring, compare for before/after.
6. Multi-part designs
- One module per part.
module lid() { ... },module body() { ... }, and a
separate assembly view that translates them into place. Never one monolithic union.
- Overlap coplanar faces by epsilon. Two solids that exactly touch along a face
or an edge produce a non-manifold result that CGAL drops or reports as not 2-manifold. Add eps so the parts genuinely interpenetrate, and subtract eps on through-holes so the cutter pokes out both sides.
- Get clearances from `reference(topic="fits")`, not from memory. Press fit,
slip fit, and free fit differ by tenths of a millimetre and the right number depends on the process. Related topics: fasteners, inserts, bearings, magnets, joints, dfm, materials, conventions, cheatsheet.
- Check the solid count.
measure(mode="parts")should report exactly as many
components as you designed. Two when you expected one means a part is floating free; one when you expected two means they fused and will print as a single lump.
- Check manifoldness.
validate(mode="geometry")returnsmesh_health. Look at
mesh_health.manifold: true is good, false names the defect in mesh_health.issue, and null means the check was not performed, which is not the same as passing.
6b. Assemblies: name the parts, then ask check
Once a design has more than one part, stop reasoning from pictures and give the server the parts by name. Every part is exported separately (never unioned), so identity survives and every relation is a number in the assembly frame.
stateisclear,contact, orinterference. Flush contact is contact,
never interference; a sliding pair (a pinion on a plate) that reports contact is the defect, so declare motion on the moving part and use contact with kind="sliding".
mode="clearance"gives the exact minimum distance and both closest points;
mode="motion" sweeps a part about an axis or along a vector and, for a full turn, adds a certificate that says whether the parts can ever touch.
mode="alignment"is the only check that sees a 0.6 mm hole misalignment:
interference and clearance both read zero there.
rule: massin a check file limits total mass, centre-of-mass offset from an
axis or point, and inertia about an axis, composed from the exported meshes with each part's mass_g, material or density_g_cm3 (PLA if none, flagged).
- Write coordinates and limits in check files as SCAD expressions of the model's
parameters (point: "[BOLT_R, 0, BASE_H]", min_mm: "GAP_MIN"), never as copied numbers: a copied number keeps passing after the parameter changes.
- Every row carries
quality.fn. A distance smaller than the tessellation error
bound comes back UNRESOLVED; re-run with quality="high" or an integer $fn.
measure(mode="probe")answers "is there material at this point, and whose",
ray casts ("does the scanner see the card"), and line-of-sight polylines.
measure(mode="features")lists the holes a part cuts (axis, diameter, depth,
fit name) straight from the CSG tree, and reference(topic="fits", diameter_mm=3.3) names what a hole is.
- Freeze the rules in a check file (YAML:
frames,quality,parts,checks,
model) and re-run check(check_file=..., mode="rules") after every edit; openscad-mcp check file.yaml does the same from a Makefile.
Purchased parts. reference(topic="parts") lists the five sourced entries: 28byj-48, nema17, lazy-susan-4in, kw11-3z (snap-action microswitch) and tcrt5000-module. model(action="create", template="part:28byj-48") writes BOSL2 modules with named anchors, a clearance mask for difference(), and a verify[] list of dimensions to confirm on your own motor. The module names come from the entry, not from the id: 28byj-48 gives part_28byj48(), part_28byj48_mask(), part_28byj48_mount_holes_mask() and part_28byj48_info(). Design the pocket from the part's named numbers, then let check prove it: the mask, not a minkowski() grow, is the pocket; hull() of two poses is wrong for an insertion sweep.
Before printing. measure(mode="printability", orientation=[180,0,0]) gives overhang patches with their unsupported reach, the wall-thickness distribution against the nozzle, islands, and a support estimate. mode="orientation" lists candidates but names no winner; you decide by which faces must look good. validate(mode="printability") turns the facts into findings with thresholds.
7. Iterate by changing a variable and re-measuring
Change one variable, re-run measure, compare the number to the previous number. That is the whole inner loop. Use scad_eval to check a derived expression in the design's own parameter space before you commit to a render: it evaluates expressions against the file's variables and returns typed results, which is far cheaper than rendering to find out that lid_inner came back undef.
8. export_model last
Export only once the numbers and the manifold check pass. STL for printing, 3MF when you want units and metadata preserved.
Worked example: a box with a lid
What to read in every response, in order: errors, then warnings, then hints (these carry the specific repair advice for the message class OpenSCAD emitted), then the payload. On renders and measurements also check cached. A cached: true response is a previous result replayed; if you edited an included file rather than the top-level source and the flag says cached, the number you are looking at may predate your edit. Force a fresh run or clear_cache before believing it.
Reading a render
Every render arrives as a text digest followed by an image. The digest is the part you reason from. It states the units, the up-axis and handedness, the exact camera eye, center, and up vectors, the projection, the view direction in plain language ("camera looks along +Y; +X is right, +Z is up"), the model's bounding box, and the scale in millimetres per pixel.
- `grounded=true` gives orthographic projection and a real scale. The stated
mm/px is true everywhere in the frame, so you can measure a feature by counting pixels and multiplying. Annotations and a scale bar are drawn into the image.
- The mm/px guarantee holds only under orthographic projection. Under the default
perspective camera the scale varies across the image and no single number describes it.
- Auto-framed renders have unknown absolute scale. Anything rendered with
--viewall fits the model to the frame, so a 2 mm cube and a 500 mm cube come out pixel-identical. Use those images for shape and topology only. If a question is about size, either read the bbox from the digest or ask for grounded=true.
Gotchas that bite most often
Variables are compile-time, not sequential. OpenSCAD assignments are resolved before evaluation, and the last assignment in a scope wins for the whole scope. This does not work:
This is the start of the file. Read the full SKILL.md on GitHub.
Security
- Security scanPassed, 100 of 100Pattern checks on the skill's files.
- Model reviewNot runA model review is scheduled for the next rescan.
Quality evaluation
- Task evaluationNot runNo evaluation yet. Run one in Skill Studio.
Source
- SKILL.md in the repositoryCheckingskills/openscad-design/SKILL.md
Popularity
- Repository stars
- 142
- Repository forks
- 18
- 7-day trend score
- 25
Stars and forks are for the whole GitHub repository, not this skill alone. Not refreshed yet.
Works with
Any agent vskill installs to: 56 targets in all. These 39 have a page on this site.
- Claude Code
- Cursor
- GitHub Copilot
- Windsurf
- Codex
- Gemini CLI
- Cline
- Amp
- Roo Code
- Goose
- Continue
- Kilo Code
- Junie
- Trae
- OpenHands
- Qwen Code
- AI Agent
- Tabnine Chat
- Sourcegraph Cody
- Amazon Q
- Firebase Genkit
- Sweep
- Devin
- Phind
- Mentat
- Claude Desktop
- Aider
- GPT Pilot
- Plandex
- bolt.new
- v0
- Replit Agent
- Anse
- TypingMind
- BetterChatGPT
- LibreChat
- Warp AI
- Pieces
- Fig AI
Embed badge
[](https://verified-skill.com/skills/robertcoop/openscad-mcp/openscad-design)