Skip to main content

Looks

How the 3D view draws: the realistic or the flat look, and materials for the products in the realistic look. A host needs it to switch the look from controls of its own, or to give its products the materials they are made of.

Functions​

setRenderMode()​

function setRenderMode(mode): void;

Switches the look, as the user's switch does: the page remembers it, and opens in it the next time.

It is kept in the page's localStorage (where there is none, for as long as the page is open). A remembered look outweighs setDefaultRenderMode and Buerligons' defaultLook.

Parameters​

ParameterTypeDescription
modeRenderModethe look to draw in.

Returns​

void

Example​

import { getRenderMode, setRenderMode, type RenderMode } from '@buerli.io/buerligons'

// The host's presentation: the realistic look while it lasts, then the look the user had
let before: RenderMode | null = null

export function startPresenting() {
before = getRenderMode()
setRenderMode('realistic')
}

export function stopPresenting() {
if (before) setRenderMode(before)
before = null
}

setLooks()​

function setLooks(looks): void;

Gives products their looks in the realistic look, by product name; replaces those set before, {} clears them.

The name is a part's name, or a template's name in an assembly: each body wears the look of its product, and a product without one keeps the stage's finish. A host sets the looks after it opened a document, and clears them when it closes it. The flat look (RenderMode) does not show them.

Parameters​

ParameterTypeDescription
looksRecord<string, Look>the look of each product, by its name.

Returns​

void

Example​

import { EditorController, setLooks, type Look } from '@buerli.io/buerligons'

declare const editor: EditorController
declare function materialOf(productName: string): Promise<Look | undefined> // the host's material library

// After an open: a look for every product the host has a material for
export async function dressProducts() {
const looks: Record<string, Look> = {}
for (const product of editor.products()) {
const look = await materialOf(product.name)
if (look) looks[product.name] = look
}
setLooks(looks) // replaces the looks set before
}

Hooks​

useRenderMode()​

function useRenderMode(): RenderMode;

The look the stage draws in now: the component renders again when it changes.

Returns​

RenderMode

The render mode.

Example​

import { setRenderMode, useLooks, useRenderMode } from '@buerli.io/buerligons'

// A hint where the host gave its products looks and the stage draws flat, in which they do not show
export function LooksHint() {
const flat = useRenderMode() === 'flat'
const hasLooks = useLooks(s => Object.keys(s.looks).length > 0)
if (!flat || !hasLooks) return null
return <button onClick={() => setRenderMode('realistic')}>Show the materials</button>
}

Types​

RenderMode​

type RenderMode = "flat" | "realistic";

How the stage draws the bodies: 'realistic' (the default) or 'flat'.

  • realistic: a lit studio. Physically based materials among softboxes, deeper occlusion, light bounced between parts, edges rounded in screen space and a hint of reflection. The ink edges are switched off each time it is switched on (the user can switch them on again; the flat look gets back what it had). The products' looks (setLooks) show in it.
  • flat: the drawing look. Even light, ink edges and silhouettes, a little occlusion where faces meet.

The user switches it in the view options and in the stage's context menu. A host reads it with useRenderMode or getRenderMode, and sets it with setRenderMode or, as the look to open in, with setDefaultRenderMode.

Example​

import { Buerligons, setRenderMode, useRenderMode, type RenderMode } from '@buerli.io/buerligons'

// A choice of the host's own, at the end of the app's bar
function LookChoice() {
const mode = useRenderMode()
return (
<select value={mode} onChange={e => setRenderMode(e.target.value as RenderMode)}>
<option value="realistic">Realistic</option>
<option value="flat">Drawing</option>
</select>
)
}

export const App = () => (
<div style={{ height: '100vh' }}>
<Buerligons trail={<LookChoice />} />
</div>
)

Look​

A material for the bodies of a product in the realistic look, named as three.js's MeshPhysicalMaterial names it.

A host gives its products their looks by name (setLooks); colours are #rrggbb. The flat look does not show them. Not every field is taken:

  • A body's colour and opacity stay the model's (color and opacity are not taken): a host that wants another colour sets it in the model (v1.part.setAppearance).
  • The environment is the studio's for every body alike, so envMapIntensity is not taken.
  • Neither are anisotropy and its rotation: brushed metal needs a direction along its surface, which a CAD body's mesh does not carry.
  • Glass (transmission) is see-through rather than refracting, so thickness is not taken either.

A field left out keeps the stage's satin finish (roughness and metalness) or three.js's default.

Example​

import { init, WASMClient } from '@buerli.io/classcad'
import { Buerligons, EditorController, setLooks, setRenderMode, type Look } from '@buerli.io/buerligons'

init(drawingId => new WASMClient(drawingId, { token: 'ccpk_…' }))
const editor = new EditorController()

// Materials of the host's own, named as three.js names them; the colours stay the model's
const brushedSteel: Look = { metalness: 1, roughness: 0.4 }
const frostedGlass: Look = { transmission: 0.9, roughness: 0.6 }
const lacquer: Look = { roughness: 0.5, clearcoat: 1, clearcoatRoughness: 0.1 }

// Once the document is open: its products' looks by name, and the realistic look, in which they show
export async function openGearbox(data: ArrayBuffer) {
await editor.open({ name: 'Gearbox.ofb', format: 'OFB', data })
setLooks({ Housing: brushedSteel, Cover: frostedGlass, Knob: lacquer })
setRenderMode('realistic')
}

// On close the looks go with the document
export async function closeGearbox() {
setLooks({})
await editor.close()
}

export const App = () => <div style={{ height: '100vh' }}><Buerligons welcome={false} /></div>

Properties​

PropertyTypeDescription
anisotropy?numberNot taken: brushed metal needs a direction along the surface, which a CAD body's mesh does not carry.
anisotropyRotation?numberIn degrees. Not taken, as anisotropy is not.
clearcoat?number0 to 1: a coat of lacquer over the surface.
clearcoatRoughness?number0 to 1: how rough the coat is (with clearcoat); by default 0.
color?stringNot taken: a body keeps the model's colour.
emissive?stringColour the surface gives off itself (#rrggbb).
emissiveIntensity?numberStrength of emissive; by default 1.
envMapIntensity?numberNot taken: the environment is the studio's for every body alike.
ior?numberIndex of refraction, which shapes the reflections; by default 1.5.
metalness?number0 to 1: how much the surface is a metal. By default the stage's finish.
opacity?numberNot taken: a body keeps the model's opacity.
roughness?number0 to 1: how much the surface scatters its reflections. By default the stage's finish.
sheen?number0 to 1: a soft sheen at grazing angles, as cloth has.
sheenColor?stringColour of the sheen (#rrggbb); by default #ffffff.
specularColor?stringTint of the specular reflection (#rrggbb); by default #ffffff.
specularIntensity?numberStrength of the specular reflection; by default 1.
thickness?numberNot taken: glass is see-through here rather than refracting.
transmission?number0 to 1: how much light passes through, as through glass. Drawn see-through rather than refracting.

Advanced​

Most apps do not need these directly: types they meet through the exports above, and what is there for special cases or for building on buerli itself.

getRenderMode()​

function getRenderMode(): RenderMode;

The look the stage draws in now, read once (outside React, say); useRenderMode follows it.

Returns​

RenderMode

The render mode.

Example​

import { getRenderMode } from '@buerli.io/buerligons'

declare function capture(): Promise<Blob> // the host's screenshot of the page

// A screenshot the host files, with the look it was taken in
export async function screenshot() {
return { image: await capture(), look: getRenderMode() }
}

setDefaultRenderMode()​

function setDefaultRenderMode(mode): void;

Sets the look to draw in where the page remembers no choice of the user's; otherwise it does nothing.

A look chosen before (by the user, or with setRenderMode) stays. Buerligons' defaultLook prop calls it; called before the stage is there, the stage opens in the look.

Parameters​

ParameterTypeDescription
modeRenderModethe look to open in.

Returns​

void

Example​

import { createRoot } from 'react-dom/client'
import { init, WASMClient } from '@buerli.io/classcad'
import { Buerligons, setDefaultRenderMode } from '@buerli.io/buerligons'

init(drawingId => new WASMClient(drawingId, { token: 'ccpk_…' }))

// A host for drawings opens in the flat look, unless the user chose a look on this page before
setDefaultRenderMode('flat') // or <Buerligons defaultLook="flat" />

createRoot(document.getElementById('root')!).render(
<div style={{ height: '100vh' }}>
<Buerligons />
</div>,
)

useLooks​

const useLooks: UseBoundStore<StoreApi<{
looks: Record<string, Look>;
setLooks: (looks) => void;
}>>;

The looks as a zustand store: useLooks(s => s.looks) in a component, useLooks.getState() outside React.

looks holds the look of each product by its name; setLooks on it is setLooks.

Example​

import { useLooks } from '@buerli.io/buerligons'

// A legend beside the app: the products that wear a look
export function LookLegend() {
const looks = useLooks(s => s.looks)
return (
<ul>
{Object.entries(looks).map(([name, look]) => (
<li key={name}>
{name}: {(look.metalness ?? 0) > 0.5 ? 'metal' : look.transmission ? 'glass' : 'plastic'}
</li>
))}
</ul>
)
}

// Outside React
console.log(Object.keys(useLooks.getState().looks))