(guide-compilers-slicer-project)= # Slicer Project Compiler ```{include} ../_guide-sidebar-compiler-membership.md ``` The **SlicerProjectCompiler** turns OpenVCAD designs that carry **scalar slicer attributes** (for example **`INFILL_DENSITY`**, **`FUZZY_SKIN_POINT_DISTANCE`**, or **`TEMPERATURE`**) into a **PrusaSlicer-style 3MF project** (`.3mf`). You **import that file into PrusaSlicer** (or another slicer that understands the same project layout), slice, and print on **filament / FFF** hardware. This page explains **how the compiler works** (by method, not line-by-line code), walks through **examples**, and documents the **Python API**. Renders show the **OpenVCAD** fields; **PrusaSlicer** screenshots show the sliced out. ## Prerequisites - OpenVCAD with **`pyvcad`** and **`pyvcad_compilers`** installed. - Familiarity with **scalar attributes** on geometry (see {ref}`guide-getting-started`, especially **Lesson 4: Attributes**, and the [Functional Grading Guide](../gradients.md)). ## What this compiler is for Use **Slicer Project** when you want **spatially varying slicer settings** derived from continuous fields on your model, exported as a **single project file** for **PrusaSlicer**, instead of **voxel PNG stacks** for inkjet workflows. For slice **images**, see the [Material Inkjet](material-inkjet.md) and [Color Inkjet](color-inkjet.md) guides. (opening-your-project-in-prusaslicer)= ## Opening your project in PrusaSlicer The compiler **only writes** the **`.3mf`**. It does **not** launch a slicer. 1. Run your Python script (or build the compiler in code) so **`compile()`** finishes and the **`.3mf`** path exists. 2. Open **PrusaSlicer**, use **File → Import**, and select the generated **`.3mf`** (or drag it into the window). 3. Inspect **sub-volumes** and **per-volume settings** in the **Plater / Models** UI, then **Slice now** and review the **G-code preview** (layer view, color by feature, etc.). Printer and filament choices inside PrusaSlicer are up to you; the **`.3mf`** carries **model geometry** and **embedded project/config** produced by the compiler. ## How it works At a high level, **`compile()`** does the following: 1. **Discover attributes** on your tree and **classify** each supported name using an internal **registry**. There are two families: - **Settings mesh:** attributes that map to **PrusaSlicer per-volume metadata** (for example **`INFILL_DENSITY`** → **`fill_density`**, **`FUZZY_SKIN_POINT_DISTANCE`** → **`fuzzy_skin_point_dist`**). The compiler **does not** need separate **`.ini`** profiles for this mode. - **Virtual extrusion:** attributes that must be driven through **G-code** (today this path is built around **`TEMPERATURE`** with a **`FLOW_RATE`** companion). This mode **requires** **`printer_profile_path`** and **`filament_profile_path`** pointing to PrusaSlicer **`.ini`** files so the compiler can **inject** toolchange-style **G-code** derived from templates. Unsupported attribute names are **printed to the console** and **ignored**. 2. **Sample** the prepared tree on a **voxel grid** over the **bounding box** using your **`voxel_size`**. For each voxel **inside** the solid, the compiler reads **double-valued** attributes it cares about. 3. **Estimate ranges** for each segmented attribute over the solid, then split each range into **`num_regions`** **sub-ranges** (default **10**). Each sub-range becomes a **region** of the solid where attribute values are **similar**. 4. **Build geometry** for those regions (segmented meshes), attach **Prusa-compatible metadata** (settings mesh) and/or **extruder / tool** assignments (virtual extrusion), and **package** everything into a **`.3mf`** with the expected **config** attachments. 5. **Progress** and **cancellation** follow the usual **`CompilerBase`** behavior. The important idea: **continuous** fields in OpenVCAD become **piecewise-constant** regions in the slicer project—each region carries **one** representative setting (derived from the sub-range), not a unique value per voxel inside Prusa’s mesh-metadata model. ## Pipeline overview **Classify** supported attributes → **sample** on a grid → **segment** by attribute ranges → **emit** meshes + metadata and/or **virtual extruders** → **write** **`.3mf`**. ## Reference: Python API ### Constructor `SlicerProjectCompiler(root, voxel_size, output_file_path, num_regions=10, printer_profile_path="", filament_profile_path="")` | Argument | Meaning | | -------- | ------- | | `root` | Root **`Node`**. | | `voxel_size` | **`Vec3`** sampling spacing (mm); finer values better resolve thin regions at higher cost. | | `output_file_path` | Full path to the output **`.3mf`** file. | | `num_regions` | Number of **sub-ranges** per segmented attribute (default **10**). | | `printer_profile_path` | PrusaSlicer **printer** **`.ini`**; **required** when **virtual extrusion** attributes (e.g. **`TEMPERATURE`**) are present. | | `filament_profile_path` | PrusaSlicer **filament** **`.ini`**; **required** with virtual extrusion. | ### Methods (including **`CompilerBase`**) | Method | Role | | ------ | ---- | | `compile()` | Build the **`.3mf`**. | | `supported_attributes()` | **Discovery** list: every attribute name the registry knows (settings mesh + virtual extrusion + companions). The tree does **not** need all of them; only present attributes participate. | | `cancel()` | Request cooperative cancellation. | | `set_progress_callback(fn)` | **`fn(progress)`** with **`progress`** in **\[0, 1\]**. | For autodoc signatures, see **pyvcad_compilers** (**`SlicerProjectCompiler`**, **`CompilerBase`**). ## Examples and figures The scripts below live under **`examples/compilers/slicer_project/`** and write **`.3mf`** files under **`output/`** next to each script. Run them from the repository with your venv, then **import the `.3mf` into PrusaSlicer** as described [above](#opening-your-project-in-prusaslicer). ### (a) Fuzzy skin gradient on a cylinder Design (**`FUZZY_SKIN_POINT_DISTANCE`** ramp along **Z**): matches the idea of **`examples/applications/slicer_settings_mesh/fuzzy_skin_cylinder.py`**. Script: **`01_fuzzy_skin_cylinder.py`** → **`output/fuzzy_skin_cylinder.3mf`**. ```python """ Slicer project - fuzzy skin gradient (cylinder) ============================================== Upright cylinder with **FUZZY_SKIN_POINT_DISTANCE** ramping along Z, compiled to a PrusaSlicer-style **.3mf** for per-volume fuzzy skin settings. Companion to: docs/source/guides/compilers/slicer-project.md See also: examples/applications/slicer_settings_mesh/fuzzy_skin_cylinder.py """ import os import pyvcad as pv import pyvcad_compilers as pvc import pyvcad_rendering as viz cylinder_height_mm = 100.0 cylinder_radius_mm = 15.0 edge_buffer_mm = 10.0 half_h = 0.5 * cylinder_height_mm span = 2.0 * (half_h - edge_buffer_mm) fuzzy_expr = ( f"0.4 * clamp((z + {half_h} - {edge_buffer_mm}) / ({span}), 0, 1)" ) cylinder = pv.Cylinder(pv.Vec3(0, 0, 0), cylinder_radius_mm, cylinder_height_mm) cylinder.set_attribute( pv.DefaultAttributes.FUZZY_SKIN_POINT_DISTANCE, pv.FloatAttribute(fuzzy_expr), ) root = cylinder viz.Render(root) _here = os.path.dirname(os.path.abspath(__file__)) out_dir = os.path.join(_here, "output") os.makedirs(out_dir, exist_ok=True) out_3mf = os.path.join(out_dir, "fuzzy_skin_cylinder.3mf") regions = 12 compiler = pvc.SlicerProjectCompiler( root, pv.Vec3(0.25, 0.25, 0.25), out_3mf, regions, ) compiler.compile() print("Wrote", out_3mf) ``` **OpenVCAD** preview (field used for segmentation):
OpenVCAD (fuzzy skin distance)
Slicer Preview (left: model preview | right: g-code fuzzy skin texture preview)
Models / sub-volumes (fuzzy skin overrides)
OpenVCAD (infill density)
G-code preview (infill gradient, cutaway)
OpenVCAD (temperature)
G-code preview (temperature)