How to Create Assemblies with build123d Joints in the Text-to-CAD Library

The Text-to-CAD library wraps native build123d joint functionality through the AssemblyHelper class, allowing you to define datum frames, connect parts with rigid, revolute, and linear joints, and export complete assemblies to STEP format without directly manipulating build123d APIs.

The earthtojake/text-to-cad repository provides a high-level Python interface for programmatic CAD assembly creation. By leveraging the AssemblyHelper class in viewer/packages/cadpy/src/cadpy/assembly.py, engineers can create complex mechanical assemblies using build123d joints while abstracting away low-level geometric constraints.

Understanding the AssemblyHelper Architecture

The AssemblyHelper class serves as the central orchestrator for assembly creation. It manages part registration, joint definition, and relationship mapping through a declarative API that internally constructs native build123d joint objects.

Core Joint Frame Methods

To establish connection points on individual parts, the helper provides specialized frame methods that return MateTarget objects. These include rigid_frame(), revolute_frame(), linear_frame(), cylindrical_frame(), and ball_frame(), each creating the appropriate build123d joint type at a specified location and orientation.

Connection Utilities

Once frames are defined, methods like connect(), face_to_face(), coaxial(), revolute(), and linear() establish relationships between fixed and moving targets. These utilities automatically invoke _normalize_target to process (part, frame_name) tuples and _joint_for_target to retrieve underlying build123d joint instances from the part's joints mapping, storing the result as a MateRelation.

Step-by-Step: Creating Your First Assembly

Begin by importing the necessary modules and instantiating AssemblyHelper with a unique assembly name.

import build123d
from cadpy.assembly import AssemblyHelper, target

# Initialize the assembly container

assy = AssemblyHelper("my_assembly")

# Add primitive shapes as parts

part_a = assy.add(build123d.Box(20, 10, 5).wrapped, "base")
part_b = assy.add(build123d.Cylinder(5, 30).wrapped, "shaft")

Next, define datum frames on each part where mechanical connections will occur.


# Create a rigid datum at the center of the base

rigid_a = assy.rigid_frame(part_a, "origin", build123d.Location((0, 0, 0)))

# Create a revolute datum aligned with the cylinder's central axis

revolute_b = assy.revolute_frame(
    part_b,
    "axis",
    axis=build123d.Location((0, 0, 1)),
    axis_offset=build123d.Location((0, 0, 0))
)

Finally, connect the frames using the appropriate joint type and positional offset.


# Rigidly attach the shaft to the base with a 5mm vertical offset

assy.connect(
    fixed=rigid_a,
    moving=revolute_b,
    relation="rigid",
    offset=build123d.Location((0, 0, 5))
)

Advanced Joint Types and Relationships

Beyond basic rigid connections, the library supports sophisticated mechanical relationships through specialized mating methods.

Rigid and Revolute Connections

Use assy.connect() with relation="rigid" for fixed attachments where no relative motion occurs. For rotational degrees of freedom, first declare a revolute_frame() on the part to establish the axis of rotation, then use assy.revolute() to constrain the motion between two mating frames.

Linear and Coaxial Mating

For prismatic sliding motion, linear_frame() creates the translational axis on a part, while assy.linear() sets the specific travel position between two frames. The coaxial() convenience method automatically aligns cylindrical features, making it ideal for shaft-and-bearing assemblies without manual axis alignment.


# Define sliding axes on both parts

linear_a = assy.linear_frame(part_a, "slide_a", axis=build123d.Location((1, 0, 0)))
linear_b = assy.linear_frame(part_b, "slide_b", axis=build123d.Location((1, 0, 0)))

# Connect with 10mm of travel

assy.linear(fixed=linear_a, moving=linear_b, position=10.0)

# Or use coaxial alignment for cylindrical features

assy.coaxial(fixed=target(part_a, "axis"), moving=target(part_b, "axis"))

Exporting Assemblies to STEP

The build() method aggregates all child shapes into a build123d.Compound. When no explicit children are supplied, the helper automatically injects assembly_mates metadata—serialized via the private _mate_endpoint_payload utility—into the resulting geometry. This metadata captures each joint's position, orientation, and axis data.

Use export_build123d_step_scene() from viewer/packages/cadpy/src/cadpy/step_export.py to generate the final STEP file containing the assembly structure.


# Generate the compound with embedded joint metadata

final_assembly = assy.build()

# Export to STEP format

from cadpy.step_export import export_build123d_step_scene
export_build123d_step_scene(final_assembly, "my_assembly.step")

The resulting STEP file contains an assemblyMates section that lists each defined joint, its type, and full location data—ready for downstream tools such as CAD viewers or robot simulation pipelines.

Summary

  • The AssemblyHelper class in viewer/packages/cadpy/src/cadpy/assembly.py provides a high-level wrapper around native build123d joints.
  • Frame declaration methods like rigid_frame() and revolute_frame() create local datum references that return MateTarget objects.
  • Connection utilities establish mechanical relationships without requiring direct build123d API calls.
  • The internal _joint_for_target and _mate_endpoint_payload methods handle joint retrieval and serialization.
  • Assemblies export to STEP format with embedded joint metadata via export_build123d_step_scene().

Frequently Asked Questions

What is the AssemblyHelper class in text-to-cad?

The AssemblyHelper class is the primary interface in viewer/packages/cadpy/src/cadpy/assembly.py that abstracts build123d's native joint system. It provides methods to label parts via label_shape, define joint frames, connect components using connect() or face_to_face(), and export complete assemblies, eliminating the need to manually manage build123d's lower-level joint APIs.

How does text-to-cad handle build123d joint serialization?

The library uses the private utility _mate_endpoint_payload to serialize each joint's position, orientation, and axis data into a structured format. When build() is called, this metadata populates the assembly_mates attribute of the resulting Compound, which export_build123d_step_scene() then embeds into the STEP file's assemblyMates section for external compatibility.

Can I use raw build123d joints with AssemblyHelper?

While the helper is designed to abstract build123d joints, you can access the underlying joint objects through the joints dictionary stored on individual parts. The _joint_for_target method retrieves these native objects when establishing connections, ensuring compatibility with the broader build123d ecosystem while maintaining the helper's simplified declarative workflow.

Where are assembly definitions stored in the exported files?

Joint definitions and mate relationships are stored in the assemblyMates metadata section of exported STEP files. This section lists each joint type, its associated parts, and full transformation data including position vectors and rotation matrices, making the assemblies compatible with mechanical CAD viewers and robotic simulation pipelines that parse STEP assembly structures.

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:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →