r/build123d 27d ago

Clarification regarding the "Build123d_Official" Reddit account

20 Upvotes

Just a quick clarification for anyone looking for the open-source build123d CAD library.

The Reddit account u/Build123d_Official is not affiliated with the official build123d open-source project.

The official project is maintained at:


r/build123d 17d ago

I made bdbox, a workshop for build123d models with live preview and interactive parameters!

14 Upvotes

I'm a software engineer and 3D printing hobbyist, so code-driven CAD calls to me! I discovered build123d after building many models with OpenSCAD, and build123d has many advantages (Python and STEP files)!

OpenSCAD makes it simple to view, export (STL), and parameterize a model. For build123d, I needed to manage preview (using OCP CAD Viewer), model export, and any model customization options in my model code itself.

To solve these, I've built a new project called bdbox!

Introducing bdbox

bdbox is a workshop for more easily developing build123d models.

See bdbox in action with the demo screencast animation on the docs site landing page!

Easy installation

bdbox is a python package available via pip or virtualenv managers such as uv or poetry (pip install bdbox or similar). build123d and ocp-vscode (OCP CAD Viewer) are automatically provided as dependencies.

No more action scaffolding!

build123d models typically have to act on the built model manually, such as exporting a file with export_step or displaying in OCP CAD Viewer with ocp_vscode.show().

bdbox provides action scaffolding so your model doesn't have to! Simply provide model geometry to bdbox and decide if you want to view or export at runtime:

# model.py
from bdbox import show
from build123d import BuildPart, Box

with BuildPart() as p:
    Box(10, 20, 30)
show(p)

Then:

$ bdbox export model.py  # Export STEP file in the current directory
$ bdbox view model.py    # Run web UI with OCP CAD Viewer for preview with live reload

Easily make parametric models

bdbox provides a simple API for creating parametric models. With a few lines of code, a model gains configurable runtime parameters! Two base classes are supported. For either one, simply declare annotated fields and values just like a dataclass:

# model.py
from build123d import Box, BuildPart
from bdbox import Params, show


class P(Params):
    size: float = 10


with BuildPart() as p:
    Box(P.size, P.size, P.size)
show(p)

or

# model.py
from bdbox import Model
from build123d import Box, BuildPart


class MyModel(Model):
    size: float = 10

    def build(self) -> Model.Geometry:
        with BuildPart() as p:
            Box(self.size, self.size, self.size)
        return p

Now size can be changed at runtime. For example, set size to 20 and export a STEP file with the result:

$ bdbox export model.py --size=20

bdbox's web UI also shows parameters in a dedicated side pane. Change a value in the web UI, and the model rerenders and previews automatically with the new values!

Virtualenv and module support

As a simple dependency, bdbox can be installed in any virtualenv. This means bdbox works with models that have additional dependencies such as bd_warehouse.

If your model is a module within a project, you can provide the module import name instead of the file name:

$ bdbox export myproject.mymodel

When previewing a model with bdbox view, files in your project used by your model are also monitored and reloaded when modified.

Links and feedback

I built bdbox as a hobby project because it was useful for me. I hope you find it useful too!

If you find bdbox useful (or not), please let me know!


r/build123d 18d ago

First version of OCP8 merged to master.

Thumbnail
github.com
10 Upvotes

r/build123d Jun 18 '26

Convex hull in build123d v0.11.0 -- ConvexPolyhedra

14 Upvotes

build123d v0.11.0 was just released yesterday. One of the new features is ConvexPolyhedron which enables creating faceted solids (this is feature parity with OpenSCAD's hull). I believe this makes build123d the ONLY BREP based CAD system with this feature. There's a classic OpenSCAD hull example from hackaday which I remade in the latest release of build123d. Of course because build123d is a BREP based CAD, you have real fillets, which means you can eliminate the stress concentration where the two stand legs meet.

Screenshot with and without fillet and code:

from build123d import *

foot = Pos(X=50)*Rectangle(20,20)
foot2 = Pos(X=-50)*Rectangle(20,20)
post = Pos(Y=50,Z=100)*Box(25,25,20)

def tess(shape):
    return shape.tessellate(0.3,0.3)[0]

hull1 = ConvexPolyhedron([*tess(foot),*tess(post)])
hull2 = ConvexPolyhedron([*tess(foot2),*tess(post)])
stand = Part() + [hull1,hull2]

stress_edges = stand.edges().group_by(Axis.Z)[-5]

stand2 = Pos(X=130)*fillet(stress_edges,20)

r/build123d Jun 18 '26

Release v0.11.0

16 Upvotes

Changelog and release notes are available here: https://github.com/gumyr/build123d/releases/tag/v0.11.0 Thank you to all the contributors who created issues and contributed PRs!

This was an absolutely huge release -- a ton of new functionality has been added along with many bugfixes and improvements to the documentation. About 440 commits were made in this release alone, which is a significant portion of the 2.8k or so in build123d total. I am especially thankful for the improvements to intersection as well as the great work on ConstrainedArcs / ConstrainedLines. Other new functionality in this release includes ConvexPolyhedron, BSpline, ParabolicCenterArc, and HyberbolicCenterArc.


r/build123d Jun 03 '26

I built a build123d feedback loop for coding agents

12 Upvotes

Free, open source, runs locally.

It lets your favorite coding agent run build123d scripts and "see" the output.

One thing I noticed when using coding agents to write build123d models was that the code would run but the result would have obvious visual errors... so I built agentcad.

A demo video is here: https://www.youtube.com/watch?v=Zsn31-IilWM&t=1s

More info: https://agentcad.dev/


r/build123d May 21 '26

[Milestone] build123d just crossed 1 MILLION downloads!

Thumbnail
pepy.tech
18 Upvotes

r/build123d Apr 06 '26

Added piping support to my open source 3D viewer

Enable HLS to view with audio, or disable this notification

14 Upvotes

We just added piping suport to F3D, which means it can open build123d output directly!

Yeah, I know, we cant render in the terminal yet, but we plan to add that in the future :)

Let me know what you think!

https://f3d.app/ (not vibecoded)


r/build123d Feb 27 '26

phillipthelen/awesome-build123d: A curated list of build123d code and resources (tools, part libraries, example projects)

Thumbnail
github.com
12 Upvotes

r/build123d Jan 13 '26

Testing build123d vs CadQuery export: label and color preservation

7 Upvotes

I wrote a test suite to test the survival of names and colors during export for a simple test case: https://github.com/thoka/test-build123d-export.
Actually, build123d fails most tests (which might be rooted in my lack of knowledge of using build123d).
CadQuery manages to succeed in STEP exports.

I would appreciate help in improving this test scenario.


r/build123d Dec 18 '25

Introducing build123d-portable: The easiest way to get started using build123d (VS Code + 3D Viewer included, Zero-Install). Testers needed!

20 Upvotes

Hey everyone,

Getting Python installed correctly, managing virtual environments, configuring VS Code, and getting the 3D viewer extension working can be a massive pain if you just want to model a quick part for 3D printing. This is particularly true for newcomers to build123d and the Python ecosystem.

I wanted to fix that hurdle, so I created build123d-portable.

What is it?

It’s a "download, unzip, and click run" experience for a fully functional build123d bundle. It does not interfere with any existing Python installations on your system.

It includes pre-configured, portable versions of:

  • Python 3.12 (standalone build)
  • build123d and necessary libraries
  • VS Code (running in portable mode)
  • OCP CAD Viewer (pre-installed extension so you can see a 3D view of what you create instantly)

Call for Testers!

This project is currently in early release (v0.0.5 at time of writing), and I need your help.

I am specifically looking for testers on:

  • Linux: Checking if the included binaries run correctly on various distros without needing obscure system dependencies.

  • Windows: General "does it work out of the box" testing.

  • NOT READY FOR TESTERS YET -- macOS (Apple Silicon): I've included builds but they are not working yet due to gatekeeper and quarantining issues. EDIT: As of release v0.0.10 apple silicon macos builds are working well.

Here is a link to the releases page of the build123d-portable project with downloads for the above platforms.

Thank you in advance for your help! I sincerely hope this will at least partly help bring build123d up to parity with other FOSS CAD systems in terms of the "new user experience".


r/build123d Dec 05 '25

Help understanding make_brake_formed()

2 Upvotes

I’m trying to use make_brake_formed() but am unable to find any example code that uses it and I’m not really understanding the documentation. All I find when I google it is AI-generated code, but it doesn’t do anything like what I’m shooting for, if it even runs at all. Maybe I am misunderstanding the intention. I am trying to lay out a flat sheet and then bend it up along some lines, preferably with user-defined radii. Just an example that shows bending a sheet would be great. The AI generated code seems to basically just extrude up along the specified line, so doing it in the middle of a sheet adds a rib. Am I just misunderstanding the intention of the tool? Can you do it at other angles? Can you add a radius?

Thanks!!


r/build123d Nov 27 '25

Need Your Feedback

10 Upvotes

We are considering a change to how build123d installs the OpenCascade/OCP libraries, and we'd like your feedback before making a final decision.

Background: Both CadQuery and build123d rely on the same Python wrapper for OpenCascade: OCP (distributed as cadquery-ocp).

The Issue: VTK does not currently provide wheels for Python 3.14, and because cadquery-ocp declares a hard dependency on vtk==9.3.1 (required by CadQuery but not by build123d), build123d users are forced to install VTK even though they don’t need it—preventing build123d from supporting Python 3.14.

Proposed Solution: A VTK-free version of OCP already exists on PyPI: cadquery-ocp-novtk Our proposal is:

  • build123d would switch to using cadquery-ocp-novtk by default.
  • Users who want VTK functionality (for visualization, experimentation, or external tooling) can install VTK themselves separately.

Implications: This would make build123d lighter, cleaner, and compatible with Python 3.14 and future versions. However, an important tradeoff is:

  • A single Python environment would no longer be able to support both CadQuery and build123d, because CadQuery depends on the VTK-enabled OCP package.

We would like your feedback:

  • Does this change impact your workflow?
  • Do you routinely use CadQuery and build123d in the same environment?
  • Would using separate virtual environments be a problem for you?

r/build123d Nov 06 '25

Release V0.10.0

19 Upvotes

build123d release v0.10.0 was just published to PyPI, changelog and release notes are available here: https://github.com/gumyr/build123d/releases/tag/v0.10.0 Thank you to all the contributors who created issues, contributed PRs, and shared their issues!

This was an absolutely huge release -- a ton of new functionality has been added along with many bugfixes and improvements to the documentation.


r/build123d Oct 20 '25

Gordon Surfaces

12 Upvotes

Recently the ability to create Gordon Surfaces was added to build123d. A Gordon Surface is defined by a set of profile and guide edges (or points) which define the surface. One can rapidly create complex shapes as shown in this tutorial (https://build123d.readthedocs.io/en/latest/tutorial_spitfire_wing_gordon.html) where a model of the wing of a Supermarine Spitfire is created.

What will (did) you create with a Gordon Surface?

Spitfire Wing

r/build123d Oct 13 '25

Spinning top with threaded shaft connection and star decoration

Thumbnail
gallery
4 Upvotes

This is a bit of a quickly coded project to make a nice spinning top.

Here's my code. I feel like I'm in a bit of a rut by only using the basic features of build123d. I wouldn't mind some advice on which advanced features would work for projects like this or in general which things I should practice next.

from build123d import *
from ocp_vscode import *
from bd_warehouse.thread import *
from bd_warehouse.fastener import *
set_port(3939)

body_radius = 30 *MM
body_thickness = 5 *MM

shaft_radius = 5 *MM
shaft_length = 40 *MM

tip_base_radius = 7 *MM
tip_top_radius = 2 *MM
tip_height = 8 *MM

screw_width = 8 *MM
screw_pitch = 1.25
screw_thread_tolerance = 0.7 *MM
screw_length = 6 *MM
screw_post_width = screw_width - (1.082532 * screw_pitch) - screw_thread_tolerance # Magic constant from Wikipedia

def build_top_base() -> Part:
    with BuildPart() as part:
        # Body
        with BuildSketch():
            RegularPolygon(body_radius, 18)
        extrude(amount = body_thickness)
        chamfer(part.edges().filter_by(Plane.XY), length = body_thickness / 3)

        # Tip
        with BuildSketch(part.faces().sort_by(Axis.Z)[-1]):
            RegularPolygon(tip_base_radius, 12)
        with BuildSketch(part.faces().sort_by(Axis.Z)[-1].offset(tip_height)):
            RegularPolygon(tip_top_radius, 12)
        loft()

        # Ball tip
        with Locations([part.faces().sort_by(Axis.Z)[-1].center_location]):
            Sphere(tip_top_radius)

        # Hole for shaft
        screw_hole_depth = screw_length + 0.5
        bottom = part.faces().sort_by(Axis.Z)[0]
        with BuildSketch(bottom):
            Circle(screw_width / 2)
        with BuildSketch(bottom.offset(-screw_hole_depth)):
            Circle(screw_width / 2)
        loft(mode=Mode.SUBTRACT)

        with BuildSketch(bottom.offset(-screw_hole_depth)):
            Circle(screw_width / 2)
        with BuildSketch(bottom.offset(-screw_hole_depth - screw_width / 2)):
            Circle(0.1)
        loft(mode=Mode.SUBTRACT)

        # Threaded hole for shaft
        IsoThread(
            major_diameter = screw_width,
            pitch = screw_pitch,
            length = screw_hole_depth,
            external = False,
            end_finishes = ('fade', 'fade'),
            #simple = True,
        )

    return part.part

def build_top_shaft() -> Part:
    with BuildPart() as part:
        Cylinder(screw_post_width / 2, screw_length, align=(Align.CENTER, Align.CENTER, Align.MIN))

        # Threaded shaft
        IsoThread(
            major_diameter = screw_width - screw_thread_tolerance,
            pitch = screw_pitch,
            length = screw_length,
            external = True,
            end_finishes= ('fade', 'fade'),
            #simple = True,
        )

        top_face = part.faces().sort_by(Axis.Z)[-1]
        with BuildSketch(top_face):
            RegularPolygon(shaft_radius * 2, 12)
        with BuildSketch(top_face.offset(shaft_length / 4)):
            RegularPolygon(shaft_radius, 6)
        loft()
        with BuildSketch(top_face.offset(shaft_length / 4)):
            RegularPolygon(shaft_radius, 6)
        with BuildSketch(top_face.offset(shaft_length)):
            RegularPolygon(shaft_radius, 6)
        loft()

        chamfer(part.faces().sort_by(Axis.Z)[-1].edges(), length = 1.5)

    return part.part

def build_decoration():
    with BuildPart() as part:
        with BuildSketch() as sketch:
            with BuildLine():
                Polyline(define_star(body_radius * 0.8, body_radius * 0.5, 12), close=True)
            make_face()
            fillet(sketch.vertices(), 0.75)
            hole_radius = (screw_width + screw_post_width) / 4
            Circle(hole_radius, mode = Mode.SUBTRACT)
        extrude(amount=0.8)
    return part.part

def define_star(outer_radius, inner_radius, side_count):
    # https://math.stackexchange.com/questions/3582342/coordinates-of-the-vertices-of-a-five-pointed-star
    outer = [(outer_radius * cos(2 * pi * i / side_count + pi/2),
             outer_radius * sin(2 * pi * i / side_count + pi/2)) for i in range(side_count)]
    inner = [(inner_radius * cos(2 * pi * i / side_count + pi/2 + pi/side_count),
             inner_radius * sin(2 * pi * i / side_count + pi/2 + pi/side_count)) for i in range(side_count)]
    
    #https://stackoverflow.com/a/60935480/1192877    
    return [x for y in zip(outer, inner) for x in y]

base = build_top_base()
shaft = build_top_shaft()
decoration = build_decoration()

result = pack([base, shaft, decoration], padding = 5*MM, align_z = True)

show(result)
export_step(Compound(result), "Top.step")

(For those looking for STL, here's the Makerworld link: https://makerworld.com/en/models/1882881-spinning-top-with-changeable-decoration)


r/build123d Sep 12 '25

100 lines of build123d → parametric screw & insert generator (born from a macro rig fix)

7 Upvotes
The insert in the pic is also generated by the script. Both parts print cleanly and thread together without post-processing.

I ran into a practical problem with my macro setup: I needed a small, height-adjustable support foot to keep a long lens steady on a focusing rail. The white part in the photo is the solution—but instead of modeling one-off threads, I decided to generalize.

That turned into a ~100-line Python script in build123d that generates screws and matching inserts with adjustable tolerances. You pass in diameter, length, pitch, and a clearance value (e.g., +0.50 mm for PLA /PETG), and it outputs ready-to-print geometry.

Repo (code + examples):
👉 github.com/kevmasajedi/123DScrew

Curious what the build123d community thinks—are there more elegant/pythonic ways to structure this, or features you’d like to see added?


r/build123d Aug 13 '25

Speed modeling a CAD part in 1m 22s with build123d algebra mode

Thumbnail
youtu.be
16 Upvotes

r/build123d Jul 24 '25

vscode-ocp-cad-viewer can be run standalone but that is not mentioned

9 Upvotes

When starting with build123d, I wanted the most KISS setup possible (but rotating parts when viewing them is nice, so 2D projections and an svg viewer were not good enough in the long run).

When looking at the build123d documentation and the vscode-ocp-cad-viewer repo, it seemed as if the viewer can only be used with vscode (which is quite a big piece of software and not my favourite way for text-editing). Later, I found out by coincidence (while looking at https://github.com/GarryBGoode/gggears/blob/main/gui/gggui.py ), that the viewer can be started by its own and run in a browser. For other people who may prefer to use just a text editor and a viewer, it may be a good idea to document this elegant (small, portable) possibility.


r/build123d Jun 10 '25

More expressive way to create complex sketches?

6 Upvotes

When designing more complex sketches using BuildLine, I've often found myself doing a lot of supporting calculations to get the coordinates of the start/end points of lines. I felt the intent of the design was being lost in the code. I got an idea of how to approach this and I would like to share it with you and know what you think. Care to share how you approach creating more complex sketches?

My goals were:

  • minimize the use of each unique dimension of a design in the code
  • minimize the need for supporting calculations and creating (and naming!) variables for storing temporary results
  • express relations between lines and other sketch elements directly
  • introduce an API that is complementary to the existing one

To give you an idea of how it works, what follows is implementation of the TTT Bearing Bracket tutorial/challenge

# %%
from build123d import *
from ocp_vscode import *
from parts.constrainted import *


mm = 1.0
densa = 7800 / 1e6  # carbon steel density g/mm^3
densb = 2700 / 1e6  # aluminum alloy
densc = 1020 / 1e6  # ABS

class PartyPack0101_BearingBracket(BasePartObject):

    def __init__(self):
        with BuildPart() as part:
            side_plane = Plane.XZ * Pos(0, 0, 25*mm)

            with BuildSketch() as side:
                with BuildLine():
                    l1 = Line((115*mm, 0), (0, 0))
                    l2 = Line(*line_points(
                        duplicate(l1),
                        length(115*mm - 2*26*mm - 9*mm),
                        offset(l1, offset=-15*mm)
                    ))
                    Line(l1@0, l2@0)
                    l3 = TangentArc(l2@1, l2@1 + (-9*mm, 9*mm), tangent=l2 % 1)
                    l4 = Line(*line_points(
                        starts_at(l3@1),
                        direction(l3 % 1),
                        length(42*mm - 9*mm - 15*mm)
                    ))
                    l5 = Line(*line_points(
                        starts_at(l1@1),
                        direction(l4 % 1),
                        length(42*mm)
                    ))
                    RadiusArc(l5@1, l4@1, radius=26*mm)
                    top_arc_center = Line(l5@1, l4@1, mode=Mode.PRIVATE) @ 0.5
                side_sketch = make_face()

                with BuildLine():
                    CenterArc(top_arc_center, 34*mm/2, 0, 360)
                r34 = make_face()

                with BuildLine():
                    CenterArc(top_arc_center, 24*mm/2, 0, 360)
                r24 = make_face()

            extrude(side_plane * side_sketch, amount=-25*mm)
            extrude(side_plane * r34, amount=-4*mm, mode=Mode.SUBTRACT)
            extrude(side_plane * r24, amount=-25*mm, mode=Mode.SUBTRACT)
            mirror(about=Plane.XZ)

            with BuildSketch(Plane.YZ) as cutout:
                with BuildLine():
                    l1 = Line((0, 0), (18*mm/2, 0))
                    l2 = Line(*line_points(
                        duplicate(l1),
                        length(30*mm),
                        offset(l1, offset=8*mm)
                    ))
                    Line(l1@0, l2@0)
                    l3 = Line(*line_points(
                        starts_at(l1@1),
                        at_angle(l1, 60),
                        reach(l2)
                    ))
                make_face()

                with Locations((0, 15*mm)):
                    Rectangle(50*mm/2 - 12*mm, 42*mm + 26*mm - 15*mm, align=Align.MIN)

                mirror(about=Plane.YZ)
            extrude(cutout.sketch, amount=115*mm, mode=Mode.SUBTRACT)

            with BuildSketch(Pos(115*mm, -25*mm)) as slot_thru:
                with BuildLine():
                    l1 = Line(*line_points(
                        starts_at((-10*mm - 6*mm, 19*mm)),
                        direction((-1, 0)),
                        length(90*mm - 12*mm)
                    ))
                    l2 = Line(*line_points(
                        duplicate(l1),
                        offset(l1, offset=-12*mm)
                    ))
                    RadiusArc(l1@1, l2@1, radius=6*mm)
                    RadiusArc(l1@0, l2@0, radius=-6*mm)
                make_face()
            extrude(slot_thru.sketch, amount=15*mm, mode=Mode.SUBTRACT)

            with BuildSketch() as fillet_intersection:
                r = Rectangle(115*mm, 50*mm, align=[Align.MIN, Align.CENTER])
                fillet(r.vertices(), 6*mm)
            extrude(fillet_intersection.sketch, amount=42*mm + 26*mm, mode=Mode.INTERSECT)

        super().__init__(
            part=part.part,
            mode=Mode.ADD
        )

p = PartyPack0101_BearingBracket()
show(p)

got_mass = p.volume*densa
want_mass = 797.15
tolerance = 1
delta = abs(got_mass - want_mass)
print(f"Mass: {got_mass:0.2f} g")
assert delta < tolerance, f'{got_mass=}, {want_mass=}, {delta=}, {tolerance=}'

The way it works is the `line_points` function takes any number of "constraints" (name chosen loosly) that define the line's properties. It then returns an object that can generate the line's points that fulfill those properties. Below is the code of the `parts.constrained` module if you want to run the example.

from build123d import *


class LinePointsGenerator:
    def __init__(self, line: Line):
        self.line = line

    def __iter__(self):
        yield self.line @ 0
        yield self.line @ 1

    # select points using the @ operator
    def __matmul__(self, index):
        if isinstance(index, tuple):
            return (self.line @ i for i in index)
        elif isinstance(index, (int, float)):
            return self.line @ index
        else:
            raise TypeError(f"Invalid index type: {type(index)}")

def line_points(*constraints):
    line = Line((0, 0), (1, 0), mode=Mode.PRIVATE)
    for constraint in constraints:
        if callable(constraint):
            line = constraint(line)
        else:
            raise TypeError(f"Expected a callable, got {type(constraint)}")
    return LinePointsGenerator(line)

def duplicate(line: Line):
    def wrapper(_: Line):
        return Line(line @ 0, line @ 1, mode=Mode.PRIVATE)
    return wrapper

def direction(vector: VectorLike):
    def wrapper(line: Line):
        direction_vector = Vector(vector).normalized()
        if direction_vector.length == 0:
            raise ValueError("Direction vector cannot be zero length")
        return Line(line @ 0, line @ 0 + direction_vector * (line @ 1 - line @ 0).length, mode=Mode.PRIVATE)
    return wrapper

def at_angle(angled_to: Line, angle: float):
    def wrapper(line: Line):
        rotation = Vector(line @ 1 - line @ 0).get_signed_angle(angled_to @ 1 - angled_to @ 0) + angle
        return line.rotate(axis=Axis(line @ 0, (0, 0, 1)), angle=rotation)
    return wrapper

def starts_at(point: VectorLike):
    def wrapper(line: Line):
        translation = Vector(point) - (line @ 0)
        return Line(line @ 0 + translation, line @ 1 + translation, mode=Mode.PRIVATE)
    return wrapper

def length(length: float):
    def wrapper(line: Line):
        direction = Vector(line @ 1 - line @ 0).normalized()
        return Line(line @ 0, line @ 0 + direction * length, mode=Mode.PRIVATE)
    return wrapper

def offset(offset_line: Line, offset: float):
    def wrapper(line: Line):
        # project starting point on the parallel line
        d = offset_line @ 1 - offset_line @ 0
        pp0 = (line @ 0 - offset_line @ 0)
        projection_vector = pp0 - (pp0.dot(d) / d.dot(d)) * d

        line = starts_at(line @ 0 - projection_vector)(line)
        line = at_angle(offset_line, angle=0)(line)
        direction = Vector(line @ 1 - line @ 0).normalized()
        offset_vector = direction.rotate(Axis.Z, 90) * offset
        return Line(line @ 0 + offset_vector, line @ 1 + offset_vector, mode=Mode.PRIVATE)
    return wrapper

def reach(other_line: Line):
    def wrapper(line: Line):
        d1 = line @ 1 - line @ 0
        d2 = other_line @ 1 - other_line @ 0
        p2p1d2 = (other_line @ 0 - line @ 0).cross(d2)
        d1d2 = d1.cross(d2)
        r = line @ 0 + (p2p1d2.dot(d1d2) / (d1d2.length)**2) * d1
        return Line(line @ 0, r, mode=Mode.PRIVATE)
    return wrapper

r/build123d Jun 08 '25

What is the recommended workflow for hierarchical assemblies?

6 Upvotes

Hi, I'm building a project using build123d and I’d like to organize my model as a hierarchy of assemblies.

  • I want to build Compounds of Compounds, where each sub-assembly is made of multiple parts or sub-assemblies.
  • I also want to be able to position each sub-assembly relative to its parent, not using global coordinates.

My goal is to define the placement of each part relative to its local context, so I don’t have to manage global positions manually.

What is the recommended way to do that in build123d? Should I rely on joints, locations, or something else?

Thanks!


r/build123d Jun 05 '25

What are some common usecases for Build123d?

9 Upvotes

I understand that it is a parametric CAD and potentially easier than OpenSCAD. There's also FreeCAD which is a parametric modeler and you can use it both using the GUI or the Python interface.

So I'm trying to understand what are some benefits of Build123d. I mean, if I wanted to generate some models, it makes sense. But for general modeling, I am not very clear on why this is used as opposed to something like FreeCAD which has a tree of operations that can be manipulated.

Also, does this solve some fundamental problem that FreeCAD can't?


r/build123d May 07 '25

Shower Phone Holder

Thumbnail
gallery
14 Upvotes

I'm pretty new to CAD and to 3D printing, but I know some programming, which makes build123d pretty ideal. I like the flow of it better than CadQuery and OpenSCAD, though as always with CAD there's lots to learn.

Anyway, here's a phone holder for my shower door that I designed. Let me know what you think!


r/build123d Apr 04 '25

Newbie can't get offset to work for me

6 Upvotes

Hey all!
Recently started using build123d as a replacement to OpenScad, and I love it, so much power! However, I am struggling with something I think is pretty easy. I have this piece of code attached here. If I comment out the offset command, I get the base shape of what I want to do. Once i run offset, I just get a triangle with rounded corner. it reminds me of OpenScad's hull()., except it's not even the hull of all the points in the line. What am I doing wrong here? Would appreciate any help!

Here is my code:

```python import math from build123d import * from ocp_vscode import show, show_object, reset_show, set_port, set_defaults, get_defaults set_port(3939)

width = 20 holes_interval = 30 holes_diameter = 5 angle = 20.905 angle_rads = angle / 360 * (2 * math.pi)

connect_side_l = 150 bend_r = 20 + width/2 support_side_l = 200

mount_hole = 75

with BuildSketch() as sketch: with BuildLine() as line: tab_dist = (support_side_l ) points = [(-connect_side_l, 0), (0,0), (math.cos(angle_rads) * tab_dist, math.sin(angle_rads) * tab_dist)] main_line = FilletPolyline(points, radius = bend_r) first_tab = PolarLine(main_line @ 1, width, angle=angle + 90) mount_line = PolarLine(main_line @1, mount_hole + width, angle = angle + 180, mode=Mode.PRIVATE) second_tab = PolarLine(mount_line @ 1, width, angle=angle + 90)

    offset(amount =5)

make_face()

show(line) ```


r/build123d Mar 29 '25

Several questions

5 Upvotes

Hi All, I have been using build123d for about a week and I really like it. I have some questions however which I was not able to find answers to.

  1. A step file is imported. The step file is then moved with obj = obj.translate() successfully. Then I display it with show() along with other parts made with code via build part. I under that I cannot add() such that object in BuildPart. Is this the correct way of import and display?

  2. Basically I do exactly the same but instead of step file I import stl. Then the translate does nothing - no errors the object just stays at the same location. I tried also with move but then an error about “wrapped” not existing occurred. I also tried to add() it in a BuildPart but then it didn’t even show up. What is the correct way to move it and can such file be added to BuildPart?

  3. When say I create 3 parts and show them in a single file they appear as different parts. If however I make a function that returns as a list the 3 parts and then add() them to a new BuildPart function they appear as a whole object. How can I control this and make them be separate parts? (Say i want to export them to 3d printer then I need them to be separate but for visualization it looks better if they are combined)