@liveroom-tech/react-immersive 5.2.0 → 6.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (52) hide show
  1. package/LICENSE +10 -6
  2. package/README.md +106 -3856
  3. package/dist/binding-builder.css +1 -1
  4. package/dist/binding-builder.d.mts +5 -1
  5. package/dist/binding-builder.d.ts +5 -1
  6. package/dist/binding-builder.js +67 -17
  7. package/dist/binding-builder.mjs +1 -1
  8. package/dist/chunk-2JFUMJUP.mjs +1 -0
  9. package/dist/chunk-4JMJALRO.mjs +2 -0
  10. package/dist/chunk-OTSCPJWF.mjs +1 -0
  11. package/dist/chunk-P2JZ5Z7I.mjs +1 -0
  12. package/dist/chunk-UGPR4EPP.mjs +81 -0
  13. package/dist/chunk-V7WZUWJ5.mjs +1 -0
  14. package/dist/chunk-WWUWEPFK.mjs +3 -0
  15. package/dist/hosted.css +1 -1
  16. package/dist/hosted.d.mts +48 -19
  17. package/dist/hosted.d.ts +48 -19
  18. package/dist/hosted.js +66 -16
  19. package/dist/hosted.mjs +1 -1
  20. package/dist/index.css +1 -1
  21. package/dist/index.d.mts +78 -12
  22. package/dist/index.d.ts +78 -12
  23. package/dist/index.js +65 -15
  24. package/dist/index.mjs +1 -1
  25. package/dist/{materialVariants-DnZe9eMC.d.mts → modelFileResolver-Co7j1tdQ.d.mts} +125 -27
  26. package/dist/{materialVariants-DnZe9eMC.d.ts → modelFileResolver-Co7j1tdQ.d.ts} +125 -27
  27. package/dist/modelViewerProps-BibuMND7.d.ts +1988 -0
  28. package/dist/modelViewerProps-Ce4-wb57.d.mts +1988 -0
  29. package/dist/{publicProps-tJuWZgT3.d.ts → publicProps-BaJHCDa_.d.mts} +7 -0
  30. package/dist/{publicProps-tJuWZgT3.d.mts → publicProps-CP18d_mt.d.ts} +7 -0
  31. package/dist/simple-model-viewer.d.mts +2 -4
  32. package/dist/simple-model-viewer.d.ts +2 -4
  33. package/dist/simple-model-viewer.js +3 -3
  34. package/dist/simple-model-viewer.mjs +1 -1
  35. package/dist/utils.d.mts +62 -4
  36. package/dist/utils.d.ts +62 -4
  37. package/dist/utils.js +2 -1
  38. package/dist/utils.mjs +1 -1
  39. package/package.json +2 -1
  40. package/dist/chunk-4NLJSD3S.mjs +0 -1
  41. package/dist/chunk-B7REIGDG.mjs +0 -1
  42. package/dist/chunk-HYFJ5DYJ.mjs +0 -1
  43. package/dist/chunk-QC3NT76G.mjs +0 -3
  44. package/dist/chunk-SEESCGUS.mjs +0 -1
  45. package/dist/chunk-T3M3BQ7H.mjs +0 -32
  46. package/dist/chunk-ZPK67UG7.mjs +0 -1
  47. package/dist/modelInfo-BYebMPdZ.d.mts +0 -43
  48. package/dist/modelInfo-XfUQO7C_.d.ts +0 -43
  49. package/dist/modelViewerProps-CIZ2R_Fv.d.ts +0 -569
  50. package/dist/modelViewerProps-DoRiTZMn.d.mts +0 -569
  51. package/dist/rendererBackend-QwMzISTn.d.mts +0 -903
  52. package/dist/rendererBackend-QwMzISTn.d.ts +0 -903
@@ -0,0 +1,3 @@
1
+ import{A as Wl,B as Yl,C as Jl,D as _e,E as Xl,F as Zl,G as Ql,H as Yi,I as ed,J as nd,L as od,M as ad,N as cd,a as $i,b as pl,c as bl,d as ul,e as ml,f as qi,h as Fa,j as Al,k as wo,l as Va,m as Dl,n as Ll,o as _i,p as zl,q as Fl,r as ut,s as Hl,t as Mt,u as bn,v as $l,w as lt,x as Vl,y as Gl,z as _l}from"./chunk-UGPR4EPP.mjs";import{J as qa,K as Ul,g as Vi,j as Pn,z as Bl}from"./chunk-OTSCPJWF.mjs";import{Ba as Ui,Ca as Ha,D as gl,Da as $a,E as fl,F as hl,Fa as Ki,G as xl,Ga as Rl,H as yl,Ha as Wi,I as vl,J as Yo,Ja as ql,K as Sl,L as Tn,M as wl,P as La,Q as _n,Qa as Jo,Sa as Ua,T as Wn,Ta as Kl,U as Cl,Ua as td,V as kl,Va as Ji,W as Ml,Wa as id,Xa as rd,Ya as sd,Za as ld,_a as dd,a as Da,e as _o,f as sl,g as ll,h as Hi,i as dl,j as Gn,ka as za,l as cl,na as So,qa as Nl,r as vo,s as en,t as Yt,u as Wo}from"./chunk-4JMJALRO.mjs";import{L as jl,M as El,P as Il,Q as Gi,n as Tl,q as Pl,w as Ol}from"./chunk-V7WZUWJ5.mjs";function Bn(e){return{annotations:e.annotations,animations:e.animations,activeVariants:e.model.activeVariants,measurements:e.measurements,selectionSets:e.selectionSets,sequences:e.sequences}}function mt(e,t){return{...e,model:{...e.model,activeVariants:t?.activeVariants??[]},annotations:t?.annotations??[],animations:t?.animations??Tn.animations,measurements:t?.measurements,selectionSets:t?.selectionSets,sequences:t?.sequences}}function bd(e){if(e===void 0)return!0;try{return So(e),!0}catch{return!1}}function ud(e){if(e===void 0)return!0;try{return za(e),!0}catch{return!1}}var pm="react-immersive:binding-builder",bm=2,Rn="session",An="model",On="textures",Zi="current",md=1;function tn(e){return e.kind==="file"?`file:${e.key}`:`url:${e.url}`}var Yn=null;function Xo(){return Yn||(Yn=new Promise((e,t)=>{if(typeof indexedDB>"u"){t(new Error("IndexedDB is not available in this environment."));return}let a=indexedDB.open(pm,bm);a.onupgradeneeded=()=>{let i=a.result;i.objectStoreNames.contains(Rn)||i.createObjectStore(Rn),i.objectStoreNames.contains(An)||i.createObjectStore(An),i.objectStoreNames.contains(On)||i.createObjectStore(On)},a.onsuccess=()=>{let i=a.result;i.onversionchange=()=>{i.close(),Yn=null},e(i)},a.onerror=()=>t(a.error??new Error("Failed to open IndexedDB."))}),Yn.catch(()=>{Yn=null}),Yn)}function Co(e){return new Promise((t,a)=>{e.oncomplete=()=>t(),e.onerror=()=>a(e.error??new Error("IndexedDB transaction failed.")),e.onabort=()=>a(e.error??new Error("IndexedDB transaction aborted."))})}function Qi(e){return new Promise((t,a)=>{e.onsuccess=()=>t(e.result),e.onerror=()=>a(e.error??new Error("IndexedDB request failed."))})}function Pt(e){return e!==null&&typeof e=="object"&&!Array.isArray(e)}function er(e){return!Pt(e)||typeof e.name!="string"?!1:e.kind==="file"?typeof e.key=="string":e.kind==="url"?typeof e.url=="string":!1}function gd(e){return Pt(e)&&er(e.model)&&typeof e.namePrefix=="string"}function um(e){if(e===void 0)return!0;try{return wl(e),!0}catch{return!1}}function fd(e){if(e===void 0)return!0;try{return Gn(e),!0}catch{return!1}}function mm(e){return!Pt(e)||!er(e.model)||!Pt(e.bindings)||!Pt(e.originalTransforms)||e.modelSettings!==void 0&&(!Pt(e.modelSettings)||!Array.isArray(e.modelSettings.annotations)||!Pt(e.modelSettings.animations)||!Array.isArray(e.modelSettings.animations.clips)||e.modelSettings.activeVariants!==void 0&&(!Array.isArray(e.modelSettings.activeVariants)||!e.modelSettings.activeVariants.every(t=>typeof t=="string")))||Pt(e.modelSettings)&&!ud(e.modelSettings.measurements)||Pt(e.modelSettings)&&!bd(e.modelSettings.selectionSets)||Pt(e.modelSettings)&&!fd(e.modelSettings.sequences)?!1:e.mergeModels===void 0?!0:Array.isArray(e.mergeModels)&&e.mergeModels.every(gd)}function Ka(e){if(!Pt(e)||e.version!==md)return!1;if(e.composition!==void 0)try{Wn(e.composition)}catch{return!1}return!(typeof e.savedAt!="number"||!Pt(e.bindings)||!Pt(e.sceneConfig)||!er(e.model)||!ud(e.sceneConfig.measurements)||!bd(e.sceneConfig.selectionSets)||!fd(e.sceneConfig.sequences)||!um(e.sceneConfig.section)||e.parkedModels!==void 0&&(!Array.isArray(e.parkedModels)||!e.parkedModels.every(mm))||e.mergeModels!==void 0&&(!Array.isArray(e.mergeModels)||!e.mergeModels.every(gd))||e.modelOrder!==void 0&&(!Array.isArray(e.modelOrder)||!e.modelOrder.every(t=>typeof t=="string")))}function Xi(e,t){return e.kind==="url"?Promise.resolve(null):Qi(t.get(e.key)).then(a=>!a||a.key!==e.key?null:new File([a.blob],a.name,{type:a.type,lastModified:a.lastModified}))}async function hd(e,t){let a=await Xo(),i={...e,version:md,savedAt:Date.now()},n=a.transaction([Rn,An],"readwrite"),o=Co(n);n.objectStore(Rn).put(i,Zi);let d=n.objectStore(An),l=new Set,c=h=>{h.kind==="file"&&l.add(h.key)};c(i.model),i.mergeModels?.forEach(h=>c(h.model)),i.parkedModels?.forEach(h=>{c(h.model),h.mergeModels?.forEach(y=>c(y.model))});for(let{key:h,file:y}of t??[]){let u={key:h,blob:y,name:y.name,type:y.type,lastModified:y.lastModified};d.put(u,h)}let w=d.getAllKeys();return w.onsuccess=()=>{for(let h of w.result)l.has(h)||d.delete(h)},await o,i}function pd(e,t){return Promise.all(e.map(async a=>({entry:a,file:await Xi(a.model,t)})))}async function xd(){let e=await Xo(),t=e.transaction(Rn,"readonly"),a=Co(t),i=await Qi(t.objectStore(Rn).get(Zi));if(await a,!Ka(i))return null;let n=i.parkedModels??[],o=i.mergeModels??[],d=e.transaction(An,"readonly"),l=Co(d),c=d.objectStore(An),[w,h,y]=await Promise.all([Xi(i.model,c),pd(o,c),Promise.all(n.map(async u=>({entry:u,file:await Xi(u.model,c),mergeFiles:await pd(u.mergeModels??[],c)})))]);return await l,i.model.kind==="file"&&!w?null:{session:{...i,parkedModels:n,mergeModels:o},file:w,parkedFiles:y,mergeFiles:h}}async function yd(){let t=(await Xo()).transaction([Rn,An,On],"readwrite"),a=Co(t);t.objectStore(Rn).delete(Zi),t.objectStore(An).clear(),t.objectStore(On).clear(),await a}async function ko(e,t){let i=(await Xo()).transaction(On,"readwrite"),n=Co(i),o={blob:t,name:t.name,type:t.type,savedAt:Date.now()};i.objectStore(On).put(o,e),await n}async function un(e){let a=(await Xo()).transaction(On,"readonly"),i=Co(a),n=await Qi(a.objectStore(On).get(e));return await i,n?new File([n.blob],n.name,{type:n.type,lastModified:n.savedAt}):null}function Xn(e){return`url:${e}`}function nr(e){return e.models.find(t=>!e.composition.placements[Xn(t.url)]?.deleted)??e.models[0]}function or(e){return Wn(e.composition)}function _a(e,t){return mt(e,t.modelSettings)}function gm(e){return{url:e.url,namePrefix:e.namePrefix,resolved:{url:e.url,name:e.namePrefix,format:"glb",cleanup:()=>{}},sessionModel:{kind:"url",url:e.url,name:e.namePrefix},nodeNames:[],loadState:"loading"}}function Mo(e){return(e.mergeModels??[]).map(gm)}function ar(e){let t=e.name??"model";return{url:e.url,name:t,bindings:e.objectBindings,originalTransforms:{},sessionModel:{kind:"url",url:e.url,name:t},mergedModelSources:Mo(e),modelSettings:e.modelSettings}}function ir(e){let t=new Map;for(let a of e.models){let{url:i,name:n,assetId:o,tilesetUrl:d,assetVersion:l}=a;t.set(i,{url:i,name:n,assetId:o,tilesetUrl:d,assetVersion:l});for(let c of a.mergeModels??[])t.set(c.url,{url:c.url,assetId:c.assetId})}return t}function vd(e){let t=i=>i.map(n=>({url:n.url,assetId:e.sources.get(n.url)?.assetId??null,namePrefix:n.namePrefix})),a=e.modelOrder.flatMap(i=>{if(e.composition.placements[Xn(i)]?.deleted)return[];let n=e.sources.get(i)??{url:i};if(i===e.modelUrl)return[{...n,url:i,name:e.modelName,objectBindings:e.bindings,mergeModels:t(e.mergedModelSources),modelSettings:Bn(e.sceneConfig)}];let o=e.parkedModels.find(d=>d.url===i);return o?[{...n,url:i,name:o.name,objectBindings:o.bindings,mergeModels:t(o.mergedModelSources),modelSettings:o.modelSettings}]:[]});return{projectId:e.project.id,baseRevision:e.project.revision,models:a,composition:{...e.composition,placements:Object.fromEntries(Object.entries(e.composition.placements).filter(([,i])=>!i.deleted))},sceneConfig:mt(e.sceneConfig)}}function tr(e){return JSON.stringify(e,(t,a)=>a&&typeof a=="object"&&!Array.isArray(a)?Object.fromEntries(Object.entries(a).sort(([i],[n])=>i<n?-1:i>n?1:0)):a)}function Wa(e,t){return e===t||tr(e)===tr(t)}function fm(e){return Bn(mt(Tn,e))}function Zo(e){return tr({models:e.models.map(t=>({url:t.url,name:t.name,objectBindings:t.objectBindings,mergeModels:(t.mergeModels??[]).map(({url:a,namePrefix:i})=>({url:a,namePrefix:i})),modelSettings:fm(t.modelSettings)})),composition:e.composition,sceneConfig:mt(e.sceneConfig)})}function Tx(e){if(!(e.models.length<2))return e.models.flatMap(t=>{let a=e.composition.placements[Xn(t.url)]??{};return a.deleted?[]:[{url:t.url,label:a.label??t.name,transform:a,visible:a.visible!==!1,objectBindings:t.objectBindings,sceneConfig:_a(e.sceneConfig,t),mergeModels:t.mergeModels?.map(({url:i,namePrefix:n})=>({url:i,namePrefix:n}))}]})}var Sd=new Set(["path","image","url","poster","src","imageUrl"]);function hm(e){return e.startsWith("blob:")||e.startsWith("data:")||!!en(e)}function Jn(e,t=new Set){if(Array.isArray(e))e.forEach(a=>Jn(a,t));else if(e&&typeof e=="object")for(let[a,i]of Object.entries(e))typeof i=="string"?Sd.has(a)&&hm(i)&&t.add(i):Jn(i,t);return t}function Ga(e,t){return Array.isArray(e)?e.map(a=>Ga(a,t)):e&&typeof e=="object"?Object.fromEntries(Object.entries(e).map(([a,i])=>[a,typeof i=="string"&&Sd.has(a)&&t.has(i)?t.get(i):Ga(i,t)])):e}async function wd(e){let t=en(e)??e,a=await(await fetch(t)).blob(),i=e.startsWith("blob:")||e.startsWith("data:")?"image":e.split("/").pop()||"image";return new File([a],i,{type:a.type})}async function Cd(e,t){let a=h=>e.session.composition?.placements[tn(h)]?.deleted;e={...e,parkedFiles:e.parkedFiles.filter(h=>!a(h.entry.model))};let i=new Map,n=async(h,y)=>{if(h.kind!=="file")return h;if(!y)throw new Error(`The scene bundle is missing ${h.name}.`);let{url:u}=await t(y);return i.set(`file:${h.key}`,Xn(u)),{kind:"url",url:u,name:h.name}},o=async h=>{let y=[];for(let{entry:u,file:g}of h)y.push({entry:{...u,model:await n(u.model,g)},file:null});return y},d=await n(e.session.model,e.file),l=await o(e.mergeFiles),c=[];for(let h of e.parkedFiles){let y=await n(h.entry.model,h.file),u=await o(h.mergeFiles);c.push({entry:{...h.entry,model:y,mergeModels:u.map(g=>g.entry)},file:null,mergeFiles:u})}let w=e.session.composition;return{file:null,mergeFiles:l,parkedFiles:c,session:{...e.session,model:d,mergeModels:l.map(h=>h.entry),parkedModels:c.map(h=>h.entry),modelOrder:e.session.modelOrder?.map(h=>i.get(h)??h),composition:w&&{...w,placements:Object.fromEntries(Object.entries(w.placements).map(([h,y])=>[i.get(h)??h,y]))}}}}import{strFromU8 as xm,strToU8 as ym,unzip as vm}from"fflate";var Qo=512*1024*1024,kd=5*1024*1024;function rr(e){return[e.model,...(e.mergeModels??[]).map(t=>t.model),...(e.parkedModels??[]).flatMap(t=>[t.model,...(t.mergeModels??[]).map(a=>a.model)])]}function Md(e){let t=n=>n.kind==="file"?`/bundle/${encodeURIComponent(n.key)}.glb`:n.url,a=[{model:e.model,bindings:e.bindings,merges:e.mergeModels,config:e.sceneConfig},...(e.parkedModels??[]).map(n=>({model:n.model,bindings:n.bindings,merges:n.mergeModels,config:mt(e.sceneConfig,n.modelSettings)}))],i=a.map(n=>n.model.kind==="file"?`file:${n.model.key}`:`url:${n.model.url}`);if(new Set(i).size!==i.length||a.length>256)throw new Error("Scene instances must have unique identities (maximum 256).");if(e.modelOrder&&(new Set(e.modelOrder).size!==e.modelOrder.length||e.modelOrder.some(n=>!i.includes(n))))throw new Error("Invalid scene asset order.");for(let n of e.parkedModels??[])for(let o of Object.values(n.originalTransforms))for(let d of["position","rotation","scale"]){let l=o?.[d];if(l!==void 0&&(!Array.isArray(l)||l.length!==3||!l.every(c=>typeof c=="number"&&Number.isFinite(c))))throw new Error("Invalid original node transform.")}for(let n of a)Nl({version:1,objectBindings:n.bindings,configuration:{modelUrl:t(n.model),sceneConfig:n.config,mergeModels:n.merges?.map(o=>({url:t(o.model),namePrefix:o.namePrefix}))}})}async function Nd(e,t){let a=JSON.parse(JSON.stringify({...e,version:1,savedAt:Date.now()})),i={},n=[],o=[],d=0;async function l(u,g){if(d+=g.size,d>Qo)throw new Error("Scene bundle exceeds the 512 MiB expanded limit.");i[u]=new Uint8Array(await g.arrayBuffer())}for(let u of rr(a)){if(u.kind!=="file"||n.some(v=>v.key===u.key))continue;let g=t.get(u.key);if(!g)throw new Error(`Cannot save scene: missing uploaded file ${u.name}.`);let B=`models/${n.length}`;n.push({key:u.key,path:B,name:g.name,type:g.type,lastModified:g.lastModified}),await l(B,g)}let c=new Map;async function w(u,g=0){if(g>64)throw new Error("Scene data is too deeply nested.");if(!(!u||typeof u!="object"))for(let[B,v]of Object.entries(u)){if(["__proto__","prototype","constructor"].includes(B))throw new Error("Reserved scene property.");if(B!=="metadata")if(typeof v=="string"){if(!["path","image","url","poster","src","imageUrl","customEnvironmentUrl"].includes(B))continue;let P=en(v),x=P||v.startsWith("blob:")||v.startsWith("data:")?null:await un(v);if(!x&&!P&&!v.startsWith("blob:")&&!v.startsWith("data:"))continue;let C=c.get(v);if(C){u[B]=C;continue}if(!x){let k=await fetch(P??v);if(!k.ok)throw new Error("Cannot read an uploaded texture for this scene.");let O=await k.blob();x=new File([O],`texture-${o.length}`,{type:O.type})}let S=`textures/${o.length}`,f=`/__ri_bundle_texture__/${o.length}`;o.push({ref:f,path:S,name:x.name,type:x.type}),await l(S,x),c.set(v,f),u[B]=f}else await w(v,g+1)}}for(let u of rr(a))if(u.kind==="url"&&u.url.startsWith("blob:"))throw new Error("Cannot save a temporary model URL without its original file.");if(await w(a),!Ka(a))throw new Error("Invalid scene snapshot.");Md(a);let h=ym(JSON.stringify({format:"react-immersive-scene",version:1,session:a,files:n,textures:o}));if(h.byteLength>kd)throw new Error("Scene settings exceed the 5 MiB limit.");if(d+h.byteLength>Qo||Object.keys(i).length+1>1024)throw new Error("Scene bundle exceeds its size or file-count limit.");i["scene.json"]=h;let y=await Va(i);if(y.byteLength>Qo)throw new Error("Compressed scene bundle exceeds 512 MiB.");return new Blob([y],{type:"application/zip"})}async function Td(e){if(e.size>Qo)throw new Error("Scene ZIP exceeds 512 MiB.");let t=0,a=0,i="",n=new Set,o=new Uint8Array(await e.arrayBuffer()),d=await new Promise((v,P)=>vm(o,{filter(x){return t+=x.originalSize,a++,n.has(x.name)?(i="Duplicate scene ZIP entry.",!1):(n.add(x.name),a>1024||t>Qo||x.name==="scene.json"&&x.originalSize>kd||!/^(scene\.json|models\/\d+|textures\/\d+)$/.test(x.name)?(i="Invalid or oversized scene ZIP entries.",!1):!0)}},(x,C)=>x?P(x):i?P(new Error(i)):v(C)));if(!d["scene.json"])throw new Error("This ZIP does not contain a React Immersive scene.");let l=JSON.parse(xm(d["scene.json"]));if(l.format!=="react-immersive-scene"||l.version!==1||!Ka(l.session)||!Array.isArray(l.files)||!Array.isArray(l.textures))throw new Error("Invalid scene bundle manifest.");Md(l.session);let c=new Map,w=new Set;for(let v of l.files){if(!v||typeof v.key!="string"||!/^models\/\d+$/.test(v.path)||!d[v.path]||typeof v.name!="string"||typeof v.type!="string"||!Number.isFinite(v.lastModified)||w.has(v.path)||c.has(v.key))throw new Error("Invalid model file in scene bundle.");w.add(v.path),c.set(v.key,new File([d[v.path]],v.name,{type:v.type,lastModified:v.lastModified}))}for(let v of rr(l.session))if(v.kind==="file"&&!c.has(v.key))throw new Error(`Scene bundle is missing ${v.name}.`);let h=new Map,y=crypto.randomUUID();for(let v of l.textures){if(!v||typeof v.ref!="string"||!/^\/__ri_bundle_texture__\/\d+$/.test(v.ref)||!/^textures\/\d+$/.test(v.path)||!d[v.path]||typeof v.name!="string"||typeof v.type!="string"||w.has(v.path)||h.has(v.ref))throw new Error("Invalid texture in scene bundle.");w.add(v.path),h.set(v.ref,{path:`materials/scene-${y}/${h.size}`,file:new File([d[v.path]],v.name,{type:v.type})})}function u(v,P=0){if(P>64)throw new Error("Scene data is too deeply nested.");if(!(!v||typeof v!="object"))for(let[x,C]of Object.entries(v)){if(["__proto__","constructor","prototype"].includes(x))throw new Error("Reserved scene property.");if(x!=="metadata")if(typeof C=="string"&&C.startsWith("/__ri_bundle_texture__/")){let S=h.get(C);if(!S)throw new Error("Scene bundle is missing a texture.");if(x==="path")v[x]=S.path;else{let f=d[[...l.textures].find(O=>O.ref===C).path],k="";for(let O=0;O<f.length;O+=32768)k+=String.fromCharCode(...f.subarray(O,O+32768));v[x]=`data:${S.file.type||"application/octet-stream"};base64,${btoa(k)}`}}else u(C,P+1)}}u(l.session),await Promise.all([...h.values()].map(v=>ko(v.path,v.file)));let g=v=>v.kind==="file"?c.get(v.key):null,B=v=>v.map(P=>({entry:P,file:g(P.model)}));return{session:l.session,file:g(l.session.model),mergeFiles:B(l.session.mergeModels??[]),parkedFiles:(l.session.parkedModels??[]).map(v=>({entry:v,file:g(v.model),mergeFiles:B(v.mergeModels??[])}))}}import{useCallback as ie,useEffect as dt,useMemo as ct,useRef as de,useState as _}from"react";import{Box3 as ab,Vector3 as ox}from"three";import{Ellipsis as ax,Pin as ix,PinOff as rx,SlidersHorizontal as sx,SquareSplitHorizontal as lx,Trash2 as dx}from"lucide-react";import{useEffect as Sm,useId as wm,useRef as Pd,useState as Bd}from"react";import{ChevronDown as Cm,History as km,Plus as Mm,Trash2 as Nm}from"lucide-react";import{Fragment as Ad,jsx as jn,jsxs as mn}from"react/jsx-runtime";function sr({label:e,icon:t,title:a,align:i="left",children:n}){let[o,d]=Bd(!1),l=Pd(null),c=Pd(null),w=wm();return Sm(()=>{if(!o)return;let h=u=>{l.current?.contains(u.target)||d(!1)},y=u=>{u.key==="Escape"&&(d(!1),c.current?.focus())};return window.addEventListener("pointerdown",h),window.addEventListener("keydown",y),()=>{window.removeEventListener("pointerdown",h),window.removeEventListener("keydown",y)}},[o]),mn("div",{className:"bb-headerMenuWrapper",ref:l,children:[mn("button",{ref:c,type:"button",className:`bb-headerButton ${e?"":"bb-headerButton--icon"} ${o?"bb-headerButton--open":""}`,onClick:()=>d(h=>!h),title:a,"aria-label":e?void 0:a,"aria-expanded":o,"aria-controls":o?w:void 0,children:[t,e?mn(Ad,{children:[e,jn(Cm,{size:12,"aria-hidden":"true"})]}):null]}),o?jn("div",{id:w,className:`bb-headerMenu bb-headerMenu--${i}`,role:"group","aria-label":a,children:n(()=>d(!1))}):null]})}function Rd({onRestore:e,onRemove:t,onAddModel:a,restoreDisabled:i,addModelDisabled:n,confirmRemove:o=!0,close:d}){let[l,c]=Bd(!1);return l&&t?mn("div",{className:"bb-headerMenuConfirm",role:"alertdialog","aria-label":"Remove model",children:[jn("p",{children:"Remove the model and its bindings from the editor? This also clears the saved session. Export your work first if you want to keep it."}),mn("div",{className:"bb-headerMenuConfirmActions",children:[jn("button",{type:"button",className:"bb-headerMenuItem",onClick:()=>c(!1),children:"Cancel"}),jn("button",{type:"button",className:"bb-headerMenuItem bb-headerMenuItem--danger",onClick:()=>{d(),t()},autoFocus:!0,children:"Remove"})]})]}):mn(Ad,{children:[a?mn("button",{type:"button",className:"bb-headerMenuItem",disabled:n,onClick:()=>{d(),a()},title:"Add another model, as a separate model or merged into this one",children:[jn(Mm,{size:14,"aria-hidden":"true"}),"Add model\u2026"]}):null,e?mn("button",{type:"button",className:"bb-headerMenuItem",disabled:i,onClick:()=>{d(),e()},title:"Restore your last session: the model, its object bindings, and scene settings saved in this browser",children:[jn(km,{size:14,"aria-hidden":"true"}),"Restore last session"]}):null,t?mn("button",{type:"button",className:"bb-headerMenuItem bb-headerMenuItem--danger",onClick:()=>{if(o){c(!0);return}d(),t()},children:[jn(Nm,{size:14,"aria-hidden":"true"}),"Remove model\u2026"]}):null]})}import{useCallback as Tm,useEffect as Pm,useMemo as Bm,useRef as Od}from"react";import{jsx as lr,jsxs as Rm}from"react/jsx-runtime";function jd({liveViewerRef:e,renderBefore:t,split:a,onSplitChange:i,labels:n,beforeAction:o,report:d,selected:l,onSelect:c,matchBy:w,onMatchByChange:h,showOutlines:y,onShowOutlinesChange:u}){let g=Od(null),B=Od(null),v=Bm(()=>nd(),[]);Pm(()=>()=>v.detach(),[v]);let P=Tm(x=>{B.current=x;let C=e.current;C&&v.attach(0,C.raw.controls,C.invalidate),v.attach(1,x.raw.controls,x.invalidate)},[v,e]);return Rm("div",{ref:g,className:"ri-compare ri-compare--overlay",style:{"--ri-compare-split":`${a*100}%`},children:[lr("div",{className:"ri-compare__layer ri-compare__layer--before",children:t(P)}),d&&lr(ed,{showOutlines:y,onShowOutlinesChange:u,matchBy:w,onMatchByChange:h,report:d,selected:l,onClear:()=>c?.(null),onSelect:x=>{let C=x.afterObjectId?0:1,S=C===0?e.current:B.current,f=C===0?x.afterObjectId:x.beforeObjectId,k=f?S?.raw.nodes[f]:null;v.setLeader(C),c?.(x),S&&k&&(S.raw.controls.fitToBox(k,!0),S.invalidate())}}),lr(od,{split:a,onSplitChange:i,labels:n,containerRef:g,beforeAction:o})]})}import{useCallback as gn,useEffect as Ed,useMemo as Id,useRef as Ya,useState as Dd}from"react";var Am={currentClip:null,isPlaying:!1,speed:1,time:0,duration:0,active:[]};function Om(e,t){let a=[],i=new Map,n=new Map,o=new Map,d=new Set;for(let l of e){let c=t.get(l);if(!c)continue;let w=c.clipDetails??c.clips.map(y=>({sourceName:y,duration:0}));o.set(l,w);let h=new Map;for(let y of w){let u=y.sourceName;for(let g=2;d.has(u);g+=1)u=`${y.sourceName} (${g})`;d.add(u),a.push({sourceName:u,duration:y.duration}),i.set(u,{url:l,sourceName:y.sourceName}),h.set(y.sourceName,u)}n.set(l,h)}return{clipDetails:a,targets:i,displayNamesByUrl:n,clipDetailsByUrl:o}}function jm(e,t,a){let i=[];for(let n of e){let o=t.get(n),d=a.get(n);if(!(!o||!d))for(let l of o.active){let c=d.get(l.clip);c&&i.push({...l,clip:c})}}return i}function Ld(e){let t=Ya(new Map),a=Ya(new Map),i=Ya(new Map),[n,o]=Dd(0),[d,l]=Dd(0),c=gn((r,M)=>{if(t.current.get(r)===M)return;i.current.get(r)?.(),i.current.delete(r),t.current.set(r,M),a.current.set(r,M.getState?.()??Am);let j=M.subscribe?.(R=>{a.current.set(r,R),l(E=>E+1)});j&&i.current.set(r,j),o(R=>R+1)},[]);Ed(()=>{let r=new Set(e),M=!1;for(let j of[...t.current.keys()])r.has(j)||(i.current.get(j)?.(),i.current.delete(j),t.current.delete(j),a.current.delete(j),M=!0);M&&o(j=>j+1)},[e]),Ed(()=>()=>i.current.forEach(r=>r()),[]);let{clipDetails:w,targets:h,displayNamesByUrl:y,clipDetailsByUrl:u,hasModels:g}=Id(()=>({...Om(e,t.current),hasModels:t.current.size>0}),[e,n]),B=Ya(h);B.current=h;let v=Id(()=>jm(e,a.current,y),[e,y,d]),P=gn((r,M,j)=>{j(),!M.subscribe&&M.getState&&(a.current.set(r,M.getState()),l(R=>R+1))},[]),x=gn(r=>{t.current.forEach((M,j)=>P(j,M,()=>r(M,j)))},[P]),C=gn((r,M)=>{let j=B.current.get(r);if(!j)return;let R=t.current.get(j.url);R&&P(j.url,R,()=>M(R,j))},[P]),S=gn((r,M)=>C(r,(j,R)=>j.play(R.sourceName,M)),[C]),f=gn(r=>r===void 0?x(M=>M.pause()):C(r,(M,j)=>M.pause(j.sourceName)),[x,C]),k=gn(r=>r===void 0?x(M=>M.stop()):C(r,(M,j)=>M.stop(j.sourceName)),[x,C]),O=gn((r,M)=>M===void 0?x(j=>j.setSpeed(r)):C(M,(j,R)=>j.setSpeed(r,R.sourceName)),[x,C]),p=gn((r,M)=>M===void 0?x(j=>j.seek?.(r)):C(M,(j,R)=>j.seek?.(r,R.sourceName)),[x,C]);return{clipDetails:w,clipDetailsByUrl:u,displayNamesByUrl:y,hasModels:g,active:v,play:S,pause:f,stop:k,setSpeed:O,seek:p,handleModelAnimationsReady:c}}import{useEffect as Lm,useMemo as zm}from"react";function ea(e,t){let a=new Map(e.animations.clips.map(o=>[o.sourceName,o])),i=t.map(({sourceName:o})=>a.get(o)??{sourceName:o,displayName:o,hidden:!1,loopMode:"repeat",speed:1}),n=e.animations.autoplayClip&&i.some(o=>o.sourceName===e.animations.autoplayClip&&!o.hidden)?e.animations.autoplayClip:null;return n===e.animations.autoplayClip&&i.length===e.animations.clips.length&&i.every((o,d)=>o===e.animations.clips[d])?e.animations:{clips:i,autoplayClip:n}}function Ja(e){return e!==null&&typeof e=="object"&&!Array.isArray(e)}function ta(e,t){if(!Ja(e)||!Ja(t))return t??e;let a={...e};for(let[i,n]of Object.entries(t)){if(i==="section"){a[i]=La(a[i],n);continue}if(i==="sequences"){a[i]=Gn(n);continue}let o=a[i];a[i]=Ja(o)&&Ja(n)?ta(o,n):n}return a}import{useCallback as En,useReducer as Em,useRef as Im}from"react";var Dm=100;function fn(e,t){switch(t.type){case"history":return t.updater(e);case"set":{let a=typeof t.updater=="function"?t.updater(e.present):t.updater;if(a===e.present)return e;let i=t.track?e.edits+1:e.edits,n=!t.track&&e.edits===0?a:e.baseline;return t.track?t.coalesce?{...e,present:a,future:[],edits:i,baseline:n}:{past:[...e.past,e.present].slice(-Dm),present:a,future:[],edits:i,baseline:n}:{...e,present:a,baseline:n}}case"undo":{if(e.past.length===0)return e;let a=e.past[e.past.length-1];return{...e,past:e.past.slice(0,-1),present:a,future:[e.present,...e.future],edits:e.edits+1}}case"redo":{if(e.future.length===0)return e;let[a,...i]=e.future;return{...e,past:[...e.past,e.present],present:a,future:i,edits:e.edits+1}}case"reset":return{past:[],present:t.value,future:[],edits:t.track?e.edits+1:0,baseline:t.track?e.baseline:t.value}}}function na(e,t=600){let[a,i]=Em(fn,{past:[],present:e,future:[],edits:0,baseline:e}),n=Im(0),o=En(g=>{let B=Date.now(),v=B-n.current<t;n.current=B,i({type:"set",updater:g,coalesce:v,track:!0})},[t]),d=En(g=>{let B=Date.now()-n.current<t;i({type:"set",updater:g,coalesce:B,track:!1})},[t]),l=En(g=>{n.current=0,i({type:"set",updater:g,coalesce:!1,track:!0})},[]),c=En(g=>{i({type:"history",updater:g})},[]),w=En(g=>{n.current=0,i({type:"history",updater:typeof g=="function"?g:()=>g})},[]),h=En(()=>{n.current=0,i({type:"undo"})},[]),y=En(()=>{n.current=0,i({type:"redo"})},[]),u=En((g,B)=>{n.current=0,i({type:"reset",value:g,track:B?.asEdit??!1})},[]);return{value:a.present,setValue:o,setValueUntracked:d,setValueAsStep:l,updateHistory:c,restoreSnapshot:w,snapshot:a,undo:h,redo:y,reset:u,canUndo:a.past.length>0,canRedo:a.future.length>0,edits:a.edits,baseline:a.baseline}}function Fm(e,t){return e.sourceName===t.sourceName&&e.displayName===t.displayName&&e.hidden===t.hidden&&e.loopMode===t.loopMode&&e.speed===t.speed}function zd(e,t,a,i){let n=mt(t,e.modelSettings);if(n.animations===a)return e;let o={...n,animations:a},d=e.sceneHistory??{past:[],present:n,future:[],baseline:n,edits:0};return{...e,modelSettings:Bn(o),sceneHistory:fn(d,{type:"set",updater:o,track:i,coalesce:!1})}}function Fd({modelUrl:e,sceneConfig:t,setSceneConfig:a,setSceneConfigUntracked:i,parkedModels:n,setParkedModels:o,animations:d,markSessionEdited:l}){let{clipDetailsByUrl:c,displayNamesByUrl:w}=d;Lm(()=>{let u=e?c.get(e):void 0;u&&i(g=>{let B=ea(g,u);return B===g.animations?g:{...g,animations:B}}),o(g=>{let B=!1,v=g.map(P=>{let x=c.get(P.url);if(!x)return P;let C=mt(t,P.modelSettings),S=zd(P,t,ea(C,x),!1);return B||(B=S!==P),S});return B?v:g})},[c,e,t,i,o]);let h=zm(()=>{let u=[],g=null;for(let[B,v]of w){let P=B===e?t:mt(t,n.find(C=>C.url===B)?.modelSettings),x=ea(P,c.get(B)??[]);for(let C of x.clips){let S=v.get(C.sourceName);S&&u.push({...C,sourceName:S,displayName:C.displayName===C.sourceName?S:C.displayName})}g??(g=x.autoplayClip?v.get(x.autoplayClip)??null:null)}return{clips:u,autoplayClip:g}},[w,c,e,t,n]);return{config:h,onChange:u=>{let g=new Map(h.clips.map(P=>[P.sourceName,P])),B=new Map(u.clips.map(P=>[P.sourceName,P])),v=(P,x)=>{let C=w.get(P);if(!C)return x.animations;let S=ea(x,c.get(P)??[]),f=S.clips.map(O=>{let p=C.get(O.sourceName),r=p?B.get(p):void 0;if(!r)return O;let M={...r,sourceName:O.sourceName,displayName:r.displayName===g.get(p)?.displayName?O.displayName:r.displayName};return Fm(O,M)?O:M}),k=u.autoplayClip===h.autoplayClip?S.autoplayClip:[...C].find(([,O])=>O===u.autoplayClip)?.[0]??null;return k===S.autoplayClip&&f.every((O,p)=>O===S.clips[p])?S:{clips:f,autoplayClip:k}};e&&a(P=>{let x=v(e,P);return x===P.animations?P:{...P,animations:x}}),o(P=>P.map(x=>zd(x,t,v(x.url,mt(t,x.modelSettings)),!0))),l()}}}import{useEffect as qd,useMemo as $m,useRef as Vm,useState as hn}from"react";import{Copy as qm,DiamondPlus as Um,Plus as pr,ScanLine as Km,Trash2 as br}from"lucide-react";import{useEffect as Hd,useState as $d}from"react";import{Fragment as Hm,jsx as ft,jsxs as In}from"react/jsx-runtime";function Zn({label:e,value:t,onChange:a,min:i,max:n,step:o=.1,disabled:d=!1}){let[l,c]=$d(String(Number(t.toFixed(5))));return Hd(()=>c(String(Number(t.toFixed(5)))),[t]),In("label",{className:"sq-field",children:[ft("span",{children:e}),ft("input",{type:"number","aria-label":e,value:l,step:o,min:i,max:n,disabled:d,onChange:h=>c(h.target.value),onBlur:()=>{let h=l.trim()?Number(l):NaN;Number.isFinite(h)&&(i===void 0||h>=i)&&(n===void 0||h<=n)&&h!==t&&a(h),c(String(Number(t.toFixed(5))))},onKeyDown:h=>{h.stopPropagation(),h.key==="Enter"&&h.currentTarget.blur(),h.key==="Escape"&&(h.preventDefault(),c(String(t)))}})]})}function cr({label:e,value:t,onChange:a}){let[i,n]=$d(t);return Hd(()=>n(t),[t]),In("label",{className:"sq-field",children:[ft("span",{children:e}),ft("input",{"aria-label":e,value:i,maxLength:256,onChange:o=>n(o.target.value),onBlur:()=>{i.trim()&&i.trim()!==t?a(i.trim()):n(t)},onKeyDown:o=>{o.stopPropagation(),o.key==="Enter"&&o.currentTarget.blur()}})]})}function dr({label:e,value:t,onChange:a,degrees:i=!1}){return In("fieldset",{className:"sq-vector",children:[In("legend",{children:[e,i?" (\xB0)":""]}),ft("div",{children:t.map((n,o)=>ft(Zn,{label:`${e} ${["X","Y","Z"][o]}`,value:i?n*180/Math.PI:n,onChange:d=>a(t.map((l,c)=>o===c?i?d*Math.PI/180:d:l))},o))})]})}function Vd({target:e,value:t,onChange:a}){if(e.kind==="camera"){let i=t;return In(Hm,{children:[ft(dr,{label:"Camera position",value:i.position,onChange:n=>a({...i,position:n})}),ft(dr,{label:"Camera target",value:i.target,onChange:n=>a({...i,target:n})}),In("div",{className:"sq-twoFields",children:[i.fov!==null&&ft(Zn,{label:"Field of view (\xB0)",min:1,max:179,value:i.fov,onChange:n=>a({...i,fov:n})}),ft(Zn,{label:"Zoom",min:.001,value:i.zoom,onChange:n=>a({...i,zoom:n})})]})]})}return Array.isArray(t)?ft(dr,{label:e.kind==="object"?e.property[0].toUpperCase()+e.property.slice(1):"Value",value:t,degrees:e.kind==="object"&&e.property==="rotation",onChange:a}):typeof t=="boolean"?In("label",{className:"sq-check",children:[ft("input",{type:"checkbox",checked:t,onChange:i=>a(i.target.checked)}),"Visible"]}):typeof t=="string"?In("label",{className:"sq-field sq-color",children:[ft("span",{children:"Color"}),ft("input",{type:"color","aria-label":"Keyframe color",value:t,onChange:i=>a(i.target.value)}),ft("code",{children:t})]}):ft(Zn,{label:e.kind==="clip"?"Clip time (s)":"Value",min:0,max:e.kind==="object"&&e.property!=="emissiveIntensity"?1:void 0,step:.01,value:t,onChange:a})}import{Fragment as Kd,jsx as W,jsxs as ye}from"react/jsx-runtime";var Qn=()=>crypto.randomUUID(),Ud={position:"Position",rotation:"Rotation",scale:"Scale",visible:"Visibility",baseColor:"Color",emissive:"Emissive color",opacity:"Opacity",roughness:"Roughness",metalness:"Metalness",emissiveIntensity:"Emissive intensity"},Gm={linear:"Linear","ease-in":"Ease in","ease-out":"Ease out","ease-in-out":"Ease in / out",step:"Hold / step"};function ur({config:e,onChange:t,controls:a,bindings:i,clipDetails:n}){let{tier:o}=lt(),d=ul(a),l=$m(()=>{try{return{sequences:Gn(e.sequences??[]),error:""}}catch(A){return{sequences:[],error:A instanceof Error?A.message:"Invalid sequence data."}}},[e.sequences]),c=l.sequences,[w,h]=hn(null),[y,u]=hn(null),[g,B]=hn(null),[v,P]=hn("object"),[x,C]=hn(""),[S,f]=hn("position"),[k,O]=hn(""),[p,r]=hn(""),[M,j]=hn(null),R=Vm(null),E=c.find(A=>A.id===w)??c[0],z=E?.tracks.find(A=>A.id===y)??E?.tracks[0],pe=z?.keyframes.find(A=>A.id===g)??z?.keyframes[0],Ce=Object.values(i).filter((A,J,pt)=>!A.removed&&pt.findIndex(be=>be.modelObjectId===A.modelObjectId)===J),fe=Ce.find(A=>A.modelObjectId===x)??Ce[0],I=n.some(A=>A.sourceName===k)?k:n[0]?.sourceName;qd(()=>{E&&a&&d.sequenceId!==E.id&&a.select(E.id)},[a,E?.id,d]),qd(()=>()=>a?.stop(),[a]);let Q=A=>{try{let J=Gn(A);t({...e,sequences:J}),r("")}catch(J){r(J instanceof Error?J.message:"Invalid sequence.")}},G=A=>Q(c.map(J=>J.id===A.id?A:J)),L=A=>{E&&G({...E,tracks:E.tracks.map(J=>J.id===A.id?A:J)})},ae=(A,J)=>{if(!E||!dl(J.value,A.target)){r("Use a valid value; scale components must be nonzero.");return}L(cl(A,{...J,time:Math.max(0,Math.min(E.duration,J.time))})),u(A.id),B(J.id),a?.pause(),a?.seek(J.time)},tt=()=>{if(c.length>=64)return;let A={id:Qn(),name:`Sequence ${c.length+1}`,duration:5,loop:!1,autoPlay:!1,tracks:[]};Q([...c,A]),h(A.id),u(null),B(null)},me=v==="camera"?{kind:"camera"}:v==="clip"?I?{kind:"clip",clip:I}:null:fe?{kind:"object",objectId:fe.modelObjectId,property:S}:null,St=!!me&&E?.tracks.some(A=>Hi(A.target)===Hi(me)),$n=()=>{if(!E||!me||St)return;let A=a?.capture(me);if(A==null){r("That target is not ready. Wait for the model, or choose another object/clip.");return}let J=me.kind==="clip"?Math.min(E.duration,n.find(be=>be.sourceName===me.clip)?.duration??E.duration):structuredClone(A),pt={id:Qn(),name:me.kind==="camera"?"Camera":me.kind==="clip"?me.clip:`${fe?.label||fe?.modelObjectId} \xB7 ${Ud[S]}`,target:me,keyframes:[{id:Qn(),time:0,value:A,easing:S==="visible"&&v==="object"?"step":"ease-in-out"},{id:Qn(),time:E.duration,value:J}]};G({...E,tracks:[...E.tracks,pt]}),u(pt.id),B(pt.keyframes[1].id),a?.seek(E.duration)},Eo=()=>{if(!z||!E||z.keyframes.length>=2048)return;let A=a?.capture(z.target);if(A==null){r("The selected target is unavailable.");return}let J={id:Qn(),time:Math.min(d.time,E.duration),value:A,easing:"ease-in-out"};ae(z,J)};return ye("section",{className:"sq-editor","aria-label":"Visual sequence authoring",children:[ye("header",{className:"sq-header",children:[ye("div",{children:[W("h2",{children:"Sequences"}),W("p",{children:"Build timed camera moves, object changes and clip playback."})]}),W("button",{type:"button",className:"bb-iconButton",title:"Add sequence","aria-label":"Add sequence",disabled:c.length>=64||!Mt(o,"sequences",c.length),onClick:tt,children:W(pr,{size:17})})]}),l.error&&W("p",{role:"alert",className:"sq-error",children:l.error}),Mt(o,"sequences",c.length)?null:W(_e,{requiredTier:bn("sequences",c.length),feature:"More sequences"}),E?ye(Kd,{children:[ye("div",{className:"sq-picker",children:[ye("label",{className:"sq-field",children:[W("span",{children:"Sequence"}),W("select",{"aria-label":"Authored sequence",value:E.id,onChange:A=>{h(A.target.value),u(null),B(null),a?.select(A.target.value)},children:c.map(A=>W("option",{value:A.id,children:A.name},A.id))})]}),W("button",{type:"button",className:"bb-iconButton",title:"Duplicate sequence","aria-label":"Duplicate sequence",disabled:c.length>=64,onClick:()=>{let A={...structuredClone(E),id:Qn(),name:`${E.name} copy`.slice(0,256),autoPlay:!1};Q([...c,A]),h(A.id)},children:W(qm,{size:15})}),W("button",{type:"button",className:"bb-iconButton",title:"Delete sequence","aria-label":"Delete sequence",onClick:()=>{a?.stop(),Q(c.filter(A=>A.id!==E.id)),h(null)},children:W(br,{size:15})})]}),W(cr,{label:"Sequence name",value:E.name,onChange:A=>G({...E,name:A})}),ye("div",{className:"sq-settings",children:[W(Zn,{label:"Duration (s)",min:.1,max:3600,value:E.duration,onChange:A=>G({...E,duration:A,tracks:E.tracks.map(J=>({...J,keyframes:J.keyframes.map(pt=>({...pt,time:pt.time/E.duration*A}))}))})}),ye("label",{className:"sq-check",children:[W("input",{type:"checkbox",checked:E.loop,onChange:A=>G({...E,loop:A.target.checked})}),"Loop"]}),ye("label",{className:"sq-check",children:[W("input",{type:"checkbox",checked:E.autoPlay,onChange:A=>Q(c.map(J=>({...J,autoPlay:J.id===E.id?A.target.checked:!1})))}),"Autoplay in viewer"]})]}),W(ml,{controls:a,duration:E.duration,hasTracks:E.tracks.some(A=>!A.muted&&A.keyframes.length>0)}),ye("div",{className:"sq-timeline","aria-label":"Sequence timeline",children:[W("div",{className:"sq-ruler",children:[0,.25,.5,.75,1].map(A=>ye("span",{children:[(E.duration*A).toFixed(1),"s"]},A))}),!E.tracks.length&&W("p",{className:"sq-hint",children:"Add a track below to create its start and end keyframes."}),E.tracks.map(A=>ye("div",{className:`sq-track ${z?.id===A.id?"sq-track--active":""}`,children:[ye("div",{className:"sq-trackLabel",children:[W("button",{type:"button",title:A.name,onClick:()=>{u(A.id),B(A.keyframes[0]?.id??null)},children:A.name}),ye("label",{title:"Mute track",children:[W("input",{"aria-label":`Mute ${A.name}`,type:"checkbox",checked:!!A.muted,onChange:J=>L({...A,muted:J.target.checked})}),"Mute"]})]}),ye("div",{className:"sq-lane",role:"group","aria-label":`${A.name} keyframes`,onDoubleClick:J=>{if(J.target!==J.currentTarget)return;let pt=J.currentTarget.getBoundingClientRect(),be=Math.round(Math.max(0,Math.min(1,(J.clientX-pt.left)/pt.width))*E.duration*100)/100,qe=a?.capture(A.target);qe!=null&&ae(A,{id:Qn(),time:be,value:qe})},children:[W("span",{className:"sq-playhead",style:{left:`${d.time/E.duration*100}%`}}),A.keyframes.map(J=>{let pt=M?.frameId===J.id&&M.trackId===A.id?M.time:J.time;return W("button",{type:"button",className:`sq-key ${pe?.id===J.id&&z?.id===A.id?"sq-key--active":""}`,style:{left:`${pt/E.duration*100}%`},"aria-label":`${A.name} keyframe at ${pt.toFixed(2)} seconds`,"aria-pressed":pe?.id===J.id&&z?.id===A.id,onClick:be=>{be.detail===0&&(u(A.id),B(J.id),a?.pause(),a?.seek(J.time))},onPointerDown:be=>{if(be.button!==0)return;be.preventDefault(),be.stopPropagation(),be.currentTarget.focus(),be.currentTarget.setPointerCapture(be.pointerId);let qe=be.currentTarget.parentElement.getBoundingClientRect();R.current={track:A,frame:J,left:qe.left,width:qe.width,time:J.time},u(A.id),B(J.id),a?.pause(),a?.seek(J.time)},onPointerMove:be=>{let qe=R.current;if(!qe||qe.frame.id!==J.id||qe.track.id!==A.id)return;let ma=be.shiftKey?.01:.1;qe.time=Math.min(E.duration,Math.max(0,Math.round((be.clientX-qe.left)/qe.width*E.duration/ma)*ma)),j({trackId:A.id,frameId:J.id,time:qe.time}),a?.seek(qe.time)},onPointerUp:()=>{let be=R.current;be&&(be.time!==be.frame.time&&ae(be.track,{...be.frame,time:be.time}),R.current=null,j(null))},onPointerCancel:()=>{R.current=null,j(null),a?.seek(J.time)},onKeyDown:be=>{if(!["ArrowLeft","ArrowRight","Home","End"].includes(be.key))return;be.preventDefault(),be.stopPropagation();let qe=be.key==="Home"?0:be.key==="End"?E.duration:J.time+(be.key==="ArrowLeft"?-1:1)*(be.shiftKey?.01:.1);ae(A,{...J,time:qe})}},J.id)})]})]},A.id))]}),W("p",{className:"sq-hint",children:"Drag keys to retime. Arrow keys move 0.1s; Shift moves 0.01s. A key at the same time is replaced."}),ye("div",{className:"sq-addTrack",children:[W("h3",{children:"Add track"}),ye("div",{className:"sq-twoFields",children:[ye("label",{className:"sq-field",children:[W("span",{children:"Track type"}),ye("select",{"aria-label":"Track type",value:v,onChange:A=>P(A.target.value),children:[W("option",{value:"object",children:"Object"}),W("option",{value:"camera",children:"Camera"}),W("option",{value:"clip",children:"Animation clip"})]})]}),v==="object"&&ye("label",{className:"sq-field",children:[W("span",{children:"Property"}),W("select",{"aria-label":"Track property",value:S,onChange:A=>f(A.target.value),children:sl.map(A=>W("option",{value:A,children:Ud[A]},A))})]})]}),v==="object"&&ye("label",{className:"sq-field",children:[W("span",{children:"Object"}),W("select",{"aria-label":"Track object",value:fe?.modelObjectId??"",onChange:A=>C(A.target.value),children:Ce.map(A=>W("option",{value:A.modelObjectId,children:A.label||A.modelObjectId},A.modelObjectId))})]}),v==="clip"&&ye("label",{className:"sq-field",children:[W("span",{children:"Clip"}),W("select",{"aria-label":"Track animation clip",value:I??"",onChange:A=>O(A.target.value),children:n.map(A=>W("option",{value:A.sourceName,children:A.sourceName},A.sourceName))}),!n.length&&W("small",{children:"This model has no animation clips."})]}),ye("button",{type:"button",className:"bb-button",onClick:$n,disabled:!me||!d.ready||St||E.tracks.length>=128,children:[W(pr,{size:14}),"Add track"]}),St&&W("p",{className:"sq-hint",children:"That property already has a track."})]}),z&&ye("section",{className:"sq-inspector","aria-label":"Selected track and keyframe",children:[ye("div",{className:"sq-inspectorTitle",children:[W("h3",{children:"Selected track"}),W("button",{type:"button",className:"bb-iconButton",title:"Delete track","aria-label":"Delete track",onClick:()=>{G({...E,tracks:E.tracks.filter(A=>A.id!==z.id)}),u(null),B(null)},children:W(br,{size:14})})]}),W(cr,{label:"Track name",value:z.name,onChange:A=>L({...z,name:A})}),ye("button",{type:"button",className:"bb-button",disabled:!d.ready||z.keyframes.length>=2048,onClick:Eo,children:[W(Um,{size:14}),"Capture keyframe at playhead"]}),pe&&ye(Kd,{children:[ye("div",{className:"sq-inspectorTitle",children:[W("h3",{children:"Keyframe"}),W("button",{type:"button",className:"bb-iconButton",title:"Delete keyframe","aria-label":"Delete keyframe",onClick:()=>{L({...z,keyframes:z.keyframes.filter(A=>A.id!==pe.id)}),B(null)},children:W(br,{size:14})})]}),ye("div",{className:"sq-twoFields",children:[W(Zn,{label:"Keyframe time (s)",min:0,max:E.duration,value:pe.time,step:.01,onChange:A=>ae(z,{...pe,time:A})}),ye("label",{className:"sq-field",children:[W("span",{children:"To next key"}),W("select",{"aria-label":"Keyframe easing",value:z.target.kind==="object"&&z.target.property==="visible"?"step":pe.easing??"ease-in-out",disabled:z.target.kind==="object"&&z.target.property==="visible",onChange:A=>ae(z,{...pe,easing:A.target.value}),children:ll.map(A=>W("option",{value:A,children:Gm[A]},A))})]})]}),W(Vd,{target:z.target,value:pe.value,onChange:A=>ae(z,{...pe,value:A})}),ye("button",{type:"button",className:"bb-button",disabled:!d.ready,onClick:()=>{let A=a?.capture(z.target);A!=null&&ae(z,{...pe,value:A})},children:[W(Km,{size:14}),"Capture current value"]})]})]}),W("p",{className:"sq-hint",children:"Stop restores the authored scene. Duration changes rescale keyframe times. Tracks belong to this asset; camera values use world space."})]}):ye("div",{className:"sq-empty",children:[W("p",{children:"Create a sequence, add tracks, then edit or capture keyframes on the timeline."}),ye("button",{type:"button",className:"bb-button bb-button--primary",onClick:tt,children:[W(pr,{size:14}),"Create sequence"]})]}),(p||d.issues.length>0)&&W("div",{role:"status",className:"sq-error",children:p||d.issues.join(" ")})]})}import{useLayoutEffect as _d,useRef as mr,useState as gr}from"react";import{createPortal as Wm}from"react-dom";import{ChevronDown as Ym,Info as Jm}from"lucide-react";import{HexColorInput as Xm,HexColorPicker as Zm}from"react-colorful";function Dn(e){let t=e.replace("#","").match(/.{2}/g).map(i=>parseInt(i,16)/255).map(i=>i<=.03928?i/12.92:Math.pow((i+.055)/1.055,2.4));return .2126*t[0]+.7152*t[1]+.0722*t[2]>.179?"#000":"#fff"}import{useEffect as _m}from"react";function Gd(e,t,a){_m(()=>{if(!a)return;let i=Array.isArray(e)?e:[e],n=o=>{let d=o.target;i.some(c=>c.current?.contains(d))||t()};return document.addEventListener("pointerdown",n,!0),()=>{document.removeEventListener("pointerdown",n,!0)}},[e,t,a])}import{jsx as ve,jsxs as vt}from"react/jsx-runtime";function oa({anchorRef:e,onClose:t,children:a}){let i=mr(null),[n,o]=gr(null);return Gd([i,e],t,!0),_d(()=>{let d=e.current;if(!d)return;let l=d.getBoundingClientRect(),c=222,w=8,h=Math.min(Math.max(l.right-c,w),window.innerWidth-c-w),y=Math.min(l.bottom+6,window.innerHeight-200);o({top:y,left:h})},[e]),n?Wm(ve("div",{ref:i,className:"se-colorPickerPopover",style:{position:"fixed",top:n.top,left:n.left},children:a}),document.body):null}function Qm(e){return e.replace(/([a-z0-9])([A-Z])/g,"$1 $2").replace(/[_-]+/g," ").replace(/\s+/g," ").trim().replace(/\b\w/g,t=>t.toUpperCase())}function xn({title:e,children:t}){return vt("section",{className:"se-section",children:[ve("h3",{className:"se-sectionTitle",children:e}),ve("div",{className:"se-sectionBody",children:t})]})}function Se({title:e,open:t,onToggle:a,trailing:i,children:n,disabled:o,tooltip:d}){let l=d?`${d}`:e;return vt("section",{className:"se-panel",children:[vt("button",{type:"button",className:"se-panelHeader",onClick:a,"aria-expanded":t,title:l,children:[vt("span",{className:"se-panelHeaderMain",children:[ve(Ym,{size:16,className:`se-panelChevron ${t?"se-panelChevron--open":""}`}),ve("span",{className:"se-panelTitle",children:e}),d?ve("span",{className:"se-panelHelp",title:l,"aria-label":l,role:"img",onClick:c=>c.stopPropagation(),children:ve(Jm,{size:13})}):null]}),i?ve("span",{className:"se-panelTrailing",onClick:c=>c.stopPropagation(),children:i}):null]}),t?ve("div",{className:"se-panelBody",style:o?{opacity:.45,pointerEvents:"none"}:void 0,children:n}):null]})}function Me({checked:e,onChange:t,label:a}){return vt("label",{className:"se-switch","aria-label":a,children:[ve("input",{type:"checkbox",checked:e,onChange:i=>t(i.target.checked)}),ve("span",{className:"se-switchTrack",children:ve("span",{className:"se-switchThumb"})})]})}function D({label:e,value:t,min:a,max:i,step:n,formatValue:o,onChange:d,disabled:l=!1}){return vt("label",{className:`se-field ${l?"se-field--disabled":""}`,children:[vt("span",{className:"se-fieldLabel",children:[e,ve("span",{className:"se-fieldValue",children:o?o(t):t})]}),ve("input",{className:"se-slider",type:"range",min:a,max:i,step:n,value:t,onChange:c=>d(Number(c.target.value)),disabled:l})]})}function Ne({label:e,checked:t,onChange:a}){return vt("label",{className:"se-field se-fieldInline",children:[ve("span",{className:"se-fieldLabel",children:e}),ve("input",{type:"checkbox",className:"se-checkbox",checked:t,onChange:i=>a(i.target.checked)})]})}function Bt({label:e,value:t,options:a,onChange:i}){return vt("label",{className:"se-field se-fieldInline",children:[ve("span",{className:"se-fieldLabel",children:e}),ve("select",{className:"se-select",value:t,onChange:n=>i(n.target.value),children:a.map(n=>ve("option",{value:n,children:Qm(n)},n))})]})}function Nt({label:e,value:t,onChange:a}){let[i,n]=gr(!1),o=mr(null);return vt("div",{className:"se-field",children:[vt("div",{className:"se-fieldInline",children:[ve("span",{className:"se-fieldLabel",children:e}),ve("span",{ref:o,style:{display:"inline-flex"},children:ve(Xm,{prefixed:!0,className:"se-swatch",onClick:()=>n(d=>!d),style:{background:t,color:Dn(t)},color:t,onChange:a})})]}),i?ve(oa,{anchorRef:o,onClose:()=>n(!1),children:ve(Zm,{color:t,onChange:a})}):null]})}function Wd({value:e,min:t,max:a,step:i,onChange:n}){let[o,d]=gr(String(e)),l=mr(!1);return _d(()=>{l.current||d(String(e))},[e]),ve("input",{type:"number",className:"se-numberInput",min:t,max:a,step:i,value:o,onFocus:()=>{l.current=!0},onChange:c=>{let w=c.target.value;d(w),w!==""&&w!=="-"&&!Number.isNaN(Number(w))&&n(Number(w))},onBlur:()=>{l.current=!1,d(String(e))}})}function Lt({label:e,value:t,min:a,max:i,step:n,onChange:o}){return vt("div",{className:"se-field",children:[ve("span",{className:"se-fieldLabel",children:e}),ve("div",{className:"se-vectorRow",children:["X","Y","Z"].map((l,c)=>vt("label",{className:"se-vectorAxis",children:[ve("span",{children:l}),ve(Wd,{value:t[c],min:a,max:i,step:n,onChange:w=>{let h=[...t];h[c]=w,o(h)}})]},l))})]})}function eo({label:e,value:t,min:a,max:i,step:n,onChange:o}){return vt("div",{className:"se-field",children:[ve("span",{className:"se-fieldLabel",children:e}),ve("div",{className:"se-vectorRow",children:["X","Y"].map((l,c)=>vt("label",{className:"se-vectorAxis",children:[ve("span",{children:l}),ve(Wd,{value:t[c],min:a,max:i,step:n,onChange:w=>{let h=[...t];h[c]=w,o(h)}})]},l))})]})}import{Copy as eg,Trash2 as tg,Plus as ng}from"lucide-react";import{jsx as nt,jsxs as zt}from"react/jsx-runtime";function fr(e){let t=e.assets.find(i=>i.url===e.activeUrl),a=t?.placement??{};return zt("div",{className:"ri-assets",children:[e.addRequiresTier?nt(_e,{requiredTier:e.addRequiresTier,feature:"More models in a project"}):null,nt("div",{className:"ri-assets-actions",children:zt("button",{type:"button",className:"bb-button bb-button--ghost",disabled:e.busy||!!e.addRequiresTier,onClick:e.onAdd,children:[nt(ng,{size:14}),"Add asset"]})}),nt("button",{type:"button",className:"bb-button bb-button--ghost",onClick:e.onFrameAll,children:"Frame all assets"}),nt("p",{className:"ri-assets-hint",children:"Arrange whole assets in the shared scene. Object edits stay inside their own asset."}),nt("ul",{className:"ri-assets-list","aria-label":"Scene assets",children:e.assets.map(i=>nt("li",{children:zt("button",{type:"button",className:i.url===e.activeUrl?"ri-assets-item is-active":"ri-assets-item","aria-pressed":i.url===e.activeUrl,onClick:()=>e.onSelect(i.url),disabled:e.busy,children:[i.name,nt("small",{children:i.placement.visible===!1?"Hidden":i.ready?"Ready":"Loading"})]})},i.id))}),t&&nt("section",{className:"se-panel",children:zt("div",{className:"se-panelBody ri-assets-fields",children:[zt("label",{className:"ri-assets-label",children:["Name",nt("input",{"aria-label":"Asset name",value:a.label??t.name,maxLength:512,onChange:i=>e.onChange(t.id,{label:i.target.value})})]}),zt("label",{className:"ri-assets-check",children:[nt("input",{type:"checkbox",checked:a.visible!==!1,onChange:i=>e.onChange(t.id,{visible:i.target.checked})}),"Visible"]}),nt(Lt,{min:-1e6,max:1e6,label:"Position",value:a.position??[0,0,0],step:.1,onChange:i=>e.onChange(t.id,{position:i})}),nt(Lt,{min:-1e6,max:1e6,label:"Rotation (\xB0)",value:(a.rotation??[0,0,0]).map(i=>i*180/Math.PI),step:1,onChange:i=>e.onChange(t.id,{rotation:i.map(n=>n*Math.PI/180)})}),nt(Lt,{min:-1e6,max:1e6,label:"Scale",value:a.scale??[1,1,1],step:.1,onChange:i=>{i.every(n=>n!==0)&&e.onChange(t.id,{scale:i})}}),zt("label",{className:"ri-assets-label",children:["Grid spacing",nt("input",{"aria-label":"Grid spacing",type:"number",min:.001,step:.1,value:e.composition.gridSize,onChange:i=>{let n=Number(i.target.value);n>0&&Number.isFinite(n)&&e.onGridSize(n)}})]}),zt("div",{className:"ri-assets-actions",children:[nt("button",{type:"button",className:"bb-button bb-button--ghost",onClick:()=>e.onSnap(t.id),children:"Snap X/Z to grid"}),nt("button",{type:"button",className:"bb-button bb-button--ghost",disabled:!t.ready,onClick:()=>e.onGround(t.url),children:"Place on ground"})]}),zt("div",{className:"ri-assets-actions",children:[zt("button",{type:"button",className:"bb-button bb-button--ghost",disabled:e.busy||!t.ready,onClick:()=>e.onDuplicate(t.url),children:[nt(eg,{size:14}),"Duplicate"]}),zt("button",{type:"button",className:"bb-button bb-button--ghost",disabled:e.busy||e.assets.length<2,title:e.assets.length<2?"Use Remove model to clear the last asset":"Delete asset (undoable)",onClick:()=>e.onDelete(t.url),children:[nt(tg,{size:14}),"Delete"]})]}),zt("small",{className:"ri-assets-hint",children:["Instance ID: ",t.id]})]})})]})}import{Layers as sf}from"lucide-react";import{useState as lf,useEffect as df}from"react";import{useEffect as Yd,useRef as Jd,useState as Xd}from"react";import{ChevronDown as og,ChevronLeft as ag,ChevronRight as ig,FileUp as rg,RotateCcw as sg,X as lg}from"lucide-react";import{HexColorInput as dg,HexColorPicker as cg}from"react-colorful";import{Fragment as hr,jsx as V,jsxs as Oe}from"react/jsx-runtime";var pg="image/png,image/jpeg,image/webp,image/avif,image/gif";function bg(e){let t=e.trim();return!!(t&&en(t))||/^(blob:|data:image\/)/i.test(t)}var ug=["lit","unlit","normals"],mg=["color","image","environment"];function Zd(e){let t=e%360;return t<0?t+360:t}function Ln({title:e,open:t,onToggle:a,children:i,trailing:n}){return Oe("section",{className:"se-panel",children:[Oe("button",{type:"button",className:"se-panelHeader",onClick:a,"aria-expanded":t,children:[Oe("span",{className:"se-panelHeaderMain",children:[V(og,{size:16,className:`se-panelChevron ${t?"se-panelChevron--open":""}`}),V("span",{className:"se-panelTitle",children:e})]}),n?V("span",{className:"se-panelTrailing",onClick:o=>o.stopPropagation(),children:n}):null]}),t?V("div",{className:"se-panelBody",children:i}):null]})}function xr({diagnostics:e,onDiagnosticsOpenChange:t,config:a,onChange:i,materialVariantGroups:n=[],onImageFile:o}){let{model:d,camera:l,wireframe:c,background:w,environment:h}=a,y=Jd(null),[u,g]=Xd(null),B=bg(w.imageUrl),v=El(d),P=n.length>0?v.filter(L=>!n.some(ae=>ae.variants.some(tt=>tt.name===L))):[],{tier:x,measurementPanelTarget:C,setMeasurementPanelTarget:S,measurementsPanelOpen:f,setMeasurementsPanelOpen:k}=lt(),O=Jd(null);Yd(()=>{f&&C&&O.current?.scrollIntoView({block:"start"})},[f,C]);let p=qa(),[r,M]=Xd({diagnostics:!1,general:!0,camera:!0,autoRotate:!1,section:!1,wireframe:!1,background:!1});Yd(()=>(t?.(r.diagnostics),()=>t?.(!1)),[r.diagnostics,t]);let j=L=>M(ae=>({...ae,[L]:!ae[L]})),R=L=>i({...a,model:L}),E=L=>i({...a,camera:L}),z=a.section??Sl,pe=L=>i({...a,section:{...z,...L}}),Ce=L=>i({...a,wireframe:L}),fe=L=>i({...a,background:L}),I=L=>i({...a,environment:L}),Q=L=>{if(!L.type.startsWith("image/")){g("Choose a PNG, JPG, WEBP, AVIF or GIF image.");return}g(null);let ae=vo(L);ae===w.imageUrl&&en(ae)||Yt(ae,URL.createObjectURL(L)),o?.(ae,L),fe({...w,imageUrl:ae})},G=L=>{I({...h,source:"preset",preset:L})};return Oe("div",{className:"se-generalContent",children:[Oe(Ln,{title:"General",open:r.general,onToggle:()=>j("general"),children:[Oe("div",{className:"se-field",children:[Oe("div",{className:"se-fieldLabel",children:[V("span",{children:"Straighten model"}),V("button",{type:"button",className:"se-iconButton",onClick:()=>R({...d,rotation:[0,0,0]}),"aria-label":"Reset model rotation",children:V(sg,{size:16})})]}),V("div",{className:"se-axisStepperGrid",children:["X","Y","Z"].map((L,ae)=>Oe("div",{className:"se-axisStepper",children:[V("button",{type:"button",className:"se-axisStepperButton",onClick:()=>{let tt=[...d.rotation];tt[ae]=Zd(tt[ae]-90),R({...d,rotation:tt})},"aria-label":`Rotate ${L} axis backward`,children:V(ag,{size:16})}),V("span",{className:"se-axisStepperLabel",children:L}),V("button",{type:"button",className:"se-axisStepperButton",onClick:()=>{let tt=[...d.rotation];tt[ae]=Zd(tt[ae]+90),R({...d,rotation:tt})},"aria-label":`Rotate ${L} axis forward`,children:V(ig,{size:16})})]},L))})]}),V(Lt,{label:"Rotation",value:d.rotation,min:0,max:360,step:1,onChange:L=>R({...d,rotation:L})}),Oe("div",{className:"se-field",children:[V("span",{className:"se-fieldLabel",children:"Renderer"}),V("div",{className:"se-segmentedControl se-segmentedControl--renderer",children:hl.map(L=>V("button",{type:"button",className:`se-segmentedOption ${d.renderer===L?"se-segmentedOption--active":""}`,onClick:()=>R({...d,renderer:L}),children:L==="uv-checker"?"UV CHECKER":L.toUpperCase()},L))})]}),V(Bt,{label:"Shading",value:d.shading,options:ug,onChange:L=>R({...d,shading:L})}),n.length>0&&!ut(x,"materialVariants")?V(_e,{requiredTier:"starter",feature:"Material variants"}):null,(ut(x,"materialVariants")?n:[]).map((L,ae)=>{let tt=v.find(me=>L.variants.some(St=>St.name===me));return Oe("label",{className:"se-field se-fieldInline",children:[V("span",{className:"se-fieldLabel",children:L.name??"Material variant"}),Oe("select",{className:"se-select",value:tt??"",onChange:me=>{let St=me.target.value,$n=v.filter(Eo=>Eo!==tt);R(Gi(d,St?jl($n,St,n):$n))},children:[V("option",{value:"",children:"Model default"}),L.variants.map(me=>V("option",{value:me.name,children:me.label},me.name))]})]},L.name??`group-${ae}`)}),P.length>0?Oe("div",{className:"se-placeholder se-placeholder--spaced",children:["Not in this model: ",P.join(", "),"."," ",V("button",{type:"button",className:"se-linkButton",onClick:()=>R(Gi(d,v.filter(L=>!P.includes(L)))),children:"Remove"})]}):null]}),V("div",{ref:O,className:"se-measurementsSection",children:V(Ln,{title:`Measurements (${a.measurements?.items.length??0})`,open:f??!1,onToggle:()=>k?.(!f),children:V("div",{ref:S})})}),e&&V(Ln,{title:"Asset diagnostics",open:r.diagnostics,onToggle:()=>j("diagnostics"),children:V(cd,{...e})}),V(Ln,{title:"Camera",open:r.camera,onToggle:()=>j("camera"),children:V(D,{label:"Field Of View",value:l.fieldOfView,min:20,max:100,step:.1,formatValue:L=>`${L.toFixed(3)}\xB0`,onChange:L=>E({...l,fieldOfView:L})})}),Oe(Ln,{title:"Auto Rotate",open:r.autoRotate,onToggle:()=>j("autoRotate"),trailing:Oe("label",{className:"se-switch","aria-label":"Toggle auto rotate",children:[V("input",{type:"checkbox",checked:d.autoRotate??!1,onChange:L=>R({...d,autoRotate:L.target.checked})}),V("span",{className:"se-switchTrack",children:V("span",{className:"se-switchThumb"})})]}),children:[d.autoRotate&&p?V("div",{className:"se-placeholder se-placeholder--spaced",children:"Your device is set to reduce motion, so this preview won't turn. Visitors without that setting will see it."}):null,d.autoRotate?V(D,{label:"Rotation Speed",value:d.autoRotateSpeed??1,min:.1,max:3,step:.1,formatValue:L=>`${L.toFixed(1)}x`,onChange:L=>R({...d,autoRotateSpeed:L})}):V("div",{className:"se-placeholder",children:"Enable auto rotate to adjust its speed."})]}),V(Ln,{title:"Section Cut",open:r.section,onToggle:()=>j("section"),trailing:Oe("label",{className:"se-switch","aria-label":"Toggle section cut",children:[V("input",{type:"checkbox",checked:z.enabled,onChange:L=>pe({enabled:L.target.checked})}),V("span",{className:"se-switchTrack",children:V("span",{className:"se-switchThumb"})})]}),children:z.enabled?V(Xl,{section:z,onChange:pe}):V("div",{className:"se-placeholder",children:"Cut the model open to see inside. Drag the plane in the preview, or set it here."})}),V(Ln,{title:"Wireframe",open:r.wireframe,onToggle:()=>j("wireframe"),trailing:Oe("label",{className:"se-switch","aria-label":"Toggle wireframe preview",children:[V("input",{type:"checkbox",checked:c.enabled,onChange:L=>Ce({...c,enabled:L.target.checked})}),V("span",{className:"se-switchTrack",children:V("span",{className:"se-switchThumb"})})]}),children:Oe(hr,{children:[V(D,{label:"Opacity",value:c.opacity,min:0,max:1,step:.01,onChange:L=>Ce({...c,opacity:L})}),V(Nt,{label:"Wire color",value:c.color,onChange:L=>Ce({...c,color:L})})]})}),V(Ln,{title:"Background",open:r.background,onToggle:()=>j("background"),trailing:Oe("label",{className:"se-switch","aria-label":"Toggle scene background",children:[V("input",{type:"checkbox",checked:w.enabled,onChange:L=>fe({...w,enabled:L.target.checked})}),V("span",{className:"se-switchTrack",children:V("span",{className:"se-switchThumb"})})]}),children:w.enabled?Oe(hr,{children:[Oe("div",{className:"se-field",children:[V("span",{className:"se-fieldLabel",children:"Background type"}),V("div",{className:"se-segmentedControl",children:mg.map(L=>V("button",{type:"button",className:`se-segmentedOption ${w.type===L?"se-segmentedOption--active":""}`,onClick:()=>fe({...w,type:L}),children:L},L))})]}),w.type==="environment"?Oe(hr,{children:[Oe("div",{className:"se-field",children:[V("span",{className:"se-fieldLabel",children:"Environment source"}),Oe("div",{className:"se-segmentedControl",children:[V("button",{type:"button",className:`se-segmentedOption ${h.source==="preset"?"se-segmentedOption--active":""}`,onClick:()=>I({...h,source:"preset"}),children:"PRESET"}),V("button",{type:"button",className:`se-segmentedOption ${h.source==="custom"?"se-segmentedOption--active":""}`,onClick:()=>I({...h,source:"custom"}),children:"CUSTOM"})]})]}),h.source==="preset"?V(Bt,{label:"Environment preset",value:h.preset,options:xl,onChange:G}):ut(x,"customEnvironment")?Oe("label",{className:"se-field",children:[V("span",{className:"se-fieldLabel",children:"Custom environment URL"}),V("input",{type:"text",className:"se-textInput",placeholder:"https://example.com/environment.hdr",value:h.customEnvironmentUrl,onChange:L=>I({...h,customEnvironmentUrl:L.target.value})}),V("span",{className:"bb-note",children:"Enter a HDR, EXR, JPG, JPEG, PNG, or WEBP URL."}),h.customEnvironmentUrl.trim()&&!gl(h.customEnvironmentUrl)?V("span",{className:"bb-note",style:{color:"#fca5a5"},children:"Invalid image/HDRI URL."}):null]}):V(_e,{requiredTier:"starter",feature:"Custom environments"}),V(D,{label:"Environment intensity",value:h.intensity,min:0,max:3,step:.05,onChange:L=>I({...h,intensity:L})})]}):null,w.type==="image"&&!ut(x,"backgroundImages")?V(_e,{requiredTier:"starter",feature:"Background images"}):w.type==="image"?Oe("div",{className:"se-field",children:[V("label",{className:"se-fieldLabel",htmlFor:"se-background-image-url",children:"Background image"}),Oe("div",{className:"bb-fileField",children:[V("input",{id:"se-background-image-url",type:"text",className:"se-textInput bb-fileField-input se-backgroundImageInput",placeholder:"Paste an image link or upload a file",value:w.imageUrl,readOnly:B,onChange:L=>{g(null),fe({...w,imageUrl:L.target.value})}}),B?V("button",{type:"button",className:"bb-fileFieldButton",onClick:()=>fe({...w,imageUrl:""}),"aria-label":"Remove uploaded background image",title:"Remove uploaded image",children:V(lg,{size:18})}):V("button",{type:"button",className:"bb-fileFieldButton",onClick:()=>y.current?.click(),"aria-label":"Upload background image",title:"Upload image",children:V(rg,{size:18})}),V("input",{ref:y,type:"file",accept:pg,className:"bb-hiddenInput",onChange:L=>{let ae=L.target.files?.[0];L.target.value="",ae&&Q(ae)}})]}),V("span",{className:"bb-note",children:B?"Uploaded files are bundled into the scene export zip.":"Paste a JPG, PNG, WEBP, AVIF or GIF link, or upload a file."}),u?V("span",{className:"bb-note",style:{color:"#fca5a5"},children:u}):null]}):null,w.type==="color"?Oe("div",{className:"se-field",children:[V("span",{className:"se-fieldLabel",children:"Background color"}),V("div",{className:"se-inlineColorPicker",children:V(cg,{color:w.color,onChange:L=>fe({...w,color:L})})}),V("div",{className:"se-fieldInline",children:V(dg,{prefixed:!0,className:"se-swatch",style:{background:w.color,color:Dn(w.color)},color:w.color,onChange:L=>fe({...w,color:L})})})]}):null]}):V("div",{className:"se-placeholder",children:"Background rendering is disabled for this scene preset."})})]})}import{useState as fg}from"react";import{jsx as ee,jsxs as aa}from"react/jsx-runtime";function Qd({pp:e,set:t,open:a,toggle:i}){let{ssao:n}=e;return aa(Se,{title:"SSAO",tooltip:"Adds soft contact shadows in corners, creases, and tight spaces.",open:a.ssao,onToggle:()=>i("ssao"),disabled:!n.enabled,trailing:ee(Me,{checked:n.enabled,onChange:o=>t("ssao",{...n,enabled:o}),label:"Toggle SSAO"}),children:[ee(D,{label:"Samples",value:n.samples,min:1,max:64,step:1,onChange:o=>t("ssao",{...n,samples:o})}),ee(D,{label:"Rings",value:n.rings,min:1,max:12,step:1,onChange:o=>t("ssao",{...n,rings:o})}),ee(D,{label:"Intensity",value:n.intensity,min:0,max:20,step:.5,onChange:o=>t("ssao",{...n,intensity:o})}),ee(D,{label:"Radius",value:n.radius,min:.01,max:1,step:.01,onChange:o=>t("ssao",{...n,radius:o})}),ee(D,{label:"Bias",value:n.bias,min:0,max:.1,step:.001,onChange:o=>t("ssao",{...n,bias:o})}),ee(D,{label:"Luminance Influence",value:n.luminanceInfluence,min:0,max:1,step:.01,onChange:o=>t("ssao",{...n,luminanceInfluence:o})}),ee(D,{label:"Fade",value:n.fade,min:0,max:.1,step:.001,onChange:o=>t("ssao",{...n,fade:o})}),ee(D,{label:"Min Radius Scale",value:n.minRadiusScale,min:0,max:1,step:.01,onChange:o=>t("ssao",{...n,minRadiusScale:o})}),ee(D,{label:"World Distance Threshold",value:n.worldDistanceThreshold,min:0,max:100,step:.1,onChange:o=>t("ssao",{...n,worldDistanceThreshold:o})}),ee(D,{label:"World Distance Falloff",value:n.worldDistanceFalloff,min:0,max:20,step:.1,onChange:o=>t("ssao",{...n,worldDistanceFalloff:o})}),ee(D,{label:"World Proximity Threshold",value:n.worldProximityThreshold,min:0,max:100,step:.1,onChange:o=>t("ssao",{...n,worldProximityThreshold:o})}),ee(D,{label:"World Proximity Falloff",value:n.worldProximityFalloff,min:0,max:20,step:.1,onChange:o=>t("ssao",{...n,worldProximityFalloff:o})})]})}function ec({pp:e,set:t,open:a,toggle:i}){let{autofocus:n}=e;return aa(Se,{title:"Auto focus",tooltip:"Keeps the focus plane tracking a subject so the image stays sharp where you want it.",open:a.autofocus,onToggle:()=>i("autofocus"),disabled:!n.enabled,trailing:ee(Me,{checked:n.enabled,onChange:o=>t("autofocus",{...n,enabled:o}),label:"Toggle Autofocus"}),children:[ee(D,{label:"Focus Distance",value:n.focusDistance,min:0,max:50,step:.1,onChange:o=>t("autofocus",{...n,focusDistance:o})}),ee(D,{label:"Focus Range",value:n.focusRange,min:.1,max:50,step:.1,onChange:o=>t("autofocus",{...n,focusRange:o})}),ee(D,{label:"Focal Length",value:n.focalLength,min:0,max:1,step:.01,onChange:o=>t("autofocus",{...n,focalLength:o})}),ee(D,{label:"Bokeh Scale",value:n.bokehScale,min:0,max:20,step:.1,onChange:o=>t("autofocus",{...n,bokehScale:o})}),ee(Lt,{label:"Target",value:n.target,min:-100,max:100,step:.1,onChange:o=>t("autofocus",{...n,target:o})}),ee(Ne,{label:"Mouse Follow",checked:n.mouse,onChange:o=>t("autofocus",{...n,mouse:o})}),ee(Ne,{label:"Manual Update",checked:n.manual,onChange:o=>t("autofocus",{...n,manual:o})}),ee(D,{label:"Debug",value:n.debug,min:0,max:1,step:.01,onChange:o=>t("autofocus",{...n,debug:o})}),ee(D,{label:"Smooth Time",value:n.smoothTime,min:0,max:2,step:.01,onChange:o=>t("autofocus",{...n,smoothTime:o})})]})}function tc({pp:e,set:t,open:a,toggle:i}){let{godRays:n}=e;return aa(Se,{title:"God Rays",tooltip:"Creates light shafts that streak outward from a bright sun or light source.",open:a.godRays,onToggle:()=>i("godRays"),disabled:!n.enabled,trailing:ee(Me,{checked:n.enabled,onChange:o=>t("godRays",{...n,enabled:o}),label:"Toggle GodRays"}),children:[ee(Lt,{label:"Sun Position",value:n.sunPosition,min:-100,max:100,step:.1,onChange:o=>t("godRays",{...n,sunPosition:o})}),ee(D,{label:"Samples",value:n.samples,min:1,max:128,step:1,onChange:o=>t("godRays",{...n,samples:o})}),ee(D,{label:"Density",value:n.density,min:0,max:2,step:.01,onChange:o=>t("godRays",{...n,density:o})}),ee(D,{label:"Decay",value:n.decay,min:0,max:1,step:.01,onChange:o=>t("godRays",{...n,decay:o})}),ee(D,{label:"Weight",value:n.weight,min:0,max:2,step:.01,onChange:o=>t("godRays",{...n,weight:o})}),ee(D,{label:"Exposure",value:n.exposure,min:0,max:2,step:.01,onChange:o=>t("godRays",{...n,exposure:o})}),ee(D,{label:"Clamp Max",value:n.clampMax,min:0,max:2,step:.01,onChange:o=>t("godRays",{...n,clampMax:o})}),ee(Ne,{label:"Blur",checked:n.blur,onChange:o=>t("godRays",{...n,blur:o})}),ee(Bt,{label:"Kernel Size",value:n.kernelSize,options:Yo,onChange:o=>t("godRays",{...n,kernelSize:o})})]})}function nc({pp:e,set:t,open:a,toggle:i}){let{lensflare:n}=e;return aa(Se,{title:"Lens Flare",tooltip:"Adds camera flare artifacts and glow from a bright light source.",open:a.lensflare,onToggle:()=>i("lensflare"),disabled:!n.enabled,trailing:ee(Me,{checked:n.enabled,onChange:o=>t("lensflare",{...n,enabled:o}),label:"Toggle Lensflare"}),children:[ee(Lt,{label:"Lens Position",value:n.lensPosition,min:-100,max:100,step:.1,onChange:o=>t("lensflare",{...n,lensPosition:o})}),ee(D,{label:"Smooth Time",value:n.smoothTime,min:0,max:1,step:.01,onChange:o=>t("lensflare",{...n,smoothTime:o})}),ee(D,{label:"Glare Size",value:n.glareSize,min:0,max:1,step:.01,onChange:o=>t("lensflare",{...n,glareSize:o})}),ee(D,{label:"Flare Size",value:n.flareSize,min:0,max:.1,step:.001,onChange:o=>t("lensflare",{...n,flareSize:o})}),ee(D,{label:"Flare Speed",value:n.flareSpeed,min:0,max:.2,step:.001,onChange:o=>t("lensflare",{...n,flareSpeed:o})}),ee(D,{label:"Flare Shape",value:n.flareShape,min:0,max:.2,step:.001,onChange:o=>t("lensflare",{...n,flareShape:o})}),ee(Ne,{label:"Animated",checked:n.animated,onChange:o=>t("lensflare",{...n,animated:o})}),ee(Ne,{label:"Anamorphic",checked:n.anamorphic,onChange:o=>t("lensflare",{...n,anamorphic:o})}),ee(Nt,{label:"Color Gain",value:n.colorGain,onChange:o=>t("lensflare",{...n,colorGain:o})}),ee(D,{label:"Halo Scale",value:n.haloScale,min:0,max:2,step:.01,onChange:o=>t("lensflare",{...n,haloScale:o})}),ee(Ne,{label:"Secondary Ghosts",checked:n.secondaryGhosts,onChange:o=>t("lensflare",{...n,secondaryGhosts:o})}),ee(Ne,{label:"Additional Streaks",checked:n.aditionalStreaks,onChange:o=>t("lensflare",{...n,aditionalStreaks:o})}),ee(D,{label:"Ghost Scale",value:n.ghostScale,min:0,max:1,step:.01,onChange:o=>t("lensflare",{...n,ghostScale:o})}),ee(D,{label:"Opacity",value:n.opacity,min:0,max:1,step:.01,onChange:o=>t("lensflare",{...n,opacity:o})}),ee(Ne,{label:"Star Burst",checked:n.starBurst,onChange:o=>t("lensflare",{...n,starBurst:o})})]})}function oc({pp:e,set:t,open:a,toggle:i}){let{depthOfField:n}=e;return aa(Se,{title:"Depth Of Field",tooltip:"Blurs areas that sit away from the focal plane for a camera-like look.",open:a.depthOfField,onToggle:()=>i("depthOfField"),disabled:!n.enabled,trailing:ee(Me,{checked:n.enabled,onChange:o=>t("depthOfField",{...n,enabled:o}),label:"Toggle DepthOfField"}),children:[ee(D,{label:"Focus Distance",value:n.focusDistance,min:0,max:50,step:.1,onChange:o=>t("depthOfField",{...n,focusDistance:o})}),ee(D,{label:"Focus Range",value:n.focusRange,min:.1,max:50,step:.1,onChange:o=>t("depthOfField",{...n,focusRange:o})}),ee(D,{label:"Focal Length",value:n.focalLength,min:0,max:1,step:.01,onChange:o=>t("depthOfField",{...n,focalLength:o})}),ee(D,{label:"Bokeh Scale",value:n.bokehScale,min:0,max:20,step:.1,onChange:o=>t("depthOfField",{...n,bokehScale:o})})]})}import{jsx as he,jsxs as No}from"react/jsx-runtime";var gg=["linear","reinhard","aces"];function ac({pp:e,set:t,open:a,toggle:i}){let{colorAverage:n}=e;return he(Se,{title:"Color Average",tooltip:"Blends the frame toward a single average color for a washed-out stylized look.",open:a.colorAverage,onToggle:()=>i("colorAverage"),disabled:!n.enabled,trailing:he(Me,{checked:n.enabled,onChange:o=>t("colorAverage",{...n,enabled:o}),label:"Toggle ColorAverage"}),children:he("div",{className:"se-placeholder",children:"Averages the frame color using the docs default blend mode."})})}function ic({pp:e,set:t,open:a,toggle:i}){let{brightnessContrast:n}=e;return No(Se,{title:"Brightness Contrast",tooltip:"Raises or lowers overall brightness and contrast across the scene.",open:a.brightnessContrast,onToggle:()=>i("brightnessContrast"),disabled:!n.enabled,trailing:he(Me,{checked:n.enabled,onChange:o=>t("brightnessContrast",{...n,enabled:o}),label:"Toggle BrightnessContrast"}),children:[he(D,{label:"Brightness",value:n.brightness,min:-1,max:1,step:.01,onChange:o=>t("brightnessContrast",{...n,brightness:o})}),he(D,{label:"Contrast",value:n.contrast,min:-1,max:1,step:.01,onChange:o=>t("brightnessContrast",{...n,contrast:o})})]})}function rc({pp:e,set:t,open:a,toggle:i}){let{hueSaturation:n}=e;return No(Se,{title:"Hue Saturation",tooltip:"Shifts the hue and saturation to tint the whole image.",open:a.hueSaturation,onToggle:()=>i("hueSaturation"),disabled:!n.enabled,trailing:he(Me,{checked:n.enabled,onChange:o=>t("hueSaturation",{...n,enabled:o}),label:"Toggle HueSaturation"}),children:[he(D,{label:"Hue",value:n.hue,min:-Math.PI,max:Math.PI,step:.01,formatValue:o=>`${o.toFixed(2)} rad`,onChange:o=>t("hueSaturation",{...n,hue:o})}),he(D,{label:"Saturation",value:n.saturation,min:-1,max:1,step:.01,onChange:o=>t("hueSaturation",{...n,saturation:o})})]})}function sc({pp:e,set:t,open:a,toggle:i}){let{vignette:n}=e;return No(Se,{title:"Vignette",tooltip:"Darkens the edges of the screen so the center feels more focused.",open:a.vignette,onToggle:()=>i("vignette"),disabled:!n.enabled,trailing:he(Me,{checked:n.enabled,onChange:o=>t("vignette",{...n,enabled:o}),label:"Toggle Vignette"}),children:[he(D,{label:"Offset",value:n.offset,min:0,max:1,step:.01,onChange:o=>t("vignette",{...n,offset:o})}),he(D,{label:"Darkness",value:n.darkness,min:0,max:1,step:.01,onChange:o=>t("vignette",{...n,darkness:o})}),he(Ne,{label:"Eskil",checked:n.eskil,onChange:o=>t("vignette",{...n,eskil:o})})]})}function lc({pp:e,set:t,open:a,toggle:i}){let{bloom:n}=e;return No(Se,{title:"Bloom",tooltip:"Makes bright areas glow and bleed softly into nearby pixels.",open:a.bloom,onToggle:()=>i("bloom"),disabled:!n.enabled,trailing:he(Me,{checked:n.enabled,onChange:o=>t("bloom",{...n,enabled:o}),label:"Toggle Bloom"}),children:[he(D,{label:"Threshold",value:n.luminanceThreshold,min:0,max:1,step:.01,onChange:o=>t("bloom",{...n,luminanceThreshold:o})}),he(D,{label:"Smoothing",value:n.luminanceSmoothing,min:0,max:1,step:.01,onChange:o=>t("bloom",{...n,luminanceSmoothing:o})}),he(D,{label:"Intensity",value:n.intensity,min:0,max:3,step:.05,onChange:o=>t("bloom",{...n,intensity:o})}),he(Ne,{label:"Mipmap Blur",checked:n.mipmapBlur,onChange:o=>t("bloom",{...n,mipmapBlur:o})}),he(D,{label:"Radius",value:n.radius,min:0,max:1,step:.01,onChange:o=>t("bloom",{...n,radius:o})}),he(D,{label:"Levels",value:n.levels,min:1,max:16,step:1,onChange:o=>t("bloom",{...n,levels:o})})]})}function dc({pp:e,set:t,open:a,toggle:i}){let{toneMapping:n}=e;return No(Se,{title:"Tone Mapping",tooltip:"Remaps HDR lighting to screen output and controls exposure style.",open:a.toneMapping,onToggle:()=>i("toneMapping"),disabled:!n.enabled,trailing:he(Me,{checked:n.enabled,onChange:o=>t("toneMapping",{...n,enabled:o}),label:"Toggle ToneMapping"}),children:[No("div",{className:"se-field",children:[he("span",{className:"se-fieldLabel",children:"Mode"}),he("div",{className:"se-segmentedControl",children:gg.map(o=>he("button",{type:"button",className:`se-segmentedOption ${n.mode===o?"se-segmentedOption--active":""}`,onClick:()=>t("toneMapping",{...n,mode:o}),children:o==="aces"?"Filmic":o.charAt(0).toUpperCase()+o.slice(1)},o))})]}),he(D,{label:"Resolution",value:n.resolution,min:64,max:4096,step:64,onChange:o=>t("toneMapping",{...n,resolution:o})}),he(D,{label:"White Point",value:n.whitePoint,min:0,max:16,step:.01,onChange:o=>t("toneMapping",{...n,whitePoint:o})}),he(D,{label:"Middle Grey",value:n.middleGrey,min:0,max:1,step:.01,onChange:o=>t("toneMapping",{...n,middleGrey:o})}),he(D,{label:"Min Luminance",value:n.minLuminance,min:0,max:1,step:.01,onChange:o=>t("toneMapping",{...n,minLuminance:o})}),he(D,{label:"Average Luminance",value:n.averageLuminance,min:0,max:4,step:.01,onChange:o=>t("toneMapping",{...n,averageLuminance:o})}),he(D,{label:"Adaptation Rate",value:n.adaptationRate,min:0,max:10,step:.01,onChange:o=>t("toneMapping",{...n,adaptationRate:o})}),he(D,{label:"Exposure",value:n.exposure,min:0,max:3,step:.01,onChange:o=>t("toneMapping",{...n,exposure:o})})]})}function cc({pp:e,set:t,open:a,toggle:i}){let{sepia:n}=e;return he(Se,{title:"Sepia",tooltip:"Adds a warm vintage brown tint to the entire image.",open:a.sepia,onToggle:()=>i("sepia"),disabled:!n.enabled,trailing:he(Me,{checked:n.enabled,onChange:o=>t("sepia",{...n,enabled:o}),label:"Toggle Sepia"}),children:he(D,{label:"Intensity",value:n.intensity,min:0,max:1,step:.01,onChange:o=>t("sepia",{...n,intensity:o})})})}import{jsx as ce,jsxs as To}from"react/jsx-runtime";function pc({pp:e,set:t,open:a,toggle:i}){let{dotScreen:n}=e;return To(Se,{title:"Dot Screen",tooltip:"Overlays a halftone dot pattern for a printed or retro look.",open:a.dotScreen,onToggle:()=>i("dotScreen"),disabled:!n.enabled,trailing:ce(Me,{checked:n.enabled,onChange:o=>t("dotScreen",{...n,enabled:o}),label:"Toggle DotScreen"}),children:[ce(D,{label:"Angle",value:n.angle,min:0,max:Math.PI*2,step:.01,formatValue:o=>`${o.toFixed(2)} rad`,onChange:o=>t("dotScreen",{...n,angle:o})}),ce(D,{label:"Scale",value:n.scale,min:.1,max:10,step:.05,onChange:o=>t("dotScreen",{...n,scale:o})})]})}function bc({pp:e,set:t,open:a,toggle:i}){let{glitch:n}=e;return To(Se,{title:"Glitch",tooltip:"Introduces digital distortion, tearing, and scan noise.",open:a.glitch,onToggle:()=>i("glitch"),disabled:!n.enabled,trailing:ce(Me,{checked:n.enabled,onChange:o=>t("glitch",{...n,enabled:o}),label:"Toggle Glitch"}),children:[ce(Bt,{label:"Mode",value:n.mode,options:yl,onChange:o=>t("glitch",{...n,mode:o})}),ce(eo,{label:"Delay",value:n.delay,min:0,max:10,step:.01,onChange:o=>t("glitch",{...n,delay:o})}),ce(eo,{label:"Duration",value:n.duration,min:0,max:5,step:.01,onChange:o=>t("glitch",{...n,duration:o})}),ce(eo,{label:"Strength",value:n.strength,min:0,max:2,step:.01,onChange:o=>t("glitch",{...n,strength:o})}),ce(eo,{label:"Chromatic Aberration Offset",value:n.chromaticAberrationOffset,min:0,max:.02,step:1e-4,onChange:o=>t("glitch",{...n,chromaticAberrationOffset:o})}),ce(D,{label:"Columns",value:n.columns,min:0,max:.5,step:.001,onChange:o=>t("glitch",{...n,columns:o})}),ce(D,{label:"Ratio",value:n.ratio,min:0,max:1,step:.01,onChange:o=>t("glitch",{...n,ratio:o})})]})}function uc({pp:e,set:t,open:a,toggle:i}){let{grid:n}=e;return To(Se,{title:"Grid",tooltip:"Adds a visual grid overlay that feels retro or debug-like.",open:a.grid,onToggle:()=>i("grid"),disabled:!n.enabled,trailing:ce(Me,{checked:n.enabled,onChange:o=>t("grid",{...n,enabled:o}),label:"Toggle Grid"}),children:[ce(D,{label:"Scale",value:n.scale,min:.1,max:10,step:.05,onChange:o=>t("grid",{...n,scale:o})}),ce(D,{label:"Line Width",value:n.lineWidth,min:0,max:1,step:.01,onChange:o=>t("grid",{...n,lineWidth:o})})]})}function mc({pp:e,set:t,open:a,toggle:i}){let{chromaticAberration:n}=e;return To(Se,{title:"Chromatic Aberration",tooltip:"Separates color channels slightly to mimic lens fringing.",open:a.chromaticAberration,onToggle:()=>i("chromaticAberration"),disabled:!n.enabled,trailing:ce(Me,{checked:n.enabled,onChange:o=>t("chromaticAberration",{...n,enabled:o}),label:"Toggle ChromaticAberration"}),children:[ce(D,{label:"Offset X",value:n.offsetX,min:0,max:.02,step:1e-4,onChange:o=>t("chromaticAberration",{...n,offsetX:o})}),ce(D,{label:"Offset Y",value:n.offsetY,min:0,max:.02,step:1e-4,onChange:o=>t("chromaticAberration",{...n,offsetY:o})}),ce(Ne,{label:"Radial Modulation",checked:n.radialModulation,onChange:o=>t("chromaticAberration",{...n,radialModulation:o})}),ce(D,{label:"Modulation Offset",value:n.modulationOffset,min:0,max:1,step:.01,onChange:o=>t("chromaticAberration",{...n,modulationOffset:o})})]})}function gc({pp:e,set:t,open:a,toggle:i}){let{noise:n}=e;return To(Se,{title:"Noise",tooltip:"Adds film grain or static noise to the rendered image.",open:a.noise,onToggle:()=>i("noise"),disabled:!n.enabled,trailing:ce(Me,{checked:n.enabled,onChange:o=>t("noise",{...n,enabled:o}),label:"Toggle Noise"}),children:[ce(D,{label:"Amount",value:n.opacity,min:0,max:1,step:.01,onChange:o=>t("noise",{...n,opacity:o})}),ce(Ne,{label:"Premultiply",checked:n.premultiply,onChange:o=>t("noise",{...n,premultiply:o})})]})}function fc({pp:e,set:t,open:a,toggle:i}){let{scanline:n}=e;return ce(Se,{title:"Scan Line",tooltip:"Draws horizontal CRT-style scan lines over the frame.",open:a.scanline,onToggle:()=>i("scanline"),disabled:!n.enabled,trailing:ce(Me,{checked:n.enabled,onChange:o=>t("scanline",{...n,enabled:o}),label:"Toggle Scanline"}),children:ce(D,{label:"Density",value:n.density,min:0,max:10,step:.25,onChange:o=>t("scanline",{...n,density:o})})})}function hc({pp:e,set:t,open:a,toggle:i}){let{pixelation:n}=e;return ce(Se,{title:"Pixelation",tooltip:"Reduces detail into larger pixels for a blocky stylized effect.",open:a.pixelation,onToggle:()=>i("pixelation"),disabled:!n.enabled,trailing:ce(Me,{checked:n.enabled,onChange:o=>t("pixelation",{...n,enabled:o}),label:"Toggle Pixelation"}),children:ce(D,{label:"Granularity",value:n.granularity,min:0,max:20,step:1,onChange:o=>t("pixelation",{...n,granularity:o})})})}function xc({pp:e,set:t,open:a,toggle:i}){let{ramp:n}=e;return To(Se,{title:"Ramp",tooltip:"Adds a screen-space color gradient, or masks effects earlier in the stack.",open:a.ramp,onToggle:()=>i("ramp"),disabled:!n.enabled,trailing:ce(Me,{checked:n.enabled,onChange:o=>t("ramp",{...n,enabled:o}),label:"Toggle Ramp"}),children:[ce(Bt,{label:"Ramp Type",value:n.rampType,options:vl,onChange:o=>t("ramp",{...n,rampType:o})}),ce(eo,{label:"Ramp Start",value:n.rampStart,min:0,max:1,step:.01,onChange:o=>t("ramp",{...n,rampStart:o})}),ce(eo,{label:"Ramp End",value:n.rampEnd,min:0,max:1,step:.01,onChange:o=>t("ramp",{...n,rampEnd:o})}),ce(Nt,{label:"Start Color",value:n.startColor,onChange:o=>t("ramp",{...n,startColor:o})}),ce(Nt,{label:"End Color",value:n.endColor,onChange:o=>t("ramp",{...n,endColor:o})}),!n.rampMask&&ce(D,{label:"Gradient Opacity",value:n.opacity??.5,min:0,max:1,step:.01,onChange:o=>t("ramp",{...n,opacity:o})}),ce(D,{label:"Bias",value:n.rampBias,min:0,max:1,step:.01,onChange:o=>t("ramp",{...n,rampBias:o})}),ce(D,{label:"Gain",value:n.rampGain,min:0,max:1,step:.01,onChange:o=>t("ramp",{...n,rampGain:o})}),ce(Ne,{label:"Mask Earlier Effects",checked:n.rampMask,onChange:o=>t("ramp",{...n,rampMask:o})}),ce(Ne,{label:"Invert",checked:n.rampInvert,onChange:o=>t("ramp",{...n,rampInvert:o})})]})}import{jsx as Ue,jsxs as wc}from"react/jsx-runtime";function yc({pp:e,set:t,open:a,toggle:i}){let{outline:n}=e;return wc(Se,{title:"Outline",tooltip:"Draws a visible edge around the selected object binding.",open:a.outline,onToggle:()=>i("outline"),disabled:!n.enabled,trailing:Ue(Me,{checked:n.enabled,onChange:o=>t("outline",{...n,enabled:o}),label:"Toggle Outline"}),children:[Ue("div",{className:"se-placeholder",children:"Outlines the currently selected object binding in the model editor."}),Ue(D,{label:"Selection Layer",value:n.selectionLayer,min:0,max:20,step:1,onChange:o=>t("outline",{...n,selectionLayer:o})}),Ue(D,{label:"Edge Strength",value:n.edgeStrength,min:0,max:10,step:.1,onChange:o=>t("outline",{...n,edgeStrength:o})}),Ue(D,{label:"Pulse Speed",value:n.pulseSpeed,min:0,max:10,step:.1,onChange:o=>t("outline",{...n,pulseSpeed:o})}),Ue(Nt,{label:"Visible Edge Color",value:n.visibleEdgeColor,onChange:o=>t("outline",{...n,visibleEdgeColor:o})}),Ue(Nt,{label:"Hidden Edge Color",value:n.hiddenEdgeColor,onChange:o=>t("outline",{...n,hiddenEdgeColor:o})}),Ue(Bt,{label:"Kernel Size",value:n.kernelSize,options:Yo,onChange:o=>t("outline",{...n,kernelSize:o})}),Ue(Ne,{label:"Blur",checked:n.blur,onChange:o=>t("outline",{...n,blur:o})}),Ue(Ne,{label:"X-Ray",checked:n.xRay,onChange:o=>t("outline",{...n,xRay:o})})]})}function vc({pp:e,set:t,open:a,toggle:i}){let{selectiveBloom:n}=e;return wc(Se,{title:"Selective Bloom",tooltip:"Applies bloom only to objects assigned to the selected layer.",open:a.selectiveBloom,onToggle:()=>i("selectiveBloom"),disabled:!n.enabled,trailing:Ue(Me,{checked:n.enabled,onChange:o=>t("selectiveBloom",{...n,enabled:o}),label:"Toggle SelectiveBloom"}),children:[Ue("div",{className:"se-placeholder",children:"Applies bloom to the currently selected object binding."}),Ue(D,{label:"Selection Layer",value:n.selectionLayer,min:0,max:20,step:1,onChange:o=>t("selectiveBloom",{...n,selectionLayer:o})}),Ue(D,{label:"Intensity",value:n.intensity,min:0,max:5,step:.05,onChange:o=>t("selectiveBloom",{...n,intensity:o})}),Ue(D,{label:"Threshold",value:n.luminanceThreshold,min:0,max:1,step:.01,onChange:o=>t("selectiveBloom",{...n,luminanceThreshold:o})}),Ue(D,{label:"Smoothing",value:n.luminanceSmoothing,min:0,max:1,step:.01,onChange:o=>t("selectiveBloom",{...n,luminanceSmoothing:o})}),Ue(Bt,{label:"Kernel Size",value:n.kernelSize,options:Yo,onChange:o=>t("selectiveBloom",{...n,kernelSize:o})}),Ue(Ne,{label:"Mipmap Blur",checked:n.mipmapBlur,onChange:o=>t("selectiveBloom",{...n,mipmapBlur:o})}),Ue(Ne,{label:"Inverted",checked:n.inverted,onChange:o=>t("selectiveBloom",{...n,inverted:o})}),Ue(Ne,{label:"Ignore Background",checked:n.ignoreBackground,onChange:o=>t("selectiveBloom",{...n,ignoreBackground:o})})]})}function Sc({pp:e,set:t,open:a,toggle:i}){let{smaa:n}=e;return Ue(Se,{title:"SMAA",tooltip:"Reduces jagged edges with subpixel anti-aliasing.",open:a.smaa,onToggle:()=>i("smaa"),trailing:Ue(Me,{checked:n.enabled,onChange:o=>t("smaa",{...n,enabled:o}),label:"Toggle SMAA"}),children:Ue("div",{className:"se-placeholder",children:"Subpixel Morphological Anti-Aliasing smooths jagged edges in post-process."})})}import{Fragment as Cc,jsx as Le,jsxs as yr}from"react/jsx-runtime";function vr({config:e,onChange:t}){let[a,i]=fg({autofocus:!1,colorAverage:!1,dotScreen:!1,glitch:!1,godRays:!1,grid:!1,lensflare:!1,outline:!1,selectiveBloom:!1,ramp:!1,ssao:!1,brightnessContrast:!1,hueSaturation:!1,depthOfField:!1,chromaticAberration:!1,vignette:!1,bloom:!1,toneMapping:!1,noise:!1,sepia:!1,scanline:!1,pixelation:!1,smaa:!1}),n=w=>i(h=>({...h,[w]:!h[w]})),{tier:o}=lt(),d=e.postProcessing,c={pp:d,set:(w,h)=>t({...e,postProcessing:{...d,[w]:h}}),open:a,toggle:n};return yr("div",{className:"se-generalContent",children:[Le(ac,{...c}),Le(ic,{...c}),Le(rc,{...c}),Le(sc,{...c}),Le(lc,{...c}),Le(dc,{...c}),Le(cc,{...c}),ut(o,"postLighting")?yr(Cc,{children:[Le(Qd,{...c}),Le(ec,{...c}),Le(tc,{...c}),Le(nc,{...c}),Le(oc,{...c})]}):Le(_e,{requiredTier:"starter",feature:"SSAO, depth of field, god rays and lens flare"}),ut(o,"postSelection")?yr(Cc,{children:[Le(yc,{...c}),Le(vc,{...c}),Le(Sc,{...c}),Le(pc,{...c}),Le(bc,{...c}),Le(uc,{...c}),Le(mc,{...c}),Le(gc,{...c}),Le(fc,{...c}),Le(hc,{...c}),Le(xc,{...c})]}):Le(_e,{requiredTier:"growth",feature:"Outline, selective bloom and stylize effects"})]})}import{useState as kc,useSyncExternalStore as hg}from"react";import{Eye as xg,EyeOff as yg,Plus as vg,Trash2 as Sg}from"lucide-react";import{Fragment as Mc,jsx as se,jsxs as Rt}from"react/jsx-runtime";var wg=["512","1024","2048","4096"],Nc={none:"None",directional:"Direction",point:"Point",spot:"Spot",hemisphere:"Hemi"};function Cg({index:e,light:t,selected:a,onSelect:i,onToggleVisible:n}){return Rt("div",{className:`se-lightRow ${a?"se-lightRow--active":""}`,onClick:i,children:[Rt("span",{className:"se-lightRowLabel",children:[e+1,": ",Nc[t.type]]}),se("button",{type:"button",className:"se-iconButton","aria-label":t.visible?"Hide light":"Show light",onClick:o=>{o.stopPropagation(),n()},children:t.visible?se(xg,{size:14}):se(yg,{size:14})})]})}function kg(){return{id:crypto.randomUUID(),type:"directional",color:"#ffffff",intensity:1,position:[5,10,5],attachedToCamera:!1,castShadow:!1,shadowBias:-5e-4,visible:!0}}function Sr({config:e,onChange:t}){let[a,i]=kc({lights:!0,shadows:!1,groundShadows:!1,environment:!1,envShadow:!1}),n=hg(_l,Wl),[o,d]=kc(e.lighting.lights[0]?.id??null),l=n??o,c=r=>{d(r),Gl(r)},w=r=>i(M=>({...M,[r]:!M[r]})),{tier:h}=lt(),{lighting:y,shadows:u,groundShadows:g,environment:B}=e,v=r=>t({...e,lighting:r}),P=r=>t({...e,shadows:r}),x=r=>t({...e,groundShadows:r}),C=r=>t({...e,environment:r}),S=(r,M)=>{v({...y,lights:y.lights.map(j=>j.id===r?{...j,...M}:j)})},f=y.lights.find(r=>r.id===l)??null,k=()=>{let r=kg();v({...y,lights:[...y.lights,r]}),c(r.id)},O=()=>{if(!f)return;let r=y.lights.filter(M=>M.id!==f.id);v({...y,lights:r}),c(r[0]?.id??null)},p=Mt(h,"lights",y.lights.length);return Rt("div",{className:"se-generalContent",children:[Rt(Se,{title:"Lights",open:a.lights,onToggle:()=>w("lights"),children:[se("div",{className:"se-lightList",children:y.lights.map((r,M)=>se(Cg,{index:M,light:r,selected:r.id===l,onSelect:()=>c(r.id),onToggleVisible:()=>S(r.id,{visible:!r.visible})},r.id))}),p?null:se(_e,{requiredTier:bn("lights",y.lights.length),feature:"More lights"}),Rt("div",{className:"se-lightActions",children:[se("button",{type:"button",className:"se-iconButton",onClick:k,disabled:!p,title:"Add light",children:se(vg,{size:14})}),f&&y.lights.length>1&&se("button",{type:"button",className:"se-iconButton",onClick:O,title:"Remove selected light",children:se(Sg,{size:14})})]}),f?Rt("div",{className:"se-lightProps",children:[Rt("div",{className:"se-field",children:[se("span",{className:"se-fieldLabel",children:"Type"}),se("div",{className:"se-segmentedControl",style:{gridAutoColumns:"1fr"},children:fl.map(r=>se("button",{type:"button",className:`se-segmentedOption ${f.type===r?"se-segmentedOption--active":""}`,onClick:()=>S(f.id,{type:r}),children:Nc[r]},r))})]}),se(Nt,{label:"Color",value:f.color,onChange:r=>S(f.id,{color:r})}),se(D,{label:"Intensity",value:f.intensity,min:0,max:10,step:.1,onChange:r=>S(f.id,{intensity:r})}),f.type!=="hemisphere"&&f.type!=="none"&&se(Lt,{label:"Position",value:f.position,min:-100,max:100,step:.05,onChange:r=>S(f.id,{position:r})}),f.type==="spot"&&Rt(Mc,{children:[se(D,{label:"Angle",value:f.angle??Math.PI/6,min:0,max:Math.PI/2,step:.01,formatValue:r=>`${Math.round(r*180/Math.PI)}\xB0`,onChange:r=>S(f.id,{angle:r})}),se(D,{label:"Penumbra",value:f.penumbra??.2,min:0,max:1,step:.01,onChange:r=>S(f.id,{penumbra:r})}),se(D,{label:"Distance",value:f.distance??0,min:0,max:100,step:.5,onChange:r=>S(f.id,{distance:r})}),se(D,{label:"Decay",value:f.decay??2,min:0,max:4,step:.1,onChange:r=>S(f.id,{decay:r})})]}),se(Ne,{label:"Attached to camera",checked:f.attachedToCamera,onChange:r=>S(f.id,{attachedToCamera:r})}),se(Ne,{label:"Cast shadows",checked:f.castShadow,onChange:r=>S(f.id,{castShadow:r})}),se(D,{label:"Shadow bias",value:f.shadowBias,min:-.01,max:.01,step:1e-4,onChange:r=>S(f.id,{shadowBias:r})})]}):null]}),Rt(Se,{title:"Shadows",open:a.shadows,onToggle:()=>w("shadows"),disabled:!u.enabled,trailing:se(Me,{checked:u.enabled,onChange:r=>P({...u,enabled:r}),label:"Toggle shadows"}),children:[se(Bt,{label:"Map size",value:String(u.mapSize),options:wg,onChange:r=>P({...u,mapSize:Number(r)})}),se(D,{label:"Bias",value:u.bias,min:-.01,max:.01,step:1e-4,onChange:r=>P({...u,bias:r})}),se(D,{label:"Normal bias",value:u.normalBias,min:0,max:.2,step:.01,onChange:r=>P({...u,normalBias:r})}),se(D,{label:"Radius (softness)",value:u.radius,min:0,max:20,step:.5,onChange:r=>P({...u,radius:r})})]}),Rt(Se,{title:"Ground Shadows",open:a.groundShadows,onToggle:()=>w("groundShadows"),disabled:!g.enabled,trailing:se(Me,{checked:g.enabled,onChange:r=>x({...g,enabled:r}),label:"Toggle ground shadows"}),children:[Rt("div",{className:"se-field",children:[se("span",{className:"se-fieldLabel",children:"Mode"}),se("div",{className:"se-segmentedControl",style:{gridAutoColumns:"1fr"},children:["shadowCatcher"].map(r=>se("button",{type:"button",className:`se-segmentedOption ${g.mode===r?"se-segmentedOption--active":""}`,onClick:()=>x({...g,mode:r}),children:r==="shadowCatcher"?"Shadow Catcher":"Baked AO"},r))})]}),g.mode==="bakedAO"&&se("div",{className:"se-placeholder",children:"Requires pre-baked AO textures \u2014 not yet available."}),se(D,{label:"Intensity",value:g.intensity,min:0,max:1,step:.01,onChange:r=>x({...g,intensity:r})}),se(D,{label:"Border fade",value:g.borderFade,min:0,max:10,step:.1,onChange:r=>x({...g,borderFade:r})}),se(D,{label:"Height",value:g.height,min:-5,max:5,step:.1,onChange:r=>x({...g,height:r})}),se(D,{label:"Size",value:g.size,min:1,max:50,step:.5,onChange:r=>x({...g,size:r})})]}),se(Se,{title:"Environment",open:a.environment,onToggle:()=>w("environment"),children:Rt(Mc,{children:[se(D,{label:"Orientation",value:B.rotation,min:0,max:360,step:1,formatValue:r=>`${r}\xB0`,onChange:r=>C({...B,rotation:r})}),se(D,{label:"Brightness",value:B.intensity,min:0,max:3,step:.05,onChange:r=>C({...B,intensity:r})}),Rt(Se,{title:"Shadow",open:a.envShadow,onToggle:()=>w("envShadow"),trailing:se(Me,{checked:B.shadowLight.enabled,onChange:r=>C({...B,shadowLight:{...B.shadowLight,enabled:r}}),label:"Toggle environment shadow light"}),disabled:!B.shadowLight.enabled,children:[se(D,{label:"Light intensity",value:B.shadowLight.intensity,min:0,max:20,step:.1,onChange:r=>C({...B,shadowLight:{...B.shadowLight,intensity:r}})}),se(D,{label:"Shadow bias",value:B.shadowLight.bias,min:-.01,max:.01,step:1e-4,onChange:r=>C({...B,shadowLight:{...B.shadowLight,bias:r}})})]})]})})]})}import{useMemo as Mg,useState as Ng}from"react";import{ChevronDown as Tg,Pause as Tc,Play as Pg,Rewind as Bg,Square as Rg,Trash2 as Ag}from"lucide-react";import{jsx as ue,jsxs as Ke}from"react/jsx-runtime";var Og={playing:"Playing",paused:"Paused",finished:"Finished"},Pc={repeat:"Looping",once:"Play once","ping-pong":"Ping-pong"};function jg(e){if(!Number.isFinite(e)||e<=0)return"Unknown duration";let t=Math.round(e*10)/10;if(t<60)return`${t.toFixed(1)}s`;let a=Math.floor(t/60),i=(t%60).toFixed(1).padStart(4,"0");return`${a}:${i}`}function Bc(e){let t=Number.isFinite(e)&&e>0?e:0;if(t<60)return`${t.toFixed(1)}s`;let a=Math.floor(t/60),i=(t%60).toFixed(1).padStart(4,"0");return`${a}:${i}`}function Eg(e){return Number.isFinite(e)?Math.min(3,Math.max(.1,Number(e.toFixed(2)))):1}function wr({config:e,onChange:t,clipDetails:a,active:i,play:n,pause:o,stop:d,setSpeed:l,seek:c}){let w=ut(lt().tier,"animationConfig"),[h,y]=Ng(!1),u=Mg(()=>new Map(a.map(p=>[p.sourceName,p.duration])),[a]),g=e.animations.clips.filter(p=>!p.hidden),B=e.animations.clips.filter(p=>p.hidden),v=(p,r=e.animations.autoplayClip)=>{t({...e,animations:{clips:p(e.animations.clips),autoplayClip:r}})},P=(p,r)=>{v(M=>M.map(j=>j.sourceName===p?r(j):j))},x=(p,r)=>{P(p,M=>({...M,loopMode:r}))},C=(p,r)=>{let M=Eg(r);P(p,j=>({...j,speed:M})),i.some(j=>j.clip===p)&&l(M,p)},S=(p,r)=>{P(p,M=>({...M,displayName:r}))},f=p=>{let r=e.animations.autoplayClip===p?null:p;t({...e,animations:{...e.animations,autoplayClip:r}})},k=p=>{v(r=>r.map(M=>M.sourceName===p?{...M,hidden:!0}:M),e.animations.autoplayClip===p?null:e.animations.autoplayClip),i.some(r=>r.clip===p)&&d(p)},O=p=>{v(r=>r.map(M=>M.sourceName===p?{...M,hidden:!1}:M))};return e.animations.clips.length===0?ue(xn,{title:"Animations",children:ue("div",{className:"se-helperCard",children:"Upload a model with embedded animations to manage playback, naming, autoplay, and per-clip speed here."})}):Ke(xn,{title:"Animations",children:[w?null:ue(_e,{requiredTier:"starter",feature:"Autoplay, looping, speed and clip names"}),g.length===0&&ue("div",{className:"se-helperCard",children:ue("span",{children:"Preview clips directly in the viewer (several can play at once), choose one optional autoplay animation, and use soft delete to hide clips without modifying the GLB."})}),g.length===0?ue("div",{className:"se-placeholder",children:"All animations are currently removed. Restore a clip below to make it available again."}):ue("div",{className:"se-animationList",children:g.map(p=>{let r=i.find(z=>z.clip===p.sourceName),M=r?.status==="playing",j=r?.time??0,R=u.get(p.sourceName)??0,E=r?Og[r.status]:"Ready";return Ke("article",{className:`se-animationCard ${r?"se-animationCard--active":""}`,children:[Ke("div",{className:"se-animationHeader",children:[Ke("div",{className:"se-animationHeading",children:[Ke("div",{className:"se-animationTitleRow",children:[ue("span",{className:"se-animationStatus",children:E}),e.animations.autoplayClip===p.sourceName?ue("span",{className:"se-animationBadge",children:"Autoplay"}):null]}),ue("div",{className:"se-animationSource",children:p.sourceName})]}),ue("button",{type:"button",className:"se-animationDangerButton",onClick:()=>k(p.sourceName),title:"Remove animation",children:ue(Ag,{size:16})})]}),Ke("div",{className:"se-field",children:[ue("span",{className:"se-fieldLabel",children:"Display name"}),ue("input",{className:"se-textInput",value:p.displayName,onChange:z=>S(p.sourceName,z.target.value),placeholder:"Animation name"})]}),Ke("div",{className:"se-animationMeta",children:[ue("span",{children:jg(R)}),ue("span",{children:Pc[p.loopMode]??Pc.repeat}),Ke("span",{children:[p.speed.toFixed(2),"x"]})]}),Ke("div",{className:"se-animationButtonRow",children:[ue("button",{type:"button",className:"se-animationButton se-animationButton--icon",onClick:()=>M&&!r?.reverse?o(p.sourceName):n(p.sourceName,{alongside:!0}),"aria-label":M&&!r?.reverse?"Pause":"Play",title:M&&!r?.reverse?"Pause":"Play",children:M&&!r?.reverse?ue(Tc,{size:16}):ue(Pg,{size:16})}),ue("button",{type:"button",className:"se-animationButton se-animationButton--icon",onClick:()=>M&&r?.reverse?o(p.sourceName):n(p.sourceName,{alongside:!0,reverse:!0}),"aria-label":M&&r?.reverse?"Pause":"Play backwards",title:M&&r?.reverse?"Pause":"Play backwards",children:M&&r?.reverse?ue(Tc,{size:16}):ue(Bg,{size:16})}),ue("button",{type:"button",className:"se-animationButton se-animationButton--icon",onClick:()=>d(p.sourceName),disabled:!r,"aria-label":"Stop",title:"Stop",children:ue(Rg,{size:16})})]}),Ke("div",{className:"se-animationSeekRow",children:[ue("input",{className:"se-slider se-animationSeek",type:"range",min:0,max:Math.max(R,.001),step:.01,value:Math.min(j,R),disabled:!r||R<=0,onChange:z=>c(Number(z.target.value),p.sourceName),"aria-label":"Seek"}),Ke("span",{className:"se-animationSeekTime",children:[Bc(Math.min(j,R))," / ",Bc(R)]})]}),w?Ke("div",{className:"se-animationGrid",children:[Ke("label",{className:"se-field",children:[ue("span",{className:"se-fieldLabel",children:"Loop mode"}),Ke("select",{className:"se-select",value:p.loopMode,onChange:z=>x(p.sourceName,z.target.value),children:[ue("option",{value:"repeat",children:"Loop"}),ue("option",{value:"once",children:"Play Once"}),ue("option",{value:"ping-pong",children:"Ping-Pong"})]})]}),Ke("label",{className:"se-field",children:[Ke("span",{className:"se-fieldLabel",children:["Speed",Ke("span",{className:"se-fieldValue",children:[p.speed.toFixed(2),"x"]})]}),Ke("div",{className:"se-animationSpeedRow",children:[ue("input",{className:"se-slider",type:"range",min:.1,max:3,step:.1,value:p.speed,onChange:z=>C(p.sourceName,Number(z.target.value))}),ue("input",{className:"se-numberInput se-animationSpeedInput",type:"number",min:.1,max:3,step:.1,value:p.speed,onChange:z=>C(p.sourceName,Number(z.target.value))})]})]})]}):null,w?ue("button",{type:"button",className:`se-animationAutoplayButton ${e.animations.autoplayClip===p.sourceName?"se-animationAutoplayButton--active":""}`,onClick:()=>f(p.sourceName),children:e.animations.autoplayClip===p.sourceName?"Disable autoplay":"Set as autoplay"}):null]},p.sourceName)})}),B.length>0?Ke("section",{className:"se-removedAnimations",children:[ue("button",{type:"button",className:"se-panelHeader",onClick:()=>y(p=>!p),children:Ke("span",{className:"se-panelHeaderMain",children:[ue(Tg,{size:16,className:`se-panelChevron ${h?"se-panelChevron--open":""}`}),Ke("span",{className:"se-panelTitle",children:["Removed Animations (",B.length,")"]})]})}),h?ue("div",{className:"se-removedAnimationList",children:B.map(p=>Ke("div",{className:"se-removedAnimationRow",children:[Ke("div",{children:[ue("div",{className:"se-removedAnimationName",children:p.displayName||p.sourceName}),ue("div",{className:"se-animationSource",children:p.sourceName})]}),ue("button",{type:"button",className:"se-animationButton",onClick:()=>O(p.sourceName),children:"Restore"})]},p.sourceName))}):null]}):null]})}import{useState as Cr}from"react";import{Eye as Ig,Pencil as Dg,Trash2 as Lg}from"lucide-react";import{jsx as le,jsxs as xe}from"react/jsx-runtime";function kr({config:e,onChange:t,cameraState:a,onPreviewView:i}){let[n,o]=Cr(null),[d,l]=Cr(""),[c,w]=Cr(""),h=P=>{o(structuredClone(P)),l(P.minDistance?.toString()??""),w(P.maxDistance?.toString()??"")},y=d.trim()===""?void 0:Number(d),u=c.trim()===""?void 0:Number(c),g=[y,u].some(P=>P!==void 0&&(!Number.isFinite(P)||P<0))?"Distances must be non-negative numbers.":y!==void 0&&u!==void 0&&y>u?"Maximum distance must be at least the minimum.":n?.images?.some(P=>P.src.trim()&&!$i(P.src))||n?.links?.some(P=>P.href.trim()&&!$i(P.href))?"Use an HTTP(S) URL or a relative path for images and links.":null,B=()=>{if(!n?.title.trim()||g)return;let P={...n,title:n.title.trim(),category:n.category?.trim()||void 0,minDistance:y,maxDistance:u,images:n.images?.filter(x=>x.src.trim()).map(x=>({...x,src:x.src.trim()})),links:n.links?.filter(x=>x.href.trim()).map(x=>({...x,href:x.href.trim(),label:x.label.trim()||"Learn more"}))};t({...e,annotations:e.annotations.map(x=>x.id===n.id?P:x)}),o(null)},v=P=>{window.confirm("Delete this annotation?")&&(t({...e,annotations:e.annotations.filter(x=>x.id!==P).map((x,C)=>({...x,id:C+1}))}),o(null))};return xe(xn,{title:"Annotations",children:[e.annotations.length===0?le("div",{className:"bb-emptyAnnotations",children:"No annotations yet. Double-click on the model to add one."}):le("div",{className:"se-annotationList",children:e.annotations.map(P=>xe("div",{className:"se-annotationRow",children:[xe("span",{className:"se-annotationNumber",children:["#",P.id]}),xe("div",{className:"se-annotationSummary",children:[xe("div",{className:"se-annotationHeading",children:[le("span",{className:"se-annotationTitle",title:P.title,children:P.title}),P.category?.trim()&&le("span",{className:"se-annotationCategory",title:P.category,children:P.category})]}),P.description&&le("p",{className:"se-annotationDescription",title:P.description,children:P.description})]}),xe("div",{className:"se-annotationActions",children:[pl(P.cameraView)&&le("button",{type:"button",className:"se-annotationAction",disabled:!i,onClick:()=>i?.(P.cameraView),title:"Preview saved view","aria-label":`Preview saved view for ${P.title}`,children:le(Ig,{size:15,"aria-hidden":"true"})}),le("button",{type:"button",className:"se-annotationAction",onClick:()=>h(P),title:"Edit annotation","aria-label":`Edit ${P.title}`,children:le(Dg,{size:15,"aria-hidden":"true"})}),le("button",{type:"button",className:"se-annotationAction se-annotationAction--delete",onClick:()=>v(P.id),title:"Delete annotation","aria-label":`Delete ${P.title}`,children:le(Lg,{size:15,"aria-hidden":"true"})})]})]},P.id))}),n&&le("div",{className:"bb-editAnnotationOverlay",onClick:()=>o(null),children:xe("div",{className:"bb-editAnnotationPopup",onKeyDown:P=>{P.key==="Escape"&&(P.stopPropagation(),o(null))},role:"dialog","aria-modal":"true","aria-labelledby":"annotation-edit-title",onClick:P=>P.stopPropagation(),children:[xe("div",{className:"bb-editAnnotationHeader",children:[le("h3",{id:"annotation-edit-title",className:"bb-editAnnotationTitle",children:"Edit annotation"}),le("button",{className:"bb-editAnnotationClose","aria-label":"Close annotation editor",onClick:()=>o(null),children:"\xD7"})]}),xe("div",{className:"bb-editAnnotationBody",children:[xe("label",{className:"bb-field",children:[le("span",{className:"bb-label",children:"Title"}),le("input",{className:"bb-input",autoFocus:!0,value:n.title,onChange:P=>o({...n,title:P.target.value})})]}),xe("label",{className:"bb-field",children:[le("span",{className:"bb-label",children:"Description"}),le("textarea",{className:"bb-textarea",rows:3,value:n.description,onChange:P=>o({...n,description:P.target.value})})]}),xe("label",{className:"bb-field",children:[le("span",{className:"bb-label",children:"Category"}),le("input",{className:"bb-input",value:n.category??"",onChange:P=>o({...n,category:P.target.value}),placeholder:"For example, Features"})]}),xe("p",{className:"se-annotationCoordinates",children:["Position: [",n.worldPosition.map(P=>P.toFixed(2)).join(", "),"]"]}),xe("fieldset",{className:"bb-annotationFields",children:[le("legend",{children:"Saved camera view"}),le("p",{children:n.cameraView?"Tours use this saved view. Clear it to restore automatic close-up zoom.":"Tours automatically zoom in on the marker. Capture a view to use custom framing."}),xe("div",{className:"bb-annotationFieldActions",children:[le("button",{className:"bb-button",disabled:!a,onClick:()=>a&&o({...n,cameraView:structuredClone(a)}),children:"Capture current view"}),le("button",{className:"bb-button",disabled:!n.cameraView||!i,onClick:()=>n.cameraView&&i?.(n.cameraView),children:"Preview"}),le("button",{className:"bb-button",disabled:!n.cameraView,onClick:()=>o({...n,cameraView:void 0}),children:"Clear view"})]})]}),xe("fieldset",{className:"bb-annotationFields",children:[le("legend",{children:"Marker distance (scene units)"}),le("p",{children:"Leave blank to show markers at any distance."}),xe("div",{className:"bb-annotationDistanceFields",children:[xe("label",{className:"bb-field",children:[le("span",{className:"bb-label",children:"Minimum distance"}),le("input",{className:"bb-input",type:"number",min:"0",step:"any",value:d,onChange:P=>l(P.target.value)})]}),xe("label",{className:"bb-field",children:[le("span",{className:"bb-label",children:"Maximum distance"}),le("input",{className:"bb-input",type:"number",min:"0",step:"any",value:c,onChange:P=>w(P.target.value)})]})]})]}),xe("fieldset",{className:"bb-annotationFields",children:[le("legend",{children:"Images"}),n.images?.map((P,x)=>xe("div",{className:"bb-annotationMediaRow",children:[xe("label",{className:"bb-field",children:[xe("span",{className:"bb-label",children:["Image URL ",x+1]}),le("input",{className:"bb-input",value:P.src,onChange:C=>o({...n,images:n.images.map((S,f)=>f===x?{...S,src:C.target.value}:S)}),placeholder:"https://example.com/image.jpg"})]}),xe("label",{className:"bb-field",children:[xe("span",{className:"bb-label",children:["Image description ",x+1]}),le("input",{className:"bb-input",value:P.alt??"",onChange:C=>o({...n,images:n.images.map((S,f)=>f===x?{...S,alt:C.target.value}:S)})})]}),xe("button",{className:"bb-button",onClick:()=>o({...n,images:n.images.filter((C,S)=>S!==x)}),children:["Remove image ",x+1]})]},x)),le("button",{className:"bb-button",onClick:()=>o({...n,images:[...n.images??[],{src:"",alt:""}]}),children:"Add image"})]}),xe("fieldset",{className:"bb-annotationFields",children:[le("legend",{children:"Links"}),n.links?.map((P,x)=>xe("div",{className:"bb-annotationMediaRow",children:[xe("label",{className:"bb-field",children:[xe("span",{className:"bb-label",children:["Link URL ",x+1]}),le("input",{className:"bb-input",value:P.href,onChange:C=>o({...n,links:n.links.map((S,f)=>f===x?{...S,href:C.target.value}:S)}),placeholder:"https://example.com/details"})]}),xe("label",{className:"bb-field",children:[xe("span",{className:"bb-label",children:["Link label ",x+1]}),le("input",{className:"bb-input",value:P.label,onChange:C=>o({...n,links:n.links.map((S,f)=>f===x?{...S,label:C.target.value}:S)})})]}),xe("button",{className:"bb-button",onClick:()=>o({...n,links:n.links.filter((C,S)=>S!==x)}),children:["Remove link ",x+1]})]},x)),le("button",{className:"bb-button",onClick:()=>o({...n,links:[...n.links??[],{href:"",label:""}]}),children:"Add link"})]}),g&&le("p",{role:"alert",children:g}),xe("div",{className:"bb-editAnnotationActions",children:[le("button",{className:"bb-button",onClick:()=>o(null),children:"Cancel"}),le("button",{className:"bb-button bb-button--primary",disabled:!n.title.trim()||!!g,onClick:B,children:"Save"}),le("button",{className:"bb-button bb-button--danger",onClick:()=>v(n.id),children:"Delete"})]})]})]})})]})}import{useState as zg,useCallback as to}from"react";import{ArrowDown as Fg,ArrowUp as Hg,MapPin as $g,Plus as Vg,Trash2 as qg,Settings as Ug}from"lucide-react";import{Fragment as Gg,jsx as je,jsxs as Qe}from"react/jsx-runtime";var Kg={enabled:!0,waypoints:[],loop:!0,autoPlay:!1},no=3.5;function Mr({config:e,onChange:t,cameraState:a,onPreviewWaypoint:i}){let n=e.cinematic??Kg,o=qa(),{waypoints:d}=n,l=to((C,S)=>{if(C.length<2)return 0;let f=0;for(let k=0;k<C.length-1;k++){let O=C[k].segmentDuration??no;f+=O}return S&&C.length>1&&(f+=C[C.length-1].segmentDuration??no),Math.max(f,0)},[]),c=to(C=>{t({...e,cinematic:{...n,...C}})},[e,n,t]),w=to(()=>{if(!a)return;let C={position:[...a.position],target:[...a.target],...a.azimuthAngle!=null?{azimuthAngle:a.azimuthAngle}:{},...a.polarAngle!=null?{polarAngle:a.polarAngle}:{},segmentDuration:no},S=[...d,C],f=l(S,n.loop);c({waypoints:S,duration:f})},[a,d,n.loop,l,c]),h=to(C=>{let S=d.filter((k,O)=>O!==C),f=l(S,n.loop);c({waypoints:S,duration:f})},[d,n.loop,l,c]),y=to((C,S)=>{let f=C+S;if(f<0||f>=d.length)return;let k=[...d];[k[C],k[f]]=[k[f],k[C]];let O=l(k,n.loop);c({waypoints:k,duration:O})},[d,n.loop,l,c]),u=to((C,S)=>{let f=d.map((O,p)=>p===C?{...O,...S}:O),k=l(f,n.loop);c({waypoints:f,duration:k})},[d,n.loop,l,c]),[g,B]=zg(!1),v=d.some(C=>C.segmentDuration!==void 0),P=to(C=>C>=d.length-1?no:d[C]?.segmentDuration??no,[d]),x=d.length>=2;return Qe(xn,{title:"Cinematic Camera",children:[je("p",{className:"se-cinematicHint",children:"Frame the model in the viewer, then capture it as a waypoint. The camera glides through the waypoints in order \u2014 enable and press play in the viewer to preview."}),Qe("button",{type:"button",className:"bb-button bb-button--primary se-cinematicAdd",onClick:w,disabled:!a,title:"Capture the current camera view as a waypoint",children:[je(Vg,{size:15}),"Add waypoint from current view"]}),Qe("div",{className:"se-customizeToggle",children:[Qe("label",{className:"se-toggleLabel",children:[je("input",{type:"checkbox",checked:g,onChange:C=>B(C.target.checked)}),je(Ug,{size:14}),je("span",{children:"Customize durations between waypoints"})]}),g&&Qe("span",{className:"se-toggleHint",children:["Set duration for each segment between waypoints: 1\u21922, 2\u21923, etc. Default: ",no,"s"]})]}),d.length===0?je("div",{className:"bb-emptyAnnotations",children:"No waypoints yet. Position the camera and add your first one."}):Qe(Gg,{children:[je("div",{className:"se-waypointList",children:d.map((C,S)=>{let f=P(S),k=S===d.length-1,O=C.segmentDuration!==void 0&&C.segmentDuration!==no;return Qe("div",{children:[Qe("div",{className:"se-waypointCard",children:[je("div",{className:"se-waypointBadge",children:S+1}),Qe("div",{className:"se-waypointBody",children:[Qe("div",{className:"se-waypointCoords",children:["pos [",C.position.map(p=>p.toFixed(1)).join(", "),"]"]}),Qe("div",{className:"se-waypointCoords",children:["look [",C.target.map(p=>p.toFixed(1)).join(", "),"]"]}),g&&!k&&Qe("div",{className:`se-customBadge ${O?"se-customBadge--custom":"se-customBadge--default"}`,children:[f.toFixed(1),"s",!O&&" (default)"]})]}),Qe("div",{className:"se-waypointActions",children:[je("button",{className:"se-waypointAction",onClick:()=>i?.(C),title:"Fly camera to this waypoint",disabled:!i,children:je($g,{size:15})}),je("button",{className:"se-waypointAction",onClick:()=>y(S,-1),title:"Move up",disabled:S===0,children:je(Hg,{size:15})}),je("button",{className:"se-waypointAction",onClick:()=>y(S,1),title:"Move down",disabled:k,children:je(Fg,{size:15})}),je("button",{className:"se-waypointAction se-waypointAction--delete",onClick:()=>h(S),title:"Delete waypoint",children:je(qg,{size:15})})]})]}),g&&!k&&Qe("div",{className:"se-segmentBetween",children:[Qe("div",{className:"se-segmentLabel",children:[S+1," \u2192 ",S+2,!C.segmentDuration&&" (default)"]}),Qe("div",{className:"se-segmentControls",children:[je("span",{className:"se-durationLabel",children:"Duration:"}),je("input",{type:"range",className:"se-segmentSlider",min:1,max:20,step:.5,value:f,onChange:p=>{let r=parseFloat(p.target.value);u(S,{segmentDuration:r})}}),Qe("span",{className:"se-segmentValue",children:[f.toFixed(1),"s"]}),Qe("div",{className:"se-presetButtons",children:[[2,4,6,8].map(p=>Qe("button",{className:"se-presetButton",onClick:()=>u(S,{segmentDuration:p}),children:[p,"s"]},`preset-${S}-${p}`)),je("button",{className:"se-presetButton se-presetButton--default",onClick:()=>{let p=d.map((M,j)=>{if(j===S){let{segmentDuration:R,...E}=M;return E}return M}),r=l(p,n.loop);c({waypoints:p,duration:r})},children:"Reset"})]})]})]})]},`waypoint-wrapper-${S}`)})}),Qe("div",{className:"se-totalDuration",children:[je("span",{className:"se-totalLabel",children:"Total duration:"}),je("span",{className:"se-totalValue",children:x?(n.duration??l(d,n.loop)).toFixed(1)+"s":"-"}),!x&&je("span",{className:"se-totalHint",children:"(need at least 2 waypoints)"})]})]}),je(Ne,{label:"Enable cinematic camera",checked:n.enabled,onChange:C=>c({enabled:C})}),je(Ne,{label:"Loop",checked:n.loop,onChange:C=>{let S=C,f=l(d,S);c({loop:S,duration:f})}}),je(Ne,{label:"Auto-play on load",checked:n.autoPlay,onChange:C=>c({autoPlay:C})}),n.autoPlay&&o?je("div",{className:"se-placeholder se-placeholder--spaced",children:"Your device is set to reduce motion, so this preview won't play on its own. Visitors without that setting will see it."}):null,!g&&x&&je(D,{label:"Duration",value:n.duration??l(d,n.loop),min:4,max:120,step:1,formatValue:C=>`${C}s`,onChange:C=>c({duration:C})})]})}import{useMemo as _g,useRef as Wg,useState as Dc}from"react";import{HexColorInput as Yg,HexColorPicker as Jg}from"react-colorful";import{ArrowDown as Xg,ArrowUp as Zg,ChevronDown as Qg,Plus as Nr,Trash2 as ef,X as Ac}from"lucide-react";var Rc=["other","body","light","wheel","glass","interior","floor","wall","door","furniture","decor","electronics","seat","table","chair","window","sofa","bed","engine","headlight"],Xa=["normal","hidden","selected","disabled"];import{Fragment as Ic,jsx as K,jsxs as Ve}from"react/jsx-runtime";var Tr={all:"All objects",group:"Group",tag:"Tag",type:"Type",object:"One object"},Oc={metric:"Metric",status:"Status",metadata:"Metadata"},tf={metric:"",stops:[[0,"#3b82f6"],[100,"#ef4444"]]};function nf(e){return e===void 0?"all":typeof e=="string"||Array.isArray(e)?"object":"group"in e?"group":"tag"in e?"tag":"type"}function ia(e){return e===void 0?"":typeof e=="string"?e:Array.isArray(e)?e[0]??"":"group"in e?e.group:"tag"in e?e.tag:e.type}function jc(e,t){if(e!=="all")return e==="object"?t:e==="group"?{group:t}:e==="tag"?{tag:t}:{type:t}}function of(e){return"metric"in e?"metric":"status"in e?"status":"metadata"}function Ec(e){return e==="metric"?{metric:""}:e==="status"?{status:["disabled"]}:{metadata:"",equals:""}}function af(e){let t=e.trim();return t==="true"?!0:t==="false"?!1:t==="null"?null:t!==""&&Number.isFinite(Number(t))?Number(t):e}function Pr(e){return e.trim()===""||!Number.isFinite(Number(e))?void 0:Number(e)}function Lc(e,t="",a=0){return typeof e!="object"||e===null||Array.isArray(e)?t?[t]:[]:a>2?t?[t]:[]:Object.entries(e).flatMap(([i,n])=>Lc(n,t?`${t}.${i}`:i,a+1))}var ra=e=>[...new Set(e.filter(t=>!!t))].sort((t,a)=>t.localeCompare(a));function nn({label:e,children:t}){return Ve("label",{className:"se-field",children:[K("span",{className:"se-fieldLabel",children:e}),t]})}function sa({label:e,checked:t,color:a,onToggle:i,onColorChange:n}){let[o,d]=Dc(!1),l=Wg(null);return Ve("div",{className:"se-field se-fieldInline",children:[Ve("label",{className:"se-ruleLook",children:[K("input",{type:"checkbox",className:"se-checkbox",checked:t,onChange:c=>i(c.target.checked)}),e]}),t&&a!==void 0&&n?K("span",{ref:l,style:{display:"inline-flex"},children:K(Yg,{prefixed:!0,className:"se-swatch","aria-label":`${e} value`,onClick:()=>d(c=>!c),style:{background:a,color:Dn(a)},color:a,onChange:n})}):null,o?K(oa,{anchorRef:l,onClose:()=>d(!1),children:K(Jg,{color:a,onChange:n})}):null]})}function rf({title:e,open:t,onToggle:a,actions:i,children:n}){return Ve("section",{className:"se-panel",children:[Ve("div",{className:"se-ruleHeader",children:[K("button",{type:"button",className:"se-panelHeader",onClick:a,"aria-expanded":t,children:Ve("span",{className:"se-panelHeaderMain",children:[K(Qg,{size:16,className:`se-panelChevron ${t?"se-panelChevron--open":""}`}),K("span",{className:"se-panelTitle",children:e})]})}),K("span",{className:"se-ruleActions",children:i})]}),t?K("div",{className:"se-panelBody",children:n}):null]})}function Br({config:e,onChange:t,objectBindings:a}){let i=e.styleRules??[],[n,o]=Dc(i[0]?.id??null),d=_g(()=>{let u=Object.values(a);return{groups:ra(u.map(g=>g.group)),tags:ra(u.flatMap(g=>g.tags??[])),types:ra(u.map(g=>g.type??"other")),objects:u.map(g=>({id:g.id,label:g.label||g.id})).sort((g,B)=>g.label.localeCompare(B.label)),metrics:ra(u.flatMap(g=>Object.keys(g.metrics??{}))),metadata:ra(u.flatMap(g=>Lc(g.metadata)))}},[a]),l=u=>t({...e,styleRules:u}),c=(u,g)=>l(i.map(B=>B.id===u?g(B):B)),w=()=>{let u=crypto.randomUUID();l([...i,{id:u,label:`Rule ${i.length+1}`,when:[{status:["disabled"]}],material:{baseColor:"#9ca3af"}}]),o(u)},h=(u,g)=>{let B=[...i],[v]=B.splice(u,1);B.splice(u+g,0,v),l(B)},y=u=>{let g=u.target?Wi(a,u.target):Object.keys(a),B=u.when?Array.isArray(u.when)?u.when:[u.when]:[];return g.filter(v=>B.every(P=>ql(a[v],P))).length};return Ve(xn,{title:"Style rules",children:[K("div",{className:"se-helperCard se-ruleIntro",children:"Restyle objects from their data while the app runs: a colour from a metric, grey when disabled, a pulse for an alarm. Set an object's metrics, status, and metadata in the Object tab to try a rule here. Later rules win over earlier ones."}),K("datalist",{id:"se-ruleMetrics",children:d.metrics.map(u=>K("option",{value:u},u))}),K("datalist",{id:"se-ruleMetadata",children:d.metadata.map(u=>K("option",{value:u},u))}),i.map((u,g)=>{let B=u.when?Array.isArray(u.when)?u.when:[u.when]:[],v=nf(u.target),P=u.material??{},x=u.pulse===!0?{}:u.pulse||void 0,C=u.target?Wi(a,u.target).length:Object.keys(a).length,S=r=>c(u.id,M=>({...M,when:r.length>0?r:void 0})),f=(r,M)=>S(B.map((j,R)=>R===r?M:j)),k=r=>c(u.id,M=>{let j={...M.material,...r};for(let R of Object.keys(j))j[R]===void 0&&delete j[R];return{...M,material:Object.keys(j).length>0?j:void 0}}),O=r=>c(u.id,M=>({...M,colorScale:r})),p=v==="group"?d.groups:v==="tag"?d.tags:v==="type"?d.types:[];return Ve(rf,{title:u.label||`Rule ${g+1}`,open:n===u.id,onToggle:()=>o(r=>r===u.id?null:u.id),actions:Ve(Ic,{children:[K("button",{type:"button",className:"se-iconButton",onClick:()=>h(g,-1),disabled:g===0,"aria-label":"Move rule up",title:"Move up",children:K(Zg,{size:14})}),K("button",{type:"button",className:"se-iconButton",onClick:()=>h(g,1),disabled:g===i.length-1,"aria-label":"Move rule down",title:"Move down",children:K(Xg,{size:14})}),K("button",{type:"button",className:"se-iconButton",onClick:()=>l(i.filter(r=>r.id!==u.id)),"aria-label":"Delete rule",title:"Delete rule",children:K(ef,{size:14})})]}),children:[K(nn,{label:"Name",children:K("input",{className:"se-textInput",value:u.label??"",placeholder:`Rule ${g+1}`,onChange:r=>c(u.id,M=>({...M,label:r.target.value}))})}),Ve("div",{className:"se-ruleGrid",children:[K(nn,{label:"Applies to",children:K("select",{className:"se-select",value:v,onChange:r=>{let M=r.target.value,j=M==="object"?d.objects[0]?.id:M==="group"?d.groups[0]:M==="tag"?d.tags[0]:M==="type"?d.types[0]:"";c(u.id,R=>({...R,target:jc(M,j??"")}))},children:Object.keys(Tr).map(r=>K("option",{value:r,children:Tr[r]},r))})}),v!=="all"?K(nn,{label:Tr[v],children:Ve("select",{className:"se-select",value:ia(u.target),onChange:r=>c(u.id,M=>({...M,target:jc(v,r.target.value)})),children:[v==="object"?d.objects.map(r=>K("option",{value:r.id,children:r.label},r.id)):p.map(r=>K("option",{value:r,children:r},r)),(v==="object"?d.objects.some(r=>r.id===ia(u.target)):p.includes(ia(u.target)))?null:K("option",{value:ia(u.target),children:ia(u.target)||"None in this model"})]})}):null]}),K("div",{className:"se-fieldLabel",children:"When"}),B.length===0?K("div",{className:"se-ruleHint",children:"Always applies."}):null,B.map((r,M)=>{let j=of(r);return Ve("div",{className:"se-ruleCondition",children:[Ve("div",{className:"se-ruleConditionHeader",children:[K("select",{className:"se-select","aria-label":"Condition type",value:j,onChange:R=>f(M,Ec(R.target.value)),children:Object.keys(Oc).map(R=>K("option",{value:R,children:Oc[R]},R))}),K("button",{type:"button",className:"se-iconButton","aria-label":"Remove condition",title:"Remove condition",onClick:()=>S(B.filter((R,E)=>E!==M)),children:K(Ac,{size:14})})]}),"metric"in r?Ve("div",{className:"se-ruleGrid se-ruleGrid--three",children:[K(nn,{label:"Metric",children:K("input",{className:"se-textInput",list:"se-ruleMetrics",value:r.metric,placeholder:"temperature",onChange:R=>f(M,{...r,metric:R.target.value})})}),K(nn,{label:"Above",children:K("input",{className:"se-numberInput",type:"number",value:r.above??"",placeholder:"any",onChange:R=>f(M,{...r,above:Pr(R.target.value)})})}),K(nn,{label:"Below",children:K("input",{className:"se-numberInput",type:"number",value:r.below??"",placeholder:"any",onChange:R=>f(M,{...r,below:Pr(R.target.value)})})})]}):"status"in r?K("div",{className:"se-ruleStatuses",children:Xa.map(R=>{let E=[].concat(r.status).includes(R);return Ve("label",{className:"se-ruleStatus",children:[K("input",{type:"checkbox",className:"se-checkbox",checked:E,onChange:()=>{let z=[].concat(r.status),pe=E?z.filter(Ce=>Ce!==R):[...z,R];f(M,{status:pe})}}),R]},R)})}):Ve("div",{className:"se-ruleGrid",children:[K(nn,{label:"Key",children:K("input",{className:"se-textInput",list:"se-ruleMetadata",value:r.metadata,placeholder:"alarm.state",onChange:R=>f(M,{...r,metadata:R.target.value})})}),K(nn,{label:"Equals",children:K("input",{className:"se-textInput",value:r.equals===null?"null":String(r.equals),placeholder:"fault",onChange:R=>f(M,{...r,equals:af(R.target.value)})})})]})]},M)}),Ve("button",{type:"button",className:"se-animationButton",onClick:()=>S([...B,Ec("metric")]),children:[K(Nr,{size:14})," Add condition"]}),K("div",{className:"se-fieldLabel",children:"Look"}),K(sa,{label:"Colour",checked:P.baseColor!==void 0,color:P.baseColor,onToggle:r=>k({baseColor:r?"#9ca3af":void 0}),onColorChange:r=>k({baseColor:r})}),K(sa,{label:"Opacity",checked:P.opacity!==void 0,onToggle:r=>k({opacity:r?.4:void 0})}),P.opacity!==void 0?K(D,{label:"Opacity",value:P.opacity,min:0,max:1,step:.05,formatValue:r=>`${Math.round(r*100)}%`,onChange:r=>k({opacity:r})}):null,K(sa,{label:"Glow",checked:P.emissive!==void 0,color:P.emissive,onToggle:r=>k({emissive:r?"#ff3b30":void 0,emissiveIntensity:r?P.emissiveIntensity??1:void 0}),onColorChange:r=>k({emissive:r})}),K(sa,{label:"Colour from a metric",checked:u.colorScale!==void 0,onToggle:r=>O(r?{...tf,metric:d.metrics[0]??""}:void 0)}),u.colorScale?Ve("div",{className:"se-ruleCondition",children:[Ve("div",{className:"se-ruleGrid",children:[K(nn,{label:"Metric",children:K("input",{className:"se-textInput",list:"se-ruleMetrics",value:u.colorScale.metric,placeholder:"temperature",onChange:r=>O({...u.colorScale,metric:r.target.value})})}),K(nn,{label:"Sets",children:Ve("select",{className:"se-select",value:u.colorScale.channel??"baseColor",onChange:r=>O({...u.colorScale,channel:r.target.value}),children:[K("option",{value:"baseColor",children:"Colour"}),K("option",{value:"emissive",children:"Glow colour"})]})})]}),u.colorScale.stops.map(([r,M],j)=>{let R=E=>O({...u.colorScale,stops:u.colorScale.stops.map((z,pe)=>pe===j?E:z)});return Ve("div",{className:"se-ruleStop",children:[K("input",{className:"se-numberInput",type:"number","aria-label":"Stop value",value:r,onChange:E=>R([Pr(E.target.value)??0,M])}),K(Nt,{label:`At ${r}`,value:M,onChange:E=>R([r,E])}),K("button",{type:"button",className:"se-iconButton","aria-label":"Remove stop",title:"Remove stop",disabled:u.colorScale.stops.length<=1,onClick:()=>O({...u.colorScale,stops:u.colorScale.stops.filter((E,z)=>z!==j)}),children:K(Ac,{size:14})})]},j)}),Ve("button",{type:"button",className:"se-animationButton",onClick:()=>{let r=u.colorScale.stops,M=r[r.length-1];O({...u.colorScale,stops:[...r,[(M?.[0]??0)+10,M?.[1]??"#ffffff"]]})},children:[K(Nr,{size:14})," Add stop"]})]}):null,K(sa,{label:"Pulse",checked:x!==void 0,color:x?.color??"#ff3b30",onToggle:r=>c(u.id,M=>({...M,pulse:r?{color:"#ff3b30",speed:1}:void 0})),onColorChange:r=>c(u.id,M=>({...M,pulse:{...x,color:r}}))}),x?K(Ic,{children:K(D,{label:"Pulses per second",value:x.speed??1,min:.2,max:4,step:.1,formatValue:r=>r.toFixed(1),onChange:r=>c(u.id,M=>({...M,pulse:{...x,speed:r}}))})}):null,Ve("div",{className:"se-ruleHint se-ruleMatches",children:["Matches ",y(u)," of ",C," ",C===1?"object":"objects"," right now."]})]},u.id)}),Ve("button",{type:"button",className:"se-animationButton",onClick:w,children:[K(Nr,{size:14})," Add rule"]})]})}import{Box as cf,Clapperboard as pf,ListVideo as bf,MessageSquareText as uf,Palette as mf,Sparkles as gf,Spotlight as ff,Video as hf}from"lucide-react";import{jsx as We,jsxs as Sf}from"react/jsx-runtime";var xf=[{label:"General",icon:We(cf,{})},{label:"Assets",icon:We(sf,{})},{label:"Lighting",icon:We(ff,{})},{label:"Animations",icon:We(pf,{})},{label:"Sequences",icon:We(bf,{})},{label:"Post Processing",icon:We(gf,{})},{label:"Annotations",icon:We(uf,{})},{label:"Cinematic",icon:We(hf,{})},{label:"Rules",icon:We(mf,{})}],zc={active:[],play:()=>{},pause:()=>{},stop:()=>{},setSpeed:()=>{},seek:()=>{}},yf=[],vf={};function Rr({assets:e,sequenceControls:t=null,sequenceClipDetails:a=[],diagnostics:i,onDiagnosticsOpenChange:n,config:o,onChange:d,activeSubTab:l,onActiveSubTabChange:c,cameraState:w=null,onPreviewWaypoint:h,animationClipDetails:y=[],animationConfig:u,onAnimationConfigChange:g,materialVariantGroups:B=yf,onImageFile:v,objectBindings:P=vf,animationPlayback:x=zc}){let[C,S]=lf("General"),f=l??C,k=x??zc,{tier:O}=lt();df(()=>{l!==void 0&&S(l)},[l]);let p=r=>{l===void 0&&S(r),c?.(r)};return Sf("div",{className:"se-tabContent",children:[We("div",{className:"se-subTabRow",children:xf.filter(r=>r.label!=="Assets"||e).map(r=>We("button",{type:"button",title:r.label,"aria-label":r.label,"aria-pressed":f===r.label,className:`se-subTab ${f===r.label?"se-subTab--active":""}`,onClick:()=>p(r.label),children:r.icon},r.label))}),f==="General"&&We(xr,{diagnostics:i,onDiagnosticsOpenChange:n,config:o,onChange:d,materialVariantGroups:B,onImageFile:v}),f==="Assets"&&e&&We(fr,{...e}),f==="Lighting"&&We(Sr,{config:o,onChange:d}),f==="Animations"&&We(wr,{config:u?{...o,animations:u}:o,onChange:g?r=>g(r.animations):d,clipDetails:y,active:k.active,play:k.play,pause:k.pause,stop:k.stop,setSpeed:k.setSpeed,seek:k.seek}),f==="Sequences"&&We(ur,{config:o,onChange:d,controls:t,bindings:P,clipDetails:a}),f==="Post Processing"&&We(vr,{config:o,onChange:d}),f==="Annotations"&&We(kr,{config:o,onChange:d,cameraState:w,onPreviewView:h}),f==="Cinematic"&&(ut(O,"cinematic")?We(Mr,{config:o,onChange:d,cameraState:w,onPreviewWaypoint:h}):We(_e,{requiredTier:"starter",feature:"Cinematic camera"})),f==="Rules"&&(ut(O,"rules")?We(Br,{config:o,onChange:d,objectBindings:P}):We(_e,{requiredTier:"growth",feature:"Style rules"}))]})}import{ChevronDown as Fc,Info as Hc}from"lucide-react";import{jsx as ht,jsxs as oo}from"react/jsx-runtime";function $c({title:e,trailing:t,children:a,disabled:i,open:n,onToggle:o,tooltip:d}){let l=d?`${d}`:e;return oo("div",{className:"bb-materialPanel",children:[oo("button",{type:"button",className:"bb-materialPanelHeader",onClick:o,"aria-expanded":n,title:l,children:[oo("div",{className:"bb-materialPanelTitleWrap",children:[ht(Fc,{size:14,className:`bb-materialPanelChevron ${n?"bb-materialPanelChevron--open":""}`}),ht("span",{className:"bb-materialPanelTitle",children:e}),d?ht("span",{className:"bb-materialPanelHelp",title:l,"aria-label":l,role:"img",onClick:c=>c.stopPropagation(),children:ht(Hc,{size:12})}):null]}),t?ht("div",{onClick:c=>c.stopPropagation(),children:t}):null]}),n?ht("div",{className:"bb-materialPanelBody",style:i?{opacity:.45,pointerEvents:"none"}:void 0,children:a}):null]})}function ot({title:e,open:t,onToggle:a,trailing:i,children:n,tooltip:o}){let d=o?`${e}: ${o}`:e;return oo("div",{className:"bb-section",children:[oo("div",{className:"bb-sectionHeaderRow",children:[ht("button",{type:"button",className:"bb-sectionHeaderButton",onClick:a,"aria-expanded":t,title:d,children:oo("span",{className:"bb-sectionHeaderMain",children:[ht(Fc,{size:15,className:`bb-sectionChevron ${t?"bb-sectionChevron--open":""}`}),ht("h2",{className:"bb-sectionTitle",children:e}),o?ht("span",{className:"bb-sectionHelp",title:d,"aria-label":d,role:"img",onClick:l=>l.stopPropagation(),children:ht(Hc,{size:13})}):null]})}),i?ht("span",{className:"bb-sectionHeaderTrailing",children:i}):null]}),t?ht("div",{className:"bb-sectionBody",children:n}):null]})}function Vc({checked:e,onChange:t,label:a}){return oo("label",{className:"se-switch","aria-label":a,children:[ht("input",{type:"checkbox",checked:e,onChange:i=>t(i.target.checked)}),ht("span",{className:"se-switchTrack",children:ht("span",{className:"se-switchThumb"})})]})}import{useState as Kc}from"react";import{Trash2 as Af}from"lucide-react";import{jsx as Ar}from"react/jsx-runtime";function At({panelKey:e,title:t,tooltip:a,toggleLabel:i,controls:n,children:o,requiredTier:d}){let{openMaterialPanels:l,materialPanelEnabled:c,onToggleMaterialPanel:w,onSetMaterialPanelState:h}=n,y=d?.locked??!1;return Ar($c,{title:t,tooltip:a,disabled:y||!c[e],open:l[e],onToggle:()=>w(e),trailing:Ar(Vc,{checked:!y&&c[e],onChange:y?()=>{}:u=>h(e,u),label:i??`Toggle ${t}`}),children:y&&d?Ar(_e,{requiredTier:d.tier,feature:t}):o})}import{createContext as wf,useContext as Cf,useRef as qc,useState as kf}from"react";import{HexColorInput as Mf,HexColorPicker as Nf}from"react-colorful";import{FileUp as Tf,Minus as Pf,Plus as Bf}from"lucide-react";import{jsx as Ee,jsxs as on}from"react/jsx-runtime";var Or=wf(null);function et({label:e,value:t,placeholder:a,onChange:i}){let n=qc(null),o=Cf(Or);return on("div",{className:"bb-field bb-field--full",children:[Ee("label",{className:"bb-label",children:e}),on("div",{className:"bb-fileField",title:o??void 0,children:[Ee("input",{className:"bb-input bb-fileField-input",placeholder:a,value:t,disabled:!!o&&!t,onChange:d=>{let l=d.target.value;!l&&t&&Wo(t),i(l)}}),Ee("button",{type:"button",className:"bb-fileFieldButton",disabled:!!o,onClick:()=>n.current?.click(),"aria-label":`Select file for ${e}`,title:`Select file for ${e}`,children:Ee(Tf,{size:20})}),Ee("input",{ref:n,type:"file",accept:"image/png,image/jpeg,image/webp,image/avif",className:"bb-hiddenInput",onChange:d=>{let l=d.target.files?.[0];if(!l)return;let c=vo(l);t&&t!==c&&Wo(t),Yt(c,URL.createObjectURL(l)),i(c),d.target.value=""}})]})]})}function zn({label:e,value:t,fallback:a="#ffffff",variant:i="swatch",onChange:n}){let[o,d]=kf(!1),l=t||a,c=qc(null);return on("div",{className:"bb-field",children:[Ee("span",{className:"bb-label",children:e}),Ee("div",{className:"se-fieldInline",children:Ee("span",{ref:c,className:i==="input"?"bb-colorFieldAnchor":void 0,style:i==="swatch"?{display:"inline-flex"}:void 0,children:Ee(Mf,{prefixed:!0,className:i==="input"?"bb-input bb-colorInput":"se-swatch","aria-label":e,onClick:()=>d(w=>!w),style:{background:l,color:Dn(l)},color:l,onChange:n})})}),o?Ee(oa,{anchorRef:c,onClose:()=>d(!1),children:Ee(Nf,{color:l,onChange:n})}):null]})}function la({label:e,checked:t,onChange:a}){return on("label",{className:"bb-checkbox",children:[Ee("input",{type:"checkbox",checked:t,onChange:i=>a(i.target.checked)}),e]})}function Uc({label:e,value:t,min:a,max:i,step:n,placeholder:o,disabled:d,onChange:l}){return on("div",{className:"bb-field",children:[Ee("label",{className:"bb-label",children:e}),Ee("input",{className:"bb-input",type:"number",min:a,max:i,step:n,placeholder:o,disabled:d,value:t??"",onChange:c=>l(c.target.value===""?void 0:Number(c.target.value))})]})}function Rf(e,t){let a=t<1?Math.ceil(-Math.log10(t)):0,i=10**Math.max(a,0);return Math.round(e*i)/i}function jr({label:e,value:t,min:a,max:i,step:n=.01,disabled:o,onChange:d}){let l=t??0,c=h=>{let y=h;return a!==void 0&&(y=Math.max(a,y)),i!==void 0&&(y=Math.min(i,y)),y},w=h=>{d(c(Rf(l+h*n,n)))};return on("div",{className:"bb-field",children:[Ee("label",{className:"bb-label",children:e}),on("div",{className:"bb-numberStepper",children:[Ee("button",{type:"button",className:"bb-numberStepper-btn",disabled:o,onClick:()=>w(-1),"aria-label":`Decrease ${e}`,title:`Decrease ${e}`,children:Ee(Pf,{size:12})}),Ee("input",{className:"bb-input bb-numberStepper-input",type:"number",min:a,max:i,step:n,disabled:o,value:l,onChange:h=>{h.target.value!==""&&d(c(Number(h.target.value)))}}),Ee("button",{type:"button",className:"bb-numberStepper-btn",disabled:o,onClick:()=>w(1),"aria-label":`Increase ${e}`,title:`Increase ${e}`,children:Ee(Bf,{size:12})})]})]})}function Po({label:e,value:t,options:a,onChange:i}){return on("div",{className:"bb-field",children:[Ee("label",{className:"bb-label",children:e}),Ee("select",{className:"bb-select",value:t,onChange:n=>i(n.target.value),children:a.map(n=>Ee("option",{value:n,children:n},n))})]})}function Re({label:e,value:t,min:a,max:i,step:n,onChange:o}){return on("div",{className:"bb-field bb-field--full",children:[Ee("label",{className:"bb-label",children:e}),on("div",{className:"bb-sliderField",children:[Ee("input",{className:`bb-slider ${t===void 0?"bb-slider--unset":""}`,type:"range",min:a,max:i,step:n,value:t??a,onChange:l=>o(Number(l.target.value))}),Ee("input",{className:"bb-input bb-input--compact",type:"number",min:a,max:i,step:n,value:t??"",onChange:l=>o(l.target.value===""?void 0:Number(l.target.value))})]})]})}import{Fragment as _c,jsx as H,jsxs as Ye}from"react/jsx-runtime";var Gc="This object has no texture coordinates (UVs), so image maps can't be placed on it. Colors and the other settings work, and Decals can put an image on it.";function Wc({selectedItem:e,selectedMaterial:t,pbrWorkflow:a,onPbrWorkflowChange:i,openMaterialPanels:n,materialPanelEnabled:o,onToggleMaterialPanel:d,onSetMaterialPanelState:l,updateSelectedMaterial:c,setSelectedTexturePath:w,isTexturePositioningEnabled:h,onConfirmTexturePosition:y,takesImage:u=!0}){let g={openMaterialPanels:n,materialPanelEnabled:o,onToggleMaterialPanel:d,onSetMaterialPanelState:l},{tier:B}=lt(),v={tier:"starter",locked:!ut(B,"advancedMaterials")},[P,x]=Kc("roughness"),[C,S]=Kc("factor"),f=(p,r)=>{c(e,M=>{if(!M?.texture?.path)return M??{};let j=M.texture.offset??[0,0],R=[j[0],j[1]];return R[p]=r,{...M,texture:{...M.texture,offset:R}}})},k=p=>{c(e,r=>{if(!r?.texture?.path)return r??{};let M=(p%360+360)%360;return{...r,texture:{...r.texture,rotation:M*Math.PI/180}}})},O=()=>{w(e,"texture","")};return Ye(Or.Provider,{value:u?null:Gc,children:[u?null:H("p",{className:"bb-note bb-materialNotice",children:Gc}),H(At,{panelKey:"pbr",title:"PBR Maps",tooltip:"Controls the base color and workflow used for physically based shading.",controls:g,children:Ye("div",{className:"bb-grid",children:[H(Po,{label:"Workflow",value:a,options:["metalness","specular"],onChange:i}),H("div",{className:"bb-field bb-field--full",children:H("p",{className:"bb-note",style:{margin:0},children:a==="metalness"?"Metalness workflow maps directly to the underlying physical material.":"Specular workflow exposes the same physical material with non-metal specular controls; it does not switch to a separate spec/gloss shader."})}),H(et,{label:a==="specular"?"Albedo texture path":"Base color texture path",placeholder:"materials/oak-wood.jpg",value:t?.texture?.path??"",onChange:p=>w(e,"texture",p)}),t?.texture?.path?Ye("div",{className:"bb-field bb-field--full",children:[Ye("div",{className:"bb-fieldLabel",style:{display:"flex",alignItems:"center",justifyContent:"space-between"},children:[H("span",{className:"bb-label",children:"Texture position"}),Ye("button",{type:"button",className:"bb-button bb-button--ghost",onClick:O,title:"Remove the base color texture and its position offset",children:[H(Af,{size:14,style:{marginRight:4,verticalAlign:"-2px"}}),"Remove texture"]})]}),Ye("div",{className:"bb-grid",style:{marginTop:6},children:[H(jr,{label:"Offset X",value:t?.texture?.offset?.[0]??0,step:.01,onChange:p=>f(0,p)}),H(jr,{label:"Offset Y",value:t?.texture?.offset?.[1]??0,step:.01,onChange:p=>f(1,p)})]}),H(Re,{label:"Rotation",value:((t?.texture?.rotation??0)*180/Math.PI%360+360)%360,min:0,max:360,step:1,onChange:p=>k(p??0)}),h?H("button",{type:"button",className:"bb-button bb-button--primary",style:{marginTop:8},onClick:y,title:"Confirm this texture position and exit positioning mode",children:"Done positioning"}):H("p",{className:"bb-note",style:{margin:"6px 0 0"},children:"Double-click the object in the preview to drag its texture directly (scroll to zoom), or edit its offset numerically once positioning."})]}):null,H(zn,{label:a==="specular"?"Albedo color":"Base color",value:t?.baseColor??"#ffffff",onChange:p=>c(e,r=>({...r,baseColor:p}))}),a==="metalness"?Ye(_c,{children:[H(Re,{label:"Metalness",value:t?.metalness,min:0,max:1,step:.01,onChange:p=>c(e,r=>({...r,metalness:p}))}),H(et,{label:"Metalness map path",placeholder:"materials/body-metalness.jpg",value:t?.metalnessMap?.path??"",onChange:p=>w(e,"metalnessMap",p)})]}):Ye(_c,{children:[H(Re,{label:"Specular intensity",value:t?.specularIntensity,min:0,max:1,step:.01,onChange:p=>c(e,r=>({...r,specularIntensity:p}))}),H(zn,{label:"Specular color",value:t?.specularColor??"#ffffff",onChange:p=>c(e,r=>({...r,specularColor:p}))}),H(et,{label:"Specular intensity map path",placeholder:"materials/body-specular-intensity.jpg",value:t?.specularIntensityMap?.path??"",onChange:p=>w(e,"specularIntensityMap",p)}),H(et,{label:"Specular color map path",placeholder:"materials/body-specular-color.jpg",value:t?.specularColorMap?.path??"",onChange:p=>w(e,"specularColorMap",p)})]}),H(Re,{label:"Specular F0 / reflectivity",value:t?.reflectivity,min:0,max:1,step:.01,onChange:p=>c(e,r=>({...r,reflectivity:p}))})]})}),H(At,{panelKey:"roughness",title:"Roughness / Glossiness",tooltip:"Adjusts how matte or shiny the surface appears.",toggleLabel:"Toggle Roughness and Glossiness",controls:g,children:Ye("div",{className:"bb-grid",children:[H(Po,{label:"Mode",value:P,options:["roughness","glossiness"],onChange:x}),H("div",{className:"bb-field bb-field--full",children:H("p",{className:"bb-note",style:{margin:0},children:P==="roughness"?"Roughness: 0 is glossy, 1 is matte.":"Glossiness is the inverse of roughness (glossiness = 1 \u2212 roughness)"})}),P==="roughness"?H(Re,{label:"Roughness",value:t?.roughness,min:0,max:1,step:.01,onChange:p=>c(e,r=>({...r,roughness:p}))}):H(Re,{label:"Glossiness",value:t?.roughness===void 0?void 0:1-t.roughness,min:0,max:1,step:.01,onChange:p=>c(e,r=>({...r,roughness:p===void 0?void 0:1-p}))}),H(et,{label:P==="glossiness"?"Glossiness map path (applied as roughness)":"Roughness map path",placeholder:"materials/body-roughness.jpg",value:t?.roughnessMap?.path??"",onChange:p=>w(e,"roughnessMap",p)})]})}),H(At,{panelKey:"emission",title:"Emission",tooltip:"Makes the material self-illuminated with emissive color and intensity.",controls:g,children:Ye("div",{className:"bb-grid",children:[H(zn,{label:"Emissive color",value:t?.emissive??"#000000",fallback:"#000000",onChange:p=>c(e,r=>({...r,emissive:p}))}),H(Re,{label:"Emissive intensity",value:t?.emissiveIntensity,min:0,max:10,step:.1,onChange:p=>c(e,r=>({...r,emissiveIntensity:p}))}),H(et,{label:"Emissive map path",placeholder:"materials/body-emissive.jpg",value:t?.emissiveMap?.path??"",onChange:p=>w(e,"emissiveMap",p)})]})}),H(At,{panelKey:"opacity",title:"Opacity",tooltip:"Controls transparency, alpha testing, and blending behavior.",controls:g,children:Ye("div",{className:"bb-grid",children:[H(Re,{label:"Opacity",value:t?.opacity,min:0,max:1,step:.01,onChange:p=>c(e,r=>({...r,opacity:p}))}),H(Re,{label:"Alpha test",value:t?.alphaTest,min:0,max:1,step:.01,onChange:p=>c(e,r=>({...r,alphaTest:p}))}),H(et,{label:"Alpha map path",placeholder:"materials/body-alpha.png",value:t?.alphaMap?.path??"",onChange:p=>w(e,"alphaMap",p)}),H(Po,{label:"Blending mode",value:t?.blendingMode??"normal",options:rd,onChange:p=>c(e,r=>({...r,blendingMode:p}))}),Ye("div",{className:"bb-field",children:[H("label",{className:"bb-label",children:"Alpha hash"}),H("div",{className:"bb-checkboxRow",children:H(la,{label:"Use alpha hash",checked:t?.alphaHash??!1,onChange:p=>c(e,r=>({...r,alphaHash:p}))})})]}),Ye("div",{className:"bb-field",children:[H("label",{className:"bb-label",children:"Dithering"}),H("div",{className:"bb-checkboxRow",children:H(la,{label:"Use dithering",checked:t?.dithering??!1,onChange:p=>c(e,r=>({...r,dithering:p}))})})]})]})}),Ye(At,{panelKey:"normalBump",title:"Normal & Bump",tooltip:"Adds surface detail without changing the actual mesh shape.",toggleLabel:"Toggle Normal and Bump",controls:g,children:[Ye("div",{className:"bb-grid",children:[H(et,{label:"Normal map path",placeholder:"materials/body-normal.jpg",value:t?.normalMap?.path??"",onChange:p=>w(e,"normalMap",p)}),H(Re,{label:"Normal scale",value:t?.normalScale,min:0,max:5,step:.01,onChange:p=>c(e,r=>({...r,normalScale:p}))}),H(et,{label:"Bump map path",placeholder:"materials/body-bump.jpg",value:t?.bumpMap?.path??"",onChange:p=>w(e,"bumpMap",p)}),H(Re,{label:"Bump scale",value:t?.bumpScale,min:0,max:5,step:.01,onChange:p=>c(e,r=>({...r,bumpScale:p}))})]}),H("div",{className:"bb-checkboxRow",style:{marginTop:12},children:H(la,{label:"Flip normal Y",checked:t?.flipNormalY??!1,onChange:p=>c(e,r=>({...r,flipNormalY:p}))})})]}),H(At,{panelKey:"displacement",requiredTier:v,title:"Displacement",tooltip:"Offsets geometry using a texture to create real surface height.",controls:g,children:Ye("div",{className:"bb-grid",children:[H(et,{label:"Displacement map path",placeholder:"materials/body-displacement.jpg",value:t?.displacementMap?.path??"",onChange:p=>w(e,"displacementMap",p)}),H(Re,{label:"Displacement scale",value:t?.displacementScale,min:-5,max:5,step:.01,onChange:p=>c(e,r=>({...r,displacementScale:p}))}),H(Re,{label:"Displacement bias",value:t?.displacementBias,min:-5,max:5,step:.01,onChange:p=>c(e,r=>({...r,displacementBias:p}))})]})}),H(At,{panelKey:"ao",title:"Ambient Occlusion",tooltip:"Darkens creases and contact areas to add depth.",controls:g,children:Ye("div",{className:"bb-grid",children:[H(et,{label:"AO map path",placeholder:"materials/body-ao.jpg",value:t?.aoMap?.path??"",onChange:p=>w(e,"aoMap",p)}),H(Re,{label:"AO intensity",value:t?.aoMapIntensity,min:0,max:5,step:.01,onChange:p=>c(e,r=>({...r,aoMapIntensity:p}))})]})}),Ye(At,{panelKey:"clearcoat",requiredTier:v,title:"Clearcoat",tooltip:"Adds a glossy protective layer on top of the base material.",controls:g,children:[Ye("div",{className:"bb-grid",children:[H(et,{label:"Clearcoat map path",placeholder:"materials/body-clearcoat.jpg",value:t?.clearcoatMap?.path??"",onChange:p=>w(e,"clearcoatMap",p)}),H(Re,{label:"Clearcoat",value:t?.clearcoat,min:0,max:1,step:.01,onChange:p=>c(e,r=>({...r,clearcoat:p}))}),H(et,{label:"Clearcoat roughness map path",placeholder:"materials/body-clearcoat-roughness.jpg",value:t?.clearcoatRoughnessMap?.path??"",onChange:p=>w(e,"clearcoatRoughnessMap",p)}),H(Re,{label:"Clearcoat roughness",value:t?.clearcoatRoughness,min:0,max:1,step:.01,onChange:p=>c(e,r=>({...r,clearcoatRoughness:p}))}),H(et,{label:"Clearcoat normal map path",placeholder:"materials/body-clearcoat-normal.jpg",value:t?.clearcoatNormalMap?.path??"",onChange:p=>w(e,"clearcoatNormalMap",p)}),H(Re,{label:"Clearcoat normal scale",value:t?.clearcoatNormalScale,min:0,max:5,step:.01,onChange:p=>c(e,r=>({...r,clearcoatNormalScale:p}))})]}),H("div",{className:"bb-checkboxRow",style:{marginTop:12},children:H(la,{label:"Flip clearcoat normal Y",checked:t?.flipClearcoatNormalY??!1,onChange:p=>c(e,r=>({...r,flipClearcoatNormalY:p}))})})]}),H(At,{panelKey:"sheen",requiredTier:v,title:"Sheen",tooltip:"Adds a soft fabric-like sheen on grazing angles.",controls:g,children:Ye("div",{className:"bb-grid",children:[H(Re,{label:"Sheen",value:t?.sheen,min:0,max:1,step:.01,onChange:p=>c(e,r=>({...r,sheen:p}))}),H(zn,{label:"Sheen color",value:t?.sheenColor??"#ffffff",onChange:p=>c(e,r=>({...r,sheenColor:p}))}),H(et,{label:"Sheen color map path",placeholder:"materials/body-sheen-color.jpg",value:t?.sheenColorMap?.path??"",onChange:p=>w(e,"sheenColorMap",p)}),H(Re,{label:"Sheen roughness",value:t?.sheenRoughness,min:0,max:1,step:.01,onChange:p=>c(e,r=>({...r,sheenRoughness:p}))}),H(et,{label:"Sheen roughness map path",placeholder:"materials/body-sheen-roughness.jpg",value:t?.sheenRoughnessMap?.path??"",onChange:p=>w(e,"sheenRoughnessMap",p)})]})}),H(At,{panelKey:"anisotropy",requiredTier:v,title:"Anisotropy",tooltip:"Stretches reflections in one direction for brushed or fiber-like surfaces.",controls:g,children:Ye("div",{className:"bb-grid",children:[H(Re,{label:"Intensity",value:t?.anisotropy,min:0,max:1,step:.01,onChange:p=>c(e,r=>({...r,anisotropy:p}))}),H(Po,{label:"Tilt direction",value:C,options:["factor","texture"],onChange:S}),C==="factor"?H(Re,{label:"Rotation (rad)",value:t?.anisotropyRotation,min:0,max:6.28,step:.01,onChange:p=>c(e,r=>({...r,anisotropyRotation:p}))}):H(et,{label:"Anisotropy map path",placeholder:"materials/body-anisotropy.jpg",value:t?.anisotropyMap?.path??"",onChange:p=>w(e,"anisotropyMap",p)})]})}),H(At,{panelKey:"transmission",requiredTier:v,title:"Transmission & Volume",tooltip:"Controls glass-like transmission and how light travels through volume.",toggleLabel:"Toggle Transmission and Volume",controls:g,children:Ye("div",{className:"bb-grid",children:[H(Re,{label:"Transmission",value:t?.transmission,min:0,max:1,step:.01,onChange:p=>c(e,r=>({...r,transmission:p}))}),H(et,{label:"Transmission map path",placeholder:"materials/body-transmission.jpg",value:t?.transmissionMap?.path??"",onChange:p=>w(e,"transmissionMap",p)}),H(Re,{label:"Thickness",value:t?.thickness,min:0,max:5,step:.01,onChange:p=>c(e,r=>({...r,thickness:p}))}),H(et,{label:"Thickness map path",placeholder:"materials/body-thickness.jpg",value:t?.thicknessMap?.path??"",onChange:p=>w(e,"thicknessMap",p)}),H(zn,{label:"Volume tint",value:t?.attenuationColor??"#ffffff",onChange:p=>c(e,r=>({...r,attenuationColor:p}))}),H(Uc,{label:"Attenuation distance",value:t?.attenuationDistance,min:0,step:.01,placeholder:"Infinity when unset",onChange:p=>c(e,r=>({...r,attenuationDistance:p}))})]})}),H(At,{panelKey:"faces",title:"Faces Rendering",tooltip:"Chooses which side of the mesh renders and how backfaces are handled.",controls:g,children:H("div",{className:"bb-grid",children:H(Po,{label:"Side",value:t?.side??"front",options:id,onChange:p=>c(e,r=>({...r,side:p}))})})})]})}import{Ban as Ef}from"lucide-react";var Za="default",Er=[{id:Za,label:"Default",swatch:"transparent",material:{}},{id:"wood",label:"Wood",swatch:"#8b5a2b",material:{baseColor:"#8b5a2b",metalness:0,roughness:.75,reflectivity:.04}},{id:"brushed-metal",label:"Brushed Metal",swatch:"linear-gradient(135deg, #cfcfcf, #8a8a8a)",material:{baseColor:"#c8c8c8",metalness:1,roughness:.35}},{id:"chrome",label:"Polished Chrome",swatch:"linear-gradient(135deg, #ffffff, #9aa0a6)",material:{baseColor:"#e8e8e8",metalness:1,roughness:.05}},{id:"gold",label:"Gold",swatch:"linear-gradient(135deg, #ffe9a8, #c89b2c)",material:{baseColor:"#e6b325",metalness:1,roughness:.2}},{id:"copper",label:"Copper",swatch:"linear-gradient(135deg, #e3a576, #8a4a26)",material:{baseColor:"#b87333",metalness:1,roughness:.3}},{id:"glass",label:"Glass",swatch:"linear-gradient(135deg, rgba(255,255,255,0.9), rgba(180,210,230,0.4))",material:{baseColor:"#ffffff",metalness:0,roughness:.02,reflectivity:.5,opacity:1,transmission:1,thickness:.5,attenuationColor:"#ffffff",attenuationDistance:1}},{id:"frosted-glass",label:"Frosted Glass",swatch:"linear-gradient(135deg, rgba(255,255,255,0.85), rgba(210,225,235,0.6))",material:{baseColor:"#ffffff",metalness:0,roughness:.4,reflectivity:.3,opacity:1,transmission:.9,thickness:.5}},{id:"plastic-glossy",label:"Glossy Plastic",swatch:"#dadada",material:{baseColor:"#dadada",metalness:0,roughness:.25,reflectivity:.5,clearcoat:.3,clearcoatRoughness:.1}},{id:"plastic-matte",label:"Matte Plastic",swatch:"#9a9a9a",material:{baseColor:"#9a9a9a",metalness:0,roughness:.85,reflectivity:.04}},{id:"rubber",label:"Rubber",swatch:"#1a1a1a",material:{baseColor:"#1a1a1a",metalness:0,roughness:.9,reflectivity:.02}},{id:"fabric",label:"Fabric",swatch:"#9c8a6b",material:{baseColor:"#9c8a6b",metalness:0,roughness:.95,sheen:.4,sheenColor:"#ffffff",sheenRoughness:.6}},{id:"ceramic",label:"Ceramic",swatch:"#f5f5f0",material:{baseColor:"#f5f5f0",metalness:0,roughness:.15,clearcoat:.6,clearcoatRoughness:.1}},{id:"concrete",label:"Concrete",swatch:"#9b9b93",material:{baseColor:"#9b9b93",metalness:0,roughness:.95,reflectivity:.03}}],Of=Array.from(new Set(Er.flatMap(e=>Object.keys(e.material)))),jf=Object.fromEntries(Of.map(e=>[e,void 0]));function Yc(e){return e.id===Za?jf:e.material}import{jsx as Qa,jsxs as If}from"react/jsx-runtime";function Jc({disabled:e,onApply:t}){return Qa("div",{className:"bb-presetGallery",children:Er.map(a=>If("button",{type:"button",className:"bb-presetSwatch",disabled:e,title:`Apply ${a.label} preset`,onClick:()=>t(Yc(a)),children:[Qa("span",{className:"bb-presetSwatchColor",style:{background:a.swatch,display:"flex",alignItems:"center",justifyContent:"center"},children:a.id===Za?Qa(Ef,{size:28,strokeWidth:2,color:"#ffffff"}):null}),Qa("span",{className:"bb-presetSwatchLabel",children:a.label})]},a.id))})}import{jsx as ao,jsxs as Ir}from"react/jsx-runtime";function Xc({selectedItem:e,selectedBinding:t,open:a,onToggle:i,updateBinding:n,idError:o}){return ao(ot,{title:"Identity",open:a,onToggle:i,children:Ir("div",{className:"bb-grid",children:[Ir("div",{className:"bb-field bb-field--full",children:[ao("label",{className:"bb-label",children:"Model Node ID"}),ao("span",{className:"bb-note",children:"This is the exact mesh name from the imported model and stays locked."}),ao("input",{className:"bb-input bb-readonly",value:t.modelObjectId,readOnly:!0})]}),Ir("div",{className:"bb-field bb-field--full",children:[ao("label",{className:"bb-label",children:"ID"}),ao("input",{className:`bb-input ${o?"bb-input--error":""}`,value:t.id,onChange:d=>n(e,l=>({...l,id:d.target.value}))}),o?ao("span",{className:"bb-status bb-status--error",children:o}):null]})]})})}import{useEffect as Df,useState as Zc}from"react";import{jsx as xt,jsxs as Jt}from"react/jsx-runtime";function Qc({selectedItem:e,selectedBinding:t,open:a,onToggle:i,updateBinding:n}){let[o,d]=Zc(t.group??""),[l,c]=Zc(t.tags?.join(", ")??"");Df(()=>{d(t.group??""),c(t.tags?.join(", ")??"")},[e,t.group,t.tags]);let w=()=>{n(e,y=>({...y,group:o.trim()||void 0}))},h=()=>{let y=[...new Set(l.split(",").map(u=>u.trim()).filter(Boolean))];n(e,u=>({...u,tags:y.length>0?y:void 0}))};return Jt(ot,{title:"Basics",open:a,onToggle:i,children:[Jt("div",{className:"bb-grid",children:[Jt("div",{className:"bb-field",children:[xt("label",{className:"bb-label",children:"Label"}),xt("input",{className:"bb-input",value:t.label??"",onChange:y=>n(e,u=>({...u,label:y.target.value}))})]}),Jt("div",{className:"bb-field",children:[xt("label",{className:"bb-label",children:"Type"}),xt("input",{className:"bb-input",list:"binding-type-suggestions",value:t.type??"other",onChange:y=>n(e,u=>({...u,type:y.target.value}))}),xt("datalist",{id:"binding-type-suggestions",children:Rc.map(y=>xt("option",{value:y},y))})]}),Jt("div",{className:"bb-field",children:[xt("label",{className:"bb-label",children:"Status"}),xt("select",{className:"bb-select",value:t.status??"normal",onChange:y=>n(e,u=>({...u,status:y.target.value})),children:Xa.map(y=>xt("option",{value:y,children:y},y))})]}),Jt("div",{className:"bb-field",children:[xt("label",{className:"bb-label",children:"Group"}),xt("input",{className:"bb-input",placeholder:"paint",value:o,onChange:y=>d(y.target.value),onBlur:w,onKeyDown:y=>{y.key==="Enter"&&y.currentTarget.blur()}})]}),Jt("div",{className:"bb-field",children:[xt("label",{className:"bb-label",children:"Tags"}),xt("input",{className:"bb-input",placeholder:"exterior, configurable",value:l,onChange:y=>c(y.target.value),onBlur:h,onKeyDown:y=>{y.key==="Enter"&&y.currentTarget.blur()}})]})]}),Jt("div",{className:"bb-checkboxRow",style:{marginTop:12},children:[Jt("label",{className:"bb-checkbox",children:[xt("input",{type:"checkbox",checked:t.selectable??!1,onChange:y=>n(e,u=>({...u,selectable:y.target.checked}))}),"selectable"]}),Jt("label",{className:"bb-checkbox",children:[xt("input",{type:"checkbox",checked:t.hoverable??!1,onChange:y=>n(e,u=>({...u,hoverable:y.target.checked}))}),"hoverable"]}),Jt("label",{className:"bb-checkbox",children:[xt("input",{type:"checkbox",checked:t.visible??!1,onChange:y=>n(e,u=>({...u,visible:y.target.checked}))}),"visible"]})]})]})}import{useEffect as Lf,useState as zf}from"react";import{Fragment as Hf,jsx as Ze,jsxs as Ft}from"react/jsx-runtime";var ep=Ui.filter(e=>e.handling==="viewer"),Ff=Ui.filter(e=>e.handling==="host");function tp({selectedItem:e,selectedBinding:t,open:a,onToggle:i,updateBinding:n,takesImage:o=!0}){let[d,l]=zf(new Set);Lf(()=>{l(new Set)},[e]);let c=t.actions??[],w=(u,g)=>n(e,B=>({...B,actions:(B.actions??[]).map((v,P)=>P===u?g(v):v)})),h=u=>{n(e,g=>({...g,actions:(g.actions??[]).filter((B,v)=>v!==u)})),l(g=>{let B=new Set;return g.forEach(v=>{v<u?B.add(v):v>u&&B.add(v-1)}),B})},y=(u,g)=>l(B=>{let v=new Set(B);return g?v.add(u):v.delete(u),v});return Ft(ot,{title:"Actions",open:a,onToggle:i,children:[Ze("div",{className:"bb-actionList",children:c.map((u,g)=>{let B=$a(u.id),v=d.has(g)||!B,P=u.id.trim(),x=B?null:Rl(u.id),C=P.length>0&&c.some((S,f)=>f!==g&&S.id.trim()===P);return Ft("div",{className:"bb-actionCard",children:[Ft("div",{className:"bb-actionCardHeader",children:[Ft("div",{className:"bb-actionCardTitle",children:["Action ",g+1]}),Ze("div",{className:"bb-actionCardMeta",children:u.type})]}),Ft("div",{className:"bb-actionGrid",children:[Ft("div",{className:"bb-field",children:[Ze("label",{className:"bb-label",children:"Action ID"}),Ft("select",{className:"bb-select",value:v?Ha:u.id,onChange:S=>{let f=S.target.value;if(f===Ha){y(g,!0);return}y(g,!1);let k=$a(f);w(g,O=>({...O,id:f,label:k&&Ki(O.label)?k.label:O.label}))},children:[Ze("optgroup",{label:"Handled by the viewer",children:ep.map(S=>Ze("option",{value:S.id,children:S.id},S.id))}),Ze("optgroup",{label:"Handled by your app",children:Ff.map(S=>Ze("option",{value:S.id,children:S.id},S.id))}),Ze("option",{value:Ha,children:"Custom\u2026"})]})]}),v?Ft("div",{className:"bb-field",children:[Ze("label",{className:"bb-label",children:"Custom action ID"}),Ze("input",{className:"bb-input",value:u.id,placeholder:"open-datasheet",onChange:S=>{y(g,!0),w(g,f=>({...f,id:S.target.value}))}})]}):null,Ft("div",{className:"bb-field",children:[Ze("label",{className:"bb-label",children:"Label"}),Ze("input",{className:"bb-input",value:u.label,onChange:S=>w(g,f=>({...f,label:S.target.value}))})]}),B?.id==="change-material"&&!o?Ze("span",{className:"bb-note",style:{color:"#fcd34d"},children:"This object has no texture coordinates, so an image picked here can't be placed on it, and the viewer says so. Change Color and Add Image work."}):B?Ze("span",{className:"bb-note",children:B.description}):P.length===0?Ze("span",{className:"bb-note",style:{color:"#fca5a5"},children:"An action ID is required, the button renders but can never be identified in onAction."}):Ft("span",{className:"bb-note",style:{color:"#fcd34d"},children:["Unrecognised ID, the viewer has no built-in behavior for it. Add declarative effects and execute them with useViewerActions, or handle it in onAction.",x?Ft(Hf,{children:[" Did you mean ",Ze("button",{type:"button",className:"bb-linkButton",onClick:()=>{y(g,!1);let S=$a(x);w(g,f=>({...f,id:x,label:S&&Ki(f.label)?S.label:f.label}))},children:x}),"?"]}):null]}),u.effects?.length?Ft("span",{className:"bb-note",children:[u.effects.length," declarative effect",u.effects.length===1?"":"s",", execute with useViewerActions."]}):null,C?Ze("span",{className:"bb-note",style:{color:"#fcd34d"},children:"Another action on this binding uses the same ID, they will render as two identical buttons."}):null]}),Ze("div",{className:"bb-actionFooter",children:Ze("button",{type:"button",className:"bb-button bb-button--ghost bb-actionRemove",onClick:()=>h(g),children:"Remove Action"})})]},g)})}),Ze("div",{style:{marginTop:10},children:Ze("button",{type:"button",className:"bb-button",onClick:()=>{let u=ep.find(g=>!c.some(B=>B.id===g.id));n(e,g=>({...g,actions:[...g.actions??[],{id:u?.id??"",label:u?.label??"New Action",type:"command"}]})),u||y(c.length,!0)},children:"Add Action"})})]})}import{useRef as $f}from"react";import{ImagePlus as Vf,Trash2 as qf,Type as Uf}from"lucide-react";import{Fragment as op,jsx as at,jsxs as Ht}from"react/jsx-runtime";var np=()=>`decal-${Date.now().toString(36)}-${Math.random().toString(36).slice(2,8)}`;function ap({selectedItem:e,selectedBinding:t,open:a,onToggle:i,updateBinding:n,placement:o,onPlacementChange:d,defaultSize:l,onImageFile:c,onNudge:w}){let{tier:h}=lt(),y=$f(null),u=t.decals??[],g=o?.nodeKey===e?o:null,B=x=>n(e,C=>({...C,decals:x.length>0?x:void 0})),v=(x,C)=>B(u.map(S=>S.id===x?{...S,...C}:S)),P=x=>{x.image&&Wo(x.image),g?.decal.id===x.id&&d(null),B(u.filter(C=>C.id!==x.id))};return Ht(ot,{title:"Decals",open:a,onToggle:i,tooltip:"Print a logo, image, or text on the selected object's surface.",children:[Mt(h,"decalsPerObject",u.length)?null:at(_e,{requiredTier:bn("decalsPerObject",u.length),feature:"More decals on this object"}),Ht(op,{children:[Ht("div",{className:"bb-decalActions",children:[Ht("button",{type:"button",className:"bb-button bb-button--ghost",disabled:!Mt(h,"decalsPerObject",u.length),onClick:()=>y.current?.click(),children:[at(Vf,{size:15})," Add image"]}),Ht("button",{type:"button",className:"bb-button bb-button--ghost",onClick:()=>d({nodeKey:e,decal:{id:np(),text:"Your text",color:"#ffffff",size:l}}),children:[at(Uf,{size:15})," Add text"]}),at("input",{ref:y,type:"file",accept:"image/png,image/jpeg,image/webp,image/avif,image/svg+xml",className:"bb-hiddenInput",onChange:x=>{let C=x.target.files?.[0];if(x.target.value="",!C)return;let S=vo(C);Yt(S,URL.createObjectURL(C)),c?.(S,C),d({nodeKey:e,decal:{id:np(),image:S,size:l}})}})]}),u.length===0&&!g?at("div",{className:"bb-decalEmpty",children:"No decals on this object yet."}):null,u.map(x=>Ht("div",{className:"bb-decalCard",children:[Ht("div",{className:"bb-decalCardHeader",children:[at("span",{className:"bb-decalKind",children:x.image?"Image":"Text"}),at("span",{className:"bb-decalName",title:x.image??x.text,children:x.image??x.text}),at("button",{type:"button",className:"bb-iconButton bb-iconButton--danger",title:"Delete decal","aria-label":"Delete decal",onClick:()=>P(x),children:at(qf,{size:15})})]}),at(Al,{onNudge:C=>w(x.id,C)}),Ht("div",{className:"bb-grid",children:[x.image?null:Ht(op,{children:[Ht("div",{className:"bb-field bb-field--full",children:[at("label",{className:"bb-label",children:"Text"}),at("input",{className:"bb-input",value:x.text??"",onChange:C=>v(x.id,{text:C.target.value})})]}),at(zn,{label:"Colour",variant:"input",value:x.color??"#ffffff",onChange:C=>v(x.id,{color:C})}),Ht("div",{className:"bb-field",children:[at("label",{className:"bb-label",children:"Weight"}),Ht("select",{className:"bb-input bb-decalWeight",value:x.fontWeight??"bold",onChange:C=>v(x.id,{fontWeight:C.target.value}),children:[at("option",{value:"bold",children:"Bold"}),at("option",{value:"normal",children:"Regular"})]})]})]}),at(Re,{label:"Size",value:Number(x.size.toFixed(4)),min:Number((l/20).toPrecision(2)),max:Number((l*6).toPrecision(2)),step:Number((l/50).toPrecision(1)),onChange:C=>C!==void 0&&C>0&&v(x.id,{size:C})}),at(Re,{label:"Rotation (\xB0)",value:Math.round((x.rotation??0)*180/Math.PI),min:-180,max:180,step:1,onChange:C=>v(x.id,{rotation:(C??0)*Math.PI/180})}),at(Re,{label:"Opacity",value:x.opacity??1,min:0,max:1,step:.05,onChange:C=>v(x.id,{opacity:C??1})})]})]},x.id))]})]})}import{MapPin as Kf,Trash2 as Gf}from"lucide-react";import{Fragment as _f,jsx as $t,jsxs as Ot}from"react/jsx-runtime";function ip({selectedBinding:e,open:t,onToggle:a,cameraState:i,formattedCameraState:n,savedCameraPosition:o,onSaveCameraPosition:d,onGoToSavedCamera:l,onClearSavedCamera:c,onResetView:w,onFitScene:h}){return Ot(ot,{title:"Camera Position",open:t,onToggle:a,children:[Ot("div",{className:"se-waypointCard bb-cameraWaypoint",children:[$t("span",{className:"bb-cameraLiveBadge",children:"LIVE"}),Ot("div",{className:"se-waypointBody",children:[$t("div",{className:"bb-cameraWaypointLabel",children:"Current view"}),i?Ot(_f,{children:[Ot("div",{className:"se-waypointCoords",children:["pos ",n?.position]}),Ot("div",{className:"se-waypointCoords",children:["look ",n?.target]})]}):$t("div",{className:"se-waypointCoords",children:"Move the camera to see live position"})]})]}),Ot("div",{className:"bb-cameraControls bb-cameraControls--centered",children:[$t("button",{type:"button",className:"bb-button bb-button--primary",onClick:d,disabled:!i,children:"Save"}),$t("button",{type:"button",className:"bb-button bb-button--ghost",onClick:w,children:"Reset View"}),$t("button",{type:"button",className:"bb-button bb-button--ghost",onClick:h,children:"Fit Scene"})]}),o?.position&&o?.target&&Ot("div",{className:"se-waypointCard bb-cameraWaypoint",children:[$t("span",{className:"bb-cameraSavedBadge",children:"SAVED"}),Ot("div",{className:"se-waypointBody",children:[Ot("div",{className:"bb-cameraWaypointLabel",children:["For ",e.label]}),Ot("div",{className:"se-waypointCoords",children:["pos [",o.position.map(y=>y.toFixed(1)).join(", "),"]"]}),Ot("div",{className:"se-waypointCoords",children:["look [",o.target.map(y=>y.toFixed(1)).join(", "),"]"]})]}),Ot("div",{className:"se-waypointActions",children:[$t("button",{className:"se-waypointAction",onClick:l,title:"Fly camera to the saved position",children:$t(Kf,{size:15})}),$t("button",{className:"se-waypointAction se-waypointAction--delete",onClick:c,title:"Delete saved position",children:$t(Gf,{size:15})})]})]}),$t("span",{className:"bb-note",children:'Tip: Position the camera how you want, then click "Save" to store this position for the selected object. The camera position updates in real-time as you navigate.'})]})}import{useLayoutEffect as Wf,useRef as Yf,useState as Jf}from"react";import{Maximize2 as Xf,Move3d as Zf,RotateCcw as Qf}from"lucide-react";import{Fragment as ih,jsx as we,jsxs as gt}from"react/jsx-runtime";var sp=["X","Y","Z"],eh=.1,th=.1,rp=.01;function lp(e){let t=e%360;return t<0?t+360:t}function nh(e){return lp(e*180/Math.PI)}function oh(e){return e*Math.PI/180}function Dr({value:e,min:t=-1/0,max:a=1/0,step:i=.1,disabled:n=!1,onChange:o,formatValue:d=w=>Number(w.toFixed(3)),ariaLabel:l,className:c}){let w=d(e),[h,y]=Jf(String(w)),u=Yf(!1);return Wf(()=>{u.current||y(String(w))},[w]),we("input",{type:"number",className:c,step:i,min:t===-1/0?void 0:t,max:a===1/0?void 0:a,value:h,disabled:n,"aria-label":l,onFocus:()=>{u.current=!0},onChange:g=>{let B=g.target.value;if(y(B),B===""||B==="-")return;let v=Number(B);if(Number.isFinite(v)){let P=Math.max(t,Math.min(a,v));o(P)}},onBlur:()=>{u.current=!1,y(String(d(e)))}})}function ah({value:e,min:t=-1/0,max:a=1/0,step:i=.1,disabled:n=!1,onChange:o,formatValue:d=c=>Number(c.toFixed(3)),label:l}){return we("div",{className:"bb-transformAxesGrid",children:sp.map((c,w)=>gt("div",{className:"bb-transformAxis",children:[we("span",{className:"se-axisStepperLabel bb-transformAxisLabel",children:c}),we("div",{className:"bb-transformAxisControl",children:we(Dr,{className:"se-numberInput bb-transformNumberInput",step:i,min:t,max:a,value:e[w],disabled:n,formatValue:d,ariaLabel:`${c} ${l?.toLowerCase()||""}`,onChange:h=>{let y=[...e];y[w]=h,o(y,w)}})})]},c))})}function dp({selectedItem:e,selectedBinding:t,open:a,onToggle:i,updateBinding:n,moveModeEnabled:o,onToggleMoveMode:d,scaleModeEnabled:l,onToggleScaleMode:c,transformSpace:w,onTransformSpaceChange:h,originalTransform:y,originalTransforms:u}){let g=t.transform?.rotation??y?.rotation??[0,0,0],B=t.transform?.position??y?.position??[0,0,0],v=y?.scale??[1,1,1],P=_i(t.transform?.scale??v,v),x=(p=e??"")=>u?.[p]??(p===e?y:null),C=(p,r)=>p.transform?.pivot??Ll(r?.pivotLocal??[0,0,0],p.transform?.rotation??r?.rotation??[0,0,0],p.transform?.scale??r?.scale??[1,1,1],r?.rotationOrder??"XYZ",p.transform?.shear),S=(p,r)=>{e&&n(e,(M,j)=>{let R=x(j),z=[...M.transform?.rotation??R?.rotation??[0,0,0]];return z[p]=oh(lp(r)),{...M,transform:{...M.transform,rotation:z,pivot:C(M,R)}}})},f=(p,r)=>{e&&n(e,(M,j)=>{let R=x(j),z=[...M.transform?.position??R?.position??[0,0,0]];return z[p]=r,{...M,transform:{...M.transform,position:z}}})},k=p=>{if(!e)return;let r=Math.max(rp,p);n(e,(M,j)=>{let R=x(j),E=R?.scale??[1,1,1],z=M.transform?.scale??E,pe=_i(z,E),Ce=pe>0?z:E,fe=r/(pe||1);return{...M,transform:{...M.transform,scale:Ce.map(I=>I*fe),pivot:C(M,R)}}})},O=()=>{!e||!y||n(e,p=>{let r={...p.transform};return delete r.position,delete r.rotation,delete r.scale,delete r.pivot,delete r.shear,{...p,transform:Object.keys(r).length>0?r:void 0}})};return gt(ot,{title:"Move, Rotate & Scale",open:a,onToggle:i,tooltip:"Enable Transform Gizmo to move or rotate the selected object, and Scale to resize it. Rotation and resizing keep its visible center fixed; resizing preserves its proportions.",children:[gt("div",{className:"se-field",children:[gt("div",{className:"se-fieldLabel",children:[gt("span",{children:[we(Zf,{size:14,style:{marginRight:6,verticalAlign:"-2px"}}),"Transform Gizmo"]}),gt("label",{className:"se-switch","aria-label":"Toggle transform gizmo",children:[we("input",{type:"checkbox",checked:o,onChange:p=>d(p.target.checked)}),we("span",{className:"se-switchTrack",children:we("span",{className:"se-switchThumb"})})]})]}),we("span",{className:"bb-note",children:"Select a mesh \xB7 drag the colored arrows or planes to move"})]}),gt("div",{className:"se-field",style:{marginTop:10},children:[we("div",{className:"se-fieldLabel",children:we("span",{children:"Axis space"})}),we("div",{className:"se-segmentedControl",children:["world","local"].map(p=>we("button",{type:"button",className:`se-segmentedOption ${w===p?"se-segmentedOption--active":""}`,onClick:()=>h(p),children:p},p))})]}),gt("div",{className:"se-field",style:{marginTop:10},children:[we("div",{className:"se-fieldLabel",children:we("span",{children:"Rotation (degrees)"})}),we("div",{className:"bb-transformAxesGrid",children:sp.map((p,r)=>{let M=Math.round(nh(g[r]));return gt("div",{className:"bb-transformAxis",children:[we("span",{className:"se-axisStepperLabel bb-transformAxisLabel",children:p}),we("div",{className:"bb-transformAxisControl",children:we(Dr,{className:"se-numberInput bb-transformNumberInput",step:1,min:0,max:359,value:M,disabled:!e,formatValue:j=>Math.round(j),ariaLabel:`${p} rotation in degrees`,onChange:j=>S(r,j)})})]},p)})})]}),gt("div",{className:"se-field",style:{marginTop:10},children:[we("div",{className:"se-fieldLabel",children:we("span",{children:"Position"})}),we(ah,{value:B,min:-1/0,max:1/0,step:eh,disabled:!e,label:"position",onChange:(p,r)=>f(r,p[r])})]}),gt("div",{className:"se-field",style:{marginTop:10},children:[gt("div",{className:"se-fieldLabel",children:[gt("span",{children:[we(Xf,{size:14,style:{marginRight:6,verticalAlign:"-2px"}}),"Scale"]}),gt("label",{className:"se-switch","aria-label":"Toggle scale controls",children:[we("input",{type:"checkbox",checked:l,onChange:p=>c(p.target.checked)}),we("span",{className:"se-switchTrack",children:we("span",{className:"se-switchThumb"})})]})]}),l?gt(ih,{children:[gt("div",{className:"bb-transformAxis",style:{marginTop:8},children:[we("span",{className:"se-axisStepperLabel bb-transformAxisLabel",children:"\xD7"}),we("div",{className:"bb-transformAxisControl",children:we(Dr,{className:"se-numberInput bb-transformNumberInput",step:th,min:rp,value:P,disabled:!e,formatValue:p=>Number(p.toFixed(2)),ariaLabel:"Uniform scale factor",onChange:k})})]}),we("span",{className:"bb-note",children:"1 is the model's original size \xB7 smaller shrinks, larger grows it"})]}):we("span",{className:"bb-note",children:"Enable to resize this object independently of the others"})]}),gt("button",{type:"button",className:"bb-button bb-button--ghost",style:{marginTop:10,display:"inline-flex",alignItems:"center",gap:6},disabled:!e||!y,onClick:O,title:"Restore this node's position, rotation, and scale to what they were in the original model",children:[we(Qf,{size:14}),"Restore original transform"]})]})}import{memo as yh}from"react";import{ListChecks as vh}from"lucide-react";import{useEffect as rh,useId as sh,useLayoutEffect as up,useMemo as Bo,useRef as zr,useState as Ro}from"react";import{ChevronDown as lh,ChevronRight as dh,ChevronsDownUp as ch,ChevronsUpDown as ph,Focus as bh,Trash2 as uh}from"lucide-react";function cp(e,t){let a=new Map(Object.entries(t).filter(([,d])=>!d.removed).map(([d,l])=>[l.modelObjectId??d,d])),i=new Set,n=new Map;for(let d of e){let l=d.objectId?a.get(d.objectId):void 0;l&&i.add(l),n.set(d.id,{id:d.id,name:d.name,key:l,children:[],keys:[]})}let o=[];for(let d of e){let l=n.get(d.id);((d.parentId?n.get(d.parentId):void 0)?.children??o).push(l)}for(let[d,l]of Object.entries(t))!l.removed&&!i.has(d)&&o.push({id:`binding:${d}`,name:l.modelObjectId??d,key:d,children:[],keys:[d]});for(let d=e.length-1;d>=0;d--){let l=n.get(e[d].id);l.children=l.children.filter(c=>c.keys.length),l.keys=[...l.key?[l.key]:[],...l.children.flatMap(c=>c.keys)]}return o.filter(d=>d.keys.length)}function pp(e,t,a){let i=a.trim().toLowerCase();if(!i)return e;let n=o=>{let d=o.key?t[o.key]:void 0;if([o.name,o.key,d?.label,d?.type,d?.group,...d?.tags??[]].join(" ").toLowerCase().includes(i))return o;let c=o.children.map(n).filter(w=>!!w);return c.length?{...o,key:void 0,children:c,keys:c.flatMap(w=>w.keys)}:null};return e.map(n).filter(o=>!!o)}function Lr(e,t,a=!1){let i=[],n=e.slice().reverse().map(o=>({node:o,depth:0,parentId:null}));for(;n.length;){let o=n.pop();if(i.push(o),a||!t.has(o.node.id))for(let d=o.node.children.length-1;d>=0;d--)n.push({node:o.node.children[d],depth:o.depth+1,parentId:o.node.id})}return i}function bp(e,t,a,i,n){if(n.range){let o=a?i.indexOf(a):-1,d=i.indexOf(t);if(o>=0&&d>=0){let l=i.slice(Math.min(o,d),Math.max(o,d)+1);return[...new Set(n.additive?[...e,...l]:l)]}}return n.toggle||n.additive?e.includes(t)?e.filter(o=>o!==t):[...e,t]:[t]}import{jsx as ze,jsxs as Vt}from"react/jsx-runtime";var mh=[],gh=[],fh=[],yn=56;function hh({count:e,total:t,name:a,onChange:i}){let n=zr(null);return up(()=>{n.current&&(n.current.indeterminate=e>0&&e<t)},[e,t]),ze("input",{ref:n,className:"bb-treeCheckbox",type:"checkbox","aria-label":`Select ${a}`,"aria-checked":e>0&&e<t?"mixed":e===t,checked:e===t&&t>0,onChange:i})}function ei({bindings:e,hierarchy:t=gh,selectedItem:a,onSelect:i,onHover:n,fill:o,isolatedItem:d,onIsolate:l,multiSelectEnabled:c=!1,multiSelectedKeys:w=mh,onSetMultiSelected:h,selectionSets:y=fh,onSelectionSetsChange:u}){let[g,B]=Ro(""),[v,P]=Ro(()=>new Set),[x,C]=Ro(""),S=zr(null),f=Bo(()=>cp(t,e),[t,e]),k=Bo(()=>pp(f,e,g),[f,e,g]),O=Bo(()=>Lr(k,v,!!g.trim()),[k,v,g]),p=Bo(()=>O.flatMap(({node:I})=>I.key?[I.key]:[]),[O]),r=Bo(()=>k.flatMap(I=>I.keys),[k]),M=Bo(()=>new Set(c||w.length>0?w:a?[a]:[]),[c,w,a]),j=r.length>0&&r.every(I=>M.has(I)),R=I=>{let Q=I.every(L=>M.has(L)),G=new Set(I);h?.(Q?[...M].filter(L=>!G.has(L)):[...new Set([...M,...I])])},E=I=>P(Q=>{let G=new Set(Q);return G.has(I)?G.delete(I):G.add(I),G}),z=(I,Q)=>{let G=I.node.key;if(!G){E(I.node.id);return}h&&(c||Q.shiftKey||Q.ctrlKey||Q.metaKey)?h(bp([...M],G,S.current??a,p,{range:Q.shiftKey,additive:Q.ctrlKey||Q.metaKey,toggle:c&&!Q.shiftKey})):i(G),Q.shiftKey||(S.current=G)},pe=I=>{let Q=new Set(I.objectIds);return Object.keys(e).filter(G=>!e[G].removed&&Q.has(e[G].modelObjectId??G))},Ce=Mt(lt().tier,"selectionSets",y.length),fe=()=>{let I=[...M].filter(Q=>e[Q]&&!e[Q].removed);!I.length||!x.trim()||y.length>=128||!Ce||(u?.([...y,{id:crypto.randomUUID(),name:x.trim(),objectIds:I.map(Q=>e[Q].modelObjectId??Q)}]),C(""))};return Vt("section",{className:`bb-nodeList ${o?"bb-nodeList--fill":""}`,children:[ze("div",{className:"bb-search",children:ze("input",{className:"bb-input","aria-label":"Search scene hierarchy",placeholder:"Search hierarchy, labels, or types",value:g,onChange:I=>B(I.target.value)})}),Vt("div",{className:"bb-treeToolbar",children:[h&&Vt("button",{type:"button",className:"bb-button bb-button--ghost",disabled:!r.length,onClick:()=>R(r),children:[j?"Clear matches":"Select matches"," (",r.length,")"]}),ze("button",{type:"button",className:"bb-treeIcon","aria-label":"Expand hierarchy",title:"Expand all",onClick:()=>P(new Set),children:ze(ph,{size:15})}),ze("button",{type:"button",className:"bb-treeIcon","aria-label":"Collapse hierarchy",title:"Collapse all",onClick:()=>P(new Set(Lr(f,new Set,!0).filter(({node:I})=>I.children.length).map(({node:I})=>I.id))),children:ze(ch,{size:15})})]}),u&&Vt("details",{className:"bb-selectionSets",children:[Vt("summary",{children:["Saved selections (",y.length,")"]}),Vt("div",{className:"bb-selectionSetCreate",children:[ze("input",{className:"bb-input","aria-label":"Selection name",placeholder:"Name this selection",maxLength:200,value:x,onChange:I=>C(I.target.value),onKeyDown:I=>{I.key==="Enter"&&(I.preventDefault(),fe())}}),ze("button",{type:"button",className:"bb-button bb-button--ghost",disabled:!M.size||!x.trim()||y.length>=128||!Ce,title:Ce?void 0:"Saving more selections requires the Starter plan or higher.",onClick:fe,children:"Save"})]}),!y.length&&ze("p",{children:"Select objects, then save the selection to reuse it."}),y.map(I=>{let Q=pe(I);return Vt("div",{className:"bb-selectionSetRow",children:[Vt("button",{type:"button",className:"bb-button bb-button--ghost",disabled:!Q.length,title:Q.length<I.objectIds.length?`${I.objectIds.length-Q.length} objects unavailable`:void 0,onClick:()=>{B(""),P(new Set),h?.(Q),S.current=Q[0]??null},children:[I.name,Vt("small",{children:[Q.length," / ",I.objectIds.length]})]}),ze("button",{type:"button",className:"bb-treeIcon","aria-label":`Delete selection ${I.name}`,onClick:()=>u(y.filter(G=>G.id!==I.id)),children:ze(uh,{size:14})})]},I.id)})]}),ze(xh,{rows:O,bindings:e,selected:M,multiSelect:c,collapsed:v,searching:!!g.trim(),search:g,onSelect:z,onToggle:E,onToggleKeys:h?R:void 0,onSelectAll:h?()=>h(r):void 0,onHover:n,isolatedItem:d,onIsolate:l}),ze("p",{className:"bb-treeHint",children:c?"Click to toggle \xB7 Done or Esc to exit multi-select":"Ctrl/Cmd-click to toggle \xB7 Plain click selects one"})]})}function xh({rows:e,bindings:t,selected:a,multiSelect:i,collapsed:n,searching:o,search:d,onSelect:l,onToggle:c,onToggleKeys:w,onSelectAll:h,onHover:y,isolatedItem:u,onIsolate:g}){let B=zr(null),[v,P]=Ro(400),[x,C]=Ro(0),[S,f]=Ro(0),k=sh();up(()=>{let R=B.current;if(!R)return;let E=new ResizeObserver(()=>P(R.clientHeight));return E.observe(R),()=>E.disconnect()},[]),rh(()=>{B.current&&(B.current.scrollTop=0),C(0),f(0)},[d]);let O=R=>{R=Math.max(0,Math.min(e.length-1,R)),f(R);let E=B.current;E&&(R*yn<E.scrollTop?E.scrollTop=R*yn:(R+1)*yn>E.scrollTop+E.clientHeight&&(E.scrollTop=(R+1)*yn-E.clientHeight))},p=R=>{let E=e[Math.min(S,e.length-1)];if(E){if((R.ctrlKey||R.metaKey)&&R.key.toLowerCase()==="a"){R.preventDefault(),R.stopPropagation(),h?.();return}if(["ArrowDown","ArrowUp","ArrowLeft","ArrowRight","Home","End","Enter"," "].includes(R.key)){if(R.preventDefault(),R.stopPropagation(),R.key==="ArrowDown"&&O(S+1),R.key==="ArrowUp"&&O(S-1),R.key==="Home"&&O(0),R.key==="End"&&O(e.length-1),R.key==="ArrowRight"&&E.node.children.length&&(n.has(E.node.id)?c(E.node.id):O(S+1)),R.key==="ArrowLeft")if(E.node.children.length&&!n.has(E.node.id))c(E.node.id);else{let z=e.findIndex(pe=>pe.node.id===E.parentId);z>=0&&O(z)}(R.key==="Enter"||R.key===" ")&&(R.key===" "&&i&&!E.node.key?w?.(E.node.keys):l(E,R))}}},r=Math.max(0,Math.min(e.length-1,Math.floor(x/yn))-5),M=Math.min(e.length,r+Math.ceil(v/yn)+12),j=Math.min(S,e.length-1);return Vt("div",{ref:B,className:"bb-sceneTree",role:"tree","aria-label":"Scene hierarchy","aria-multiselectable":!!h,tabIndex:0,"aria-activedescendant":j>=r&&j<M?`${k}-${j}`:void 0,onKeyDown:p,onScroll:R=>C(R.currentTarget.scrollTop),children:[!e.length&&ze("p",{className:"bb-treeEmpty",children:"No matching objects."}),ze("div",{style:{height:e.length*yn,position:"relative"},children:e.slice(r,M).map((R,E)=>{let{node:z,depth:pe}=R,Ce=r+E,fe=z.key?t[z.key]:void 0,I=z.keys.reduce((L,ae)=>L+Number(a.has(ae)),0),Q=z.children.length?o||!n.has(z.id):void 0,G=z.key?a.has(z.key):I===z.keys.length;return Vt("div",{id:`${k}-${Ce}`,role:"treeitem","aria-level":pe+1,"aria-expanded":Q,"aria-selected":G,className:`bb-treeRow${G?" bb-treeRow--selected":""}`,style:{top:Ce*yn,height:yn,paddingLeft:8+Math.min(pe,10)*14},onFocus:()=>f(Ce),onMouseEnter:()=>y?.(z.key??null),onMouseLeave:()=>y?.(null),children:[z.children.length?ze("button",{type:"button",tabIndex:-1,className:"bb-treeIcon","aria-label":`${Q?"Collapse":"Expand"} ${z.name}`,onClick:()=>c(z.id),children:Q?ze(lh,{size:14}):ze(dh,{size:14})}):ze("span",{className:"bb-treeSpacer"}),i&&w&&ze(hh,{count:I,total:z.keys.length,name:z.name,onChange:()=>w(z.keys)}),Vt("button",{type:"button",tabIndex:-1,className:"bb-treeNode",onClick:L=>{f(Ce),B.current?.focus({preventScroll:!0}),l(R,L)},children:[ze("span",{children:fe?.label||z.name}),ze("small",{children:fe?`${fe.type??"other"} \xB7 ${fe.modelObjectId}`:`${z.keys.length} objects`})]}),z.key&&g&&ze("button",{type:"button",tabIndex:-1,className:"bb-treeIcon bb-treeIsolate","aria-label":`${u===z.key?"Show all":"Isolate"} ${z.name}`,"aria-pressed":u===z.key,onClick:()=>g(u===z.key?null:z.key),children:ze(bh,{size:14})})]},z.id)})})]})}import{Fragment as Ch,jsx as Tt,jsxs as Ao}from"react/jsx-runtime";var Fr=[],mp=yh(Sh);function Hr(e){let t=0;for(let a of Object.values(e))a.removed||(t+=1);return t}function Sh({bindings:e,selectedItem:t,onSelect:a,onHover:i,isOpen:n=!0,onToggle:o,modelGroups:d,onSelectModel:l,isolatedItem:c=null,onIsolate:w,multiSelectEnabled:h=!1,onToggleMultiSelect:y,onExitMultiSelect:u,multiSelectedKeys:g=Fr,onSetMultiSelected:B,hierarchy:v,selectionSets:P,onSelectionSetsChange:x}){let C=d&&d.length>=2?d:null,S=C?C.reduce((f,k)=>f+Hr(k.bindings),0):Hr(e);return Ao("aside",{className:`bb-sidebar bb-sidebar--right ${n?"":"bb-sidebar--collapsed"}`,children:[Ao("div",{className:"bb-header bb-header--sidebar",children:[!n&&Tt("button",{type:"button",className:"bb-sidebarToggle",onClick:()=>o?.(!0),"aria-label":"Open scene nodes sidebar",title:"Open scene nodes",children:"\u2190"}),n&&Ao(Ch,{children:[Ao("div",{className:"bb-sidebarHeadingText",children:[Tt("div",{className:"bb-sectionKicker",children:h||g.length>1?`Scene Nodes \xB7 ${S}`:"Scene Nodes"}),Tt("div",{className:"bb-sectionHeading",style:h||g.length>1?{fontSize:15}:void 0,children:h||g.length>1?`${g.length} selected`:`${S} ${S===1?"node":"nodes"}`})]}),Ao("div",{className:"bb-sidebarActions",children:[y?Tt("button",{type:"button",className:`bb-sidebarToggle ${h?"bb-sidebarToggle--active":""}`,onClick:y,"aria-pressed":h,"aria-label":"Toggle multi-select",title:h?"Multi-select on: edits apply to every selected node":"Select multiple nodes",children:Tt(vh,{size:16,"aria-hidden":"true"})}):null,Tt("button",{type:"button",className:"bb-sidebarToggle",onClick:()=>o?.(!1),"aria-label":"Close scene nodes sidebar",title:"Close scene nodes",children:"\u2192"})]})]})]}),n&&h&&Ao("div",{className:"bb-selectionModeBar",children:[Tt("span",{children:"Multi-select mode"}),Tt("button",{type:"button",className:"bb-button bb-button--ghost","aria-label":"Exit multi-select",onClick:u??y,children:"Done"})]}),n&&(C?Tt(wh,{groups:C,selectedItem:t,onSelect:a,onHover:i,onSelectModel:l,isolatedItem:c,onIsolate:w,multiSelectEnabled:h,multiSelectedKeys:g,onSetMultiSelected:B,hierarchy:v,selectionSets:P,onSelectionSetsChange:x}):Tt(ei,{bindings:e,selectedItem:t,onSelect:a,onHover:i,isolatedItem:c,onIsolate:w,multiSelectEnabled:h,multiSelectedKeys:g,onSetMultiSelected:B,hierarchy:v,selectionSets:P,onSelectionSetsChange:x}))]})}function wh({groups:e,selectedItem:t,onSelect:a,onHover:i,onSelectModel:n,isolatedItem:o=null,onIsolate:d,multiSelectEnabled:l=!1,multiSelectedKeys:c=Fr,onSetMultiSelected:w,hierarchy:h,selectionSets:y,onSelectionSetsChange:u}){return Tt("section",{className:"bb-nodeList bb-nodeList--grouped",children:e.map(g=>{let B=g.isActive,v=Hr(g.bindings),P=`${g.label} (${v})${g.isActive?" \xB7 Active":""}`,x=B;return Tt("div",{className:`bb-groupItem ${x?"bb-groupItem--fill":""}`,children:Tt(ot,{title:P,open:B,onToggle:()=>{n?.(g.url)},children:Tt(ei,{bindings:g.bindings,hierarchy:g.isActive?h:void 0,selectionSets:g.isActive?y:void 0,onSelectionSetsChange:g.isActive?u:void 0,selectedItem:t,onSelect:C=>{n?.(g.url),a(C)},onHover:i,fill:x,isolatedItem:g.isActive?o:null,onIsolate:g.isActive?d:void 0,multiSelectEnabled:g.isActive&&l,multiSelectedKeys:g.isActive?c:Fr,onSetMultiSelected:g.isActive?w:void 0})})},g.url)})})}import{jsx as ti,jsxs as gp}from"react/jsx-runtime";function $r({title:e,label:t,open:a,onToggle:i,draft:n,error:o,example:d,onDraftChange:l,onCommit:c}){return ti(ot,{title:e,open:a,onToggle:i,children:gp("div",{className:"bb-field",children:[ti("label",{className:"bb-label",children:t}),ti("textarea",{className:"bb-textarea",value:n,onChange:w=>l(w.target.value),onBlur:c}),o?ti("span",{className:"bb-status bb-status--error",children:o}):gp("span",{className:"bb-note",children:["Use a JSON object like ",d,"."]})]})})}import{useCallback as qt}from"react";import{PropertyBinding as hp}from"three";import{PropertyBinding as Vr}from"three";function io(e,t,a=[],i={},n=new Set(Object.keys(Da(e).nodesById))){let o=new Map(Object.entries(t).filter(([,u])=>u.removed===!0).map(([u,g])=>[g.modelObjectId??u,g])),d=new Set(Object.entries(i).map(([u,g])=>g.modelObjectId??u)),l=a.filter(u=>u.loadState==="loading").map(u=>Vr.sanitizeNodeName(`${an(u.namePrefix)}_`)),c=Object.fromEntries(Object.entries(t).filter(([u,g])=>{let B=g.modelObjectId??u;return!d.has(B)&&(g.removed===!0||n.has(B)||l.some(v=>B.startsWith(v)))})),w=Object.fromEntries(Object.entries(i).map(([u,g])=>[u,o.get(g.modelObjectId??u)??g])),h={...c,...w},y=Object.keys(h);return y.length===Object.keys(t).length&&y.every(u=>h[u]===t[u])?t:h}function an(e){return e.replace(/\.[^./\\]+$/,"")}function qr(e,t,a={}){let i=Vr.sanitizeNodeName(an(e)).replace(/_/g,"-")||"Model",n=t.map(l=>Vr.sanitizeNodeName(an(l.namePrefix))),o=Object.entries(a).map(([l,c])=>c.modelObjectId??l),d=i;for(let l=2;;l++){let c=`${d}_`;if(!n.some(w=>w===d||w.startsWith(c))&&!o.some(w=>w.startsWith(c)))return d;d=`${i}-${l}`}}function Oo(e){e.resolved.cleanup()}function da(e){e.resolved?.cleanup(),e.mergedModelSources.forEach(Oo)}function ca(e,t){let a=Kl(e),i=Jo(a,Ua(e));if(t){let o=new Map(Object.values(t).map(d=>[d.modelObjectId,d]));for(let d of a){let l=o.get(d);l&&(i[d]=l)}}e.updateMatrixWorld(!0);let n={};for(let o of a){let d=_o(e,o);if(!d){n[o]={position:[0,0,0],rotation:[0,0,0],scale:[1,1,1],pivotLocal:[0,0,0],rotationOrder:"XYZ"};continue}let l=Dl(d);n[o]={position:[d.position.x,d.position.y,d.position.z],rotation:[d.rotation.x,d.rotation.y,d.rotation.z],scale:[d.scale.x,d.scale.y,d.scale.z],pivotLocal:[l.x,l.y,l.z],rotationOrder:d.rotation.order}}return{bindings:i,originalTransforms:n,nodeNames:a}}function kh(e,t){let a=e;for(;a;){if(a===t)return!0;a=a.parent}return!1}function Ur(e,t){let a=e.parent??e,i=ca(a,t),n=i.nodeNames.filter(o=>{let d=_o(a,o);return d?kh(d,e):!1});return{bindings:Object.fromEntries(n.map(o=>[o,i.bindings[o]])),originalTransforms:Object.fromEntries(n.map(o=>[o,i.originalTransforms[o]])),nodeNames:n}}function ni(e,t=[]){let a={bindings:e,mergeSources:t};return{past:[],present:a,future:[],baseline:a,edits:0}}function xp(e,t){let a=t(e.present),i=e.past.map(t),n=e.future.map(t),o=t(e.baseline);return a===e.present&&o===e.baseline&&i.every((d,l)=>d===e.past[l])&&n.every((d,l)=>d===e.future[l])?e:{...e,present:a,past:i,future:n,baseline:o}}function yp(e,t,a,i={}){return xp(e,n=>{if(!n.mergeSources.some(l=>l.url===t))return n;let o=new Map(Object.entries(n.bindings).map(([l,c])=>[c.modelObjectId??l,c])),d={...n.bindings};for(let[l,c]of Object.entries(i))d[l]=o.get(c.modelObjectId??l)??c;return{bindings:d,mergeSources:n.mergeSources.map(l=>l.url===t?{...l,...a}:l)}})}function Kr(e,t){let a=e.mergeSources.find(o=>o.url===t);if(!a)return e;let i=new Set(a.nodeNames),n=hp.sanitizeNodeName(`${an(a.namePrefix)}_`);return{mergeSources:e.mergeSources.filter(o=>o.url!==t),bindings:Object.fromEntries(Object.entries(e.bindings).filter(([o,d])=>{let l=d.modelObjectId??o;return!i.has(l)&&!i.has(o)&&!l.startsWith(n)}))}}function Gr(e,t){let a=fn(e.bindingHistory??ni(e.bindings,e.mergedModelSources),{type:"set",updater:t,track:!0,coalesce:!1});return{...e,bindings:a.present.bindings,mergedModelSources:a.present.mergeSources,bindingHistory:a}}function _r(e,t,a,i){let n=yp(e.bindingHistory??ni(e.bindings,e.mergedModelSources),t,a,i);return{...e,bindings:n.present.bindings,mergedModelSources:n.present.mergeSources,bindingHistory:n}}function vp(e,t){let a=e.bindingHistory??ni(e.bindings,e.mergedModelSources),n=[a.present,...a.past,...a.future].flatMap(l=>l.mergeSources).map(l=>hp.sanitizeNodeName(`${an(l.namePrefix)}_`)),o=Object.fromEntries(Object.entries(t).filter(([l,c])=>!n.some(w=>(c.modelObjectId??l).startsWith(w)))),d=xp(a,l=>({...l,bindings:{...o,...l.bindings}}));return{...e,bindings:d.present.bindings,bindingHistory:d}}function fp(e,t){let a=new Set(t.mergeSources.map(i=>i.url));return{...e,present:{...e.present,mergeSources:e.present.mergeSources.map(i=>a.has(i.url)?i:{...i,loadState:"loading"})}}}function Sp(e,t=[]){let a=na({bindings:e,mergeSources:t}),{setValue:i,setValueAsStep:n,updateHistory:o,restoreSnapshot:d}=a,l=qt(S=>i(f=>{let k=typeof S=="function"?S(f.bindings):S;return k===f.bindings?f:{...f,bindings:k}}),[i]),c=qt(S=>n(f=>{let k=typeof S=="function"?S(f.bindings):S;return k===f.bindings?f:{...f,bindings:k}}),[n]),w=qt(S=>o(f=>{let k=typeof S=="function"?S(f.present.bindings):S;if(k===f.present.bindings)return f;let O={...f.present,bindings:k};return{...f,present:O,baseline:f.edits===0?O:f.baseline}}),[o]),h=qt(S=>o(f=>{let k=typeof S=="function"?S(f.present.mergeSources):S,O={...f.present,mergeSources:k};return{...f,present:O,baseline:f.edits===0?O:f.baseline}}),[o]),y=qt(S=>n(f=>({...f,mergeSources:[...f.mergeSources,typeof S=="function"?S(f):S]})),[n]),u=qt(S=>n(f=>Kr(f,S)),[n]),g=qt((S,f,k)=>{o(O=>yp(O,S,f,k))},[o]),B=qt(()=>d(S=>{let f=fn(S,{type:"undo"});return f===S?S:fp(f,S.present)}),[d]),v=qt(()=>d(S=>{let f=fn(S,{type:"redo"});return f===S?S:fp(f,S.present)}),[d]),P=qt((S,f)=>d(k=>fn(k,{type:"reset",value:{bindings:S,mergeSources:k.present.mergeSources},track:f?.asEdit??!1})),[d]),x=qt(()=>d(S=>fn(S,{type:"reset",value:S.present,track:!1})),[d]),C=qt(S=>d({...S.bindingHistory??ni(S.bindings,S.mergedModelSources),present:{bindings:S.bindings,mergeSources:S.mergedModelSources}}),[d]);return{value:a.value.bindings,baseline:a.baseline.bindings,mergeSources:a.value.mergeSources,snapshot:a.snapshot,edits:a.edits,canUndo:a.canUndo,canRedo:a.canRedo,setValue:l,setValueAsStep:c,setValueUntracked:w,setMergeSourcesUntracked:h,addMerge:y,removeMerge:u,hydrateMerge:g,undo:B,redo:v,reset:P,clearHistory:x,restoreModel:C}}import{useEffect as wp,useRef as Mh}from"react";function Cp(e,t,{modelUrl:a,modelSourceRef:i,uploadedFilesRef:n}={}){let o=Mh(new Map);wp(()=>{let d=new Map,l=h=>{for(let y of[h.present,...h.past,...h.future])y.mergeSources.forEach(u=>d.set(u.url,u))};l(e);for(let h of t)h.bindingHistory&&l(h.bindingHistory),h.mergedModelSources.forEach(y=>d.set(y.url,y));for(let[h,y]of o.current)d.has(h)||y.resolved.cleanup();o.current=d;let c=new Set,w=h=>{h?.kind==="file"&&c.add(h.key)};a&&w(i?.current?.model),t.forEach(h=>w(h.sessionModel)),d.forEach(h=>w(h.sessionModel));for(let h of n?.current.keys()??[])c.has(h)||n?.current.delete(h)},[e,t,a,i,n]),wp(()=>()=>{o.current.forEach(d=>d.resolved.cleanup()),o.current.clear(),n?.current.clear()},[n])}import{useCallback as Nh,useEffect as Wr,useRef as Th}from"react";var Ph=500;function kp({composition:e,autosaveEnabled:t,hasEdits:a,modelUrl:i,bindings:n,sceneConfig:o,parkedModels:d,mergedModelSources:l,modelOrder:c,onTextureUpload:w,modelSourceRef:h,pendingLoadRef:y,storedModelKeysRef:u,uploadedFilesRef:g,pendingAutosaveRef:B,autosaveFailureShownRef:v,setStatusMessage:P,setStatusTone:x}){let C=Th(0),S=Nh(async(f,k)=>{if(w)return w(f,k);let O=URL.createObjectURL(f);if(t)try{await ko(O,f)}catch(p){console.warn("[BindingBuilder] Could not store texture file for autosave:",p)}return O},[w,t]);return Wr(()=>{if(!t||!a){B.current=null;return}let f=h.current;if(i&&!f){B.current=null;return}let k=i,O=()=>{if(B.current!==O||y.current)return;B.current=null;let r=++C.current,M=G=>{console.warn("[BindingBuilder] Autosave failed:",G),!v.current&&(v.current=!0,P("Couldn't autosave this session \u2014 the browser refused to store it, possibly for lack of space. Export your work to keep it."),x("error"))};if(!k||!f){u.current.clear(),yd().then(()=>{r===C.current&&(v.current=!1)}).catch(M);return}let{model:j}=f,R=[],E=new Set,z=G=>{if(!G||G.kind!=="file"||(E.add(G.key),u.current.has(G.key)))return;let L=g.current.get(G.key);L&&R.push({key:G.key,file:L})};z(j),d.forEach(G=>{z(G.sessionModel),G.mergedModelSources.forEach(L=>z(L.sessionModel))}),l.forEach(G=>z(G.sessionModel)),u.current=new Set([...u.current].filter(G=>E.has(G)));let pe=G=>({model:G.sessionModel,namePrefix:G.namePrefix}),Ce=d.filter(G=>!!G.sessionModel).map(G=>({model:G.sessionModel,bindings:G.bindings,originalTransforms:G.originalTransforms,modelSettings:G.modelSettings,mergeModels:G.mergedModelSources.map(pe)})),fe=l.map(pe),I=new Map;I.set(k,j),d.forEach(G=>{G.sessionModel&&I.set(G.url,G.sessionModel)});let Q=c.map(G=>{let L=I.get(G);return L?tn(L):null}).filter(G=>G!==null);hd({model:j,composition:e,bindings:n,sceneConfig:o,parkedModels:Ce,mergeModels:fe,modelOrder:Q},R).then(()=>{r===C.current&&(u.current=E,v.current=!1)}).catch(M)};if(B.current=O,!k){O();return}let p=window.setTimeout(O,Ph);return()=>window.clearTimeout(p)},[e,t,a,i,n,o,d,l,c]),Wr(()=>{if(!t)return;let f=()=>B.current?.(),k=()=>{document.visibilityState==="hidden"&&f()};return window.addEventListener("pagehide",f),document.addEventListener("visibilitychange",k),()=>{window.removeEventListener("pagehide",f),document.removeEventListener("visibilitychange",k),f()}},[t]),Wr(()=>{if(!t||!i||!a)return;let f=k=>{B.current?.(),k.preventDefault(),k.returnValue=""};return window.addEventListener("beforeunload",f),()=>window.removeEventListener("beforeunload",f)},[t,i,a]),{handleTextureUpload:S}}import{useLayoutEffect as Bh}from"react";function Mp({bindings:e,multiSelectMode:t,selectedItem:a,multiSelectedKeys:i,setSelectedItem:n,setMultiSelectedKeys:o}){Bh(()=>{let d=c=>!!(e[c]&&!e[c].removed),l=i.filter(d);l.length!==i.length&&o(l),a&&(!d(a)||t&&!l.includes(a))&&n(t?l[l.length-1]??null:null)},[e,t,a,i,n,o])}import{useCallback as Fn,useReducer as Rh}from"react";var Jr={selectedItem:null,keys:[],checkboxMode:!1},Yr=(e,t)=>typeof e=="function"?e(t):e;function Ah(e,t){if(t.type==="primary"){let c=Yr(t.value,e.selectedItem);return c===e.selectedItem?e:{...e,selectedItem:c}}if(t.type==="keys"){let c=Yr(t.value,e.keys);return c===e.keys?e:{...e,keys:c}}if(t.type==="mode"){let c=Yr(t.value,e.checkboxMode);return c===e.checkboxMode?e:{...e,checkboxMode:c}}if(t.type==="clear")return Jr;if(t.type==="exitMode"||t.type==="toggleMode"&&e.checkboxMode)return{...e,checkboxMode:!1,keys:[]};if(t.type==="toggleMode")return{...e,checkboxMode:!0,keys:e.keys.length?e.keys:e.selectedItem?[e.selectedItem]:[]};if(t.type==="selection"){let c=[...new Set(t.keys)];return{...e,keys:c,selectedItem:e.selectedItem&&c.includes(e.selectedItem)?e.selectedItem:c[c.length-1]??null}}if(t.type!=="select")return e;let{key:a,modifiers:i}=t;if(!a)return e.checkboxMode?e:Jr;if(!e.checkboxMode&&!i.shiftKey&&!i.ctrlKey&&!i.metaKey)return{...e,selectedItem:a,keys:[]};let n=e.keys.length?e.keys:e.selectedItem?[e.selectedItem]:[],o=i.shiftKey&&!i.ctrlKey&&!i.metaKey,d=n.includes(a)&&!o,l=d?n.filter(c=>c!==a):[...new Set([...n,a])];return{...e,keys:l,selectedItem:d?e.selectedItem&&l.includes(e.selectedItem)?e.selectedItem:l[l.length-1]??null:a}}function Np(){let[e,t]=Rh(Ah,Jr),a=Fn(h=>t({type:"primary",value:h}),[]),i=Fn(h=>t({type:"keys",value:h}),[]),n=Fn(h=>t({type:"mode",value:h}),[]),o=Fn(h=>t({type:"selection",keys:h}),[]),d=Fn((h,y={})=>t({type:"select",key:h,modifiers:y}),[]),l=Fn(()=>t({type:"toggleMode"}),[]),c=Fn(()=>t({type:"exitMode"}),[]),w=Fn(()=>t({type:"clear"}),[]);return{selectedItem:e.selectedItem,multiSelectedKeys:e.keys,multiSelectMode:e.checkboxMode,groupSelectionActive:e.checkboxMode||e.keys.length>1,setSelectedItem:a,setMultiSelectedKeys:i,setMultiSelectMode:n,setSelection:o,selectObject:d,toggleMultiSelect:l,exitMultiSelect:c,clearSelection:w}}import{useCallback as Tp,useEffect as Oh,useState as jh}from"react";function Pp(e,t){let[a,i]=jh(!1),n=e>0||t>0,o=Tp(()=>i(!0),[]),d=Tp(()=>i(!1),[]);return Oh(()=>{n&&o()},[n,o]),{hasEdits:a||n,markSessionEdited:o,resetSessionEdits:d}}import{useEffect as Bp,useReducer as Eh,useRef as Ih}from"react";function Rp({enabled:e=!0,modelUrl:t,bindings:a,mergeSources:i,parkedModels:n,scenesRef:o,sceneRevision:d,setBindings:l,setParkedModels:c}){let[w,h]=Eh(u=>u+1,0),y=Ih(new WeakMap);Bp(()=>{if(!e)return;let u=[t,...n.map(v=>v.url)],g=new Set(u.flatMap(v=>{let P=v?o.current.get(v):void 0;return P?[P]:[]})),B=v=>{v.target&&y.current.delete(v.target),h()};for(let v of g)v.addEventListener("childadded",B),v.addEventListener("childremoved",B);return()=>{for(let v of g)v.removeEventListener("childadded",B),v.removeEventListener("childremoved",B)}},[e,t,n,o,d]),Bp(()=>{if(!e)return;let u=B=>{let v=y.current.get(B);return v||(v=new Set(Object.keys(Da(B).nodesById)),y.current.set(B,v)),v},g=t?o.current.get(t):void 0;if(g){let B=u(g);l(v=>io(g,v,i,{},B))}c(B=>{let v=!1,P=B.map(x=>{let C=o.current.get(x.url);if(!C)return x;let S=io(C,x.bindings,x.mergedModelSources,{},u(C));return S===x.bindings?x:(v=!0,{...x,bindings:S})});return v?P:B})},[e,t,a,i,n,o,d,w,l,c])}import{useEffect as Dh,useMemo as Lh,useReducer as zh}from"react";function Ap({modelUrl:e,scenesRef:t,sceneRevision:a,streaming:i=!1}){let n=e?t.current.get(e):void 0,[o,d]=zh(l=>l+1,0);return Dh(()=>{if(!n||i)return;let l=()=>d();return n.addEventListener("childadded",l),n.addEventListener("childremoved",l),()=>{n.removeEventListener("childadded",l),n.removeEventListener("childremoved",l)}},[n,i]),Lh(()=>({materialVariantGroups:n?Il(n):[],objectsWithoutUvs:n&&!i?Ua(n):new Set,hierarchy:n&&!i?sd(n):[]}),[n,a,o,i])}import{ListRestart as _h,Redo2 as Wh,Undo2 as Yh}from"lucide-react";import{useEffect as Fh,useId as Hh,useLayoutEffect as $h,useRef as Op,useState as jp}from"react";import{ChevronDown as Vh,Download as qh,FileArchive as Uh,FileCode2 as Kh,FileJson as Ep,Upload as Gh}from"lucide-react";import{jsx as Ut,jsxs as oi}from"react/jsx-runtime";function Ip({action:e,groups:t,busy:a}){let[i,n]=jp(!1),[o,d]=jp(480),l=Op(null),c=Op(null),w=Hh(),h=a||t.every(y=>y.options.every(u=>u.disabled));return $h(()=>{if(!i)return;let y=()=>{let u=l.current?.closest(".bb-toolbar"),g=l.current?.closest(".bb-sidebar");u&&g&&d(Math.max(80,u.getBoundingClientRect().top-Math.max(0,g.getBoundingClientRect().top)-8))};return y(),window.addEventListener("resize",y),()=>window.removeEventListener("resize",y)},[i]),Fh(()=>{if(!i)return;let y=u=>{l.current?.contains(u.target)||n(!1)};return window.addEventListener("pointerdown",y),()=>window.removeEventListener("pointerdown",y)},[i]),oi("div",{className:"bb-exportMenuWrapper",ref:l,onKeyDown:y=>{y.key!=="Escape"||!i||(y.preventDefault(),y.stopPropagation(),n(!1),c.current?.focus())},children:[oi("button",{ref:c,type:"button",className:"bb-button bb-button--ghost",disabled:h,"aria-busy":a||void 0,onClick:()=>n(y=>!y),title:`${e} files`,"aria-label":`${e} files`,"aria-expanded":i,"aria-controls":i?w:void 0,children:[e==="Import"?Ut(Gh,{size:14}):Ut(qh,{size:14}),e,Ut(Vh,{size:12})]}),i&&Ut("div",{className:"bb-exportMenu",id:w,role:"group","aria-label":`${e} options`,style:{maxHeight:`min(65vh, ${o}px)`},children:t.map((y,u)=>oi("div",{className:"bb-fileMenuScope",children:[Ut("div",{className:"bb-exportMenuTitle",children:y.title}),Ut("p",{className:"bb-exportMenuDescription",id:`${w}-${u}`,children:y.description}),y.options.map(g=>oi("button",{type:"button",className:"bb-exportMenuItem",disabled:g.disabled||a,"aria-label":`${e} ${g.label}`,"aria-describedby":`${w}-${u}`,onClick:()=>{n(!1),g.run()},children:[g.icon,g.label]},g.label))]},y.title))})]})}function Dp(e,t,a){return[...a?[{title:"Complete scene",description:"All models, placements, uploaded textures, bindings and scene settings. Remote assets keep their URLs.",options:[{label:"Complete scene ZIP",icon:Ut(Uh,{size:14}),disabled:e==="Import"?a.importDisabled:a.exportDisabled,run:e==="Import"?a.onImport:a.onExport}]}]:[],...t.map(i=>({title:`${i.title} only`,description:i.description,options:e==="Import"?[{label:`${i.title} JSON`,icon:Ut(Ep,{size:14}),disabled:i.importDisabled,run:i.onImport}]:[{label:`${i.title} JSON`,icon:Ut(Ep,{size:14}),disabled:i.exportDisabled,run:i.onExportJson},{label:`${i.title} TypeScript`,icon:Ut(Kh,{size:14}),disabled:i.exportDisabled,run:i.onExportTs}]}))]}function Lp({scopes:e,sceneBundle:t,busy:a}){return Ut(Ip,{action:"Export",groups:Dp("Export",e,t),busy:a})}function zp({scopes:e,sceneBundle:t,busy:a}){return Ut(Ip,{action:"Import",groups:Dp("Import",e,t),busy:a})}import{jsx as rn,jsxs as Fp}from"react/jsx-runtime";function Xr({canUndo:e,canRedo:t,onUndo:a,onRedo:i,onReset:n,resetDisabled:o,resetTitle:d,fileScopes:l,sceneBundle:c,busy:w}){return Fp("div",{className:"bb-toolbar",children:[Fp("div",{className:"bb-toolbarGroup",children:[rn("button",{type:"button",className:"bb-iconButton",disabled:!e||w,onClick:a,title:"Undo (Cmd/Ctrl+Z)",children:rn(Yh,{size:16})}),rn("button",{type:"button",className:"bb-iconButton",disabled:o||w,onClick:n,title:d,children:rn(_h,{size:16})}),rn("button",{type:"button",className:"bb-iconButton",disabled:!t||w,onClick:i,title:"Redo (Cmd/Ctrl+Shift+Z)",children:rn(Wh,{size:16})})]}),rn("div",{className:"bb-toolbarDivider"}),rn(zp,{scopes:l,sceneBundle:c,busy:w}),rn("div",{className:"bb-toolbarDivider"}),rn(Lp,{scopes:l,sceneBundle:c,busy:w})]})}import{AlertTriangle as Zr,History as Jh,Upload as Xh,X as ba}from"lucide-react";import{useId as pa,useState as Zh}from"react";import{jsx as ne,jsxs as ge}from"react/jsx-runtime";function Qh(e){let t=new Date(e);return t.toDateString()===new Date().toDateString()?`today at ${t.toLocaleTimeString([],{hour:"numeric",minute:"2-digit"})}`:t.toLocaleString([],{dateStyle:"medium",timeStyle:"short"})}function Hp({target:e,onCancel:t,onConfirm:a}){return ne("div",{className:"bb-reset-overlay",onClick:t,children:ge("div",{className:"bb-reset-dialog",onClick:i=>i.stopPropagation(),children:[ge("div",{className:"bb-reset-header",children:[ge("h3",{className:"bb-reset-title",children:[ne(Zr,{size:20,className:"bb-icon-warning"}),"Confirm Reset"]}),ne("button",{className:"bb-reset-close",onClick:t,children:ne(ba,{size:20})})]}),ge("div",{className:"bb-reset-body",children:[ge("p",{className:"bb-reset-message",children:["Are you sure you want to reset"," ",ne("strong",{children:e==="bindings"?"Object Bindings":e==="assets"?"Asset Placements":"Scene Config"}),"?"]}),ne("p",{className:"bb-reset-details",children:e==="bindings"?"This will remove all your custom changes to object properties, groups, tags, transforms, materials, actions, camera positions, metrics, and metadata.":e==="assets"?"This will reset every asset's position, rotation and scale, and restore the default grid spacing. Asset membership, names, visibility and object edits are kept.":"This will restore all scene settings (camera, lighting, environment, background, animations, annotations, etc.) to their default values."}),ne("p",{className:"bb-reset-warning",children:e==="assets"?"You can undo this reset.":"This action cannot be undone!"})]}),ge("div",{className:"bb-reset-footer",children:[ne("button",{className:"bb-reset-btn",onClick:t,children:"Cancel"}),ne("button",{className:"bb-reset-btn-danger",onClick:a,children:"Reset"})]})]})})}function $p({modelNames:e,mergedSourceCount:t,savedAt:a,onCancel:i,onConfirm:n}){let o=pa();return ne("div",{className:"bb-reset-overlay",onClick:i,children:ge("div",{className:"bb-reset-dialog",role:"dialog","aria-modal":"true","aria-labelledby":o,onClick:d=>d.stopPropagation(),children:[ge("div",{className:"bb-reset-header",children:[ge("h3",{className:"bb-reset-title",id:o,children:[ne(Jh,{size:20,className:"bb-icon-restore"}),"Restore Last Session"]}),ne("button",{className:"bb-reset-close",onClick:i,children:ne(ba,{size:20})})]}),ge("div",{className:"bb-reset-body",children:[ge("p",{className:"bb-reset-message",children:["Restore the session saved ",Qh(a),"?"]}),ge("p",{className:"bb-reset-message",children:[ge("strong",{children:[e.length," ",e.length===1?"model":"models"]})," \xB7 ",t," merged ",t===1?"source":"sources"]}),ne("ul",{className:"bb-restoreModelNames","aria-label":"Saved models",children:e.map((d,l)=>ne("li",{children:d},l))}),ne("p",{className:"bb-reset-details",children:"This restores the saved models and merged nodes with their object bindings and scene settings, replacing what's in the editor now."})]}),ge("div",{className:"bb-reset-footer",children:[ne("button",{className:"bb-reset-btn",onClick:i,children:"Cancel"}),ne("button",{className:"bb-reset-btn-restore",onClick:n,children:"Restore"})]})]})})}function Vp({nodeLabel:e,count:t=1,onCancel:a,onConfirm:i}){let n=t>1;return ne("div",{className:"bb-reset-overlay",onClick:a,children:ge("div",{className:"bb-reset-dialog",onClick:o=>o.stopPropagation(),children:[ge("div",{className:"bb-reset-header",children:[ge("h3",{className:"bb-reset-title",children:[ne(Zr,{size:20,className:"bb-icon-warning"}),n?"Delete Objects":"Delete Object"]}),ne("button",{className:"bb-reset-close",onClick:a,children:ne(ba,{size:20})})]}),ge("div",{className:"bb-reset-body",children:[ge("p",{className:"bb-reset-message",children:["Delete ",ne("strong",{children:e}),"?"]}),ne("p",{className:"bb-reset-details",children:n?"This removes them from the Object and Scene Nodes panels and takes them out of the 3D view entirely, for every viewer, not just hidden, as the Visible toggle does.":"This removes it from the Object and Scene Nodes panels and takes it out of the 3D view entirely, for every viewer, not just hidden, as the Visible toggle does."}),ne("p",{className:"bb-reset-warning",children:"This action cannot be undone!"})]}),ge("div",{className:"bb-reset-footer",children:[ne("button",{className:"bb-reset-btn",onClick:a,children:"Cancel"}),ne("button",{className:"bb-reset-btn-danger",onClick:i,children:"Delete"})]})]})})}function qp({destinations:e,onCancel:t,onChoose:a}){let[i,n]=Zh(e.find(c=>c.isActive)?.url??e[0]?.url??""),o=e.find(c=>c.url===i),d=pa(),l=pa();return ne("div",{className:"bb-reset-overlay",onClick:t,children:ge("div",{className:"bb-reset-dialog",role:"dialog","aria-modal":"true","aria-labelledby":d,onClick:c=>c.stopPropagation(),children:[ge("div",{className:"bb-reset-header",children:[ge("h3",{className:"bb-reset-title",id:d,children:[ne(Xh,{size:20,className:"bb-icon-restore"}),"Add Model"]}),ne("button",{className:"bb-reset-close",onClick:t,children:ne(ba,{size:20})})]}),ge("div",{className:"bb-reset-body",children:[ne("p",{className:"bb-reset-message",children:"Add this as a separate model or add its nodes to an existing model?"}),ne("p",{className:"bb-reset-details",children:"A separate model stays independent and switchable, with its own entry in Scene Nodes. Adding its nodes combines it with the destination selected below."}),ne("label",{className:"bb-label",htmlFor:l,children:"Destination model for added nodes"}),ne("select",{className:"bb-select",id:l,value:i,onChange:c=>n(c.target.value),children:e.map(c=>ge("option",{value:c.url,children:[c.label,": ",c.name,c.isActive?" (active)":""]},c.url))})]}),ge("div",{className:"bb-reset-footer",children:[ne("button",{className:"bb-reset-btn",onClick:t,children:"Cancel"}),ne("button",{className:"bb-reset-btn-secondary",onClick:()=>a({mode:"separate"}),children:"Add as Separate Model"}),ne("button",{className:"bb-reset-btn-restore",disabled:!o,title:o?`Add nodes to ${o.name}`:void 0,onClick:()=>o&&a({mode:"merge",targetUrl:i}),children:"Add Nodes"})]})]})})}function Up({options:e,onCancel:t,onRemoveModel:a,onRemoveMerge:i,onRemoveAll:n,permanent:o=!1}){let d=pa(),l=pa();return ne("div",{className:"bb-reset-overlay",onClick:t,children:ge("div",{className:"bb-reset-dialog",role:"dialog","aria-modal":"true","aria-labelledby":d,onClick:c=>c.stopPropagation(),children:[ge("div",{className:"bb-reset-header",children:[ge("h3",{className:"bb-reset-title",id:d,children:[ne(Zr,{size:20,className:"bb-icon-warning"}),"Remove Model"]}),ne("button",{className:"bb-reset-close",onClick:t,children:ne(ba,{size:20})})]}),ge("div",{className:"bb-reset-body",children:[ne("p",{className:"bb-reset-message",children:"Which model do you want to remove?"}),ne("p",{className:"bb-reset-details",children:"Selecting a model below removes its bindings, transforms, and any nodes merged into it. Removing one entry keeps the remaining models."}),ne("div",{className:"bb-removeModelList",children:e.map(c=>c.kind==="model"?ge("button",{type:"button",className:"bb-removeModelOption",onClick:()=>a(c.url),children:[ge("span",{className:"bb-removeModelOptionLabel",children:[c.label,c.isActive&&ne("span",{className:"bb-removeModelOptionActive",children:"active"})]}),ne("span",{className:"bb-removeModelOptionName",children:c.name})]},c.url):ge("button",{type:"button",className:"bb-removeModelOption bb-removeModelOptionMerge",onClick:()=>i(c.url),children:[ge("span",{className:"bb-removeModelOptionLabel",children:[c.label,ge("span",{className:"bb-removeModelOptionActive",children:["merged into ",c.ownerLabel]})]}),ne("span",{className:"bb-removeModelOptionName",children:c.name})]},c.url))}),ne("p",{className:"bb-reset-warning",id:l,children:o?"Removing a model removes it for everyone in this project and deletes its stored file unless another project uses it. This frees its storage and cannot be undone.":"Remove All Models removes every model and its edits, including merged nodes. This also clears the saved session in this browser and cannot be undone. Export your work first if you want to keep it."})]}),ge("div",{className:"bb-reset-footer",children:[ne("button",{className:"bb-reset-btn",onClick:t,children:"Cancel"}),n?ne("button",{className:"bb-reset-btn-danger","aria-describedby":l,onClick:n,children:"Remove All Models"}):null]})]})})}import{strToU8 as ex}from"fflate";function Kp(e){return JSON.stringify(e,null,2)}function Gp(e){return['import { defineObjectBindings } from "@liveroom-tech/react-immersive/utils";',"",`export const objectBindings = defineObjectBindings(${JSON.stringify(e,null,2)});`,""].join(`
2
+ `)}function _p(e){return JSON.stringify(e,null,2)}function Wp(e){return['import type { SceneConfig } from "@liveroom-tech/react-immersive/utils";',"",`export const sceneConfig: SceneConfig = ${JSON.stringify(e,null,2)};`,""].join(`
3
+ `)}function Yp(e,t,a){wo(new Blob([t],{type:a}),e)}function Qr(e){return JSON.stringify(e??{},null,2)}function es(e){return`[${e[0].toFixed(3)}, ${e[1].toFixed(3)}, ${e[2].toFixed(3)}]`}function tx(e){return(e.decals??[]).map(t=>t.image).filter(t=>!!t?.trim())}function nx(e){let t=e.style?.material;return t?Object.values(t).filter(a=>!!a&&typeof a=="object"&&typeof a.path=="string"&&a.path.trim().length>0).map(a=>a.path):[]}async function Jp(e){let t=new Set;for(let a of Object.values(e)){for(let i of nx(a))t.add(i);for(let i of tx(a))t.add(i)}return Zp(t)}async function Xp(e){let t=new Set,a=e.background?.imageUrl?.trim();return a&&t.add(a),Zp(t)}async function Zp(e){let t=[],a=[];return await Promise.all(Array.from(e).map(async i=>{let n=en(i);if(n)try{let o=await fetch(n);if(!o.ok)throw new Error(String(o.status));t.push({path:i,blob:await o.blob()});return}catch{a.push(i);return}try{let o=await un(i);o&&t.push({path:i,blob:o})}catch{}})),{assets:t,failedPaths:a}}async function ua(e,t,a,i,n){if(n.length===0){Yp(e,t,a);return}let o={[e]:ex(t)};for(let l of n)o[l.path]=new Uint8Array(await l.blob.arrayBuffer());let d=await Va(o);wo(new Blob([d],{type:"application/zip"}),i)}async function ai(e){let t=e.background?.imageUrl?.trim();if(t)try{let a=await un(t);a&&Yt(t,URL.createObjectURL(a))}catch(a){console.warn("[BindingBuilder] Could not rehydrate the background image:",a)}}async function jo(e){return await Promise.all(Object.entries(e).map(async([t,a])=>{for(let n of a.decals??[])if(n.image)try{let o=await un(n.image);o&&Yt(n.image,URL.createObjectURL(o))}catch(o){console.warn(`[BindingBuilder] Could not rehydrate a decal image on "${t}":`,o)}let i=a.style?.material;if(i)for(let n of Ol){let d=i[n]?.path;if(d)try{let l=await un(d);if(!l){console.warn(`[BindingBuilder] No stored texture found for "${t}"'s ${n} ("${d}"). If this is meant to be an uploaded file rather than a hosted URL, it was uploaded before texture autosave existed (or this browser's storage was cleared) \u2014 re-upload it once so it's stored for future restores.`);continue}let c=URL.createObjectURL(l);Yt(d,c)}catch(l){console.warn(`[BindingBuilder] Could not rehydrate "${t}"'s ${n}:`,l)}}})),e}async function Qp(e){let t=new Set,a=new WeakSet;function i(n,o=0){if(!(!n||typeof n!="object"||a.has(n)||o>64)){a.add(n);for(let[d,l]of Object.entries(n))d!=="metadata"&&(d==="path"&&typeof l=="string"&&l?t.add(l):i(l,o+1))}}return i(e),await Promise.all([...t].map(async n=>{let o=await un(n);o&&Yt(n,URL.createObjectURL(o))})),e}function eb({bindings:e,setBindings:t,sceneConfig:a,setSceneConfig:i,nodeKeys:n,sceneConfigInputRef:o,setIsExporting:d,setStatusMessage:l,setStatusTone:c}){let w=x=>y("bindings",()=>Jp(e),C=>x==="json"?ua("objectBindings.json",Kp(e),"application/json","objectBindings.zip",C):ua("objectBindings.ts",Gp(e),"text/typescript","objectBindings-ts.zip",C)),h=x=>y("scene config",()=>Xp(a),C=>x==="json"?ua("sceneConfig.json",_p(a),"application/json","sceneConfig.zip",C):ua("sceneConfig.ts",Wp(a),"text/typescript","sceneConfig-ts.zip",C)),y=async(x,C,S)=>{d(!0);try{let{assets:f,failedPaths:k}=await C();await S(f),k.length>0?(l(`Exported, but ${k.length} uploaded image${k.length===1?"":"s"} couldn't be bundled: ${k.join(", ")}.`),c("error")):f.length>0&&(l(`Exported with ${f.length} uploaded image${f.length===1?"":"s"} bundled into the zip.`),c("success"))}catch(f){let k=f instanceof Error?f.message:"Unknown export error.";l(`Failed to export ${x}: ${k}`),c("error")}finally{d(!1)}},u=async x=>{if(!n.length){l("Load a model before importing bindings."),c("error");return}let C;try{C=JSON.parse(await x.text())}catch{l(`${x.name} is not valid JSON.`),c("error");return}if(C===null||typeof C!="object"||Array.isArray(C)){l("Expected a JSON object mapping object IDs to bindings."),c("error");return}let S=new Map;for(let M of Object.values(C))if(M!==null&&typeof M=="object"&&typeof M.id=="string"&&typeof M.type=="string"&&typeof M.modelObjectId=="string"){let j=M;S.set(j.modelObjectId,j)}if(S.size===0){l(`${x.name} doesn't look like an exported bindings file.`),c("error");return}let f={...e},k={},O=0;for(let M of Object.keys(f)){let j=S.get(M);j&&(f[M]=j,k[M]=j,O++)}if(O===0){l(`None of the object IDs in ${x.name} match this model \u2014 nothing imported.`),c("error");return}let p=await jo(k);Object.assign(f,p),t(f);let r=S.size-O;l(r>0?`Imported ${O} binding${O===1?"":"s"} from ${x.name} (${r} skipped \u2014 not in this model).`:`Imported ${O} binding${O===1?"":"s"} from ${x.name}.`),c("success")},g=async x=>{let C=x.target.files?.[0];C&&(await u(C),x.target.value="")},B=()=>{o.current?.click()},v=async x=>{let C;try{C=JSON.parse(await x.text())}catch{l(`${x.name} is not valid JSON.`),c("error");return}if(C===null||typeof C!="object"||Array.isArray(C)){l("Expected a JSON object with scene config sections."),c("error");return}let S=["model","camera","lighting","wireframe","shadows","environment","background","groundShadows","postProcessing","animations","annotations","cinematic","styleRules","section","measurements","selectionSets"],f=C;if(f.section!==void 0)try{f.section=La(a.section,f.section)}catch(O){l(O instanceof Error?O.message:String(O)),c("error");return}if(f.selectionSets!==void 0)try{f.selectionSets=So(f.selectionSets)}catch(O){l(O instanceof Error?O.message:String(O)),c("error");return}if(f.measurements!==void 0)try{f.measurements=za(f.measurements)}catch(O){l(O instanceof Error?O.message:String(O)),c("error");return}let k=S.filter(O=>f[O]!==void 0);if(k.length===0){l(`${x.name} doesn't look like an exported scene config file.`),c("error");return}k.includes("background")&&f.background&&await ai({background:f.background}),i(O=>{let p={...O};for(let r of k)p[r]=r==="measurements"||r==="section"?f[r]:ta(O[r],f[r]);return p}),l(`Imported ${k.length} section${k.length===1?"":"s"} from ${x.name}.`),c("success")};return{handleExportBindings:w,handleExportSceneConfig:h,importBindingsFile:u,handleImportBindingsChange:g,openSceneConfigImportPicker:B,importSceneConfigFile:v,handleImportSceneConfigChange:async x=>{let C=x.target.files?.[0];C&&(await v(C),x.target.value="")}}}var ts={pbr:["texture","baseColor","metalness","metalnessMap","specularIntensity","specularIntensityMap","specularColor","specularColorMap","reflectivity"],roughness:["roughness","roughnessMap"],emission:["emissive","emissiveIntensity","emissiveMap"],opacity:["opacity","alphaMap","alphaTest","alphaHash","dithering","blendingMode"],normalBump:["normalMap","normalScale","flipNormalY","bumpMap","bumpScale"],displacement:["displacementMap","displacementScale","displacementBias"],ao:["aoMap","aoMapIntensity"],clearcoat:["clearcoat","clearcoatMap","clearcoatRoughness","clearcoatRoughnessMap","clearcoatNormalMap","clearcoatNormalScale","flipClearcoatNormalY"],sheen:["sheen","sheenColor","sheenColorMap","sheenRoughness","sheenRoughnessMap"],anisotropy:["anisotropy","anisotropyRotation","anisotropyMap"],transmission:["transmission","transmissionMap","thickness","thicknessMap","attenuationColor","attenuationDistance"],faces:["side"]},tb=Object.keys(ts);function nb(e){if(e==null)return!1;if(typeof e=="string")return e.trim().length>0;if(typeof e=="number")return Number.isFinite(e);if(typeof e=="boolean")return e;if(typeof e=="object"&&"path"in e){let t=e.path;return typeof t=="string"&&t.trim().length>0}return!1}function ns(e){if(e)return Object.values(e).some(nb)?e:void 0}function Kt(e,t){return e?ts[t].some(a=>nb(e[a])):!1}function os(e){return{pbr:Kt(e,"pbr"),roughness:Kt(e,"roughness"),emission:Kt(e,"emission"),opacity:Kt(e,"opacity"),normalBump:Kt(e,"normalBump"),displacement:Kt(e,"displacement"),ao:Kt(e,"ao"),clearcoat:Kt(e,"clearcoat"),sheen:Kt(e,"sheen"),anisotropy:Kt(e,"anisotropy"),transmission:Kt(e,"transmission"),faces:Kt(e,"faces")}}function as(e,t){if(t)return{...e,style:{...e.style,material:t}};if(!e.style)return e;let{material:a,...i}=e.style;return{...e,style:Object.keys(i).length>0?i:void 0}}function ob(e,t){if(!e)return;let a={...e};for(let i of ts[t])delete a[i];return a}import{Fragment as Hn,jsx as q,jsxs as Te}from"react/jsx-runtime";var ib="/room.glb";function is(){return`${Date.now().toString(36)}-${Math.random().toString(36).slice(2,10)}`}function rb(e){return`Couldn't reload ${e} from your last session. It's still saved in this browser.`}function cx({label:e,values:t,onChange:a}){let i=t.length>0&&t.every(Boolean),n=!i&&t.some(Boolean);return Te("label",{className:"bb-groupFlag",children:[q("input",{type:"checkbox",ref:o=>{o&&(o.indeterminate=n)},checked:i,onChange:o=>a(o.target.checked)}),e]})}function px({licenseKey:e,licenseValidationUrl:t,arHandoff:a=!0,mobileHandoffUrl:i,dracoDecoderPath:n,ktx2TranscoderPath:o,meshopt:d,project:l,onProjectChange:c,projectChangeDebounceMs:w=350,onModelUpload:h,onTextureUpload:y,onEditLeaseChange:u,allowModelChange:g=!0,hideLicenseCheckingOverlay:B=!1}){let v=de(null),P=de(null),x=de(null),C=de(null),S=de(null),[f]=_(()=>l?nr(l):null),[k,O]=_(f?.url??null),[p,r]=_(()=>l?l.models.filter(s=>s!==f).map(ar):[]),[M,j]=_(()=>l?l.models.map(s=>s.url):[]),[R,E]=_(f?.name??""),[z,pe]=_(f),Ce=ct(()=>l&&M.length>1&&z?.tilesetUrl?{...z,tilesetUrl:null}:z,[l,M.length,z]),fe=de(l?ir(l):new Map),{selectedItem:I,setSelectedItem:Q,multiSelectMode:G,setMultiSelectMode:L,multiSelectedKeys:ae,setMultiSelectedKeys:tt,groupSelectionActive:me,selectObject:St,setSelection:$n,toggleMultiSelect:Eo,exitMultiSelect:A,clearSelection:J}=Np(),pt=de({mode:!1,keys:[]}),be=de({shiftKey:!1,ctrlKey:!1,metaKey:!1}),[qe,ma]=_(null);pt.current={mode:me,keys:ae};let re=Sp(f?.objectBindings??{}),X=re.value,Vn=re.setValue,ii=de("free");Mp({bindings:X,multiSelectMode:me,selectedItem:I,multiSelectedKeys:ae,setSelectedItem:Q,setMultiSelectedKeys:tt});let Je=re.mergeSources,vn=re.setMergeSourcesUntracked;dt(()=>{f?.mergeModels?.length&&vn(Mo(f))},[f,vn]);let[Ie,sn]=_(!1),[ga,Io]=_(null),sb=ct(()=>ga?{target:ga}:null,[ga]);dt(()=>{Io(null)},[k]),dt(()=>{L(!1),tt([])},[k]);let[fa,Sn]=_(null);dt(()=>Sn(null),[I,k]),dt(()=>{hi(null),yi(null)},[k]);let[lb,qn]=_(null),[rs,db]=_(!1),[ss,Z]=_("Load the demo model or upload a GLB, GLTF, OBJ, FBX, USDZ, STL, or PLY model to generate bindings."),[ha,te]=_("default"),[cb,Do]=_(!1),[ls,xa]=_("{}"),[ds,ya]=_("{}"),[pb,va]=_(null),[bb,Sa]=_(null),[ub,Lo]=_(!1),[ro,cs]=_(!1),[mb,gb]=_(!1),[Xt,ps]=_({identity:!0,basics:!0,material:!1,decals:!1,actions:!1,camera:!1,transform:!1,metrics:!1,metadata:!1}),[fb,hb]=_({pbr:!1,roughness:!1,emission:!1,opacity:!1,normalBump:!1,displacement:!1,ao:!1,clearcoat:!1,sheen:!1,anisotropy:!1,transmission:!1,faces:!1}),Zt=s=>ps(b=>({...b,[s]:!b[s]})),xb=s=>hb(b=>({...b,[s]:!b[s]})),[ln,zo]=_("object"),[wn,ri]=_("General"),[bs,yb]=_(null),[us,ms]=_(!1),gs=ie(()=>{cs(!1),zo("scene"),ri("General"),ms(!0)},[]),[vb,Sb]=_("metalness"),[wb,si]=_(os()),fs=de(null),[hs,Cb]=_(!1),[li,kb]=_(!0),[di,Mb]=_(!0),[Nb,xs]=_(!1),[Fo,ys]=_(null),[Un,ci]=_(null),[Tb,pi]=_(!1),wa=de(null),Ca=de({modelUrl:k,modelName:R,modelOrder:M,parkedModels:p});Ca.current={modelUrl:k,modelName:R,modelOrder:M,parkedModels:p};let[Pb,so]=_(!1),[Cn,bi]=_(null),[ui,vs]=_(!1),[Ss,ws]=_(!1),[Cs,Bb]=_("world"),jt=de({}),Fe=na(l&&f?_a(l.sceneConfig,f):Tn),Xe=na(l?or(l):_n),[ks,lo]=_([]),wt=ct(()=>({...Xe.value,placements:{...Object.fromEntries(ks.map(s=>[s,{deleted:!0}])),...Xe.value.placements}}),[Xe.value,ks]),[co,po]=_(!1),Ms=de(null),Ae=Fe.value,Ho=Fe.setValue,Rb=ie(s=>{let b=So(s);Fe.setValueAsStep(m=>({...m,selectionSets:b}))},[Fe.setValueAsStep]),ka=Fe.setValueUntracked,mi=ie(s=>{let b=mt(Ae,s.modelSettings);s.sceneHistory?Fe.restoreSnapshot({...s.sceneHistory,present:b}):Fe.reset(b)},[Ae,Fe.restoreSnapshot,Fe.reset]),{hasEdits:Ab,markSessionEdited:Ct,resetSessionEdits:gi}=Pp(re.edits,Fe.edits+Xe.edits),[kn,Ob]=_(!1),[jb,Eb]=_(.5),[fi,Ib]=_(!0),[bo,hi]=_(null),uo=bo??{bindings:re.baseline,sceneConfig:Fe.baseline},[xi,Db]=_("modelObjectId"),[Ma,yi]=_(null),$o=ct(()=>kn?td({objectBindings:uo.bindings,sceneConfig:uo.sceneConfig},{objectBindings:X,sceneConfig:Ae},{matchBy:xi}):null,[kn,uo.bindings,uo.sceneConfig,X,Ae,xi]),Ns=ct(()=>$o&&fi?{before:Ji($o,"before",Ma),after:Ji($o,"after",Ma)}:null,[$o,Ma,fi]),[Ts,vi]=_("orbit"),[Lb,Ps]=_(!1),Si=de(void 0),wi=ie(()=>{Ps(!0),clearTimeout(Si.current),Si.current=setTimeout(()=>Ps(!1),5e3)},[]);dt(()=>()=>clearTimeout(Si.current),[]),dt(()=>{k&&!Ie&&wi()},[k,Ie,wi]);let it=Ts==="pointerLock",[Bs,zb]=_(null),Rs=de(null),Fb=Bs?.objectKey===I&&Bs?.textureKey==="texture",[Hb,mo]=_(null),[$b,Ci]=_(null),Vo=Vl(e,t),go=zl(Vo.tier);ii.current=go;let As=Hl.models[go],Vb=ct(()=>({isInsideEditor:!0,activeTab:ln,activeSubTab:wn,tier:go,setActiveTab:zo,setActiveSubTab:ri,measurementPanelTarget:bs,setMeasurementPanelTarget:yb,measurementsPanelOpen:us,setMeasurementsPanelOpen:ms,openMeasurementsPanel:gs}),[ln,wn,go,bs,us,gs]),bt=de(null),fo=de(0),Et=de(0),Os=de(l?`${l.id}:${l.revision}`:null),js=de(null),bx=de(!1),Na=de(!1),ki=de(l?Zo(l):null),Mi=de(!1),Ta=de(new Map),Pa=de(void 0),Kn=de(0),rt=de(null),kt=de(l?{requestId:0,modelName:f.name??"model",modelUrl:f.url,storedBindings:f.objectBindings,streaming:!!f.tilesetUrl}:null),st=de(f?{model:{kind:"url",url:f.url,name:f.name??"model"}}:null),Ba=de(new Set),dn=de(new Map);Cp(re.snapshot,p,{modelUrl:k,modelSourceRef:st,uploadedFilesRef:dn});let qo=de(null),qb=de(!1),cn=de(null),It=de(new Map),[Ni,Es]=_(0),Mn=ct(()=>new Map(M.map(s=>{let b=s===k?st.current?.model:p.find(m=>m.url===s)?.sessionModel;return[s,b?tn(b):`url:${s}`]})),[M,k,p]),Uo=s=>wt.placements[Mn.get(s)??`url:${s}`]??{},He=ct(()=>M.map((s,b)=>({id:Mn.get(s)??`url:${s}`,url:s,name:Uo(s).label??(s===k?R:p.find(m=>m.url===s)?.name)??`Asset ${b+1}`,placement:Uo(s),ready:It.current.has(s)})).filter(s=>!s.placement.deleted),[M,k,R,p,wt,Mn,Ni]),Is=Mt(go,"models",He.length),[Ti,Ub]=_(!1),[Ds,Ls]=_(null),[Kb,zs]=_(null),Gb=ie(()=>{let s=k?It.current.get(k):void 0;!s||!k||Ls({url:k,report:Pl(s,{source:{...Tl(s),name:R},scope:Ce?.tilesetUrl?"resident-tiles":"asset"})})},[k,R,Ce?.tilesetUrl]);dt(()=>{zs(null)},[k,Ti]);let{materialVariantGroups:_b,objectsWithoutUvs:Fs,hierarchy:Wb}=Ap({modelUrl:k,scenesRef:It,sceneRevision:Ni,streaming:!!Ce?.tilesetUrl});dt(()=>{let s=new Set(He.map(b=>b.url));for(let b of It.current.keys())s.has(b)||It.current.delete(b)},[He]),Rp({enabled:!Ce?.tilesetUrl,modelUrl:k,bindings:X,mergeSources:Je,parkedModels:p,scenesRef:It,sceneRevision:Ni,setBindings:re.setValueUntracked,setParkedModels:r});let ho=de(null),[Yb,Jb]=_(null),[Hs,Xb]=_({}),Zb=ct(()=>{if(!me||ae.length===0||!ho.current)return null;let b=ae.filter(m=>X[m]&&!X[m].removed).map(m=>Hs[m]).filter(m=>!!m);return b.length>0?b:null},[me,ae,Hs,X]),{cameraState:$e,resetView:$s,focusObject:Vs,fitScene:qs,setCameraState:Ra,handleCameraChange:Qb,handleViewerReady:eu}=bl(),tu=ie(s=>{it||Ra({position:s.position,target:s.target,fov:s.fov??$e?.fov??null,zoom:s.zoom??$e?.zoom??1,azimuthAngle:s.azimuthAngle,polarAngle:s.polarAngle},!0)},[it,Ra,$e]),Gt=ad(),nu=ct(()=>He.map(s=>s.url),[He]),xo=Ld(nu),Us=Fd({modelUrl:k,sceneConfig:Ae,setSceneConfig:Ho,setSceneConfigUntracked:ka,parkedModels:p,setParkedModels:r,animations:xo,markSessionEdited:Ct}),De=I?X[I]??null:null,Pi=De?.style?.material,Ks=!Fs.has(De?.modelObjectId??I??""),ou=ct(()=>{if(!(He.length<2))return He.map(s=>({url:s.url,label:s.name,bindings:s.url===k?X:p.find(b=>b.url===s.url)?.bindings??{},isActive:s.url===k}))},[He,k,X,p]),Ko=ct(()=>{let s=[];return He.forEach((b,m)=>{let N=b.url,T=N===k,F=T?void 0:p.find(Y=>Y.url===N),$=b.name||`Asset ${m+1}`;s.push({kind:"model",url:N,label:$,name:T?R:F?.name??"Untitled model",isActive:T}),(T?Je:F?.mergedModelSources??[]).forEach(Y=>{s.push({kind:"merge",url:Y.url,label:"Merged nodes",name:an(Y.namePrefix),ownerLabel:$})})}),l&&He.length<2?s.filter(b=>b.kind!=="model"):s},[l,He,k,R,p,Je]),Bi=ct(()=>Je.map(s=>({url:s.url,namePrefix:s.namePrefix})),[Je]),Gs=ct(()=>(l?M.length<2:M.length<1)?void 0:M.map((b,m)=>{let N=wt.placements[Mn.get(b)??`url:${b}`]??{},T={transform:N,visible:N.visible!==!1&&!N.deleted,label:N.label};if(b===k)return{url:b,label:T.label??(R||`Model ${m+1}`),transform:T.transform,visible:T.visible,objectBindings:X,originalNodePoses:jt.current,mergeModels:Bi};let $=p.find(U=>U.url===b);return{url:b,label:T.label??($?.name||`Model ${m+1}`),transform:T.transform,visible:T.visible,objectBindings:$?.bindings??{},originalNodePoses:$?.originalTransforms,sceneConfig:mt(Ae,$?.modelSettings),mergeModels:($?.mergedModelSources??[]).map(U=>({url:U.url,namePrefix:U.namePrefix}))}}).filter(b=>!wt.placements[Mn.get(b.url)??`url:${b.url}`]?.deleted),[l,M,k,R,X,p,Bi,Ae,wt,Mn]);dt(()=>{let s=x.current;if(!s)return;let b=s.querySelector(".ri-modelSwitcher"),m=()=>{let T=kn?48:12,F=b?Math.max(T,b.getBoundingClientRect().bottom-s.getBoundingClientRect().top+8):T;s.style.setProperty("--bb-canvas-hint-top",`${F}px`)};m();let N=new ResizeObserver(m);return N.observe(s),b&&N.observe(b),()=>{N.disconnect(),s.style.removeProperty("--bb-canvas-hint-top")}},[Gs,kn]);let Nn=De?.cameraState,au=$e?{position:es($e.position),target:es($e.target)}:null,iu=ie(s=>{Ho(b=>{let m=b.annotations.map(T=>T.id).join(","),N=s.map(T=>T.id).join(",");return m===N?b:s.length>b.annotations.length&&!Mt(ii.current,"annotations",b.annotations.length)?(Z(`More annotations require the ${Fl[bn("annotations",b.annotations.length)]} plan or higher.`),te("error"),b):{...b,annotations:s}})},[]),ru=ie(s=>{mo(s?{annotation:s}:null)},[]);dt(()=>{if(!De){xa("{}"),ya("{}"),va(null),Sa(null);return}xa(Qr(De.metrics)),ya(Qr(De.metadata)),va(null),Sa(null)},[De]),dt(()=>{let s=os(Pi);if(fs.current!==I){fs.current=I,si(s);return}si(b=>{let m=!1,N={...b};for(let T of tb)s[T]&&!b[T]&&(N[T]=!0,m=!0);return m?N:b})},[I,Pi]),dt(()=>()=>{bt.current?.cleanup(),rt.current&&clearTimeout(rt.current)},[]);let Aa=ie((s,b)=>{let m=Jo(s);if(b){let N=new Map(Object.values(b).map(T=>[T.modelObjectId,T]));for(let T of s){let F=N.get(T);F&&(m[T]=F)}}return m},[]);dt(()=>{if(!l)return;let s=`${l.id}:${l.revision}`;if(Os.current===s)return;Os.current=s,fe.current=ir(l);let b=l.models.find(oe=>oe.url===k),m=b&&!l.composition.placements[Xn(b.url)]?.deleted?b:nr(l),N=_a(l.sceneConfig,m),T=k!==m.url||z?.tilesetUrl!==m.tilesetUrl||z?.assetVersion!==m.assetVersion,F=!Wa(X,m.objectBindings),$=!Wa(Ae,N);pe(m),E(m.name??"model");let U=m.objectBindings;if(F){let oe=js.current;U=oe?Aa(oe,m.objectBindings):m.objectBindings,re.reset(U)}else U=X;$&&Fe.reset(N),r(oe=>l.models.filter(ke=>ke.url!==m.url).map(ke=>{let Ge=oe.find(Pe=>Pe.url===ke.url);if(!Ge)return ar(ke);let pn=JSON.stringify(Ge.mergedModelSources.map(Pe=>Pe.url))===JSON.stringify((ke.mergeModels??[]).map(Pe=>Pe.url));return{...Ge,name:ke.name??Ge.name,bindings:ke.objectBindings,modelSettings:ke.modelSettings,mergedModelSources:pn?Ge.mergedModelSources:Mo(ke),bindingHistory:pn?Ge.bindingHistory:void 0}})),j(l.models.map(oe=>oe.url));let Y=(m.mergeModels??[]).map(oe=>oe.url);if(JSON.stringify(Je.map(oe=>oe.url))!==JSON.stringify(Y)&&(vn(Mo(m)),re.clearHistory()),Wa(Xe.value,l.composition)||Xe.reset(or(l)),T){Gt.clearAnimations();let oe=++Et.current;kt.current={requestId:oe,modelName:m.name??"model",modelUrl:m.url,storedBindings:m.objectBindings,streaming:!!m.tilesetUrl},st.current={model:{kind:"url",url:m.url,name:m.name??"model"}},cn.current=null,Q(null),sn(!0),O(m.url)}ki.current=Zo({models:l.models.map(oe=>oe===m?{...oe,objectBindings:U}:oe),composition:l.composition,sceneConfig:l.sceneConfig})},[z,X,Aa,Xe,Je,l,k,Ae,re,Fe,vn,Gt.clearAnimations]);let Ri=de(c);Ri.current=c;let _s=de(y);_s.current=y,dt(()=>{if(!l||!Ri.current||!k||kt.current)return;let s=()=>vd({project:l,modelUrl:k,modelName:R,bindings:X,sceneConfig:Ae,mergedModelSources:Je,parkedModels:p,modelOrder:M,composition:wt,sources:fe.current});if(Na.current){Na.current=!1,ki.current=Zo(s());return}let b=window.setTimeout(()=>{if(Mi.current)return;let m=s();if(Zo(m)===ki.current)return;let N=_s.current,T=N?Jn(m.models).size+Jn(m.sceneConfig).size:0;if(N&&T>0){Mi.current=!0;let F=Jn(m.sceneConfig,Jn(m.models));Promise.all([...F].map(async $=>{if(!Ta.current.has($))try{Ta.current.set($,await N(await wd($),$))}catch(U){Z(U instanceof Error?U.message:"Could not save an image."),te("error"),Ta.current.set($,"")}})).then(()=>{Mi.current=!1;let $=U=>Ga(U,Ta.current);re.setValueUntracked($),Fe.setValueUntracked($),r(U=>U.map(Y=>({...Y,bindings:$(Y.bindings),modelSettings:$(Y.modelSettings)})))});return}Ri.current?.(m,"local")},w);return()=>window.clearTimeout(b)},[X,wt,Je,R,M,k,p,l,w,Ae]),dt(()=>{let s=b=>{if(b.key.toLowerCase()!=="z"||!(b.metaKey||b.ctrlKey))return;let m=b.target,N=m?.tagName;if(N==="INPUT"||N==="TEXTAREA"||m?.isContentEditable)return;b.preventDefault();let T=ln==="scene"?wn==="Assets"?Xe:Fe:re;b.shiftKey?T.redo():T.undo()};return window.addEventListener("keydown",s),()=>window.removeEventListener("keydown",s)},[ln,wn,Xe,re,Fe]);let Ai=!l&&g,{handleTextureUpload:su}=kp({composition:wt,autosaveEnabled:Ai,hasEdits:Ab,modelUrl:k,bindings:X,sceneConfig:Ae,parkedModels:p,mergedModelSources:Je,modelOrder:M,onTextureUpload:y,modelSourceRef:st,pendingLoadRef:kt,storedModelKeysRef:Ba,uploadedFilesRef:dn,pendingAutosaveRef:qo,autosaveFailureShownRef:qb,setStatusMessage:Z,setStatusTone:te});dt(()=>{if(Ie||ha==="default"||ha==="success")return;Do(!0);let s=window.setTimeout(()=>Do(!1),4e3);return()=>window.clearTimeout(s)},[ss,ha,Ie]);let Qt=ct(()=>Object.keys(X),[X]),lu=ct(()=>!I||!De?null:De.id.trim()?Object.entries(X).some(([m,N])=>m!==I&&N.id===De.id)?"Another binding already uses this ID.":null:"ID is required.",[X,I,De]),Dt=(s,b)=>{Vn(m=>{let N=pt.current,T=N.mode&&N.keys.includes(s)?N.keys.filter($=>m[$]):[s];if(T.length<=1)return{...m,[s]:b(m[s],s)};let F={...m};for(let $ of T){let U=m[$];F[$]={...b(U,$),id:U.id,modelObjectId:U.modelObjectId}}return F})},Oi=(s,b)=>{Dt(s,m=>{let N=ns(b(m.style?.material));return as(m,N)})},du=(s,b,m)=>{Oi(s,N=>({...N,[b]:m?{path:m}:void 0}))},cu=(s,b)=>{si(m=>({...m,[s]:b})),!b&&I&&Dt(I,m=>{let N=ns(ob(m.style?.material,s));return as(m,N)})},ji=ie((s,b,m)=>{let{bindings:N,originalTransforms:T,nodeNames:F}=ca(s,m);jt.current=T,re.reset(io(s,m??{},Je,N)),Q(F[0]??null),m||ka($=>({...$,annotations:[]})),Z(`Generated ${F.length} bindings from ${b}.`),te("success"),Kn.current=100,qn(100),rt.current&&clearTimeout(rt.current),rt.current=setTimeout(()=>{rt.current=null,sn(!1),qn(null)},400)},[re,ka,Je]),Ei=(s,b,m,N)=>{qo.current?.();let T=++Et.current;gi(),Xe.reset(_n),lo([]),l||Fe.reset(s!==k?mt(Ae):Ae),s!==k&&Gt.clearAnimations(),p.forEach(U=>U.resolved?.cleanup()),r([]),j([s]),vn([]),sn(!0),qn(null),Kn.current=0,rt.current&&(clearTimeout(rt.current),rt.current=null),Pa.current=m;let F=m?m/1048576:0;Z(F>=100?`Reading ${b} (${Math.round(F)}MB \u2014 large file, this can take a while)...`:`Reading ${b} and generating starter bindings...`),te("default"),E(b),pe(N??{url:s,name:b}),mo(null);let $=cn.current;if(s===k&&$?.url===s){kt.current=null,ji($.scene,b);return}kt.current={requestId:T,modelName:b,modelUrl:s,streaming:!!N?.tilesetUrl},O(s),re.reset({}),Q(null)},pu=ie(s=>{k&&It.current.get(k)!==s&&(It.current.set(k,s),Es(m=>m+1));let b=kt.current;if(!(b&&b.requestId!==Et.current)&&(k&&(cn.current={url:k,scene:s}),Sn(null),Io(null),!!b)){if(kt.current=null,b.streaming){Z(`Streaming ${b.modelName}.`),te("success"),sn(!1);return}b.storedBindings&&(Na.current=!0),ji(s,b.modelName,b.storedBindings),b.restoring&&Z(`Restored your last session with ${b.modelName}.`)}},[ji,k]),bu=ie(s=>{if(!Ce?.tilesetUrl)return;let b=s.map(T=>T.name);if(b.length===0)return;js.current=b,Na.current=!0;let m=l?.models.find(T=>T.url===k)?.objectBindings,N=Aa(b,m);re.reset(N),Q(T=>T??b[0]??null),Z(`Streaming ${b.length} bindable objects.`),te("success"),sn(!1)},[Aa,re,k,l,Ce]),uu=ie(s=>{let b=kt.current;if(!(b&&b.requestId!==Et.current)){if(kt.current=null,console.error(s),b?.restoring)st.current=null,O(null),Z(rb(b.modelName));else if(b)Z(Bl(s)?`${b.modelName} is a point cloud: it has points but no faces. Turn it into a mesh first, for example with MeshLab or Blender.`:`Could not read ${b.modelName}. Make sure the file is a valid GLB, GLTF, OBJ, FBX, USDZ, STL, or PLY asset.`);else{let{detail:m}=Fa(s,k??"",bt.current?.format);Z(`Could not read ${R||"the model"}. ${m}`)}te("error"),rt.current&&(clearTimeout(rt.current),rt.current=null),Kn.current=0,sn(!1),qn(null)}},[k,R]),mu=ie(s=>{let b=null;if(s.lengthComputable&&s.total>0)b=s.loaded/s.total*100;else{let N=Pa.current;N&&N>0&&(b=s.loaded/N*100)}if(b===null)return;let m=Math.min(90,Math.floor(b/10)*10);m>Kn.current&&(Kn.current=m,qn(m)),b>=99.5&&Z(N=>N.startsWith("Finalizing")?N:"Finalizing model \u2014 parsing geometry and textures (large files can take a moment here)...")},[]),gu=ie(s=>{Gt.handleAnimationsReady(s),k&&xo.handleModelAnimationsReady(k,s)},[Gt,k,xo.handleModelAnimationsReady]),ux=async()=>{bt.current?.cleanup(),bt.current=null,st.current={model:{kind:"url",url:ib,name:"room.glb"}},await Ei(ib,"room.glb")},Ws=async s=>{if(!g)return;if(s.name.toLowerCase().endsWith(".ri.zip")){await nl(s);return}if(h){try{sn(!0),Z(`Uploading ${s.name}...`),te("default");let N=await h(s);fe.current.set(N.url,N),st.current={model:{kind:"url",url:N.url,name:N.name??s.name}},await Ei(N.url,N.name??s.name,s.size,N)}catch(N){sn(!1),Z(N instanceof Error?N.message:`Could not upload ${s.name}.`),te("error")}return}let b;try{b=await Pn(s)}catch(N){Z(N instanceof Error?N.message:"Could not read model file. Upload a .glb, .gltf, .obj, .fbx, .usdz, .stl, .ply, or .zip asset."),te("error");return}bt.current?.cleanup(),bt.current=b;let m=is();dn.current.set(m,s),st.current={model:{kind:"file",key:m,name:b.name},file:s},await Ei(b.url,b.name,s.size,{url:b.url,name:b.name})},fu=async s=>{let b=s.target.files?.[0];b&&(await Ws(b),s.target.value="")},Oa=()=>{qo.current=null,Ct(),bt.current?.cleanup(),bt.current=null,cn.current=null,kt.current=null,st.current=null,Gt.clearAnimations(),jt.current={},fo.current=0,Lo(!1),rt.current&&(clearTimeout(rt.current),rt.current=null),Kn.current=0,qn(null),Pa.current=void 0,O(null),E(""),p.forEach(s=>s.resolved?.cleanup()),r([]),j([]),Xe.reset(_n),lo([]),vn([]),pe(null),Q(null),mo(null),re.reset({}),xa("{}"),ya("{}"),va(null),Sa(null),Ci(null),vs(!1),ws(!1),ka(s=>mt(s)),Z("Load the demo model or upload a GLB, GLTF, OBJ, FBX, USDZ, STL, or PLY model to generate bindings."),te("default")},Ys=s=>l?{...s,bindingHistory:void 0}:s,hu=()=>{Ko.length>1?so(!0):Oa()},xu=()=>{so(!1)},yu=s=>{if(so(!1),M.length<=1){Oa();return}if(!M.includes(s))return;if(Ct(),s!==k){let F=p.find($=>$.url===s);F?.resolved?.cleanup(),r($=>$.filter(U=>U.url!==s)),j($=>$.filter(U=>U!==s)),Z(`Removed ${F?.name??"the model"}.`),te("success");return}let b=M.filter(F=>F!==s),m=b[0],N=p.findIndex(F=>F.url===m),T=p[N];if(!T){Oa();return}bt.current?.cleanup(),r(F=>F.filter(($,U)=>U!==N)),j(b),bt.current=T.resolved??null,st.current={model:T.sessionModel??{kind:"url",url:T.url,name:T.name}},cn.current=null,kt.current=null,jt.current=T.originalTransforms,Gt.clearAnimations(),mi(T),O(T.url),E(T.name),pe(fe.current.get(T.url)??{url:T.url,name:T.name}),re.restoreModel(T),Q(Object.keys(T.bindings)[0]??null),mo(null),Z(`Removed the model \u2014 now viewing ${T.name}.`),te("success")},vu=s=>{so(!1);let b=Je.find(T=>T.url===s);if(b){Ct(),re.removeMerge(s),l&&re.clearHistory(),Z(`Removed ${an(b.namePrefix)}.`),te("success");return}let m=p.find(T=>T.mergedModelSources.some(F=>F.url===s));if(!m)return;let N=m.mergedModelSources.find(T=>T.url===s);N&&(Ct(),r(T=>T.map(F=>F.url!==m.url?F:Ys(Gr(F,$=>Kr($,s))))),Z(`Removed ${an(N.namePrefix)}.`),te("success"))},Su=()=>{v.current?.click()},Js=()=>{pi(!0)},wu=s=>{let b=s.target.files?.[0];s.target.value="";let m=wa.current;wa.current=null,!(!b||!g||!m)&&(m.mode==="separate"?Mu(b):Nu(b,m.targetUrl))},Cu=ie(()=>{wa.current=null,pi(!1)},[]),ku=ie(s=>{wa.current=s,pi(!1),P.current?.click()},[]),Ii=ie(async s=>{if(l&&h){Z(`Uploading ${s.name}...`),te("default");let N=await h(s);fe.current.set(N.url,N);let T=N.name??s.name;return{resolved:{url:N.url,name:T,format:"glb",cleanup:()=>{}},sessionModel:{kind:"url",url:N.url,name:T}}}let b=await Pn(s),m=is();return dn.current.set(m,s),{resolved:b,sessionModel:{kind:"file",key:m,name:b.name}}},[l,h]),Mu=ie(async s=>{if(!Mt(ii.current,"models",Ca.current.modelOrder.length)){Z("Your plan has no room for another model in this project. Upgrade to add more."),te("error");return}let b,m;try{({resolved:b,sessionModel:m}=await Ii(s))}catch(N){Z(N instanceof Error?N.message:"Could not read model file. Upload a .glb, .gltf, .obj, .fbx, .usdz, or .zip asset."),te("error");return}r(N=>[...N,{url:b.url,name:b.name,bindings:{},originalTransforms:{},resolved:b,sessionModel:m,mergedModelSources:[]}]),j(N=>[...N,b.url]),Ct(),Z(`Added ${b.name} as a separate model.`),te("success")},[Ct,Ii]),Nu=ie(async(s,b)=>{let m,N;try{({resolved:m,sessionModel:N}=await Ii(s))}catch(Y){Z(Y instanceof Error?Y.message:"Could not read model file. Upload a .glb, .gltf, .obj, .fbx, .usdz, or .zip asset."),te("error");return}let T=Ca.current,F=T.parkedModels.find(Y=>Y.url===b);if(!T.modelOrder.includes(b)||b!==T.modelUrl&&!F){m.cleanup(),Z("The destination model was removed. Choose a model and add the file again."),te("error");return}let $={url:m.url,resolved:m,sessionModel:N,nodeNames:[],loadState:"loading"};b===T.modelUrl?(re.addMerge(Y=>({...$,namePrefix:qr(m.name,Y.mergeSources,Y.bindings)})),l&&re.clearHistory()):r(Y=>{let oe=Y.findIndex(Ge=>Ge.url===b);if(oe===-1)return Y;let ke=[...Y];return ke[oe]=Ys(Gr(ke[oe],Ge=>({...Ge,mergeSources:[...Ge.mergeSources,{...$,namePrefix:qr(m.name,Ge.mergeSources,Ge.bindings)}]}))),ke});let U=b===T.modelUrl?T.modelName:F?.name;Ct(),Z(`Merging ${m.name} into ${U||"the model"}...`),te("default")},[re.addMerge,Ct]),Tu=ie((s,b)=>{let m=Je.find(Y=>Y.url===s);if(m){let{bindings:Y,originalTransforms:oe,nodeNames:ke}=Ur(b,X);re.hydrateMerge(s,{nodeNames:ke,loadState:"loaded"},Y),jt.current={...jt.current,...oe},Z(`Merged ${ke.length} node${ke.length===1?"":"s"} from ${m.namePrefix||"the added model"} into ${R||"the model"}.`),te("success");return}let N=p.find(Y=>Y.mergedModelSources.some(oe=>oe.url===s));if(!N)return;let T=N.mergedModelSources.find(Y=>Y.url===s);if(!T)return;let{bindings:F,originalTransforms:$,nodeNames:U}=Ur(b,N.bindings);r(Y=>Y.map(oe=>oe.url!==N.url?oe:{..._r(oe,s,{nodeNames:U,loadState:"loaded"},F),originalTransforms:{...oe.originalTransforms,...$}})),Z(`Merged ${U.length} node${U.length===1?"":"s"} from ${T.namePrefix||"the added model"} into ${N.name||"the model"}.`),te("success")},[re.hydrateMerge,R,Je,X,p]),Pu=ie((s,b)=>{let m=Je.find(T=>T.url===s)??p.flatMap(T=>T.mergedModelSources).find(T=>T.url===s);if(!m)return;re.hydrateMerge(s,{loadState:"failed"}),r(T=>T.map(F=>F.mergedModelSources.some($=>$.url===s)?_r(F,s,{loadState:"failed"}):F));let{detail:N}=Fa(b,s,m.resolved.format);Z(`Could not merge ${m.resolved.name}. ${N} Remove the failed file using the Remove model menu.`),te("error")},[Je,p,re.hydrateMerge]),Bu=ie((s,b)=>{let m=p.find(T=>T.url===s);if(!m)return;let{detail:N}=Fa(b,s,m.resolved?.format);Z(`Could not read ${m.name}. ${N} Remove the failed file using the Remove model menu.`),te("error")},[p]),Ru=ie((s,b)=>{It.current.get(s)!==b&&(It.current.set(s,b),Es(m=>m+1)),r(m=>{let N=m.findIndex(U=>U.url===s);if(N===-1)return m;let{bindings:T,originalTransforms:F}=ca(b,m[N].bindings),$=[...m];return $[N]={...vp($[N],T),bindings:io(b,m[N].bindings,m[N].mergedModelSources,T),originalTransforms:{...F,...m[N].originalTransforms}},$})},[]),yo=ie(s=>{if(s===k)return;let b=p.findIndex(T=>T.url===s);if(b===-1)return;let m=p[b];qo.current?.(),Ct();let N=k?{url:k,name:R,bindings:X,originalTransforms:jt.current,resolved:bt.current??void 0,sessionModel:st.current?.model,mergedModelSources:Je,modelSettings:Bn(Ae),bindingHistory:re.snapshot,sceneHistory:Fe.snapshot}:null;r(T=>{let F=T.filter(($,U)=>U!==b);return N?[...F,N]:F}),bt.current=m.resolved??null,st.current={model:m.sessionModel??{kind:"url",url:m.url,name:m.name}},cn.current=null,kt.current=null,Gt.clearAnimations(),mi(m),jt.current=m.originalTransforms,O(m.url),E(m.name),pe(fe.current.get(m.url)??{url:m.url,name:m.name}),re.restoreModel(m),Q(Object.keys(m.bindings)[0]??null),mo(null)},[k,R,X,p,re,Je,Ae,Fe,mi,Gt.clearAnimations,Ct]),Au=()=>{C.current?.click()};dt(()=>{k&&He.length&&!He.some(s=>s.url===k)&&yo(He[0].url)},[k,He,yo]);let{handleExportBindings:Xs,handleExportSceneConfig:Zs,handleImportBindingsChange:Ou,openSceneConfigImportPicker:ju,handleImportSceneConfigChange:Eu}=eb({bindings:X,setBindings:Vn,sceneConfig:Ae,setSceneConfig:Ho,nodeKeys:Qt,sceneConfigInputRef:S,setIsExporting:db,setStatusMessage:Z,setStatusTone:te}),Iu=s=>{s.preventDefault(),s.stopPropagation(),!(Ie||k)&&(fo.current+=1,Lo(!0))},Du=s=>{s.preventDefault(),s.stopPropagation(),!(Ie||k)&&(s.dataTransfer.dropEffect="copy",Lo(!0))},Lu=s=>{s.preventDefault(),s.stopPropagation(),!(Ie||k)&&(fo.current=Math.max(0,fo.current-1),fo.current===0&&Lo(!1))},zu=async s=>{if(s.preventDefault(),s.stopPropagation(),fo.current=0,Lo(!1),Ie||k)return;let b=s.dataTransfer.files?.[0];b&&await Ws(b)},Qs=(s,b,m)=>{if(!I)return;let N;try{N=JSON.parse(b)}catch{m("Invalid JSON");return}if(N===null||typeof N!="object"||Array.isArray(N)){m("Expected a JSON object");return}if(s==="metrics"&&Object.values(N).some(F=>typeof F!="number"||!Number.isFinite(F))){m("Metrics values must be numbers");return}Dt(I,T=>({...T,[s]:N})),m(null)},el=ie((s,b)=>{Ai&&ko(s,b).catch(m=>console.warn("[BindingBuilder] Could not store decal image for autosave:",m))},[Ai]),Fu=ct(()=>{let s=cn.current?.scene,m=(s&&I?_o(s,I):null)?.geometry;if(!m)return .2;m.boundingBox||m.computeBoundingBox();let N=m.boundingBox?.getSize(new ox),T=N?Math.max(N.x,N.y,N.z):0;return T>0&&Number.isFinite(T)?T/3:.2},[I,k,Ie]),Hu=ct(()=>{if(!fa?.moving)return null;let{nodeKey:s,decal:b}=fa,m=X[s],N=m?.decals?.find(T=>T.id===b.id);return N?{objectId:m.modelObjectId??s,decal:N,onCancel:()=>Sn(null),onCommit:T=>{Vn(F=>{let $=F[s];return $?{...F,[s]:{...$,decals:$.decals?.map(U=>U.id===N.id?{...U,...T}:U)}}:F}),Sn(null)}}:null},[X,fa,Vn]),$u=ie((s,b)=>{if(!I)return;let m=X[I],N=m?.decals?.find(U=>U.id===s);if(!N)return;let T=ho.current,F=T?.raw.nodes[m.modelObjectId??I],$=Jl(F,T?.raw.controls.camera,N,b);if(!$){Z("No visible surface in that direction. Try another arrow or rotate the view."),te("error"),Do(!0);return}Sn(null),Do(!1),Dt(I,U=>({...U,decals:U.decals?.map(Y=>Y.id===s?{...Y,...$}:Y)}))},[X,I,Dt]),Vu=ie(s=>{if(!s||s.moving){Sn(s);return}let b=ho.current,m=X[s.nodeKey],N=b?.raw.nodes[m?.modelObjectId??s.nodeKey],T=Yl(N,b?.raw.controls.camera);if(!T){Z("Could not find a surface on this object for the decal."),te("error"),Do(!0);return}let F={...s.decal,...T};Vn($=>{let U=$[s.nodeKey];if(!U)return $;let Y=(U.decals??[]).filter(oe=>oe.id!==F.id);return{...$,[s.nodeKey]:{...U,decals:[...Y,F]}}}),Sn({...s,moving:!0})},[X,Vn]),qu=ie((s,b)=>{let m=Object.entries(X).find(([U,Y])=>Y===s||U===s.modelObjectId||Y.modelObjectId===s.modelObjectId)?.[0],N=m?X[m]?.decals?.find(U=>U.id===b):void 0;if(!m||!N)return;zo("object"),ps(U=>({...U,decals:!0})),Q(m);let{position:T,normal:F,...$}=N;setTimeout(()=>Sn({nodeKey:m,decal:$,moving:!0}),0)},[X]),Uu=ie(s=>{let b=[...new Set(s)].filter(m=>X[m]&&!X[m].removed);$n(b)},[X,$n]),Ku=ie(s=>{let b=be.current;if(be.current={shiftKey:!1,ctrlKey:!1,metaKey:!1},it){vi("orbit");return}if(!s){St(null);return}let m=Object.entries(X).find(([N,T])=>T===s||N===s.modelObjectId||T.modelObjectId===s.modelObjectId)?.[0]??null;St(m,b)},[it,X,St]),Di=ie(async s=>{if(it){vi("orbit");return}St(s),!G&&(Ci(null),await Vs(s))},[it,Vs,G,St]),Gu=ie(s=>{Ci(s?X[s]??null:null)},[X]),_u=ie(s=>gb(!s),[]),Wu=ie(()=>{if(it){Z("Camera positions aren't available while Pointer Lock is the active camera controller."),te("error");return}if(!I||!$e)return;let s={position:$e.position,target:$e.target,...$e.fov!=null?{fov:$e.fov}:{},zoom:$e.zoom};Dt(I,b=>({...b,cameraState:s}))},[it,I,$e]),Yu=ie(()=>{if(it){Z("Camera positions aren't available while Pointer Lock is the active camera controller."),te("error");return}!Nn?.position||!Nn?.target||Ra({position:Nn.position,target:Nn.target,fov:Nn.fov??$e?.fov??null,zoom:Nn.zoom??$e?.zoom??1},!0)},[it,Nn,Ra,$e]),Ju=ie(()=>{it||I&&Dt(I,s=>({...s,cameraState:void 0}))},[it,I]),Xu=ie(async()=>{if(it){Z("Reset View isn't available while Pointer Lock is the active camera controller."),te("error");return}await $s()},[it,$s]),Zu=ie(async()=>{if(it){Z("Fit Scene isn't available while Pointer Lock is the active camera controller."),te("error");return}await qs()},[it,qs]),Qu=ie(()=>{Z("Texture position saved."),te("success"),Rs.current?.()},[]),tl=ie(s=>{ys(s),xs(!0)},[]),ja=ie(()=>{xs(!1),ys(null)},[]),em=ie(()=>{if(Fo==="bindings"){if(!Qt.length){ja();return}let s=Jo(Qt,Fs);re.reset(s,{asEdit:!0}),Q(Qt[0]??null),Z("Object bindings reset to default values."),te("success")}else Fo==="assets"?(Xe.setValueAsStep(s=>({...s,gridSize:_n.gridSize,placements:Object.fromEntries(Object.entries(s.placements).map(([b,m])=>{let{position:N,rotation:T,scale:F,...$}=m;return[b,$]}))})),Z("Asset placements reset to default values."),te("success")):Fo==="scene"&&(Fe.reset(Tn,{asEdit:!0}),Z("Scene config reset to default values."),te("success"));ja()},[Fo,Qt,re,Fe,Xe,ja]),tm=ie(s=>{s.length>0&&bi(s)},[]),nm=ie(()=>{bi(null)},[]),om=ie(()=>{let s=Cn;if(!s||s.length===0)return;let b=new Set(s);re.setValueAsStep(m=>{let N={...m};for(let T of s)m[T]&&(N[T]={...m[T],removed:!0});return N}),Q(m=>m&&b.has(m)?null:m),tt(m=>m.filter(N=>!b.has(N))),Io(m=>m&&b.has(m)?null:m),Z(s.length===1?`Deleted ${X[s[0]]?.label||s[0]}.`:`Deleted ${s.length} objects.`),te("success"),bi(null)},[Cn,X,re.setValueAsStep]),am=ie(()=>{ci(null)},[]),im=async()=>{let s;try{s=await xd()}catch(b){console.warn("[BindingBuilder] Could not read the saved session:",b),Z("Couldn't read the saved session from this browser."),te("error");return}if(!s){Z("No saved session in this browser. Sessions are saved when you edit a model or add another one."),te("error");return}ci(s)},Li=async(s,b)=>(await Promise.all(s.map(async({entry:N,file:T})=>{if(N.model.kind==="url"&&l)return Mo({url:"",objectBindings:{},mergeModels:[{url:N.model.url,namePrefix:N.namePrefix}]})[0];if(N.model.kind==="url")return console.warn(`[BindingBuilder] Could not restore merged model "${N.model.name}" \u2014 merged models must come from an uploaded file.`),null;if(!T)return console.warn(`[BindingBuilder] Could not restore merged model "${N.model.name}" \u2014 its file is no longer in this browser's storage.`),null;try{let F=await Pn(T);return b.set(N.model.key,T),{url:F.url,namePrefix:N.namePrefix,resolved:F,sessionModel:N.model,nodeNames:[],loadState:"loading"}}catch(F){return console.warn(`[BindingBuilder] Could not restore merged model "${N.model.name}":`,F),null}}))).filter(N=>N!==null),rm=async(s,b,m)=>{let N=await Promise.all(s.map(async({entry:F,file:$,mergeFiles:U})=>{if(F.model.kind==="url")return{url:F.model.url,name:F.model.name,bindings:await jo(F.bindings),originalTransforms:F.originalTransforms,modelSettings:F.modelSettings,sessionModel:F.model,mergedModelSources:await Li(U,m)};if(!$)return console.warn(`[BindingBuilder] Could not restore parked model "${F.model.name}" \u2014 its file is no longer in this browser's storage.`),null;try{let Y=await Pn($);return m.set(F.model.key,$),{url:Y.url,name:F.model.name,bindings:await jo(F.bindings),originalTransforms:F.originalTransforms,modelSettings:F.modelSettings,resolved:Y,sessionModel:F.model,mergedModelSources:await Li(U,m)}}catch(Y){return console.warn(`[BindingBuilder] Could not restore parked model "${F.model.name}":`,Y),null}})),T=await Li(b,m);return{parkedModels:N.filter(F=>F!==null),mergedModelSources:T}},zi=(s,b)=>{Xe.setValue(m=>({...m,placements:{...m.placements,[s]:{...m.placements[s],...b}}}))},sm=async s=>{if(co||!g||!Is)return;let b=s===k?{url:s,name:R,bindings:X,originalTransforms:jt.current,resolved:bt.current??void 0,sessionModel:st.current?.model,mergedModelSources:Je,modelSettings:Bn(Ae)}:p.find(T=>T.url===s);if(!b?.sessionModel)return;if(l){let T=`${s.split("#")[0]}#copy-${crypto.randomUUID()}`,F=Xn(T),$=fe.current.get(s);fe.current.set(T,{...$,url:T});let U=`${b.name} copy`,Y=structuredClone(b.modelSettings);Y?.measurements&&(Y.measurements.items=Y.measurements.items.map(Pe=>({...Pe,modelId:F}))),r(Pe=>[...Pe,{...b,url:T,name:U,resolved:void 0,sessionModel:{kind:"url",url:T,name:U},bindings:structuredClone(b.bindings),originalTransforms:structuredClone(b.originalTransforms),modelSettings:Y,mergedModelSources:b.mergedModelSources.map(Go=>({...Go,loadState:"loading"})),bindingHistory:void 0,sceneHistory:void 0}]),j(Pe=>[...Pe,T]),lo(Pe=>[...Pe,F]);let oe=Uo(s),[ke,Ge,pn]=oe.position??[0,0,0];Xe.setValueAsStep(Pe=>({...Pe,placements:{...Pe.placements,[F]:{...oe,deleted:!1,label:`${oe.label??b.name} copy`,position:[ke+wt.gridSize,Ge,pn]}}})),Ct(),Z(`Duplicated ${b.name}.`),te("success");return}po(!0);let m=Et.current,N=[];try{let F=(b.sessionModel.kind==="file"?dn.current.get(b.sessionModel.key):void 0)??new File([await(await fetch(b.url)).blob()],b.name),$=await Pn(F);N.push($);let U=is(),Y=`file:${U}`,oe=[];for(let Be of b.mergedModelSources){if(Be.sessionModel.kind!=="file")throw new Error("Cannot duplicate a merged source without its original file.");let yt=dn.current.get(Be.sessionModel.key);if(!yt)throw new Error("An added source file is unavailable.");let _t=await Pn(yt);N.push(_t),oe.push({...Be,resolved:_t,url:_t.url,loadState:"loading"})}if(m!==Et.current||!Ca.current.modelOrder.includes(s)){N.forEach(Be=>Be.cleanup());return}dn.current.set(U,F);let ke=structuredClone(b.modelSettings);ke?.measurements&&(ke.measurements.items=ke.measurements.items.map(Be=>({...Be,modelId:Y}))),r(Be=>[...Be,{...b,url:$.url,name:`${b.name} copy`,resolved:$,sessionModel:{kind:"file",key:U,name:F.name},bindings:structuredClone(b.bindings),originalTransforms:structuredClone(b.originalTransforms),modelSettings:ke,mergedModelSources:oe,bindingHistory:void 0,sceneHistory:void 0}]),j(Be=>[...Be,$.url]),lo(Be=>[...Be,Y]);let Ge=Uo(s),[pn,Pe,Go]=Ge.position??[0,0,0];Xe.setValueAsStep(Be=>({...Be,placements:{...Be.placements,[Y]:{...Ge,deleted:!1,label:`${Ge.label??b.name} copy`,position:[pn+wt.gridSize,Pe,Go]}}})),Ct(),Z(`Duplicated ${b.name}.`),te("success")}catch(T){N.forEach(F=>F.cleanup()),Z(T instanceof Error?T.message:"Could not duplicate asset."),te("error")}finally{po(!1)}},lm=s=>{if(He.length<2||!g)return;let b=He.find(m=>m.url===s);b&&(s===k&&yo(He.find(m=>m.url!==s).url),Xe.setValueAsStep(m=>({...m,placements:{...m.placements,[b.id]:{...m.placements[b.id],deleted:!0}}})))},nl=async s=>{if(!(co||!g)){po(!0);try{let b=await Td(s);if(l){if(!h)throw new Error("This project can't accept new models.");let m=N=>b.session.composition?.placements[tn(N)]?.deleted;if(1+b.parkedFiles.filter(N=>!m(N.entry.model)).length>As)throw new Error(`Your plan allows ${As} models per project. Upgrade to import this scene.`);Z(`Uploading the models in ${s.name}...`),te("default"),b=await Cd(b,async N=>{let T=await h(N);return fe.current.set(T.url,T),T})}await ol(b),Ct()}catch(b){Z(b instanceof Error?b.message:"Could not load scene bundle."),te("error")}finally{po(!1)}}},dm=async()=>{let s=st.current;if(!(!s||!k||co)){po(!0);try{let b=T=>({model:T.sessionModel,namePrefix:T.namePrefix}),m={model:s.model,bindings:X,sceneConfig:Ae,composition:wt,mergeModels:Je.map(b),parkedModels:p.map(T=>({model:T.sessionModel??{kind:"url",url:T.url,name:T.name},bindings:T.bindings,originalTransforms:T.originalTransforms,modelSettings:T.modelSettings,mergeModels:T.mergedModelSources.map(b)})),modelOrder:M.map(T=>Mn.get(T)).filter(Boolean)},N=await Nd(m,new Map(dn.current));wo(N,"scene.ri.zip"),Z("Saved complete scene bundle."),te("success")}catch(b){Z(b instanceof Error?b.message:"Could not save scene."),te("error")}finally{po(!1)}}},ol=async s=>{let b=s??Un;if(ci(null),!b)return;let{session:m,file:N}=b,{model:T}=m;qo.current=null;let F=Et.current,$=await Qp(ta(Tn,m.sceneConfig)),U=await jo(m.bindings);if(await ai($),Et.current!==F)return;let Y=new Map,{parkedModels:oe,mergedModelSources:ke}=await rm(b.parkedFiles,b.mergeFiles,Y);if(Et.current!==F){oe.forEach(da),ke.forEach(Oo);return}let Ge=Be=>{let yt=new Map;yt.set(tn(T),Be),oe.forEach(Wt=>{Wt.sessionModel&&yt.set(tn(Wt.sessionModel),Wt.url)});let _t=(m.modelOrder??[]).map(Wt=>yt.get(Wt)).filter(Wt=>!!Wt),rl=new Set(_t);for(let Wt of[Be,...oe.map(cm=>cm.url)])rl.has(Wt)||(_t.push(Wt),rl.add(Wt));return _t},pn=()=>{for(let[Be,yt]of Y)dn.current.set(Be,yt),s?Ba.current.delete(Be):Ba.current.add(Be)},Pe;if(T.kind==="file"){if(!N){oe.forEach(da),ke.forEach(Oo);return}let Be=Et.current,yt;try{yt=await Pn(N)}catch(_t){console.warn("[BindingBuilder] Could not read the saved model:",_t),Z(rb(T.name)),te("error"),oe.forEach(da),ke.forEach(Oo);return}if(Et.current!==Be){yt.cleanup(),oe.forEach(da),ke.forEach(Oo);return}bt.current?.cleanup(),bt.current=yt,Pe=yt.url,Y.set(T.key,N),pn(),gi(),p.forEach(_t=>_t.resolved?.cleanup()),r(oe),vn(ke),j(Ge(Pe)),Xe.reset(m.composition?Wn(m.composition):_n),lo([])}else{Pe=T.url,pn(),gi(),p.forEach(yt=>yt.resolved?.cleanup()),r(oe),vn(ke),j(Ge(Pe)),Xe.reset(m.composition?Wn(m.composition):_n),lo([]);let Be=cn.current;if(Pe===k&&Be?.url===Pe&&!kt.current){st.current={model:T},re.reset(io(Be.scene,U,ke,ca(Be.scene,U).bindings)),Fe.reset($),Z(`Restored your last session with ${T.name}.`),te("success");return}bt.current?.cleanup(),bt.current=null}st.current={model:T,file:N??void 0},T.kind==="file"&&!s&&Ba.current.add(T.key);let Go=++Et.current;Pe!==k&&Gt.clearAnimations(),sn(!0),qn(null),Kn.current=0,rt.current&&(clearTimeout(rt.current),rt.current=null),Pa.current=N?.size,Z(`Restoring your last session with ${T.name}...`),te("default"),E(T.name),pe({url:Pe,name:T.name}),mo(null),Q(null),cn.current=null,re.reset({}),Fe.reset($),kt.current={requestId:Go,modelName:T.name,modelUrl:Pe,storedBindings:U,restoring:!0},O(Pe)};if(Vo.status==="checking")return q("div",{className:"bb-root bb-root--licenseChecking",children:!B&&q(qi,{title:"Verifying License",message:"Checking your license key..."})});if(Vo.status==="invalid")return q("div",{className:"bb-root bb-root--licenseInvalid",children:q(qi,{tone:"error",title:"Invalid License",message:Vo.isLocalDomain?Vo.reason??"License has been revoked or has expired":"Failed to load. Please contact the site administrator."})});let Ea=wn==="Assets",Ia=Ea?Xe:Fe,al=[{title:"Scene settings",description:"Lighting, camera, environment and the active model's scene settings. No model files or object bindings.",onImport:ju,onExportJson:()=>Zs("json"),onExportTs:()=>Zs("ts"),importDisabled:!Qt.length||Ie,exportDisabled:!Qt.length||Ie},{title:"Object bindings",description:"Object bindings for the active model. Uploaded binding textures are bundled when available. No model files or scene settings.",onImport:Au,onExportJson:()=>Xs("json"),onExportTs:()=>Xs("ts"),importDisabled:!Qt.length||Ie,exportDisabled:!Qt.length||Ie}],il=g&&ut(go,"sceneBundle")?{onImport:()=>Ms.current?.click(),onExport:dm,importDisabled:Ie,exportDisabled:Ie||!He.length||He.some(s=>!s.ready)}:void 0,Fi=it?q(Hn,{children:"Click the preview to look around \xB7 Esc to release"}):ui?q(Hn,{children:"Select a mesh \xB7 drag the colored arrows, planes, or rings"}):Lb&&di?Te(Hn,{children:[Te("span",{children:[q("kbd",{children:"W"}),q("kbd",{children:"A"}),q("kbd",{children:"S"}),q("kbd",{children:"D"})," move"]}),Te("span",{children:["\xB7 ",q("kbd",{children:"Space"}),"/",q("kbd",{children:"C"})," up \xB7 down"]}),q("span",{children:"\xB7 drag to look"})]}):null;return Te($l.Provider,{value:Vb,children:[Te("div",{className:"bb-root",onKeyDown:s=>{s.key!=="Escape"||s.defaultPrevented||!me||s.target.closest('input:not([type="checkbox"]), textarea, select, [contenteditable="true"]')||(s.preventDefault(),s.stopPropagation(),J())},children:[q("input",{ref:v,type:"file",accept:Vi,className:"bb-hiddenInput",onChange:fu,disabled:Ie}),q("input",{ref:P,type:"file",accept:Vi,className:"bb-hiddenInput",onChange:wu,disabled:Ie}),q("input",{ref:C,type:"file",accept:".json,application/json",className:"bb-hiddenInput",onChange:Ou,disabled:Ie}),q("input",{ref:S,type:"file",accept:".json,application/json",className:"bb-hiddenInput",onChange:Eu,disabled:Ie}),q("input",{ref:Ms,type:"file",accept:".zip,application/zip",hidden:!0,onChange:async s=>{let b=s.target.files?.[0];s.target.value="",b&&await nl(b)}}),Te("aside",{className:`bb-sidebar bb-sidebar--left ${ro?"bb-sidebar--collapsed":""}`,children:[Te("div",{className:"bb-header bb-header--sidebar",children:[!ro&&q("h1",{className:"bb-title",children:"Binding Builder"}),q("button",{type:"button",className:"bb-sidebarToggle",onClick:()=>cs(s=>!s),"aria-label":ro?"Open editor sidebar":"Collapse editor sidebar",title:ro?"Open editor":"Collapse editor",children:ro?"\u2192":"\u2190"})]}),!ro&&Te(Hn,{children:[Te("div",{className:"bb-tabRow",children:[q("button",{type:"button",className:`bb-tab ${ln==="object"?"bb-tab--active":""}`,onClick:()=>zo("object"),children:"Object"}),q("button",{type:"button",className:`bb-tab ${ln==="scene"?"bb-tab--active":""}`,onClick:()=>zo("scene"),children:"Scene"})]}),q("section",{className:"bb-editor",children:ln==="scene"?q(Hn,{children:k?q(Rr,{assets:g?{assets:He,activeUrl:k,composition:wt,busy:co||Ie,onFrameAll:()=>{let s=new ab;for(let m of He){if(m.placement.visible===!1)continue;let N=It.current.get(m.url);N&&(N.updateWorldMatrix(!0,!0),s.union(new ab().setFromObject(N)))}let b=ho.current;!s.isEmpty()&&b&&(Zl(s,b.raw.controls),b.raw.controls.fitToBox(s,!0,Ql).then(()=>b.invalidate()))},onSelect:yo,onAdd:Js,addRequiresTier:Is?void 0:bn("models",He.length),onChange:zi,onGridSize:s=>Xe.setValue(b=>({...b,gridSize:s})),onDuplicate:s=>{sm(s)},onDelete:l?()=>so(!0):lm,onSnap:s=>zi(s,Cl(wt.placements[s]??{},wt.gridSize)),onGround:s=>{let b=It.current.get(s),m=b?Ml(b):null;m&&zi(Mn.get(s),kl(Uo(s),m))}}:void 0,diagnostics:{report:Ds?.url===k?Ds.report:null,runtimeStats:Kb,onRefresh:Gb,onSelectObject:s=>{let b=Object.keys(X).find(m=>m===s||X[m].modelObjectId===s);b&&Di(b)}},onDiagnosticsOpenChange:Ub,config:Ae,onChange:Ho,activeSubTab:wn,onActiveSubTabChange:ri,cameraState:(wn==="Cinematic"||wn==="Annotations")&&$e?{position:$e.position,target:$e.target,azimuthAngle:$e.azimuthAngle,polarAngle:$e.polarAngle,fov:$e.fov,zoom:$e.zoom}:null,onPreviewWaypoint:tu,sequenceControls:Yb,sequenceClipDetails:Gt.clipDetails,animationClipDetails:xo.clipDetails,animationConfig:Us.config,onAnimationConfigChange:Us.onChange,animationPlayback:xo,materialVariantGroups:_b,onImageFile:el,objectBindings:X}):q("div",{className:"bb-emptyEditor",children:"Upload a model to edit its scene settings."})}):!De||!I?q("div",{className:"bb-emptyEditor",children:"Select a generated node binding to edit its values."}):Te(Hn,{children:[Te("div",{className:"bb-editorHeader",children:[Te("div",{children:[q("div",{className:"bb-sectionKicker",children:"Editing Binding"}),q("h2",{className:"bb-editorTitle",children:me&&ae.length>1?`${ae.length} objects selected`:De.label||I}),q("div",{className:"bb-editorMeta",children:me?q("span",{children:"Changes apply to every selected object"}):Te(Hn,{children:[q("span",{children:De.type}),q("span",{children:De.modelObjectId})]})})]}),(()=>{let s=me&&ae.length>0?ae:[I],b=s.length>1?`Delete ${s.length} selected objects`:"Delete this object";return q("button",{type:"button",className:"bb-editorDeleteButton",onClick:()=>tm(s),title:b,"aria-label":b,children:q(dx,{size:18})})})()]}),Te("div",{className:"bb-styleClipboard",children:[Te("div",{className:"bb-styleClipboardActions",children:[q("button",{type:"button",className:"bb-button bb-button--ghost",onClick:()=>ma({name:De.label||I,style:ld(De)}),children:"Copy style"}),Te("button",{type:"button",className:"bb-button bb-button--ghost",disabled:!qe,onClick:()=>{if(!qe)return;let s=me?ae:[I];re.setValueAsStep(b=>dd(b,s,qe.style))},children:["Paste style",me&&ae.length>1?` (${ae.length})`:""]})]}),qe&&Te("p",{children:["Copied from ",qe.name]}),me&&ae.length>1&&Te("p",{children:["Values shown for ",De.label||I,". Edits apply to all selected objects."]})]}),!me&&q(Xc,{selectedItem:I,selectedBinding:De,open:Xt.identity,onToggle:()=>Zt("identity"),updateBinding:Dt,idError:lu}),!me&&q(Qc,{selectedItem:I,selectedBinding:De,open:Xt.basics,onToggle:()=>Zt("basics"),updateBinding:Dt}),me&&q(ot,{title:"Basics",open:Xt.basics,onToggle:()=>Zt("basics"),children:q("div",{className:"bb-groupFlags",children:["selectable","hoverable","visible"].map(s=>q(cx,{label:s,values:ae.map(b=>X[b]).filter(b=>b&&!b.removed).map(b=>b[s]!==!1),onChange:b=>re.setValueAsStep(m=>{let N={...m};for(let T of ae)m[T]&&!m[T].removed&&(N[T]={...m[T],[s]:b});return N})},s))})}),Te(ot,{title:"Material",open:Xt.material,onToggle:()=>Zt("material"),tooltip:"Edit the selected object's base material, textures, and surface properties.",children:[q(Jc,{disabled:!I,onApply:s=>I&&Oi(I,b=>({...b,...s}))}),q(Wc,{selectedItem:I,selectedMaterial:Pi,pbrWorkflow:vb,onPbrWorkflowChange:Sb,openMaterialPanels:fb,materialPanelEnabled:wb,onToggleMaterialPanel:xb,onSetMaterialPanelState:cu,updateSelectedMaterial:Oi,setSelectedTexturePath:du,isTexturePositioningEnabled:Fb,onConfirmTexturePosition:Qu,takesImage:Ks})]}),!me&&q(ap,{selectedItem:I,selectedBinding:De,open:Xt.decals,onToggle:()=>Zt("decals"),updateBinding:Dt,placement:fa,onPlacementChange:Vu,defaultSize:Fu,onImageFile:el,onNudge:$u}),!me&&q(tp,{selectedItem:I,selectedBinding:De,open:Xt.actions,onToggle:()=>Zt("actions"),updateBinding:Dt,takesImage:Ks}),!me&&q(ip,{selectedBinding:De,open:Xt.camera,onToggle:()=>Zt("camera"),cameraState:$e,formattedCameraState:au,savedCameraPosition:Nn,onSaveCameraPosition:Wu,onGoToSavedCamera:Yu,onClearSavedCamera:Ju,onResetView:Xu,onFitScene:Zu}),q(dp,{selectedItem:I,selectedBinding:De,open:Xt.transform,onToggle:()=>Zt("transform"),updateBinding:Dt,moveModeEnabled:ui,onToggleMoveMode:vs,scaleModeEnabled:Ss,onToggleScaleMode:ws,transformSpace:Cs,onTransformSpaceChange:Bb,originalTransform:jt.current[I]??null,originalTransforms:jt.current}),q($r,{title:"Metrics",label:"Metrics JSON",open:Xt.metrics,onToggle:()=>Zt("metrics"),draft:ls,error:pb,example:'{"area": 42}',onDraftChange:xa,onCommit:()=>Qs("metrics",ls,va)}),q($r,{title:"Metadata",label:"Metadata JSON",open:Xt.metadata,onToggle:()=>Zt("metadata"),draft:ds,error:bb,example:'{"room": "kitchen"}',onDraftChange:ya,onCommit:()=>Qs("metadata",ds,Sa)})]})}),ln==="object"&&q(Xr,{canUndo:re.canUndo,canRedo:re.canRedo,onUndo:re.undo,onRedo:re.redo,onReset:()=>tl("bindings"),resetDisabled:!Qt.length,resetTitle:"Reset object bindings to default",fileScopes:al,sceneBundle:il,busy:co||rs}),ln==="scene"&&q(Xr,{canUndo:Ia.canUndo,canRedo:Ia.canRedo,onUndo:Ia.undo,onRedo:Ia.redo,onReset:()=>tl(Ea?"assets":"scene"),resetTitle:Ea?"Reset asset placements to default":"Reset scene config to default",resetDisabled:Ea&&(!He.length||Ie),fileScopes:al,sceneBundle:il,busy:co||rs})]})]}),Te("main",{className:"bb-previewShell",children:[Te("div",{className:"bb-previewHeader",children:[q(sr,{label:"View",icon:q(sx,{size:14,"aria-hidden":"true"}),title:"Preview options",children:()=>Te(Hn,{children:[Te("label",{className:"bb-headerMenuItem",children:[q("input",{type:"checkbox",checked:hs,onChange:s=>Cb(s.target.checked)}),"Zoom on selected"]}),Te("label",{className:"bb-headerMenuItem",children:[q("input",{type:"checkbox",checked:li,onChange:s=>kb(s.target.checked)}),"Highlight on hover"]}),Te("label",{className:"bb-headerMenuItem",children:[q("input",{type:"checkbox",checked:di,onChange:s=>Mb(s.target.checked)}),"Camera controller"]})]})}),q("div",{className:"bb-previewMeta",children:q("span",{title:I??void 0,children:I?`Focused: ${I}`:"Select a node to inspect it"})}),k&&Te("button",{type:"button",className:`bb-compareButton ${kn?"bb-compareButton--active":""}`,onClick:()=>{Ob(s=>!s),hi(null)},"aria-pressed":kn,title:"Compare: drag a divider across the preview to see it before and after your changes",children:[q(lx,{size:14}),"Compare"]}),g&&q(sr,{icon:q(ax,{size:16,"aria-hidden":"true"}),title:"More model actions",align:"right",children:s=>q(Rd,{close:s,onRestore:k||l?void 0:im,restoreDisabled:Ie,onAddModel:k?Js:void 0,addModelDisabled:Ie,onRemove:k&&(!l||Ko.length>1)?hu:void 0,confirmRemove:Ko.length<=1})})]}),Te("div",{className:"bb-preview",ref:x,onPointerDownCapture:s=>{be.current={shiftKey:s.shiftKey,ctrlKey:s.ctrlKey,metaKey:s.metaKey}},onKeyDownCapture:()=>{be.current={shiftKey:!1,ctrlKey:!1,metaKey:!1}},onFocus:s=>{s.currentTarget.contains(s.relatedTarget)||wi()},children:[q(Ul,{visible:Ie||cb,message:ss,tone:ha,progress:lb??void 0}),k&&q("div",{className:`bb-canvasHint ${Fi?"bb-canvasHint--visible":""} ${kn?"bb-canvasHint--belowCompare":""}`,"aria-hidden":!Fi,children:Fi}),k?q(Yi,{loading:"eager",enableXR:!0,arHandoff:a,mobileHandoffUrl:i,modelUrl:k,tilesetUrl:Ce?.tilesetUrl,models:Gs,onModelChange:yo,onExtraModelLoaded:Ru,onExtraModelError:Bu,mergeModels:Bi,onMergeModelLoaded:Tu,onMergeModelError:Pu,originalNodePoses:jt.current,objectBindings:X,comparisonHighlights:Ns?.after,selectedObject:De,selectedObjectRefs:Zb,selectedObjectOutlineColor:"#22c55e",onObjectSelect:Ku,onSelectionClear:J,onObjectBindingsChange:Vn,onTextureUpload:su,onObjectEditLeaseChange:(s,b)=>u?.(`${k}|${s.modelObjectId||s.id}`,b),showObjectBindingDataPanel:!1,showSceneObjectsPanel:!1,onCameraChange:Qb,onViewerReady:s=>{ho.current=s,Xb(s.raw.nodes),eu(s)},onAnnotationsChange:iu,activeAnnotation:Hb?.annotation??null,onActiveAnnotationChange:ru,onSequencesReady:Jb,showSequenceControls:!1,sequenceAutoPlay:!1,onAnimationsReady:gu,onModelAnimationsReady:xo.handleModelAnimationsReady,onSceneLoaded:pu,onAssetDiagnostics:Ti?s=>Ls({url:k,report:s}):void 0,onRuntimeStats:Ti?zs:void 0,onLoadError:uu,onObjectCatalog:Ce?.tilesetUrl?bu:void 0,onProgress:mu,onCameraControllerChange:vi,cameraControllerType:Ts,onTexturePositioningChange:zb,endTexturePositioningRef:Rs,licenseKey:e,licenseValidationUrl:t,dracoDecoderPath:n,ktx2TranscoderPath:o,meshopt:d,sceneConfig:Ae,onSceneConfigChange:Ho,preserveDrawingBuffer:!0,disableZoom:!1,zoomOnSelected:hs,highlightOnHover:li,enableCameraControls:di,moveModeEnabled:ui,scaleModeEnabled:Ss,objectTransformSpace:Cs,enableKeyboardNavigation:!0,showViewGizmo:!0,showMeasureTools:!0,measurementModelId:st.current?.model.kind==="file"?tn(st.current.model):void 0,showSectionTools:Ae.section?.enabled??!1,isolation:sb,onIsolationChange:()=>Io(null),showIsolateControls:!0,decalMove:Hu,onDecalDoubleClick:qu,panelHoveredObject:li?$b:null,showLoadingOverlay:!1,autoRotate:it?!1:Ae.model.autoRotate??!1,autoRotateSpeed:Ae.model.autoRotateSpeed??1}):q("div",{className:`bb-previewPlaceholder ${ub?"bb-previewPlaceholder--dragActive":""}`,onDragEnter:Iu,onDragOver:Du,onDragLeave:Lu,onDrop:zu,children:Te("div",{children:[q("div",{children:"Upload a GLB, GLTF, OBJ, FBX, USDZ, STL, or PLY model, or drag a supported model/ZIP bundle here to generate editable object bindings."}),g?q("button",{type:"button",className:"bb-previewPlaceholderButton",onClick:Su,disabled:Ie,children:"Upload"}):null]})}),k&&kn?q(jd,{showOutlines:fi,onShowOutlinesChange:Ib,matchBy:xi,onMatchByChange:s=>{Db(s),yi(null)},report:$o??void 0,selected:Ma,onSelect:s=>{yi(s?.id??null),s?.afterKey&&Di(s.afterKey)},liveViewerRef:ho,split:jb,onSplitChange:Eb,labels:[bo?"Pinned":"Before","Now"],beforeAction:Te("button",{type:"button",className:"ri-compare__labelAction",onClick:()=>hi(s=>s?null:{bindings:X,sceneConfig:Ae}),"aria-pressed":!!bo,title:bo?"Unpin: compare with the project as it was opened again":"Pin as before: compare later changes with how the preview looks now",children:[bo?q(rx,{size:12}):q(ix,{size:12}),bo?"Unpin":"Pin"]}),renderBefore:s=>q(Yi,{loading:"eager",modelUrl:k,tilesetUrl:Ce?.tilesetUrl,comparisonHighlights:Ns?.before,objectBindings:uo.bindings,sceneConfig:{...uo.sceneConfig,section:Ae.section},licenseKey:e,licenseValidationUrl:t,dracoDecoderPath:n,ktx2TranscoderPath:o,meshopt:d,preset:"minimal",showLoadingOverlay:!1,showObjectNavigator:!1,selectedObject:null,zoomOnSelected:!1,highlightOnHover:!1,autoRotate:!1,cinematic:!1,onViewerReady:s})}):null]})]}),q(mp,{bindings:X,selectedItem:I,onSelect:Di,onHover:Gu,isOpen:!mb,onToggle:_u,modelGroups:ou,onSelectModel:yo,isolatedItem:ga,onIsolate:Io,multiSelectEnabled:G,onToggleMultiSelect:Eo,onExitMultiSelect:A,multiSelectedKeys:ae,onSetMultiSelected:Uu,hierarchy:Wb,selectionSets:Ae.selectionSets,onSelectionSetsChange:Rb})]}),Nb&&q(Hp,{target:Fo,onCancel:ja,onConfirm:em}),Un&&q($p,{modelNames:[Un.session.model.name,...(Un.session.parkedModels??[]).map(s=>s.model.name)],mergedSourceCount:(Un.session.mergeModels?.length??0)+(Un.session.parkedModels??[]).reduce((s,b)=>s+(b.mergeModels?.length??0),0),savedAt:Un.session.savedAt,onCancel:am,onConfirm:()=>{ol()}}),Tb&&q(qp,{destinations:Ko.filter(s=>s.kind==="model"),onCancel:Cu,onChoose:ku}),Pb&&q(Up,{options:Ko,onCancel:xu,onRemoveModel:yu,onRemoveMerge:vu,permanent:!!l,onRemoveAll:l?void 0:()=>{so(!1),Oa()}}),Cn&&q(Vp,{nodeLabel:Cn.length===1?X[Cn[0]]?.label||Cn[0]:`${Cn.length} objects`,count:Cn.length,onCancel:nm,onConfirm:om})]})}export{_a as a,Tx as b,px as c};