Opening a scene that renders any @react-three/uikit Content node (<Svg>, <Image>, …) crashes the Triplex renderer with:
Could not render scene: Cannot read properties of undefined (reading 'x')
The crash originates in Triplex's camera auto-frame, which computes scene bounds via THREE.Box3.setFromObject → Box3.expandByObject over the user scene. uikit Content nodes carry a non-Box3 value on Object3D.boundingBox (a @preact/signals-core Signal), which three.js copies unguarded — so a single uikit node takes down the entire editor view.
Environment
| Package |
Version |
| Triplex |
0.70.51 |
three |
0.185.0 |
@react-three/fiber |
9.6.1 |
@react-three/uikit / @pmndrs/uikit |
1.0.74 |
Steps to reproduce
- In an R3F project wired for Triplex, create a scene that renders a uikit
Content node, e.g. <Root><Svg src="/icon.svg" /></Root>.
- Open that scene in Triplex.
- The editor fails to render: Could not render scene: Cannot read properties of undefined (reading 'x').
A scene with no uikit Content nodes (or where they are unmounted) opens fine.
Root cause
three.js Box3.expandByObject reads object.boundingBox and assumes it is a Box3:
if ( object.boundingBox !== undefined ) {
if ( object.boundingBox === null ) object.computeBoundingBox();
_box.copy( object.boundingBox ); // Signal here -> Box3.copy reads .min.x on undefined -> throw
}
uikit's Content base class (Svg, Image, …) assigns a Signal to mesh.boundingBox, violating three's Object3D.boundingBox: Box3 | null contract. Triplex's auto-frame calls setFromObject across the whole scene, so the malformed bound on one node crashes the entire "render scene" path. Upstream uikit report: .
Why Triplex should guard this
Triplex auto-frames arbitrary user scenes that legitimately contain third-party objects. A duck-typed/malformed boundingBox on a single node shouldn't hard-fail the whole editor — uikit is widely used, and other libraries may similarly attach non-Box3 data. Defensive handling in the auto-frame bounds computation keeps the editor usable across the ecosystem, even before the upstream fix lands.
Suggested fix
When computing scene bounds for camera framing, ignore objects whose .boundingBox is not a valid THREE.Box3 (let three fall back to geometry bounds), or wrap the traversal defensively so one bad node can't abort the render.
Workaround for affected users
Install an editor-only guard in the Triplex provider (.triplex/provider.tsx). It patches Box3.expandByObject to ignore non-Box3 boundingBox values. It loads only in the editor — production runtime is untouched:
import { Box3 } from 'three'
const isUsableBox3 = (b: unknown): b is Box3 =>
typeof (b as { min?: { x?: unknown } } | null)?.min?.x === 'number' &&
typeof (b as { max?: { x?: unknown } } | null)?.max?.x === 'number'
const expandByObject = Box3.prototype.expandByObject
Box3.prototype.expandByObject = function (object, precise) {
const node = object as unknown as { boundingBox?: unknown }
const bb = node.boundingBox
if (bb != null && !isUsableBox3(bb)) {
node.boundingBox = undefined
try {
return expandByObject.call(this, object, precise)
} finally {
node.boundingBox = bb
}
}
return expandByObject.call(this, object, precise)
}
This resolves the crash and the camera still frames the node from its geometry bounds.
Opening a scene that renders any
@react-three/uikitContentnode (<Svg>,<Image>, …) crashes the Triplex renderer with:The crash originates in Triplex's camera auto-frame, which computes scene bounds via
THREE.Box3.setFromObject→Box3.expandByObjectover the user scene. uikitContentnodes carry a non-Box3value onObject3D.boundingBox(a@preact/signals-coreSignal), which three.js copies unguarded — so a single uikit node takes down the entire editor view.Environment
three@react-three/fiber@react-three/uikit/@pmndrs/uikitSteps to reproduce
Contentnode, e.g.<Root><Svg src="/icon.svg" /></Root>.A scene with no uikit
Contentnodes (or where they are unmounted) opens fine.Root cause
three.js
Box3.expandByObjectreadsobject.boundingBoxand assumes it is aBox3:uikit's
Contentbase class (Svg,Image, …) assigns aSignaltomesh.boundingBox, violating three'sObject3D.boundingBox: Box3 | nullcontract. Triplex's auto-frame callssetFromObjectacross the whole scene, so the malformed bound on one node crashes the entire "render scene" path. Upstream uikit report: .Why Triplex should guard this
Triplex auto-frames arbitrary user scenes that legitimately contain third-party objects. A duck-typed/malformed
boundingBoxon a single node shouldn't hard-fail the whole editor — uikit is widely used, and other libraries may similarly attach non-Box3data. Defensive handling in the auto-frame bounds computation keeps the editor usable across the ecosystem, even before the upstream fix lands.Suggested fix
When computing scene bounds for camera framing, ignore objects whose
.boundingBoxis not a validTHREE.Box3(let three fall back to geometry bounds), or wrap the traversal defensively so one bad node can't abort the render.Workaround for affected users
Install an editor-only guard in the Triplex provider (
.triplex/provider.tsx). It patchesBox3.expandByObjectto ignore non-Box3boundingBoxvalues. It loads only in the editor — production runtime is untouched:This resolves the crash and the camera still frames the node from its geometry bounds.