From 48fc8c0c7f03c94f1b57ec3df33a8f0474a73b29 Mon Sep 17 00:00:00 2001 From: Anton Pascal Date: Fri, 3 Jul 2026 04:06:17 +0000 Subject: [PATCH] fix(editor): guard GLB export against undefined array-material slots (Sentry MONOREPO-EDITOR-79) --- packages/editor/src/lib/glb-export.test.ts | 20 ++++++++++++++++++++ packages/editor/src/lib/glb-export.ts | 14 ++++++++++++++ 2 files changed, 34 insertions(+) diff --git a/packages/editor/src/lib/glb-export.test.ts b/packages/editor/src/lib/glb-export.test.ts index 11b4df7ee..10487802f 100644 --- a/packages/editor/src/lib/glb-export.test.ts +++ b/packages/editor/src/lib/glb-export.test.ts @@ -107,6 +107,26 @@ describe('prepareSceneForExport', () => { expect(visibleChildren).toHaveLength(1) }) + test('fills undefined slots in an array material so no undefined survives the prune', () => { + // Multi-material / group geometry where one slot was never assigned: + // `mesh.material = [validMat, undefined]`. The scalar-null guard doesn't + // catch this (an array is never `== null`), so the undefined slot used to + // reach GLTFExporter and crash on `material.isShaderMaterial`. + const root = new THREE.Group() + const mesh = new THREE.Mesh(new THREE.BoxGeometry(1, 1, 1)) + mesh.material = [nodeMaterial(), undefined as unknown as THREE.Material] + root.add(mesh) + + const { scene } = prepareSceneForExport(root, {}) + + const exported = scene.children[0] as THREE.Mesh + const materials = exported.material as THREE.Material[] + expect(Array.isArray(materials)).toBe(true) + expect(materials).toHaveLength(2) + // No undefined/null slot survives; every slot is a real material. + expect(materials.every((m) => m != null)).toBe(true) + }) + test('stamps identity from the scene registry and strips other userData', () => { const root = new THREE.Group() const doorGroup = new THREE.Group() diff --git a/packages/editor/src/lib/glb-export.ts b/packages/editor/src/lib/glb-export.ts index b00931042..b1ad3977a 100644 --- a/packages/editor/src/lib/glb-export.ts +++ b/packages/editor/src/lib/glb-export.ts @@ -216,6 +216,20 @@ function pruneNonRenderableMeshes(root: THREE.Object3D, identityNodes: Set