Web-based SLA slicing application powered by PrusaSlicer CLI (headless). Features a React frontend with 3D preview, configurable slicing parameters, and support mesh visualization.
- SLA Slicing: Slice STL models into layer images using PrusaSlicer engine
- 3D Preview: Interactive Three.js viewer with orbit controls (Z-up coordinate system)
- Support Generation: Auto-generate supports with configurable parameters
- Support Mesh Export: Download generated supports as STL for external use
- Hollow Interior Generation: Generate hollow interior mesh for visualization (NEW)
- Configurable Parameters: Layer height, exposure times, support settings, pad options, hollowing
- Layer Navigation: Browse through sliced layers with slider control
- macOS (tested on macOS 15.x) or Windows (see Windows setup for TBB)
- Python 3.9+
- Node.js 18+
- PrusaSlicer Fork (with
--export-support-stlfeature)
Recommended (easiest): Use Python 3.11 or 3.12 and follow Quick Start (Windows) (submodule init → build PrusaSlicer → create .venv312 → scripts\run_agent.bat). manifold3d has prebuilt wheels for 3.11/3.12, so no TBB or compilation is needed.
py -3.12 -m venv .venv312
scripts\run_agent.batYou must build PrusaSlicer first (use scripts\build_prusaslicer_fork_windows.bat on Windows). The script prefers .venv312 if it exists and will install all dependencies from wheels.
Alternative (Python 3.14 or other): If you use the default .venv (e.g. Python 3.14), manifold3d builds from source and requires TBB. Use vcpkg:
vcpkg install tbb:x64-windows- Set
VCPKG_ROOTand add%VCPKG_ROOT%\installed\x64-windows\binto your PATH. - Run
scripts\run_agent.bat
See Troubleshooting below if you see "tbb was not found" or "DLL load failed".
After clone: init submodules so the PrusaSlicer fork source is available:
git submodule update --init --recursiveAfter cloning (and initializing submodules), run in order:
:: 1. Init submodules (get PrusaSlicer fork source)
git submodule update --init --recursive
:: 2. Build PrusaSlicer CLI (requires CMake, Visual Studio; 16GB RAM use default, 32GB+ use full)
:: Builds PrusaSlicer_app_console + OCCTWrapper (STEP plugin). Package is OFF by default.
scripts\build_prusaslicer_fork_windows.bat
:: Optional: build then package consumer staging in one step
:: scripts\build_prusaslicer_fork_windows.bat low package
:: or: set PACKAGE_SLICER_ENGINE=1 && scripts\build_prusaslicer_fork_windows.bat low
:: 3. Python 3.12 venv (recommended so manifold3d installs from wheel)
py -3.12 -m venv .venv312
:: 4. Start backend (installs deps and runs agent)
scripts\run_agent.batBackend runs at https://127.0.0.1:5179. Then start the frontend (see step 3 below).
Due to de-identification, the new build output on Windows is
third_party\prusaslicer_build\src\Release\slicer-engine.exeplusslicer_core.dllandOCCTWrapper.dll(the console shim loads the neutral core DLL; STEP/STP uses the OCCT plugin). Point the agent at it withset SLICER_ENGINE_BIN=%CD%\third_party\prusaslicer_build\src\Release\slicer-engine.exe. See De-identification notes.
Prerequisites for Windows: Python 3.12 (or 3.11), Node.js 18+, CMake, Visual Studio 2017+ (2019/2022/2026). Low RAM (16GB): use default; 32GB+: run scripts\build_prusaslicer_fork_windows.bat full. Args: [full|low|qa] [clean|qa|package] … — pass package or set PACKAGE_SLICER_ENGINE=1 to run D13 staging after build (default off).
The project uses a custom PrusaSlicer fork with support mesh STL export capability.
# Build the fork (includes --export-support-stl feature)
./scripts/build_prusaslicer_fork_macos.shThis builds the binary at third_party/prusaslicer_build/src/prusa-slicer.
Due to de-identification, the new (current) output is
third_party/prusaslicer_build/src/slicer-engineon macOS (the CMakeOUTPUT_NAMEis nowslicer-engine; branded symlinks such asprusa-slicerare removed on macOS). On Linux the binary is still namedprusa-slicer. See De-identification notes.
# Set the path to the forked binary
export PRUSA_SLICER_BIN=$(pwd)/third_party/prusaslicer_build/src/prusa-slicer
# Start the agent
./scripts/run_agent.shDue to de-identification, the new recommended variable is
SLICER_ENGINE_BINpointing atslicer-engine(macOS example:export SLICER_ENGINE_BIN=$(pwd)/third_party/prusaslicer_build/src/slicer-engine).PRUSA_SLICER_BINabove is kept only as a local legacy fallback and still works during the transition — do not rely on it as the shipped default.
Backend runs at https://127.0.0.1:5179
cd web
npm install
npm run devFrontend runs at http://localhost:5174
| Interface | URL | Description |
|---|---|---|
| React UI | http://localhost:5174 | Main frontend - slicing, preview, supports, hollow |
| Boolean Test | http://localhost:5179/test/boolean | Experimental boolean operations test page |
| API Docs | http://localhost:5179/docs | Swagger UI for API exploration |
De-identification only applies to the consumer artifact (the formal, shipped package): it renames the surfaces a user or support agent can see so no Prusa/slic3r brand fingerprint leaks. Slicing behavior and parameters are unchanged.
De-identification is landed on the dev branches of both web_slicer_core and prusaslicer_fork. Pull both to latest before continuing development.
- Local build & run are unchanged — no extra manual steps for day-to-day work:
- macOS:
./scripts/build_prusaslicer_fork_macos.sh(build) +./scripts/run_agent.sh(run) - Windows:
scripts\build_prusaslicer_fork_windows.bat(build) +scripts\run_agent.bat(run) - Windows packaging is opt-in (same idea as macOS): pass
packageorPACKAGE_SLICER_ENGINE=1after a successful build when you needslicer-engine\staging.
- macOS:
- Direct CLI — same native PrusaSlicer flag grammar; only the executable name is neutral (
slicer-engine/slicer-engine.exe). Example:--load config.ini --export-gcode -o out.gcode model.stl(or--export-slafor SLA). PreferSLICER_ENGINE_BINover legacyPRUSA_SLICER_BIN. - Scenarios & copy-paste commands —
docs/slicer-engine-deidentification/build-test-runbook.md(safe to feed to an AI assistant for guidance). - Full R&D record —
openspec/changes/backend-slicer-engine-deidentification/(design.md,naming-manifest.md,blacklist.md,acceptance-procedure.md, evidence, etc.). - Pre-merge retest (both platforms): clean build → dental workflow smoke (one-click process + long supports + slice) → CLI slice smoke.
Build / test runbook:
docs/slicer-engine-deidentification/build-test-runbook.mdFull spec:
openspec/changes/backend-slicer-engine-deidentification/
| Context | Name to use |
|---|---|
| Development / source / fork / submodule | Keep PrusaSlicer (no need to rename) |
Build tree third_party/prusaslicer_build/ |
Keep as-is (folder name not required to change) |
| Consumer package / install path | Neutral names slicer-engine/, slicer-engine(.exe), slicer_core.dll |
slicer ≠ slic3r: the neutral slicer-* names are not blacklist hits; the blacklisted token is slic3r (with the digit 3).
- For normal development, debugging, and running the CLI, just use PrusaSlicer as before — de-identification does not affect the dev workflow.
- Output filenames become neutral right after compilation (CMake
OUTPUT_NAME):- macOS:
third_party/prusaslicer_build/src/slicer-engine(OCCT linked statically into the binary on Apple) - Windows:
…\src\Release\slicer-engine.exe+slicer_core.dll+OCCTWrapper.dll(delay-loaded MODULE; the build script builds it explicitly afterPrusaSlicer_app_console) - The CMake target is still internally named
PrusaSlicer— that is expected, leave it.
- macOS:
- PE icon on Windows is embedded at link time from SoT
third_party/prusaslicer_fork/resources/icons/slicer-engine.ico(SLIC3R_APP_ICON→PrusaSlicer.rc.in). Changing the.icorequires a clean rebuild of the console shim. Do not rely on Explorer list-view icons (shell cache); packaging verifiesExtractAssociatedIconagainst the SoT (fail-closed). - Run a clean build when you touch any of these, so stale cache doesn't leave brand names behind (
build_...windows.bat clean, or deleteprusaslicer_buildfirst on mac):OUTPUT_NAME, visibility flags,BUNDLE_QA_CRASH_HARNESS, exports (.def), VERSIONINFO /version.inc,SLIC3R_APP_ICON/.ico. - The QA crash harness (the three intentional crashes) is compiled only when
flavor=qa; consumer builds default to OFF, and no runtime-triggerable crash path may be compiled into the formal package. - Do not touch slicing algorithms or do a wide C++ namespace rename for the sake of de-branding (
Slic3r::→slice::is L3 and out of scope for this round).
- Plain compilation does not strip or seal PDBs; the formal package requires a separate package step (opt-in on both platforms):
- macOS:
PACKAGE_SLICER_ENGINE=1 ./scripts/build_prusaslicer_fork_macos.sh→third_party/slicer-engine/bin/ - Windows:
scripts\build_prusaslicer_fork_windows.bat low packageorset PACKAGE_SLICER_ENGINE=1then build orpowershell -File scripts\package_slicer_engine_windows.ps1→slicer-engine\bin\ - Packaging deletes the previous staging root then recopies (no leftover files from older packages).
- macOS:
- The consumer package must not contain:
.pdb(Win),.dSYM/*.unstripped(mac), the QA harness, or brand leftovers likeprusa-slicer*/PrusaSlicer.dll. - Keep symbols internally: archive the mac
.dSYMand the Win.pdbin a private symbol store (their UUID / GUID must match that build) so function names can be restored for debugging later. - After stripping on macOS you must re-
codesign; Windows uses Authenticode. Do not strip / rename / patch after signing.
- The agent binary path is driven by
SLICER_ENGINE_BIN;PRUSA_SLICER_BINis a local legacy fallback only — do not rely on it as the shipped default. - When invoking the CLI directly, the formal package calls
slicer-engine(.exe); the arguments are identical to PrusaSlicer (--export-sla,--export-support-stl,--help, etc.). - Running
slicer-engine.exeon Windows requiresslicer_core.dll,OCCTWrapper.dll, and GMP/MPFR (libgmp-10.dll/libmpfr-4.dll) in the same directory; missing files cause a LoadLibrary failure (error 126).
# --help must not print PrusaSlicer / slic3r (the neutral name slicer-engine is fine)
"$SLICER_ENGINE_BIN" --help
# The formal package dir has no prusa / slic3r filenames; no .pdb on Win, no .dSYM on mac- Select STL File: Click file input to select a model - 3D preview appears immediately
- Configure Settings (optional): Expand "Slicing Config" to adjust parameters
- Layer height: 0.025mm, 0.05mm, or 0.1mm
- Exposure time: 1-30 seconds
- Initial exposure: 5-60 seconds
- Enable/disable supports with detailed settings
- Enable/disable pad
- Slice: Click "Slice" button to start processing
- View Results:
- 3D Preview: Model (blue) with support mesh overlay (red) if supports enabled
- Layer View: Navigate through individual slice images
- Download Support STL: When supports are generated, download button appears
| Parameter | Description | Range | Default |
|---|---|---|---|
layer_height |
Height of each slice layer | 0.025, 0.05, 0.1 mm | 0.05 mm |
exposure_time |
UV exposure per layer | 1-30 s | 10 s |
initial_exposure_time |
First layers exposure | 5-60 s | 15 s |
supports_enable |
Generate support structures | on/off | off |
support_head_front_diameter |
Support tip diameter | 0.2-1.0 mm | 0.4 mm |
support_head_penetration |
Tip penetration depth | 0.1-0.5 mm | 0.2 mm |
support_pillar_diameter |
Support pillar width | 0.5-2.0 mm | 1.0 mm |
support_points_density_relative |
Support density | 50-200% | 100% |
pad_enable |
Generate base pad | on/off | off |
hollowing_enable |
Enable hollowing | on/off | off |
hollowing_min_thickness |
Wall thickness | 0.5-10 mm | 3.0 mm |
hollowing_quality |
Voxel quality (higher = finer) | 0.1-1.0 | 0.5 |
hollowing_closing_distance |
Smoothing distance | 0-10 mm | 2.0 mm |
curl http://127.0.0.1:5179/# Basic (default config)
curl -X POST http://127.0.0.1:5179/api/jobs \
-F "file=@model.stl"
# With custom config
curl -X POST http://127.0.0.1:5179/api/jobs \
-F "file=@model.stl" \
-F 'config={"layer_height":0.05,"supports_enable":true,"exposure_time":12}'Response:
{"job_id": "a1b2c3d4", "status": "pending"}curl http://127.0.0.1:5179/api/jobs/{job_id}Response:
{
"job_id": "a1b2c3d4",
"status": "completed",
"layer_count": 750,
"error": null,
"has_support_mesh": true
}curl http://127.0.0.1:5179/api/jobs/{job_id}/layers/50.png --output layer50.pngcurl http://127.0.0.1:5179/api/jobs/{job_id}/model.stl --output model.stlcurl http://127.0.0.1:5179/api/jobs/{job_id}/support.stl --output support.stlReturns combined mesh of supports and pad (if enabled). Only available when has_support_mesh: true in job status.
# 1. Create job with hollow config
curl -X POST http://127.0.0.1:5179/api/v2/slices \
-H "Content-Type: application/json" \
-d '{"config": {"hollowing_enable": true, "hollowing_min_thickness": 2.0}}'
# 2. Upload model
curl -X POST http://127.0.0.1:5179/api/v2/slices/{job_id}/upload \
-F "file=@model.stl"
# 3. Generate hollow interior
curl -X POST http://127.0.0.1:5179/api/v2/slices/{job_id}/generate-hollow
# 4. Poll status until completed
curl http://127.0.0.1:5179/api/v2/slices/{job_id}
# Response: {"data": {"status": "completed", "hasHollowMesh": true}}
# 5. Download hollow mesh
curl http://127.0.0.1:5179/api/jobs/{job_id}/hollow.stl --output hollow.stlcurl http://127.0.0.1:5179/api/jobs/{job_id}/hollow.stl --output hollow.stlReturns the hollow interior mesh. Only available when has_hollow_mesh: true in job status.
The backend supports multiple frontends through versioned API endpoints:
┌─────────────────────┐ ┌─────────────────────┐
│ DS-Online (Vue) │ │ web_slicer_core │
│ Dental Slicer UI │ │ (React) Basic UI │
│ :5173 │ │ :5174 │
└──────────┬──────────┘ └──────────┬──────────┘
│ │
│ /api/v2/slices │ /api/jobs
│ │
▼ ▼
┌─────────────────────────────────────────────────┐
│ FastAPI Backend (:5179) │
│ ┌─────────────────┐ ┌─────────────────────┐ │
│ │ /api/v2/slices │ │ /api/jobs (v1) │ │
│ │ DS-Online API │ │ Original API │ │
│ └────────┬────────┘ └──────────┬──────────┘ │
│ └────────────┬──────────┘ │
│ ▼ │
│ ┌─────────────────────┐ │
│ │ Job Manager │ │
│ │ (shared service) │ │
│ └──────────┬──────────┘ │
│ ▼ │
│ ┌─────────────────────┐ │
│ │ PrusaSlicer CLI │ │
│ │ (Fork + support │ │
│ │ mesh export) │ │
│ └─────────────────────┘ │
└─────────────────────────────────────────────────┘
│
▼
┌─────────────────┐
│ Job Storage │
│ agent/jobs/ │
└─────────────────┘
┌─────────────────────────────────────────────────────────────┐
│ UI Layer │
│ - DS-Online (Vue + Three.js + PrimeVue) │
│ - web_slicer_core (React + Three.js) │
├─────────────────────────────────────────────────────────────┤
│ API Layer (FastAPI) │
│ - /api/jobs/* (v1 - original) │
│ - /api/v2/slices/* (v2 - DS-Online compatible) │
├─────────────────────────────────────────────────────────────┤
│ Service Layer │
│ - Job Manager (create, status, polling) │
│ - Config Manager (INI generation, validation) │
├─────────────────────────────────────────────────────────────┤
│ Engine Layer │
│ - PrusaSlicer CLI Adapter │
│ - Support mesh export (--export-support-stl) │
│ - Hollow interior export (--export-hollow-stl) │
└─────────────────────────────────────────────────────────────┘
Due to de-identification, the "PrusaSlicer CLI" box in these diagrams ships as the neutral
slicer-engineengine (Windows:slicer-engine.exe→slicer_core.dll). The adapter, APIs, and slicing behavior are unchanged; only the consumer-facing executable/DLL names are neutral. See De-identification notes.
web_slicer_core/
├── agent/
│ ├── main.py # FastAPI application & endpoints
│ ├── config.py # Configuration constants
│ ├── models.py # Pydantic models (SLAConfig, JobStatus)
│ ├── jobs.py # Job management & slicing logic
│ └── jobs/ # Job data storage (gitignored)
│ └── {job_id}/
│ ├── input/model.stl
│ ├── output/
│ │ ├── model.sl1
│ │ └── model_support.stl # If supports enabled
│ ├── layers/{0..N}.png
│ ├── config.ini
│ └── status.json
├── web/
│ ├── src/
│ │ ├── App.tsx # Main application component
│ │ ├── App.css # Styles
│ │ ├── STLViewer.tsx # Three.js 3D viewer component
│ │ └── main.tsx # Entry point
│ ├── package.json
│ └── vite.config.ts
├── third_party/
│ ├── prusaslicer_fork/ # PrusaSlicer fork (submodule)
│ └── prusaslicer_build/ # Build output (gitignored)
├── scripts/
│ ├── run_agent.sh
│ └── build_prusaslicer_fork_macos.sh
├── requirements.txt
└── README.md
Due to de-identification, the new tree also includes:
third_party/slicer-engine/— optional packaged consumer layout (bin/,symbols/,legal/, manifest), produced by the packaging scripts; gitignored.prusaslicer_build/still builds withOUTPUT_NAME=slicer-engine(slicer-engine/slicer-engine.exe+slicer_core.dll); the folder name itself is left as-is.- Additional scripts under
scripts/:build_prusaslicer_fork_windows.bat,package_slicer_engine_macos.sh,package_slicer_engine_windows.ps1,scan_slicer_engine_macos.sh,scan_slicer_engine_windows.ps1.
This project uses a custom fork of PrusaSlicer (github.com:MaxShih147/PrusaSlicer.git) with additional CLI options:
Due to de-identification, the new shipped binary is invoked as
slicer-engine(slicer-engine.exeon Windows), notprusa-slicer. Theprusa-slicercommands shown in the examples below still describe the exact same CLI options and arguments — only the executable name changed for consumer artifacts. On Linux the dev binary remainsprusa-slicer. See De-identification notes.
Exports the generated support and pad meshes as a combined STL file after SLA slicing.
prusa-slicer --export-sla --export-support-stl -o output.sl1 model.stl
# Creates: output.sl1 and model_support.stlThe exported STL includes:
- Support structures (if
supports_enable = true) - Pad/raft (if
pad_enable = true)
Implementation details:
- Added in
src/libslic3r/PrintConfig.cpp(CLI option definition) - Export logic in
src/CLI/ProcessActions.cpp - Uses
SLAPrintObject::support_mesh()andSLAPrintObject::pad_mesh()
Generates and exports the hollow interior mesh as STL. This is a standalone operation that doesn't require full slicing.
prusa-slicer --export-hollow-stl \
--hollowing-min-thickness 2 \
--hollowing-quality 0.5 \
--hollowing-closing-distance 1 \
-o interior.stl model.stl
# Creates: interior.stl (hollow interior mesh only)Parameters:
--hollowing-min-thickness: Wall thickness in mm (default: 2.0)--hollowing-quality: Voxel quality 0.1-1.0 (default: 0.5, higher = finer detail)--hollowing-closing-distance: Morphological closing distance in mm (default: 0.5)
Important notes:
- Wall thickness must be appropriate for model size (small models need thinner walls)
- The interior mesh has flipped normals for proper visualization
- Uses OpenVDB for voxelization and interior generation
Implementation details:
- CLI option defined in
src/libslic3r/PrintConfig.cpp - Handler in
src/CLI/ProcessActions.cpp - Uses
sla::generate_interior()fromlibslic3r/SLA/Hollowing.hpp - Normals flipped via
sla::swap_normals()for visualization
The DS-Online frontend (paramsStore.bedSize) and the PrusaSlicer backend use separate, unconnected parameter sets. When slicing via backend CLI, generate_config_ini() in agent/sla_operations.py writes only slicing parameters (layer_height, exposure, supports, hollowing) to the config INI — no printer/display parameters are included. PrusaSlicer therefore falls back to its hardcoded defaults.
This matters for any feature that needs to map between PNG pixel coordinates and real-world mm coordinates (e.g., island detection 3D overlay, cross-section alignment).
Source: third_party/prusaslicer_fork/src/libslic3r/PrintConfig.cpp (lines ~4272-4295)
| Parameter | Default Value | Description |
|---|---|---|
display_width |
120.0 mm | Physical display width |
display_height |
68.0 mm | Physical display height |
display_pixels_x |
2560 | Horizontal pixel count |
display_pixels_y |
1440 | Vertical pixel count |
display_orientation |
portrait | Display rotation |
These defaults closely match the Original Prusa SL1 printer profile.
Profiles are stored in third_party/prusaslicer_build/resources/profiles/:
| Printer | display_width | display_height | pixels_x | pixels_y | orientation |
|---|---|---|---|---|---|
| Prusa SL1 | 120.96 mm | 68.04 mm | 2560 | 1440 | portrait |
| Prusa SL1S SPEED | 128.00 mm | 81.00 mm | 2560 | 1620 | portrait |
| Anycubic Photon Mono | (see AnycubicSLA.ini) | ||||
| Anycubic Photon Mono X | (see AnycubicSLA.ini) | ||||
| Anycubic Photon Mono X 6K | (see AnycubicSLA.ini) |
Output PNGs are 1440 x 2560 pixels (width x height). With display_orientation = portrait, the pixel layout is rotated 90 degrees from the physical display:
PNG width (1440 px) → physical short axis → 68.0 mm (display_height)
PNG height (2560 px) → physical long axis → 120.0 mm (display_width)
Pixel-to-mm conversion:
world_x = (px / png_width) * display_height // 68.0 mm
world_y = (py / png_height) * display_width // 120.0 mm
Note: PrusaSlicer auto-centers the model on the bed and auto-drops it to Z=0. The model's position in the PNG is relative to the bed center.
Frontend config generate_config_ini() PrusaSlicer CLI
(backendSlicer.js) --> (sla_operations.py) --> (--load config.ini)
Writes EVERY SLAConfig Reads config.ini.
field, including: Its own defaults apply
- layer_height only when no --load is
- exposure_time passed at all:
- supports_enable - display_width (120.0)
- hollowing_* - display_height (68.0)
- display_width - display_pixels_x (2560)
- display_height - display_pixels_y (1440)
- display_pixels_x / _y
- display_orientation
display_pixels_x / display_pixels_y reaching the INI is what lets the agent
derive the preview downscale ratio from the same format the engine rasterises
at — see agent/preview_scale.py.
- Add printer/display config to
generate_config_ini()— Done: it dumps everySLAConfigfield, sodisplay_width,display_height,display_pixels_x,display_pixels_yanddisplay_orientationall reach the INI and PrusaSlicer uses the same bed as the frontend - Add printer profile selection to frontend — Let users choose a printer profile (SL1, SL1S, Anycubic, custom) or enter custom display dimensions
- Return display config from backend API — Include
display_width,display_height,display_pixels_x,display_pixels_yin slice job status response so the frontend knows the actual bed size used - Sync
paramsStore.bedSizewith PrusaSlicer display — Frontend'sparamsStore.bedSize(currently [195.84, 122.4] for LS Plus) should match the PrusaSlicer printer profile, or be overridden by it - Read actual PNG dimensions — Instead of assuming 1440x2560, read the IHDR header from the first layer PNG to get actual pixel dimensions (supports different printer profiles)
- Handle display_orientation — Account for portrait vs landscape orientation when mapping pixel coordinates to world coordinates
- Add layer_height to job status response — Backend currently returns
layerCountbut notlayer_height; needed for accurate Z coordinate mapping
From the repository root (the scripts run the agent with HTTPS on https://127.0.0.1:5179 and require TLS cert/key; see agent/tls/ or scripts/trust_dev_tls_*.sh / scripts/trust_dev_tls_windows.ps1).
macOS / Linux
pip install -r requirements.txt
./scripts/run_agent.shWindows (Command Prompt or PowerShell)
pip install -r requirements.txt
scripts\run_agent.batcd web
npm install
npm run dev # Vite dev server with HMRIf you need to modify the PrusaSlicer fork:
- Edit source in
third_party/prusaslicer_fork/ - Rebuild:
cd third_party/prusaslicer_build make -j8 - Test the binary:
./src/prusa-slicer --help | grep export-support
Due to de-identification, on macOS the new test binary is
./src/slicer-engine(e.g../src/slicer-engine --help | grep export-support); Linux still producesprusa-slicer.
Build the fork first: scripts\build_prusaslicer_fork_windows.bat. Ensure you ran git submodule update --init --recursive after clone. The binary will be at third_party\prusaslicer_build\src\Release\slicer-engine.exe (with slicer_core.dll and OCCTWrapper.dll beside it).
Due to de-identification, do not look for
prusa-slicer.exe. Useslicer-engine.exe+ runtime DLLs in the same folder.
The manifold3d package needs TBB to build. Follow Windows setup: install TBB via vcpkg, set VCPKG_ROOT or CMAKE_PREFIX_PATH, then run scripts\run_agent.bat again.
Ensure PRUSA_SLICER_BIN is set correctly:
export PRUSA_SLICER_BIN=$(pwd)/third_party/prusaslicer_build/src/prusa-slicer
$PRUSA_SLICER_BIN --versionDue to de-identification, the new preferred variable and path are:
# macOS export SLICER_ENGINE_BIN=$(pwd)/third_party/prusaslicer_build/src/slicer-engine "$SLICER_ENGINE_BIN" --help # Windows (cmd) set SLICER_ENGINE_BIN=%CD%\third_party\prusaslicer_build\src\Release\slicer-engine.exe "%SLICER_ENGINE_BIN%" --help
PRUSA_SLICER_BINis still accepted as a local legacy fallback only.
The backend includes CORS middleware for common localhost dev origins and https://dentalslice.onrender.com.
To add more origins without editing code, set:
export CORS_ALLOWED_ORIGINS="https://your-ui.example.com,https://another.example.com"- Ensure "Enable Supports" is checked in config panel
- Check backend logs for "Support mesh exported" message
- Verify
has_support_mesh: truein job status response
| Feature | CLI | Backend API | Frontend | Notes |
|---|---|---|---|---|
| SLA Slicing | ✅ --export-sla |
✅ /execute |
✅ | Full layer export |
| Support Generation | ✅ --export-support-stl |
✅ /generate-supports |
✅ | Includes pad mesh |
| Hollow Interior | ✅ --export-hollow-stl |
✅ /generate-hollow |
✅ | Interior mesh only |
| Layer Preview | ✅ | ✅ /layers/{idx}.png |
✅ | PNG extraction from SL1 |
| 3D Visualization | - | - | ✅ | Three.js with Z-up |
- Drain Holes: Add
--export-drill-stlfor drain hole generation- PrusaSlicer has
DrainHoleinHollowing.hpp - Needs position input (click-to-place in UI)
- PrusaSlicer has
- Combined Hollow + Supports: Single operation for hollowed model with internal supports
- Hollow Preview Before Apply: Show preview without generating full mesh
- Auto-Orient: Expose PrusaSlicer's auto-orient via CLI
- Support Editing: Manual support point placement/removal
- Infill Patterns: Support for partial hollowing with infill
- Multi-Model Support: Handle multiple models in single job
- WebAssembly Port: Run hollowing in browser (OpenVDB is complex)
- Streaming Layers: WebSocket for real-time layer streaming during slice
- Diff Slicing: Only re-slice changed regions
-
Wall Thickness vs Model Size
- Small models need thinner walls (0.5-1mm)
- Large models can use thicker walls (2-3mm)
- Error "interior mesh is empty" means wall is too thick for model
-
Hollow Mesh Positioning
- Frontend must apply same transform as original model
- Currently copies position/rotation/scale from selected model
- If model is transformed after hollow generation, mesh will be misaligned
-
Memory Usage
- Hollowing uses OpenVDB which can be memory-intensive
- High quality setting (1.0) on large models may use several GB RAM
-
No Incremental Updates
- Changing hollow parameters requires full regeneration
- No caching of intermediate voxel grids
-
Single Model Per Job
- v2 API currently only processes first uploaded model
- Multi-model support requires job structure changes
Decision: Export only the hollow interior mesh, not a combined hollowed model.
Rationale:
- Frontend already has the original mesh
- Smaller data transfer (interior only vs full hollowed model)
- Can toggle hollow preview on/off without re-fetching
- Allows different materials/transparency for interior visualization
- PrusaSlicer stores interior separately in
sla::Interior
Trade-off: Frontend must combine meshes; can't directly print the exported hollow mesh.
Decision: Flip normals in PrusaSlicer CLI before export (sla::swap_normals()).
Rationale:
- Interior mesh faces inward by default (for boolean subtraction)
- Visualization requires outward-facing normals
- Better to flip once at export than in every frontend
- Consistent with how support mesh is exported
Decision: Hollow generation is a separate endpoint, not part of /execute.
Rationale:
- Hollow preview doesn't need full slicing
- Faster feedback loop for parameter tuning
- Can hollow without committing to slice
- Matches
/generate-supportspattern - Future: could cache hollow result for final slice
┌─────────────┐
│ created │ (in-memory, _pending_jobs)
└──────┬──────┘
│ upload model
▼
┌─────────────┐
┌─────────│ pending │─────────┐
│ └─────────────┘ │
│ generate-supports generate-hollow
▼ ▼
┌───────────┐ ┌───────────┐
│ processing│ │ processing│
└─────┬─────┘ └─────┬─────┘
│ │
▼ ▼
┌───────────┐ ┌───────────┐
│ completed │ │ completed │
│ +supports │ │ +hollow │
└───────────┘ └───────────┘
│
│ execute (full slice)
▼
┌───────────┐
│ completed │
│ +layers │
└───────────┘
This section is a self-reminder for future product and business evolution. Not all items are meant to be pursued at once.
Idea: Expose the slicer as a headless, scalable service rather than a desktop tool.
Potential value:
- Remove slicer maintenance burden for customers
- Enable cloud / automation / AI pipelines
- Natural fit for batch processing and scale
Target users:
- Manufacturing platforms
- Dental labs
- Cloud manufacturing services
- AI-generated model pipelines
Indicators to revisit:
- Stable job-based API
- Clear cost metrics (per job / per GB / per minute)
- Demand for non-interactive slicing
Idea: Sell decision-making instead of slicing itself.
Examples:
- Support quality evaluation
- Failure risk estimation
- Auto parameter / support suggestions
- Comparative analysis between slicing strategies
Why this matters:
- Support = process know-how, not just geometry
- Enables AI-driven optimization
- Hard to copy, high long-term value
Indicators to revisit:
- Support data is structured and comparable
- Repeated slicing failures observed in users
- Need for "why did this fail?" answers
Idea: Provide the slicer as an embedded or white-label component for hardware vendors.
Potential value:
- Recurring licensing revenue
- Strong fit with device-centric workflows
- Avoids consumer software competition
Target customers:
- 3D printer manufacturers
- Specialized hardware startups
- Non-general-purpose printing systems
Indicators to revisit:
- Requests for custom workflow / UI
- Need for tight hardware-software integration
- Vendor reluctance to maintain slicer teams
Idea: Turn slicing outputs and parameters into auditable, traceable production records.
Examples:
- Layer-level archives
- Parameter history
- Reproducibility reports
- Compliance-ready logs
Why it's valuable:
- Required in medical / dental / industrial contexts
- Seen as a cost of doing business, not a feature
- High willingness to pay
Indicators to revisit:
- Regulated customers (medical, dental, ISO)
- Need for print reproducibility
- QA / audit requirements
- This project is not just a slicer; it is a platform around slicing
- Engine choice is a means, not the product
- Supports, layers, and parameters are data assets, not UI details
- Monetization should prioritize process value, not feature count
PrusaSlicer is licensed under AGPLv3. See the fork repository for details.
Due to de-identification, the new note is: de-branding renames consumer-facing artifacts only — it does NOT change AGPLv3 obligations. The AGPL license, copyright, modification notices, and Corresponding Source offer must still ship with the consumer package (see
legal/slicer-engine/andopenspec/changes/backend-slicer-engine-deidentification/).