Support Fins — OrcaSlicer plugin lane
Companion to printfins.com, targeting OrcaSlicer's Python
plugin system (embedded CPython; single-.py PEP 723 plugins or .whl).
Slice-time fins (src/support_fins_orca.py) — the write path exists
The table below is right that Orca's model API is read-only. But the
slicing pipeline is writable: at Step.posSlice a plugin can replace each
layer's slice polygons (LayerRegion.slices.set/append, then
Layer.make_slices()), and Orca carries the edit through perimeters, infill and
G-code. Orca's own samples do exactly this (sandboxes/orca_inset_plugin_any.py,
orca_twistify_plugin_any.py). This isn't the support-toolpath route either:
at posSlice there are no toolpaths yet, only the per-layer polygons a finned STL
would have produced.
So this plugin:
- reads the part as Orca slices it (
PrintObject.model_object()volumes throughPrintObject.trafo()), - runs the website's engine, unmodified —
web/*.jsbundled with esbuild and executed in an embedded V8 (mini-racer). The bundle and its bridge are shared with the other plugins (plugins/shared/), - cross-sections the fin shells at every layer's
slice_z(the shared mesh slicer,plugins/shared/py/supportfins_slice.py) and merges them into the layer (Orca's ownunion_exfuses the tines into the part).
No export, no re-import, no "fins land on the plate" API needed. Rotate the part, re-slice, and the fins follow. Parts with Orca's Enable support on are skipped, so the per-object support toggle picks fins vs Orca supports.
python3 plugins/orca/build.py # -> build/support_fins_orca.py (one file, ~110 KB)
deno test --allow-read tests/ plugins/shared/tests/
python3 -m pytest -q plugins/orca/tests/ plugins/shared/py/tests/ # needs numpy, trimesh, scipy, shapely, rtree, networkx, mini-racer
src/support_fins_orca.py holds only Orca glue. The build inlines the shared Python
modules (plugins/shared/py/: V8 host, mesh slicer) at their # __SUPPORTFINS_*__
marker lines, so the plugin still ships as one file.
Install and turn on (OrcaSlicer 2.5 nightly):
- Drop
build/support_fins_orca.pyinto<data_dir>/orca_plugins/SupportFins/(or Plugins ▸ Install plugin). Open Plugins from the main menu and tick Support Fins. Orca's bundleduvinstallsnumpyandmini-racerfrom the PEP 723 header on that first activation. - Switch the process settings to Advanced, open Others ▸ Slicing Pipeline Plugin ▸ Add plugin and pick Support Fins. Activating the plugin alone does nothing; the process preset has to reference it.
- Slice. The first slice of each Orca session shows a few Plugin permission
request prompts (reading Python's own library files, and
socket.__new__, which is the local self-pipe of the asyncio loop mini-racer creates, not network access). Answer Yes.
What the tests pin (offline)
plugins/shared/tests/entry.test.js— the plugin entry places the same fins as the website on the same posed part, anywhere on the plate; watertight; walls clear the part; tines bite.tests/test_plugin.py— againsttests/fake_orca.py(same shapes/units as the real bindings): every layer's islands match an independent trimesh+shapely slice of part + fins, including off-centre placement and XY/Z shrinkage compensation; supports-on parts, other steps and a disabled config change nothing; errors come back asRecoverableError, never an exception mid-slice.plugins/shared/ENGINE-SENSITIVITY.md— an upstream engine finding (tine placement moves under 1e-13 mm of noise) and how the plugin neutralises it.
Checked in a real Orca build (2.5.0-dev nightly, Windows, 2026-09-23)
Part: lbracket tilted 35°, Elegoo Centauri Carbon 2 profile, 0.2 mm layers.
Compared the plugin's G-code with the website's finned STL sliced the normal way.
- Plugin log:
4 fin(s), 16 tine(s) on 139 layer(s), the same as the engine run offline. PrintObject.bounding_box()is the tight XY footprint, centred on the origin. The frame calibration measured a scale of 1.0000000 of nominal.- From layer 4 up, every layer's wall toolpaths are identical to the finned STL. Total extrusion is within 0.01 %.
- Layers 1–3 (the bed pad) overlap 87–97 %. Two Orca-side effects cause it, and
the plugin now handles the first:
- Orca puts a layer whose slice plane touches a top face inside the solid. The plugin now does the same (it was the other way, which dropped one pad layer).
- Orca applies elephant-foot compensation during slicing, before the hook runs. The plugin now shrinks first-layer fins to match, leaving thin walls intact. It's approximate, since Orca's own routine is flow-aware.
- Auto brim is decided from the plain part, so Orca adds a brim around the pad that it wouldn't add for a finned STL. Set Brim type to No brim if you don't want it.
- Parts with Enable support on are skipped. The log reads
skipped (Orca supports are on for this part).
The read/write split that shapes everything here
OrcaSlicer and PrusaSlicer expose opposite halves of what this tool needs, and neither exposes both:
| read the loaded mesh? | add geometry to the plate? | |
|---|---|---|
| PrusaSlicer 3.0 (Lua) | ❌ no triangle access | ✅ generative (make_cube…) — our Prusa plugin drops a fin you hand-place |
| OrcaSlicer (Python) | ✅ orca.host returns vertices()/triangles() |
❌ host is read-only — "nothing here mutates the model" |
So on Orca we can do the smart half Prusa can't — read the user's actual model and
auto-fit fins to its overhangs — but we cannot place the result on the live
plate. There is no add-object / import-mesh / make-primitive call anywhere in Orca's
plugin surface (verified across orca.host, orca.script, orca.slicing). The
honest ceiling: compute the fins in-Orca, write a finned .3mf, user does
File ▸ Import. That still beats the Prusa plugin (real auto-fit, not hand-placed),
it just isn't the "fins land on your plate automatically" the feature request imagined.
The one theoretical write-path is the slicing pipeline (posSupportMaterial, "mutate
the live slicing graph") — but that emits support as toolpaths, not our contoured
breakaway mesh fin. Different, deeper, lower-fidelity. Not the plan.
Roadmap
support_fins_probe.py— the spike (this commit). Reads the loaded model viaorca.host, runs the 45° overhang classification in pure numpy (no trimesh), reports faces/bbox/overhang-area per volume, and separately reports whethertrimeshimports. Answers the two unknowns before we port anything: does the read work on a real dragged-in model, and what deps can the port rely on?- Port the analysis + fit.
spike_overhangs.py→ region/contact-line, thenspike_orient.py(re-orient to minimise overhang) andspike_fins.py(contour the breakaway fins). Reimplement trimesh's few calls (submesh, surface sample) in numpy if step 1 says trimesh is absent. - Export. Reuse
web/threemf.js's structure (part + fins as separate placed objects, mm units, production UUIDs) to write a finned.3mfto disk. Filesystem writes are permitted (permission-gated audit hook). - Funnel option. A lightweight "flag my overhangs → open in printfins.com" panel using only the read-only mesh API — legit in-slicer discovery within the rules.
Install (side-load)
OrcaSlicer → Plugins dialog → Browse ▸ Install local plugin → pick
support_fins_probe.py. Or drop it in <data_dir>/orca_plugins/. Load a model, then
Plugins ▸ Run the probe; the report comes back in the result dialog (and stdout).
Status: untested against a live OrcaSlicer build — written to the documented API. Run the probe first; if it loads and reports sane overhang numbers, phase 2 is greenlit.