Generators
A generator is a parametric CAD model — a function that takes user-supplied parameters and produces a customized artifact.
While a plain @artifact function always builds the same model, a generator lets end-users on MakerRepo.com tweak dimensions, counts, or any other value and get a new model built on demand.
Generators use the @customizable decorator from mr together with Pydantic models to define, validate, and constrain the parameters.
Defining parameters
Parameters are defined as a Pydantic BaseModel. Each field becomes a knob the user can adjust.
Use Pydantic's Field to set defaults and constraints (e.g. gt=0 to require positive values):
from pydantic import BaseModel
from pydantic import Field
class BoxParameters(BaseModel):
width: float = Field(default=10, gt=0)
height: float = Field(default=10, gt=0)
length: float = Field(default=10, gt=0)
Because parameters are just Pydantic models, you get automatic validation, serialization, and clear error messages for free.
The @customizable decorator
Mark a function as a generator with @customizable.
The function must accept a single parameters argument typed to your Pydantic model and return a Build123D object:
from build123d import *
from mr import customizable
from pydantic import BaseModel
from pydantic import Field
class BoxParameters(BaseModel):
width: float = Field(default=10, gt=0)
height: float = Field(default=10, gt=0)
length: float = Field(default=10, gt=0)
@customizable(sample_parameters=BoxParameters(width=10, height=10, length=10))
def main(parameters: BoxParameters):
box = Box(parameters.width, parameters.height, parameters.length)
return box
@customizable arguments
| Argument | Type | Description |
|---|---|---|
desc |
str |
Optional. Detailed description of the generator, in Markdown format. You can also provide the description via the function's docstring. If both a docstring and desc are given, desc is used. |
short_desc |
str |
Optional. A short description of the generator, for lists and previews. Should be less than 128 characters. |
sample_parameters |
BaseModel |
Optional. An instance of the parameter model used to build a snapshot of the model for preview. If not provided, no snapshot will be taken. |
Custom parameter validation
In most cases, Pydantic's built-in JSON Schema compatible rules — such as gt, lt, ge, le, min_length, max_length, and pattern — are sufficient for validating generator parameters.
However, sometimes the validation logic is more complex than simple per-field checks.
For example, imagine a post generator that lets the user cut notches at different positions along the post. You need to ensure that none of the given notch positions overlap — something that cannot be expressed with standard field constraints alone.
For situations like this, you can perform custom validation inside your generator function and raise a GeneratorValidationError with detailed error information:
from build123d import *
from mr import customizable
from mr.exceptions import FieldError
from mr.exceptions import GeneratorValidationError
from pydantic import BaseModel
from pydantic import Field
class Notch(BaseModel):
position: float = Field(default=0, ge=0)
width: float = Field(default=5, gt=0)
class PostParameters(BaseModel):
height: float = Field(default=100, gt=0)
notches: list[Notch] = Field(default_factory=list)
@customizable(sample_parameters=PostParameters())
def main(parameters: PostParameters):
for i, a in enumerate(parameters.notches):
for j, b in enumerate(parameters.notches):
if i >= j:
continue
a_end = a.position + a.width
b_end = b.position + b.width
if a.position < b_end and b.position < a_end:
raise GeneratorValidationError(
"Notch positions must not overlap",
fields=[
FieldError(
path=("notches", str(i)),
message=f"Overlaps with notch {j}",
),
FieldError(
path=("notches", str(j)),
message=f"Overlaps with notch {i}",
),
],
)
# ... build the post with notches ...
GeneratorValidationError accepts one or more general error messages and an optional list of FieldError instances for field-level errors.
Each FieldError takes a path tuple pointing to the problematic field (following JSON path conventions) and a human-readable message.
MakerRepo uses these structured errors to display clear feedback in the web UI, highlighting exactly which fields need attention.
How it works on MakerRepo.com
- Push your code — CI discovers every
@customizablefunction and registers it as a generator. - Sample build — MakerRepo builds the model with the
sample_parametersyou provided and displays a snapshot in the repository UI. - Customize — Visitors can adjust the parameters in the web UI and request a new build with their values.
Performance considerations
Generating a model from scratch with Build123D can take a noticeable amount of time, depending on the complexity of the model and the CAD operations involved. Since the generator feature is still in its early stages, we have not yet invested heavily in optimizing build times. However, MakerRepo does cache the generated model for identical parameters — if someone requests a build with the exact same parameter values that have been built before, the cached result is returned immediately.
In future releases, we plan to introduce features to speed up generation significantly, such as:
- B-Rep caching — caching intermediate boundary representations so unchanged parts of a model don't need to be recomputed.
- Live in-memory models — keeping a running model instance in memory so that parameter changes can be applied incrementally rather than rebuilding from scratch.
- Pre-built models — pre-building and caching models for common parameter combinations so that they can be served instantly.
Besides these platform improvements, generator authors can also improve performance through modeling strategy: how you structure and order CAD operations has a direct impact on build time. For example, some operations (such as fillets) are much more expensive when applied at scale; building a single “tool” shape with the desired details and then patterning or reusing it can be far faster than repeating expensive operations on many edges. For a concrete Build123d example and more tips, see CAD modeling strategy for performance (Iteration3D).
Running generators locally
You can build and serve generators on MakerRepo.com, or run them locally (and host them on your own machine) using MakerRepo CLI (our open-source CLI tool). Use the CLI to list, view, export, and snapshot generators from the command line.
Full example
See the generator_example.py file in the open-models repository for a working example.