<assembly.part />
assembly.part is a generic mechanical component, such as a bearing, bracket, or cover. Give it a stable name and optionally supply a CAD model. It has no PCB footprint, schematic symbol, or electrical ports.
Mount a bearing model
This example seats an 8 × 22 × 7 mm bearing in a printed housing. mountedTo=".HOUSING > .bearingSeat" selects the pocket floor; mountFace="base" selects the bearing's authored bottom reference. The bearing's origin is at that bottom face, so no CAD offset is needed.
import { assembly } from "tscircuit"
import { BearingHousing, bearingModel } from "./models"
export default () => (
<assembly.device>
<assembly.printedpart name="HOUSING" jscad={<BearingHousing />}>
<assembly.referencesurface name="bearingSeat" centerZOffset={4} />
<assembly.referencesurface name="boltSeat"
centerXOffset={22} centerYOffset={12} centerZOffset={6} />
</assembly.printedpart>
<assembly.part name="BEARING"
cadModel={bearingModel}
mountedTo=".HOUSING > .bearingSeat" mountFace="base">
<assembly.referencesurface name="base" normalDirection="z-" />
</assembly.part>
<assembly.bolt name="BOLT" model="hexsocketbolt_m3_l10mm"
fastenedTo=".HOUSING > .boltSeat" />
</assembly.device>
)
The housing, bearing races and recessed shields are modeled in models.tsx; the bolt uses an existing JSCAD Electronics model. assembly.referencesurface adds attachment frames to these parts without adding material. The bolt uses its own fastenedTo prop.
For a purchased bearing CAD file, replace cadModel={bearingModel} with modelUrl="./bearing.glb" and keep the references at the asset's physical mounting locations. This example's authored model has its bottom at local Z = 0.
Part properties
| Property | Description |
|---|---|
name | Required stable identity. Trimmed and must not be empty. |
displayName | Optional human-facing name. |
purchaseUrls | Optional array of HTTP(S) purchase links, including Amazon or a manufacturer's store. |
supplierPartNumbers | Optional supplier-to-SKU map, for example { jlcpcb: ["C123"] }. |
model | Modelprinter/footprinter specification or an HTTP(S) model URL. |
modelUrl | Imported model URL or asset path. |
cadModel | Existing CAD formats and model-alignment transforms, including CAD JSX; see cadmodel. |
mountedTo | Target face selector, such as .HOUSING > .bearingSeat, or compact path HOUSING.bearingSeat. |
mountFace | This part's named mating face. Supply with mountedTo. |
mountOffset | Signed distances along the target face's local X/Y tangents: { x?, y? }. Omitted axes are zero. |
mountGap | Nonnegative clearance along the target's outward normal, default zero. |
Supply at most one of model, modelUrl, or cadModel. Omit all three for a part with no geometry. cadModel={null} also keeps the identity without rendering a model; it cannot be combined with another model source. For a jscad JSX prop, use assembly.printedpart.
Bill of materials
Assembly parts appear in the assembly bill of materials even when they have no CAD model. Use purchaseUrls for store links and supplierPartNumbers for supplier lookup identifiers. These are independent: URLs are not matched to SKUs by their position in an array, and a purchase link alone does not supply a price.
import { assembly } from "@tscircuit/core"
export default () => (
<assembly.device name="sensor">
<assembly.subassembly name="HOUSING" displayName="Sensor housing">
<assembly.part
name="COVER"
displayName="ABS cover"
purchaseUrls={[
"https://amazon.com/dp/example",
"https://store.example/cover",
]}
/>
{[1, 2].map((index) => (
<assembly.part
key={index}
name={`SCREW${index}`}
purchaseUrls={["https://store.example/m3-screw"]}
/>
))}
<assembly.part name="MODULE" supplierPartNumbers={{ jlcpcb: ["C123"] }} />
</assembly.subassembly>
</assembly.device>
)
Replace the example URLs and SKU with your actual purchasing information. This example needs no geometry: it produces a housing material line with four children (cover, two screws and module). The model-less outer device contributes no line.
Each assembly element contributes quantity one, regardless of how many CAD models it contains. Represent multiple physical instances with separate elements, as with the two screws above. Nesting determines BOM ownership; mountedTo determines placement and does not reparent BOM lines. displayName, where supported, supplies the material label; otherwise the label comes from name.
The same purchasing props are available on assembly.subassembly (and its assembly.cadassembly alias), assembly.device, assembly.bolt, assembly.printedpart, assembly.motor, assembly.screen and assembly.cable. Reference surfaces, CAD primitives, drawings and explosion instructions do not add material lines. See device BOM behavior for when a device contributes its own line.
Read the assembly BOM
Core emits cad_assembly_bom_item records in Circuit JSON. Render the design, then use convertCircuitJsonToAssemblyBom from circuit-json-to-bom-csv (version 0.0.28 or later) to obtain the nested BOM:
import { Circuit } from "@tscircuit/core"
import { convertCircuitJsonToAssemblyBom } from "circuit-json-to-bom-csv"
import SensorAssembly from "./sensor-assembly"
const circuit = new Circuit()
circuit.add(<SensorAssembly />)
await circuit.renderUntilSettled()
const bom = await convertCircuitJsonToAssemblyBom({
circuitJson: circuit.getCircuitJson(),
})
Save the first example as sensor-assembly.tsx. Each resulting node exposes name, quantity, total_quantity, purchase_urls and children, with supplier identifiers when supplied. Remaining PCB components are grouped by their electrical subcircuits. Assembly materials do not enter the existing PCB manufacturing BOM CSV.
Core records purchasing metadata without fetching prices. A consuming viewer can use a parts engine to quote supported supplier SKUs; arbitrary store links do not enable automatic pricing. Parent and child materials remain separate entries: nesting does not indicate that a parent's purchase price includes its children.
Placement and CAD alignment
Standalone unmounted parts use the world origin. Nested parts inherit the nearest assembly's full placement, including tilt. A face mount sets the complete position and orientation; its children and reference surfaces follow that frame. Use mountOffset for in-plane adjustment and mountGap for separation. Both require mountedTo.
cadModel.positionOffset and rotationOffset align the mesh within that frame. They do not move the assembly origin, its children, or its reference surfaces. An imported model needs authored reference surfaces; core does not infer mounting faces from its mesh.
Coordinates are in millimetres in a right-handed frame: +X right, +Y top, and +Z above. Target selectors resolve within the nearest assembly.device, including targets declared later. A selector must match exactly one face; missing or ambiguous references and mounting cycles report errors.
An assembly.screen can target the part's identity with connectsTo=".BEARING"; this uses its assembly origin and creates no electrical connections. Use assembly.subassembly to move a group through one mounting constraint.