Using the Cadpy Assembly Composition API for Multi-Part CAD Models
The cadpy assembly composition API builds hierarchical JSON representations of multi-part CAD assemblies from STEP files or GLB topology, enabling programmatic generation of complex mechanical designs.
The earthtojake/text-to-cad repository provides the cadpy package, a low-level Python toolkit for procedural CAD generation. At its core, the assembly composition API—implemented across cadpy/assembly_composition.py, cadpy/assembly_spec.py, and cadpy/generation.py—enables developers to aggregate individual parts into unified assemblies with preserved spatial transforms and hierarchical relationships.
Architecture of the Assembly Composition System
The API follows a three-layer architecture that separates data description from scene construction and export orchestration.
Assembly Specification Layer
The assembly specification defines the structural blueprint of your multi-part model. Defined in cadpy/assembly_spec.py, the AssemblySpec dataclass stores component references, local coordinate transforms, and nested sub-assembly relationships. Each component is represented by an AssemblyComponent instance that points to a source STEP file and defines its orientation in 3D space via a 12-element affine transform matrix.
Assembly Composition Layer
The composition engine in cadpy/assembly_composition.py translates specifications into traversable scene graphs. Two primary builders handle different source topologies:
build_linked_assembly_composition– ResolvesAssemblySpectrees into linked hierarchies where each node references its original STEP source file.build_native_assembly_composition– Reconstructs assemblies from existing GLB files that already contain embedded occurrence data.
Internal helpers such as _linked_instance_node and _native_occurrence_node manage the conversion of raw topology into JSON-ready node dictionaries.
Generation Pipeline Layer
The orchestration layer in cadpy/generation.py provides _assembly_composition_for_spec, which automatically selects the appropriate builder based on the specification's kind field. This function returns a complete scene dictionary that can be passed directly to STEP export utilities or viewer payloads.
Building a Multi-Part Assembly Step-by-Step
Step 1: Define the Assembly Specification
Create an AssemblySpec that references individual STEP files and defines their relative positioning. In cadpy/assembly_spec.py, the specification acts as the single source of truth for assembly structure.
from pathlib import Path
from cadpy.assembly_spec import AssemblySpec, AssemblyComponent
# Define a root assembly containing two translated parts
spec = AssemblySpec(
kind="assembly",
assembly_path=Path("models/assembly_example"),
step_path=None, # Linked composition does not require a root STEP
components=[
AssemblyComponent(
source_path=Path("models/part_a.step"),
instance_id="part_a",
transform=[1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0], # Identity matrix
),
AssemblyComponent(
source_path=Path("models/part_b.step"),
instance_id="part_b",
transform=[1, 0, 0, 10, 0, 1, 0, 0, 0, 0, 1, 0], # Translate 10mm on X
),
],
)
Step 2: Build the Linked Composition
Call build_linked_assembly_composition from cadpy/assembly_composition.py to resolve the specification into a hierarchical node structure. This function requires a topology manifest—typically loaded from a GLB file—and a mapping of STEP paths to their specifications.
from pathlib import Path
from cadpy.assembly_composition import build_linked_assembly_composition
from cadpy.glb_topology import read_step_topology_manifest_from_glb
from cadpy.render import part_glb_path, relative_to_repo
# Load the GLB topology manifest for the root assembly container
topology_path = part_glb_path(Path("models/assembly_example.glb"))
topology_manifest = read_step_topology_manifest_from_glb(topology_path)
# Map source STEP files to their specifications for nested resolution
entries_by_step_path = {
Path("models/part_a.step"): spec,
Path("models/part_b.step"): spec
}
composition = build_linked_assembly_composition(
cad_ref=relative_to_repo(Path("models/assembly_example")),
topology_path=topology_path,
topology_manifest=topology_manifest,
assembly_spec=spec,
entries_by_step_path=entries_by_step_path,
read_assembly_spec=lambda p: spec, # Resolver function for nested specs
mesh_path=topology_path,
)
Step 3: Generate the Scene with the Pipeline
Use _assembly_composition_for_spec from cadpy/generation.py to automate builder selection and scene assembly. This internal helper handles the conditional logic between linked and native composition modes.
from cadpy.generation import _assembly_composition_for_spec
# Payload defines the assembly type and root path
payload = {"kind": "assembly", "assemblyPath": "models/assembly_example"}
# Generate the complete scene dictionary with root node and children
scene = _assembly_composition_for_spec(
spec=spec,
cad_ref="assembly_example",
topology_path=topology_path,
topology_manifest=topology_manifest,
entries_by_step_path=entries_by_step_path,
read_assembly_spec=lambda p: spec,
mesh_path=topology_path,
)
# The scene dict contains a 'root' node with nested children for part_a and part_b
Step 4: Export to STEP Format
Feed the composed scene to export_assembly_step_scene in cadpy/step_export.py to generate the final CAD file. This function handles mesh URL resolution, topology validation, and hash computation for downstream tools.
from cadpy.step_export import export_assembly_step_scene
from pathlib import Path
export_assembly_step_scene(
assembly_spec=spec,
scene=scene,
output_path=Path("out/assembly_example.step"),
text_to_cad_entry_kind="assembly",
)
Key Implementation Files
The assembly composition system spans four critical modules in the earthtojake/text-to-cad codebase:
cadpy/assembly_spec.py– DefinesAssemblySpecandAssemblyComponentdataclasses, plusread_assembly_specfor JSON/YAML deserialization.cadpy/assembly_composition.py– Implementsbuild_linked_assembly_compositionandbuild_native_assembly_composition, along with private helpers_linked_instance_nodeand_native_occurrence_nodefor node construction.cadpy/generation.py– Contains_assembly_composition_for_specfor pipeline orchestration and_write_assembly_step_payloadfor final file serialization.cadpy/step_export.py– Providesexport_assembly_step_sceneandread_step_topology_manifest_from_glbfor topology introspection and STEP generation.
Summary
- The cadpy assembly composition API transforms discrete STEP files into unified, hierarchical CAD assemblies through a three-stage pipeline.
AssemblySpecdefines the assembly structure, component transforms, and source file references incadpy/assembly_spec.py.build_linked_assembly_compositionconstructs scene graphs by linking external STEP files, whilebuild_native_assembly_compositionprocesses embedded GLB topology._assembly_composition_for_specincadpy/generation.pyorchestrates the build process and prepares data for export.export_assembly_step_scenegenerates the final STEP file with proper topology manifests and mesh references.
Frequently Asked Questions
What is the difference between linked and native assembly composition?
Linked composition (build_linked_assembly_composition) assembles parts by referencing external STEP files defined in an AssemblySpec, making it ideal for aggregating discrete components. Native composition (build_native_assembly_composition) reconstructs assemblies from GLB files that already contain internal occurrence trees, useful for reprocessing existing models. Both methods produce identical JSON scene graphs but source their topology data differently.
How do I specify the position of individual parts in an assembly?
Each AssemblyComponent accepts a 12-element transform list representing a 4×3 affine transformation matrix in row-major order. The first nine elements define the rotation/scale matrix, while the final three elements specify the translation vector in millimeters. This transform places the component relative to the parent assembly's coordinate system.
Can I nest assemblies within other assemblies using this API?
Yes. The entries_by_step_path mapping allows build_linked_assembly_composition to resolve nested AssemblySpec instances. When a component's source_path points to another assembly rather than a part, the resolver function (passed as read_assembly_spec) returns the sub-assembly specification, enabling arbitrary depth in the scene hierarchy.
What file formats does the assembly composition API support for export?
The primary export format is STEP (.step), generated via export_assembly_step_scene in cadpy/step_export.py. The API also produces intermediate GLB payloads for viewer visualization, handled by part_glb_path utilities in cadpy/glb.py. The composition itself is format-agnostic, returning a JSON tree that can be serialized to either format or streamed to web viewers.
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →