Mix.install([{:smith, "~> 0.2.0"}, {:kino, "~> 0.19.0"}])Before you start
After mechanical parts, make two instances of a reusable foot and place reference hardware above them. An assembly keeps these parts separately named and printable.
Run cells in order. Lengths are millimeters and modeling angles are degrees. Each 3D preview supports orbit, zoom, and fullscreen.
Define a reusable part
Use ordinary functions for features and parameters. Both instances below reuse the same recipe, which Smith evaluates once within this assembly evaluation. The rounded sketch sets the footprint; an explicit entry plane fixes the counterbore at its center. The 3 mm recess leaves 5 mm of material below the screw head.
defmodule NotebookParts do
def foot(width, depth, height) do
Smith.Sketch.rounded_rectangle(width, depth, 1, align: {:min, :min})
|> Smith.extrude(height)
|> Smith.counterbore(on: Smith.Plane.xy(z: height), at: {width / 2, depth / 2},
diameter: 5, bore_diameter: 8, bore_depth: 3, through: :all)
end
end
foot = NotebookParts.foot(12, 16, 8)
Smith.Kino.render(foot, label: "1 · Reusable foot")Place two instances
Installed geometry and printable orientation are independent. References are available for inspection but excluded from manufactured geometry and print packs.
alias Smith.Assembly
pair =
Assembly.new(:support)
|> Assembly.part(:left, foot, position: {-20, 0, 0}, print: [on_bed: true])
|> Assembly.part(:right, foot, position: {20, 0, 0}, print: [on_bed: true],
exploded_offset: {0, 0, 16})
|> Assembly.reference(:device, Smith.box(28, 16, 6), position: {-8, 0, 8})
{:ok, result} = Smith.evaluate(pair)
Smith.Kino.render(result, label: "2 · Installed feet")Inspect the members
Use Assembly.members/1 to list evaluated leaves without reaching into the
recipe's internal fields. Each member has a path, a kind, an installed flag,
and its evaluated result. References are listed too, but are never manufactured
parts. The same function traverses nested assemblies.
{:ok, members} = Assembly.members(result)
2 = Enum.count(members, &(&1.kind == :part))
1 = Enum.count(members, &(&1.kind == :reference))
members
|> Enum.map(fn member ->
%{path: member.key, kind: member.kind, installed: member.installed}
end)
|> Kino.DataTable.new()Inspect the exploded view
Create a view from the evaluated assembly. The right foot moves up by its declared exploded offset; its installed and print placements stay unchanged. The view is a combined geometry snapshot. Keep the original assembly result for export.
{:ok, exploded} = Assembly.view(result, :exploded)
Smith.Kino.render(exploded, label: "3 · Exploded feet")Inspect a reference
{:ok, device} = Assembly.fetch(result, :device)
Smith.Kino.render(device, label: "Reference · Device")Export the complete assembly
Each manufactured part gets verified STL and 3MF files. The bundle also includes installed STEP geometry, a separate reference STEP, and a ZIP of printable parts.
{:ok, solids} = OCEx.solids(result.shape)
2 = length(solids)
{:ok, files} = Smith.export(result, "output/livebook", name: "support")
filesFor a reusable group of parts, use Assembly.subassembly/4. The nested assembly notebook covers parent/child placement, path lookup, printable extras, and per-leaf exports.