Skip to main content

React

API#

type HeadlessConfig = Partial<BuerliState['options']> & {
/** Buerli socket adapter, default: SocketIOClient */
socket?: new (...args: any) => AwvNodeClient
/** Suspense entry invalidation in ms, default: 0 (keep-alive forever) */
lifespan?: number
/** Suspense cache equality function, default: (a, b) => a === b (reference equality) */
equal?: (a: any, b: any) => boolean
/** An object that can persist values for the lenght of the session */
store?: { [key: string]: any }
}
headless(impl: typeof solid | typeof history, url: string, config: HeadlessConfig = {})

BuerliGeometry component#

The BuerliGeometry component is a very important component. It helps to visualise and interact with CAD models. It simply can be added to the canvas and already will work. There are a few properties to configure the component. See the properties in the following code snippet.

type BuerliGeometryProps = {
/**
* buerli is able to handle multiple drawings (cad models) at once. This is the id to
* the one that should be rendered by this component. In most headless applications,
* it should not be needed, because only one drawing exists in the buerli state.
*/
drawingId?: DrawingID
/**
* Identifies the object from which the geometry tree has to be rendered.
* By default, the root of the model (Assembly, Part) is taken.
* In most headless applications, it should not be needed.
*/
productId?: ObjectID
/**
* Flag to activate selection on the CAD model. This is necessary e.g. to make
* use of the selectGeometry() method in the history API.
*/
selection?: boolean
/**
* If true, this component suspends rendering until all async, pending api calls
* are finished. It allows for easy integration into the standard @see React.Suspense
* workflow.
*/
suspend?: boolean | ((pending: Pending) => boolean) | string[]
}

In the following code snippet we can find an example how to use the BuerliGeometry component. As we can see, selection property is set and selectGeometry() is used in the code to make edge selections. To get the whole example see buerli-starter

function Scene({ drawingId, width = 50, ...props }) {
const geometry = useRef()
useEffect(() => {
buerli.run(async (api, store) => {
const part = await api.createPart('Part')
const wcsx = await api.createWorkCoordSystem(part, WorkCoordSystemType.WCS_Custom, [], [0, -width / 5, -width / 8], [0, 0, 0])
await api.cylinder(part, [wcsx], 10, width)
const selection = (store.edges = await api.selectGeometry(EdgeTypes, 2))
await api.chamfer(part, ChamferType.EQUAL_DISTANCE, selection.map(sel => sel.graphicId), 2, 2, 45)
})
}, [])
useLayoutEffect(() => {
geometry.current?.traverse(obj => {
obj.receiveShadow = obj.castShadow = true
if (obj.type === 'Mesh') obj.material = new THREE.MeshStandardMaterial({ color: 'orange', roughness: 0.5 })
})
})
return (
<group {...props}>
<Bounds fit observe margin={1.75}>
<Resize scale={2}>
<Center top ref={geometry} rotation={[0, -Math.PI / 4, 0]}>
<BuerliGeometry drawingId={drawingId} suspend selection />
</Center>
</Resize>
</Bounds>
</group>
)
}

Run#

Either use run which merely executes and <BuerliGeometry> to display the results asynchroneously (although the suspend option would allow you to orchestrate inside useEffect and useLayoutEffect).

import { BuerliGeometry, headless } from '@buerli.io/react'
import { history } from '@buerli.io/headless'
const { run } = headless(history, 'ws://localhost:9091')
function Scene({ width = 100 }) {
useEffect(() => {
run(async (api, store) => {
const part = await api.createPart('Part')
const wcsy = await api.createWorkCoordSystem(part, 8, [], [], [0, width / 3, 0], [Math.PI / 3, 0, 0])
const wcsx = await api.createWorkCoordSystem(part, 8, [], [], [0, -width / 5, -width / 8], [0, 0, 0])
const a = await api.cylinder(part, [wcsx], 10, width)
const b = await api.cylinder(part, [wcsy], 10, width)
await api.boolean(part, 0, [a, b])
// You can put anything into the store and use it in consecutive run calls
store.part = part
})
}, [])
return <BuerliGeometry suspend />
}

Cache#

Or use cache which suspends and returns the result of the function as a cached and memoized value. The results can be displayed in whichever way you like, for instance returning a geometry and adding it to a mesh right away.

The dependecies are cache keys. Similar to a useMemo the inner function is called when the cache keys change. The dependencies are also passed to the inner function, so you could hoist it.

import { BuerliGeometry, headless } from '@buerli.io/react'
import { history } from '@buerli.io/headless'
const { cache } = headless(history, 'ws://localhost:9091')
function Scene({ width = 100 }) {
const geo = cache(
async (api, store, ...args) => {
const part = await api.createPart('Part')
const wcsy = await api.createWorkCoordSystem(part, 8, [], [], [0, width / 3, 0], [Math.PI / 3, 0, 0])
const wcsx = await api.createWorkCoordSystem(part, 8, [], [], [0, -width / 5, -width / 8], [0, 0, 0])
const a = await api.cylinder(part, [wcsx], 10, width)
const b = await api.cylinder(part, [wcsy], 10, width)
const solid = await api.boolean(part, 0, [a, b])
return await api.createBufferGeometry(solid)
},
[width],
)
return (
<mesh geometry={geo}>
<meshStandardMaterial />
</mesh>
)
}