editor: texture references — source stamping + reference mode in GLB export#532
Conversation
| kind: 'project-asset', | ||
| src: resolvedUrl, | ||
| slot: 'map', | ||
| }) |
There was a problem hiding this comment.
Wrong stamp kind for custom textures
Medium Severity
In getTexture, stampPascalTextureRef is always called with kind: 'project-asset', so only project-assets storage URLs can be stamped. Preset loads use kind: 'material', which also accepts materials-bucket and assets-CDN /material/… URLs. Custom material.texture.url values on those paths never get pascalTextureRef, so reference bakes embed full texture data instead of packer-resolvable refs.
Reviewed by Cursor Bugbot for commit 62276ae. Configure here.
…ode in GLB export Bake v2 exporter side: library/preset, legacy scene-material, and item-GLB textures get a validated pascalTextureRef stamped at load (origin-checked, env-derived). Material-ish sources resolve to 'library-material' (storage bucket) or 'app-material' (static catalog on the assets CDN) by URL shape. exportSceneToGlb grows a textures: 'embed' | 'reference' option — reference mode swaps stamped textures for 1x1 canvas-backed placeholders (skipping the WebGPU blit) and writes the ref to both texture and image extras via a GLTFExporter writeTexture plugin. Download GLB stays embed; the bake page passes reference. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
62276ae to
472db40
Compare
There was a problem hiding this comment.
Cursor Bugbot has reviewed your changes using high effort and found 3 potential issues.
There are 4 total unresolved issues (including 1 from previous review).
❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.
Reviewed by Cursor Bugbot for commit 472db40. Configure here.
| } catch { | ||
| cachedStorageOrigin = null | ||
| } | ||
| return cachedStorageOrigin |
There was a problem hiding this comment.
Storage origin cached permanently
Medium Severity
pascalStorageOrigin caches the first resolved value, including null when NEXT_PUBLIC_SUPABASE_URL is missing or invalid. Later calls never re-read the env, so storage-backed stampPascalTextureRef / getPascalTextureRef checks can stay disabled for the whole JS realm even after the variable becomes available (e.g. test order or late config).
Reviewed by Cursor Bugbot for commit 472db40. Configure here.
| ) as LoadedItemGltf | ||
| return useMemo(() => { | ||
| stampItemTextureReferences(gltf, url) | ||
| return gltf |
There was a problem hiding this comment.
Item refs skip CDN paths
Medium Severity
stampItemTextureReferences passes the resolveCdnUrl load URL into stampPascalTextureRef as item-glb src, but validation only accepts Supabase storage URLs under /storage/v1/object/public/items/. App-relative paths like /items/…/model.glb become assets-CDN URLs, so item textures never get pascalTextureRef and reference bakes embed full item texture pixels.
Reviewed by Cursor Bugbot for commit 472db40. Configure here.
| imageDef.extras = { | ||
| ...imageDef.extras, | ||
| pascalTextureRef: ref, | ||
| } |
There was a problem hiding this comment.
Shared image extras overwritten
Medium Severity
In reference mode, writeTextureReferenceExtras writes pascalTextureRef onto the shared glTF images[] entry for every stamped map. Identical 1×1 placeholder pixels are often deduplicated to one image index, so each writeTexture overwrites imageDef.extras and only the last ref remains while earlier textures[] entries may still point at that image.
Reviewed by Cursor Bugbot for commit 472db40. Configure here.


What does this PR do?
Bake v2 exporter side (private-editor plan
editor-baked-glb-client-capture, Decisions section). Textures in a baked scene always have a server-known source, so the export no longer needs to ship their pixels:viewer/lib/texture-reference.tsstamps a validatedpascalTextureRef({v, kind, src, map, colorSpace, imageIndex?}) ontotexture.userDataat the three load sites: preset/library materials (materials.ts, resolving tolibrary-materialfor storage-bucket URLs orapp-materialfor static-catalog/material/…URLs), the legacygetTexturepath (project-asset), and item GLB textures (item-glbwith the glTF image index viaparser.associations, including theKHR_texture_basisusource indirection).exportSceneToGlbgainstextures: 'embed' | 'reference'(defaultembed, byte-for-byte current behavior). Reference mode swaps stamped textures for 1×1 canvas-backed placeholders (skipping the WebGPUTextureUtils blit — the export speedup) while preserving sampler state/transforms, and writes the ref to BOTHtextures[i].extrasandimages[j].extrasvia a GLTFExporterwriteTextureplugin.BakeExporter) passesreference; the Download GLB button staysembed(external consumers need pixels).Origin validation is env-derived (
NEXT_PUBLIC_SUPABASE_URL/NEXT_PUBLIC_ASSETS_CDN_URLdefault) and fails closed — no env, no stamps, everything falls back to embed. Pairs with the private-editor packer PR that resolves these refs in the bake LOD chain (attach original KTX2, no decode/re-encode).How to test
bun test packages/viewer/src/lib/texture-reference.test.ts packages/editor/src/lib/glb-export.test.ts— 21 tests cover stamp resolution per kind, origin rejection, placeholder swap, shared-texture dedup, and identical texture/image extras.bun dev), paint a wall and use Download GLB — output is unchanged (embed mode; textures render in any glTF viewer).feat/bake-v2): run a local bake of a painted scene and check the[bake:textures]log line — referenced textures resolve,rejected: 0, and lod0 textures are byte-identical to the catalog KTX2 files. (Verified on the Wawa House local copy: 31 refs, raw 9.79 → 4.79 MB.)Screenshots / screen recording
N/A — non-visual change (export/bake internals; Download GLB output is byte-for-byte unchanged in default mode).
Checklist
bun devbun checkto verify)editor-baked-glb-client-capture.mdin private-editor carries the contract + decisions)mainbranch🤖 Generated with Claude Code
Note
Medium Risk
Touches GLB export and bake capture paths; default embed mode preserves prior behavior, but reference mode must stay aligned with the downstream bake packer contract.
Overview
Adds
pascalTextureRefmetadata on textures at load time so baked GLBs can point at server-known KTX2/sources instead of embedding pixels.Stamping (
texture-reference.ts): validated refs (kind,src,map,colorSpace, optionalimageIndexfor item GLBs) are written totexture.userDatafrom library/preset materials, project-asset maps, and item GLB loads (image index from glTF parser associations). Non-Pascal URLs are left unstamped.GLB export gains
textures: 'embed' | 'reference'(defaultembed— unchanged for Download GLB). Reference mode replaces stamped maps with shared 1×1 placeholders (keeping UV/sampler state), registers aGLTFExporterplugin to copy the same ref intotextures[].extrasandimages[].extras, andBakeExporternow exports withtextures: 'reference'for smaller/faster bakes resolved downstream by the packer.Reviewed by Cursor Bugbot for commit 472db40. Bugbot is set up for automated code reviews on this repo. Configure here.