Status — what works, what doesn't
This page describes the current state of the project: implemented features and known limitations. Planned-but-not-yet-implemented work lives in GitHub issues, linked below, instead of an in-page roadmap.
Last updated: 2026-07-23 · engine version: OrcaSlicer v2.4.2 (self-built, live in production) · app version: v0.8.9
✅ Works
User interface
| Feature | Notes |
|---|---|
| Drag & drop STL | ASCII and binary STL; multiple files at once — sequential queue, each G-code downloadable separately |
| 3MF import | Engine-side read (orc_read_3mf, OrcaSlicer's native reader — applies per-object/instance transforms correctly); no JS fallback — an engine failure surfaces as an import error |
| OBJ import | OBJ → STL conversion via OrcaSlicer's native parser (objparser.cpp + OBJ.cpp) compiled into WASM — no extra dependencies; supports triangles, quads, multi-object |
| STEP import | STEP → STL conversion via OCCT 7.8.1 compiled directly into slicer.wasm (Model::read_from_step); no separate download. IGES unsupported (OrcaSlicer's STEP reader doesn't read IGES) |
| 3D model preview (Three.js) | Model on a virtual print bed at real mm scale, OrbitControls |
| Bed grid — dynamic size | Bed size read from the printer preset or machine profile |
Bed shape (bed_shape) |
Rectangular or circular (e.g. Bambu Lab P1S); visualised in both the 3D preview and G-code viewer |
| Fuzzy skin (surface roughness) | Modes: none / external (outer walls only) / all; thickness 0.05–2 mm, point spacing 0.1–5 mm; libnoise compiled for WASM (Perlin/Billow/RidgedMulti/Voronoi) — since PR #32 |
| Multi-file — sequential queue | Drag & drop multiple files → each sliced separately, own G-code to download |
| Multi-file — one plate | "One plate (N)" button — all STLs auto-arranged via arrange_objects() (libnest2d), one G-code |
| Model / Settings / Slice tabs | Smooth navigation, tabs locked until a file is loaded |
| Settings panel | Printer, filament, and quality selection |
| G-code preview (layer by layer) | Layer slider, colouring by move type (perimeter/infill/support/travel), thick 3D lines, layer cursor — since PR #16 |
| G-code preview — both comment dialects | Layers from ;LAYER_CHANGE / ; CHANGE_LAYER markers, move types from ;TYPE: and ; FEATURE: (Bambu dialect — type colours previously didn't work for BBL printers), G2/G3 arc tessellation, correct vase/spiral mode rendering |
| G-code statistics | Print time, layers, filament (mm/g) on the file card — parsed from the G-code header and footer (both time-comment dialects) |
| Side-by-side model + G-code view | Synchronised layout after slicing |
| G-code download | "Download" button with the correct filename; "Download All (.zip)" bundles every result into one archive |
| .3mf export | ".3mf" button on a sliced card — the engine writes the mesh + embedded OrcaSlicer settings (orc_write_3mf); no bed/G-code/thumbnail data (see below) |
| Slice cancellation | "Cancel" button — restarts the worker (the synchronous WASM slice loop can't be interrupted any other way); pending OBJ/STEP conversions are retried automatically |
| Stale-result detection | Changing settings after slicing marks a result "Sliced with previous settings"; the button becomes "Re-slice" |
| Settings persistence | Printer, filament, quality preset, and overrides kept in localStorage, restored on the next visit |
| Manual overrides outrank profiles | A hand-edited field is flagged (amber outline + per-field "reset") and survives switching printer/filament/quality preset and loading another 3MF or profile — preset < imported file < your edits, see Settings precedence |
| Queue as a state machine | useSliceQueue (reducer) — correlates worker responses by requestId; an engine error fails every pending item instead of leaving spinners running forever |
| Engine status badge | "Loading engine…" / "Engine error" in the header |
| Engine version in header | v{app} · {date} · engine v{orca} under the logo — same text at every screen width |
| Footer — source link (AGPL) | Visible "Source (AGPL-3.0)" link → GitHub repo |
WASM engine
| Feature | Notes |
|---|---|
| STL → G-code slicing | Runs in a Web Worker, doesn't block the UI |
| Self-built OrcaSlicer v2.4.2 | Built via orca-wasm/ + Emscripten; artifacts in the wasm-v2.4.2 release |
| ST / MT engine variants | Single-threaded (ST, slicer.js/slicer.wasm) served everywhere; multithreaded (MT, slicer-mt.js/slicer-mt.wasm, real oneTBB) served only where the page is cross-origin isolated (currently the Cloudflare mirror) — see ADR-011 and the ST vs MT benchmark |
orc_obj_to_stl |
WASM export: OBJ → binary STL conversion without needing orc_init; result returned as an ArrayBuffer to the worker |
orc_slice_multi |
Multiple STLs → one G-code: auto-arrange via arrange_objects() (libnest2d + NLopt); output identical in shape to orc_slice |
| Multi-material + real multi-nozzle printers | Filament slots are defined in the Settings panel and assigned per object on the Slice tab, reaching the engine as orc_slice_multi's extruder_ids (OrcaSlicer's per-object "extruder" key, normalised to *_filament_id by normalize_fdm()). filament_map decides whether slots share one nozzle (AMS-style) or drive genuine T0/T1 tool changes on a real dual-nozzle machine such as a Bambu Lab H2D — see withFilamentSlots() in src/lib/profiles.ts. Unblocked in #160: the crash that had gated real multi-nozzle profiles off was the bridge joining every multi-value option with , regardless of its type, not the engine |
orc_write_3mf |
WASM export: writes the mesh + embedded config as .3mf via Slic3r::store_bbs_3mf() — no plate/G-code/thumbnail data (no PartPlateList in the headless bridge); verified by the smoke test (ZIP unpacks, 3D/3dmodel.model + Metadata/*.config present) |
orc_read_3mf |
WASM import: reads .3mf via Slic3r::load_bbs_3mf() — merged binary STL (per-instance/volume transforms applied by ModelObject::mesh()) + config JSON (same keys as OrcaSlicer's native .config, parsed by the existing parseOrcaProfileJson()); verified by the smoke test (round-trip: triangle count + config keys) |
No slicer.data |
The headless flat-config slicer never reads orca/resources → data file reduced 200 MB → 0 |
| Singleton worker | One worker for the whole session |
| Error handling | Error codes -1…-9, readable messages |
| WASM load while slicing is requested | SLICE requests are queued while WASM is still loading |
| Streaming WASM compile | WebAssembly.compileStreaming compiles slicer.wasm in parallel with the download (and with fetching slicer.js); falls back to buffered compile on a wrong Content-Type |
| G-code JPEG thumbnails | Real JPEG (RGBA→RGB, standard libjpeg) — since PR #13 |
| Slice timer | Button shows Slicing… (12s) — honest elapsed time, no fake stage names — since PR #15 |
| PWA / offline mode | Service Worker (Workbox) pre-caches all assets + WASM on first visit; installable as a native app |
Session-scoped engine (orc_session_create/orc_session_destroy) |
Engine state (config, bed, last error) moved from global C++ statics to a session handle — see ADR-008 |
| WASM crash recovery | onAbort reliably reports WASM_ERROR to the main thread; the dead worker is dropped and replaced with a fresh one on the next attempt |
| Engine smoke test in CI | orca-wasm/scripts/smoke-test.mjs — real orc_init/orc_slice(_multi) after every build, before publishing a release — see ADR-009 |
| E2E UI smoke test in CI | Playwright (e2e/slice.spec.ts) — uploads the real Voron Design Cube v7 model → slices → gets G-code through the real WASM engine, on every open PR — see ADR-010 |
Engine clean layer (patches vs. overrides)
OrcaSlicer's C++ source is patched in place (orca-wasm/patches/apply.py) for WASM-compatibility fixes (narrowing, ABI, platform guards), while whole files whose implementation depends on a library unavailable in WASM (OCCT-dependent SVG/text export, OpenVDB, OpenCV, Draco) are replaced wholesale by no-op overrides in orca-wasm/overrides/. These are two distinct mechanisms — see ADR-006 for the full three-layer strategy (header shims + C++ overrides + in-place patches) and architecture.md for the current table of stubs.
| Aspect | Details |
|---|---|
| Disabled WASM dependencies | OpenVDB, OpenCV, Draco replaced by overrides; OCCT and libnoise are compiled in |
| Upgrading to a new version | Just ORCA_VERSION in the workflow, plus any stub adjustments |
| AGPL-3.0 compliance | LICENSE, NOTICE.md, source link in the UI — §13 network copyleft satisfied |
OrcaSlicer profiles
| Feature | Notes |
|---|---|
| Built-in quality presets | Draft (0.3 mm) / Standard (0.2 mm) / Fine (0.1 mm) |
| Built-in filaments | PLA, PETG, ABS, TPU |
| Built-in printers | Generic 0.4/0.6, Bambu Lab P1S/X1C, Prusa MK4, Ender 3, Voron 2.4 |
| JSON profile import from OrcaSlicer | .json file from a desktop install; ORCA_FIELD_MAP mapping + passthrough of all other fields |
| Machine profile import | gcode_flavor, retract_length/speed, lift_z, machine_start/end_gcode, machine_max_speed_*, printable_height — all reach the engine |
| Profile extraction from 3MF | Via orc_read_3mf (falls back to a JS read of Metadata/*.json/.config from the archive if the engine fails) |
Deployment
| Aspect | Status |
|---|---|
| GitHub Actions CI (deploy.yml) | ✅ builds and deploys on every push to master |
| PR snapshot on GitHub Pages | ✅ pr-preview.yml publishes previews/pr-<number>/, comments the URL, removes the snapshot when the PR closes; same-repository branches only |
| Same-origin WASM serving | ✅ no CORS — files live in gh-pages/app/wasm/ |
WASM release wasm-v2.4.2 |
✅ slicer.js + slicer.wasm (~29 MB total, includes OCCT for STEP) |
| Deploy resilience | ✅ falls back to the previous gh-pages state if the release is missing |
CI build on PRs touching orca-wasm/** |
✅ every PR touching the engine runs a ~12 min build |
E2E smoke test on PRs (e2e-smoke.yml) |
✅ every open PR — downloads the published WASM engine and slices the Voron Design Cube v7 through the real UI (Playwright) |
| App version auto-bump | ✅ every deploy bumps the patch version in package.json/status.md and tags vX.Y.Z automatically (see the /release skill for a deliberate minor/major bump) |
Engine auto-rebuild on orca-wasm/ changes |
✅ a push to master touching orca-wasm/** triggers build-wasm.yml; deploy.yml waits for its result (workflow_run) instead of racing an older engine |
| Landing page | ✅ hiosdra.github.io/OrcaWeb/ |
| MkDocs documentation | ✅ hiosdra.github.io/OrcaWeb/docs/ |
| Dependabot + dependency grouping | ✅ weekly schedule |
⚠️ Partially working / known limitations
| Area | Details |
|---|---|
| Printer temperature ranges | Not independently verified — printer+filament preset combinations may be inconsistent for exotic pairings |
| Large STL files (>50 MB) | May cause stutter during preview |
Not yet implemented
Tracked in GitHub issues rather than listed here, so this page doesn't drift into a stale roadmap:
- #138 — Variable layer height
- #139 — Support enforcement / blocking
- #108 — Full "sliced project" 3MF export (per-plate G-code, plate thumbnails);
orc_write_3mf/orc_read_3mfintentionally cover mesh + embedded config only, since the headless bridge has noPartPlateListto source that from — this is a documented non-goal for the current bridge shape, not a plain backlog item
Architecture note
There is no cli/ directory — a Node CLI wrapper existed early on and was deliberately removed in its entirety (chore: remove CLI — frontend → bridge → engine only). It is not a project goal; see agents.md. For the current component breakdown, see architecture.md.