Configuration
Most users need to create a single package, containing one or more parts, and maybe an assembly.
That is achieved by creating a configuration file (partcad.yaml
) that defines the package and
declares all parts and assemblies it contains.
PartCAD aims to maintain three ways to manage the configuration files:
Manual configuration file edits.
PartCAD aims to maintain a simple and intuitive syntax for configuration files. It is currently expected that PartCAD users edit the configuration file manually immediately or after a few hours of using PartCAD, as the other ways to maintain the configuration files are not mature enough yet to meet the needs of advanced users.
Command line interface.
PartCAD aims to provide a command line interface for all possible configuration changes to any section or field. However, there is currently a very limited set of commands implemented: mostly the very first operations a new PartCAD user would need.
Graphical user interface.
PartCAD aims to provide a Visual Studio Code plugin with a graphical interface to allow changes to any configuration file sections or fields. However, there is currently a very limited set of operations implemented: mostly the very first operations a new PartCAD user would need.
The complete syntax of configuration files is described below.
Packages
The package is defined using the configuration file partcad.yaml
placed
in the package folder.
Besides the package properties and, optionally, a list of imported dependencies,
partcad.yaml
declares parts and assemblies contained in this package.
name: <(optional) for advanced users, the assumed package path for standalone development>
desc: <(optional) description>
url: <(optional) package or maintainer's url>
poc: <(optional) point of contact, maintainer's email>
partcad: <(optional) required PartCAD version spec string>
pythonVersion: <(optional) python version for sandboxing if applicable>
pythonRequirements: <(python scripts only) the list of dependencies to install>
import:
<dependency-name>:
desc: <(optional) textual description>
type: <(optional) git|tar|local, can be guessed by path or url>
path: <(local only) relative path to the package>
url: <(git|tar only) URL of the package>
relPath: <(git|tar only) relative path within the repository>
revision: <(git only) the exact revision to import>
includePaths: <(optional) Jinja2 include path>
parts:
<part declarations, see below>
assemblies:
<assembly declarations, see below>
Dependencies
Here are some examples of references to imported packages:
Method |
Example |
---|---|
Local files
(in the same
source code
repository)
|
import:
other_directory:
path: ../../other
|
GIT repository
|
import:
other_repo:
url: https://github.com/openvmp/partcad
relPath: examples # where to "cd"
|
Hosted tar ball
|
import:
other_archive:
url: https://github.com/openvmp/partcad/archive/7544a5a1e3d8909c9ecee9e87b30998c05d090ca.tar.gz
|
Sketches
Sketches are declared in partcad.yaml
using the following syntax:
sketches:
<sketch-name>:
type: <basic|dxf|svg|cadquery|build123d>
desc: <(optional) textual description>
path: <(optional) the source file path, "{sketch name}.{ext}" otherwise>
# ... type-specific options ...
Basic
The basic sketches are defined using the following syntax:
sketches:
<sketch-name>:
type: basic
desc: <(optional) textual description>
# The below are mutualy exclusive options
circle: <(optional) radius>
circle: # alternative syntax
radius: <radius>
x: <(optional) x offset>
y: <(optional) y offset>
square: <(optional) edge size>
square: # alternative syntax
side: <edge size>
x: <(optional) x offset>
y: <(optional) y offset>
rectangle: <(optional)>
side-x: <x edge size>
side-y: <y edge size>
x: <(optional) x offset>
y: <(optional) y offset>
There must be only one field circle
, square
or rectangle
.
DXF
A sketch can be defined using a DXF file. Such sketches are declared using the following syntax:
sketches:
<sketch-name>:
type: dxf
desc: <(optional) textual description>
path: <(optional) filename> # otherwise "<sketch-name>.dxf"
tolerance: <(optional) tolerance used for merging edges into wires>
include: <(optional) a layer name or a list of layer names to import>
exclude: <(optional) a layer name or a list of layer names not to import>
SVG
A sketch can be defined using an SVG file. Such sketches are declared using the following syntax:
sketches:
<sketch-name>:
type: svg
desc: <(optional) textual description>
path: <(optional) filename> # otherwise "<sketch-name>.svg"
use-wires: <(optional) boolean>
use-faces: <(optional) boolean>
ignore-visibility: <(optional) boolean>
flip-y: <(optional) boolean>
CAD Scripts
See the “CAD Scripts” section in the “Parts” chapter below.
Interfaces
Interfaces are declared in partcad.yaml
using the following syntax:
interfaces:
<interface name>:
abstract: <(optional) whether the interface is abstract>
desc: <(optional) textual description>
path: <(optional) the source file path, "{interface name}.{ext}" otherwise>
inherits: # (optional) the list of other interfaces to inherit from
<parent interface name>: <instance name>
<other interface name>: # instance name is implied to be empty ("")
<yet another interface>:
<instance name>: <OCCT Location object> # e.g. [[0,0,0], [0,0,1], 0]
ports: # (optional) the list of ports in addition to the inherited ones
<port name>: <OCCT Location object> # e.g. [[0,0,0], [0,0,1], 0]
<other port name>: # [[0,0,0], [0,0,1], 0] is implied
<another port name>:
location: <OCCT Location object> # e.g. [[0,0,0], [0,0,1], 0]
sketch: <(optional) name of the sketch used for visualization>
parameters:
moveX: # (optional) offset along X
min: <(optional) min value>
max: <(optional) max value>
default: <(optional) default value>
moveY: [<min>, <max>, <(optional) default>] # alternative syntax
moveZ: ... # (optional) offset along Z
turnX: ... # (optional) rotation around X
turnY: ... # (optional) rotation around Y
turnZ: ... # (optional) rotation around Z
<custom parameter name>: # (optional) offset or rotation with an arbitrary direction vector
min: ...
max: ...
default: ...
type: <move (default)|turn>
dir: [<x>, <y>, <z>] # the vector to move along or rotate around
Abstract interfaces
Abstract interfaces can’t be implemented by parts directly. They also can’t be used for mating with other interfaces. They are a convinence feature so that a property can be implemented once but inherited mutiple times by all child interfaces.
Port visualization
When a part or an assembly is rendered (in a GUI or when exported to a file), the ports can be visualized. When ports are visualized, each port looks like a coordinate system (3D location, direction and rotation) and, optionally, as a 2D image of an alleged “boundary” (or “siluette”) of the port.
It is recommended to define the port boundary at all times. Here is an example how to define the port boundary using a primitive sketch:
sketches:
m3:
type: basic
circle: 3.0
interfaces:
m3:
ports:
m3:
sketch: m3
Here is how it will get visualized:

Port matching
Each port has the coordinates of the logical center of the port and the direction (orientation) of the port. Whenever two ports are meant to connect without any offset or angle (e.g. male and female connectors), their coordinates should match and their directions should be opposite (rotated 180 degrees around [1, 1, 0]). The suggested convention is to use the Z-axis (blue) as the main direction. Male ports should have the Z-axis pointing outwards, while female ports should have the Z-axis pointing inwards.
Matching multiple ports
Sometimes there are multiple interchangeable ports within one interface. For example, take a look at the NEMA-17 mounting ports:

It is desired that any mounting port of the motor can be connected to any mounting port of the bracket. That can be achieved by orienting the ports in a circular direction. See how the X-axis (red) is pointing to the next port clockwise (right-hand rule). If any pair of ports is aligned then all three other port pairs are aligned too.

Interface parameters
Each interface may declare parameters to allow parametrized mating (e.g. a slotted hole allows for a mating at an offset within the size of the slot). There is a list of predefined parameters that are easy to use:
moveX, moveY, moveZ: offset along X, Y, and Z axes
turnX, turnY, turnZ: rotation around X, Y, and Z axes
interfaces:
<interface name>:
parameters:
moveX: # (optional) offset along X
min: <(optional) min value>
max: <(optional) max value>
default: <(optional) default value>
However custom parameters can be defined to use an arbitrary direction vector and an arbitary offset or rotation.
interfaces:
<interface name>:
parameters:
<custom parameter name>:
min: ...
max: ...
default: ...
type: <move (default)|turn>
dir: [<x>, <y>, <z>] # the vector to move along or rotate around
When the interface is inherited or used to connect parts, the parameter values get resolved and applied as inheritance or connection coordinate offsets.
# Interface inheritance with parameters
interfaces:
<interface name>:
# ...
inherits: # (optional) the list of other interfaces to inherit from
<parent interface name>:
<instance name>:
params:
moveX: 10
# Interface implementation with parameters
parts:
<part name>:
# ...
implements: # (optional) the list of other interfaces to inherit from
<interface name>:
<instance name>:
params: { moveX: 10 }
# Assembly YAML connection example
links:
- part: <target part>
- part: <source part>
connect:
name: <target part>
toParams:
turnZ: 1.57
Interface examples
See the feature_interfaces example for more information.
Parts
Parts are declared in partcad.yaml
using the following syntax:
parts:
<part name>:
type: <openscad|cadquery|build123d|ai-openscad|ai-cadquery|ai-build123d|step|stl|3mf>
desc: <(optional) textual description, also used by AI>
path: <(optional) the source file path, "{part name}.{ext}" otherwise>
# ... type-specific options ...
offset: <OCCT Location object, e.g. "[[0,0,0], [0,0,1], 0]">
# The below syntax is similar to the one used for interfaces,
# with the only exception being the word "implements" instead of "inherits".
implements: # (optional) the list of interfaces to implement
<interface name>: <instance name>
<other interface name>: # instance name is implied to be be empty ("")
<yet another interface>:
<instance name>: <OCCT Location object> # e.g. [[0,0,0], [0,0,1], 0]
ports: # (optional) the list of ports in addition to the inherited ones
<port name>: <OCCT Location object> # e.g. [[0,0,0], [0,0,1], 0]
<other port name>: # [[0,0,0], [0,0,1], 0] is implied
<another port name>:
location: <OCCT Location object> # e.g. [[0,0,0], [0,0,1], 0]
sketch: <(optional) name of the sketch used for visualization>
Depending on the type of the part, the configuration may have different options.
CAD Scripts
Define parts with CodeCAD scripts using the following syntax:
parts:
<part name>:
type: <openscad|cadquery|build123d>
cwd: <alternative current working directory>
showObject: <(optional) the name of the object to show using "show_object(...)">
patch:
# ...regexp substitutions to apply...
"patern": "repl"
pythonRequirements: <(python scripts only) the list of dependencies to install>
parameters:
<param name>:
type: <string|float|int|bool>
enum: <(optional) list of possible values>
default: <default value>
Example |
Configuration |
Result |
---|---|---|
parts:
src/cylinder:
type: cadquery
# type: build123d
|
||
OpenSCAD script
in
cube.scad |
parts:
cube:
type: scad
|
AI Generated CAD Scripts
Generate OpenSCAD, CadQuery or build123d scripts with Generative AI using the following syntax:
parts:
<part name>:
type: <ai-openscad|ai-cadquery|ai-build123d>
provider: <google|openai|ollama, the model provider to use>
model: <(optional) the model to use>
tokens: <(optional) the limit of token context>
temperature: <(optional) the temperature LLM parameter>
top_p: <(optional) the top_p LLM parameter>
top_k: <(optional, openai|ollama) the top_k LLM parameter>
images: <(optional) contextual images as input for AI>
- <image path>
The following models are recommended for use:
Provider |
Model |
---|---|
|
|
openai |
|
ollama |
|
Example |
Result |
---|---|
parts:
cube:
type: ai-cadquery
provider: google
desc: A cube
|
CAD Files
Define parts with CAD files using the following syntax:
parts:
<part name>:
type: <step|stl|3mf>
binary: <(stl only) use the binary format>
Example |
Configuration |
Result |
---|---|---|
parts:
screw:
type: step
# type: stl
# type: 3mf
|
References
It is also possible to declare new parts by referencing other parts that are already defined elsewhere.
Method |
Configuration |
Description |
---|---|---|
Alias |
parts:
<alias-name>:
type: alias
source: </path/to:existing-part>
|
Create a shallow
clone of the
existing part.
For example, to
make it easier to
reference it locally.
|
Enrich |
parts:
<enriched-part-name>:
type: enrich
source: </path/to:existing-part>
with:
<param1>: <value1>
<param2>: <value2>
offset: <OCCT-Location-obj>
|
Create an opinionated
alternative to the
existing part by
initializing some of
its parameters, and
overriding any of its
properties. For
example, to avoid
passing the same set
of parameters many times.
|
Other Part Types
Other methods to define parts are coming soon (e.g. SDF). Please, express your interest in support for other formats by filing a corresponding issue on GitHub or sending an email to openvmp@proton.me.
Parameters
Each part may have a list of parameters that are passed into the scripts to
modify the part.
The parameters can be of types string
, float
, int
and bool
.
The parameter values can be restricted by specifying the list of possibe values
in enum
.
The initial parameter value is set using default
.
parts:
<part name>:
# ...
parameters:
<param name>:
type: <string|float|int|bool>
enum: <(optional) list of possible values>
default: <default value>
There are several parameter names that are reserved for values used in
visualisation, simulation calculations and, if applicable, manufacturing
(also referred to as MCFTT prameters
using their first letters):
material
Must point at an object of type
material
. Some of them are defined in/pub/std/manufacturing/material
. When a request is made to a manufacturing API, a close enough material is selected from the materials provided by the manufacturer. The responsibility to select the right material is on the implementation of the manufacturing API (theprovider
object in PartCAD).Not implemented yet. Use hardcoded values for now.
color
Not implemented yet. Use color names for now.
finish
Optional. Can be omitted for no finish.
Not implemented yet.
texture
Optional. Can be omitted for no texture.
Not implemented yet.
tolerance
Optional. Can be omitted for a claim to perfect precision during manufacturing.
Not implemented yet.
If the part has variable MCFTT parameters depending on the surface, then either this part must be broken down into multiple parts, or the values must be derived from CAD files/scripts (not implemented yet). In the latter case the part will not be eligible for manufacturing features, unless a specific manufacturing service provider recognises (vendor,SKU) values and have received corresponding manufacturing instructions out-of-band.
The MCFTT parameters are not required and have no impact on parts that have
vendor
and sku
set and that are procured using providers of the type
store
.
Assemblies
Assembly YAML
Assemblies are declared in partcad.yaml
using the following syntax:
assemblies:
<assembly name>:
type: assy # Assembly YAML
path: <(optional) the source file path>
parameters: # (optional)
<param name>:
type: <string|float|int|bool>
enum: <(optional) list of possible values>
default: <default value>
offset: <OCCT Location object, e.g. "[[0,0,0], [0,0,1], 0]">
Here is an example:
The example above shows an assembly created using Assembly YAML
.
Other methods to define assemblies are coming soon (e.g. using CadQuery
or build123d
).
The assembly file syntax is described in the Assembly YAML
section of this documentation.
References
It is also possible to declare assemblies by referencing other assemblies that are
already defined elsewhere. Unfortunately, enrich
(documented in the Parts section) is not yet implemented for
assemblies.
Method |
Configuration |
Description |
---|---|---|
Alias |
assemblies:
<alias-name>:
type: alias
source: </path/to:existing-assembly>
|
Create a shallow
clone of the
existing assembly.
For example, to
make it easier to
reference it locally.
|
Providers
Providers are declared in partcad.yaml
using the following syntax:
providers:
<provider name>:
type: <store|manufacturer|enrich>
desc: <(optional) textual description>
# ... type-specific options ...
parameters: # (optional)
<param name>:
type: <string|float|int|bool>
enum: <(optional) list of possible values>
default: <default value>
enrich
providers are just references to other providers with some prameters
modified to specific values.
store
and manufacturer
providers are implemented as Python scripts.
These scripts are invoked using the runpy
module which allows to pass input
as values of global objects. The outputs are also extracted from the value of
global objects.
The input is passed as the dictionary request
.
The output is extracted from the dictionary output
Store
store
providers use the following input and output values:
request[“parameters”]: The configuration parameters of the provider.
request[“api”]: The API method called.
request[“api”] == “caps”
Get capabilities of this provider. Currently PartCAD does not use capabilities for
store
providers.output: no output is expected
request[“api”] == “avail”
Check availability of the specific part.
request[“vendor”]: the vendor of the part
request[“sku”]: the SKU of the part
request[“count”]: the requested quantity of the parts
request[“count_per_sku”]: the known number of parts per SKU
output[“available”]: boolean, whether it is available in this store
request[“api”] == “quote”
Get a quote for the specific cart of parts. Quote API is the core of the provider. It is expected to return the price of a cart.
request[“cart”][“parts”]: the dictionary of parts
request[“cart”][“parts”][<id>][“vendor”]: the vendor of the part
request[“cart”][“parts”][<id>][“sku”]: the SKU of the part
request[“cart”][“parts”][<id>][“count”]: the requested quantity of the parts
request[“cart”][“parts”][<id>][“count_per_sku”]: the known number of parts per SKU
output[“price”]: the total price of the cart
output[“cartId”]: the id of the cart (to be used for the order later)
request[“api”] == “order”
Order the specific quote. Order API does not need to be implemented as there is no infrastructure for payments yet.
request[“cartId”]: the id of the cart to be purchased
Manufacturer
manufacturer
providers use the following input and output values:
request[“parameters”]: The configuration parameters of the provider.
request[“api”]: The API method called.
request[“api”] == “caps”
Get capabilities of this provider.
output[“materials”]: the dictionary of supported materials
{ "/pub/std/manufacturing/material/plastic:pla": { "colors": [{"name": "red"}], "finishes": [{"name": "none"}] } }
output[“format”]: the list of supported formats (e.g. [“step”])
request[“api”] == “quote”
Get a quote for the specific cart of parts. Quote API is the core of the provider. It is expected to return the price of a cart.
request[“cart”][“parts”]: the dictionary of parts
request[“cart”][“parts”][<id>][“format”]: the format of the binary (e.g. “step”)
request[“cart”][“parts”][<id>][“binary”]: the geometry data
output[“price”]: the total price of the cart
output[“cartId”]: the id of the cart (to be used for the order later)
request[“api”] == “order”
Order the specific quote. Order API does not need to be implemented as there is no infrastructure for payments yet.
request[“cartId”]: the id of the cart to be purchased
Common Options
The following options are shared by all or some shapes: sketches, parts and assemblies.
Files
For shape types that are defined using a source file, the default file path is the name of the shape plus the extension of that file type.
An alternative file path (absolute or relative to the package path) can be defined explicitly using the path parameter:
parts:
part-name:
type: step
path: alternatative-path.step
When the source file is not present in the package source repository but needs to be pulled from a remote location, the following options can be used:
fileFrom: url
fileUrl: <url to pull the file from>
# fileCompressed: <(optional) whether the file needs to be decompressed before use>
# fileMd5Sum: <(optional) the MD5 checksum of the file>
# fileSha1Sum: <(optional) the SHA1 checksum of the file>
# fileSha2Sum: <(optional) the SHA2 checksum of the file>