(guide-compilers-slicer-project)=
# Slicer Project Compilers
```{include} ../_guide-sidebar-compiler-membership.md
```
## Intro
Slicer project compilers turn prepared OpenVCAD designs into slicer-native **`.3mf` project files** for filament printing workflows. Use them when you want OpenVCAD to generate geometry regions and attribute-derived assignments, while the downstream slicer still owns slicing, preview, and G-code generation.
There are two separate workflows:
| Workflow | Input attributes | Output project | Best fit |
| -------- | ---------------- | -------------- | -------- |
| **PrusaSlicer** settings meshes | Scalar planning attributes such as `INFILL_DENSITY`, `FUZZY_SKIN_POINT_DISTANCE`, `LAYER_HEIGHT`, or `PERIMETER_SPEED` | PrusaSlicer-style `.3mf` | Spatially varying slicer planning settings |
| **PrusaSlicer** virtual extrusion | `TEMPERATURE` with optional companion `FLOW_RATE` | PrusaSlicer-style `.3mf` with logical tools and toolchange G-code | Machine-state changes at region boundaries |
| **PrusaSlicer** ColorMix color | `COLOR_RGB` | PrusaSlicer-style `.3mf` with ColorMix virtual extruders | Mixed-filament color approximation from design-space colors |
| **PrusaSlicer** ColorMix material fractions | `VOLUME_FRACTIONS` plus `volume_fraction_materials` | PrusaSlicer-style `.3mf` with ColorMix virtual extruders | Direct material-fraction to filament-slot recipes |
| **FullSpectrum** color | `COLOR_RGB` | Orca / Bambu-style Full Spectrum `.3mf` | Mixed-filament color approximation from design-space colors |
| **FullSpectrum** material fractions | `VOLUME_FRACTIONS` plus `volume_fraction_materials` | Orca / Bambu-style Full Spectrum `.3mf` | Direct material-fraction to filament-slot recipes |
For slice-image workflows instead of slicer projects, see [Material Inkjet](material-inkjet.md), [Color Inkjet](color-inkjet.md), and [VAT Photo](vat-photo.md).
### Prerequisites
- OpenVCAD with **`pyvcad`**, **`pyvcad_compilers`**, and **`pyvcad_rendering`** installed.
- Familiarity with attributes on geometry. See {ref}`guide-getting-started`, especially Lesson 4, and the [Functional Grading Guide](../gradients.md).
- A matching slicer for the project you generate: **PrusaSlicer** for Prusa-style scalar projects, or the [OrcaSlicer-FullSpectrum](https://github.com/ratdoux/OrcaSlicer-FullSpectrum) fork for the FullSpectrum examples in this guide.
### Shared 3MF Concepts
A **3MF** file is a compressed package, not a single flat mesh file. Conceptually it behaves like a ZIP / OPC-style container with relationship files, content-type metadata, and XML model parts. The core model part stores triangle meshes as XML vertices and triangles. Slicers extend the package by adding their own project settings and per-model metadata.
Typical package shapes:
```text
generic_part.3mf
[Content_Types].xml
_rels/.rels
3D/3dmodel.model
prusa_project.3mf
3D/3dmodel.model
Metadata/Slic3r_PE.config
Metadata/Slic3r_PE_model.config
prusa_colormix_project.3mf
3D/3dmodel.model
Metadata/Slic3r_PE_model.config
Metadata/Prusa_Slicer_full_spectrum.json
orca_full_spectrum_project.3mf
3D/3dmodel.model
Metadata/project_settings.config
Metadata/model_settings.config
```
A very small 3MF mesh fragment looks like this:
```xml
```
The extra value of slicer project 3MFs comes from the attachments around that core mesh. A PrusaSlicer project can carry Prusa project configuration and per-volume settings. An Orca / Bambu-style project can carry model settings, project settings, and component assignments that tell the slicer which extruder or virtual mixed filament belongs to each region.
For the 3MF container and core mesh format, see the [3MF Consortium specification page](https://3mf.io/spec/) and the [Core 3MF Specification](https://3mf.io/spec/core-v1-3-0/).
## PrusaSlicer
Use the PrusaSlicer compiler when your OpenVCAD design carries scalar process attributes and you want a PrusaSlicer-compatible project file. The compiler samples scalar attributes over the solid, partitions the sampled field into a finite number of regions, emits a mesh for each region, and writes a PrusaSlicer-style `.3mf`.
The important idea is that a continuous OpenVCAD field becomes **piecewise constant slicer regions**. Each generated region gets one representative value. More regions preserve more variation, but they also create more sub-volumes for PrusaSlicer to manage.
### Opening The Project
The compiler only writes the `.3mf`. It does not launch PrusaSlicer.
1. Run your Python script so `compile()` finishes and the `.3mf` path exists.
2. Open **PrusaSlicer**, use **File -> Import**, and select the generated `.3mf`.
3. Inspect sub-volumes and per-volume settings in the **Plater / Models** UI, then slice and review the G-code preview.
### Settings Applied To Meshes
The settings-mesh path is for attributes that directly affect **slicer planning**. These settings change how PrusaSlicer computes toolpaths: infill density, layer height, perimeter counts, line widths, and feature speeds. OpenVCAD emits sub-volumes, and each sub-volume carries Prusa-compatible metadata for the selected slicer setting.
This path is appropriate when the parameter should influence slicing decisions before G-code is generated. For example, an `INFILL_DENSITY` gradient changes how dense the internal infill toolpaths are in each generated region.
Settings-mesh attributes are scalar fields. The Python names below are available under `pv.DefaultAttributes`.
| Attribute | PrusaSlicer setting key | Typical use |
| --------- | ----------------------- | ----------- |
| `INFILL_DENSITY` | `fill_density` | Spatial infill percentage |
| `FUZZY_SKIN_POINT_DISTANCE` | `fuzzy_skin_point_dist` | Distance between fuzzy skin points; lower values create denser texture |
| `FUZZY_SKIN_THICKNESS` | `fuzzy_skin_thickness` | Maximum perpendicular displacement of fuzzy skin points |
| `BRIDGE_SPEED` | `bridge_speed` | Bridge planning speed |
| `EXTERNAL_PERIMETER_EXTRUSION_WIDTH` | `external_perimeter_extrusion_width` | Outer wall line width |
| `EXTERNAL_PERIMETER_SPEED` | `external_perimeter_speed` | Outer wall speed |
| `EXTRUSION_WIDTH` | `extrusion_width` | General line width |
| `GAP_FILL_SPEED` | `gap_fill_speed` | Gap fill speed |
| `INFILL_EXTRUSION_WIDTH` | `infill_extrusion_width` | Infill line width |
| `INFILL_SPEED` | `infill_speed` | Infill speed |
| `IRONING_FLOWRATE` | `ironing_flowrate` | Ironing flow |
| `IRONING_SPEED` | `ironing_speed` | Ironing speed |
| `LAYER_HEIGHT` | `layer_height` | Region layer height |
| `PERIMETER_EXTRUSION_WIDTH` | `perimeter_extrusion_width` | Perimeter line width |
| `PERIMETER_SPEED` | `perimeter_speed` | Perimeter speed |
| `PERIMETERS` | `perimeters` | Perimeter count |
| `SMALL_PERIMETER_SPEED` | `small_perimeter_speed` | Small-feature perimeter speed |
| `SOLID_INFILL_EXTRUSION_WIDTH` | `solid_infill_extrusion_width` | Solid infill line width |
| `SOLID_INFILL_SPEED` | `solid_infill_speed` | Solid infill speed |
| `SUPPORT_MATERIAL_EXTRUSION_WIDTH` | `support_material_extrusion_width` | Support extrusion width |
| `TOP_INFILL_EXTRUSION_WIDTH` | `top_infill_extrusion_width` | Top infill line width |
| `TOP_SOLID_INFILL_SPEED` | `top_solid_infill_speed` | Top solid infill speed |
**Fuzzy skin cylinder (`01_fuzzy_skin_cylinder.py`)**: this example applies `FUZZY_SKIN_POINT_DISTANCE` along the cylinder height and writes **`output/fuzzy_skin_cylinder.3mf`**. The generated sub-volumes carry `fuzzy_skin_point_dist` overrides, so PrusaSlicer changes the planned surface texture by region.
Fuzzy skin must still be enabled in PrusaSlicer, typically as **Outside walls**.
`FUZZY_SKIN_THICKNESS` controls the maximum displacement from the perimeter,
while lower `FUZZY_SKIN_POINT_DISTANCE` values place displaced points more
densely. A thickness of zero produces a smooth region.
```python
cylinder.set_attribute(
pv.DefaultAttributes.FUZZY_SKIN_POINT_DISTANCE,
pv.FloatAttribute(fuzzy_expr),
)
compiler = pvc.PrusaSlicerProjectCompiler(
root,
pv.Vec3(0.25, 0.25, 0.25),
out_3mf,
num_regions=12,
)
```
OpenVCAD (fuzzy skin distance)
PrusaSlicer preview (model and fuzzy skin G-code texture)
Models / sub-volumes (fuzzy skin overrides)
**Infill density bar (`02_infill_density_bar.py`)**: this example ramps `INFILL_DENSITY` along the bar and writes **`output/infill_density_bar.3mf`**. The generated regions carry `fill_density` metadata, so PrusaSlicer computes denser or sparser infill toolpaths in each region.
```python
bar.set_attribute(
pv.DefaultAttributes.INFILL_DENSITY,
pv.FloatAttribute(infill_expr),
)
compiler = pvc.PrusaSlicerProjectCompiler(
root,
pv.Vec3(0.25, 0.25, 0.25),
out_3mf,
num_regions=12,
)
```
### Virtual Extrusion
Virtual extrusion controls **machine state** by taking advantage of slicer toolchange events. OpenVCAD assigns synthetic extruder indices to regions, patches the project profile to declare those logical tools, and provides toolchange G-code that applies the desired process commands when the slicer switches between regions.
The logical toolhead does not need to correspond to a separate physical nozzle. On a single-tool printer, the slicer can still emit toolchange events between logical tools, and the toolchange script can update temperature, flow, or other machine state without changing filament. On a multi-tool printer, the same concept can coexist with physical tool changes if the printer profile and script are written that way.
This path is intentionally different from settings meshes:
| Path | Controls | Slicer sees it before planning? | Best fit |
| ---- | -------- | ------------------------------- | -------- |
| Settings mesh | Toolpath planning settings | Yes | Infill, speeds, widths, layer height, perimeters |
| Virtual extrusion | Machine state commands | No, it runs as G-code | Temperature, flow, and process state that can be changed at region boundaries |
In the current method, `TEMPERATURE` is the primary virtual-extrusion attribute and `FLOW_RATE` is its companion.
| Attribute | Role | Effect |
| --------- | ---- | ------ |
| `TEMPERATURE` | Primary region attribute | Creates logical tools and emits `M104` temperatures through toolchange G-code |
| `FLOW_RATE` | Companion attribute | Supplies `M221` flow values for the same logical toolchange events |
The toolchange script applies commands such as:
```gcode
M104 S{temperature}
M221 S{flow_rate}
```
**Temperature and flow example (`03_temperature_compensation_demo.py`)**: this example applies a `TEMPERATURE` field, derives `FLOW_RATE` from a lookup table, and writes **`output/temperature_compensation_demo.3mf`**. The compiler uses Prusa profile files from **`examples/applications/foaming_filaments/profiles/`** so the generated project can define logical tools and toolchange G-code.
```python
rect_prism.set_attribute(
pv.DefaultAttributes.TEMPERATURE,
pv.FloatAttribute("max(min((x/3+236),256),216)"),
)
compiler = pvc.PrusaSlicerProjectCompiler(
root,
pv.Vec3(0.25, 0.25, 0.25),
out_3mf,
num_regions=10,
printer_profile_path=printer_profile_path,
filament_profile_path=filament_profile_path,
)
```
OpenVCAD (temperature)
PrusaSlicer G-code preview (temperature)
### ColorMix
PrusaSlicer ColorMix uses Prusa's FullSpectrum project metadata and `Prusa_Slicer_full_spectrum.json` to define virtual extruders whose IDs start after the physical filament slots. OpenVCAD assigns generated color/material regions to those physical or virtual extruder IDs in the normal Prusa `Slic3r_PE_model.config` metadata.
ColorMix mode is mutually exclusive with the scalar settings-mesh and virtual-extrusion paths. It is selected automatically when the design contains `COLOR_RGB` or `VOLUME_FRACTIONS`, or explicitly with `enable_color_mix=True`.
For `COLOR_RGB`, OpenVCAD uses a device-aware recipe selector. It generates valid Prusa ColorMix recipes from the configured physical filaments, predicts each recipe's apparent color with Prusa's mixer model, and then selects up to `max_palette_size` printable recipes that best cover the sampled design colors. `max_palette_size` counts both direct physical filament colors and virtual mixed recipes. The generated 3MF also includes `Metadata/OpenVCAD_prusa_colormix_report.json`, which records the selected recipes and DeltaE fit summary for inspection.
**Color gradient example (`06_prusa_colormix_color_gradient.py`)**: this example applies a `COLOR_RGB` ramp and writes **`output/prusa_colormix_color_gradient.3mf`**.
```python
bar.set_attribute(
pv.DefaultAttributes.COLOR_RGB,
pv.Vec3Attribute(red_expr, green_expr, blue_expr),
)
compiler = pvc.PrusaSlicerProjectCompiler(
root,
pv.Vec3(0.25, 0.25, 0.25),
out_3mf,
enable_color_mix=True,
color_mix_recipe_preset="expanded",
max_palette_size=10,
min_component_percent=15,
max_recipe_components=3,
region_overlap_mm=0.2,
)
```
**Volume-fraction example (`07_prusa_colormix_volume_fractions.py`)**: this example maps OpenVCAD materials directly to physical filament slots and writes **`output/prusa_colormix_volume_fractions.3mf`**.
```python
compiler = pvc.PrusaSlicerProjectCompiler(
root,
pv.Vec3(0.25, 0.25, 0.25),
out_3mf,
enable_color_mix=True,
total_physical_extruders=5,
color_mix_filaments=[
{"slot": 1, "color_hex": "#FF0000"},
{"slot": 2, "color_hex": "#0000FF"},
],
volume_fraction_materials={"red": 1, "blue": 2},
max_palette_size=10,
min_component_percent=1,
max_recipe_components=3,
region_overlap_mm=0.0,
)
```
### Prusa Constructor Options
```python
compiler = pvc.PrusaSlicerProjectCompiler(
root,
pv.Vec3(0.25, 0.25, 0.25),
out_3mf,
num_regions=12,
printer_profile_path=printer_profile_path,
filament_profile_path=filament_profile_path,
enable_color_mix=False,
color_mix_filaments=None,
total_physical_extruders=5,
color_mix_recipe_preset="expanded",
max_palette_size=32,
min_component_percent=15,
max_recipe_components=3,
direct_physical_delta_e=1.0,
region_overlap_mm=0.2,
volume_fraction_materials={},
material_defs_path="",
)
compiler.compile()
```
| Option | Meaning |
| ------ | ------- |
| `root` | The OpenVCAD design tree to compile. |
| `voxel_size` | Sampling spacing in mm. Smaller values resolve smaller regions but cost more time and memory. |
| `output_file_path` | Destination `.3mf` project path. |
| `num_regions` | Number of value bands for each scalar attribute. More regions preserve more variation but create more sub-volumes. |
| `printer_profile_path` | PrusaSlicer printer `.ini`. Required when virtual extrusion attributes are present. |
| `filament_profile_path` | PrusaSlicer filament `.ini`. Required when virtual extrusion attributes are present. |
| `enable_color_mix` | Explicitly enables Prusa ColorMix mode. `COLOR_RGB` or `VOLUME_FRACTIONS` also selects it automatically. |
| `color_mix_filaments` | Physical filament slots and colors for ColorMix. Each dictionary may include `slot`, `color_hex`, and `nozzle_diameter_mm`. Empty uses Prusa CMYKW defaults for `COLOR_RGB`: `#0082ad`, `#d10f4f`, `#efd00b`, `#3d3e3d`, `#e6eaef`. |
| `total_physical_extruders` | Total physical tool slots in PrusaSlicer. Virtual ColorMix extruders start after this count, so unused physical tool IDs can be skipped. Defaults to `5`. |
| `color_mix_recipe_preset` | Recipe vocabulary for Prusa `COLOR_RGB` ColorMix. `conservative` uses base colors plus 25/75, 50/50, and 75/25 pair blends. `expanded` also includes 50/25/25 three-filament rotations. |
| `max_palette_size` | Maximum generated ColorMix palette size or volume-fraction recipe-region count. For Prusa `COLOR_RGB`, this counts both physical base colors and virtual mixed recipes. |
| `min_component_percent` | Minimum component percentage kept in generated ColorMix recipes. |
| `max_recipe_components` | Maximum physical filaments allowed in one Prusa ColorMix recipe. Prusa ColorMix supports up to 3. |
| `direct_physical_delta_e` | Legacy setting retained for compatibility. Prusa `COLOR_RGB` ColorMix now chooses physical colors and virtual recipes from the same device-aware candidate set. |
| `region_overlap_mm` | Small overlap between generated ColorMix sub-parts to avoid visible cracks between separately meshed regions. |
| `volume_fraction_materials` | Material-name to physical-slot mapping for direct `VOLUME_FRACTIONS` export, such as `{"red": 1, "blue": 2}`. |
| `material_defs_path` | Optional `MaterialDefs` JSON path. Empty uses the bundled default material definitions. |
## FullSpectrum
Use the FullSpectrum compiler when your OpenVCAD design carries either `COLOR_RGB` or `VOLUME_FRACTIONS` and you want an Orca / Bambu-style project for the FullSpectrum workflow.
**Full Spectrum** is a slicer workflow for getting more apparent colors out of a limited set of loaded filaments. Instead of truly melting filaments together into a homogeneous mixed polymer, it creates **virtual mixed-color filaments** by alternating physical filaments through layer dithering or related patterns. Thin layers and partially translucent filament let light interact with multiple colors, so the eye sees an intermediate color.
The achievable colors depend strongly on the actual filaments loaded in the printer, their translucency, layer height, surface orientation, and slicer settings. A **CMYKW** physical set, cyan, magenta, yellow, black, and white, is the recommended starting point because it gives the color-matching algorithm a broad gamut to work with.
OpenVCAD targets the [OrcaSlicer-FullSpectrum](https://github.com/ratdoux/OrcaSlicer-FullSpectrum) community fork for this project format. Treat this as an emerging ecosystem: the generated projects use Orca / Bambu-style metadata and FullSpectrum mixed-filament settings, and stock PrusaSlicer, stock OrcaSlicer, or stock Bambu Studio may not interpret those settings correctly.
### COLOR_RGB Workflow
Use `COLOR_RGB` when the design field is an intended color. The compiler samples the RGB target field, reduces it to a bounded palette with `max_palette_size`, compares each palette color against the loaded physical filaments and possible mixed-filament recipes, and assigns each generated mesh region to a physical or virtual mixed filament.
The default physical palette for `COLOR_RGB` mode is CYMKW if you do not pass `filaments`. Pass explicit filament dictionaries when your loaded spool colors differ.
```python
compiler = pvc.FullSpectrumSlicerProjectCompiler(
root,
pv.Vec3(0.25, 0.25, 0.25),
out_3mf,
[
{"slot": 1, "color_hex": "#00FFFF"},
{"slot": 2, "color_hex": "#FF00FF"},
{"slot": 3, "color_hex": "#FFFF00"},
{"slot": 4, "color_hex": "#000000"},
{"slot": 5, "color_hex": "#FFFFFF"},
],
max_palette_size=32,
min_component_percent=15,
max_recipe_components=5,
)
```
**Color gradient example (`04_full_spectrum_color_gradient.py`)**: this example applies a `COLOR_RGB` ramp from cyan toward magenta and writes **`output/full_spectrum_color_gradient.3mf`**. The compiler samples the RGB target field, reduces it to a small palette, and assigns each palette color to a physical or virtual mixed filament recipe.
```python
bar.set_attribute(
pv.DefaultAttributes.COLOR_RGB,
pv.Vec3Attribute(red_expr, green_expr, blue_expr),
)
compiler = pvc.FullSpectrumSlicerProjectCompiler(
root,
pv.Vec3(0.25, 0.25, 0.25),
out_3mf,
max_palette_size=10,
min_component_percent=15,
max_recipe_components=5,
)
```
OpenVCAD (COLOR_RGB target)
OrcaSlicer-FullSpectrum g-code screenshot
### VOLUME_FRACTIONS Workflow
Use `VOLUME_FRACTIONS` when the OpenVCAD field already describes material proportions and you want those proportions to become FullSpectrum recipe weights. This is simpler than color matching because the design says which materials should participate.
The compiler maps OpenVCAD material names to physical filament slots with `volume_fraction_materials`, normalizes the mapped fractions for each sample, clusters fraction vectors into at most `max_palette_size` recipe regions, and emits physical or virtual mixed-filament recipes using representative weights for each region.
```python
compiler = pvc.FullSpectrumSlicerProjectCompiler(
root,
pv.Vec3(0.25, 0.25, 0.25),
out_3mf,
volume_fraction_materials={"red": 1, "blue": 2},
max_palette_size=10,
min_component_percent=1,
max_recipe_components=5,
)
```
**Volume-fraction example (`05_full_spectrum_volume_fractions.py`)**: this example ramps red and blue material fractions across the bar and writes **`output/full_spectrum_volume_fractions.3mf`**. The `volume_fraction_materials={"red": 1, "blue": 2}` mapping sends those OpenVCAD material names directly to physical filament slots.
```python
bar.set_attribute(
pv.DefaultAttributes.VOLUME_FRACTIONS,
pv.VolumeFractionsAttribute(
[
(red_fraction_expr, materials.id("red")),
(blue_fraction_expr, materials.id("blue")),
]
),
)
compiler = pvc.FullSpectrumSlicerProjectCompiler(
root,
pv.Vec3(0.25, 0.25, 0.25),
out_3mf,
volume_fraction_materials={"red": 1, "blue": 2},
max_palette_size=10,
min_component_percent=1,
max_recipe_components=5,
)
```
OpenVCAD (VOLUME_FRACTIONS target)
OrcaSlicer-FullSpectrum g-code screenshot
### FullSpectrum Constructor Options
```python
compiler = pvc.FullSpectrumSlicerProjectCompiler(
root,
voxel_size,
output_file_path,
filaments=None,
max_palette_size=32,
min_component_percent=15,
max_recipe_components=5,
direct_physical_delta_e=1.0,
region_overlap_mm=0.2,
base_project_settings_path="",
orca_machine_profile_path="",
orca_process_profile_path="",
orca_default_filament_profile_path="",
orca_profile_search_paths=[],
volume_fraction_materials={},
material_defs_path="",
)
```
| Option | Meaning |
| ------ | ------- |
| `filaments` | Physical filament slots and colors. Each dictionary may include `slot`, `color_hex`, `filament_settings_id`, `filament_id`, `filament_profile_path`, and `nozzle_diameter_mm`. |
| `max_palette_size` | Maximum generated `COLOR_RGB` palette size or `VOLUME_FRACTIONS` recipe-region count. |
| `min_component_percent` | Minimum component percentage kept in generated mixed recipes. Tiny components are dropped and the remaining weights are normalized. |
| `max_recipe_components` | Maximum physical filaments allowed in one mixed recipe. |
| `direct_physical_delta_e` | DeltaE threshold for assigning a `COLOR_RGB` target directly to a physical filament instead of creating a mixed recipe. |
| `region_overlap_mm` | Small overlap between generated FullSpectrum sub-parts to avoid visible cracks between separately meshed regions. |
| `base_project_settings_path` | Optional Orca project settings JSON to merge before compiler-controlled FullSpectrum keys are written. |
| `orca_machine_profile_path` | Optional Orca machine profile path or resolvable profile name. |
| `orca_process_profile_path` | Optional Orca process profile path or resolvable profile name. |
| `orca_default_filament_profile_path` | Optional default filament profile path or resolvable profile name. |
| `orca_profile_search_paths` | Additional directories searched for Orca JSON profiles. |
| `volume_fraction_materials` | Material-name to physical-slot mapping for direct `VOLUME_FRACTIONS` export, such as `{"red": 1, "blue": 2}`. |
| `material_defs_path` | Optional `MaterialDefs` JSON path. Empty uses the bundled default material definitions. |
### FullSpectrum Limitations
- FullSpectrum is not true molten filament mixing. It is an optical and geometric approximation based on alternating physical filaments.
- The reachable color gamut depends on the loaded filaments, translucency, layer height, top/bottom shell behavior, and surface orientation.
- OpenVCAD emits a finite number of mesh regions. More regions can preserve more variation, but they also increase project complexity.
- Sloped surfaces, small details, top layers, and short regions can show different color behavior than tall vertical walls.
- Stock slicers may ignore or reject FullSpectrum metadata. Use the documented FullSpectrum fork unless you have verified another slicer version.
- `max_recipe_components` and `min_component_percent` intentionally bound recipe complexity. Some requested colors or material blends cannot be represented within those limits.