Skip to content
The-DorkknightPublic

About

Resources

Contributing

Security policy

Stars

0 stars

Watchers

0 watching

Forks

Repository files navigation

WORK IN PROGRESS: MANY FEATURES MAY BE BROKEN (version 0.7.1-wip)

STL2STEP

Source-available · Non-commercial — licensed under the PolyForm Noncommercial License 1.0.0. Provided as is, with no warranty and no liability. Check converted files before relying on them. Not legal advice; see Licence below.

Preview of a converted part

One portable app that turns things into real STEP solids (true planes, cylinders, spheres and fitted NURBS, not thousands of triangles), with the mesh converter at its core:

Tab What it does
Convert STL / OBJ / PLY / 3MF mesh → STEP solid: planes, cylinders, spheres and NURBS for organic areas. Experimental engines (Staged, v2, Second pass), Guesstimate, and Extrude outline / Loft for flat-profile and tapered parts.
Hardpoints Open a hardpoint STL (an ordinary STL that also remembers which CAD face each triangle came from) and rebuild the solid from its faces instead of guessing them; or turn any plain STL into one.
SCAD → STEP Rebuild an OpenSCAD model as real CAD geometry (true cylinders, spheres, swept surfaces, exact booleans) instead of exporting a mesh and guessing afterwards. Customizer parameters, 3D preview and a live link that re-exports every time you save.
Image → STEP Trace a photo, scan or drawing of a flat part into its outline as real CAD curves (lines, arcs, circles, ellipses, splines; holes found by nesting) and save it as STEP: a solid of the thickness you type, or the flat shape. Scale from a printed scale token (paper or plastic), a marker sheet, a scan's own resolution, or a number. Experimental: every colour change, where each colour area of an icon or logo becomes its own piece.
Jetwash Cleans junk (slivers, 0.0001 mm steps, thin fins, specks, tiny holes/chamfers) out of existing STEP files.
Plugins One-click FreeCAD workbench and Fusion add-in, app-menu entry, right-click entries.

It runs in your web browser from one portable folder; no Tk, nothing installed on your system. Mac, Windows and Linux. Page with screenshots: https://The-Dorkknight.github.io/stl2step/

Reporting a problem? The 3D preview window carries a Diagnostic panel: the job's mode, surface fitter, quality settings and result as a QR code and in plain words. One screenshot of that window says it all; see Diagnostic code.

Start (install)

System Double-click
macOS 12+ (Apple Silicon or Intel) STL2STEP (Mac).command
Windows 10/11, 64-bit STL2STEP (Windows).bat
Linux (x86-64 / 64-bit ARM) stl2step-linux.sh

A small window (Terminal / console) opens and your browser shows the app. Keep that window open while you work; close it to quit.

macOS first time: macOS blocks scripts from the internet. Right-click the .command file → Open → Open. If there's no Open button (macOS 15+), open System Settings → Privacy & Security and click "Open Anyway". After that it opens with a normal double-click.

Portable and self-contained

Everything stays inside this folder:

STL2STEP/
  app/        the program
  runtime/    private Python 3.12 + libraries, one subfolder per CPU type
  Output/     your results (also offered as a browser download)
  • The first start downloads uv (the installer, ~20 MB), Python 3.12 (~30 MB) and the libraries (~500 MB); about 1.5 GB on disk. That takes a few minutes. Later starts are instant.
  • It never uses or changes your system Python, Homebrew, conda or anything else. User settings (PYTHONPATH, pip/uv config files, ~/.local packages) are ignored.
  • Nothing is written outside the folder: temporary files go to runtime/tmp.
  • Move or copy the folder anywhere — another disk, another Mac, a USB drive — and it keeps working without reinstalling. An Intel Mac and an Apple Silicon Mac can share one folder: each sets up its own runtime subfolder the first time. (USB drives: use an APFS or Mac OS Extended format; exFAT is untested.)
  • Uninstall: delete the folder. Reset: delete runtime/.

Hardpoints tab: STL files that remember their CAD faces

Hardpoints tab after converting a labelled STL

A hardpoint STL is an ordinary binary STL, same triangles, same file size, same .stl extension, that also records in its spare bytes which CAD face every triangle came from, what kind of surface that face is (flat, cylinder, sphere, cone, torus, freeform) and where the CAD corners are. Slicers and viewers open it as a normal mesh. STL2STEP can skip the guessing and rebuild each face as the surface it really was. The format is described in HARDPOINT_STL.md.

  • Drop an STL and the tab says what it is: a hardpoint STL with valid labels (with its faces, units and tolerance), one whose triangles were edited after labelling (the labels are then ignored), or a plain STL.
  • Convert using the labels rebuilds the solid from the faces in the file. Every labelled face is checked against the tolerance before it is trusted; a face that doesn't fit its label goes through the normal detection instead, so a wrong label can cost speed but not correctness.
  • Convert ignoring the labels does the same file the normal way, to compare.
  • Convert and make a hardpoint STL converts a plain STL and also writes the same mesh back out as a hardpoint STL carrying the faces it found (the triangles are copied byte for byte), so the next conversion of that file is faster and cleaner.
  • The FreeCAD and Fusion plug-ins have an Export hardpoint STL command that writes the real CAD faces straight from your model.

The same knob converted from a plain STL and from a hardpoint STL

On the test knob (a cylinder, a torus blend and a ball) the plain STL gives 1,103 faces (max deviation 0.129 mm) and the hardpoint STL gives 8 faces (0.060 mm). A bracket gives 21 faces plain and 17 with labels. Command line: python app/stl2step.py hardpoints part.stl shows what a file contains, --no-labels ignores them, and --save-labelled also writes the hardpoint STL. Labels are only used on the full mesh, not on one that was reduced first. Tested on four small sample files and nothing else; cones and tori become fitted NURBS faces, not true cone and torus surfaces.

SCAD → STEP tab: OpenSCAD models as real CAD

SCAD to STEP tab

Turns an OpenSCAD model (.scad, or a .csg export) into a solid STEP file with true geometry: cubes become boxes, cylinders true cylinders and cones, spheres true spheres, extrusions and revolutions true swept surfaces, booleans exact solid booleans. A low $fn on purpose (a $fn=6 nut trap) stays the polygon it is. hull() and minkowski() of common shapes are built exactly too; text and imported 2D outlines come in as exact outlines; the rare parts with no exact CAD form (an imported STL, surface()) are rendered by OpenSCAD and joined in as flat facets. The engine is the SCAD2STEP project, now built into this app.

  1. Choose a .scad… (or paste its path, or drop it on the page). Choosing from disk keeps include / use libraries next to the file working and lets the live link watch it.
  2. Parameters: the model's own Customizer variables appear as fields (ranges, drop-downs and /* [Groups] */ are respected), so you can export a variant without editing the file.
  3. Options: units, which circles stay polygons, where the STEP goes (next to the .scad, or Output/), a comparison with OpenSCAD's own render (volume and size), and smooth text outlines.
  4. Convert to STEP. The result opens in the same 3D preview as the Convert tab.
  5. Live link: keep editing in OpenSCAD; each time you save (F2) the STEP beside the .scad is rebuilt within a second or two (including when a library it uses changes).

3D preview of a converted OpenSCAD bracket

You need OpenSCAD installed (2021.01 or newer; only 2021.01 was tried) unless you only convert .csg files. The app looks for it in the usual places (normal install, AppImage in your home, Downloads or Applications folder, Flatpak, Snap); otherwise enter its location on the tab. OpenSCAD is not bundled and keeps its own licence. On the example bracket the STEP has 31 faces and its volume is within 0.002 % of OpenSCAD's render. Command line: python app/stl2step.py scad model.scad -D width=40, --watch for the live link, --no-verify. Right-click entries (Linux Mint Nemo, GNOME Files, Windows Send to) and FreeCAD / Fusion OpenSCAD → STEP solid commands come from the Plugins tab.

Image → STEP tab: a photo, scan or drawing as a STEP outline

Image to STEP tab

Drop a picture of a flat part (PNG, JPG, BMP, TIFF, WebP). Its outline is traced into the fewest lines, arcs, circles, ellipses and splines that fit, outlines inside outlines become holes, and the result is written as STEP in millimetres. The engine is the ImageToSketch project (a FreeCAD add-in by the same author); the parts of it that need no FreeCAD are built into app/imagetosketch (this build carries ImageToSketch 0.9.1).

  1. Picture. A dark part on plain white paper, lit evenly, photographed from above works best. Scans and clean drawings work too (a line drawing is traced along the middle of its lines). The preview shows what will be kept: green becomes geometry, amber is borderline and left out, red is rejected.
  2. Scale. The tab looks at the picture and picks what it finds:
    • Scale token: a black square (40 mm) with one clipped and one rounded corner. Printed on paper: download the token sheet (PDF, A4 or Letter; a token in two opposite corners), print it at 100 %, measure a square with a ruler and type what you measure, lay the part on the sheet. One token gives the scale; with both in view the camera's tilt is measured across the whole sheet. 3D-printed plastic: download the STL (40 x 40 x 1.2 mm), print it in matt black, lay it on white paper beside the part. Either way a photo taken a little off vertical is straightened.
    • Part's top above the token: something nearer the camera looks bigger (a 10 mm part from 300 mm: about 3 %). Type the part's height here and that is taken out. It needs the camera distance, which a phone or camera JPEG carries in its lens data (0.9.1: the lens data now comes first, and a typed distance is only compared with it); for a PNG, a screenshot or an edited photo, type Camera distance. A distance that is only roughly right just scales the outline evenly (from 1 m, 10 % out costs about 1.6 % on a 140 mm tall part); with neither, a phone's main camera is assumed. The side-wall correction is skipped, with a message, when the camera's position is too uncertain. Send photos of tall parts straight from the phone, not through a messenger (it strips the lens data). Part's top above the token, Camera distance and Part has straight vertical sides now sit just above Convert to STEP.
    • Marker sheet (four printed markers around the part), the file's own resolution (flatbed scans), the picture's width, millimetres per pixel, or a plain square of known size.
  3. STEP. Thickness: 0 writes the flat shape as a face, any other value a solid of that thickness standing on Z = 0. A STEP file does not have to contain a solid, so there is no need to extrude by a dummy 1 mm just to be able to save: the file then holds a surface, which you can extrude in your CAD program. Curves only writes just the lines and arcs with no face; that is valid STEP too, but some programs skip bare curves when importing (Fusion's STEP import reads faces and solids), so the face is the safer flat form. Include borderline shapes adds the amber ones the tracer was unsure of. Also save the outline as SVG / DXF writes the same outline as a millimetre drawing into Output/ beside the STEP, for laser cutters and 2D CAD.
  4. A shape that fills the picture. A logo or icon often runs right to the picture's edge. Shape runs off the picture → work it out continues drawn graphics a little beyond the edge so the whole shape is traced, and leaves photos alone; the other two choices force it either way. (Before 0.5.1 such a shape was left out and only what was inside it was written.)
  5. Convert to STEP. The result opens in the same 3D preview as the other tabs.

3D preview of a traced plate

Every colour change (experimental, new in 0.5.2-wip; neighbours meet exactly since 0.7.0-wip)

Image tab tracing every colour change of an icon

Normally the part is traced against its background: one outline per part, plus its holes. A picture with several colours has more edges than that. On an app icon (a grey rounded square, a cube drawn in three shades of blue, a yellow ring) the ordinary trace outlines the square and the light blob standing in it, and nothing says where the cube ends and the ring begins, or where one face of the cube meets the next. Set What to trace to every colour change and:

  • every colour area gets its own outline, and in the STEP its own face or solid: the pieces lie side by side like a jigsaw (the icon above: 6 solids, each within 0.1 % of its true area on the test redrawing);
  • a smooth blend is not an edge: a gradient, a soft drop shadow or light falling off across a table gives no line;
  • neighbours may shade: two faces with a light-to-dark gradient are told apart even where their colours overlap;
  • the colour round the picture's edge is the background, and the same colour seen through a hole is a hole;
  • Colour difference that counts sets how different two colours must be (left to work it out, it is cautious with noisy photos and JPEGs); Edge shared by two areas only matters for the SVG / DXF copies.

Tracing the ordinary way, a clean picture with three or more flat colours gets a line in the log saying that this mode exists. It is 2 to 4 times slower than the ordinary trace and works on pictures up to 1600 px a side (larger ones are reduced first). It has only been tried on pictures drawn by the test code, among them a redrawing of the icon it was reported with, made from a photograph of a screen: not that icon's file, no real logo, no real photograph. Known limits: drawn outlines between areas (each area is traced to the inside of the line), the same colour on both sides of a thin line (one area), greys closer than about 10 levels, pictures under about 96 px, blur over about 2 px. What was tried and dropped, the numbers and the limits: docs/research/TRANSITION_TRACING.md.

To try it without printing anything: examples/plate-on-token-sheet-simulated.jpg is a simulated photo (it carries lens data like a phone photo) of a 90 x 60 x 10 mm plate with a 16 mm bore on the token sheet. Drop it in, type 10 under Part's top above the token and 10 under Thickness.

Command line: python app/stl2step.py image photo.jpg --part-above-token 10 --thickness 10, --markers, --dpi, --mm-per-px 0.1, --picture-edge edge, --include-borderline, --also-svg, --also-dxf, --find transitions (with --colour-step, --shared-edges), --make-token-sheet sheet.pdf, --make-token token.stl (image --help lists the rest).

How far this has been tested: on pictures drawn by the test code and on photographs made by a simulated camera, where the true sizes are known (plate sides within about 0.2 % with the part's height typed in; without the camera distance a 10 mm part reads 2 - 4 % large, and the log says so). No token has been printed and no real photo traced. Lens distortion is not corrected. Details and the accuracy table are in the ImageToSketch repository.

The mesh side already had its own depth setting: in Convert → Extrude outline, Extrude height (0 = the part's own height; --height on the command line) sets how deep a traced mesh outline is extruded.

Neighbours meet exactly (on by default, new with ImageToSketch 0.9.0): where two colour areas touch, both use one and the same curve for the edge they share, so the faces or solids fit together with no gap and no overlap. Untick it (command line --no-weld) to let each area keep its own fit of the edge, as in 0.5.2.

Diagnostic code: one screenshot says what was set and what came out

Preview window with the diagnostic panel

New in 0.5.2-wip. When a conversion finishes, the 3D preview opens with a Diagnostic panel on its right:

  • a QR code that carries the job's settings and result;
  • the same in plain words: mode, surface fitter, the quality settings (tolerance, guesstimate, angles, patch size, switches), the performance profile with its time budget and fill allowance, then the result: closed solid or not, geometry check, route taken, face counts, deviation, volume difference, time, and which limits were hit (time budget reached, checkpoint kept, memory tight, faces left as facets ...);
  • the code as text with a Copy code button.

Take one screenshot of the preview window and the report is complete: nothing to remember, nothing to copy from the log. The Diagnostic button in the window's bar hides the panel. A job that failed has no preview, so its red result box has a Show the diagnostic code button that opens the same panel. A Smooth surfaces or Exact facets conversion run from the command line prints its code at the end.

Reading one back, from a screenshot (or a phone photo of the screen) or from the code itself:

./stl2step-linux.sh diag screenshot.png
./stl2step-linux.sh diag S2S1-H0C9EZAYQ02GA00-C22W0053RY7KR0000AB186-RT0800Q3G07C000B8004003G00207H013G0Y800G-KFWJ

What is in the code: the app version, the time to the minute (UTC), a tag for the job, the settings and numbers listed above, and "Linux / Windows / macOS". What is not: the file's name, any path, the log, the error text, anything else about your computer. The panel shows the file name and an error's text in words and marks them "(not in the code)". Nothing is sent anywhere: the QR is a picture on the page.

The code follows the conventions of the author's ErrCode project (several records multiplexed into one string, Crockford base32, the same time stamp and tag) but is its own format, S2S1; it does not contain ErrCode's error dictionary. It carries the settings of STL → STEP conversions; Jetwash, SCAD and Image jobs get the header and the result only, and the panel says so. The QR picture needs the small segno package, which the start file adds on its next start (needs the internet once); without it the words and the code are still shown. Format, sizes and how far it was tested: docs/research/DIAGNOSTIC_CODE.md. Tested on Linux in a headless browser only; a real phone photo of a real screen has not been tried.

Front panel, activity LEDs and effort LEDs

Front panel

The top bar is styled like an 80s/90s PC case. Left to right: tabs, a CPU % display and VU bar, a red DISK LED, a green RUN heartbeat that blinks every second while a job is running (amber if it has been quiet for 45 s), and a 3-position LOCK / NORM / TURBO key switch that is purely decorative for now.

Every setting has two little LED stacks: red = how hard it works your computer, green = quality of the result. Red high + green high means the computer will drag but the output will be as good as it gets. They are rough guides computed from the value, not measurements, and update as you change a setting.

Smooth sketch (optional, in Extrude outline mode)

Smooth sketch preview

Extrude outline normally redraws a part's outline as straight segments, so an oval hole becomes dozens of tiny flats. Tick Smooth sketch and each loop is redrawn as the simplest shapes that stay within the outline tolerance: straight lines, true arcs and circles, ellipses, and splines with as few control points as possible. Press Preview outline to see it; red dots mark where two pieces meet. Command line: --mode extrude --smooth-sketch.

On a test plate with rounded corners, a slot, a D-shaped hole, a hex hole, a round hole, an ellipse and a freeform "bean" hole, the result has 25 faces, the same as the original CAD model (94 without Smooth sketch at the automatic tolerance, 319 at 0.02 mm). The ellipse comes back as one true ellipse and the bean as one closed spline (11 control points at the automatic tolerance, 33 at 0.02 mm).

Limits: it only applies to Extrude outline (not Loft, not Smooth surfaces). A loop that can't be fitted within tolerance stays as straight segments, and the log says so. Noisy or scanned outlines come out in more pieces. A very coarse round fillet (steps over 25°) is read as corners. The plug-ins don't offer it yet.

Guesstimate organic areas (optional, off by default)

Settings with Guesstimate switched on

Tick Guesstimate organic areas (fast) in Settings when the freeform parts of a model only need to be roughly right. Organic tolerance (default 0.3 mm) is how far a freeform surface may sit from the mesh inside a patch. Flat faces, round holes (cylinders), spheres and all edges keep the normal tight tolerance. With it on, dense meshes are first reduced (staying within a third of the normal tolerance, checked, and kept closed) and the slow patch filler is skipped. Command line: --guess or --guess 0.3. Works with the Classic and Staged fitters; the FreeCAD and Fusion plug-ins don't offer it yet.

Measured on a 160,000-triangle organic test model (2-core machine): 41 min → 4.3 min, 107 MB → 28 MB STEP, 40,484 → 9,239 faces, max deviation 0.105 → 0.211 mm. It does not reduce the number of areas left as triangles (513 vs 450 regions); that needs the boundary work planned next. Parts made only of flats and round features come out identical with it on or off.

Performance profiles, GPU, queue and scheduling

Performance card

Pick a profile in the Performance card (or leave it on Auto, which looks at your cores and RAM):

Profile For What it does
Potato old or small laptops (e.g. 8 GB RAM, 4 cores) 1 thread, low priority, no GPU. Slowest, lightest.
Moderate typical modern laptops about half the threads, GPU where supported.
Extreme Apple Silicon Macs, workstations every thread, Classic and v2 run side by side in Second pass, several queued files at once, GPU where supported.

Command line: --profile potato|moderate|extreme|auto (and --no-gpu).

Graphics card (optional, experimental). OpenCASCADE, which builds faces and writes STEP, is CPU-only, so a GPU cannot speed those parts up. Only the v2 fitter's shape-guess scoring can use a GPU, through an optional GPU pack (PyTorch: Apple Metal or Nvidia CUDA). Click Install GPU pack in the Performance card on a supported machine (about 80 MB on an Apple Silicon Mac, about 2.5 GB for Nvidia CUDA), then restart. After installing, the log says whether the pack can actually see your card; on Nvidia an old graphics driver is the usual reason it can't. Without the pack everything runs on the CPU. The default Classic converter does not use the GPU.

Queue and scheduling. Click Convert more than once (same file with different settings, or other files) and the jobs line up in a Queue card; the profile decides how many run at once. Start next to the Convert button can delay a job: in 1 or 3 hours, tonight at 01:00, or at a time you choose. The app stays open and keeps the computer awake while it waits; if you close the app, scheduled jobs are lost.

Queue

Cancel and activity monitor

While a job runs, Cancel stops it (the work is in a separate process that is killed) and resets the tab so you can drop a new file. The header shows a CPU VU bar and a big red DISK LED that lights on disk activity; under the progress bar you see the running time and how long since the last message. Long steps can leave the percentage still for minutes — if the CPU bar is busy, it is working. (STL2STEP uses the CPU only, so there is no GPU meter.)

Running job with Cancel button

Big meshes and slower computers

Speed only affects how long a job takes; running out of memory is what can crash it. Measured peak memory:

Triangles Smooth surfaces Exact facets
10,000 0.4 GB, 5 s 0.55 GB, 12 s
40,000 0.5 GB, 20 s 1.0 GB, 1–2 min
160,000 0.9 GB, 30 s 2.2 GB, 9 min

Reducing big meshes keeps features. "Reduce to N triangles" (and the memory guard below) first finds flat faces, holes, cylinders, spheres and sharp edges on the full mesh, then simplifies only inside each region with its outline locked. Flat faces are rebuilt from their outline alone, round features stay on their exact cylinder/sphere, so a 60-sided hole is still recognised as one true cylinder afterwards. Example, a 224,000-triangle plate reduced to 22,000: 12 exact faces (0.005 mm), where blind reduction gave 44 fragments and 5 mm of damage.

"Protect memory" (on by default) checks this computer's free RAM before starting and reduces meshes that wouldn't fit. On an 8 GB laptop that's above ~190,000 triangles in Exact facets mode or ~775,000 in Smooth surfaces mode. The log says when this happens. While a job runs, the app works at low priority, so the computer stays usable, and stops it from idle-sleeping, so an hour-long job isn't interrupted.

Staged engine (experimental, off by default)

Settings with the Staged fitter selected

Choose Surface fitter → Staged in Settings (or --engine staged) to try roughing first. Before any patch fitting, the whole smooth part of the model is searched for lathe shapes (one revolve axis, a profile spline) and for extruded freeform outlines. Where they fit within tolerance they become single exact faces — a true cylinder, cone or sphere when the profile is straight or circular, otherwise a spline profile revolved or extruded — instead of hundreds of NURBS patches. Everything left over goes through the normal Classic patch fitter. Faces are trimmed directly on their own surface, then the STEP is written, read back, and any face that did not survive is demoted and rebuilt, so the solid stays closed.

It is opt-in because it is new: Classic is still the default and its results are unchanged. Guesstimate works with it too (shapes are found on the full mesh, then the mesh is reduced with those regions locked).

Measured (2-core Linux machine, synthetic test parts, default settings):

Part Classic Staged
Turned vase 8,665 faces, 199 s 14 faces, 12 s
Torus 605 faces, 72 s 9 faces, 4 s
Fine tray (flats, holes, rounded edges) 1,927 faces, 23 s 131 faces, 15 s
Coarse tray 635 faces 119 faces
Bracket, sphere, blob identical identical

Max deviation from the mesh was equal or smaller on every one of these. On very dense (about 100,000-triangle) CAD-like test meshes with Guesstimate on, it also finished (vase 191 faces in 38 s, tray 4,080 faces in 3 min, oval-cut plate 1,497 faces in under 2 min, all valid closed solids within 0.14 mm). On a 160,000-triangle organic ghost model with Guesstimate it took 272 s and gave 3,271 faces (Classic with Guesstimate: 262 s, 9,239 faces). Where it is not better: the same ghost at full strict tolerance without Guesstimate took 75 minutes, 4.3 GB of memory and ended as an all-triangle solid (Classic: 41 min, 40,484 faces), and a non-watertight 100,000-triangle plate test did not finish in 25 minutes. So: try it on turned, round or prismatic parts, and add Guesstimate for dense organic scans. Tested on synthetic parts and one organic ghost model only, on a 2-core Linux machine — not yet on a range of real-world parts. Please try it on yours and compare; python tools/bench.py part.stl --engines classic staged prints the same table (faces, share of area as exact shapes, deviation, time, peak memory) for any mesh.

Ladder engine (experimental, off by default)

Settings → Surface fitter → Ladder or --engine ladder. Easy things first: the mesh is looked at for a few milliseconds (its edge-angle histogram, which flats are bounded by sharp edges, whether the curved area is a surface of revolution about some axis) and routed as prismatic, lathe, organic or mixed. Exact shapes are claimed before anything slow runs, searches that cannot succeed are skipped, and problem areas are guesstimated (freeform patches within the Guesstimate tolerance, 0.3 mm by default) or kept as facets instead of being refined for minutes. Classic is untouched and stays the default.

Part (this 2-core Linux machine) Classic Ladder
Dense lathe vase, 24k triangles 264 s, 8,980 faces 8.0 s, 14 faces, max 0.025 mm
Organic blob, 10k triangles 17 s, 20 faces, 0.059 mm 2.4 s, 20 faces, 0.108 mm (guesstimated)
Knob 17 s, 1,103 faces, 0.129 mm 12 s, 951 faces, 0.129 mm
Fine stepped shaft with a cross hole 23 s, 2,190 facets 1.8 s, 8 faces, 0.007 mm
Block with a 15 mm fillet 20 planes (the fillet as flats) 9 faces, the fillet a true cylinder
Bracket, plate, tray same result, same time
Organic figure, 160k triangles (Potato profile) Classic + Guesstimate: 262 s, 9,239 faces, 0.21 mm 318 s, 3,271 faces, 0.26 mm, checkpoint written, peak 1.3 GB

Never ending with nothing. Every performance profile has a time ceiling (Potato 2.5 h, Moderate / Extreme 40 min) after which unfinished areas are kept as exact facets and the file is written; on big meshes a checkpoint STEP (exact faces, the rest as facets) is written before the slow fitting starts and is kept if the fitter dies, out of memory included; the slow plate filler is skipped when memory is nearly full; the faceted fallback is capped at about 20,000 faces so the file stays openable. These apply to Classic too (they only change what happens to a run that would otherwise go past the ceiling or crash).

Options: --no-ceiling switches the time ceiling and fill allowance off (refine for as long as it takes); --route prismatic|lathe|organic|mixed forces a route; --no-ladder-guess keeps everything at the tight tolerance (problem areas become facets); --budget 60 turns anything still outside tolerance into facets once 60 s have passed; --max-fills 10 limits the slow plate filler; --plane-rule length is the flat-border test the prismatic route uses (usable with Classic too). Tested on 13 synthetic CAD meshes and two synthetic organic shapes only, on this machine; not on scans, not on real downloads, not on the target laptops. The reasoning and measurements are in docs/research/.

Research notes (for anyone who wants to dig in)

Three test parts as input mesh, Classic result and Staged result

Why does converting a mesh to STEP take so long and give so many faces? docs/research/ has a plain-English summary with pictures of a research report on exactly that: the slow fallbacks are the real cost, exact shapes (flats, holes, lathe shapes, extrusions) should be claimed first, and the freeform rest is better built from four-sided patches that need no trimming. It also lists what is already built into STL2STEP (the experimental Staged engine), what is not, and the open questions. The full 7,000-word report with every source link is FULL_REPORT.md. It was written with AI assistance and is not independently verified; it is there so others can check it, argue with it and build on it. A second round (October 2026) asked whether cheap machine vision could help (mostly no: use the vision toolbox on the mesh's own normals and sections, not on pictures), how the techniques combine (one ladder; the saving is in what it skips), and what "easy things first, guesstimate the rest" costs in accuracy; those three reports are in the same folder and led to the Ladder engine above. A third round (POTATO.md) covers never crashing on a small computer and finishing within a time ceiling, and a fourth (SLICER.md) asks whether the app could work like a 3D-printing slicer (short answer: Loft and Extrude outline already do; borrow the slicer's rules for where to put layers, not the layers themselves; nothing from it is built yet). Two sets of working notes from building 0.5.2 are there too: TRANSITION_TRACING.md (tracing every colour change of a picture: the first design that was dropped, the one that was built, 29 measured cases) and DIAGNOSTIC_CODE.md (the code in the preview window: format, why packed bits and not JSON, what was tested).

What to expect

  • CAD-style parts (flat faces, holes, rounded edges and corners, chamfers): flat faces become true planes; edge rounds and corner balls are split apart and become true cylinders and spheres. Every face is checked (valid, right size, on the mesh) and anything that fails is kept as exact facets, so the result is always a closed solid.
  • Organic shapes (sculpts, scans) become smooth fitted patches.
  • Organic shapes with many sharp rims or tunnels work but are slow and come out partly faceted. A 160k-triangle test ghost took 30 min and gave a valid, accurate solid with many facets. For those, "Exact facets" mode is quicker if you only need a closed STEP.
  • Preview: when a conversion finishes, a 3D preview opens in the app (drag to rotate, scroll to zoom). Blue = flat, green = cylinder/sphere, light grey = smooth NURBS, dark = kept as facets. Original shows the input mesh for comparison.

Experimental options

The default converter is the proven Classic one. These are opt-in:

  • Surface fitter → v2: a newer fitter (adaptive NURBS, stricter checks). Better on some CAD parts, worse on others (can give more faces or facets).
  • Surface fitter → Staged: roughing first — lathe and extruded shapes become exact faces before patch fitting (see above). Far fewer faces on turned, round or prismatic parts.
  • Surface fitter → Second pass: runs Classic, then v2, and keeps whichever came out better — it can only improve on Classic, but takes about twice as long.
  • Extrude outline / Loft cross-sections modes: only for flat-profile or tapered/stepped parts. On organic shapes they give a striped mess — use Smooth surfaces for those. Command line: --engine staged, --engine ladder (with --route, --budget, --max-fills, --no-ladder-guess, --plane-rule), --engine v2, --engine best, --mode extrude, --mode loft.

Command line (optional)

Pass arguments to the launcher, e.g. on Mac/Linux:

./stl2step-linux.sh part.stl                       # → part.step
./stl2step-linux.sh part.stl out.step --units in --mode faceted
./stl2step-linux.sh wash old.step --threshold 0.05 --coarseness 2
./stl2step-linux.sh plate.stl --mode extrude --axis z        # redraw from its outline
./stl2step-linux.sh taper.stl --mode loft --max-slices 10
./stl2step-linux.sh plate.stl --mode extrude --height 5      # the same, extruded 5 mm deep
./stl2step-linux.sh image photo.jpg --part-above-token 10 --thickness 10   # photo on the token sheet → 10 mm solid
./stl2step-linux.sh image scan.png --dpi                      # flatbed scan → flat STEP face
./stl2step-linux.sh image --make-token-sheet token_sheet.pdf  # the sheet to print (--make-token x.stl for plastic)
./stl2step-linux.sh image icon.png --width-mm 50 --thickness 2 --find transitions   # EXPERIMENTAL: every colour area its own solid
./stl2step-linux.sh diag screenshot.png                       # read a diagnostic code back from a screenshot (or: diag CODE)
./stl2step-linux.sh scad model.scad -D width=40               # OpenSCAD model → solid STEP
./stl2step-linux.sh scad model.scad --watch                   # live link: re-export on every save
./stl2step-linux.sh hardpoints part.stl                       # what a hardpoint STL contains
./stl2step-linux.sh part.stl --save-labelled                  # also write a hardpoint STL
./stl2step-linux.sh install files                             # right-click entries (add --remove to undo)

(On a Mac: bash app/portable.sh …, on Windows: "STL2STEP (Windows).bat" …)

Using it

Convert: drop a mesh, pick the input units (mm / inches / cm / m) and a mode:

  • Smooth surfaces: planes, cylinders and spheres become true surfaces and organic areas become fitted NURBS patches. Any patch that can't meet the tolerance stays as exact facets, so the result is still a closed solid.
  • Exact facets: every triangle kept, coplanar ones merged. Fast; always matches the mesh.
  • Extrude outline (experimental): the part is redrawn instead of rebuilt — its outline along an axis (the whole-part silhouette, or an exact cross-section at a height you pick) is cleaned up and extruded. Perfect for plates, brackets, gaskets and logos: every face is an ideal plane and round holes become true circles. Height defaults to the part's own height.
  • Loft cross-sections (experimental): for tapered or stepped parts. A handful of slices is picked where the profile actually changes shape (not a dense stack, so no staircase and it stays fast), and lofted into one smooth solid. Holes are lofted when every slice has the same number. Preview outline shows what will be traced before you convert. Extrude symmetric splits the extrude height both ways around the cross-section (or the part's middle), and Slice heights lets you choose the loft slices yourself instead of picking them automatically. (These two modes come from the earlier stand-alone outline-tracing STL2STEP, now built in. Command line: --symmetric, --heights 2,10,30; in Python: profile2d.convert_stl_to_step(...).)

Hardpoints, SCAD → STEP and Image → STEP are described above.

Jetwash: drop a STEP (or an STL, which is converted first), or click "Use last converted STEP". Threshold is the size below which something counts as junk (0.01–0.05 mm for cut-extrude debris). Coarseness: 1 gentle, 2 normal, 3 aggressive (also removes holes, fillets and chamfers smaller than the threshold). Each removal is checked and undone if it would damage the part.

FreeCAD and Fusion plugins

Easiest: start STL2STEP, open the Plugins tab and click Install FreeCAD plugin (or Install Fusion add-in). It finds every FreeCAD on the computer (normal install, AppImage, Flatpak, Snap, 1.0 and 1.1 settings folders), copies the workbench in and tells it where this folder is. Restart FreeCAD and pick STL2STEP from the workbench list. (It won't appear in FreeCAD's Addon Manager — that only lists add-ons it downloaded itself.) Linux: Add STL2STEP to the app menu makes it start like any other app. Add right-click entries puts Convert to STEP (for meshes and OpenSCAD models) and Live-link (for a .scad) in Linux Mint's Nemo, GNOME Files' Scripts menu or Windows' Send to menu (install files, undo with install files --remove). Command line: ./stl2step-linux.sh install (or install freecad, install fusion, install menu, install files).

Linux: the app opened FreeCAD instead of a browser? Some programs claim web links. STL2STEP now skips those and opens Firefox/Chrome/Chromium; the address is also printed in the terminal window if you want to paste it yourself.

Manual install, if you prefer: The plugins folder has a FreeCAD workbench and a Fusion add-in (Fusion's free Personal Use licence runs add-ins too). They are thin front ends: they send the mesh to this STL2STEP folder, it does the conversion in the background, and the solid comes back into your model. Double-click the STL2STEP start file once first so its setup is done; the plugins won't download anything themselves. They look for this folder in your home folder, Applications, Desktop, Documents and Downloads, and ask where it is if it isn't there. Results are also saved in Output/.

FreeCAD (0.20 or newer)

  1. Copy plugins/FreeCAD/STL2STEP into FreeCAD's Mod folder:
    • Linux: ~/.local/share/FreeCAD/Mod/ (for FreeCAD 1.0+ AppImage/Flatpak the same path usually works; in FreeCAD, Macro → Macros… shows the user folder, and Mod sits next to it)
    • macOS: ~/Library/Application Support/FreeCAD/Mod/
    • Windows: %APPDATA%\FreeCAD\Mod\
  2. Restart FreeCAD and pick the STL2STEP workbench.
    • Mesh → STEP solid: converts the selected mesh object(s). With nothing selected it asks for mesh files. The solid is added as <name>_solid and the mesh is hidden.
    • OpenSCAD → STEP solid: pick a .scad / .csg; it is rebuilt as real geometry and added as a solid.
    • Jetwash (clean STEP): cleans the selected solid(s), or STEP files you pick. Result: <name>_clean.
    • Export hardpoint STL: saves the selected solid(s) as a hardpoint STL (done inside FreeCAD, no STL2STEP folder needed).
    • STL2STEP folder…: choose where STL2STEP is. Progress shows in a dialog with Cancel; the full log is in View → Panels → Report view.

Fusion

  1. Copy plugins/Fusion/STL2STEP somewhere permanent (e.g. next to this folder).
  2. In Fusion: Utilities → Add-Ins (or Shift+S) → Add-Ins tab → the + → choose that STL2STEP folder → select it → Run. Tick Run on Startup to keep it.
  3. The buttons are under Utilities → Add-Ins:
    • Mesh → STEP solid: select mesh bodies (or choose a mesh file), set options, OK. The STEP is imported into the same component and the mesh is hidden.
    • OpenSCAD → STEP solid: choose a .scad / .csg; the solid is imported.
    • Jetwash STEP: choose a STEP file (defaults to the last converted one); the cleaned result is imported.
    • Export hardpoint STL: select solid bodies and save them as a hardpoint STL. Fusion works in cm internally; the add-in converts to mm for you.

Screenshots

Convert tab
Convert tab
Finished conversion with log
Settings and log
Jetwash tab
Jetwash tab
Plugins tab
Plugins tab (one-click FreeCAD / Fusion install)
First-start notice
First-start notice
Staged engine option
Experimental Staged fitter
Hardpoints tab
Hardpoints tab
SCAD to STEP tab
SCAD → STEP tab
Image to STEP tab
Image → STEP tab
Traced plate in the 3D preview
A traced plate as a solid
Every colour change of an icon
Image → STEP: every colour change (experimental)
The icon's six pieces in the preview
... as six solids
Diagnostic panel in the preview
Diagnostic panel: settings and result as QR and words

Troubleshooting

Problem What to do
macOS says the .command file can't be opened Right-click → Open → Open, or System Settings → Privacy & Security → Open Anyway.
First start is slow It is downloading a private Python and libraries (~500 MB, a few minutes). Later starts are instant.
Browser doesn't open Copy the http://127.0.0.1:… address printed in the terminal window into a browser.
Linux opened FreeCAD instead of a browser Fixed: STL2STEP skips programs that claim web links. The address is also printed in the terminal.
STL2STEP isn't in FreeCAD's Addon Manager Expected. It is a workbench: choose it in the workbench dropdown after installing from the Plugins tab and restarting FreeCAD.
Install GPU pack fails with "managed by uv and should not be modified" Fixed in this build (the installer now uses the same switches as the first-run setup). Update, then click it again.
Result has black (facet) patches Those areas couldn't be fitted within tolerance and are kept as exact triangles so the solid stays closed. Try a larger tolerance, or Exact facets mode.
Out of memory on a big mesh Leave "Protect memory" on, or set "Reduce to N triangles".
SCAD → STEP says OpenSCAD was not found Install it from openscad.org, or type its location (the program or the AppImage) into the box on the tab and press Use this. .csg files convert without it.
A hardpoint STL's labels were ignored The log says why: the triangles were edited after the labels were written, or it is a newer format version. Re-export it from the CAD program, or convert it as a plain STL.
Image → STEP says the picture tracer needs OpenCV This version added one library. Close the app and start it again with its start file: it sees that the list of libraries changed and installs what is missing (needs the internet once).
Image → STEP says "No scale token found" The token must be the black square with one clipped and one rounded corner, flat on a light surface, fully in view, not touching the part, not in glare. Or choose another way to set the scale.
A traced part comes out a few percent too big The part is thicker than the token and the camera distance is not known: type the part's height under Part's top above the token, and if the log says the picture has no lens data, the Camera distance too.
The live link doesn't update It needs a file chosen from disk (not dropped in), and it watches the file and its include/use libraries. Save in OpenSCAD with F2.
Start over Delete the runtime/ folder.

Known limitations

  • Work in progress. Expect rough edges.
  • Organic shapes with many sharp rims or tunnels convert slowly and come out partly faceted (the black patches in the preview).
  • Staged, v2 fitter, Second pass, Extrude outline and Loft cross-sections are experimental. Staged was tested only on a handful of synthetic parts and one organic model, on a 2-core Linux machine; on dense organic meshes at strict tolerance, or on non-watertight dense meshes, it can be much slower than Classic (see the Staged section above).
  • The FreeCAD workbench and Fusion add-in, the one-click installer and the WebGL preview were tested only against stand-in mocks and headless Chromium, not yet in real FreeCAD or Fusion.
  • The profiles, queue, scheduling and parallel Second pass were tested on a 2-core Linux machine only. The GPU pack path was verified to give identical results on the CPU build of PyTorch, but not on a real Apple/Nvidia GPU, and its speed-up is unmeasured.
  • Hardpoints and SCAD → STEP were added in 0.3.0-wip and tested on this Linux machine only: four small hardpoint sample files, and OpenSCAD 2021.01 with one example model plus a .csg test. Many OpenSCAD features are covered but not every model has been tried; unsupported pieces fall back to flat facets from OpenSCAD's own mesh. The FreeCAD / Fusion OpenSCAD and Export hardpoint STL commands, and the right-click entries, were tested against stand-ins or fake home folders, not in real FreeCAD, Fusion, Nemo, Nautilus or Windows.
  • Image → STEP was added in 0.5.0-wip and tested on this Linux machine only, on pictures drawn by the test code and on photographs from a simulated camera: no printed token, no real phone photo, no real EXIF data from a phone. Its STEP files were read back with OpenCascade and shown in the app's own preview; they were not opened in FreeCAD, Fusion or any other CAD program. Lens distortion is not corrected. The FreeCAD and Fusion plug-ins have no Image → STEP command.
  • Every colour change (Image → STEP, 0.5.2-wip) is experimental and was tried only on pictures drawn by the test code: no real icon or logo file, no real photograph. Drawn outlines between areas, the same colour on both sides of a thin line, very faint edges, and small or blurred pictures are known limits (notes).
  • The Diagnostic panel (0.5.2-wip) was checked in headless Chromium on Linux: screenshots of the window read back; a photograph of a screen was only simulated. It carries the settings of STL → STEP conversions only, and no ErrCode error codes.
  • The result is a solid of surfaces, not an editable feature history (no sketches / extrudes). See HOW_IT_WORKS.md.
  • Windows and macOS launchers were not run on real Windows/macOS by the author yet; Linux is the tested platform.

Where the pieces came from

This app was built up from five earlier builds, all by the same author with AI assistance (Claude, from Anthropic): the mesh converter at its core, the stand-alone outline-tracing tool (its Extrude and Loft modes live on as Extrude outline and Loft cross-sections), the hardpoint STL work (the Hardpoints tab, the plug-in Export hardpoint STL commands and HARDPOINT_STL.md), SCAD2STEP (the SCAD → STEP tab; app/scad2step_core.py is a copy of its engine) and ImageToSketch (the Image → STEP tab; app/imagetosketch is a copy of its tracing library, refreshed with tools/sync_imagetosketch.py).

Licence

Copyright Matthew Armstrong. PolyForm Noncommercial License 1.0.0 — source-available, not open source (not OSI-approved); GitHub shows the licence as "Other".

  • You may use, modify and share it for non-commercial purposes. Anyone you share it with must get the licence and the Required Notice.
  • Commercial use is not allowed without separate written permission from the author. That includes companies such as Bambu Lab — no permission is granted to them. Permission for other companies (for example Prusa Research) can be requested by opening a GitHub issue; it is at the author's discretion.
  • No warranty, no liability. "Non-commercial" has fuzzy edges; if unsure, ask.
  • Contributions are accepted under the same licence (CONTRIBUTING.md).
  • Third-party libraries keep their own licences: THIRD_PARTY.md.

This is a plain-language summary and not legal advice; the licence text in LICENSE.md is what counts.

More: HOW_IT_WORKS.md · CHANGELOG.md · SECURITY.md

About

Resources

Contributing

Security policy

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages