# Plan: Fix GLB Export Pipeline + Viewer Staleness ## Root Cause Analysis ### Bug 1 — `export_colors` not valid in Blender 5.0 (CRITICAL) **File**: `render-worker/scripts/export_gltf.py` `bpy.ops.export_scene.gltf(export_colors=False)` → Blender exits code 1: `keyword "export_colors" unrecognized` → Blender path always fails → always falls back to trimesh → no materials, no sharp edges, faceted mesh. This is confirmed in every single log entry. Blender has never successfully exported a GLB. ### Bug 2 — `GlbModel` `cloned` ref never resets on URL change (CRITICAL) **File**: `frontend/src/components/cad/InlineCadViewer.tsx` `cloned = useRef(null)` with guard `if (!cloned.current)` only clones once. When `glbBlobUrl` changes (new GLB generated), React does NOT remount `GlbModel` (same position in tree), so `cloned.current` still holds the old geometry → old mesh shown forever. Fix: add `key={glbBlobUrl}` to `` → forces remount on each new URL. ### Bug 3 — `glbBlobUrl` not cleared between fetches (UX) **File**: `frontend/src/components/cad/InlineCadViewer.tsx` When `downloadUrl` changes, cleanup revokes the old blob URL, but `glbBlobUrl` state still holds the (now revoked) old URL → `GlbModel` tries to render a revoked URL for the duration of the new fetch. Fix: `setGlbBlobUrl(null)` at the start of the effect before fetching. ### Bug 4 — `staleTime: 30_000` delays detecting new GLB (UX) **File**: `frontend/src/components/cad/InlineCadViewer.tsx` After "Generate GLB" the task completes and a new MediaAsset is written to DB, but the assets query is cached for 30 seconds → `downloadUrl` stays stale → viewer fetches old GLB. Fix: reduce `staleTime` to `0` so the query always refetches on focus/mount after invalidation. --- ## Affected Files | File | Change | Bug | |------|--------|-----| | `render-worker/scripts/export_gltf.py` | Remove invalid `export_colors=False` | 1 | | `frontend/src/components/cad/InlineCadViewer.tsx` | key={glbBlobUrl} on GlbModel + clear state + staleTime=0 | 2, 3, 4 | --- ## Tasks ### Task 1: Fix Blender GLTF export parameters **File**: `render-worker/scripts/export_gltf.py` Remove `export_colors=False` from `bpy.ops.export_scene.gltf()` call. Keep `export_materials="EXPORT"` and `export_image_format="AUTO"` — these are valid in Blender 5.0. **Acceptance**: Blender exits 0, GLB file is created with materials. **Requires rebuild**: yes — scripts are COPY'd into container. ### Task 2: Fix GlbModel stale mesh on regeneration **File**: `frontend/src/components/cad/InlineCadViewer.tsx` Add `key={glbBlobUrl}` on the `` element inside the Canvas. This forces React to unmount+remount GlbModel whenever the blob URL changes, resetting the `cloned` ref and loading the fresh geometry. **Acceptance**: After generating a new GLB, the viewer shows the new mesh, not the old one. ### Task 3: Clear stale blob URL before new fetch **File**: `frontend/src/components/cad/InlineCadViewer.tsx` At the top of the `useEffect([downloadUrl, token])` body, add `setGlbBlobUrl(null)` before the fetch. This shows the loading spinner instead of a broken/stale model during re-fetch. **Acceptance**: After regeneration, viewer shows spinner while new GLB loads. ### Task 4: Remove staleTime delay on asset query **File**: `frontend/src/components/cad/InlineCadViewer.tsx` Change `staleTime: 30_000` → `staleTime: 0` on the `gltf_geometry` assets query. The `qc.invalidateQueries()` call after generating already forces a refetch, but staleTime=0 also ensures refetch on window focus/tab return. **Acceptance**: New MediaAsset is picked up within seconds of task completion. --- ## Reihenfolge Task 1 (rebuild) + Tasks 2/3/4 (frontend hot-reload) in parallel. ## Risiken - `export_materials="EXPORT"` and `export_image_format="AUTO"` may also be invalid in Blender 5.0. If so, remove them too and test with bare minimum params (format + apply only). - If the Schaeffler .blend library materials use custom node groups instead of Principled BSDF, the GLTF exporter will still export flat grey — that requires material baking, out of scope here.