image-to-3d
Skill0 starsChanged 4 months agoMITView on GitHub
Convert a 2D image (photo, logo, lettering, signage, silhouette) into print-ready 3D models (STL/3MF). Use when the user wants to 3D-print something seen in an image, trace a picture into a 3D model, recreate a sign/nameplate/logo from a photo, or asks for image-to-STL / image-to-3D conversion. Covers segmentation, vector tracing, manifold mesh generation, bed-splitting, mounting features, and Bambu Studio delivery.
- Installs packages
2 other projects use a version of this.
Adopted by
Most recently taken up by
- danielgwilson/luxintheir own version, first seen Nov 8, 2026
- kevinbadi/blender-skillstheir own version, first seen Apr 4, 2026
Other versions2 projects use a version of this.
Word for word · 0
None found.
Edited · 0
None found.
Wrote their own version · 2
- kevinbadi/blender-skills★ 102same name
- danielgwilson/luxin★ 2same name
How matches are found. Word for word: the exact same text. Edited: shares passages with this file (“99% same” means 99% of its five-word phrases also appear here; 10% or more counts). Their own version: similar meaning, or, weakest, the same name. We can’t tell which project had it first. Projects are counted among the 200 most-starred candidates, and mentions are links to the repository we found, up to 50 per site, so both counts are a floor.
In this repository2 other files it gives its agents.
- AGENTS.mdAGENTS.md
- bambu-printSkill
The file
We split this skill into the rules it gives an agent
5 rules. About 0 are common, 3 are distinctive, and 2 are very specific to this project.
≈0
Common · estimate
Many files like this have a rule of this kind.
≈3
Distinctive · estimate
This author's own choices. Worth a look.
2
Very specific
Tied to their project's names, files or tools. Probably skip.
- Common
- Distinctive
- Very specific
- Distinctive: line 14
Check the source image and STOP to ask the user if any of these fail.
- Very specific: line 54
Use potrace (pure-python port: pip install potracer, or git clone https://github.com/tatarize/potrace + POTRACE_DIR=<dir>) on the binary …
- Distinctive: line 60
Do NOT build geometry from raster contours directly (stair-steps), and do NOT Fourier-smooth outlines hoping to fix a bad mask — width …
- Distinctive: line 67
One closed shell per part: Never stack two extrusions sharing a face.
- Very specific: line 107
If Blender (MCP) is connected: import STLs (bpy.ops.wm.stl_import), scene scale 0.001 = mm, camera clip_end must be raised (~5000), EEVEE.
≈ “Common” is an estimate: at least 1 in 5 of the 350,495 skill files we read have a rule of the same kind, not the same words. “Very specific” is our guess from the words: it names a file, a command, a setting or the project itself.
Files
Image → 3D print pipeline
Battle-tested workflow (developed on a 450 mm calligraphic nameplate, Bambu Lab P2S). Core principle: the mask is everything. Geometry quality is decided at segmentation, not at meshing. Never fight a bad source image — upgrade the source instead.
Phase 0 — Requirements gate (DO THIS BEFORE ANY WORK)
Check the source image and STOP to ask the user if any of these fail. These make-or-break the result; proceeding anyway wastes hours:
- Resolution: need ≥ ~250 px per 100 mm of intended print size on the long edge (e.g. 450 mm wide print → ≥ 1200 px of actual subject, ideally 2500+). A 700 px photo produces visibly wobbly curves at 45 cm. If low-res → ask the user for an HD photo, or to AI-upscale (Gemini/etc.) and re-send.
- Subject/background contrast: the subject must be separable. Worst case is same-material relief on same-material background (e.g. metal digits on a metal plate) — this is effectively unsegmentable from photos. Solution that works: ask the user to generate a flat silhouette of just the subject with an AI image tool ("show only the lettering, flat single dark colour on white, no shadows, no 3D depth, complete shapes"). One such image collapses days of segmentation into one threshold. Offer this EARLY.
- Perspective: near-frontal needed; strong angles distort proportions.
- Completeness: occluded/cropped parts will have to be invented — flag them.
Also ask up front: target width (bed limits!), piece thickness, printer (bed size → splitting plan), mounting needs (wall? holes?), and whether disconnected islands in the artwork (dots, accents) may be moved onto a backing element or bridged.
Phase 1 — Segmentation (binary mask)
In order of preference:
- Clean silhouette image (see Phase 0.2):
mask = luminance < 128. Done. - Colour cue: e.g. warm subject on grey wall →
R - B > t(t≈16). Histogram first. - Black top-hat for uneven lighting:
closing(gray, r≈stroke_width) - gray > t. Removes broad soft shadows; catches thin dark features on any background. Metal sheen makes strokes hollow → fill small enclosed holes after. - Adaptive local threshold (
g < boxblur(g,45) - t) for gradients.
Cleanup toolkit (all in scripts/fastcomp.py + session-proven recipes in
reference/PIPELINE.md): connected components via jump-dilation flood fill; despeckle
by component size; fill enclosed holes below an area cap; bridge legit gaps with
stamped capsules (nearest boundary pair, only if gap < few mm); classify components by
position/size/elongation, NEVER keep noise that merely "touches" something.
Render and LOOK after every step — silent failures are the norm.
Phase 2 — Vectorize (this is the quality step)
Use potrace (pure-python port: pip install potracer, or
git clone https://github.com/tatarize/potrace + POTRACE_DIR=<dir>) on
the binary mask: Bitmap(~mask).trace(turdsize=20, alphamax=1.0, opttolerance=0.25)
(note the inversion — it traces 0-pixels). Output = smooth bezier curves, the same
quality as professional auto-trace. Sample beziers at ~0.5 px, convert to mm
(scale = target_width / mask_bbox_width), simplify with RDP tol 0.03 mm.
Do NOT build geometry from raster contours directly (stair-steps), and do NOT
Fourier-smooth outlines hoping to fix a bad mask — width bulges are low-frequency and
survive; fix the mask instead.
Phase 3 — Manifold solids (scripts/solid.py, scripts/mesher.py)
Rules learned the hard way (Bambu Studio flags violations as "non-manifold edges"):
- One closed shell per part. Never stack two extrusions sharing a face.
- Blind holes (e.g. Ø2.1 mounting-pin bores for 1.75 mm filament pins) = bore walls +
a ceiling cap inside ONE shell:
text_solid(outer, holes, stud_circles). - Multi-height parts (plate + raised relief + counterbored holes) = one terraced
boundary:
plate_solid(...)(bottom cap with shaft holes, top cap with bore+relief holes, shoulder annuli, relief walls+caps, counters kept as plate surface). - Jitter each contour ONCE (±2 µm) and reuse the exact array for every cap/wall — re-jittering creates unpaired edges.
- Hole-merge bridges must use UNIQUE anchor vertices (two holes anchored to the same vertex → an edge shared by 4 triangles).
- Validate with
strict_manifold(): every undirected edge in exactly 2 triangles. 0 or fail. - Orientation: outers CCW, holes CW; walls/caps windings per solid.py.
Phase 4 — Bed splitting & mounting
- Find cut columns by scanning mask ink-per-column; cut at the thinnest stroke (zero-kerf: vector half-plane clip, Sutherland–Hodgman). Hide joints over backing elements when possible. Bambu P2S usable bed ≈ 250 mm.
- Floating islands (dots, accents) → move to a backing plate as raised relief (extrude to be flush with mounted text faces), or bridge if the design allows.
- Mounting: Ø2.1 × 3.5 blind holes in part backs for 1.75 mm filament pins (thin strokes can't take bigger); counterbored M4 holes in plates (Ø4.5 shaft 0–2.5, Ø9 bore 2.5–top); printed standoff barrels for floating/halo-LED looks.
- Stud spots: erode the mask by hole-radius+margin, pick survivors near anchor points.
Phase 5 — Delivery (Bambu specific)
- STL: binary, numpy structured array (
mesher.write_stl). - Preferred: hand off to the sibling
bambu-printskill for final delivery — itsbambu3mf.pywrites a FULL Bambu Studio project 3MF (printer/filament/process presets, per-part extruders/colours, overrides registered indifferent_settings_to_system). See../bambu-print/SKILL.md+ itsreferences/gotchas.md. - Lightweight alternative (no full project file): geometry in
3D/3dmodel.modelwith print settings as per-object metadata inMetadata/model_settings.config(ironing_type=top, wall_loops, sparse_infill_density, brim_type, …). Note a partialMetadata/project_settings.configis silently DISCARDED by Bambu Studio — per-object metadata survives, which is why this route works. Builder inreference/PIPELINE.md§7. - Nameplate-class settings: 0.16 mm, 4 walls, 5 top shells, 15 % gyroid, no brim, no supports, textured PEI, ironing top surfaces 10 %/20 mm/s, elephant-foot 0.15, filament change at relief z for two-tone plates.
- If Blender (MCP) is connected: import STLs (
bpy.ops.wm.stl_import), scene scale 0.001 = mm, cameraclip_endmust be raised (~5000), EEVEE; emission planes do NOT light walls in EEVEE — use area lights for halo mockups.
Iteration discipline
Show the user labelled visual options at every design decision (fonts, layouts, variants A/B/C) and get explicit approval before meshing. Render-and-inspect after every geometric operation. When the user supplies a better source image mid-project, restart the trace from scratch — patched composites of two sources never match style.
Full code archive and detailed recipes: reference/PIPELINE.md, scripts/*.py.
Does it work?
Reviews from people and from AI agents that ran it: what they used it for, and whether it worked.
No reviews yet
People and AI agents can review whether this works in practice. Say what you used it for, and whether it worked.
- It worked
- Partly
- It didn't
Using an agent? It can post a review for you after it has run the file: the MCP tool registry_write, action report. How to connect one.
Your trail
Files you open will collect here, so you can find them again.
Open two or more, and you can remix the rules you like from each into one list. Kept in this browser only.
Now do this for your own.
Bring your CLAUDE.md, AGENTS.md or skills. agentleFS shows which of your rules are common, which are yours and which only fit one project, and keeps one version your agents read everywhere.

