bambuddy/slicer-api
maziggy 6deaa513af ● feat(slicer): server-side slicing via OrcaSlicer / Bambu Studio sidecar
Adds an optional slicer-api/ Compose stack and wires Bambuddy's File
  Manager, Archives, and MakerWorld pages to a new server-side Slice flow.
  Slicing runs as an in-memory background job (POST returns 202 + job_id,
  polled via GET /api/v1/slice-jobs/{id}) so a multi-minute slice no
  longer pins the modal; result lands as a new .gcode.3mf in the same
  folder (or new archive for archive sources) with the embedded
  thumbnail extracted.

  Backend
  - New services: slice_dispatch (in-memory dispatcher, 30min retention
    sweep) and slicer_api (HTTP bridge with 4xx/5xx/connection error
    split that drives the 3MF embedded-settings fallback retry path).
  - New schemas: SliceRequest, SliceResponse, SliceArchiveResponse,
    SliceJobEnqueueResponse.
  - New routes: POST /library/files/{id}/slice,
    POST /archives/{id}/slice, GET /api/v1/slice-jobs/{id} (gated on
    LIBRARY_READ since job IDs are sequential and the body leaks source
    filenames and result IDs).
  - AppSettings + env defaults: use_slicer_api, orcaslicer_api_url,
    bambu_studio_api_url. DB-stored values override env defaults.

  Frontend
  - New SliceModal handles preset gating; enqueues then closes
    immediately.
  - New SliceJobTrackerProvider polls active jobs at app level, surfaces
    a single toast per job (queued -> running -> completed / failed)
    and invalidates library/archives queries on terminal status.
  - Settings -> Workflow -> Slicer card: preferred slicer dropdown,
    Use Slicer API toggle, contextual sidecar URL field.
  - File Manager / Archives / MakerWorld get a Slice button gated on
    the Use Slicer API setting.
  - gcode-viewer adapter learns ?library_file=<id> so sliced library
    files preview inline.

  i18n
  - New slice.* and settings.{useSlicerApi,slicerCard,orcaslicerApiUrl,
    bambuStudioApiUrl,slicerApiUrlDescription,useSlicerApiDescription}
    + fileManager.noPermissionSlice keys across all 8 locales (en, de,
    fr, it, ja, pt-BR, zh-CN, zh-TW). English fully translated, German
    fully translated, the other six seeded with English fallbacks
    pending native translation.

  Tests
  - 10 backend integration tests in test_library_slice_api.py covering
    validation (404/400), happy-path enqueue, sidecar-down, 3MF
    embedded-settings fallback, STL no-fallback, and preset-error ->
    failed job paths.
  - New unit tests in test_slicer_api.py for the HTTP bridge.
  - 5 new SliceModal frontend tests covering preset gating, library +
    archive enqueue paths, error surface, and preset-load failure.
  - Existing SettingsPage tests adjusted: slicer dropdown asserts now
    switch to the Workflow tab first; added a beforeEach URL reset so
    one test's tab click doesn't bleed into sibling tests.

  Sidecar
  - New slicer-api/ folder is self-contained and optional. Two services
    (orca-slicer-api on 3003, bambu-studio-api on 3001 behind --profile
    bambu) build via Docker git-build-context from
    maziggy/orca-slicer-api@bambuddy/profile-resolver. The fork patches
    the OrcaSlicer CLI's profile compatibility quirks (inherits-chain
    resolver, from:User -> system rewrite, '# ' clone-prefix strip,
    sentinel-value strip) empirically required to slice real GUI
    exports without segfaulting the CLI.

  Docs
  - CHANGELOG entry under [0.2.4b1] - Unreleased Added.
  - README File Manager bullet for the new server-side Slice button.
  - bambuddy-website features.html: new card under "Configurable Slicer".
  - bambuddy-wiki: new page features/slicer-api.md + nav entry +
    features index card.

  Notes
  - Opt-in: with Use Slicer API off, the existing "open in desktop
    slicer via URI" flow is the default and unchanged.
  - 3MF inputs that segfault the CLI on --load-settings transparently
    retry with embedded settings; the resulting job carries
    used_embedded_settings: true.
  - Sliced files always export as .gcode.3mf so File Manager picks up
    the embedded thumbnail; file_type is set to "gcode" (blue badge).
2026-04-27 15:28:37 +02:00
..
.env.example ● feat(slicer): server-side slicing via OrcaSlicer / Bambu Studio sidecar 2026-04-27 15:28:37 +02:00
.gitignore ● feat(slicer): server-side slicing via OrcaSlicer / Bambu Studio sidecar 2026-04-27 15:28:37 +02:00
docker-compose.yml ● feat(slicer): server-side slicing via OrcaSlicer / Bambu Studio sidecar 2026-04-27 15:28:37 +02:00
README.md ● feat(slicer): server-side slicing via OrcaSlicer / Bambu Studio sidecar 2026-04-27 15:28:37 +02:00

Slicer-API sidecar (optional)

Self-contained Docker Compose stack that runs HTTP wrappers around the OrcaSlicer and/or Bambu Studio CLI. Bambuddy's Slice action calls these to slice models server-side, no desktop slicer required.

This folder is optional. Bambuddy works without it — Slice falls back to opening the model in the user's local desktop slicer via URI scheme. Enable the API path by:

  1. Starting one or both services here
  2. Settings → Slicer → Use Slicer API = on
  3. Set Slicer sidecar URL for whichever slicer you've started

Quick start

cd slicer-api/
cp .env.example .env       # edit ports / versions if you like

# OrcaSlicer only (default profile):
docker compose up -d
curl http://localhost:3003/health

# Both slicers:
docker compose --profile bambu up -d
curl http://localhost:3001/health   # bambu-studio-api
curl http://localhost:3003/health   # orca-slicer-api

First build downloads the slicer's AppImage (~110 MB OrcaSlicer, ~220 MB BambuStudio) and compiles the Node wrapper. Takes 38 minutes per service. Subsequent runs reuse the local image — instant start.

Ports

Service Default host port Why this port
orca-slicer-api 3003 Bambuddy's virtual-printer feature reserves 3000 and 3002
bambu-studio-api 3001 First free port in that range

Override via ORCA_API_PORT / BAMBU_API_PORT in .env.

Bambuddy wiring

In the Bambuddy UI: Settings → Slicer:

  • Preferred Slicer: pick OrcaSlicer or Bambu Studio.
  • Use Slicer API: turn on.
  • Sidecar URL: paste the full URL of the chosen slicer's sidecar. Default values match the Compose defaults:
    • OrcaSlicer: http://localhost:3003
    • Bambu Studio: http://localhost:3001

Leaving the URL field blank uses the SLICER_API_URL / BAMBU_STUDIO_API_URL environment defaults from Bambuddy's config.

Where the source lives

Both images build from the maziggy/orca-slicer-api fork (bambuddy/profile-resolver branch). The Compose file uses Docker's git build context, so you don't need to clone it manually — Docker pulls the repo at build time.

The fork patches AFKFelix's upstream wrapper with the inherits: chain resolver, from: "User""system" rewrite, # clone-prefix strip, and sentinel-value strip — all empirically required to slice real GUI exports without segfaulting the CLI. Once those land upstream, this Compose file can be flipped to pull from ghcr.io/afkfelix/orca-slicer-api directly.

Updating

Bump the versions in .env, then:

docker compose --profile bambu build --no-cache
docker compose --profile bambu up -d

--no-cache is needed because the Dockerfile downloads the AppImage inline; Docker won't re-fetch it on a version change otherwise.

Troubleshooting

  • address already in use on port 3000 or 3002 — Bambuddy's virtual-printer feature owns those. Don't change ORCA_API_PORT to 3000 or 3002.

  • /health reports version: "unknown" — cosmetic. The bundled binary works; the wrapper just couldn't parse the version string from the slicer's --help output (BambuStudio's format differs from OrcaSlicer's, which is what the wrapper was tuned for).

  • Slice returns "Failed to slice the model" — the wrapper hides the CLI's stderr. Re-run inside the container to see it:

    docker exec orca-slicer-api /app/squashfs-root/AppRun --slice 1 \
        --load-settings "/path/to/printer.json;/path/to/preset.json" \
        --load-filaments /path/to/filament.json \
        --allow-newer-file --outputdir /tmp/out /path/to/model.3mf