From 43100ad65037d7df5b8e3c3cca66b44c8e495d21 Mon Sep 17 00:00:00 2001 From: Michael Mainguy Date: Sat, 15 Nov 2025 08:05:49 -0600 Subject: [PATCH] Fix color persistence using metadata and source mesh ID fallback MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Colors were being lost during resize operations because toDiagramEntity extracted color from material.diffuseColor, which is no longer used after the emissiveColor rendering optimization (commit c7887d7). Root Causes: 1. Rendering system changed from diffuseColor to emissiveColor 2. Material properties unreliable when materials are shared 3. Material-based extraction broke when properties changed Solution - Three-Tier Fallback Chain: Priority 1: mesh.metadata.color - Most reliable, explicitly set during mesh creation - Already populated by buildMeshFromDiagramEntity (line 163) Priority 2: Extract from mesh.sourceMesh.id (InstancedMesh) - Tool mesh IDs encode color: "tool-BOX-#FF0000" - Preserves original tool color regardless of material state - Works for all instanced diagram meshes Priority 3: Material properties (backwards compatibility) - Checks emissiveColor first (current system) - Falls back to diffuseColor (old system) - Handles both StandardMaterial and PBRMaterial - Maintains compatibility with non-instanced meshes Changes: - Import InstancedMesh from @babylonjs/core - Replace direct material extraction with fallback chain - Parse tool mesh ID to extract hex color code - Normalize colors to lowercase - Add null checks for safe color extraction Benefits: ✅ Independent of material system changes ✅ Works with shared materials ✅ Preserves original tool colors ✅ Backwards compatible ✅ More reliable than material-only extraction Files modified: - toDiagramEntity.ts: Implement fallback chain for color extraction 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude --- src/diagram/functions/toDiagramEntity.ts | 34 ++++++++++++++++++++---- 1 file changed, 29 insertions(+), 5 deletions(-) diff --git a/src/diagram/functions/toDiagramEntity.ts b/src/diagram/functions/toDiagramEntity.ts index abb9783..ed7bc9c 100644 --- a/src/diagram/functions/toDiagramEntity.ts +++ b/src/diagram/functions/toDiagramEntity.ts @@ -1,4 +1,4 @@ -import {AbstractMesh} from "@babylonjs/core"; +import {AbstractMesh, InstancedMesh} from "@babylonjs/core"; import {DiagramEntity} from "../types/diagramEntity"; import log from "loglevel"; import {v4 as uuidv4} from 'uuid'; @@ -25,20 +25,44 @@ export function toDiagramEntity(mesh: AbstractMesh): DiagramEntity { entity.from = mesh?.metadata?.from; entity.to = mesh?.metadata?.to; entity.scale = vectoxys(mesh.scaling); - if (mesh.material) { + + // Extract color using fallback chain for reliability + if (mesh.metadata?.color) { + // Priority 1: Explicit metadata color (most reliable) + entity.color = mesh.metadata.color; + } else if (mesh instanceof InstancedMesh && mesh.sourceMesh?.id) { + // Priority 2: Extract from tool mesh ID (e.g., "tool-BOX-#FF0000") + const toolId = mesh.sourceMesh.id; + const parts = toolId.split('-'); + if (parts.length >= 3 && parts[0] === 'tool') { + const color = parts.slice(2).join('-'); // Handle colors with dashes + if (color.startsWith('#')) { + entity.color = color.toLowerCase(); // Normalize to lowercase + } + } + } else if (mesh.material) { + // Priority 3: Fallback to material extraction (backwards compatibility) switch (mesh.material.getClassName()) { case "StandardMaterial": - entity.color = (mesh.material as any).diffuseColor.toHexString(); + const stdMat = mesh.material as any; + const stdColor = stdMat.emissiveColor || stdMat.diffuseColor; + if (stdColor) { + entity.color = stdColor.toHexString()?.toLowerCase(); + } break; case "PBRMaterial": - entity.color = (mesh.material as any).albedoColor.toHexString(); + const pbrMat = mesh.material as any; + const pbrColor = pbrMat.emissiveColor || pbrMat.albedoColor; + if (pbrColor) { + entity.color = pbrColor.toHexString()?.toLowerCase(); + } break; } } else { if (entity.template != "#object-template") { logger.error("toDiagramEntity: mesh.material is null"); } - } + return entity; }