This repository supersedes utosrad/AutoSlicer3D, which is archived. Same project, clean history.
Splits a 3D model that does not fit your printer into printable chunks, generates the dovetail joints that hold them back together, and estimates the time and filament for each piece.
Screenshot pending. See the comment in this file for exactly what to record.
A Bambu Lab A1 Mini has a 180 mm build volume. A helmet does not fit in it. ChopShop takes the STL, works out the smallest grid of pieces that each fit, cuts them, and tells you what each piece costs to print.
Concretely:
- Grid sizing. The chunk grid is the minimum that fits:
ceil(extent / 170)per axis, where 170 mm is the 180 mm build cube minus a 10 mm margin. A 400 x 120 x 120 mm model becomes a 3 x 1 x 1 grid. A 400 x 400 x 250 mm model becomes 3 x 3 x 2, or 18 pieces. - Cutting. Each cell is carved out of the source mesh with six capped plane slices, one per box face. Capping matters: without it the interior pieces come back as open shells with no volume, and every downstream estimate reads zero. Chunk volumes sum back to the source volume exactly.
- Cut-face tracking. Each chunk records which of its six faces are artificial cuts rather than original model surface, as
+x,-x,+yand so on. Those are the faces that need joints. Outer faces are never labelled. - Joints. Dovetail pins and sockets, laid out on a 30 mm grid across the cut face with a 10 mm inset from the edges. Each candidate site is ray-cast into the chunk first and skipped unless there is at least 5 mm of material behind it. Sockets are scaled up by 0.2 mm of clearance so an FDM print still slides together. Booleans go through manifold3d.
- Estimates. If the OrcaSlicer CLI is on
PATH, ChopShop shells out to it and parses the real print time and filament usage out of its output or the resulting G-code comments. If it is not, it falls back to a geometric heuristic from mesh volume and surface area at a configurable infill. - Tracking. Every chunk is a row in SQLite with a
queued/printing/donestatus. The progress endpoint reports pieces completed and estimated minutes remaining.
Worked example, from an actual run against a generated 400 x 120 x 120 mm box with no slicer installed, at the default 15% infill:
chunk_0_0_0 133.3 x 120.0 x 120.0 mm 998.4 min 357.1 g
chunk_1_0_0 133.3 x 120.0 x 120.0 mm 998.4 min 357.1 g
chunk_2_0_0 133.3 x 120.0 x 120.0 mm 998.4 min 357.1 g
Those minutes come from the fallback heuristic, not from a slicer, and are not calibrated against a real print. Install OrcaSlicer if you want numbers you can trust.
Bring your own STL. No model is committed to this repository.
Three commands. Verified on CPython 3.14 and Node 22, macOS arm64.
# 1. install the backend
python3 -m venv .venv && .venv/bin/pip install -r chopshop/backend/requirements.txt
# 2. start the API on :8000
.venv/bin/uvicorn chopshop.backend.api.server:app --reload --port 8000
# 3. in a second terminal, start the UI on :5173
cd chopshop/frontend && npm install && npm run devOpen http://localhost:5173. Vite proxies /api to port 8000.
Uploads, generated chunk STLs and the SQLite file all land in data/ at the repository root. Set CHOPSHOP_DATA_DIR to put them somewhere else. Paths resolve from the package, not the working directory, so uvicorn runs from anywhere.
Run the tests with .venv/bin/pytest.
browser FastAPI geometry
─────── ─────── ────────
UploadView
drag an STL,
preview it against ──POST /api/upload──▶ write data/uploads/<id>/model.stl
a 180 mm wireframe insert a row in models
build volume │
▼
SplitView ChunkEngine (chunker.py)
auto-fires the ──POST /api/split/<id>─▶ load, fix normals, fill holes
split on mount ceil(extent / 170) per axis
6 capped plane slices per cell
label the interior cut faces
│
▼
place_connectors (connectors.py)
30 mm grid, 10 mm inset
ray-cast for >= 5 mm of material
union pins / subtract sockets
via manifold3d [not wired
│ into /split]
▼
SlicerEstimator (slicer_estimate.py)
OrcaSlicer CLI if on PATH,
else volume + area heuristic
4 chunks at a time
│
▼
write data/chunks/<id>/*.stl
insert chunk rows, status=queued
│
exploded 3D view ◀───SplitResult────────────────┘
of every chunk,
per-chunk mm /
minutes / grams
│
▼
PrintTracker ──PATCH .../status──▶ queued -> printing -> done
progress bar, ──GET /api/progress──▶ pieces done, minutes remaining
per-chunk buttons
AssemblyView placeholder component, not yet routed
The API surface is six endpoints:
| Method | Path | Purpose |
|---|---|---|
| POST | /api/upload |
Store an STL, return a model id |
| POST | /api/split/{model_id} |
Chunk it, estimate it, persist it |
| GET | /api/chunks/{model_id} |
List chunks with dimensions and estimates |
| GET | /api/chunks/{model_id}/{chunk_id}/stl |
Download one chunk |
| PATCH | /api/chunks/{model_id}/{chunk_id}/status |
Move a chunk through the print queue |
| GET | /api/progress/{model_id} |
Pieces done and minutes remaining |
Interactive docs at http://localhost:8000/docs.
chopshop/
backend/
config.py data directory resolution
api/
server.py app factory, CORS, SQLite schema
routes.py the six endpoints
models.py pydantic request and response types
core/
chunker.py grid sizing and capped plane slicing
connectors.py dovetail generation and placement
slicer_estimate.py OrcaSlicer CLI wrapper and heuristic fallback
frontend/src/
App.tsx upload / split / track view switch
lib/api.ts typed fetch wrappers
components/ UploadView, SplitView, PrintTracker, AssemblyView
tests/ 31 pytest tests
$ pytest
31 passed
Everything runs off trimesh primitives, so there are no fixture files and nothing external to install. The suite checks the geometry against closed-form answers rather than golden outputs: chunk volumes must sum to the source volume, a dovetail's volume must match the analytic integral of its tapering cross-section, a male pass over an 80 mm face must add exactly nine pins, and a female pass must remove exactly nine sockets. The API test walks upload, split, list, download, mark-done and progress against a temporary data directory.
Worth knowing before you read the code:
place_connectorsworks and is tested, but/api/splitdoes not call it yet. Chunks come out as plain cut pieces with no joints.- The cut plane is always axis-aligned. There is no seam optimisation, no attempt to hide cuts, and no check that a chunk is printable without supports.
AssemblyViewis a placeholder and is not routed.- The heuristic estimator has not been calibrated against real prints. Treat its output as a rough ordering of chunks by cost, not as a print time.
MIT. See LICENSE.