Early docs These pages are very early. Structure and tone are still being worked out, so anything here may change drastically.
Skip to content
Rendered from ARCHITECTURE.md in the repository — edit it there.

Architecture ​

A map of the codebase, not a manual. Each module carries its own long-form README with the reasoning behind it — this page tells you which one to open.

Using the app instead of working on it? Start at Getting started.

The shape of it ​

One Rust core, four things that drive it.

The same engine compiles to a native binary, to WebAssembly, and into a Tauri shell. That's the whole point: previews and final output can't disagree, because there is no second implementation to disagree with.

The UI picks its runtime mode at startup:

ModeSlicing happensWhen
cloudOn your serverDefault web build
webIn your browserweb-slicer build
nativeIn-processDesktop and iPad

Modules ​

Every one of these has a README. They are the real documentation.

Pipeline ​

ModuleOwnsRead
mesh/Loading STL, OBJ, 3MF; mesh types and analysisLoading and repair
core/The slicing pipeline — process_mesh, surfaces, infill boundaries, object identityStart here
walls/Perimeters: the Arachne variable-width generator and the classic fixed-offset oneBead placement
infill/Sparse fill patternsPattern generation
adhesion/Skirt, brim, raftWhy it runs last
gcode/Emission, firmware dialects, lifecycle markers, the parseable footerOutput

The pipeline's execution order is load-bearing and documented in core/README.md. Surfaces are computed after walls; infill after surfaces; adhesion dead last. Reordering breaks things in ways that are hard to see.

Scene and configuration ​

ModuleOwns
scene/Single source of truth for object placement. Every CLI flag and every UI gesture becomes a SceneOp
orient/Auto-orientation and face-to-floor
settings/Slicing parameters, validation, the JSON schema the UI generates its form from
config/slicer.toml: discovery, merge order, persistence
profiles/The user's printer / filament / process library, and its export

Interfaces ​

ModuleOwns
cli/slice, settings, config, info, changelog
server/HTTP for bytes, WebSocket for control flow
printer/Native outbound transport to printers (Moonraker today)
db/SQLite slice history and the G-code cache
gcode_viewer/Parsing G-code back for the preview

The front-end lives in ui/ (Angular) and ui-desktop/ (Tauri shell for desktop and iPadOS).

The pipeline in one pass ​

slice_mesh                    mesh → contours per layer
generate walls                contours → bead paths (Arachne or classic)
apply_single_wall_restrictions strip inner walls where configured
generate_top_bottom_surfaces  solid surfaces within the interior
add_infill_to_layers          sparse fill, minus solid regions
path ordering + flow          greedy TSP per role, then wall-overlap scaling
apply_adhesion                skirt / brim / raft

slice_plate in core/objects.rs is the single entry point. It merges the plate and runs the pipeline once when object identity isn't needed, and runs it per object when it is — the merged path is byte-identical to a plain process_mesh, which is pinned by a test.

Key types ​

rust
pub struct SliceLayer {
    pub z: f64,
    pub paths: Paths,                             // closed contours (Clipper2)
    pub path_roles: Vec<ExtrusionRole>,           // parallel array
    pub path_widths: Vec<Option<f64>>,            // per-path bead width
    pub path_vertex_widths: Vec<Option<Vec<f64>>>,// per-vertex, for tapering beads
    pub solid_regions: Paths,
    // … plus overhang and object-tag parallel arrays
}

The parallel arrays are the thing to be careful with. Anything that rebuilds a layer's paths must carry every parallel array along, or roles, widths and object tags silently shift onto the wrong paths.

ExtrusionRole distinguishes OuterWall, InnerWall, OverhangPerimeter, Infill, Bridge, TopSurface, BottomSurface, GapFill, Support and Skirt. Note that a hole boundary also carries OuterWall — it's the outermost bead of that contour. Tell solid islands from holes by signed area, never by role.

Conventions worth knowing before you edit ​

Clipper2 fill rules are not interchangeable. Surface detection uses EvenOdd (winding-independent); infill subtraction uses Positive; anything subtracting the wall-bead footprint uses NonZero, because that footprint is a frame with CW holes. Picking the wrong one produces plausible-looking, wrong geometry. The table in core/README.md is authoritative.

Don't add a second placement path. scene/ owns transforms. Baking happens once, at the slicer boundary.

Don't add a parallel version constant. src/version.rs is the only place version and changelog are read from, and the version is derived from the git tag at build time.

Validate geometry changes, don't reason about them.tools/gcode-analysis/ measures sliced output directly — wall overlap, unfilled gaps, bead-width distribution, capsule renders. Compare against the classic generator before claiming a fix.

Further reading ​

External: Clipper2 · Arachne · RepRap G-code · Marlin · Klipper