CommunityImagegithub.com

ezylevy/3d-stl

Two entry points, one standard of output: a watertight STL, a parametric script

What is 3d-stl?

3d-stl is a Claude Code agent skill that two entry points, one standard of output: a watertight STL, a parametric script.

Works with✓Claude Code~Codex CLI~Cursor
npx skills add https://github.com/ezylevy/ezy-plugins/tree/HEAD/plugins/3d-stl/skills/3d-stl

Installed? Explore more Image skills: steipete/songsee, affaan-m/frontend-design, mattpocock/improve-codebase-architecture · View all 6 →

Ask in your favorite AI

Open a new chat with this agent skill pre-loaded.

Documentation

3D STL

Two entry points, one standard of output: a watertight STL, a parametric script that regenerates it, and a slicer table that makes the print succeed.

InputRouteLibrary
Dimensions, a described object, a sketch in wordsGeometry routescripts/partlib.py
A photo or picture fileImage routescripts/imagelib.py

Setup for the geometry route:

pip install trimesh shapely manifold3d --break-system-packages -q

The image route needs only Pillow and numpy — no mesh library, no booleans.


Geometry route

1. Pin down the dimensions before modelling

Most rework here comes from ambiguity, not from bad geometry. Restate the part in a short table (dimension → value → source) and mark anything you assumed. Watch specifically for:

  • Outer size vs. mounting centres. "87 mm wide" and "87 mm between the screws" are different parts — they differ by one wall thickness. Ask.
  • A missing third dimension. A profile plus a thickness is only two of three; choose a sensible depth, say so, and make it a flag.
  • Fastener intent. "5 mm screws" can mean clearance holes for metal M5 screws, printed threaded pins, or a heat-set insert. Three different models.
  • Existing hardware. If the part mates with something that already exists, its hole spacing and material thickness are constraints, not preferences.

Ask at most the one or two questions that change the geometry; assume the rest, state the assumption, and move.

2. Model with the library

scripts/partlib.py provides profile builders, extrude, threaded_rod, threaded_pin, hex_nut, place, and finish. Import it rather than re-deriving mesh math — the helical thread is easy to get subtly wrong.

scripts/example_handle.py is a complete worked part (bridge handle + integral threaded pins + matching nut). Copy it as the skeleton for a new part.

Write the model as a parametric script with argparse flags, never hard-coded numbers. The user will ask for a variant within minutes, and the answer should be one command line rather than a new model. Hand back the script alongside the STL.

3. Common part recipes

PartBuild from
Bridge handle, ⊓ bracketbridge_profile + extrude
Flat plate with holesshapely polygon with interior rings + extrude
Pin, stud, boltthreaded_pin, then place onto its axis
Nut, threaded sockethex_nut, or subtract threaded_rod(clearance=…)
Spacer, bushingtwo concentric circles + extrude
Hook, L-bracketpolygon of the side view + extrude, flat on the bed
Enclosureouter box minus inner box; lip with 0.15 mm clearance

Anything not listed is still a polygon, an extrusion, and a boolean.


Image route

scripts/imagelib.py converts a picture into a height field and stitches an explicit vertex-grid solid — top surface, flat bottom, four side walls. It uses no boolean engine, which is exactly why it does not fall over on large or odd images.

python3 imagelib.py photo.jpg --mode lithophane --width 100 \
    --out stl_output/lithophane.stl
python3 imagelib.py logo.png --mode relief --width 80 --base 2 \
    --out stl_output/relief.stl
ModeMappingTypical z
reliefbright pixels rise0.6 → 4.0 mm, often over a --base plate
lithophanedark pixels get thick, so it glows when backlit0.8 → 3.0 mm, no base
  • --res sets samples on the long edge (default 200). Resolution beyond about 0.4 mm per sample is wasted — the nozzle cannot print it, and the file balloons. Raise it only for large prints.
  • Contrast is auto-stretched on load; a flat, low-contrast photo produces a flat, disappointing print. Say so rather than printing it.
  • Lithophanes want faces and high-contrast subjects. Landscapes and busy scenes turn to mud.
  • check() verifies that every edge appears exactly twice in opposite directions. Counting alone would pass a wall stitched backwards, which yields a "valid" STL that the slicer turns inside out. Run it, report it.

Finishing, for both routes

Verify first: finish() (geometry) and check() (image) report the bounding box, watertightness and triangle count. Compare the bounding box against the requested dimensions — it catches sign errors and unit slips instantly. Never present a mesh that is not watertight.

For anything visually non-obvious — threads, curves, assemblies — render a quick matplotlib preview and look at it. Twenty seconds beats a six-hour print of the wrong shape.

Read references/design-rules.md before choosing orientation, thread pitch, or clearances. It covers layer-direction strength, printable thread profiles, fit tolerances, image-derived parts, and the failure modes worth naming.

The reply should contain:

  1. A dimensions table, including assumed values.
  2. Any decision made on the user's behalf, with its reason. If a requested feature is mechanically weak, build what they asked for and name the weakness with a concrete alternative — never silently substitute.
  3. A slicer table: layer height, walls, infill, supports (exactly where), material, and which face goes on the bed and why.
  4. The one-line command to regenerate with different numbers.
  5. Anything to confirm against existing hardware before printing.

Deliver STL files to /mnt/user-data/outputs/ on claude.ai, or to a stl_output/ folder in the current working directory in Claude Code, and present them together with the generator script. The scripts live in this skill's scripts/ folder; call them by full path or copy them next to the part script. On Windows use python instead of python3.

Multi-part assemblies

When parts mate (pin and nut, lid and box, hinge halves):

  • generate both from shared parameters in one script — a clearance value living in two files will drift
  • derive the female part from the same function as the male, offset by a clearance, so they cannot disagree
  • state how many of each to print, and suggest a spare for the small one
  • when a fit is uncertain, offer a tolerance test: print the small part at two clearances and keep the one that turns

Related Skills