Skip to main content

Hooks

Open a drawing in a component and read buerli's state. Start with useBuerliCadFacade.

Hooks​

useBuerliCadFacade()​

function useBuerliCadFacade(name): {
api: UnwrappedApiType;
drawingId: DrawingID;
facade: BuerliCadFacade;
Geometry: (props) => Element;
graphic: (opts?) => Promise<
| {
containers: ScgGraphicContainer[];
}
| null>;
tree: (opts?) => Promise<ScgTree>;
};

Opens the drawing called name and returns its ClassCAD API, its facade and a component that renders it.

The hook suspends until the drawing is connected, so it needs a <Suspense> boundary above it (a react-three-fiber Canvas has one). Components that pass the same name share one drawing; another name opens another drawing. When the last component that uses a name unmounts, its drawing is closed and removed (facade.destroy()).

Call init from @buerli.io/classcad before the first drawing opens: it sets how drawings reach the engine.

Parameters​

ParameterTypeDescription
namestringThe drawing's name, which is also the key components share it by.

Returns​

The drawing's api, facade, drawingId, tree, graphic and Geometry.

NameTypeDescription
apiUnwrappedApiTypeThe ClassCAD API of the drawing: each call returns its result and throws when the engine reports an error.
drawingIdDrawingIDThe id of the drawing.
facadeBuerliCadFacadeThe drawing's facade: three.js geometry and scenes of its products, and the drawing's lifecycle.
Geometry()(props) => ElementA BuerliGeometry for this drawing, which suspends while the drawing has pending commands.
graphic()(opts?) => Promise< | { containers: ScgGraphicContainer[]; } | null>Reads the drawing's current tessellation: the facade's graphic. The current graphic (tessellation) of the drawing as { containers }, as held by the buerli store. Pass recalc: true to recalculate first. Note that graphic element ids are payload-local - they rotate on every re-tessellation. The stable join between graphic and structure tree is container.owner === <CC_Solid id>. Example import * as THREE from 'three' // Frames the camera on the model: the bounds of every body const graphic = await facade.graphic() const bounds = new THREE.Box3() for (const container of graphic?.containers ?? []) { if (!container.meshes?.length) continue bounds.expandByPoint(new THREE.Vector3().fromArray(container.properties.min)) bounds.expandByPoint(new THREE.Vector3().fromArray(container.properties.max)) } const center = bounds.getCenter(new THREE.Vector3()) const size = bounds.getSize(new THREE.Vector3()).length() camera.position.copy(center).add(new THREE.Vector3(0, -size, size)) camera.lookAt(center)
tree()(opts?) => Promise<ScgTree>Reads the drawing's structure tree, by object id: the facade's tree. The structure tree (id -> node) of the drawing, as held by the buerli store. The tree is kept up to date by the regular structure broadcast; pass refresh: true to explicitly request it from ClassCAD first. Example import { ccUtils, ScgClassType } from '@buerli.io/classcad' // The parts of a loaded model, by name const tree = await facade.tree({ refresh: true }) const parts = Object.values(tree).filter(node => ccUtils.base.isA(node.class, ScgClassType.CCPart)) const wheel = parts.find(node => node.name === 'Wheel') console.log(parts.map(node => node.name), wheel?.id)

Example​

import { useEffect } from 'react'
import { useBuerliCadFacade } from '@buerli.io/react'

function Box({ size = 100 }) {
const { api, Geometry } = useBuerliCadFacade('box')
useEffect(() => {
async function build() {
await api.v1.common.clear()
const part = await api.v1.part.create({ name: 'Box' })
await api.v1.part.box({ id: part, width: size, length: size, height: size })
}
build()
}, [api, size])
return <Geometry />
}

useBuerli()​

function useBuerli<T>(selector, equalityFn?): T;

Selects a part of buerli's state, and renders again when it changes.

A selector may return a new object or array each time: what decides whether the component renders again is equalityFn (Object.is if none is given), the same as with zustand 4's hooks.

Type Parameters​

Type Parameter
T

Parameters​

ParameterTypeDescription
selector(state) => TWhat to take from the state.
equalityFn?(a, b) => booleanWhether two selections are the same.

Returns​

T

What the selector returned.

Example​

Tabs for the open drawings, which switch the active one:

import { useBuerli } from '@buerli.io/react'

function DrawingTabs() {
const drawings = useBuerli((state) => state.drawing.refs)
const active = useBuerli((state) => state.drawing.active)
const setActive = useBuerli((state) => state.api.setActiveDrawing)
return (
<nav>
{Object.values(drawings).map((drawing) => (
<button key={drawing.id} disabled={drawing.id === active} onClick={() => setActive(drawing.id)}>
{drawing.name}
</button>
))}
</nav>
)
}

useDrawing()​

function useDrawing<T>(
id,
sel,
equalityFn?
): T | undefined;

Selects a part of a drawing's state, and renders again when it changes.

The drawing's state holds its structure tree, geometry, selection and plugins. While the drawing does not exist, or when the selector throws (the error is logged), the hook returns undefined. Whether the selection changed is decided by equalityFn (Object.is if none is given).

Type Parameters​

Type Parameter
T

Parameters​

ParameterTypeDescription
idDrawingIDThe drawing.
sel(state) => T | undefinedWhat to take from the drawing's state.
equalityFn?(a, b) => booleanWhether two selections are the same.

Returns​

T | undefined

What the selector returned, or undefined.

Example​

A list of the drawing's parts, from its structure tree, which updates as parts are made or renamed:

import { useBuerliCadFacade, useDrawing } from '@buerli.io/react'

function PartList() {
const { drawingId } = useBuerliCadFacade('main')
// Select something that keeps its identity (the tree), and derive from it while rendering
const tree = useDrawing(drawingId, (drawing) => drawing.structure.tree)
const parts = Object.values(tree ?? {}).filter((node) => node.class === 'CC_Part')
return (
<ul>
{parts.map((part) => (
<li key={part.id}>{part.name}</li>
))}
</ul>
)
}