Your first model
A single pass from an empty interpreter to a saved, parametric document: a document, a parameter, a second object that depends on it, a recompute, and the save that keeps it.
Generated page.
tools/userdocs.pywrites it fromtools/workflows/00_first_model.py. Edit the workflow, not this page;python3 tools/userdocs.py --checkfails when the two disagree.
Requires: the FreeCAD facade; no workbench module and no GPU.
1. Import the application
Everything starts with the FreeCAD module. In FerroCAD it is a Rust-backed implementation of the same module upstream FreeCAD ships, so the code in this tutorial is ordinary FreeCAD Python.
import FreeCAD
| Read back | Value |
|---|---|
| Version | 0.1.3 |
| Backend | ferrocad |
2. Make a document
A document is the file you are building. newDocument creates it, makes it active, and returns it. Nothing is on disk yet.
doc = FreeCAD.newDocument('FirstModel')
| Read back | Value |
|---|---|
| Active document | FirstModel |
3. Add a parameter
Objects are created by type name. App::FeaturePython is the generic scripted object; properties are added afterwards, each with a group and a description so a property editor has something to show.
parameters = doc.addObject("App::FeaturePython", "Parameters")
parameters.addProperty(
"App::PropertyLength", "Length", "Model", "The one number that drives it"
)
parameters.Length = "20 mm"
| Read back | Value |
|---|---|
| Parameters.Length | 20 mm |
4. Make something depend on it
A second object can read the first one through an expression. The expression is stored in the document, which is what makes the model parametric: the value follows the input on every recompute.
result = doc.addObject("App::FeaturePython", "Result")
result.addProperty("App::PropertyLength", "Width", "Model", "Derived width")
result.setExpression("Width", "Parameters.Length * 3")
doc.recompute()
| Read back | Value |
|---|---|
| Result.Width | 60 mm |
| Result.State | [“Up-to-date”] |
5. Change the input
Editing the parameter marks the dependent object for recompute. One call updates everything in dependency order — you never tell it what to update.
parameters.Length = "35 mm"
doc.recompute()
| Read back | Value |
|---|---|
| Parameters.Length | 35 mm |
| Result.Width | 105 mm |
6. Save it
saveAs writes the document, including the expression. The path below is a temporary one; in your own script choose a real location. Opening it again gives back the same objects and the same values.
import os, tempfile
path = os.path.join(tempfile.mkdtemp(prefix="ferrocad-tutorial-"), "first.ferrocad")
doc.saveAs(path)
FreeCAD.closeDocument("FirstModel")
reopened = FreeCAD.open(path)
| Read back | Value |
|---|---|
| Objects after reopening | [“Parameters”, “Result”] |
| Width after reopening | 105 mm |
7. Where to go next
That is the whole loop: create, parameterise, recompute, save. The how-to guides take each part further — properties and validation, undo and persistence in detail, and the workbench contracts that put objects on screen.
import shutil
FreeCAD.closeDocument(reopened.Name)
shutil.rmtree(os.path.dirname(path))
| Read back | Value |
|---|---|
| Open documents | [] |