Viewer & provider
<CadbuildrProvider> holds the session token, kernel client, and geometry
cache. <CadbuildrViewer> renders meshes via React-Three-Fiber. Together
they’re enough to embed a CADbuildr configurator with ~10 lines of TSX.
Minimal example
import {
CadbuildrProvider,
CadbuildrViewer,
} from "@cadbuildr/sdk-react";
export function LegoEmbed({ sessionToken, dag }: Props) {
return (
<CadbuildrProvider sessionToken={sessionToken} projectKey="lego">
<CadbuildrViewer
dag={dag}
background="#141a1c"
cameraPosition={[220, 140, 220]}
fov={42}
onRender={(meta) => console.info("rendered", meta)}
onError={(err) => console.error("render failed", err)}
/>
</CadbuildrProvider>
);
}<CadbuildrProvider> props
| Prop | Type | Notes |
|---|---|---|
sessionToken | string | undefined | The cbv1.… token. If undefined, requests go unauthenticated (kernel-api may reject). |
projectKey | string | Project slug. Must be in the cbsdk_* key’s allowedProjects. |
baseUrl | string? | kernel-api base. Default https://kernel-api.cadbuildr.com. |
headers | Record<string,string>? | Extra headers merged into every fetch (telemetry, etc). |
fetchImpl | typeof fetch? | Custom fetch (mocks, retries, polyfills). |
The provider also owns:
- The kernel exclusive queue — only one in-flight render per provider, so a slow render doesn’t queue behind itself when the user keeps sliding a parameter.
- The client-side mesh-hash LRU — repeated identical meshes (same
brick at different positions, same plate across renders) reuse the
same
BufferGeometryinstance instead of re-uploading to the GPU.
<CadbuildrViewer> props
| Prop | Type | Notes |
|---|---|---|
dag | KernelDag | null | The DAG to render. null = empty scene (loading state). |
parameters | Record<string, ParameterValue>? | Used with frozen-DAG templates; substituted into ParameterInput nodes. |
background | string? | Canvas background color. |
cameraPosition | [number, number, number]? | Initial camera position. Default tuned for ~half-meter scenes. |
fov | number? | Field of view in degrees. |
meshPosition | [number, number, number]? | Translation applied to the mesh group (handy for Z-up → Y-up conversions). |
meshRotation | [number, number, number]? | Euler rotation applied to the mesh group. |
onRender | (meta) => void | Fires on every successful render. meta includes mesh hashes, byte sizes, kernel ms. |
onError | (err) => void | Fires on render error. Includes code (unauthorized, rate_limited, …). |
children | ReactNode? | Extra R3F primitives to drop into the same canvas (gizmos, ground plates). |
When to drop down to useCadbuildrRender
If you need full control over the canvas — for example, embedding multiple viewers in a single R3F scene, or building a “compare A vs B” UI — use the headless hook:
import { useCadbuildrRender, MeshGroup } from "@cadbuildr/sdk-react";
function MyCanvas({ dag }: Props) {
const { meshes, status, error } = useCadbuildrRender({ dag });
if (error) return null;
return <MeshGroup meshes={meshes} />;
}<MeshGroup> is the same primitive <CadbuildrViewer> uses internally; it
takes the meshes array from useCadbuildrRender and produces R3F
<mesh> instances with cached BufferGeometry.
Coordinate system gotcha
Foundation emits meshes in Z-up, R3F is Y-up. The lego demo
applies meshRotation={[-Math.PI/2, 0, 0]} to convert. If your assemblies
look “lying on their side”, that’s the symptom — bake the rotation into
the viewer or your assembly’s transform.
Provider scope
A single provider serves any number of viewers. Re-use the provider at the page level rather than wrapping each viewer individually — the geometry LRU is per-provider, so a single provider means the same brick is uploaded to the GPU once regardless of how many viewers display it.