Files

37 KiB

disable-model-invocation, name, description, argument-hint, allowed-tools, metadata
disable-model-invocation name description argument-hint allowed-tools metadata
true openscad Programmatic 3D CAD with OpenSCAD. Generate .scad files, render STL for 3D printing, preview as PNG with AI vision feedback. Triggers on: 3D model, STL, 3D print, parametric design, openscad, CAD, enclosure, bracket, or any 3D modeling task. <description of object to design or path to existing .scad file> Bash(*),Read,Edit,Write,Glob,Grep,Agent
version category tags
1.0.0 3d-cad
openscad
3d-printing
cad
parametric
stl
modeling
design

OpenSCAD Skill

Design, render, preview, and export 3D models using OpenSCAD's programmatic CAD engine. Supports iterative AI-driven design refinement via rendered PNG analysis.

Environment

  • OpenSCAD binary: /opt/homebrew/bin/openscad (v2021.01)
  • Working directory for designs: ~/openscad-projects/ (create per-project subdirectories)
  • Skill scripts: ~/.claude/skills/openscad/scripts/
  • Templates: ~/.claude/skills/openscad/templates/
  • Language reference: ~/.claude/skills/openscad/references/

Modes

The skill operates in six modes, auto-detected from the user's request:

  • Design — Create a new 3D model from a description
  • Replicate — Reproduce a physical object from reference images
  • Reconstruct — Reverse-engineer an STL mesh into parametric OpenSCAD code
  • Refine — Iterate on an existing .scad file (modify, preview, repeat)
  • Export — Render final STL/3MF for 3D printing
  • Analyze — Review an existing design for printability or improvements

Workflow: Design Mode

When the user asks to create a new 3D object:

Step 1: Understand Requirements

Clarify with the user:

  • What is the object? (enclosure, bracket, gear, container, etc.)
  • Dimensions — key measurements in mm
  • Purpose — functional print, aesthetic, mechanical fit?
  • Constraints — printer bed size, material, wall thickness preferences
  • Parametric? — which dimensions should be adjustable?

Step 2: Set Up Project

bash ~/.claude/skills/openscad/scripts/openscad-project.sh init "<project-name>"

This creates ~/openscad-projects/<project-name>/ with subdirectories for source, output, and previews.

Step 3: Generate the .scad File

Write the OpenSCAD code to ~/openscad-projects/<project-name>/src/main.scad.

Mandatory file structure (Feature Tree pattern):

// 1. PARAMETERS (independent variables)
width = 60;  height = 30;  wall = 2;

// 2. DERIVED DIMENSIONS (calculated from parameters)
inner_width = width - 2 * wall;

// 3. BASE PROFILE (2D sketch — the core shape)
module sketch_base() {
    offset(r = corner_r)
        square([width - 2*corner_r, depth - 2*corner_r], center=true);
}

// 4. PRIMARY BODY (extrude the sketch)
module body() { linear_extrude(height = height) sketch_base(); }

// 5. ADDITIVE FEATURES (bosses, ribs, tabs)
module features_add() { ... }

// 6. SUBTRACTIVE FEATURES (holes, slots, pockets — ALWAYS LAST)
module features_cut() { ... }

// 7. ASSEMBLY (the Feature Tree)
difference() {
    union() { body(); features_add(); }
    features_cut();
}

Profile-first design rules:

  • Prefer polygon() + linear_extrude() over hull() of 3D primitives
  • Use offset(r=radius) for corner rounding instead of hull() with cylinders
  • Use rotate_extrude() for axially symmetric parts (never stack cylinders)
  • Define dimensions relative to edges/features, not absolute coordinates: hole_x = total_length - edge_margin (not magic numbers)
  • Cascade tolerances from a single fit_clearance parameter

Critical rules for generating OpenSCAD code:

  • Read ~/.claude/skills/openscad/references/language-reference.md if unsure about syntax
  • Always define parametric dimensions as variables at the top of the file
  • Use $fn = 64; for smooth curves (or higher for final renders)
  • Add comments explaining each section
  • Use modules for reusable parts
  • Keep wall thickness >= 1.2mm for FDM printing
  • Design with the print orientation in mind (flat bottom, minimal overhangs)

Step 4: Preview

Render a multi-angle PNG preview:

bash ~/.claude/skills/openscad/scripts/openscad-render.sh preview ~/openscad-projects/<project-name>/src/main.scad

This generates 4 preview images (front, side, top, isometric) in the project's previews/ directory.

Step 5: Analyze Preview

Read each preview PNG using the Read tool to see the rendered object. Evaluate:

  • Does the shape match the user's description?
  • Are proportions correct?
  • Are there visible artifacts or unintended geometry?
  • Would this print well? (overhangs, bridging, thin walls)

Report findings to the user with the preview images.

Step 6: Iterate

If changes are needed, edit the .scad file and re-render. Repeat Steps 4-5 until the user is satisfied. Each iteration should be targeted — change one aspect at a time.

Step 7: Export

When the design is approved:

bash ~/.claude/skills/openscad/scripts/openscad-render.sh export ~/openscad-projects/<project-name>/src/main.scad

This produces:

  • output/model.stl — for slicing and printing
  • output/model.3mf — alternative format (better metadata)
  • previews/final-preview.png — high-res final render

Workflow: Replicate Mode

When the user provides reference images of a physical object to reproduce in OpenSCAD:

Step 1: Analyze Reference Images

Read ALL provided reference images using the Read tool. For each image, extract:

  • Overall shape: What geometric primitives compose this object?
  • Proportions: Relative dimensions (height-to-width ratio, etc.)
  • Features: Holes, fillets, chamfers, textures, slots, lips, threads
  • Symmetry: Is it symmetric along any axis?
  • Construction: How would you decompose it into boolean operations?

If dimensions are provided, note them. If not, estimate proportions from the images and ask the user for at least one known measurement to establish scale.

Step 2: Create Decomposition Plan

Before writing any code, describe the object as a series of OpenSCAD operations:

Object: Phone stand
Decomposition:
1. Base: flat rectangle with rounded corners (80x60x5mm)
2. Back support: angled plate (60x3mm, tilted 70 degrees)
3. Front lip: small ridge to hold phone (60x3x8mm)
4. Fillet: smooth transition between base and back support
5. Cable channel: cylinder subtracted from base center

Present this plan to the user for confirmation before coding.

Step 3: Generate Initial .scad File

Write the OpenSCAD code based on the decomposition. Set up the project:

bash ~/.claude/skills/openscad/scripts/openscad-project.sh init "<object-name>"

Write the .scad to the project's src/main.scad.

Step 4: Render and Compare

Generate a preview from the same angle as the reference image:

bash ~/.claude/skills/openscad/scripts/openscad-render.sh quick ~/openscad-projects/<name>/src/main.scad

Read both the reference image and the rendered preview. Compare them side by side mentally:

  • Does the overall silhouette match?
  • Are proportions correct?
  • Are features (holes, edges, curves) in the right places?
  • What's the biggest discrepancy?

Step 5: Iterative Refinement Loop

For each discrepancy found:

  1. Identify which part of the .scad code controls the mismatched feature
  2. Make a single targeted edit to improve the match
  3. Re-render from the same angle
  4. Re-compare with the reference

Refinement priorities (fix in this order):

  1. Overall shape and proportions
  2. Major features (holes, cutouts, protrusions)
  3. Angles and curves
  4. Fillets, chamfers, and surface details
  5. Fine details

Step 6: Multi-Angle Validation

Once the primary angle looks good, render from all angles that have reference images:

bash ~/.claude/skills/openscad/scripts/openscad-render.sh preview ~/openscad-projects/<name>/src/main.scad

Compare each rendered view against its corresponding reference image. Fix any angle-specific discrepancies.

Step 7: Dimensional Verification

If the user provided measurements, add echo() statements to verify:

echo("Total width:", width);
echo("Total height:", height);
echo("Wall thickness:", wall);

Render with echo capture to verify dimensions match specifications.

Step 8: Export

When the user confirms the replication is satisfactory, export for printing.

Tips for Accurate Replication

  • Start simple: Begin with bounding-box primitives, then refine
  • Use reference dimensions: If user says "it's about 10cm tall", anchor ALL proportions to that
  • Match camera angle: Use --camera to match the reference photo's perspective
  • Organic shapes: Approximate with hull(), minkowski(), or rotate_extrude() of a profile
  • Iterate small: Change one thing per render cycle
  • Ask when unsure: If a feature is ambiguous from the images, ask the user rather than guessing

Workflow: Reconstruct Mode (STL-to-SCAD)

When the user provides an STL file and wants it converted to parametric OpenSCAD code:

Overview

STL files are triangle meshes with no semantic information about the original primitives or operations that created them. Reconstruction is the process of analyzing the mesh geometry and re-expressing it as clean, parametric OpenSCAD code. This is valuable because:

  • Parametric code can be modified (change dimensions, add features)
  • OpenSCAD code is human-readable and version-controllable
  • The resulting model can be adapted to different use cases

Critical Rules for Reconstruction

Read references/reconstruction-guide.md before starting any reconstruction. It contains the complete best practices guide learned from real reconstructions.

Rule 1: SCULPTOR APPROACH (mandatory). Start from a full solid block, subtract ALL features. Never build up from pieces — CSG ordering bugs cause added material to cover previously-cut holes. Structure: difference() { solid_body(); channels(); tapers(); ALL_holes_LAST(); }

Rule 2: NEVER add features based on assumptions. Always verify with SVG contour data AND reference images. If a feature doesn't appear as a separate contour in the SVG slices, IT DOES NOT EXIST. Known hallucinations to avoid:

  • Pyramids/cones from render shadows
  • Cylinders from curved wall edges
  • Top holes from through-hole exit points

Rule 3: Bounding box match ≠ correct model. 0.000mm bbox delta can mean only 70% geometric accuracy. Always use mesh comparison (openscad-stl-compare.sh) with boolean diff images.

Rule 4: ANALYZE FIRST, DECOMPOSE, THEN CHOOSE per-component approach. Do NOT jump to code. The analysis phase must answer these questions:

  1. What are the dominant features? (diagonal arm, clips, channels, holes)
  2. What is the thinnest axis? That's the likely extrusion direction — NOT necessarily the stability score winner
  3. Can the object be decomposed into simpler sub-objects? Model each with its best technique
  4. Where are internal channels/gaps? Slice along Z to find multi-body cross-sections

Rule 5: Choose the extrusion axis by geometry, not just stability score.

The profile extractor's stability score finds the axis with the most uniform cross-section. But this is misleading for models with diagonal features — slicing along Z for a diagonal bracket produces staircase artifacts. Instead:

Model Type Best Extrusion Axis Why
Flat bracket/plate Thinnest axis (smallest extent) Profile in the wide plane captures all detail
Diagonal/angled arm Thinnest axis Diagonals live in the plane of the two longest axes
Clean extrusion (stability < 0.1) Stability-score axis Profiles are identical → stability is reliable
Cylindrical (stability > 0.3) Object's rotational axis Use rotate_extrude or parametric primitives
Truly complex (no good axis) Dense multi-axis slabbing 2mm slabs along thinnest axis
# Always run ALL analysis tools before writing any code:
bash ~/.claude/skills/openscad/scripts/openscad-stl-reconstruct.sh model.stl analysis/
python3 ~/.claude/skills/openscad/scripts/openscad-profile-extract.py model.stl --json analysis/profile.json
python3 ~/.claude/skills/openscad/scripts/openscad-adaptive-slice.py model.stl analysis/

After analysis, compare: thinnest axis extent vs stability-score axis. If they differ, the thinnest axis is usually better for models with angled features.

Rule 6: Choose the right technique for each component:

Geometry Best Approach Expected Accuracy
Flat/angular (brackets, plates) Profile extraction + linear_extrude 90-96%
Diagonal features (angled arms, tapers) Profile along thinnest axis + linear_extrude 85-92%
Simple known shapes (stadium, box) Parametric primitives + SDF optimizer 90-96%
Cylindrical features (puzzle tabs, bosses) Parametric circle() + square() 85-95%
Smooth transitions (convex shapes only) hull() between boundary profiles 85-90%
Multi-width models (width varies along axis) Dense X-slab (2mm profiles along thinnest axis) ~92%
Mixed (curves + flats) Polygon profile (hi-res, tol=0.02) 70-80%
Complex organic shapes import() original STL + parametric modifications N/A

Rule 7: hull() ONLY for convex profiles. Hull between two profiles creates the convex hull — it fills in ALL concavities (channels, clips, U-forks, hooks). Only use hull for simple solid zones with 1 contour and no holes. For concave profiles, use linear_extrude of a representative profile instead.

Rule 8: Dense X-slab approach for complex models. When no single extrusion works, slice every 2mm along the thinnest axis:

  1. At each X position, extract the full Y-Z cross-section (ALL bodies, not just the largest)
  2. Extrude each slab for 2mm width
  3. Union all slabs — gaps between bodies are naturally preserved
  4. Note: this approach has a ~6% volume overestimate floor from polygon extraction artifacts. Below 6% requires hand-modeled parametric geometry.

Use the automated reconstruction analysis FIRST — before writing any code:

bash ~/.claude/skills/openscad/scripts/openscad-stl-reconstruct.sh model.stl output_dir/

This runs the full pipeline: mesh stats (trimesh), 2D profile slices (OpenSCAD projection), primitive detection (RANSAC/normal analysis), and generates SVG profiles at multiple Z levels. The SVG profile analysis is the MOST IMPORTANT output — it reveals the complete cross-section structure at each height level.

The SVG Profile Method (preferred over vertex analysis):

  1. projection(cut=true) slices the STL at a Z height → exports 2D SVG
  2. Parse the SVG to count contours: BODY (large area) vs HOLES (small area)
  3. Compare contours at different Z levels to understand how the shape changes with height
  4. This reveals: channels, slots, holes, wall thickness, taper angles — all from 2D data

After analysis, verify with mesh comparison:

bash ~/.claude/skills/openscad/scripts/openscad-stl-compare.sh original.stl reconstruction.stl output_dir/

Target: >95% geometric accuracy. Use diff images to identify remaining discrepancies.

Step 1: Automated Analysis (run ALL tools)

# Tool 1: SVG profiling + primitive detection
bash ~/.claude/skills/openscad/scripts/openscad-stl-reconstruct.sh model.stl analysis/

# Tool 2: Profile extraction + extrusion axis detection
python3 ~/.claude/skills/openscad/scripts/openscad-profile-extract.py model.stl \
    --output analysis/profile.scad --json analysis/profile.json

# Tool 3: Adaptive multi-axis feature map
python3 ~/.claude/skills/openscad/scripts/openscad-adaptive-slice.py model.stl analysis/

Key outputs to examine:

  • analysis/slices/*.svg — 2D profiles at 5 Z levels
  • analysis/profile.json — extrusion axis, stability score, profile points, hole count
  • analysis/adaptive-slicing.json — feature zones on all 3 axes, transition locations
  • analysis/primitives.json — detected cylinders/planes
  • analysis/mesh-info.json — volume, dimensions, symmetry

Step 1b: Understand the Object (BEFORE writing code)

After running analysis tools, render multi-angle previews and answer:

  1. What are the main components? (e.g. "bottom clip + diagonal arm + top clip")
  2. Which axis is thinnest? Compare extents — the thinnest is likely the extrusion direction
  3. Are there diagonal/angled features? If yes, the stability-score axis is probably WRONG
  4. Where do cross-sections change? Check the adaptive slicer's transition zones
  5. Are there multi-body zones? (channels, rails, gaps between parts)

Decision tree — axis selection:

  1. If stability_score < 0.1 AND thinnest axis matches stability axis → clean extrusion, use profile.scad
  2. If model has diagonal features → use the thinnest axis regardless of stability score
  3. If stability_score < 0.3 AND no diagonals → stability axis + feature variations
  4. If stability_score > 0.3 → complex shape. Try dense X-slab along thinnest axis, or decompose into sub-objects

Decision tree — technique per component:

  • Simple extruded body → profile + linear_extrude along extrusion axis
  • Diagonal arm/strut → profile along thinnest axis captures it naturally
  • Clips, hooks, U-channels → profile extraction (NOT hull — hull fills concavities)
  • Cylindrical features → parametric circle() + square(), NOT polygon profiles
  • Smooth convex transitions → hull() between boundary profiles (ONLY if convex)
  • Complex multi-width → dense 2mm slabs along thinnest axis

For models with cylindrical features (stability > 0.3 or SVG shows circular contours):

  • Do NOT rely on polygon profiles — they approximate curves poorly
  • Identify circle centers and radii from the SVG contour data
  • Model with circle() + square() in 2D, then extrude

Then render multi-angle previews:

// Temporary viewer file
import("path/to/model.stl");
bash ~/.claude/skills/openscad/scripts/openscad-render.sh preview /tmp/stl-viewer.scad

Read all preview images to understand the 3D shape from multiple angles.

After running the adaptive slicer, use the auto-reconstructor to generate parametric .scad directly:

# Option A: With pre-computed analysis
python3 ~/.claude/skills/openscad/scripts/openscad-auto-reconstruct.py model.stl \
    --analysis analysis/ --output project/src/main.scad

# Option B: Run analysis + reconstruction in one step
python3 ~/.claude/skills/openscad/scripts/openscad-auto-reconstruct.py model.stl \
    --output project/src/main.scad --run-analysis

# Option C: Tighter circle fitting for precision parts
python3 ~/.claude/skills/openscad/scripts/openscad-auto-reconstruct.py model.stl \
    --analysis analysis/ --output project/src/main.scad --circle-threshold 0.3

This automatically:

  1. Parses the feature map JSON into zones
  2. Extracts profiles at zone boundaries
  3. Fits circles/arcs to replace polygon approximations (Feature 3)
  4. Generates hull() blends for transition zones (Feature 2)
  5. Emits one OpenSCAD module per zone with sculptor assembly (Feature 1)

The output is a good starting point — review and refine the generated .scad, then verify with mesh comparison. For models with cylindrical features, this typically achieves >85% accuracy automatically (vs 75% with polygon-only).

Step 2: Detailed Structure Mapping

For simple models (5 SVG slices are enough): Parse the SVG contours to count bodies vs holes at each Z level.

For complex models (brackets, enclosures with multiple features): Use the adaptive multi-axis slicer for efficient feature detection:

python3 ~/.claude/skills/openscad/scripts/openscad-adaptive-slice.py model.stl analysis/

This automatically: scans all 3 axes with coarse pass (5mm) → detects transitions → fine pass (0.5mm) around transitions. Produces a feature map classifying each zone as solid, shell_or_channel, multi_body, or complex.

For manual fine-grained slicing at specific heights:

for z in $(seq 0.5 1 <max_z>); do
    echo "projection(cut=true) translate([0,0,-$z]) import(\"model.stl\");" > /tmp/s.scad
    openscad -o "slices/z${z}.svg" /tmp/s.scad
done

Parse each SVG to build a structural map:

Z=0-5:   1 body (full width) + 8 holes     → Solid base with screw holes
Z=5-10:  2 bodies + 8 holes                → Channel appeared, walls split
Z=10-20: 2 bodies narrowing                → Taper zone (measure rate)
Z=20-33: 2 bodies constant width           → Top section
Z=25-27: Bodies interrupted                → Counterbore pockets at this depth

Hole positions from SVG centroids — for each hole contour at a given Z, compute the centroid. This gives exact X,Y positions far more reliably than vertex analysis.

Feature verification rule: If a feature doesn't appear as a distinct contour in the SVG data, IT DOES NOT EXIST in the model. Never add features based on visual interpretation of 3D renders alone.

Step 3: Choose Approach and Decompose

Based on the analysis data, choose the reconstruction approach:

Approach A — Profile Extrusion (for extruded parts, stability < 0.3):

# The profile extractor already generated the .scad — use it as a starting point
cat analysis/profile.scad
# Adjust: add cavity with offset(delta=-wall), add floor, add features

Approach B — Parametric Primitives (for known shapes or cylindrical features): Create a decomposition plan using measured dimensions from SVG data:

Decomposition:
1. Base: square([80, 80]) + circle tabs — from SVG outer contour at Z=mid
2. Cavity: offset(delta=-wall) of base — from SVG inner contour
3. Floor: solid at Z=0 to floor_h — from SVG at Z=0 (1 contour = solid)
4. Holes: cylinder(d=3) at SVG hole centroids
5. Counterbores: cylinder(d=8, h=2) at same positions

Approach C — Hybrid (for complex shapes with both flat and curved features):

  1. Extract polygon profile for the overall outline
  2. Identify which curves in the profile are circles (regular spacing, arc-like)
  3. Replace those polygon sections with parametric circle(r) operations
  4. Assemble: square() + circle() union for tabs, difference() for slots

Counterbore vs Countersink — always verify from reference images:

  • Counterbore: flat cylindrical pocket (cylinder(d=cb_d, h=cb_depth))
  • Countersink: conical taper (cylinder(d1=cs_d, d2=hole_d, h=cs_depth))
  • Most 3D-printed parts use counterbores, not countersinks

Step 4: Write Parametric .scad Code

Create a new project and write the reconstructed code:

bash ~/.claude/skills/openscad/scripts/openscad-project.sh init "<name>-reconstructed"

Key principles for reconstruction:

  • Extract ALL dimensions as named variables at the top
  • Use meaningful variable names that describe the physical feature
  • Add comments linking each section to the original STL features
  • Include echo() statements for bounding box verification
  • Add assert() for parameter ranges

Step 5: Visual Comparison Loop

Render the reconstructed .scad and compare side-by-side with the original STL renders:

  1. Render the reconstruction from the same camera angles as Step 1
  2. Read both sets of images
  3. Compare silhouettes, proportions, and feature placement
  4. Identify the biggest discrepancy
  5. Fix it and re-render
  6. Repeat until the reconstruction matches the original

Step 6: Overlay Verification

For precise verification, create an overlay .scad file:

// Overlay: original STL (transparent) vs reconstruction
%import("path/to/original.stl");  // % = transparent background
color("red", 0.6) reconstructed_model();

Render this overlay — any RED areas visible through the transparent original indicate reconstruction errors. Any grey areas not covered by red indicate missing geometry.

Step 7: Mesh-to-Mesh Comparison

This is the most important verification step. Export the reconstruction as STL and compare it against the original using boolean difference:

# Export reconstruction
bash ~/.claude/skills/openscad/scripts/openscad-render.sh stl ~/openscad-projects/<name>/src/main.scad

# Run mesh comparison
bash ~/.claude/skills/openscad/scripts/openscad-stl-compare.sh \
    path/to/original.stl \
    ~/openscad-projects/<name>/output/main.stl \
    ~/openscad-projects/<name>/previews/comparison

This produces:

  • diff-A-minus-B.png — geometry in original but MISSING from reconstruction (what you need to add)
  • diff-B-minus-A.png — EXTRA geometry in reconstruction not in original (what you need to remove)
  • overlay.png — both models overlaid for visual check
  • Geometric accuracy % — based on volume of boolean differences vs original volume

Target: >95% geometric accuracy. If below 95%, examine the diff images to identify which features are wrong, fix them, re-export, and re-compare. Iterate until accuracy is satisfactory.

Important: Bounding box delta can be 0.000mm while geometric accuracy is only 78% — internal features matter more than outer dimensions.

Step 8: Dimensional Verification

Compare echo output from the reconstruction with the STL bounding box:

echo(str("Reconstructed BBOX: ", width, " x ", depth, " x ", height));

Step 9: SDF Parameter Optimization (Advanced)

If the SVG profile method doesn't achieve >95% accuracy, use the SDF optimizer for automatic parameter tuning:

python3 ~/.claude/skills/openscad/scripts/openscad-sdf-optimize.py \
    path/to/original.stl \
    stadium-slot \
    --verbose \
    --output analysis/sdf-result.json

This works by:

  1. Sampling 30,000 random points in the bounding box
  2. Computing target occupancy (inside/outside original mesh) via trimesh
  3. Defining the reconstruction as a parametric SDF (Signed Distance Field)
  4. Using scipy.optimize.minimize(method="Powell") to maximize IoU (Intersection over Union)
  5. Generating OpenSCAD code with optimized parameters

When to use: When you know the correct model topology (e.g., "stadium body with cylindrical slot") but can't find the exact parameters. The optimizer finds them automatically.

Supported model types: stadium-slot, box-holes. Add new types by defining an SDF function in the script.

Workflow: Run openscad-stl-reconstruct.sh first (to identify the model topology), then openscad-sdf-optimize.py (to find exact parameters), then openscad-stl-compare.sh (to verify).

Prerequisites: pip3 install trimesh numpy scipy rtree

Common Pitfalls

  • Bounding box match ≠ correct model. A model with completely wrong internal geometry can still have a 0.000mm bounding box delta. Always verify visually from multiple angles.
  • Don't assume features from renders alone. What looks like a cylinder in a top-down view might just be a curved wall edge. Always verify with vertex analysis.
  • Coincident faces cause Z-fighting. If a feature touches the body boundary exactly, use intersection() to clip it cleanly rather than making it the exact same size.
  • Don't flip between adding and removing features. If unsure whether a feature exists, run cross-section analysis before deciding. Oscillating between "add bar" and "remove bar" wastes iterations.
  • Offset features are common. Cylinders, holes, and channels are often NOT centered. Always calculate the actual center from vertex data rather than assuming symmetry.

Limitations

  • Organic shapes (sculpted, freeform surfaces) cannot be fully reconstructed as primitives. For these, keep the STL import and wrap it in a module.
  • Very complex models (1000+ features) should be reconstructed incrementally, starting with the major body and adding features one group at a time.
  • Thread geometry in STL is extremely difficult to reconstruct. Use threads.scad library instead of trying to match individual thread faces.
  • Text/engravings embedded in STL meshes are very hard to extract. It's better to re-add text using OpenSCAD's text() module.

Hybrid Approach

For complex models, use a hybrid strategy:

// Import the complex organic base from STL
module original_base() {
    import("base-section.stl");
}

// Reconstruct and parameterize the mechanical features
module mounting_bracket(width=30, hole_d=5) {
    difference() {
        original_base();
        // Add parametric mounting holes
        for (pos = hole_positions)
            translate(pos) cylinder(d=hole_d, h=50, center=true);
    }
}

This lets the user modify the parametric parts while keeping the complex geometry intact.


Workflow: Refine Mode

When the user wants to modify an existing design:

Step 1: Read the Existing File

# Find .scad files in the project

Read the .scad source to understand the current design.

Step 2: Render Current State

bash ~/.claude/skills/openscad/scripts/openscad-render.sh preview /path/to/file.scad

Read the preview images to see what currently exists.

Step 3: Apply Changes

Edit the .scad file with the requested modifications. Use the Edit tool for surgical changes.

Step 4: Re-render and Compare

Generate new previews and visually compare with the previous version. Report what changed.

Step 5: Repeat or Export

Continue iterating or export when satisfied.


Workflow: Export Mode

Quick export of an existing .scad file:

# Single format
bash ~/.claude/skills/openscad/scripts/openscad-render.sh stl /path/to/file.scad

# Multiple formats
bash ~/.claude/skills/openscad/scripts/openscad-render.sh export /path/to/file.scad

# With parameter overrides
bash ~/.claude/skills/openscad/scripts/openscad-render.sh stl /path/to/file.scad -D 'width=50' -D 'height=30'

Workflow: Analyze Mode

Review a design for printability:

bash ~/.claude/skills/openscad/scripts/openscad-render.sh analyze /path/to/file.scad

This renders cross-section views and reports:

  • Object bounding box dimensions
  • Whether the mesh is manifold (watertight)
  • Estimated print time indicators (volume, surface area from STL)
  • Visual check of overhangs via bottom-up view

Script Reference

All scripts live in ~/.claude/skills/openscad/scripts/:

Script Purpose
openscad-render.sh Core render/export/preview engine
openscad-project.sh Project scaffolding and management
openscad-validate.sh Strict validation with categorized error output
openscad-stl-analyze.sh STL mesh analysis: bbox, cross-sections, gap detection
openscad-stl-compare.sh Mesh comparison: boolean diff, volume delta, accuracy %
openscad-stl-reconstruct.sh Automated STL analysis: profiles, primitives, CSG inference
openscad-sdf-optimize.py SDF-based parameter optimizer (IoU scoring, no OpenSCAD in loop)
openscad-adaptive-slice.py Adaptive multi-axis slicing (coarse→transitions→fine on X,Y,Z)
openscad-auto-reconstruct.py Auto-translate feature map → parametric .scad (circle fitting, hull blending)

openscad-render.sh Commands

# Quick single preview (isometric)
openscad-render.sh quick <file.scad>

# Multi-angle preview (4 views)
openscad-render.sh preview <file.scad>

# Export STL only
openscad-render.sh stl <file.scad> [-D 'var=val' ...]

# Export all formats (STL + 3MF + PNG)
openscad-render.sh export <file.scad> [-D 'var=val' ...]

# Analyze printability
openscad-render.sh analyze <file.scad>

# Custom render
openscad-render.sh custom <file.scad> --format png --imgsize 1920,1080 --camera 0,0,0,45,0,30,200

openscad-project.sh Commands

# Initialize new project
openscad-project.sh init <project-name>

# List projects
openscad-project.sh list

# Clean build artifacts
openscad-project.sh clean <project-name>

OpenSCAD Code Guidelines

File Structure Convention

// ============================================
// Project: <name>
// Description: <what this models>
// Author: Claude Code + User
// ============================================

// --- Parameters (user-configurable) ---
width = 50;        // [mm] overall width
height = 30;       // [mm] overall height
depth = 20;        // [mm] overall depth
wall = 2.0;        // [mm] wall thickness
tolerance = 0.3;   // [mm] printer tolerance

// --- Rendering quality ---
$fn = 64;          // curve smoothness (use 128+ for final export)
eps = 0.01;        // epsilon for clean boolean operations

// --- Derived dimensions ---
inner_width = width - 2 * wall;
inner_height = height - 2 * wall;

// --- Main model ---
main_assembly();

// --- Modules ---
module main_assembly() {
    // ...
}

3D Printing Best Practices in OpenSCAD

  • Wall thickness: minimum 1.2mm for FDM (2-3 perimeters with 0.4mm nozzle)
  • Tolerance: 0.2-0.3mm clearance for fitting parts together (peg-in-hole, snap fits)
  • Overhangs: keep below 45 degrees from vertical, or add supports in design
  • Chamfer vs fillet: prefer chamfers on downward-facing surfaces (avoids supports); use fillets on top surfaces
  • Bridging: max ~10mm unsupported spans
  • First layer: design flat bottoms for bed adhesion; largest flat surface on build plate
  • Epsilon constant: always define eps = 0.01; and use it in boolean operations to prevent Z-fighting / coplanar faces
  • Manifold geometry: always ensure boolean operations produce valid solids; operands must overlap
  • Resolution: use $fn = 64 for preview, $fn = 128 for export
  • Design intent: Define hole positions relative to edges (hole_x = length - margin), never as absolute coordinates
  • Tolerance chains: Define a single fit_clearance parameter and derive all clearances from it
  • Assert validation: Use assert() to validate parameters: assert(wall >= 1.2), assert(boss_d > hole_d + 2*wall)
  • Profile-first: Use offset(r=corner_r) on 2D polygon() instead of hull() with 3D cylinders

Common Patterns

Rounded box:

module rounded_box(size, radius) {
    minkowski() {
        cube([size.x - 2*radius, size.y - 2*radius, size.z - radius]);
        cylinder(r=radius, h=radius);
    }
}

Shell (hollow object):

module shell(outer_size, wall) {
    difference() {
        cube(outer_size);
        translate([wall, wall, wall])
            cube([outer_size.x - 2*wall, outer_size.y - 2*wall, outer_size.z]);
    }
}

Screw hole with countersink:

module screw_hole(d=3, h=10, cs_d=6, cs_h=2) {
    union() {
        cylinder(d=d, h=h);
        translate([0, 0, h - cs_h])
            cylinder(d1=d, d2=cs_d, h=cs_h);
    }
}

Available Libraries

Popular libraries that can be installed for advanced features:

Library Use Case Install
BOSL2 Swiss-army knife: attachments, shapes, threading, paths git clone https://github.com/BelfrySCAD/BOSL2 ~/.local/share/OpenSCAD/libraries/BOSL2
NopSCADlib Vitamins (screws, nuts, electronics, bearings) git clone https://github.com/nophead/NopSCADlib ~/.local/share/OpenSCAD/libraries/NopSCADlib
threads.scad Metric threads, hex bolts, nuts git clone https://github.com/rcolyer/threads-scad ~/.local/share/OpenSCAD/libraries/threads
Round-Anything Smooth fillets and rounding git clone https://github.com/Irev-Dev/Round-Anything ~/.local/share/OpenSCAD/libraries/Round-Anything
YAPP_Box Parametric project enclosures git clone https://github.com/mrWheel/YAPP_Box ~/.local/share/OpenSCAD/libraries/YAPP_Box
Catch'n'Hole Nut catches, screw holes git clone https://github.com/mmalecki/catchnhole ~/.local/share/OpenSCAD/libraries/catchnhole

Check installed libraries:

ls ~/.local/share/OpenSCAD/libraries/ 2>/dev/null
ls /opt/homebrew/share/openscad/libraries/ 2>/dev/null

When user needs a library, install it and add use <library/file.scad> to the .scad source.


Error Handling

When OpenSCAD fails:

  1. Parse errorsERROR: Parser error: syntax error in file X, line Y

    • Read the .scad file at the reported line
    • Fix syntax (common: missing semicolons, unmatched braces/parens, wrong function names)
    • Re-render
  2. Geometry errorsWARNING: Object may not be a valid 2-manifold

    • Check boolean operations aren't creating degenerate geometry
    • Ensure shapes overlap properly for difference/intersection
    • Add small epsilon offsets (0.01mm) to prevent coplanar faces
  3. Rendering timeouts — complex models with high $fn

    • Lower $fn for preview (32), raise for export (128)
    • Simplify geometry where possible
    • Use render() to cache intermediate results
  4. Empty output — model produces no geometry

    • Check that modules are actually called
    • Verify boolean operations don't subtract everything
    • Use echo() statements to debug variable values

Always capture stderr when rendering — it contains warnings and errors:

openscad -o output.stl input.scad 2>&1

Camera Presets for Multi-View

View Camera Parameters
Front --camera 0,0,0,90,0,0,<dist>
Back --camera 0,0,0,90,0,180,<dist>
Right --camera 0,0,0,90,0,90,<dist>
Left --camera 0,0,0,90,0,270,<dist>
Top --camera 0,0,0,0,0,0,<dist>
Bottom --camera 0,0,0,180,0,0,<dist>
Isometric --autocenter --viewall (default)
3/4 view --camera 0,0,0,55,0,25,<dist>

Use --autocenter --viewall to auto-calculate distance, or specify explicit distance for consistent framing across iterations.