agentsclimarketplace

Image to 3d

Skill harshvladha/fabula/skills/image-to-3d

Fabula — an AI skill for turning ideas into Bambu Lab prints.

Install
npx -y skills add harshvladha/fabula --skill image-to-3d

Assembled from the repository path, not quoted from the project. Check it against their README if it does not work.

One thing to look at

  • 0 stars0 stars. Stars are a popularity signal and not a quality one, but at this level it is likely that nobody has read this closely except its author, and you would be relying on your own review.

What its author says it does

Copied from the file, not written here

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.

SKILL.md

7.3 KB, as published. Nobody here has run it

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:

  1. 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.
  2. 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.
  3. Perspective: near-frontal needed; strong angles distort proportions.
  4. 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:

  1. Clean silhouette image (see Phase 0.2): mask = luminance < 128. Done.
  2. Colour cue: e.g. warm subject on grey wall → R - B > t (t≈16). Histogram first.
  3. 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.
  4. 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-print skill for final delivery — its bambu3mf.py writes a FULL Bambu Studio project 3MF (printer/filament/process presets, per-part extruders/colours, overrides registered in different_settings_to_system). See ../bambu-print/SKILL.md + its references/gotchas.md.
  • Lightweight alternative (no full project file): geometry in 3D/3dmodel.model with print settings as per-object metadata in Metadata/model_settings.config (ironing_type=top, wall_loops, sparse_infill_density, brim_type, …). Note a partial Metadata/project_settings.config is silently DISCARDED by Bambu Studio — per-object metadata survives, which is why this route works. Builder in reference/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, camera clip_end must 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.

Keep looking

Skills are one crate of 328,083. Ordering is by how many stacks a row turns up in, so the top of any crate is what has actually been picked rather than what has the most stars.