Skip to content

Editor crashes ("Could not render scene: Cannot read properties of undefined (reading 'x')") when camera auto-frame walks a scene containing @react-three/uikit components #405

Description

@KutlayTunc

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.setFromObjectBox3.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

  1. In an R3F project wired for Triplex, create a scene that renders a uikit Content node, e.g. <Root><Svg src="/icon.svg" /></Root>.
  2. Open that scene in Triplex.
  3. 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.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions