@liveroom-tech/react-immersive 6.0.0 → 6.0.2
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.
- package/README.md +2 -2
- package/dist/binding-builder.js +21 -21
- package/dist/binding-builder.mjs +1 -1
- package/dist/chunk-33SUWPXC.mjs +3 -0
- package/dist/{chunk-UGPR4EPP.mjs → chunk-EIBW7ZJE.mjs} +1 -1
- package/dist/{chunk-2JFUMJUP.mjs → chunk-KFTJMFYF.mjs} +1 -1
- package/dist/hosted.js +20 -20
- package/dist/hosted.mjs +1 -1
- package/dist/index.js +1 -1
- package/dist/index.mjs +1 -1
- package/package.json +1 -1
- package/dist/chunk-WWUWEPFK.mjs +0 -3
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
import{A as Yl,B as Jl,C as Xl,D as _e,E as Zl,F as Ql,G as ed,H as Xi,I as td,J as od,L as ad,M as id,N as pd,a as Vi,b as ul,c as ml,d as gl,e as fl,f as Ui,h as Va,j as jl,k as Co,l as Ka,m as zl,n as Fl,o as Wi,p as Hl,q as Yi,r as lt,s as $l,t as vt,u as un,v as Vl,w as dt,x as ql,y as _l,z as Wl}from"./chunk-EIBW7ZJE.mjs";import{J as Ga,K as Kl,g as qi,j as Bn,z as Al}from"./chunk-OTSCPJWF.mjs";import{Ba as Ki,Ca as qa,D as hl,Da as Ua,E as xl,F as yl,Fa as Gi,G as vl,Ga as Ol,H as Sl,Ha as Ji,I as wl,J as Jo,Ja as Ul,K as Cl,L as Pn,M as kl,P as Ha,Q as Wn,Qa as Xo,Sa as _a,T as Yn,Ta as Gl,U as Ml,Ua as nd,V as Nl,Va as Zi,W as Tl,Wa as rd,Xa as sd,Ya as ld,Za as dd,_a as cd,a as Fa,e as Wo,f as dl,g as cl,h as $i,i as pl,j as _n,ka as $a,l as bl,na as wo,qa as Pl,r as So,s as nn,t as Xt,u as Yo}from"./chunk-4JMJALRO.mjs";import{L as Il,M as Dl,P as Ll,Q as _i,n as Bl,q as Rl,w as El}from"./chunk-V7WZUWJ5.mjs";function Rn(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??Pn.animations,measurements:t?.measurements,selectionSets:t?.selectionSets,sequences:t?.sequences}}function ud(e){if(e===void 0)return!0;try{return wo(e),!0}catch{return!1}}function md(e){if(e===void 0)return!0;try{return $a(e),!0}catch{return!1}}var bm="react-immersive:binding-builder",um=2,An="session",On="model",jn="textures",er="current",gd=1;function on(e){return e.kind==="file"?`file:${e.key}`:`url:${e.url}`}var Jn=null;function Zo(){return Jn||(Jn=new Promise((e,t)=>{if(typeof indexedDB>"u"){t(new Error("IndexedDB is not available in this environment."));return}let a=indexedDB.open(bm,um);a.onupgradeneeded=()=>{let i=a.result;i.objectStoreNames.contains(An)||i.createObjectStore(An),i.objectStoreNames.contains(On)||i.createObjectStore(On),i.objectStoreNames.contains(jn)||i.createObjectStore(jn)},a.onsuccess=()=>{let i=a.result;i.onversionchange=()=>{i.close(),Jn=null},e(i)},a.onerror=()=>t(a.error??new Error("Failed to open IndexedDB."))}),Jn.catch(()=>{Jn=null}),Jn)}function ko(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 tr(e){return new Promise((t,a)=>{e.onsuccess=()=>t(e.result),e.onerror=()=>a(e.error??new Error("IndexedDB request failed."))})}function Bt(e){return e!==null&&typeof e=="object"&&!Array.isArray(e)}function nr(e){return!Bt(e)||typeof e.name!="string"?!1:e.kind==="file"?typeof e.key=="string":e.kind==="url"?typeof e.url=="string":!1}function fd(e){return Bt(e)&&nr(e.model)&&typeof e.namePrefix=="string"}function mm(e){if(e===void 0)return!0;try{return kl(e),!0}catch{return!1}}function hd(e){if(e===void 0)return!0;try{return _n(e),!0}catch{return!1}}function gm(e){return!Bt(e)||!nr(e.model)||!Bt(e.bindings)||!Bt(e.originalTransforms)||e.modelSettings!==void 0&&(!Bt(e.modelSettings)||!Array.isArray(e.modelSettings.annotations)||!Bt(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")))||Bt(e.modelSettings)&&!md(e.modelSettings.measurements)||Bt(e.modelSettings)&&!ud(e.modelSettings.selectionSets)||Bt(e.modelSettings)&&!hd(e.modelSettings.sequences)?!1:e.mergeModels===void 0?!0:Array.isArray(e.mergeModels)&&e.mergeModels.every(fd)}function Wa(e){if(!Bt(e)||e.version!==gd)return!1;if(e.composition!==void 0)try{Yn(e.composition)}catch{return!1}return!(typeof e.savedAt!="number"||!Bt(e.bindings)||!Bt(e.sceneConfig)||!nr(e.model)||!md(e.sceneConfig.measurements)||!ud(e.sceneConfig.selectionSets)||!hd(e.sceneConfig.sequences)||!mm(e.sceneConfig.section)||e.parkedModels!==void 0&&(!Array.isArray(e.parkedModels)||!e.parkedModels.every(gm))||e.mergeModels!==void 0&&(!Array.isArray(e.mergeModels)||!e.mergeModels.every(fd))||e.modelOrder!==void 0&&(!Array.isArray(e.modelOrder)||!e.modelOrder.every(t=>typeof t=="string")))}function Qi(e,t){return e.kind==="url"?Promise.resolve(null):tr(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 xd(e,t){let a=await Zo(),i={...e,version:gd,savedAt:Date.now()},n=a.transaction([An,On],"readwrite"),o=ko(n);n.objectStore(An).put(i,er);let d=n.objectStore(On),l=new Set,c=f=>{f.kind==="file"&&l.add(f.key)};c(i.model),i.mergeModels?.forEach(f=>c(f.model)),i.parkedModels?.forEach(f=>{c(f.model),f.mergeModels?.forEach(y=>c(y.model))});for(let{key:f,file:y}of t??[]){let b={key:f,blob:y,name:y.name,type:y.type,lastModified:y.lastModified};d.put(b,f)}let w=d.getAllKeys();return w.onsuccess=()=>{for(let f of w.result)l.has(f)||d.delete(f)},await o,i}function bd(e,t){return Promise.all(e.map(async a=>({entry:a,file:await Qi(a.model,t)})))}async function yd(){let e=await Zo(),t=e.transaction(An,"readonly"),a=ko(t),i=await tr(t.objectStore(An).get(er));if(await a,!Wa(i))return null;let n=i.parkedModels??[],o=i.mergeModels??[],d=e.transaction(On,"readonly"),l=ko(d),c=d.objectStore(On),[w,f,y]=await Promise.all([Qi(i.model,c),bd(o,c),Promise.all(n.map(async b=>({entry:b,file:await Qi(b.model,c),mergeFiles:await bd(b.mergeModels??[],c)})))]);return await l,i.model.kind==="file"&&!w?null:{session:{...i,parkedModels:n,mergeModels:o},file:w,parkedFiles:y,mergeFiles:f}}async function vd(){let t=(await Zo()).transaction([An,On,jn],"readwrite"),a=ko(t);t.objectStore(An).delete(er),t.objectStore(On).clear(),t.objectStore(jn).clear(),await a}async function Mo(e,t){let i=(await Zo()).transaction(jn,"readwrite"),n=ko(i),o={blob:t,name:t.name,type:t.type,savedAt:Date.now()};i.objectStore(jn).put(o,e),await n}async function mn(e){let a=(await Zo()).transaction(jn,"readonly"),i=ko(a),n=await tr(a.objectStore(jn).get(e));return await i,n?new File([n.blob],n.name,{type:n.type,lastModified:n.savedAt}):null}function Zn(e){return`url:${e}`}function ar(e){return e.models.find(t=>!e.composition.placements[Zn(t.url)]?.deleted)??e.models[0]}function ir(e){return Yn(e.composition)}function Ja(e,t){return mt(e,t.modelSettings)}function fm(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 No(e){return(e.mergeModels??[]).map(fm)}function rr(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:No(e),modelSettings:e.modelSettings}}function sr(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 Sd(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[Zn(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:Rn(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 or(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 Xa(e,t){return e===t||or(e)===or(t)}function hm(e){return Rn(mt(Pn,e))}function To(e){return or({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:hm(t.modelSettings)})),composition:e.composition,sceneConfig:mt(e.sceneConfig)})}function Px(e){if(!(e.models.length<2))return e.models.flatMap(t=>{let a=e.composition.placements[Zn(t.url)]??{};return a.deleted?[]:[{url:t.url,label:a.label??t.name,transform:a,visible:a.visible!==!1,objectBindings:t.objectBindings,sceneConfig:Ja(e.sceneConfig,t),mergeModels:t.mergeModels?.map(({url:i,namePrefix:n})=>({url:i,namePrefix:n}))}]})}var wd=new Set(["path","image","url","poster","src","imageUrl"]);function xm(e){return e.startsWith("blob:")||e.startsWith("data:")||!!nn(e)}function Xn(e,t=new Set){if(Array.isArray(e))e.forEach(a=>Xn(a,t));else if(e&&typeof e=="object")for(let[a,i]of Object.entries(e))typeof i=="string"?wd.has(a)&&xm(i)&&t.add(i):Xn(i,t);return t}function Ya(e,t){return Array.isArray(e)?e.map(a=>Ya(a,t)):e&&typeof e=="object"?Object.fromEntries(Object.entries(e).map(([a,i])=>[a,typeof i=="string"&&wd.has(a)&&t.has(i)?t.get(i):Ya(i,t)])):e}async function Cd(e){let t=nn(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 kd(e,t){let a=f=>e.session.composition?.placements[on(f)]?.deleted;e={...e,parkedFiles:e.parkedFiles.filter(f=>!a(f.entry.model))};let i=new Map,n=async(f,y)=>{if(f.kind!=="file")return f;if(!y)throw new Error(`The scene bundle is missing ${f.name}.`);let{url:b}=await t(y);return i.set(`file:${f.key}`,Zn(b)),{kind:"url",url:b,name:f.name}},o=async f=>{let y=[];for(let{entry:b,file:g}of f)y.push({entry:{...b,model:await n(b.model,g)},file:null});return y},d=await n(e.session.model,e.file),l=await o(e.mergeFiles),c=[];for(let f of e.parkedFiles){let y=await n(f.entry.model,f.file),b=await o(f.mergeFiles);c.push({entry:{...f.entry,model:y,mergeModels:b.map(g=>g.entry)},file:null,mergeFiles:b})}let w=e.session.composition;return{file:null,mergeFiles:l,parkedFiles:c,session:{...e.session,model:d,mergeModels:l.map(f=>f.entry),parkedModels:c.map(f=>f.entry),modelOrder:e.session.modelOrder?.map(f=>i.get(f)??f),composition:w&&{...w,placements:Object.fromEntries(Object.entries(w.placements).map(([f,y])=>[i.get(f)??f,y]))}}}}import{strFromU8 as ym,strToU8 as vm,unzip as Sm}from"fflate";var Qo=512*1024*1024,Md=5*1024*1024;function lr(e){return[e.model,...(e.mergeModels??[]).map(t=>t.model),...(e.parkedModels??[]).flatMap(t=>[t.model,...(t.mergeModels??[]).map(a=>a.model)])]}function Nd(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)Pl({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 Td(e,t){let a=JSON.parse(JSON.stringify({...e,version:1,savedAt:Date.now()})),i={},n=[],o=[],d=0;async function l(b,g){if(d+=g.size,d>Qo)throw new Error("Scene bundle exceeds the 512 MiB expanded limit.");i[b]=new Uint8Array(await g.arrayBuffer())}for(let b of lr(a)){if(b.kind!=="file"||n.some(v=>v.key===b.key))continue;let g=t.get(b.key);if(!g)throw new Error(`Cannot save scene: missing uploaded file ${b.name}.`);let B=`models/${n.length}`;n.push({key:b.key,path:B,name:g.name,type:g.type,lastModified:g.lastModified}),await l(B,g)}let c=new Map;async function w(b,g=0){if(g>64)throw new Error("Scene data is too deeply nested.");if(!(!b||typeof b!="object"))for(let[B,v]of Object.entries(b)){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=nn(v),x=P||v.startsWith("blob:")||v.startsWith("data:")?null:await mn(v);if(!x&&!P&&!v.startsWith("blob:")&&!v.startsWith("data:"))continue;let C=c.get(v);if(C){b[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}`,h=`/__ri_bundle_texture__/${o.length}`;o.push({ref:h,path:S,name:x.name,type:x.type}),await l(S,x),c.set(v,h),b[B]=h}else await w(v,g+1)}}for(let b of lr(a))if(b.kind==="url"&&b.url.startsWith("blob:"))throw new Error("Cannot save a temporary model URL without its original file.");if(await w(a),!Wa(a))throw new Error("Invalid scene snapshot.");Nd(a);let f=vm(JSON.stringify({format:"react-immersive-scene",version:1,session:a,files:n,textures:o}));if(f.byteLength>Md)throw new Error("Scene settings exceed the 5 MiB limit.");if(d+f.byteLength>Qo||Object.keys(i).length+1>1024)throw new Error("Scene bundle exceeds its size or file-count limit.");i["scene.json"]=f;let y=await Ka(i);if(y.byteLength>Qo)throw new Error("Compressed scene bundle exceeds 512 MiB.");return new Blob([y],{type:"application/zip"})}async function Pd(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)=>Sm(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>Md||!/^(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(ym(d["scene.json"]));if(l.format!=="react-immersive-scene"||l.version!==1||!Wa(l.session)||!Array.isArray(l.files)||!Array.isArray(l.textures))throw new Error("Invalid scene bundle manifest.");Nd(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 lr(l.session))if(v.kind==="file"&&!c.has(v.key))throw new Error(`Scene bundle is missing ${v.name}.`);let f=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)||f.has(v.ref))throw new Error("Invalid texture in scene bundle.");w.add(v.path),f.set(v.ref,{path:`materials/scene-${y}/${f.size}`,file:new File([d[v.path]],v.name,{type:v.type})})}function b(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=f.get(C);if(!S)throw new Error("Scene bundle is missing a texture.");if(x==="path")v[x]=S.path;else{let h=d[[...l.textures].find(O=>O.ref===C).path],k="";for(let O=0;O<h.length;O+=32768)k+=String.fromCharCode(...h.subarray(O,O+32768));v[x]=`data:${S.file.type||"application/octet-stream"};base64,${btoa(k)}`}}else b(C,P+1)}}b(l.session),await Promise.all([...f.values()].map(v=>Mo(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 ae,useEffect as ct,useMemo as pt,useRef as de,useState as W}from"react";import{Box3 as ib,Vector3 as ax}from"three";import{Ellipsis as ix,Pin as rx,PinOff as sx,SlidersHorizontal as lx,SquareSplitHorizontal as dx,Trash2 as cx}from"lucide-react";import{useEffect as wm,useId as Cm,useRef as Bd,useState as Rd}from"react";import{ChevronDown as km,History as Mm,Plus as Nm,Trash2 as Tm}from"lucide-react";import{Fragment as Od,jsx as En,jsxs as gn}from"react/jsx-runtime";function dr({label:e,icon:t,title:a,align:i="left",children:n}){let[o,d]=Rd(!1),l=Bd(null),c=Bd(null),w=Cm();return wm(()=>{if(!o)return;let f=b=>{l.current?.contains(b.target)||d(!1)},y=b=>{b.key==="Escape"&&(d(!1),c.current?.focus())};return window.addEventListener("pointerdown",f),window.addEventListener("keydown",y),()=>{window.removeEventListener("pointerdown",f),window.removeEventListener("keydown",y)}},[o]),gn("div",{className:"bb-headerMenuWrapper",ref:l,children:[gn("button",{ref:c,type:"button",className:`bb-headerButton ${e?"":"bb-headerButton--icon"} ${o?"bb-headerButton--open":""}`,onClick:()=>d(f=>!f),title:a,"aria-label":e?void 0:a,"aria-expanded":o,"aria-controls":o?w:void 0,children:[t,e?gn(Od,{children:[e,En(km,{size:12,"aria-hidden":"true"})]}):null]}),o?En("div",{id:w,className:`bb-headerMenu bb-headerMenu--${i}`,role:"group","aria-label":a,children:n(()=>d(!1))}):null]})}function Ad({onRestore:e,onRemove:t,onAddModel:a,restoreDisabled:i,addModelDisabled:n,confirmRemove:o=!0,close:d}){let[l,c]=Rd(!1);return l&&t?gn("div",{className:"bb-headerMenuConfirm",role:"alertdialog","aria-label":"Remove model",children:[En("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."}),gn("div",{className:"bb-headerMenuConfirmActions",children:[En("button",{type:"button",className:"bb-headerMenuItem",onClick:()=>c(!1),children:"Cancel"}),En("button",{type:"button",className:"bb-headerMenuItem bb-headerMenuItem--danger",onClick:()=>{d(),t()},autoFocus:!0,children:"Remove"})]})]}):gn(Od,{children:[a?gn("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:[En(Nm,{size:14,"aria-hidden":"true"}),"Add model\u2026"]}):null,e?gn("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:[En(Mm,{size:14,"aria-hidden":"true"}),"Restore last session"]}):null,t?gn("button",{type:"button",className:"bb-headerMenuItem bb-headerMenuItem--danger",onClick:()=>{if(o){c(!0);return}d(),t()},children:[En(Tm,{size:14,"aria-hidden":"true"}),"Remove model\u2026"]}):null]})}import{useCallback as Pm,useEffect as Bm,useMemo as Rm,useRef as jd}from"react";import{jsx as cr,jsxs as Am}from"react/jsx-runtime";function Ed({liveViewerRef:e,renderBefore:t,split:a,onSplitChange:i,labels:n,beforeAction:o,report:d,selected:l,onSelect:c,matchBy:w,onMatchByChange:f,showOutlines:y,onShowOutlinesChange:b}){let g=jd(null),B=jd(null),v=Rm(()=>od(),[]);Bm(()=>()=>v.detach(),[v]);let P=Pm(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 Am("div",{ref:g,className:"ri-compare ri-compare--overlay",style:{"--ri-compare-split":`${a*100}%`},children:[cr("div",{className:"ri-compare__layer ri-compare__layer--before",children:t(P)}),d&&cr(td,{showOutlines:y,onShowOutlinesChange:b,matchBy:w,onMatchByChange:f,report:d,selected:l,onClear:()=>c?.(null),onSelect:x=>{let C=x.afterObjectId?0:1,S=C===0?e.current:B.current,h=C===0?x.afterObjectId:x.beforeObjectId,k=h?S?.raw.nodes[h]:null;v.setLeader(C),c?.(x),S&&k&&(S.raw.controls.fitToBox(k,!0),S.invalidate())}}),cr(ad,{split:a,onSplitChange:i,labels:n,containerRef:g,beforeAction:o})]})}import{useCallback as fn,useEffect as Id,useMemo as Dd,useRef as Za,useState as Ld}from"react";var Om={currentClip:null,isPlaying:!1,speed:1,time:0,duration:0,active:[]};function jm(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 f=new Map;for(let y of w){let b=y.sourceName;for(let g=2;d.has(b);g+=1)b=`${y.sourceName} (${g})`;d.add(b),a.push({sourceName:b,duration:y.duration}),i.set(b,{url:l,sourceName:y.sourceName}),f.set(y.sourceName,b)}n.set(l,f)}return{clipDetails:a,targets:i,displayNamesByUrl:n,clipDetailsByUrl:o}}function Em(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 zd(e){let t=Za(new Map),a=Za(new Map),i=Za(new Map),[n,o]=Ld(0),[d,l]=Ld(0),c=fn((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?.()??Om);let j=M.subscribe?.(R=>{a.current.set(r,R),l(E=>E+1)});j&&i.current.set(r,j),o(R=>R+1)},[]);Id(()=>{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]),Id(()=>()=>i.current.forEach(r=>r()),[]);let{clipDetails:w,targets:f,displayNamesByUrl:y,clipDetailsByUrl:b,hasModels:g}=Dd(()=>({...jm(e,t.current),hasModels:t.current.size>0}),[e,n]),B=Za(f);B.current=f;let v=Dd(()=>Em(e,a.current,y),[e,y,d]),P=fn((r,M,j)=>{j(),!M.subscribe&&M.getState&&(a.current.set(r,M.getState()),l(R=>R+1))},[]),x=fn(r=>{t.current.forEach((M,j)=>P(j,M,()=>r(M,j)))},[P]),C=fn((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=fn((r,M)=>C(r,(j,R)=>j.play(R.sourceName,M)),[C]),h=fn(r=>r===void 0?x(M=>M.pause()):C(r,(M,j)=>M.pause(j.sourceName)),[x,C]),k=fn(r=>r===void 0?x(M=>M.stop()):C(r,(M,j)=>M.stop(j.sourceName)),[x,C]),O=fn((r,M)=>M===void 0?x(j=>j.setSpeed(r)):C(M,(j,R)=>j.setSpeed(r,R.sourceName)),[x,C]),p=fn((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:b,displayNamesByUrl:y,hasModels:g,active:v,play:S,pause:h,stop:k,setSpeed:O,seek:p,handleModelAnimationsReady:c}}import{useEffect as zm,useMemo as Fm}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 Qa(e){return e!==null&&typeof e=="object"&&!Array.isArray(e)}function ta(e,t){if(!Qa(e)||!Qa(t))return t??e;let a={...e};for(let[i,n]of Object.entries(t)){if(i==="section"){a[i]=Ha(a[i],n);continue}if(i==="sequences"){a[i]=_n(n);continue}let o=a[i];a[i]=Qa(o)&&Qa(n)?ta(o,n):n}return a}import{useCallback as In,useReducer as Im,useRef as Dm}from"react";var Lm=100;function hn(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(-Lm),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]=Im(hn,{past:[],present:e,future:[],edits:0,baseline:e}),n=Dm(0),o=In(g=>{let B=Date.now(),v=B-n.current<t;n.current=B,i({type:"set",updater:g,coalesce:v,track:!0})},[t]),d=In(g=>{let B=Date.now()-n.current<t;i({type:"set",updater:g,coalesce:B,track:!1})},[t]),l=In(g=>{n.current=0,i({type:"set",updater:g,coalesce:!1,track:!0})},[]),c=In(g=>{i({type:"history",updater:g})},[]),w=In(g=>{n.current=0,i({type:"history",updater:typeof g=="function"?g:()=>g})},[]),f=In(()=>{n.current=0,i({type:"undo"})},[]),y=In(()=>{n.current=0,i({type:"redo"})},[]),b=In((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:f,redo:y,reset:b,canUndo:a.past.length>0,canRedo:a.future.length>0,edits:a.edits,baseline:a.baseline}}function Hm(e,t){return e.sourceName===t.sourceName&&e.displayName===t.displayName&&e.hidden===t.hidden&&e.loopMode===t.loopMode&&e.speed===t.speed}function Fd(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:Rn(o),sceneHistory:hn(d,{type:"set",updater:o,track:i,coalesce:!1})}}function Hd({modelUrl:e,sceneConfig:t,setSceneConfig:a,setSceneConfigUntracked:i,parkedModels:n,setParkedModels:o,animations:d,markSessionEdited:l}){let{clipDetailsByUrl:c,displayNamesByUrl:w}=d;zm(()=>{let b=e?c.get(e):void 0;b&&i(g=>{let B=ea(g,b);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=Fd(P,t,ea(C,x),!1);return B||(B=S!==P),S});return B?v:g})},[c,e,t,i,o]);let f=Fm(()=>{let b=[],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&&b.push({...C,sourceName:S,displayName:C.displayName===C.sourceName?S:C.displayName})}g??(g=x.autoplayClip?v.get(x.autoplayClip)??null:null)}return{clips:b,autoplayClip:g}},[w,c,e,t,n]);return{config:f,onChange:b=>{let g=new Map(f.clips.map(P=>[P.sourceName,P])),B=new Map(b.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)??[]),h=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 Hm(O,M)?O:M}),k=b.autoplayClip===f.autoplayClip?S.autoplayClip:[...C].find(([,O])=>O===b.autoplayClip)?.[0]??null;return k===S.autoplayClip&&h.every((O,p)=>O===S.clips[p])?S:{clips:h,autoplayClip:k}};e&&a(P=>{let x=v(e,P);return x===P.animations?P:{...P,animations:x}}),o(P=>P.map(x=>Fd(x,t,v(x.url,mt(t,x.modelSettings)),!0))),l()}}}import{useEffect as Ud,useMemo as Vm,useRef as qm,useState as xn}from"react";import{Copy as Um,DiamondPlus as Km,Plus as ur,ScanLine as Gm,Trash2 as mr}from"lucide-react";import{useEffect as $d,useState as Vd}from"react";import{Fragment as $m,jsx as ft,jsxs as Dn}from"react/jsx-runtime";function Qn({label:e,value:t,onChange:a,min:i,max:n,step:o=.1,disabled:d=!1}){let[l,c]=Vd(String(Number(t.toFixed(5))));return $d(()=>c(String(Number(t.toFixed(5)))),[t]),Dn("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:f=>c(f.target.value),onBlur:()=>{let f=l.trim()?Number(l):NaN;Number.isFinite(f)&&(i===void 0||f>=i)&&(n===void 0||f<=n)&&f!==t&&a(f),c(String(Number(t.toFixed(5))))},onKeyDown:f=>{f.stopPropagation(),f.key==="Enter"&&f.currentTarget.blur(),f.key==="Escape"&&(f.preventDefault(),c(String(t)))}})]})}function br({label:e,value:t,onChange:a}){let[i,n]=Vd(t);return $d(()=>n(t),[t]),Dn("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 pr({label:e,value:t,onChange:a,degrees:i=!1}){return Dn("fieldset",{className:"sq-vector",children:[Dn("legend",{children:[e,i?" (\xB0)":""]}),ft("div",{children:t.map((n,o)=>ft(Qn,{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 qd({target:e,value:t,onChange:a}){if(e.kind==="camera"){let i=t;return Dn($m,{children:[ft(pr,{label:"Camera position",value:i.position,onChange:n=>a({...i,position:n})}),ft(pr,{label:"Camera target",value:i.target,onChange:n=>a({...i,target:n})}),Dn("div",{className:"sq-twoFields",children:[i.fov!==null&&ft(Qn,{label:"Field of view (\xB0)",min:1,max:179,value:i.fov,onChange:n=>a({...i,fov:n})}),ft(Qn,{label:"Zoom",min:.001,value:i.zoom,onChange:n=>a({...i,zoom:n})})]})]})}return Array.isArray(t)?ft(pr,{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"?Dn("label",{className:"sq-check",children:[ft("input",{type:"checkbox",checked:t,onChange:i=>a(i.target.checked)}),"Visible"]}):typeof t=="string"?Dn("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(Qn,{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 Gd,jsx as Y,jsxs as ve}from"react/jsx-runtime";var eo=()=>crypto.randomUUID(),Kd={position:"Position",rotation:"Rotation",scale:"Scale",visible:"Visibility",baseColor:"Color",emissive:"Emissive color",opacity:"Opacity",roughness:"Roughness",metalness:"Metalness",emissiveIntensity:"Emissive intensity"},_m={linear:"Linear","ease-in":"Ease in","ease-out":"Ease out","ease-in-out":"Ease in / out",step:"Hold / step"};function gr({config:e,onChange:t,controls:a,bindings:i,clipDetails:n}){let{tier:o}=dt(),d=gl(a),l=Vm(()=>{try{return{sequences:_n(e.sequences??[]),error:""}}catch(A){return{sequences:[],error:A instanceof Error?A.message:"Invalid sequence data."}}},[e.sequences]),c=l.sequences,[w,f]=xn(null),[y,b]=xn(null),[g,B]=xn(null),[v,P]=xn("object"),[x,C]=xn(""),[S,h]=xn("position"),[k,O]=xn(""),[p,r]=xn(""),[M,j]=xn(null),R=qm(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],ke=Object.values(i).filter((A,X,bt)=>!A.removed&&bt.findIndex(be=>be.modelObjectId===A.modelObjectId)===X),he=ke.find(A=>A.modelObjectId===x)??ke[0],I=n.some(A=>A.sourceName===k)?k:n[0]?.sourceName;Ud(()=>{E&&a&&d.sequenceId!==E.id&&a.select(E.id)},[a,E?.id,d]),Ud(()=>()=>a?.stop(),[a]);let Q=A=>{try{let X=_n(A);t({...e,sequences:X}),r("")}catch(X){r(X instanceof Error?X.message:"Invalid sequence.")}},G=A=>Q(c.map(X=>X.id===A.id?A:X)),L=A=>{E&&G({...E,tracks:E.tracks.map(X=>X.id===A.id?A:X)})},oe=(A,X)=>{if(!E||!pl(X.value,A.target)){r("Use a valid value; scale components must be nonzero.");return}L(bl(A,{...X,time:Math.max(0,Math.min(E.duration,X.time))})),b(A.id),B(X.id),a?.pause(),a?.seek(X.time)},tt=()=>{if(c.length>=64)return;let A={id:eo(),name:`Sequence ${c.length+1}`,duration:5,loop:!1,autoPlay:!1,tracks:[]};Q([...c,A]),f(A.id),b(null),B(null)},me=v==="camera"?{kind:"camera"}:v==="clip"?I?{kind:"clip",clip:I}:null:he?{kind:"object",objectId:he.modelObjectId,property:S}:null,wt=!!me&&E?.tracks.some(A=>$i(A.target)===$i(me)),Vn=()=>{if(!E||!me||wt)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 X=me.kind==="clip"?Math.min(E.duration,n.find(be=>be.sourceName===me.clip)?.duration??E.duration):structuredClone(A),bt={id:eo(),name:me.kind==="camera"?"Camera":me.kind==="clip"?me.clip:`${he?.label||he?.modelObjectId} \xB7 ${Kd[S]}`,target:me,keyframes:[{id:eo(),time:0,value:A,easing:S==="visible"&&v==="object"?"step":"ease-in-out"},{id:eo(),time:E.duration,value:X}]};G({...E,tracks:[...E.tracks,bt]}),b(bt.id),B(bt.keyframes[1].id),a?.seek(E.duration)},Do=()=>{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 X={id:eo(),time:Math.min(d.time,E.duration),value:A,easing:"ease-in-out"};oe(z,X)};return ve("section",{className:"sq-editor","aria-label":"Visual sequence authoring",children:[ve("header",{className:"sq-header",children:[ve("div",{children:[Y("h2",{children:"Sequences"}),Y("p",{children:"Build timed camera moves, object changes and clip playback."})]}),Y("button",{type:"button",className:"bb-iconButton",title:"Add sequence","aria-label":"Add sequence",disabled:c.length>=64||!vt(o,"sequences",c.length),onClick:tt,children:Y(ur,{size:17})})]}),l.error&&Y("p",{role:"alert",className:"sq-error",children:l.error}),vt(o,"sequences",c.length)?null:Y(_e,{requiredTier:un("sequences",c.length),feature:"More sequences"}),E?ve(Gd,{children:[ve("div",{className:"sq-picker",children:[ve("label",{className:"sq-field",children:[Y("span",{children:"Sequence"}),Y("select",{"aria-label":"Authored sequence",value:E.id,onChange:A=>{f(A.target.value),b(null),B(null),a?.select(A.target.value)},children:c.map(A=>Y("option",{value:A.id,children:A.name},A.id))})]}),Y("button",{type:"button",className:"bb-iconButton",title:"Duplicate sequence","aria-label":"Duplicate sequence",disabled:c.length>=64,onClick:()=>{let A={...structuredClone(E),id:eo(),name:`${E.name} copy`.slice(0,256),autoPlay:!1};Q([...c,A]),f(A.id)},children:Y(Um,{size:15})}),Y("button",{type:"button",className:"bb-iconButton",title:"Delete sequence","aria-label":"Delete sequence",onClick:()=>{a?.stop(),Q(c.filter(A=>A.id!==E.id)),f(null)},children:Y(mr,{size:15})})]}),Y(br,{label:"Sequence name",value:E.name,onChange:A=>G({...E,name:A})}),ve("div",{className:"sq-settings",children:[Y(Qn,{label:"Duration (s)",min:.1,max:3600,value:E.duration,onChange:A=>G({...E,duration:A,tracks:E.tracks.map(X=>({...X,keyframes:X.keyframes.map(bt=>({...bt,time:bt.time/E.duration*A}))}))})}),ve("label",{className:"sq-check",children:[Y("input",{type:"checkbox",checked:E.loop,onChange:A=>G({...E,loop:A.target.checked})}),"Loop"]}),ve("label",{className:"sq-check",children:[Y("input",{type:"checkbox",checked:E.autoPlay,onChange:A=>Q(c.map(X=>({...X,autoPlay:X.id===E.id?A.target.checked:!1})))}),"Autoplay in viewer"]})]}),Y(fl,{controls:a,duration:E.duration,hasTracks:E.tracks.some(A=>!A.muted&&A.keyframes.length>0)}),ve("div",{className:"sq-timeline","aria-label":"Sequence timeline",children:[Y("div",{className:"sq-ruler",children:[0,.25,.5,.75,1].map(A=>ve("span",{children:[(E.duration*A).toFixed(1),"s"]},A))}),!E.tracks.length&&Y("p",{className:"sq-hint",children:"Add a track below to create its start and end keyframes."}),E.tracks.map(A=>ve("div",{className:`sq-track ${z?.id===A.id?"sq-track--active":""}`,children:[ve("div",{className:"sq-trackLabel",children:[Y("button",{type:"button",title:A.name,onClick:()=>{b(A.id),B(A.keyframes[0]?.id??null)},children:A.name}),ve("label",{title:"Mute track",children:[Y("input",{"aria-label":`Mute ${A.name}`,type:"checkbox",checked:!!A.muted,onChange:X=>L({...A,muted:X.target.checked})}),"Mute"]})]}),ve("div",{className:"sq-lane",role:"group","aria-label":`${A.name} keyframes`,onDoubleClick:X=>{if(X.target!==X.currentTarget)return;let bt=X.currentTarget.getBoundingClientRect(),be=Math.round(Math.max(0,Math.min(1,(X.clientX-bt.left)/bt.width))*E.duration*100)/100,Ue=a?.capture(A.target);Ue!=null&&oe(A,{id:eo(),time:be,value:Ue})},children:[Y("span",{className:"sq-playhead",style:{left:`${d.time/E.duration*100}%`}}),A.keyframes.map(X=>{let bt=M?.frameId===X.id&&M.trackId===A.id?M.time:X.time;return Y("button",{type:"button",className:`sq-key ${pe?.id===X.id&&z?.id===A.id?"sq-key--active":""}`,style:{left:`${bt/E.duration*100}%`},"aria-label":`${A.name} keyframe at ${bt.toFixed(2)} seconds`,"aria-pressed":pe?.id===X.id&&z?.id===A.id,onClick:be=>{be.detail===0&&(b(A.id),B(X.id),a?.pause(),a?.seek(X.time))},onPointerDown:be=>{if(be.button!==0)return;be.preventDefault(),be.stopPropagation(),be.currentTarget.focus(),be.currentTarget.setPointerCapture(be.pointerId);let Ue=be.currentTarget.parentElement.getBoundingClientRect();R.current={track:A,frame:X,left:Ue.left,width:Ue.width,time:X.time},b(A.id),B(X.id),a?.pause(),a?.seek(X.time)},onPointerMove:be=>{let Ue=R.current;if(!Ue||Ue.frame.id!==X.id||Ue.track.id!==A.id)return;let ma=be.shiftKey?.01:.1;Ue.time=Math.min(E.duration,Math.max(0,Math.round((be.clientX-Ue.left)/Ue.width*E.duration/ma)*ma)),j({trackId:A.id,frameId:X.id,time:Ue.time}),a?.seek(Ue.time)},onPointerUp:()=>{let be=R.current;be&&(be.time!==be.frame.time&&oe(be.track,{...be.frame,time:be.time}),R.current=null,j(null))},onPointerCancel:()=>{R.current=null,j(null),a?.seek(X.time)},onKeyDown:be=>{if(!["ArrowLeft","ArrowRight","Home","End"].includes(be.key))return;be.preventDefault(),be.stopPropagation();let Ue=be.key==="Home"?0:be.key==="End"?E.duration:X.time+(be.key==="ArrowLeft"?-1:1)*(be.shiftKey?.01:.1);oe(A,{...X,time:Ue})}},X.id)})]})]},A.id))]}),Y("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."}),ve("div",{className:"sq-addTrack",children:[Y("h3",{children:"Add track"}),ve("div",{className:"sq-twoFields",children:[ve("label",{className:"sq-field",children:[Y("span",{children:"Track type"}),ve("select",{"aria-label":"Track type",value:v,onChange:A=>P(A.target.value),children:[Y("option",{value:"object",children:"Object"}),Y("option",{value:"camera",children:"Camera"}),Y("option",{value:"clip",children:"Animation clip"})]})]}),v==="object"&&ve("label",{className:"sq-field",children:[Y("span",{children:"Property"}),Y("select",{"aria-label":"Track property",value:S,onChange:A=>h(A.target.value),children:dl.map(A=>Y("option",{value:A,children:Kd[A]},A))})]})]}),v==="object"&&ve("label",{className:"sq-field",children:[Y("span",{children:"Object"}),Y("select",{"aria-label":"Track object",value:he?.modelObjectId??"",onChange:A=>C(A.target.value),children:ke.map(A=>Y("option",{value:A.modelObjectId,children:A.label||A.modelObjectId},A.modelObjectId))})]}),v==="clip"&&ve("label",{className:"sq-field",children:[Y("span",{children:"Clip"}),Y("select",{"aria-label":"Track animation clip",value:I??"",onChange:A=>O(A.target.value),children:n.map(A=>Y("option",{value:A.sourceName,children:A.sourceName},A.sourceName))}),!n.length&&Y("small",{children:"This model has no animation clips."})]}),ve("button",{type:"button",className:"bb-button",onClick:Vn,disabled:!me||!d.ready||wt||E.tracks.length>=128,children:[Y(ur,{size:14}),"Add track"]}),wt&&Y("p",{className:"sq-hint",children:"That property already has a track."})]}),z&&ve("section",{className:"sq-inspector","aria-label":"Selected track and keyframe",children:[ve("div",{className:"sq-inspectorTitle",children:[Y("h3",{children:"Selected track"}),Y("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)}),b(null),B(null)},children:Y(mr,{size:14})})]}),Y(br,{label:"Track name",value:z.name,onChange:A=>L({...z,name:A})}),ve("button",{type:"button",className:"bb-button",disabled:!d.ready||z.keyframes.length>=2048,onClick:Do,children:[Y(Km,{size:14}),"Capture keyframe at playhead"]}),pe&&ve(Gd,{children:[ve("div",{className:"sq-inspectorTitle",children:[Y("h3",{children:"Keyframe"}),Y("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:Y(mr,{size:14})})]}),ve("div",{className:"sq-twoFields",children:[Y(Qn,{label:"Keyframe time (s)",min:0,max:E.duration,value:pe.time,step:.01,onChange:A=>oe(z,{...pe,time:A})}),ve("label",{className:"sq-field",children:[Y("span",{children:"To next key"}),Y("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=>oe(z,{...pe,easing:A.target.value}),children:cl.map(A=>Y("option",{value:A,children:_m[A]},A))})]})]}),Y(qd,{target:z.target,value:pe.value,onChange:A=>oe(z,{...pe,value:A})}),ve("button",{type:"button",className:"bb-button",disabled:!d.ready,onClick:()=>{let A=a?.capture(z.target);A!=null&&oe(z,{...pe,value:A})},children:[Y(Gm,{size:14}),"Capture current value"]})]})]}),Y("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."})]}):ve("div",{className:"sq-empty",children:[Y("p",{children:"Create a sequence, add tracks, then edit or capture keyframes on the timeline."}),ve("button",{type:"button",className:"bb-button bb-button--primary",onClick:tt,children:[Y(ur,{size:14}),"Create sequence"]})]}),(p||d.issues.length>0)&&Y("div",{role:"status",className:"sq-error",children:p||d.issues.join(" ")})]})}import{useLayoutEffect as Wd,useRef as fr,useState as hr}from"react";import{createPortal as Ym}from"react-dom";import{ChevronDown as Jm,Info as Xm}from"lucide-react";import{HexColorInput as Zm,HexColorPicker as Qm}from"react-colorful";function Ln(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 Wm}from"react";function _d(e,t,a){Wm(()=>{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 Se,jsxs as St}from"react/jsx-runtime";function oa({anchorRef:e,onClose:t,children:a}){let i=fr(null),[n,o]=hr(null);return _d([i,e],t,!0),Wd(()=>{let d=e.current;if(!d)return;let l=d.getBoundingClientRect(),c=222,w=8,f=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:f})},[e]),n?Ym(Se("div",{ref:i,className:"se-colorPickerPopover",style:{position:"fixed",top:n.top,left:n.left},children:a}),document.body):null}function eg(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 yn({title:e,children:t}){return St("section",{className:"se-section",children:[Se("h3",{className:"se-sectionTitle",children:e}),Se("div",{className:"se-sectionBody",children:t})]})}function we({title:e,open:t,onToggle:a,trailing:i,children:n,disabled:o,tooltip:d}){let l=d?`${d}`:e;return St("section",{className:"se-panel",children:[St("button",{type:"button",className:"se-panelHeader",onClick:a,"aria-expanded":t,title:l,children:[St("span",{className:"se-panelHeaderMain",children:[Se(Jm,{size:16,className:`se-panelChevron ${t?"se-panelChevron--open":""}`}),Se("span",{className:"se-panelTitle",children:e}),d?Se("span",{className:"se-panelHelp",title:l,"aria-label":l,role:"img",onClick:c=>c.stopPropagation(),children:Se(Xm,{size:13})}):null]}),i?Se("span",{className:"se-panelTrailing",onClick:c=>c.stopPropagation(),children:i}):null]}),t?Se("div",{className:"se-panelBody",style:o?{opacity:.45,pointerEvents:"none"}:void 0,children:n}):null]})}function Me({checked:e,onChange:t,label:a}){return St("label",{className:"se-switch","aria-label":a,children:[Se("input",{type:"checkbox",checked:e,onChange:i=>t(i.target.checked)}),Se("span",{className:"se-switchTrack",children:Se("span",{className:"se-switchThumb"})})]})}function D({label:e,value:t,min:a,max:i,step:n,formatValue:o,onChange:d,disabled:l=!1}){return St("label",{className:`se-field ${l?"se-field--disabled":""}`,children:[St("span",{className:"se-fieldLabel",children:[e,Se("span",{className:"se-fieldValue",children:o?o(t):t})]}),Se("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 St("label",{className:"se-field se-fieldInline",children:[Se("span",{className:"se-fieldLabel",children:e}),Se("input",{type:"checkbox",className:"se-checkbox",checked:t,onChange:i=>a(i.target.checked)})]})}function Rt({label:e,value:t,options:a,onChange:i}){return St("label",{className:"se-field se-fieldInline",children:[Se("span",{className:"se-fieldLabel",children:e}),Se("select",{className:"se-select",value:t,onChange:n=>i(n.target.value),children:a.map(n=>Se("option",{value:n,children:eg(n)},n))})]})}function Nt({label:e,value:t,onChange:a}){let[i,n]=hr(!1),o=fr(null);return St("div",{className:"se-field",children:[St("div",{className:"se-fieldInline",children:[Se("span",{className:"se-fieldLabel",children:e}),Se("span",{ref:o,style:{display:"inline-flex"},children:Se(Zm,{prefixed:!0,className:"se-swatch",onClick:()=>n(d=>!d),style:{background:t,color:Ln(t)},color:t,onChange:a})})]}),i?Se(oa,{anchorRef:o,onClose:()=>n(!1),children:Se(Qm,{color:t,onChange:a})}):null]})}function Yd({value:e,min:t,max:a,step:i,onChange:n}){let[o,d]=hr(String(e)),l=fr(!1);return Wd(()=>{l.current||d(String(e))},[e]),Se("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 zt({label:e,value:t,min:a,max:i,step:n,onChange:o}){return St("div",{className:"se-field",children:[Se("span",{className:"se-fieldLabel",children:e}),Se("div",{className:"se-vectorRow",children:["X","Y","Z"].map((l,c)=>St("label",{className:"se-vectorAxis",children:[Se("span",{children:l}),Se(Yd,{value:t[c],min:a,max:i,step:n,onChange:w=>{let f=[...t];f[c]=w,o(f)}})]},l))})]})}function to({label:e,value:t,min:a,max:i,step:n,onChange:o}){return St("div",{className:"se-field",children:[Se("span",{className:"se-fieldLabel",children:e}),Se("div",{className:"se-vectorRow",children:["X","Y"].map((l,c)=>St("label",{className:"se-vectorAxis",children:[Se("span",{children:l}),Se(Yd,{value:t[c],min:a,max:i,step:n,onChange:w=>{let f=[...t];f[c]=w,o(f)}})]},l))})]})}import{Copy as tg,Trash2 as ng,Plus as og}from"lucide-react";import{jsx as nt,jsxs as Ft}from"react/jsx-runtime";function xr(e){let t=e.assets.find(i=>i.url===e.activeUrl),a=t?.placement??{};return Ft("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:Ft("button",{type:"button",className:"bb-button bb-button--ghost",disabled:e.busy||!!e.addRequiresTier,onClick:e.onAdd,children:[nt(og,{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:Ft("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:Ft("div",{className:"se-panelBody ri-assets-fields",children:[Ft("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})})]}),Ft("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(zt,{min:-1e6,max:1e6,label:"Position",value:a.position??[0,0,0],step:.1,onChange:i=>e.onChange(t.id,{position:i})}),nt(zt,{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(zt,{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})}}),Ft("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)}})]}),Ft("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"})]}),Ft("div",{className:"ri-assets-actions",children:[Ft("button",{type:"button",className:"bb-button bb-button--ghost",disabled:e.busy||!t.ready,onClick:()=>e.onDuplicate(t.url),children:[nt(tg,{size:14}),"Duplicate"]}),Ft("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":e.deleteIsPermanent?"Delete asset":"Delete asset (undoable)",onClick:()=>e.onDelete(t.url),children:[nt(ng,{size:14}),"Delete"]})]}),Ft("small",{className:"ri-assets-hint",children:["Instance ID: ",t.id]})]})})]})}import{Layers as lf}from"lucide-react";import{useState as df,useEffect as cf}from"react";import{useEffect as Jd,useRef as Xd,useState as Zd}from"react";import{ChevronDown as ag,ChevronLeft as ig,ChevronRight as rg,FileUp as sg,RotateCcw as lg,X as dg}from"lucide-react";import{HexColorInput as cg,HexColorPicker as pg}from"react-colorful";import{Fragment as yr,jsx as $,jsxs as Ae}from"react/jsx-runtime";var bg="image/png,image/jpeg,image/webp,image/avif,image/gif";function ug(e){let t=e.trim();return!!(t&&nn(t))||/^(blob:|data:image\/)/i.test(t)}var mg=["lit","unlit","normals"],gg=["color","image","environment"];function Qd(e){let t=e%360;return t<0?t+360:t}function zn({title:e,open:t,onToggle:a,children:i,trailing:n}){return Ae("section",{className:"se-panel",children:[Ae("button",{type:"button",className:"se-panelHeader",onClick:a,"aria-expanded":t,children:[Ae("span",{className:"se-panelHeaderMain",children:[$(ag,{size:16,className:`se-panelChevron ${t?"se-panelChevron--open":""}`}),$("span",{className:"se-panelTitle",children:e})]}),n?$("span",{className:"se-panelTrailing",onClick:o=>o.stopPropagation(),children:n}):null]}),t?$("div",{className:"se-panelBody",children:i}):null]})}function vr({diagnostics:e,onDiagnosticsOpenChange:t,config:a,onChange:i,materialVariantGroups:n=[],onImageFile:o}){let{model:d,camera:l,wireframe:c,background:w,environment:f}=a,y=Xd(null),[b,g]=Zd(null),B=ug(w.imageUrl),v=Dl(d),P=n.length>0?v.filter(L=>!n.some(oe=>oe.variants.some(tt=>tt.name===L))):[],{tier:x,measurementPanelTarget:C,setMeasurementPanelTarget:S,measurementsPanelOpen:h,setMeasurementsPanelOpen:k}=dt(),O=Xd(null);Jd(()=>{h&&C&&O.current?.scrollIntoView({block:"start"})},[h,C]);let p=Ga(),[r,M]=Zd({diagnostics:!1,general:!0,camera:!0,autoRotate:!1,section:!1,wireframe:!1,background:!1});Jd(()=>(t?.(r.diagnostics),()=>t?.(!1)),[r.diagnostics,t]);let j=L=>M(oe=>({...oe,[L]:!oe[L]})),R=L=>i({...a,model:L}),E=L=>i({...a,camera:L}),z=a.section??Cl,pe=L=>i({...a,section:{...z,...L}}),ke=L=>i({...a,wireframe:L}),he=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 oe=So(L);oe===w.imageUrl&&nn(oe)||Xt(oe,URL.createObjectURL(L)),o?.(oe,L),he({...w,imageUrl:oe})},G=L=>{I({...f,source:"preset",preset:L})};return Ae("div",{className:"se-generalContent",children:[Ae(zn,{title:"General",open:r.general,onToggle:()=>j("general"),children:[Ae("div",{className:"se-field",children:[Ae("div",{className:"se-fieldLabel",children:[$("span",{children:"Straighten model"}),$("button",{type:"button",className:"se-iconButton",onClick:()=>R({...d,rotation:[0,0,0]}),"aria-label":"Reset model rotation",children:$(lg,{size:16})})]}),$("div",{className:"se-axisStepperGrid",children:["X","Y","Z"].map((L,oe)=>Ae("div",{className:"se-axisStepper",children:[$("button",{type:"button",className:"se-axisStepperButton",onClick:()=>{let tt=[...d.rotation];tt[oe]=Qd(tt[oe]-90),R({...d,rotation:tt})},"aria-label":`Rotate ${L} axis backward`,children:$(ig,{size:16})}),$("span",{className:"se-axisStepperLabel",children:L}),$("button",{type:"button",className:"se-axisStepperButton",onClick:()=>{let tt=[...d.rotation];tt[oe]=Qd(tt[oe]+90),R({...d,rotation:tt})},"aria-label":`Rotate ${L} axis forward`,children:$(rg,{size:16})})]},L))})]}),$(zt,{label:"Rotation",value:d.rotation,min:0,max:360,step:1,onChange:L=>R({...d,rotation:L})}),Ae("div",{className:"se-field",children:[$("span",{className:"se-fieldLabel",children:"Renderer"}),$("div",{className:"se-segmentedControl se-segmentedControl--renderer",children:yl.map(L=>$("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))})]}),$(Rt,{label:"Shading",value:d.shading,options:mg,onChange:L=>R({...d,shading:L})}),n.length>0&&!lt(x,"materialVariants")?$(_e,{requiredTier:"starter",feature:"Material variants"}):null,(lt(x,"materialVariants")?n:[]).map((L,oe)=>{let tt=v.find(me=>L.variants.some(wt=>wt.name===me));return Ae("label",{className:"se-field se-fieldInline",children:[$("span",{className:"se-fieldLabel",children:L.name??"Material variant"}),Ae("select",{className:"se-select",value:tt??"",onChange:me=>{let wt=me.target.value,Vn=v.filter(Do=>Do!==tt);R(_i(d,wt?Il(Vn,wt,n):Vn))},children:[$("option",{value:"",children:"Model default"}),L.variants.map(me=>$("option",{value:me.name,children:me.label},me.name))]})]},L.name??`group-${oe}`)}),P.length>0?Ae("div",{className:"se-placeholder se-placeholder--spaced",children:["Not in this model: ",P.join(", "),"."," ",$("button",{type:"button",className:"se-linkButton",onClick:()=>R(_i(d,v.filter(L=>!P.includes(L)))),children:"Remove"})]}):null]}),$("div",{ref:O,className:"se-measurementsSection",children:$(zn,{title:`Measurements (${a.measurements?.items.length??0})`,open:h??!1,onToggle:()=>k?.(!h),children:$("div",{ref:S})})}),e&&$(zn,{title:"Asset diagnostics",open:r.diagnostics,onToggle:()=>j("diagnostics"),children:$(pd,{...e})}),$(zn,{title:"Camera",open:r.camera,onToggle:()=>j("camera"),children:$(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})})}),Ae(zn,{title:"Auto Rotate",open:r.autoRotate,onToggle:()=>j("autoRotate"),trailing:Ae("label",{className:"se-switch","aria-label":"Toggle auto rotate",children:[$("input",{type:"checkbox",checked:d.autoRotate??!1,onChange:L=>R({...d,autoRotate:L.target.checked})}),$("span",{className:"se-switchTrack",children:$("span",{className:"se-switchThumb"})})]}),children:[d.autoRotate&&p?$("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?$(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})}):$("div",{className:"se-placeholder",children:"Enable auto rotate to adjust its speed."})]}),$(zn,{title:"Section Cut",open:r.section,onToggle:()=>j("section"),trailing:Ae("label",{className:"se-switch","aria-label":"Toggle section cut",children:[$("input",{type:"checkbox",checked:z.enabled,onChange:L=>pe({enabled:L.target.checked})}),$("span",{className:"se-switchTrack",children:$("span",{className:"se-switchThumb"})})]}),children:z.enabled?$(Zl,{section:z,onChange:pe}):$("div",{className:"se-placeholder",children:"Cut the model open to see inside. Drag the plane in the preview, or set it here."})}),$(zn,{title:"Wireframe",open:r.wireframe,onToggle:()=>j("wireframe"),trailing:Ae("label",{className:"se-switch","aria-label":"Toggle wireframe preview",children:[$("input",{type:"checkbox",checked:c.enabled,onChange:L=>ke({...c,enabled:L.target.checked})}),$("span",{className:"se-switchTrack",children:$("span",{className:"se-switchThumb"})})]}),children:Ae(yr,{children:[$(D,{label:"Opacity",value:c.opacity,min:0,max:1,step:.01,onChange:L=>ke({...c,opacity:L})}),$(Nt,{label:"Wire color",value:c.color,onChange:L=>ke({...c,color:L})})]})}),$(zn,{title:"Background",open:r.background,onToggle:()=>j("background"),trailing:Ae("label",{className:"se-switch","aria-label":"Toggle scene background",children:[$("input",{type:"checkbox",checked:w.enabled,onChange:L=>he({...w,enabled:L.target.checked})}),$("span",{className:"se-switchTrack",children:$("span",{className:"se-switchThumb"})})]}),children:w.enabled?Ae(yr,{children:[Ae("div",{className:"se-field",children:[$("span",{className:"se-fieldLabel",children:"Background type"}),$("div",{className:"se-segmentedControl",children:gg.map(L=>$("button",{type:"button",className:`se-segmentedOption ${w.type===L?"se-segmentedOption--active":""}`,onClick:()=>he({...w,type:L}),children:L},L))})]}),w.type==="environment"?Ae(yr,{children:[Ae("div",{className:"se-field",children:[$("span",{className:"se-fieldLabel",children:"Environment source"}),Ae("div",{className:"se-segmentedControl",children:[$("button",{type:"button",className:`se-segmentedOption ${f.source==="preset"?"se-segmentedOption--active":""}`,onClick:()=>I({...f,source:"preset"}),children:"PRESET"}),$("button",{type:"button",className:`se-segmentedOption ${f.source==="custom"?"se-segmentedOption--active":""}`,onClick:()=>I({...f,source:"custom"}),children:"CUSTOM"})]})]}),f.source==="preset"?$(Rt,{label:"Environment preset",value:f.preset,options:vl,onChange:G}):lt(x,"customEnvironment")?Ae("label",{className:"se-field",children:[$("span",{className:"se-fieldLabel",children:"Custom environment URL"}),$("input",{type:"text",className:"se-textInput",placeholder:"https://example.com/environment.hdr",value:f.customEnvironmentUrl,onChange:L=>I({...f,customEnvironmentUrl:L.target.value})}),$("span",{className:"bb-note",children:"Enter a HDR, EXR, JPG, JPEG, PNG, or WEBP URL."}),f.customEnvironmentUrl.trim()&&!hl(f.customEnvironmentUrl)?$("span",{className:"bb-note",style:{color:"#fca5a5"},children:"Invalid image/HDRI URL."}):null]}):$(_e,{requiredTier:"starter",feature:"Custom environments"}),$(D,{label:"Environment intensity",value:f.intensity,min:0,max:3,step:.05,onChange:L=>I({...f,intensity:L})})]}):null,w.type==="image"&&!lt(x,"backgroundImages")?$(_e,{requiredTier:"starter",feature:"Background images"}):w.type==="image"?Ae("div",{className:"se-field",children:[$("label",{className:"se-fieldLabel",htmlFor:"se-background-image-url",children:"Background image"}),Ae("div",{className:"bb-fileField",children:[$("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),he({...w,imageUrl:L.target.value})}}),B?$("button",{type:"button",className:"bb-fileFieldButton",onClick:()=>he({...w,imageUrl:""}),"aria-label":"Remove uploaded background image",title:"Remove uploaded image",children:$(dg,{size:18})}):$("button",{type:"button",className:"bb-fileFieldButton",onClick:()=>y.current?.click(),"aria-label":"Upload background image",title:"Upload image",children:$(sg,{size:18})}),$("input",{ref:y,type:"file",accept:bg,className:"bb-hiddenInput",onChange:L=>{let oe=L.target.files?.[0];L.target.value="",oe&&Q(oe)}})]}),$("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."}),b?$("span",{className:"bb-note",style:{color:"#fca5a5"},children:b}):null]}):null,w.type==="color"?Ae("div",{className:"se-field",children:[$("span",{className:"se-fieldLabel",children:"Background color"}),$("div",{className:"se-inlineColorPicker",children:$(pg,{color:w.color,onChange:L=>he({...w,color:L})})}),$("div",{className:"se-fieldInline",children:$(cg,{prefixed:!0,className:"se-swatch",style:{background:w.color,color:Ln(w.color)},color:w.color,onChange:L=>he({...w,color:L})})})]}):null]}):$("div",{className:"se-placeholder",children:"Background rendering is disabled for this scene preset."})})]})}import{useState as hg}from"react";import{jsx as ee,jsxs as aa}from"react/jsx-runtime";function ec({pp:e,set:t,open:a,toggle:i}){let{ssao:n}=e;return aa(we,{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 tc({pp:e,set:t,open:a,toggle:i}){let{autofocus:n}=e;return aa(we,{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(zt,{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 nc({pp:e,set:t,open:a,toggle:i}){let{godRays:n}=e;return aa(we,{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(zt,{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(Rt,{label:"Kernel Size",value:n.kernelSize,options:Jo,onChange:o=>t("godRays",{...n,kernelSize:o})})]})}function oc({pp:e,set:t,open:a,toggle:i}){let{lensflare:n}=e;return aa(we,{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(zt,{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 ac({pp:e,set:t,open:a,toggle:i}){let{depthOfField:n}=e;return aa(we,{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 xe,jsxs as Po}from"react/jsx-runtime";var fg=["linear","reinhard","aces"];function ic({pp:e,set:t,open:a,toggle:i}){let{colorAverage:n}=e;return xe(we,{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:xe(Me,{checked:n.enabled,onChange:o=>t("colorAverage",{...n,enabled:o}),label:"Toggle ColorAverage"}),children:xe("div",{className:"se-placeholder",children:"Averages the frame color using the docs default blend mode."})})}function rc({pp:e,set:t,open:a,toggle:i}){let{brightnessContrast:n}=e;return Po(we,{title:"Brightness Contrast",tooltip:"Raises or lowers overall brightness and contrast across the scene.",open:a.brightnessContrast,onToggle:()=>i("brightnessContrast"),disabled:!n.enabled,trailing:xe(Me,{checked:n.enabled,onChange:o=>t("brightnessContrast",{...n,enabled:o}),label:"Toggle BrightnessContrast"}),children:[xe(D,{label:"Brightness",value:n.brightness,min:-1,max:1,step:.01,onChange:o=>t("brightnessContrast",{...n,brightness:o})}),xe(D,{label:"Contrast",value:n.contrast,min:-1,max:1,step:.01,onChange:o=>t("brightnessContrast",{...n,contrast:o})})]})}function sc({pp:e,set:t,open:a,toggle:i}){let{hueSaturation:n}=e;return Po(we,{title:"Hue Saturation",tooltip:"Shifts the hue and saturation to tint the whole image.",open:a.hueSaturation,onToggle:()=>i("hueSaturation"),disabled:!n.enabled,trailing:xe(Me,{checked:n.enabled,onChange:o=>t("hueSaturation",{...n,enabled:o}),label:"Toggle HueSaturation"}),children:[xe(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})}),xe(D,{label:"Saturation",value:n.saturation,min:-1,max:1,step:.01,onChange:o=>t("hueSaturation",{...n,saturation:o})})]})}function lc({pp:e,set:t,open:a,toggle:i}){let{vignette:n}=e;return Po(we,{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:xe(Me,{checked:n.enabled,onChange:o=>t("vignette",{...n,enabled:o}),label:"Toggle Vignette"}),children:[xe(D,{label:"Offset",value:n.offset,min:0,max:1,step:.01,onChange:o=>t("vignette",{...n,offset:o})}),xe(D,{label:"Darkness",value:n.darkness,min:0,max:1,step:.01,onChange:o=>t("vignette",{...n,darkness:o})}),xe(Ne,{label:"Eskil",checked:n.eskil,onChange:o=>t("vignette",{...n,eskil:o})})]})}function dc({pp:e,set:t,open:a,toggle:i}){let{bloom:n}=e;return Po(we,{title:"Bloom",tooltip:"Makes bright areas glow and bleed softly into nearby pixels.",open:a.bloom,onToggle:()=>i("bloom"),disabled:!n.enabled,trailing:xe(Me,{checked:n.enabled,onChange:o=>t("bloom",{...n,enabled:o}),label:"Toggle Bloom"}),children:[xe(D,{label:"Threshold",value:n.luminanceThreshold,min:0,max:1,step:.01,onChange:o=>t("bloom",{...n,luminanceThreshold:o})}),xe(D,{label:"Smoothing",value:n.luminanceSmoothing,min:0,max:1,step:.01,onChange:o=>t("bloom",{...n,luminanceSmoothing:o})}),xe(D,{label:"Intensity",value:n.intensity,min:0,max:3,step:.05,onChange:o=>t("bloom",{...n,intensity:o})}),xe(Ne,{label:"Mipmap Blur",checked:n.mipmapBlur,onChange:o=>t("bloom",{...n,mipmapBlur:o})}),xe(D,{label:"Radius",value:n.radius,min:0,max:1,step:.01,onChange:o=>t("bloom",{...n,radius:o})}),xe(D,{label:"Levels",value:n.levels,min:1,max:16,step:1,onChange:o=>t("bloom",{...n,levels:o})})]})}function cc({pp:e,set:t,open:a,toggle:i}){let{toneMapping:n}=e;return Po(we,{title:"Tone Mapping",tooltip:"Remaps HDR lighting to screen output and controls exposure style.",open:a.toneMapping,onToggle:()=>i("toneMapping"),disabled:!n.enabled,trailing:xe(Me,{checked:n.enabled,onChange:o=>t("toneMapping",{...n,enabled:o}),label:"Toggle ToneMapping"}),children:[Po("div",{className:"se-field",children:[xe("span",{className:"se-fieldLabel",children:"Mode"}),xe("div",{className:"se-segmentedControl",children:fg.map(o=>xe("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))})]}),xe(D,{label:"Resolution",value:n.resolution,min:64,max:4096,step:64,onChange:o=>t("toneMapping",{...n,resolution:o})}),xe(D,{label:"White Point",value:n.whitePoint,min:0,max:16,step:.01,onChange:o=>t("toneMapping",{...n,whitePoint:o})}),xe(D,{label:"Middle Grey",value:n.middleGrey,min:0,max:1,step:.01,onChange:o=>t("toneMapping",{...n,middleGrey:o})}),xe(D,{label:"Min Luminance",value:n.minLuminance,min:0,max:1,step:.01,onChange:o=>t("toneMapping",{...n,minLuminance:o})}),xe(D,{label:"Average Luminance",value:n.averageLuminance,min:0,max:4,step:.01,onChange:o=>t("toneMapping",{...n,averageLuminance:o})}),xe(D,{label:"Adaptation Rate",value:n.adaptationRate,min:0,max:10,step:.01,onChange:o=>t("toneMapping",{...n,adaptationRate:o})}),xe(D,{label:"Exposure",value:n.exposure,min:0,max:3,step:.01,onChange:o=>t("toneMapping",{...n,exposure:o})})]})}function pc({pp:e,set:t,open:a,toggle:i}){let{sepia:n}=e;return xe(we,{title:"Sepia",tooltip:"Adds a warm vintage brown tint to the entire image.",open:a.sepia,onToggle:()=>i("sepia"),disabled:!n.enabled,trailing:xe(Me,{checked:n.enabled,onChange:o=>t("sepia",{...n,enabled:o}),label:"Toggle Sepia"}),children:xe(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 Bo}from"react/jsx-runtime";function bc({pp:e,set:t,open:a,toggle:i}){let{dotScreen:n}=e;return Bo(we,{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 uc({pp:e,set:t,open:a,toggle:i}){let{glitch:n}=e;return Bo(we,{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(Rt,{label:"Mode",value:n.mode,options:Sl,onChange:o=>t("glitch",{...n,mode:o})}),ce(to,{label:"Delay",value:n.delay,min:0,max:10,step:.01,onChange:o=>t("glitch",{...n,delay:o})}),ce(to,{label:"Duration",value:n.duration,min:0,max:5,step:.01,onChange:o=>t("glitch",{...n,duration:o})}),ce(to,{label:"Strength",value:n.strength,min:0,max:2,step:.01,onChange:o=>t("glitch",{...n,strength:o})}),ce(to,{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 mc({pp:e,set:t,open:a,toggle:i}){let{grid:n}=e;return Bo(we,{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 gc({pp:e,set:t,open:a,toggle:i}){let{chromaticAberration:n}=e;return Bo(we,{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 fc({pp:e,set:t,open:a,toggle:i}){let{noise:n}=e;return Bo(we,{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 hc({pp:e,set:t,open:a,toggle:i}){let{scanline:n}=e;return ce(we,{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 xc({pp:e,set:t,open:a,toggle:i}){let{pixelation:n}=e;return ce(we,{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 yc({pp:e,set:t,open:a,toggle:i}){let{ramp:n}=e;return Bo(we,{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(Rt,{label:"Ramp Type",value:n.rampType,options:wl,onChange:o=>t("ramp",{...n,rampType:o})}),ce(to,{label:"Ramp Start",value:n.rampStart,min:0,max:1,step:.01,onChange:o=>t("ramp",{...n,rampStart:o})}),ce(to,{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 Ke,jsxs as Cc}from"react/jsx-runtime";function vc({pp:e,set:t,open:a,toggle:i}){let{outline:n}=e;return Cc(we,{title:"Outline",tooltip:"Draws a visible edge around the selected object binding.",open:a.outline,onToggle:()=>i("outline"),disabled:!n.enabled,trailing:Ke(Me,{checked:n.enabled,onChange:o=>t("outline",{...n,enabled:o}),label:"Toggle Outline"}),children:[Ke("div",{className:"se-placeholder",children:"Outlines the currently selected object binding in the model editor."}),Ke(D,{label:"Selection Layer",value:n.selectionLayer,min:0,max:20,step:1,onChange:o=>t("outline",{...n,selectionLayer:o})}),Ke(D,{label:"Edge Strength",value:n.edgeStrength,min:0,max:10,step:.1,onChange:o=>t("outline",{...n,edgeStrength:o})}),Ke(D,{label:"Pulse Speed",value:n.pulseSpeed,min:0,max:10,step:.1,onChange:o=>t("outline",{...n,pulseSpeed:o})}),Ke(Nt,{label:"Visible Edge Color",value:n.visibleEdgeColor,onChange:o=>t("outline",{...n,visibleEdgeColor:o})}),Ke(Nt,{label:"Hidden Edge Color",value:n.hiddenEdgeColor,onChange:o=>t("outline",{...n,hiddenEdgeColor:o})}),Ke(Rt,{label:"Kernel Size",value:n.kernelSize,options:Jo,onChange:o=>t("outline",{...n,kernelSize:o})}),Ke(Ne,{label:"Blur",checked:n.blur,onChange:o=>t("outline",{...n,blur:o})}),Ke(Ne,{label:"X-Ray",checked:n.xRay,onChange:o=>t("outline",{...n,xRay:o})})]})}function Sc({pp:e,set:t,open:a,toggle:i}){let{selectiveBloom:n}=e;return Cc(we,{title:"Selective Bloom",tooltip:"Applies bloom only to objects assigned to the selected layer.",open:a.selectiveBloom,onToggle:()=>i("selectiveBloom"),disabled:!n.enabled,trailing:Ke(Me,{checked:n.enabled,onChange:o=>t("selectiveBloom",{...n,enabled:o}),label:"Toggle SelectiveBloom"}),children:[Ke("div",{className:"se-placeholder",children:"Applies bloom to the currently selected object binding."}),Ke(D,{label:"Selection Layer",value:n.selectionLayer,min:0,max:20,step:1,onChange:o=>t("selectiveBloom",{...n,selectionLayer:o})}),Ke(D,{label:"Intensity",value:n.intensity,min:0,max:5,step:.05,onChange:o=>t("selectiveBloom",{...n,intensity:o})}),Ke(D,{label:"Threshold",value:n.luminanceThreshold,min:0,max:1,step:.01,onChange:o=>t("selectiveBloom",{...n,luminanceThreshold:o})}),Ke(D,{label:"Smoothing",value:n.luminanceSmoothing,min:0,max:1,step:.01,onChange:o=>t("selectiveBloom",{...n,luminanceSmoothing:o})}),Ke(Rt,{label:"Kernel Size",value:n.kernelSize,options:Jo,onChange:o=>t("selectiveBloom",{...n,kernelSize:o})}),Ke(Ne,{label:"Mipmap Blur",checked:n.mipmapBlur,onChange:o=>t("selectiveBloom",{...n,mipmapBlur:o})}),Ke(Ne,{label:"Inverted",checked:n.inverted,onChange:o=>t("selectiveBloom",{...n,inverted:o})}),Ke(Ne,{label:"Ignore Background",checked:n.ignoreBackground,onChange:o=>t("selectiveBloom",{...n,ignoreBackground:o})})]})}function wc({pp:e,set:t,open:a,toggle:i}){let{smaa:n}=e;return Ke(we,{title:"SMAA",tooltip:"Reduces jagged edges with subpixel anti-aliasing.",open:a.smaa,onToggle:()=>i("smaa"),trailing:Ke(Me,{checked:n.enabled,onChange:o=>t("smaa",{...n,enabled:o}),label:"Toggle SMAA"}),children:Ke("div",{className:"se-placeholder",children:"Subpixel Morphological Anti-Aliasing smooths jagged edges in post-process."})})}import{Fragment as kc,jsx as ze,jsxs as Sr}from"react/jsx-runtime";function wr({config:e,onChange:t}){let[a,i]=hg({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(f=>({...f,[w]:!f[w]})),{tier:o}=dt(),d=e.postProcessing,c={pp:d,set:(w,f)=>t({...e,postProcessing:{...d,[w]:f}}),open:a,toggle:n};return Sr("div",{className:"se-generalContent",children:[ze(ic,{...c}),ze(rc,{...c}),ze(sc,{...c}),ze(lc,{...c}),ze(dc,{...c}),ze(cc,{...c}),ze(pc,{...c}),lt(o,"postLighting")?Sr(kc,{children:[ze(ec,{...c}),ze(tc,{...c}),ze(nc,{...c}),ze(oc,{...c}),ze(ac,{...c})]}):ze(_e,{requiredTier:"starter",feature:"SSAO, depth of field, god rays and lens flare"}),lt(o,"postSelection")?Sr(kc,{children:[ze(vc,{...c}),ze(Sc,{...c}),ze(wc,{...c}),ze(bc,{...c}),ze(uc,{...c}),ze(mc,{...c}),ze(gc,{...c}),ze(fc,{...c}),ze(hc,{...c}),ze(xc,{...c}),ze(yc,{...c})]}):ze(_e,{requiredTier:"growth",feature:"Outline, selective bloom and stylize effects"})]})}import{useState as Mc,useSyncExternalStore as xg}from"react";import{Eye as yg,EyeOff as vg,Plus as Sg,Trash2 as wg}from"lucide-react";import{Fragment as Nc,jsx as re,jsxs as At}from"react/jsx-runtime";var Cg=["512","1024","2048","4096"],Tc={none:"None",directional:"Direction",point:"Point",spot:"Spot",hemisphere:"Hemi"};function kg({index:e,light:t,selected:a,onSelect:i,onToggleVisible:n}){return At("div",{className:`se-lightRow ${a?"se-lightRow--active":""}`,onClick:i,children:[At("span",{className:"se-lightRowLabel",children:[e+1,": ",Tc[t.type]]}),re("button",{type:"button",className:"se-iconButton","aria-label":t.visible?"Hide light":"Show light",onClick:o=>{o.stopPropagation(),n()},children:t.visible?re(yg,{size:14}):re(vg,{size:14})})]})}function Mg(){return{id:crypto.randomUUID(),type:"directional",color:"#ffffff",intensity:1,position:[5,10,5],attachedToCamera:!1,castShadow:!1,shadowBias:-5e-4,visible:!0}}function Cr({config:e,onChange:t}){let[a,i]=Mc({lights:!0,shadows:!1,groundShadows:!1,environment:!1,envShadow:!1}),n=xg(Wl,Yl),[o,d]=Mc(e.lighting.lights[0]?.id??null),l=n??o,c=r=>{d(r),_l(r)},w=r=>i(M=>({...M,[r]:!M[r]})),{tier:f}=dt(),{lighting:y,shadows:b,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)})},h=y.lights.find(r=>r.id===l)??null,k=()=>{let r=Mg();v({...y,lights:[...y.lights,r]}),c(r.id)},O=()=>{if(!h)return;let r=y.lights.filter(M=>M.id!==h.id);v({...y,lights:r}),c(r[0]?.id??null)},p=vt(f,"lights",y.lights.length);return At("div",{className:"se-generalContent",children:[At(we,{title:"Lights",open:a.lights,onToggle:()=>w("lights"),children:[re("div",{className:"se-lightList",children:y.lights.map((r,M)=>re(kg,{index:M,light:r,selected:r.id===l,onSelect:()=>c(r.id),onToggleVisible:()=>S(r.id,{visible:!r.visible})},r.id))}),p?null:re(_e,{requiredTier:un("lights",y.lights.length),feature:"More lights"}),At("div",{className:"se-lightActions",children:[re("button",{type:"button",className:"se-iconButton",onClick:k,disabled:!p,title:"Add light",children:re(Sg,{size:14})}),h&&y.lights.length>1&&re("button",{type:"button",className:"se-iconButton",onClick:O,title:"Remove selected light",children:re(wg,{size:14})})]}),h?At("div",{className:"se-lightProps",children:[At("div",{className:"se-field",children:[re("span",{className:"se-fieldLabel",children:"Type"}),re("div",{className:"se-segmentedControl",style:{gridAutoColumns:"1fr"},children:xl.map(r=>re("button",{type:"button",className:`se-segmentedOption ${h.type===r?"se-segmentedOption--active":""}`,onClick:()=>S(h.id,{type:r}),children:Tc[r]},r))})]}),re(Nt,{label:"Color",value:h.color,onChange:r=>S(h.id,{color:r})}),re(D,{label:"Intensity",value:h.intensity,min:0,max:10,step:.1,onChange:r=>S(h.id,{intensity:r})}),h.type!=="hemisphere"&&h.type!=="none"&&re(zt,{label:"Position",value:h.position,min:-100,max:100,step:.05,onChange:r=>S(h.id,{position:r})}),h.type==="spot"&&At(Nc,{children:[re(D,{label:"Angle",value:h.angle??Math.PI/6,min:0,max:Math.PI/2,step:.01,formatValue:r=>`${Math.round(r*180/Math.PI)}\xB0`,onChange:r=>S(h.id,{angle:r})}),re(D,{label:"Penumbra",value:h.penumbra??.2,min:0,max:1,step:.01,onChange:r=>S(h.id,{penumbra:r})}),re(D,{label:"Distance",value:h.distance??0,min:0,max:100,step:.5,onChange:r=>S(h.id,{distance:r})}),re(D,{label:"Decay",value:h.decay??2,min:0,max:4,step:.1,onChange:r=>S(h.id,{decay:r})})]}),re(Ne,{label:"Attached to camera",checked:h.attachedToCamera,onChange:r=>S(h.id,{attachedToCamera:r})}),re(Ne,{label:"Cast shadows",checked:h.castShadow,onChange:r=>S(h.id,{castShadow:r})}),re(D,{label:"Shadow bias",value:h.shadowBias,min:-.01,max:.01,step:1e-4,onChange:r=>S(h.id,{shadowBias:r})})]}):null]}),At(we,{title:"Shadows",open:a.shadows,onToggle:()=>w("shadows"),disabled:!b.enabled,trailing:re(Me,{checked:b.enabled,onChange:r=>P({...b,enabled:r}),label:"Toggle shadows"}),children:[re(Rt,{label:"Map size",value:String(b.mapSize),options:Cg,onChange:r=>P({...b,mapSize:Number(r)})}),re(D,{label:"Bias",value:b.bias,min:-.01,max:.01,step:1e-4,onChange:r=>P({...b,bias:r})}),re(D,{label:"Normal bias",value:b.normalBias,min:0,max:.2,step:.01,onChange:r=>P({...b,normalBias:r})}),re(D,{label:"Radius (softness)",value:b.radius,min:0,max:20,step:.5,onChange:r=>P({...b,radius:r})})]}),At(we,{title:"Ground Shadows",open:a.groundShadows,onToggle:()=>w("groundShadows"),disabled:!g.enabled,trailing:re(Me,{checked:g.enabled,onChange:r=>x({...g,enabled:r}),label:"Toggle ground shadows"}),children:[At("div",{className:"se-field",children:[re("span",{className:"se-fieldLabel",children:"Mode"}),re("div",{className:"se-segmentedControl",style:{gridAutoColumns:"1fr"},children:["shadowCatcher"].map(r=>re("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"&&re("div",{className:"se-placeholder",children:"Requires pre-baked AO textures \u2014 not yet available."}),re(D,{label:"Intensity",value:g.intensity,min:0,max:1,step:.01,onChange:r=>x({...g,intensity:r})}),re(D,{label:"Border fade",value:g.borderFade,min:0,max:10,step:.1,onChange:r=>x({...g,borderFade:r})}),re(D,{label:"Height",value:g.height,min:-5,max:5,step:.1,onChange:r=>x({...g,height:r})}),re(D,{label:"Size",value:g.size,min:1,max:50,step:.5,onChange:r=>x({...g,size:r})})]}),re(we,{title:"Environment",open:a.environment,onToggle:()=>w("environment"),children:At(Nc,{children:[re(D,{label:"Orientation",value:B.rotation,min:0,max:360,step:1,formatValue:r=>`${r}\xB0`,onChange:r=>C({...B,rotation:r})}),re(D,{label:"Brightness",value:B.intensity,min:0,max:3,step:.05,onChange:r=>C({...B,intensity:r})}),At(we,{title:"Shadow",open:a.envShadow,onToggle:()=>w("envShadow"),trailing:re(Me,{checked:B.shadowLight.enabled,onChange:r=>C({...B,shadowLight:{...B.shadowLight,enabled:r}}),label:"Toggle environment shadow light"}),disabled:!B.shadowLight.enabled,children:[re(D,{label:"Light intensity",value:B.shadowLight.intensity,min:0,max:20,step:.1,onChange:r=>C({...B,shadowLight:{...B.shadowLight,intensity:r}})}),re(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 Ng,useState as Tg}from"react";import{ChevronDown as Pg,Pause as Pc,Play as Bg,Rewind as Rg,Square as Ag,Trash2 as Og}from"lucide-react";import{jsx as ue,jsxs as Ge}from"react/jsx-runtime";var jg={playing:"Playing",paused:"Paused",finished:"Finished"},Bc={repeat:"Looping",once:"Play once","ping-pong":"Ping-pong"};function Eg(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 Rc(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 Ig(e){return Number.isFinite(e)?Math.min(3,Math.max(.1,Number(e.toFixed(2)))):1}function kr({config:e,onChange:t,clipDetails:a,active:i,play:n,pause:o,stop:d,setSpeed:l,seek:c}){let w=lt(dt().tier,"animationConfig"),[f,y]=Tg(!1),b=Ng(()=>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=Ig(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}))},h=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(yn,{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."})}):Ge(yn,{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=b.get(p.sourceName)??0,E=r?jg[r.status]:"Ready";return Ge("article",{className:`se-animationCard ${r?"se-animationCard--active":""}`,children:[Ge("div",{className:"se-animationHeader",children:[Ge("div",{className:"se-animationHeading",children:[Ge("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(Og,{size:16})})]}),Ge("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"})]}),Ge("div",{className:"se-animationMeta",children:[ue("span",{children:Eg(R)}),ue("span",{children:Bc[p.loopMode]??Bc.repeat}),Ge("span",{children:[p.speed.toFixed(2),"x"]})]}),Ge("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(Pc,{size:16}):ue(Bg,{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(Pc,{size:16}):ue(Rg,{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(Ag,{size:16})})]}),Ge("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"}),Ge("span",{className:"se-animationSeekTime",children:[Rc(Math.min(j,R))," / ",Rc(R)]})]}),w?Ge("div",{className:"se-animationGrid",children:[Ge("label",{className:"se-field",children:[ue("span",{className:"se-fieldLabel",children:"Loop mode"}),Ge("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"})]})]}),Ge("label",{className:"se-field",children:[Ge("span",{className:"se-fieldLabel",children:["Speed",Ge("span",{className:"se-fieldValue",children:[p.speed.toFixed(2),"x"]})]}),Ge("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:()=>h(p.sourceName),children:e.animations.autoplayClip===p.sourceName?"Disable autoplay":"Set as autoplay"}):null]},p.sourceName)})}),B.length>0?Ge("section",{className:"se-removedAnimations",children:[ue("button",{type:"button",className:"se-panelHeader",onClick:()=>y(p=>!p),children:Ge("span",{className:"se-panelHeaderMain",children:[ue(Pg,{size:16,className:`se-panelChevron ${f?"se-panelChevron--open":""}`}),Ge("span",{className:"se-panelTitle",children:["Removed Animations (",B.length,")"]})]})}),f?ue("div",{className:"se-removedAnimationList",children:B.map(p=>Ge("div",{className:"se-removedAnimationRow",children:[Ge("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 Mr}from"react";import{Eye as Dg,Pencil as Lg,Trash2 as zg}from"lucide-react";import{jsx as se,jsxs as ye}from"react/jsx-runtime";function Nr({config:e,onChange:t,cameraState:a,onPreviewView:i}){let[n,o]=Mr(null),[d,l]=Mr(""),[c,w]=Mr(""),f=P=>{o(structuredClone(P)),l(P.minDistance?.toString()??""),w(P.maxDistance?.toString()??"")},y=d.trim()===""?void 0:Number(d),b=c.trim()===""?void 0:Number(c),g=[y,b].some(P=>P!==void 0&&(!Number.isFinite(P)||P<0))?"Distances must be non-negative numbers.":y!==void 0&&b!==void 0&&y>b?"Maximum distance must be at least the minimum.":n?.images?.some(P=>P.src.trim()&&!Vi(P.src))||n?.links?.some(P=>P.href.trim()&&!Vi(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:b,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 ye(yn,{title:"Annotations",children:[e.annotations.length===0?se("div",{className:"bb-emptyAnnotations",children:"No annotations yet. Double-click on the model to add one."}):se("div",{className:"se-annotationList",children:e.annotations.map(P=>ye("div",{className:"se-annotationRow",children:[ye("span",{className:"se-annotationNumber",children:["#",P.id]}),ye("div",{className:"se-annotationSummary",children:[ye("div",{className:"se-annotationHeading",children:[se("span",{className:"se-annotationTitle",title:P.title,children:P.title}),P.category?.trim()&&se("span",{className:"se-annotationCategory",title:P.category,children:P.category})]}),P.description&&se("p",{className:"se-annotationDescription",title:P.description,children:P.description})]}),ye("div",{className:"se-annotationActions",children:[ul(P.cameraView)&&se("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:se(Dg,{size:15,"aria-hidden":"true"})}),se("button",{type:"button",className:"se-annotationAction",onClick:()=>f(P),title:"Edit annotation","aria-label":`Edit ${P.title}`,children:se(Lg,{size:15,"aria-hidden":"true"})}),se("button",{type:"button",className:"se-annotationAction se-annotationAction--delete",onClick:()=>v(P.id),title:"Delete annotation","aria-label":`Delete ${P.title}`,children:se(zg,{size:15,"aria-hidden":"true"})})]})]},P.id))}),n&&se("div",{className:"bb-editAnnotationOverlay",onClick:()=>o(null),children:ye("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:[ye("div",{className:"bb-editAnnotationHeader",children:[se("h3",{id:"annotation-edit-title",className:"bb-editAnnotationTitle",children:"Edit annotation"}),se("button",{className:"bb-editAnnotationClose","aria-label":"Close annotation editor",onClick:()=>o(null),children:"\xD7"})]}),ye("div",{className:"bb-editAnnotationBody",children:[ye("label",{className:"bb-field",children:[se("span",{className:"bb-label",children:"Title"}),se("input",{className:"bb-input",autoFocus:!0,value:n.title,onChange:P=>o({...n,title:P.target.value})})]}),ye("label",{className:"bb-field",children:[se("span",{className:"bb-label",children:"Description"}),se("textarea",{className:"bb-textarea",rows:3,value:n.description,onChange:P=>o({...n,description:P.target.value})})]}),ye("label",{className:"bb-field",children:[se("span",{className:"bb-label",children:"Category"}),se("input",{className:"bb-input",value:n.category??"",onChange:P=>o({...n,category:P.target.value}),placeholder:"For example, Features"})]}),ye("p",{className:"se-annotationCoordinates",children:["Position: [",n.worldPosition.map(P=>P.toFixed(2)).join(", "),"]"]}),ye("fieldset",{className:"bb-annotationFields",children:[se("legend",{children:"Saved camera view"}),se("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."}),ye("div",{className:"bb-annotationFieldActions",children:[se("button",{className:"bb-button",disabled:!a,onClick:()=>a&&o({...n,cameraView:structuredClone(a)}),children:"Capture current view"}),se("button",{className:"bb-button",disabled:!n.cameraView||!i,onClick:()=>n.cameraView&&i?.(n.cameraView),children:"Preview"}),se("button",{className:"bb-button",disabled:!n.cameraView,onClick:()=>o({...n,cameraView:void 0}),children:"Clear view"})]})]}),ye("fieldset",{className:"bb-annotationFields",children:[se("legend",{children:"Marker distance (scene units)"}),se("p",{children:"Leave blank to show markers at any distance."}),ye("div",{className:"bb-annotationDistanceFields",children:[ye("label",{className:"bb-field",children:[se("span",{className:"bb-label",children:"Minimum distance"}),se("input",{className:"bb-input",type:"number",min:"0",step:"any",value:d,onChange:P=>l(P.target.value)})]}),ye("label",{className:"bb-field",children:[se("span",{className:"bb-label",children:"Maximum distance"}),se("input",{className:"bb-input",type:"number",min:"0",step:"any",value:c,onChange:P=>w(P.target.value)})]})]})]}),ye("fieldset",{className:"bb-annotationFields",children:[se("legend",{children:"Images"}),n.images?.map((P,x)=>ye("div",{className:"bb-annotationMediaRow",children:[ye("label",{className:"bb-field",children:[ye("span",{className:"bb-label",children:["Image URL ",x+1]}),se("input",{className:"bb-input",value:P.src,onChange:C=>o({...n,images:n.images.map((S,h)=>h===x?{...S,src:C.target.value}:S)}),placeholder:"https://example.com/image.jpg"})]}),ye("label",{className:"bb-field",children:[ye("span",{className:"bb-label",children:["Image description ",x+1]}),se("input",{className:"bb-input",value:P.alt??"",onChange:C=>o({...n,images:n.images.map((S,h)=>h===x?{...S,alt:C.target.value}:S)})})]}),ye("button",{className:"bb-button",onClick:()=>o({...n,images:n.images.filter((C,S)=>S!==x)}),children:["Remove image ",x+1]})]},x)),se("button",{className:"bb-button",onClick:()=>o({...n,images:[...n.images??[],{src:"",alt:""}]}),children:"Add image"})]}),ye("fieldset",{className:"bb-annotationFields",children:[se("legend",{children:"Links"}),n.links?.map((P,x)=>ye("div",{className:"bb-annotationMediaRow",children:[ye("label",{className:"bb-field",children:[ye("span",{className:"bb-label",children:["Link URL ",x+1]}),se("input",{className:"bb-input",value:P.href,onChange:C=>o({...n,links:n.links.map((S,h)=>h===x?{...S,href:C.target.value}:S)}),placeholder:"https://example.com/details"})]}),ye("label",{className:"bb-field",children:[ye("span",{className:"bb-label",children:["Link label ",x+1]}),se("input",{className:"bb-input",value:P.label,onChange:C=>o({...n,links:n.links.map((S,h)=>h===x?{...S,label:C.target.value}:S)})})]}),ye("button",{className:"bb-button",onClick:()=>o({...n,links:n.links.filter((C,S)=>S!==x)}),children:["Remove link ",x+1]})]},x)),se("button",{className:"bb-button",onClick:()=>o({...n,links:[...n.links??[],{href:"",label:""}]}),children:"Add link"})]}),g&&se("p",{role:"alert",children:g}),ye("div",{className:"bb-editAnnotationActions",children:[se("button",{className:"bb-button",onClick:()=>o(null),children:"Cancel"}),se("button",{className:"bb-button bb-button--primary",disabled:!n.title.trim()||!!g,onClick:B,children:"Save"}),se("button",{className:"bb-button bb-button--danger",onClick:()=>v(n.id),children:"Delete"})]})]})]})})]})}import{useState as Fg,useCallback as no}from"react";import{ArrowDown as Hg,ArrowUp as $g,MapPin as Vg,Plus as qg,Trash2 as Ug,Settings as Kg}from"lucide-react";import{Fragment as _g,jsx as Oe,jsxs as Qe}from"react/jsx-runtime";var Gg={enabled:!0,waypoints:[],loop:!0,autoPlay:!1},oo=3.5;function Tr({config:e,onChange:t,cameraState:a,onPreviewWaypoint:i}){let n=e.cinematic??Gg,o=Ga(),{waypoints:d}=n,l=no((C,S)=>{if(C.length<2)return 0;let h=0;for(let k=0;k<C.length-1;k++){let O=C[k].segmentDuration??oo;h+=O}return S&&C.length>1&&(h+=C[C.length-1].segmentDuration??oo),Math.max(h,0)},[]),c=no(C=>{t({...e,cinematic:{...n,...C}})},[e,n,t]),w=no(()=>{if(!a)return;let C={position:[...a.position],target:[...a.target],...a.azimuthAngle!=null?{azimuthAngle:a.azimuthAngle}:{},...a.polarAngle!=null?{polarAngle:a.polarAngle}:{},segmentDuration:oo},S=[...d,C],h=l(S,n.loop);c({waypoints:S,duration:h})},[a,d,n.loop,l,c]),f=no(C=>{let S=d.filter((k,O)=>O!==C),h=l(S,n.loop);c({waypoints:S,duration:h})},[d,n.loop,l,c]),y=no((C,S)=>{let h=C+S;if(h<0||h>=d.length)return;let k=[...d];[k[C],k[h]]=[k[h],k[C]];let O=l(k,n.loop);c({waypoints:k,duration:O})},[d,n.loop,l,c]),b=no((C,S)=>{let h=d.map((O,p)=>p===C?{...O,...S}:O),k=l(h,n.loop);c({waypoints:h,duration:k})},[d,n.loop,l,c]),[g,B]=Fg(!1),v=d.some(C=>C.segmentDuration!==void 0),P=no(C=>C>=d.length-1?oo:d[C]?.segmentDuration??oo,[d]),x=d.length>=2;return Qe(yn,{title:"Cinematic Camera",children:[Oe("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:[Oe(qg,{size:15}),"Add waypoint from current view"]}),Qe("div",{className:"se-customizeToggle",children:[Qe("label",{className:"se-toggleLabel",children:[Oe("input",{type:"checkbox",checked:g,onChange:C=>B(C.target.checked)}),Oe(Kg,{size:14}),Oe("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: ",oo,"s"]})]}),d.length===0?Oe("div",{className:"bb-emptyAnnotations",children:"No waypoints yet. Position the camera and add your first one."}):Qe(_g,{children:[Oe("div",{className:"se-waypointList",children:d.map((C,S)=>{let h=P(S),k=S===d.length-1,O=C.segmentDuration!==void 0&&C.segmentDuration!==oo;return Qe("div",{children:[Qe("div",{className:"se-waypointCard",children:[Oe("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:[h.toFixed(1),"s",!O&&" (default)"]})]}),Qe("div",{className:"se-waypointActions",children:[Oe("button",{className:"se-waypointAction",onClick:()=>i?.(C),title:"Fly camera to this waypoint",disabled:!i,children:Oe(Vg,{size:15})}),Oe("button",{className:"se-waypointAction",onClick:()=>y(S,-1),title:"Move up",disabled:S===0,children:Oe($g,{size:15})}),Oe("button",{className:"se-waypointAction",onClick:()=>y(S,1),title:"Move down",disabled:k,children:Oe(Hg,{size:15})}),Oe("button",{className:"se-waypointAction se-waypointAction--delete",onClick:()=>f(S),title:"Delete waypoint",children:Oe(Ug,{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:[Oe("span",{className:"se-durationLabel",children:"Duration:"}),Oe("input",{type:"range",className:"se-segmentSlider",min:1,max:20,step:.5,value:h,onChange:p=>{let r=parseFloat(p.target.value);b(S,{segmentDuration:r})}}),Qe("span",{className:"se-segmentValue",children:[h.toFixed(1),"s"]}),Qe("div",{className:"se-presetButtons",children:[[2,4,6,8].map(p=>Qe("button",{className:"se-presetButton",onClick:()=>b(S,{segmentDuration:p}),children:[p,"s"]},`preset-${S}-${p}`)),Oe("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:[Oe("span",{className:"se-totalLabel",children:"Total duration:"}),Oe("span",{className:"se-totalValue",children:x?(n.duration??l(d,n.loop)).toFixed(1)+"s":"-"}),!x&&Oe("span",{className:"se-totalHint",children:"(need at least 2 waypoints)"})]})]}),Oe(Ne,{label:"Enable cinematic camera",checked:n.enabled,onChange:C=>c({enabled:C})}),Oe(Ne,{label:"Loop",checked:n.loop,onChange:C=>{let S=C,h=l(d,S);c({loop:S,duration:h})}}),Oe(Ne,{label:"Auto-play on load",checked:n.autoPlay,onChange:C=>c({autoPlay:C})}),n.autoPlay&&o?Oe("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&&Oe(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 Wg,useRef as Yg,useState as Lc}from"react";import{HexColorInput as Jg,HexColorPicker as Xg}from"react-colorful";import{ArrowDown as Zg,ArrowUp as Qg,ChevronDown as ef,Plus as Pr,Trash2 as tf,X as Oc}from"lucide-react";var Ac=["other","body","light","wheel","glass","interior","floor","wall","door","furniture","decor","electronics","seat","table","chair","window","sofa","bed","engine","headlight"],ei=["normal","hidden","selected","disabled"];import{Fragment as Dc,jsx as K,jsxs as qe}from"react/jsx-runtime";var Br={all:"All objects",group:"Group",tag:"Tag",type:"Type",object:"One object"},jc={metric:"Metric",status:"Status",metadata:"Metadata"},nf={metric:"",stops:[[0,"#3b82f6"],[100,"#ef4444"]]};function of(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 Ec(e,t){if(e!=="all")return e==="object"?t:e==="group"?{group:t}:e==="tag"?{tag:t}:{type:t}}function af(e){return"metric"in e?"metric":"status"in e?"status":"metadata"}function Ic(e){return e==="metric"?{metric:""}:e==="status"?{status:["disabled"]}:{metadata:"",equals:""}}function rf(e){let t=e.trim();return t==="true"?!0:t==="false"?!1:t==="null"?null:t!==""&&Number.isFinite(Number(t))?Number(t):e}function Rr(e){return e.trim()===""||!Number.isFinite(Number(e))?void 0:Number(e)}function zc(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])=>zc(n,t?`${t}.${i}`:i,a+1))}var ra=e=>[...new Set(e.filter(t=>!!t))].sort((t,a)=>t.localeCompare(a));function an({label:e,children:t}){return qe("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]=Lc(!1),l=Yg(null);return qe("div",{className:"se-field se-fieldInline",children:[qe("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(Jg,{prefixed:!0,className:"se-swatch","aria-label":`${e} value`,onClick:()=>d(c=>!c),style:{background:a,color:Ln(a)},color:a,onChange:n})}):null,o?K(oa,{anchorRef:l,onClose:()=>d(!1),children:K(Xg,{color:a,onChange:n})}):null]})}function sf({title:e,open:t,onToggle:a,actions:i,children:n}){return qe("section",{className:"se-panel",children:[qe("div",{className:"se-ruleHeader",children:[K("button",{type:"button",className:"se-panelHeader",onClick:a,"aria-expanded":t,children:qe("span",{className:"se-panelHeaderMain",children:[K(ef,{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 Ar({config:e,onChange:t,objectBindings:a}){let i=e.styleRules??[],[n,o]=Lc(i[0]?.id??null),d=Wg(()=>{let b=Object.values(a);return{groups:ra(b.map(g=>g.group)),tags:ra(b.flatMap(g=>g.tags??[])),types:ra(b.map(g=>g.type??"other")),objects:b.map(g=>({id:g.id,label:g.label||g.id})).sort((g,B)=>g.label.localeCompare(B.label)),metrics:ra(b.flatMap(g=>Object.keys(g.metrics??{}))),metadata:ra(b.flatMap(g=>zc(g.metadata)))}},[a]),l=b=>t({...e,styleRules:b}),c=(b,g)=>l(i.map(B=>B.id===b?g(B):B)),w=()=>{let b=crypto.randomUUID();l([...i,{id:b,label:`Rule ${i.length+1}`,when:[{status:["disabled"]}],material:{baseColor:"#9ca3af"}}]),o(b)},f=(b,g)=>{let B=[...i],[v]=B.splice(b,1);B.splice(b+g,0,v),l(B)},y=b=>{let g=b.target?Ji(a,b.target):Object.keys(a),B=b.when?Array.isArray(b.when)?b.when:[b.when]:[];return g.filter(v=>B.every(P=>Ul(a[v],P))).length};return qe(yn,{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(b=>K("option",{value:b},b))}),K("datalist",{id:"se-ruleMetadata",children:d.metadata.map(b=>K("option",{value:b},b))}),i.map((b,g)=>{let B=b.when?Array.isArray(b.when)?b.when:[b.when]:[],v=of(b.target),P=b.material??{},x=b.pulse===!0?{}:b.pulse||void 0,C=b.target?Ji(a,b.target).length:Object.keys(a).length,S=r=>c(b.id,M=>({...M,when:r.length>0?r:void 0})),h=(r,M)=>S(B.map((j,R)=>R===r?M:j)),k=r=>c(b.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(b.id,M=>({...M,colorScale:r})),p=v==="group"?d.groups:v==="tag"?d.tags:v==="type"?d.types:[];return qe(sf,{title:b.label||`Rule ${g+1}`,open:n===b.id,onToggle:()=>o(r=>r===b.id?null:b.id),actions:qe(Dc,{children:[K("button",{type:"button",className:"se-iconButton",onClick:()=>f(g,-1),disabled:g===0,"aria-label":"Move rule up",title:"Move up",children:K(Qg,{size:14})}),K("button",{type:"button",className:"se-iconButton",onClick:()=>f(g,1),disabled:g===i.length-1,"aria-label":"Move rule down",title:"Move down",children:K(Zg,{size:14})}),K("button",{type:"button",className:"se-iconButton",onClick:()=>l(i.filter(r=>r.id!==b.id)),"aria-label":"Delete rule",title:"Delete rule",children:K(tf,{size:14})})]}),children:[K(an,{label:"Name",children:K("input",{className:"se-textInput",value:b.label??"",placeholder:`Rule ${g+1}`,onChange:r=>c(b.id,M=>({...M,label:r.target.value}))})}),qe("div",{className:"se-ruleGrid",children:[K(an,{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(b.id,R=>({...R,target:Ec(M,j??"")}))},children:Object.keys(Br).map(r=>K("option",{value:r,children:Br[r]},r))})}),v!=="all"?K(an,{label:Br[v],children:qe("select",{className:"se-select",value:ia(b.target),onChange:r=>c(b.id,M=>({...M,target:Ec(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(b.target)):p.includes(ia(b.target)))?null:K("option",{value:ia(b.target),children:ia(b.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=af(r);return qe("div",{className:"se-ruleCondition",children:[qe("div",{className:"se-ruleConditionHeader",children:[K("select",{className:"se-select","aria-label":"Condition type",value:j,onChange:R=>h(M,Ic(R.target.value)),children:Object.keys(jc).map(R=>K("option",{value:R,children:jc[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(Oc,{size:14})})]}),"metric"in r?qe("div",{className:"se-ruleGrid se-ruleGrid--three",children:[K(an,{label:"Metric",children:K("input",{className:"se-textInput",list:"se-ruleMetrics",value:r.metric,placeholder:"temperature",onChange:R=>h(M,{...r,metric:R.target.value})})}),K(an,{label:"Above",children:K("input",{className:"se-numberInput",type:"number",value:r.above??"",placeholder:"any",onChange:R=>h(M,{...r,above:Rr(R.target.value)})})}),K(an,{label:"Below",children:K("input",{className:"se-numberInput",type:"number",value:r.below??"",placeholder:"any",onChange:R=>h(M,{...r,below:Rr(R.target.value)})})})]}):"status"in r?K("div",{className:"se-ruleStatuses",children:ei.map(R=>{let E=[].concat(r.status).includes(R);return qe("label",{className:"se-ruleStatus",children:[K("input",{type:"checkbox",className:"se-checkbox",checked:E,onChange:()=>{let z=[].concat(r.status),pe=E?z.filter(ke=>ke!==R):[...z,R];h(M,{status:pe})}}),R]},R)})}):qe("div",{className:"se-ruleGrid",children:[K(an,{label:"Key",children:K("input",{className:"se-textInput",list:"se-ruleMetadata",value:r.metadata,placeholder:"alarm.state",onChange:R=>h(M,{...r,metadata:R.target.value})})}),K(an,{label:"Equals",children:K("input",{className:"se-textInput",value:r.equals===null?"null":String(r.equals),placeholder:"fault",onChange:R=>h(M,{...r,equals:rf(R.target.value)})})})]})]},M)}),qe("button",{type:"button",className:"se-animationButton",onClick:()=>S([...B,Ic("metric")]),children:[K(Pr,{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:b.colorScale!==void 0,onToggle:r=>O(r?{...nf,metric:d.metrics[0]??""}:void 0)}),b.colorScale?qe("div",{className:"se-ruleCondition",children:[qe("div",{className:"se-ruleGrid",children:[K(an,{label:"Metric",children:K("input",{className:"se-textInput",list:"se-ruleMetrics",value:b.colorScale.metric,placeholder:"temperature",onChange:r=>O({...b.colorScale,metric:r.target.value})})}),K(an,{label:"Sets",children:qe("select",{className:"se-select",value:b.colorScale.channel??"baseColor",onChange:r=>O({...b.colorScale,channel:r.target.value}),children:[K("option",{value:"baseColor",children:"Colour"}),K("option",{value:"emissive",children:"Glow colour"})]})})]}),b.colorScale.stops.map(([r,M],j)=>{let R=E=>O({...b.colorScale,stops:b.colorScale.stops.map((z,pe)=>pe===j?E:z)});return qe("div",{className:"se-ruleStop",children:[K("input",{className:"se-numberInput",type:"number","aria-label":"Stop value",value:r,onChange:E=>R([Rr(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:b.colorScale.stops.length<=1,onClick:()=>O({...b.colorScale,stops:b.colorScale.stops.filter((E,z)=>z!==j)}),children:K(Oc,{size:14})})]},j)}),qe("button",{type:"button",className:"se-animationButton",onClick:()=>{let r=b.colorScale.stops,M=r[r.length-1];O({...b.colorScale,stops:[...r,[(M?.[0]??0)+10,M?.[1]??"#ffffff"]]})},children:[K(Pr,{size:14})," Add stop"]})]}):null,K(sa,{label:"Pulse",checked:x!==void 0,color:x?.color??"#ff3b30",onToggle:r=>c(b.id,M=>({...M,pulse:r?{color:"#ff3b30",speed:1}:void 0})),onColorChange:r=>c(b.id,M=>({...M,pulse:{...x,color:r}}))}),x?K(Dc,{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(b.id,M=>({...M,pulse:{...x,speed:r}}))})}):null,qe("div",{className:"se-ruleHint se-ruleMatches",children:["Matches ",y(b)," of ",C," ",C===1?"object":"objects"," right now."]})]},b.id)}),qe("button",{type:"button",className:"se-animationButton",onClick:w,children:[K(Pr,{size:14})," Add rule"]})]})}import{Box as pf,Clapperboard as bf,ListVideo as uf,MessageSquareText as mf,Palette as gf,Sparkles as ff,Spotlight as hf,Video as xf}from"lucide-react";import{jsx as We,jsxs as wf}from"react/jsx-runtime";var yf=[{label:"General",icon:We(pf,{})},{label:"Assets",icon:We(lf,{})},{label:"Lighting",icon:We(hf,{})},{label:"Animations",icon:We(bf,{})},{label:"Sequences",icon:We(uf,{})},{label:"Post Processing",icon:We(ff,{})},{label:"Annotations",icon:We(mf,{})},{label:"Cinematic",icon:We(xf,{})},{label:"Rules",icon:We(gf,{})}],Fc={active:[],play:()=>{},pause:()=>{},stop:()=>{},setSpeed:()=>{},seek:()=>{}},vf=[],Sf={};function Or({assets:e,sequenceControls:t=null,sequenceClipDetails:a=[],diagnostics:i,onDiagnosticsOpenChange:n,config:o,onChange:d,activeSubTab:l,onActiveSubTabChange:c,cameraState:w=null,onPreviewWaypoint:f,animationClipDetails:y=[],animationConfig:b,onAnimationConfigChange:g,materialVariantGroups:B=vf,onImageFile:v,objectBindings:P=Sf,animationPlayback:x=Fc}){let[C,S]=df("General"),h=l??C,k=x??Fc,{tier:O}=dt();cf(()=>{l!==void 0&&S(l)},[l]);let p=r=>{l===void 0&&S(r),c?.(r)};return wf("div",{className:"se-tabContent",children:[We("div",{className:"se-subTabRow",children:yf.filter(r=>r.label!=="Assets"||e).map(r=>We("button",{type:"button",title:r.label,"aria-label":r.label,"aria-pressed":h===r.label,className:`se-subTab ${h===r.label?"se-subTab--active":""}`,onClick:()=>p(r.label),children:r.icon},r.label))}),h==="General"&&We(vr,{diagnostics:i,onDiagnosticsOpenChange:n,config:o,onChange:d,materialVariantGroups:B,onImageFile:v}),h==="Assets"&&e&&We(xr,{...e}),h==="Lighting"&&We(Cr,{config:o,onChange:d}),h==="Animations"&&We(kr,{config:b?{...o,animations:b}: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}),h==="Sequences"&&We(gr,{config:o,onChange:d,controls:t,bindings:P,clipDetails:a}),h==="Post Processing"&&We(wr,{config:o,onChange:d}),h==="Annotations"&&We(Nr,{config:o,onChange:d,cameraState:w,onPreviewView:f}),h==="Cinematic"&&(lt(O,"cinematic")?We(Tr,{config:o,onChange:d,cameraState:w,onPreviewWaypoint:f}):We(_e,{requiredTier:"starter",feature:"Cinematic camera"})),h==="Rules"&&(lt(O,"rules")?We(Ar,{config:o,onChange:d,objectBindings:P}):We(_e,{requiredTier:"growth",feature:"Style rules"}))]})}import{ChevronDown as Hc,Info as $c}from"lucide-react";import{jsx as ht,jsxs as ao}from"react/jsx-runtime";function Vc({title:e,trailing:t,children:a,disabled:i,open:n,onToggle:o,tooltip:d}){let l=d?`${d}`:e;return ao("div",{className:"bb-materialPanel",children:[ao("button",{type:"button",className:"bb-materialPanelHeader",onClick:o,"aria-expanded":n,title:l,children:[ao("div",{className:"bb-materialPanelTitleWrap",children:[ht(Hc,{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($c,{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 ao("div",{className:"bb-section",children:[ao("div",{className:"bb-sectionHeaderRow",children:[ht("button",{type:"button",className:"bb-sectionHeaderButton",onClick:a,"aria-expanded":t,title:d,children:ao("span",{className:"bb-sectionHeaderMain",children:[ht(Hc,{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($c,{size:13})}):null]})}),i?ht("span",{className:"bb-sectionHeaderTrailing",children:i}):null]}),t?ht("div",{className:"bb-sectionBody",children:n}):null]})}function qc({checked:e,onChange:t,label:a}){return ao("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 Gc}from"react";import{Trash2 as Of}from"lucide-react";import{jsx as jr}from"react/jsx-runtime";function Ot({panelKey:e,title:t,tooltip:a,toggleLabel:i,controls:n,children:o,requiredTier:d}){let{openMaterialPanels:l,materialPanelEnabled:c,onToggleMaterialPanel:w,onSetMaterialPanelState:f}=n,y=d?.locked??!1;return jr(Vc,{title:t,tooltip:a,disabled:y||!c[e],open:l[e],onToggle:()=>w(e),trailing:jr(qc,{checked:!y&&c[e],onChange:y?()=>{}:b=>f(e,b),label:i??`Toggle ${t}`}),children:y&&d?jr(_e,{requiredTier:d.tier,feature:t}):o})}import{createContext as Cf,useContext as kf,useRef as Uc,useState as Mf}from"react";import{HexColorInput as Nf,HexColorPicker as Tf}from"react-colorful";import{FileUp as Pf,Minus as Bf,Plus as Rf}from"lucide-react";import{jsx as Ee,jsxs as rn}from"react/jsx-runtime";var Er=Cf(null);function et({label:e,value:t,placeholder:a,onChange:i}){let n=Uc(null),o=kf(Er);return rn("div",{className:"bb-field bb-field--full",children:[Ee("label",{className:"bb-label",children:e}),rn("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&&Yo(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(Pf,{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=So(l);t&&t!==c&&Yo(t),Xt(c,URL.createObjectURL(l)),i(c),d.target.value=""}})]})]})}function Fn({label:e,value:t,fallback:a="#ffffff",variant:i="swatch",onChange:n}){let[o,d]=Mf(!1),l=t||a,c=Uc(null);return rn("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(Nf,{prefixed:!0,className:i==="input"?"bb-input bb-colorInput":"se-swatch","aria-label":e,onClick:()=>d(w=>!w),style:{background:l,color:Ln(l)},color:l,onChange:n})})}),o?Ee(oa,{anchorRef:c,onClose:()=>d(!1),children:Ee(Tf,{color:l,onChange:n})}):null]})}function la({label:e,checked:t,onChange:a}){return rn("label",{className:"bb-checkbox",children:[Ee("input",{type:"checkbox",checked:t,onChange:i=>a(i.target.checked)}),e]})}function Kc({label:e,value:t,min:a,max:i,step:n,placeholder:o,disabled:d,onChange:l}){return rn("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 Af(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 Ir({label:e,value:t,min:a,max:i,step:n=.01,disabled:o,onChange:d}){let l=t??0,c=f=>{let y=f;return a!==void 0&&(y=Math.max(a,y)),i!==void 0&&(y=Math.min(i,y)),y},w=f=>{d(c(Af(l+f*n,n)))};return rn("div",{className:"bb-field",children:[Ee("label",{className:"bb-label",children:e}),rn("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(Bf,{size:12})}),Ee("input",{className:"bb-input bb-numberStepper-input",type:"number",min:a,max:i,step:n,disabled:o,value:l,onChange:f=>{f.target.value!==""&&d(c(Number(f.target.value)))}}),Ee("button",{type:"button",className:"bb-numberStepper-btn",disabled:o,onClick:()=>w(1),"aria-label":`Increase ${e}`,title:`Increase ${e}`,children:Ee(Rf,{size:12})})]})]})}function Ro({label:e,value:t,options:a,onChange:i}){return rn("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 Be({label:e,value:t,min:a,max:i,step:n,onChange:o}){return rn("div",{className:"bb-field bb-field--full",children:[Ee("label",{className:"bb-label",children:e}),rn("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 Wc,jsx as H,jsxs as Ye}from"react/jsx-runtime";var _c="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 Yc({selectedItem:e,selectedMaterial:t,pbrWorkflow:a,onPbrWorkflowChange:i,openMaterialPanels:n,materialPanelEnabled:o,onToggleMaterialPanel:d,onSetMaterialPanelState:l,updateSelectedMaterial:c,setSelectedTexturePath:w,isTexturePositioningEnabled:f,onConfirmTexturePosition:y,takesImage:b=!0}){let g={openMaterialPanels:n,materialPanelEnabled:o,onToggleMaterialPanel:d,onSetMaterialPanelState:l},{tier:B}=dt(),v={tier:"starter",locked:!lt(B,"advancedMaterials")},[P,x]=Gc("roughness"),[C,S]=Gc("factor"),h=(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(Er.Provider,{value:b?null:_c,children:[b?null:H("p",{className:"bb-note bb-materialNotice",children:_c}),H(Ot,{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(Ro,{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(Of,{size:14,style:{marginRight:4,verticalAlign:"-2px"}}),"Remove texture"]})]}),Ye("div",{className:"bb-grid",style:{marginTop:6},children:[H(Ir,{label:"Offset X",value:t?.texture?.offset?.[0]??0,step:.01,onChange:p=>h(0,p)}),H(Ir,{label:"Offset Y",value:t?.texture?.offset?.[1]??0,step:.01,onChange:p=>h(1,p)})]}),H(Be,{label:"Rotation",value:((t?.texture?.rotation??0)*180/Math.PI%360+360)%360,min:0,max:360,step:1,onChange:p=>k(p??0)}),f?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(Fn,{label:a==="specular"?"Albedo color":"Base color",value:t?.baseColor??"#ffffff",onChange:p=>c(e,r=>({...r,baseColor:p}))}),a==="metalness"?Ye(Wc,{children:[H(Be,{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(Wc,{children:[H(Be,{label:"Specular intensity",value:t?.specularIntensity,min:0,max:1,step:.01,onChange:p=>c(e,r=>({...r,specularIntensity:p}))}),H(Fn,{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(Be,{label:"Specular F0 / reflectivity",value:t?.reflectivity,min:0,max:1,step:.01,onChange:p=>c(e,r=>({...r,reflectivity:p}))})]})}),H(Ot,{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(Ro,{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(Be,{label:"Roughness",value:t?.roughness,min:0,max:1,step:.01,onChange:p=>c(e,r=>({...r,roughness:p}))}):H(Be,{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(Ot,{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(Fn,{label:"Emissive color",value:t?.emissive??"#000000",fallback:"#000000",onChange:p=>c(e,r=>({...r,emissive:p}))}),H(Be,{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(Ot,{panelKey:"opacity",title:"Opacity",tooltip:"Controls transparency, alpha testing, and blending behavior.",controls:g,children:Ye("div",{className:"bb-grid",children:[H(Be,{label:"Opacity",value:t?.opacity,min:0,max:1,step:.01,onChange:p=>c(e,r=>({...r,opacity:p}))}),H(Be,{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(Ro,{label:"Blending mode",value:t?.blendingMode??"normal",options:sd,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(Ot,{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(Be,{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(Be,{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(Ot,{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(Be,{label:"Displacement scale",value:t?.displacementScale,min:-5,max:5,step:.01,onChange:p=>c(e,r=>({...r,displacementScale:p}))}),H(Be,{label:"Displacement bias",value:t?.displacementBias,min:-5,max:5,step:.01,onChange:p=>c(e,r=>({...r,displacementBias:p}))})]})}),H(Ot,{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(Be,{label:"AO intensity",value:t?.aoMapIntensity,min:0,max:5,step:.01,onChange:p=>c(e,r=>({...r,aoMapIntensity:p}))})]})}),Ye(Ot,{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(Be,{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(Be,{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(Be,{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(Ot,{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(Be,{label:"Sheen",value:t?.sheen,min:0,max:1,step:.01,onChange:p=>c(e,r=>({...r,sheen:p}))}),H(Fn,{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(Be,{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(Ot,{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(Be,{label:"Intensity",value:t?.anisotropy,min:0,max:1,step:.01,onChange:p=>c(e,r=>({...r,anisotropy:p}))}),H(Ro,{label:"Tilt direction",value:C,options:["factor","texture"],onChange:S}),C==="factor"?H(Be,{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(Ot,{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(Be,{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(Be,{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(Fn,{label:"Volume tint",value:t?.attenuationColor??"#ffffff",onChange:p=>c(e,r=>({...r,attenuationColor:p}))}),H(Kc,{label:"Attenuation distance",value:t?.attenuationDistance,min:0,step:.01,placeholder:"Infinity when unset",onChange:p=>c(e,r=>({...r,attenuationDistance:p}))})]})}),H(Ot,{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(Ro,{label:"Side",value:t?.side??"front",options:rd,onChange:p=>c(e,r=>({...r,side:p}))})})})]})}import{Ban as If}from"lucide-react";var ti="default",Dr=[{id:ti,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}}],jf=Array.from(new Set(Dr.flatMap(e=>Object.keys(e.material)))),Ef=Object.fromEntries(jf.map(e=>[e,void 0]));function Jc(e){return e.id===ti?Ef:e.material}import{jsx as ni,jsxs as Df}from"react/jsx-runtime";function Xc({disabled:e,onApply:t}){return ni("div",{className:"bb-presetGallery",children:Dr.map(a=>Df("button",{type:"button",className:"bb-presetSwatch",disabled:e,title:`Apply ${a.label} preset`,onClick:()=>t(Jc(a)),children:[ni("span",{className:"bb-presetSwatchColor",style:{background:a.swatch,display:"flex",alignItems:"center",justifyContent:"center"},children:a.id===ti?ni(If,{size:28,strokeWidth:2,color:"#ffffff"}):null}),ni("span",{className:"bb-presetSwatchLabel",children:a.label})]},a.id))})}import{jsx as io,jsxs as Lr}from"react/jsx-runtime";function Zc({selectedItem:e,selectedBinding:t,open:a,onToggle:i,updateBinding:n,idError:o}){return io(ot,{title:"Identity",open:a,onToggle:i,children:Lr("div",{className:"bb-grid",children:[Lr("div",{className:"bb-field bb-field--full",children:[io("label",{className:"bb-label",children:"Model Node ID"}),io("span",{className:"bb-note",children:"This is the exact mesh name from the imported model and stays locked."}),io("input",{className:"bb-input bb-readonly",value:t.modelObjectId,readOnly:!0})]}),Lr("div",{className:"bb-field bb-field--full",children:[io("label",{className:"bb-label",children:"ID"}),io("input",{className:`bb-input ${o?"bb-input--error":""}`,value:t.id,onChange:d=>n(e,l=>({...l,id:d.target.value}))}),o?io("span",{className:"bb-status bb-status--error",children:o}):null]})]})})}import{useEffect as Lf,useState as Qc}from"react";import{jsx as xt,jsxs as Zt}from"react/jsx-runtime";function ep({selectedItem:e,selectedBinding:t,open:a,onToggle:i,updateBinding:n}){let[o,d]=Qc(t.group??""),[l,c]=Qc(t.tags?.join(", ")??"");Lf(()=>{d(t.group??""),c(t.tags?.join(", ")??"")},[e,t.group,t.tags]);let w=()=>{n(e,y=>({...y,group:o.trim()||void 0}))},f=()=>{let y=[...new Set(l.split(",").map(b=>b.trim()).filter(Boolean))];n(e,b=>({...b,tags:y.length>0?y:void 0}))};return Zt(ot,{title:"Basics",open:a,onToggle:i,children:[Zt("div",{className:"bb-grid",children:[Zt("div",{className:"bb-field",children:[xt("label",{className:"bb-label",children:"Label"}),xt("input",{className:"bb-input",value:t.label??"",onChange:y=>n(e,b=>({...b,label:y.target.value}))})]}),Zt("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,b=>({...b,type:y.target.value}))}),xt("datalist",{id:"binding-type-suggestions",children:Ac.map(y=>xt("option",{value:y},y))})]}),Zt("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,b=>({...b,status:y.target.value})),children:ei.map(y=>xt("option",{value:y,children:y},y))})]}),Zt("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()}})]}),Zt("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:f,onKeyDown:y=>{y.key==="Enter"&&y.currentTarget.blur()}})]})]}),Zt("div",{className:"bb-checkboxRow",style:{marginTop:12},children:[Zt("label",{className:"bb-checkbox",children:[xt("input",{type:"checkbox",checked:t.selectable??!1,onChange:y=>n(e,b=>({...b,selectable:y.target.checked}))}),"selectable"]}),Zt("label",{className:"bb-checkbox",children:[xt("input",{type:"checkbox",checked:t.hoverable??!1,onChange:y=>n(e,b=>({...b,hoverable:y.target.checked}))}),"hoverable"]}),Zt("label",{className:"bb-checkbox",children:[xt("input",{type:"checkbox",checked:t.visible??!1,onChange:y=>n(e,b=>({...b,visible:y.target.checked}))}),"visible"]})]})]})}import{useEffect as zf,useState as Ff}from"react";import{Fragment as $f,jsx as Ze,jsxs as Ht}from"react/jsx-runtime";var tp=Ki.filter(e=>e.handling==="viewer"),Hf=Ki.filter(e=>e.handling==="host");function np({selectedItem:e,selectedBinding:t,open:a,onToggle:i,updateBinding:n,takesImage:o=!0}){let[d,l]=Ff(new Set);zf(()=>{l(new Set)},[e]);let c=t.actions??[],w=(b,g)=>n(e,B=>({...B,actions:(B.actions??[]).map((v,P)=>P===b?g(v):v)})),f=b=>{n(e,g=>({...g,actions:(g.actions??[]).filter((B,v)=>v!==b)})),l(g=>{let B=new Set;return g.forEach(v=>{v<b?B.add(v):v>b&&B.add(v-1)}),B})},y=(b,g)=>l(B=>{let v=new Set(B);return g?v.add(b):v.delete(b),v});return Ht(ot,{title:"Actions",open:a,onToggle:i,children:[Ze("div",{className:"bb-actionList",children:c.map((b,g)=>{let B=Ua(b.id),v=d.has(g)||!B,P=b.id.trim(),x=B?null:Ol(b.id),C=P.length>0&&c.some((S,h)=>h!==g&&S.id.trim()===P);return Ht("div",{className:"bb-actionCard",children:[Ht("div",{className:"bb-actionCardHeader",children:[Ht("div",{className:"bb-actionCardTitle",children:["Action ",g+1]}),Ze("div",{className:"bb-actionCardMeta",children:b.type})]}),Ht("div",{className:"bb-actionGrid",children:[Ht("div",{className:"bb-field",children:[Ze("label",{className:"bb-label",children:"Action ID"}),Ht("select",{className:"bb-select",value:v?qa:b.id,onChange:S=>{let h=S.target.value;if(h===qa){y(g,!0);return}y(g,!1);let k=Ua(h);w(g,O=>({...O,id:h,label:k&&Gi(O.label)?k.label:O.label}))},children:[Ze("optgroup",{label:"Handled by the viewer",children:tp.map(S=>Ze("option",{value:S.id,children:S.id},S.id))}),Ze("optgroup",{label:"Handled by your app",children:Hf.map(S=>Ze("option",{value:S.id,children:S.id},S.id))}),Ze("option",{value:qa,children:"Custom\u2026"})]})]}),v?Ht("div",{className:"bb-field",children:[Ze("label",{className:"bb-label",children:"Custom action ID"}),Ze("input",{className:"bb-input",value:b.id,placeholder:"open-datasheet",onChange:S=>{y(g,!0),w(g,h=>({...h,id:S.target.value}))}})]}):null,Ht("div",{className:"bb-field",children:[Ze("label",{className:"bb-label",children:"Label"}),Ze("input",{className:"bb-input",value:b.label,onChange:S=>w(g,h=>({...h,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."}):Ht("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?Ht($f,{children:[" Did you mean ",Ze("button",{type:"button",className:"bb-linkButton",onClick:()=>{y(g,!1);let S=Ua(x);w(g,h=>({...h,id:x,label:S&&Gi(h.label)?S.label:h.label}))},children:x}),"?"]}):null]}),b.effects?.length?Ht("span",{className:"bb-note",children:[b.effects.length," declarative effect",b.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:()=>f(g),children:"Remove Action"})})]},g)})}),Ze("div",{style:{marginTop:10},children:Ze("button",{type:"button",className:"bb-button",onClick:()=>{let b=tp.find(g=>!c.some(B=>B.id===g.id));n(e,g=>({...g,actions:[...g.actions??[],{id:b?.id??"",label:b?.label??"New Action",type:"command"}]})),b||y(c.length,!0)},children:"Add Action"})})]})}import{useRef as Vf}from"react";import{ImagePlus as qf,Trash2 as Uf,Type as Kf}from"lucide-react";import{Fragment as ap,jsx as at,jsxs as $t}from"react/jsx-runtime";var op=()=>`decal-${Date.now().toString(36)}-${Math.random().toString(36).slice(2,8)}`;function ip({selectedItem:e,selectedBinding:t,open:a,onToggle:i,updateBinding:n,placement:o,onPlacementChange:d,defaultSize:l,onImageFile:c,onNudge:w}){let{tier:f}=dt(),y=Vf(null),b=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(b.map(S=>S.id===x?{...S,...C}:S)),P=x=>{x.image&&Yo(x.image),g?.decal.id===x.id&&d(null),B(b.filter(C=>C.id!==x.id))};return $t(ot,{title:"Decals",open:a,onToggle:i,tooltip:"Print a logo, image, or text on the selected object's surface.",children:[vt(f,"decalsPerObject",b.length)?null:at(_e,{requiredTier:un("decalsPerObject",b.length),feature:"More decals on this object"}),$t(ap,{children:[$t("div",{className:"bb-decalActions",children:[$t("button",{type:"button",className:"bb-button bb-button--ghost",disabled:!vt(f,"decalsPerObject",b.length),onClick:()=>y.current?.click(),children:[at(qf,{size:15})," Add image"]}),$t("button",{type:"button",className:"bb-button bb-button--ghost",disabled:!vt(f,"decalsPerObject",b.length),onClick:()=>d({nodeKey:e,decal:{id:op(),text:"Your text",color:"#ffffff",size:l}}),children:[at(Kf,{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=So(C);Xt(S,URL.createObjectURL(C)),c?.(S,C),d({nodeKey:e,decal:{id:op(),image:S,size:l}})}})]}),b.length===0&&!g?at("div",{className:"bb-decalEmpty",children:"No decals on this object yet."}):null,b.map(x=>$t("div",{className:"bb-decalCard",children:[$t("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(Uf,{size:15})})]}),at(jl,{onNudge:C=>w(x.id,C)}),$t("div",{className:"bb-grid",children:[x.image?null:$t(ap,{children:[$t("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(Fn,{label:"Colour",variant:"input",value:x.color??"#ffffff",onChange:C=>v(x.id,{color:C})}),$t("div",{className:"bb-field",children:[at("label",{className:"bb-label",children:"Weight"}),$t("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(Be,{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(Be,{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(Be,{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 Gf,Trash2 as _f}from"lucide-react";import{Fragment as Wf,jsx as Vt,jsxs as jt}from"react/jsx-runtime";function rp({selectedBinding:e,open:t,onToggle:a,cameraState:i,formattedCameraState:n,savedCameraPosition:o,onSaveCameraPosition:d,onGoToSavedCamera:l,onClearSavedCamera:c,onResetView:w,onFitScene:f}){return jt(ot,{title:"Camera Position",open:t,onToggle:a,children:[jt("div",{className:"se-waypointCard bb-cameraWaypoint",children:[Vt("span",{className:"bb-cameraLiveBadge",children:"LIVE"}),jt("div",{className:"se-waypointBody",children:[Vt("div",{className:"bb-cameraWaypointLabel",children:"Current view"}),i?jt(Wf,{children:[jt("div",{className:"se-waypointCoords",children:["pos ",n?.position]}),jt("div",{className:"se-waypointCoords",children:["look ",n?.target]})]}):Vt("div",{className:"se-waypointCoords",children:"Move the camera to see live position"})]})]}),jt("div",{className:"bb-cameraControls bb-cameraControls--centered",children:[Vt("button",{type:"button",className:"bb-button bb-button--primary",onClick:d,disabled:!i,children:"Save"}),Vt("button",{type:"button",className:"bb-button bb-button--ghost",onClick:w,children:"Reset View"}),Vt("button",{type:"button",className:"bb-button bb-button--ghost",onClick:f,children:"Fit Scene"})]}),o?.position&&o?.target&&jt("div",{className:"se-waypointCard bb-cameraWaypoint",children:[Vt("span",{className:"bb-cameraSavedBadge",children:"SAVED"}),jt("div",{className:"se-waypointBody",children:[jt("div",{className:"bb-cameraWaypointLabel",children:["For ",e.label]}),jt("div",{className:"se-waypointCoords",children:["pos [",o.position.map(y=>y.toFixed(1)).join(", "),"]"]}),jt("div",{className:"se-waypointCoords",children:["look [",o.target.map(y=>y.toFixed(1)).join(", "),"]"]})]}),jt("div",{className:"se-waypointActions",children:[Vt("button",{className:"se-waypointAction",onClick:l,title:"Fly camera to the saved position",children:Vt(Gf,{size:15})}),Vt("button",{className:"se-waypointAction se-waypointAction--delete",onClick:c,title:"Delete saved position",children:Vt(_f,{size:15})})]})]}),Vt("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 Yf,useRef as Jf,useState as Xf}from"react";import{Maximize2 as Zf,Move3d as Qf,RotateCcw as eh}from"lucide-react";import{Fragment as rh,jsx as Ce,jsxs as gt}from"react/jsx-runtime";var lp=["X","Y","Z"],th=.1,nh=.1,sp=.01;function dp(e){let t=e%360;return t<0?t+360:t}function oh(e){return dp(e*180/Math.PI)}function ah(e){return e*Math.PI/180}function zr({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),[f,y]=Xf(String(w)),b=Jf(!1);return Yf(()=>{b.current||y(String(w))},[w]),Ce("input",{type:"number",className:c,step:i,min:t===-1/0?void 0:t,max:a===1/0?void 0:a,value:f,disabled:n,"aria-label":l,onFocus:()=>{b.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:()=>{b.current=!1,y(String(d(e)))}})}function ih({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 Ce("div",{className:"bb-transformAxesGrid",children:lp.map((c,w)=>gt("div",{className:"bb-transformAxis",children:[Ce("span",{className:"se-axisStepperLabel bb-transformAxisLabel",children:c}),Ce("div",{className:"bb-transformAxisControl",children:Ce(zr,{className:"se-numberInput bb-transformNumberInput",step:i,min:t,max:a,value:e[w],disabled:n,formatValue:d,ariaLabel:`${c} ${l?.toLowerCase()||""}`,onChange:f=>{let y=[...e];y[w]=f,o(y,w)}})})]},c))})}function cp({selectedItem:e,selectedBinding:t,open:a,onToggle:i,updateBinding:n,moveModeEnabled:o,onToggleMoveMode:d,scaleModeEnabled:l,onToggleScaleMode:c,transformSpace:w,onTransformSpaceChange:f,originalTransform:y,originalTransforms:b}){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=Wi(t.transform?.scale??v,v),x=(p=e??"")=>b?.[p]??(p===e?y:null),C=(p,r)=>p.transform?.pivot??Fl(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]=ah(dp(r)),{...M,transform:{...M.transform,rotation:z,pivot:C(M,R)}}})},h=(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(sp,p);n(e,(M,j)=>{let R=x(j),E=R?.scale??[1,1,1],z=M.transform?.scale??E,pe=Wi(z,E),ke=pe>0?z:E,he=r/(pe||1);return{...M,transform:{...M.transform,scale:ke.map(I=>I*he),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:[Ce(Qf,{size:14,style:{marginRight:6,verticalAlign:"-2px"}}),"Transform Gizmo"]}),gt("label",{className:"se-switch","aria-label":"Toggle transform gizmo",children:[Ce("input",{type:"checkbox",checked:o,onChange:p=>d(p.target.checked)}),Ce("span",{className:"se-switchTrack",children:Ce("span",{className:"se-switchThumb"})})]})]}),Ce("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:[Ce("div",{className:"se-fieldLabel",children:Ce("span",{children:"Axis space"})}),Ce("div",{className:"se-segmentedControl",children:["world","local"].map(p=>Ce("button",{type:"button",className:`se-segmentedOption ${w===p?"se-segmentedOption--active":""}`,onClick:()=>f(p),children:p},p))})]}),gt("div",{className:"se-field",style:{marginTop:10},children:[Ce("div",{className:"se-fieldLabel",children:Ce("span",{children:"Rotation (degrees)"})}),Ce("div",{className:"bb-transformAxesGrid",children:lp.map((p,r)=>{let M=Math.round(oh(g[r]));return gt("div",{className:"bb-transformAxis",children:[Ce("span",{className:"se-axisStepperLabel bb-transformAxisLabel",children:p}),Ce("div",{className:"bb-transformAxisControl",children:Ce(zr,{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:[Ce("div",{className:"se-fieldLabel",children:Ce("span",{children:"Position"})}),Ce(ih,{value:B,min:-1/0,max:1/0,step:th,disabled:!e,label:"position",onChange:(p,r)=>h(r,p[r])})]}),gt("div",{className:"se-field",style:{marginTop:10},children:[gt("div",{className:"se-fieldLabel",children:[gt("span",{children:[Ce(Zf,{size:14,style:{marginRight:6,verticalAlign:"-2px"}}),"Scale"]}),gt("label",{className:"se-switch","aria-label":"Toggle scale controls",children:[Ce("input",{type:"checkbox",checked:l,onChange:p=>c(p.target.checked)}),Ce("span",{className:"se-switchTrack",children:Ce("span",{className:"se-switchThumb"})})]})]}),l?gt(rh,{children:[gt("div",{className:"bb-transformAxis",style:{marginTop:8},children:[Ce("span",{className:"se-axisStepperLabel bb-transformAxisLabel",children:"\xD7"}),Ce("div",{className:"bb-transformAxisControl",children:Ce(zr,{className:"se-numberInput bb-transformNumberInput",step:nh,min:sp,value:P,disabled:!e,formatValue:p=>Number(p.toFixed(2)),ariaLabel:"Uniform scale factor",onChange:k})})]}),Ce("span",{className:"bb-note",children:"1 is the model's original size \xB7 smaller shrinks, larger grows it"})]}):Ce("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:[Ce(eh,{size:14}),"Restore original transform"]})]})}import{memo as vh}from"react";import{ListChecks as Sh}from"lucide-react";import{useEffect as sh,useId as lh,useLayoutEffect as mp,useMemo as Ao,useRef as Hr,useState as Oo}from"react";import{ChevronDown as dh,ChevronRight as ch,ChevronsDownUp as ph,ChevronsUpDown as bh,Focus as uh,Trash2 as mh}from"lucide-react";function pp(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 bp(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 Fr(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 up(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 Fe,jsxs as qt}from"react/jsx-runtime";var gh=[],fh=[],hh=[],vn=56;function xh({count:e,total:t,name:a,onChange:i}){let n=Hr(null);return mp(()=>{n.current&&(n.current.indeterminate=e>0&&e<t)},[e,t]),Fe("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 oi({bindings:e,hierarchy:t=fh,selectedItem:a,onSelect:i,onHover:n,fill:o,isolatedItem:d,onIsolate:l,multiSelectEnabled:c=!1,multiSelectedKeys:w=gh,onSetMultiSelected:f,selectionSets:y=hh,onSelectionSetsChange:b}){let[g,B]=Oo(""),[v,P]=Oo(()=>new Set),[x,C]=Oo(""),S=Hr(null),h=Ao(()=>pp(t,e),[t,e]),k=Ao(()=>bp(h,e,g),[h,e,g]),O=Ao(()=>Fr(k,v,!!g.trim()),[k,v,g]),p=Ao(()=>O.flatMap(({node:I})=>I.key?[I.key]:[]),[O]),r=Ao(()=>k.flatMap(I=>I.keys),[k]),M=Ao(()=>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);f?.(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}f&&(c||Q.shiftKey||Q.ctrlKey||Q.metaKey)?f(up([...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))},ke=vt(dt().tier,"selectionSets",y.length),he=()=>{let I=[...M].filter(Q=>e[Q]&&!e[Q].removed);!I.length||!x.trim()||y.length>=128||!ke||(b?.([...y,{id:crypto.randomUUID(),name:x.trim(),objectIds:I.map(Q=>e[Q].modelObjectId??Q)}]),C(""))};return qt("section",{className:`bb-nodeList ${o?"bb-nodeList--fill":""}`,children:[Fe("div",{className:"bb-search",children:Fe("input",{className:"bb-input","aria-label":"Search scene hierarchy",placeholder:"Search hierarchy, labels, or types",value:g,onChange:I=>B(I.target.value)})}),qt("div",{className:"bb-treeToolbar",children:[f&&qt("button",{type:"button",className:"bb-button bb-button--ghost",disabled:!r.length,onClick:()=>R(r),children:[j?"Clear matches":"Select matches"," (",r.length,")"]}),Fe("button",{type:"button",className:"bb-treeIcon","aria-label":"Expand hierarchy",title:"Expand all",onClick:()=>P(new Set),children:Fe(bh,{size:15})}),Fe("button",{type:"button",className:"bb-treeIcon","aria-label":"Collapse hierarchy",title:"Collapse all",onClick:()=>P(new Set(Fr(h,new Set,!0).filter(({node:I})=>I.children.length).map(({node:I})=>I.id))),children:Fe(ph,{size:15})})]}),b&&qt("details",{className:"bb-selectionSets",children:[qt("summary",{children:["Saved selections (",y.length,")"]}),qt("div",{className:"bb-selectionSetCreate",children:[Fe("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(),he())}}),Fe("button",{type:"button",className:"bb-button bb-button--ghost",disabled:!M.size||!x.trim()||y.length>=128||!ke,title:ke?void 0:"Saving more selections requires the Starter plan or higher.",onClick:he,children:"Save"})]}),!y.length&&Fe("p",{children:"Select objects, then save the selection to reuse it."}),y.map(I=>{let Q=pe(I);return qt("div",{className:"bb-selectionSetRow",children:[qt("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),f?.(Q),S.current=Q[0]??null},children:[I.name,qt("small",{children:[Q.length," / ",I.objectIds.length]})]}),Fe("button",{type:"button",className:"bb-treeIcon","aria-label":`Delete selection ${I.name}`,onClick:()=>b(y.filter(G=>G.id!==I.id)),children:Fe(mh,{size:14})})]},I.id)})]}),Fe(yh,{rows:O,bindings:e,selected:M,multiSelect:c,collapsed:v,searching:!!g.trim(),search:g,onSelect:z,onToggle:E,onToggleKeys:f?R:void 0,onSelectAll:f?()=>f(r):void 0,onHover:n,isolatedItem:d,onIsolate:l}),Fe("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 yh({rows:e,bindings:t,selected:a,multiSelect:i,collapsed:n,searching:o,search:d,onSelect:l,onToggle:c,onToggleKeys:w,onSelectAll:f,onHover:y,isolatedItem:b,onIsolate:g}){let B=Hr(null),[v,P]=Oo(400),[x,C]=Oo(0),[S,h]=Oo(0),k=lh();mp(()=>{let R=B.current;if(!R)return;let E=new ResizeObserver(()=>P(R.clientHeight));return E.observe(R),()=>E.disconnect()},[]),sh(()=>{B.current&&(B.current.scrollTop=0),C(0),h(0)},[d]);let O=R=>{R=Math.max(0,Math.min(e.length-1,R)),h(R);let E=B.current;E&&(R*vn<E.scrollTop?E.scrollTop=R*vn:(R+1)*vn>E.scrollTop+E.clientHeight&&(E.scrollTop=(R+1)*vn-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(),f?.();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/vn))-5),M=Math.min(e.length,r+Math.ceil(v/vn)+12),j=Math.min(S,e.length-1);return qt("div",{ref:B,className:"bb-sceneTree",role:"tree","aria-label":"Scene hierarchy","aria-multiselectable":!!f,tabIndex:0,"aria-activedescendant":j>=r&&j<M?`${k}-${j}`:void 0,onKeyDown:p,onScroll:R=>C(R.currentTarget.scrollTop),children:[!e.length&&Fe("p",{className:"bb-treeEmpty",children:"No matching objects."}),Fe("div",{style:{height:e.length*vn,position:"relative"},children:e.slice(r,M).map((R,E)=>{let{node:z,depth:pe}=R,ke=r+E,he=z.key?t[z.key]:void 0,I=z.keys.reduce((L,oe)=>L+Number(a.has(oe)),0),Q=z.children.length?o||!n.has(z.id):void 0,G=z.key?a.has(z.key):I===z.keys.length;return qt("div",{id:`${k}-${ke}`,role:"treeitem","aria-level":pe+1,"aria-expanded":Q,"aria-selected":G,className:`bb-treeRow${G?" bb-treeRow--selected":""}`,style:{top:ke*vn,height:vn,paddingLeft:8+Math.min(pe,10)*14},onFocus:()=>h(ke),onMouseEnter:()=>y?.(z.key??null),onMouseLeave:()=>y?.(null),children:[z.children.length?Fe("button",{type:"button",tabIndex:-1,className:"bb-treeIcon","aria-label":`${Q?"Collapse":"Expand"} ${z.name}`,onClick:()=>c(z.id),children:Q?Fe(dh,{size:14}):Fe(ch,{size:14})}):Fe("span",{className:"bb-treeSpacer"}),i&&w&&Fe(xh,{count:I,total:z.keys.length,name:z.name,onChange:()=>w(z.keys)}),qt("button",{type:"button",tabIndex:-1,className:"bb-treeNode",onClick:L=>{h(ke),B.current?.focus({preventScroll:!0}),l(R,L)},children:[Fe("span",{children:he?.label||z.name}),Fe("small",{children:he?`${he.type??"other"} \xB7 ${he.modelObjectId}`:`${z.keys.length} objects`})]}),z.key&&g&&Fe("button",{type:"button",tabIndex:-1,className:"bb-treeIcon bb-treeIsolate","aria-label":`${b===z.key?"Show all":"Isolate"} ${z.name}`,"aria-pressed":b===z.key,onClick:()=>g(b===z.key?null:z.key),children:Fe(uh,{size:14})})]},z.id)})})]})}import{Fragment as kh,jsx as Tt,jsxs as jo}from"react/jsx-runtime";var $r=[],gp=vh(wh);function Vr(e){let t=0;for(let a of Object.values(e))a.removed||(t+=1);return t}function wh({bindings:e,selectedItem:t,onSelect:a,onHover:i,isOpen:n=!0,onToggle:o,modelGroups:d,onSelectModel:l,isolatedItem:c=null,onIsolate:w,multiSelectEnabled:f=!1,onToggleMultiSelect:y,onExitMultiSelect:b,multiSelectedKeys:g=$r,onSetMultiSelected:B,hierarchy:v,selectionSets:P,onSelectionSetsChange:x}){let C=d&&d.length>=2?d:null,S=C?C.reduce((h,k)=>h+Vr(k.bindings),0):Vr(e);return jo("aside",{className:`bb-sidebar bb-sidebar--right ${n?"":"bb-sidebar--collapsed"}`,children:[jo("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&&jo(kh,{children:[jo("div",{className:"bb-sidebarHeadingText",children:[Tt("div",{className:"bb-sectionKicker",children:f||g.length>1?`Scene Nodes \xB7 ${S}`:"Scene Nodes"}),Tt("div",{className:"bb-sectionHeading",style:f||g.length>1?{fontSize:15}:void 0,children:f||g.length>1?`${g.length} selected`:`${S} ${S===1?"node":"nodes"}`})]}),jo("div",{className:"bb-sidebarActions",children:[y?Tt("button",{type:"button",className:`bb-sidebarToggle ${f?"bb-sidebarToggle--active":""}`,onClick:y,"aria-pressed":f,"aria-label":"Toggle multi-select",title:f?"Multi-select on: edits apply to every selected node":"Select multiple nodes",children:Tt(Sh,{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&&f&&jo("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:b??y,children:"Done"})]}),n&&(C?Tt(Ch,{groups:C,selectedItem:t,onSelect:a,onHover:i,onSelectModel:l,isolatedItem:c,onIsolate:w,multiSelectEnabled:f,multiSelectedKeys:g,onSetMultiSelected:B,hierarchy:v,selectionSets:P,onSelectionSetsChange:x}):Tt(oi,{bindings:e,selectedItem:t,onSelect:a,onHover:i,isolatedItem:c,onIsolate:w,multiSelectEnabled:f,multiSelectedKeys:g,onSetMultiSelected:B,hierarchy:v,selectionSets:P,onSelectionSetsChange:x}))]})}function Ch({groups:e,selectedItem:t,onSelect:a,onHover:i,onSelectModel:n,isolatedItem:o=null,onIsolate:d,multiSelectEnabled:l=!1,multiSelectedKeys:c=$r,onSetMultiSelected:w,hierarchy:f,selectionSets:y,onSelectionSetsChange:b}){return Tt("section",{className:"bb-nodeList bb-nodeList--grouped",children:e.map(g=>{let B=g.isActive,v=Vr(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(oi,{bindings:g.bindings,hierarchy:g.isActive?f:void 0,selectionSets:g.isActive?y:void 0,onSelectionSetsChange:g.isActive?b: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:$r,onSetMultiSelected:g.isActive?w:void 0})})},g.url)})})}import{jsx as ai,jsxs as fp}from"react/jsx-runtime";function qr({title:e,label:t,open:a,onToggle:i,draft:n,error:o,example:d,onDraftChange:l,onCommit:c}){return ai(ot,{title:e,open:a,onToggle:i,children:fp("div",{className:"bb-field",children:[ai("label",{className:"bb-label",children:t}),ai("textarea",{className:"bb-textarea",value:n,onChange:w=>l(w.target.value),onBlur:c}),o?ai("span",{className:"bb-status bb-status--error",children:o}):fp("span",{className:"bb-note",children:["Use a JSON object like ",d,"."]})]})})}import{useCallback as Ut}from"react";import{PropertyBinding as xp}from"three";import{PropertyBinding as Ur}from"three";function ro(e,t,a=[],i={},n=new Set(Object.keys(Fa(e).nodesById))){let o=new Map(Object.entries(t).filter(([,b])=>b.removed===!0).map(([b,g])=>[g.modelObjectId??b,g])),d=new Set(Object.entries(i).map(([b,g])=>g.modelObjectId??b)),l=a.filter(b=>b.loadState==="loading").map(b=>Ur.sanitizeNodeName(`${sn(b.namePrefix)}_`)),c=Object.fromEntries(Object.entries(t).filter(([b,g])=>{let B=g.modelObjectId??b;return!d.has(B)&&(g.removed===!0||n.has(B)||l.some(v=>B.startsWith(v)))})),w=Object.fromEntries(Object.entries(i).map(([b,g])=>[b,o.get(g.modelObjectId??b)??g])),f={...c,...w},y=Object.keys(f);return y.length===Object.keys(t).length&&y.every(b=>f[b]===t[b])?t:f}function sn(e){return e.replace(/\.[^./\\]+$/,"")}function Kr(e,t,a={}){let i=Ur.sanitizeNodeName(sn(e)).replace(/_/g,"-")||"Model",n=t.map(l=>Ur.sanitizeNodeName(sn(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 Eo(e){e.resolved.cleanup()}function da(e){e.resolved?.cleanup(),e.mergedModelSources.forEach(Eo)}function ca(e,t){let a=Gl(e),i=Xo(a,_a(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=Wo(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=zl(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 Mh(e,t){let a=e;for(;a;){if(a===t)return!0;a=a.parent}return!1}function Gr(e,t){let a=e.parent??e,i=ca(a,t),n=i.nodeNames.filter(o=>{let d=Wo(a,o);return d?Mh(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 ii(e,t=[]){let a={bindings:e,mergeSources:t};return{past:[],present:a,future:[],baseline:a,edits:0}}function yp(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 vp(e,t,a,i={}){return yp(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 _r(e,t){let a=e.mergeSources.find(o=>o.url===t);if(!a)return e;let i=new Set(a.nodeNames),n=xp.sanitizeNodeName(`${sn(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 Wr(e,t){let a=hn(e.bindingHistory??ii(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 Yr(e,t,a,i){let n=vp(e.bindingHistory??ii(e.bindings,e.mergedModelSources),t,a,i);return{...e,bindings:n.present.bindings,mergedModelSources:n.present.mergeSources,bindingHistory:n}}function Sp(e,t){let a=e.bindingHistory??ii(e.bindings,e.mergedModelSources),n=[a.present,...a.past,...a.future].flatMap(l=>l.mergeSources).map(l=>xp.sanitizeNodeName(`${sn(l.namePrefix)}_`)),o=Object.fromEntries(Object.entries(t).filter(([l,c])=>!n.some(w=>(c.modelObjectId??l).startsWith(w)))),d=yp(a,l=>({...l,bindings:{...o,...l.bindings}}));return{...e,bindings:d.present.bindings,bindingHistory:d}}function hp(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 wp(e,t=[]){let a=na({bindings:e,mergeSources:t}),{setValue:i,setValueAsStep:n,updateHistory:o,restoreSnapshot:d}=a,l=Ut(S=>i(h=>{let k=typeof S=="function"?S(h.bindings):S;return k===h.bindings?h:{...h,bindings:k}}),[i]),c=Ut(S=>n(h=>{let k=typeof S=="function"?S(h.bindings):S;return k===h.bindings?h:{...h,bindings:k}}),[n]),w=Ut(S=>o(h=>{let k=typeof S=="function"?S(h.present.bindings):S;if(k===h.present.bindings)return h;let O={...h.present,bindings:k};return{...h,present:O,baseline:h.edits===0?O:h.baseline}}),[o]),f=Ut(S=>o(h=>{let k=typeof S=="function"?S(h.present.mergeSources):S,O={...h.present,mergeSources:k};return{...h,present:O,baseline:h.edits===0?O:h.baseline}}),[o]),y=Ut(S=>n(h=>({...h,mergeSources:[...h.mergeSources,typeof S=="function"?S(h):S]})),[n]),b=Ut(S=>n(h=>_r(h,S)),[n]),g=Ut((S,h,k)=>{o(O=>vp(O,S,h,k))},[o]),B=Ut(()=>d(S=>{let h=hn(S,{type:"undo"});return h===S?S:hp(h,S.present)}),[d]),v=Ut(()=>d(S=>{let h=hn(S,{type:"redo"});return h===S?S:hp(h,S.present)}),[d]),P=Ut((S,h)=>d(k=>hn(k,{type:"reset",value:{bindings:S,mergeSources:k.present.mergeSources},track:h?.asEdit??!1})),[d]),x=Ut(()=>d(S=>hn(S,{type:"reset",value:S.present,track:!1})),[d]),C=Ut(S=>d({...S.bindingHistory??ii(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:f,addMerge:y,removeMerge:b,hydrateMerge:g,undo:B,redo:v,reset:P,clearHistory:x,restoreModel:C}}import{useEffect as Cp,useRef as Nh}from"react";function kp(e,t,{modelUrl:a,modelSourceRef:i,uploadedFilesRef:n}={}){let o=Nh(new Map);Cp(()=>{let d=new Map,l=f=>{for(let y of[f.present,...f.past,...f.future])y.mergeSources.forEach(b=>d.set(b.url,b))};l(e);for(let f of t)f.bindingHistory&&l(f.bindingHistory),f.mergedModelSources.forEach(y=>d.set(y.url,y));for(let[f,y]of o.current)d.has(f)||y.resolved.cleanup();o.current=d;let c=new Set,w=f=>{f?.kind==="file"&&c.add(f.key)};a&&w(i?.current?.model),t.forEach(f=>w(f.sessionModel)),d.forEach(f=>w(f.sessionModel));for(let f of n?.current.keys()??[])c.has(f)||n?.current.delete(f)},[e,t,a,i,n]),Cp(()=>()=>{o.current.forEach(d=>d.resolved.cleanup()),o.current.clear(),n?.current.clear()},[n])}import{useCallback as Th,useEffect as Jr,useRef as Ph}from"react";var Bh=500;function Mp({composition:e,autosaveEnabled:t,hasEdits:a,modelUrl:i,bindings:n,sceneConfig:o,parkedModels:d,mergedModelSources:l,modelOrder:c,onTextureUpload:w,modelSourceRef:f,pendingLoadRef:y,storedModelKeysRef:b,uploadedFilesRef:g,pendingAutosaveRef:B,autosaveFailureShownRef:v,setStatusMessage:P,setStatusTone:x}){let C=Ph(0),S=Th(async(h,k)=>{if(w)return w(h,k);let O=URL.createObjectURL(h);if(t)try{await Mo(O,h)}catch(p){console.warn("[BindingBuilder] Could not store texture file for autosave:",p)}return O},[w,t]);return Jr(()=>{if(!t||!a){B.current=null;return}let h=f.current;if(i&&!h){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||!h){b.current.clear(),vd().then(()=>{r===C.current&&(v.current=!1)}).catch(M);return}let{model:j}=h,R=[],E=new Set,z=G=>{if(!G||G.kind!=="file"||(E.add(G.key),b.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)),b.current=new Set([...b.current].filter(G=>E.has(G)));let pe=G=>({model:G.sessionModel,namePrefix:G.namePrefix}),ke=d.filter(G=>!!G.sessionModel).map(G=>({model:G.sessionModel,bindings:G.bindings,originalTransforms:G.originalTransforms,modelSettings:G.modelSettings,mergeModels:G.mergedModelSources.map(pe)})),he=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?on(L):null}).filter(G=>G!==null);xd({model:j,composition:e,bindings:n,sceneConfig:o,parkedModels:ke,mergeModels:he,modelOrder:Q},R).then(()=>{r===C.current&&(b.current=E,v.current=!1)}).catch(M)};if(B.current=O,!k){O();return}let p=window.setTimeout(O,Bh);return()=>window.clearTimeout(p)},[e,t,a,i,n,o,d,l,c]),Jr(()=>{if(!t)return;let h=()=>B.current?.(),k=()=>{document.visibilityState==="hidden"&&h()};return window.addEventListener("pagehide",h),document.addEventListener("visibilitychange",k),()=>{window.removeEventListener("pagehide",h),document.removeEventListener("visibilitychange",k),h()}},[t]),Jr(()=>{if(!t||!i||!a)return;let h=k=>{B.current?.(),k.preventDefault(),k.returnValue=""};return window.addEventListener("beforeunload",h),()=>window.removeEventListener("beforeunload",h)},[t,i,a]),{handleTextureUpload:S}}import{useLayoutEffect as Rh}from"react";function Np({bindings:e,multiSelectMode:t,selectedItem:a,multiSelectedKeys:i,setSelectedItem:n,setMultiSelectedKeys:o}){Rh(()=>{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 Hn,useReducer as Ah}from"react";var Zr={selectedItem:null,keys:[],checkboxMode:!1},Xr=(e,t)=>typeof e=="function"?e(t):e;function Oh(e,t){if(t.type==="primary"){let c=Xr(t.value,e.selectedItem);return c===e.selectedItem?e:{...e,selectedItem:c}}if(t.type==="keys"){let c=Xr(t.value,e.keys);return c===e.keys?e:{...e,keys:c}}if(t.type==="mode"){let c=Xr(t.value,e.checkboxMode);return c===e.checkboxMode?e:{...e,checkboxMode:c}}if(t.type==="clear")return Zr;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:Zr;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 Tp(){let[e,t]=Ah(Oh,Zr),a=Hn(f=>t({type:"primary",value:f}),[]),i=Hn(f=>t({type:"keys",value:f}),[]),n=Hn(f=>t({type:"mode",value:f}),[]),o=Hn(f=>t({type:"selection",keys:f}),[]),d=Hn((f,y={})=>t({type:"select",key:f,modifiers:y}),[]),l=Hn(()=>t({type:"toggleMode"}),[]),c=Hn(()=>t({type:"exitMode"}),[]),w=Hn(()=>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 Pp,useEffect as jh,useState as Eh}from"react";function Bp(e,t){let[a,i]=Eh(!1),n=e>0||t>0,o=Pp(()=>i(!0),[]),d=Pp(()=>i(!1),[]);return jh(()=>{n&&o()},[n,o]),{hasEdits:a||n,markSessionEdited:o,resetSessionEdits:d}}import{useEffect as Rp,useReducer as Ih,useRef as Dh}from"react";function Ap({enabled:e=!0,modelUrl:t,bindings:a,mergeSources:i,parkedModels:n,scenesRef:o,sceneRevision:d,setBindings:l,setParkedModels:c}){let[w,f]=Ih(b=>b+1,0),y=Dh(new WeakMap);Rp(()=>{if(!e)return;let b=[t,...n.map(v=>v.url)],g=new Set(b.flatMap(v=>{let P=v?o.current.get(v):void 0;return P?[P]:[]})),B=v=>{v.target&&y.current.delete(v.target),f()};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]),Rp(()=>{if(!e)return;let b=B=>{let v=y.current.get(B);return v||(v=new Set(Object.keys(Fa(B).nodesById)),y.current.set(B,v)),v},g=t?o.current.get(t):void 0;if(g){let B=b(g);l(v=>ro(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=ro(C,x.bindings,x.mergedModelSources,{},b(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 Lh,useMemo as zh,useReducer as Fh}from"react";function Op({modelUrl:e,scenesRef:t,sceneRevision:a,streaming:i=!1}){let n=e?t.current.get(e):void 0,[o,d]=Fh(l=>l+1,0);return Lh(()=>{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]),zh(()=>({materialVariantGroups:n?Ll(n):[],objectsWithoutUvs:n&&!i?_a(n):new Set,hierarchy:n&&!i?ld(n):[]}),[n,a,o,i])}import{ListRestart as Wh,Redo2 as Yh,Undo2 as Jh}from"lucide-react";import{useEffect as Hh,useId as $h,useLayoutEffect as Vh,useRef as jp,useState as Ep}from"react";import{ChevronDown as qh,Download as Uh,FileArchive as Kh,FileCode2 as Gh,FileJson as Ip,Upload as _h}from"lucide-react";import{jsx as Kt,jsxs as ri}from"react/jsx-runtime";function Dp({action:e,groups:t,busy:a}){let[i,n]=Ep(!1),[o,d]=Ep(480),l=jp(null),c=jp(null),w=$h(),f=a||t.every(y=>y.options.every(b=>b.disabled));return Vh(()=>{if(!i)return;let y=()=>{let b=l.current?.closest(".bb-toolbar"),g=l.current?.closest(".bb-sidebar");b&&g&&d(Math.max(80,b.getBoundingClientRect().top-Math.max(0,g.getBoundingClientRect().top)-8))};return y(),window.addEventListener("resize",y),()=>window.removeEventListener("resize",y)},[i]),Hh(()=>{if(!i)return;let y=b=>{l.current?.contains(b.target)||n(!1)};return window.addEventListener("pointerdown",y),()=>window.removeEventListener("pointerdown",y)},[i]),ri("div",{className:"bb-exportMenuWrapper",ref:l,onKeyDown:y=>{y.key!=="Escape"||!i||(y.preventDefault(),y.stopPropagation(),n(!1),c.current?.focus())},children:[ri("button",{ref:c,type:"button",className:"bb-button bb-button--ghost",disabled:f,"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"?Kt(_h,{size:14}):Kt(Uh,{size:14}),e,Kt(qh,{size:12})]}),i&&Kt("div",{className:"bb-exportMenu",id:w,role:"group","aria-label":`${e} options`,style:{maxHeight:`min(65vh, ${o}px)`},children:t.map((y,b)=>ri("div",{className:"bb-fileMenuScope",children:[Kt("div",{className:"bb-exportMenuTitle",children:y.title}),Kt("p",{className:"bb-exportMenuDescription",id:`${w}-${b}`,children:y.description}),y.options.map(g=>ri("button",{type:"button",className:"bb-exportMenuItem",disabled:g.disabled||a,"aria-label":`${e} ${g.label}`,"aria-describedby":`${w}-${b}`,onClick:()=>{n(!1),g.run()},children:[g.icon,g.label]},g.label))]},y.title))})]})}function Lp(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:Kt(Kh,{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:Kt(Ip,{size:14}),disabled:i.importDisabled,run:i.onImport}]:[{label:`${i.title} JSON`,icon:Kt(Ip,{size:14}),disabled:i.exportDisabled,run:i.onExportJson},{label:`${i.title} TypeScript`,icon:Kt(Gh,{size:14}),disabled:i.exportDisabled,run:i.onExportTs}]}))]}function zp({scopes:e,sceneBundle:t,busy:a}){return Kt(Dp,{action:"Export",groups:Lp("Export",e,t),busy:a})}function Fp({scopes:e,sceneBundle:t,busy:a}){return Kt(Dp,{action:"Import",groups:Lp("Import",e,t),busy:a})}import{jsx as ln,jsxs as Hp}from"react/jsx-runtime";function Qr({canUndo:e,canRedo:t,onUndo:a,onRedo:i,onReset:n,resetDisabled:o,resetTitle:d,fileScopes:l,sceneBundle:c,busy:w}){return Hp("div",{className:"bb-toolbar",children:[Hp("div",{className:"bb-toolbarGroup",children:[ln("button",{type:"button",className:"bb-iconButton",disabled:!e||w,onClick:a,title:"Undo (Cmd/Ctrl+Z)",children:ln(Jh,{size:16})}),ln("button",{type:"button",className:"bb-iconButton",disabled:o||w,onClick:n,title:d,children:ln(Wh,{size:16})}),ln("button",{type:"button",className:"bb-iconButton",disabled:!t||w,onClick:i,title:"Redo (Cmd/Ctrl+Shift+Z)",children:ln(Yh,{size:16})})]}),ln("div",{className:"bb-toolbarDivider"}),ln(Fp,{scopes:l,sceneBundle:c,busy:w}),ln("div",{className:"bb-toolbarDivider"}),ln(zp,{scopes:l,sceneBundle:c,busy:w})]})}import{AlertTriangle as es,History as Xh,Upload as Zh,X as ba}from"lucide-react";import{useId as pa,useState as Qh}from"react";import{jsx as ne,jsxs as fe}from"react/jsx-runtime";function ex(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 $p({target:e,onCancel:t,onConfirm:a}){return ne("div",{className:"bb-reset-overlay",onClick:t,children:fe("div",{className:"bb-reset-dialog",onClick:i=>i.stopPropagation(),children:[fe("div",{className:"bb-reset-header",children:[fe("h3",{className:"bb-reset-title",children:[ne(es,{size:20,className:"bb-icon-warning"}),"Confirm Reset"]}),ne("button",{className:"bb-reset-close",onClick:t,children:ne(ba,{size:20})})]}),fe("div",{className:"bb-reset-body",children:[fe("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!"})]}),fe("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 Vp({modelNames:e,mergedSourceCount:t,savedAt:a,onCancel:i,onConfirm:n}){let o=pa();return ne("div",{className:"bb-reset-overlay",onClick:i,children:fe("div",{className:"bb-reset-dialog",role:"dialog","aria-modal":"true","aria-labelledby":o,onClick:d=>d.stopPropagation(),children:[fe("div",{className:"bb-reset-header",children:[fe("h3",{className:"bb-reset-title",id:o,children:[ne(Xh,{size:20,className:"bb-icon-restore"}),"Restore Last Session"]}),ne("button",{className:"bb-reset-close",onClick:i,children:ne(ba,{size:20})})]}),fe("div",{className:"bb-reset-body",children:[fe("p",{className:"bb-reset-message",children:["Restore the session saved ",ex(a),"?"]}),fe("p",{className:"bb-reset-message",children:[fe("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."})]}),fe("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 qp({nodeLabel:e,count:t=1,onCancel:a,onConfirm:i}){let n=t>1;return ne("div",{className:"bb-reset-overlay",onClick:a,children:fe("div",{className:"bb-reset-dialog",onClick:o=>o.stopPropagation(),children:[fe("div",{className:"bb-reset-header",children:[fe("h3",{className:"bb-reset-title",children:[ne(es,{size:20,className:"bb-icon-warning"}),n?"Delete Objects":"Delete Object"]}),ne("button",{className:"bb-reset-close",onClick:a,children:ne(ba,{size:20})})]}),fe("div",{className:"bb-reset-body",children:[fe("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!"})]}),fe("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 Up({destinations:e,onCancel:t,onChoose:a}){let[i,n]=Qh(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:fe("div",{className:"bb-reset-dialog",role:"dialog","aria-modal":"true","aria-labelledby":d,onClick:c=>c.stopPropagation(),children:[fe("div",{className:"bb-reset-header",children:[fe("h3",{className:"bb-reset-title",id:d,children:[ne(Zh,{size:20,className:"bb-icon-restore"}),"Add Model"]}),ne("button",{className:"bb-reset-close",onClick:t,children:ne(ba,{size:20})})]}),fe("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=>fe("option",{value:c.url,children:[c.label,": ",c.name,c.isActive?" (active)":""]},c.url))})]}),fe("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 Kp({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:fe("div",{className:"bb-reset-dialog",role:"dialog","aria-modal":"true","aria-labelledby":d,onClick:c=>c.stopPropagation(),children:[fe("div",{className:"bb-reset-header",children:[fe("h3",{className:"bb-reset-title",id:d,children:[ne(es,{size:20,className:"bb-icon-warning"}),"Remove Model"]}),ne("button",{className:"bb-reset-close",onClick:t,children:ne(ba,{size:20})})]}),fe("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"?fe("button",{type:"button",className:"bb-removeModelOption",onClick:()=>a(c.url),children:[fe("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):fe("button",{type:"button",className:"bb-removeModelOption bb-removeModelOptionMerge",onClick:()=>i(c.url),children:[fe("span",{className:"bb-removeModelOptionLabel",children:[c.label,fe("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."})]}),fe("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 tx}from"fflate";function Gp(e){return JSON.stringify(e,null,2)}function _p(e){return['import { defineObjectBindings } from "@liveroom-tech/react-immersive/utils";',"",`export const objectBindings = defineObjectBindings(${JSON.stringify(e,null,2)});`,""].join(`
|
|
2
|
+
`)}function Wp(e){return JSON.stringify(e,null,2)}function Yp(e){return['import type { SceneConfig } from "@liveroom-tech/react-immersive/utils";',"",`export const sceneConfig: SceneConfig = ${JSON.stringify(e,null,2)};`,""].join(`
|
|
3
|
+
`)}function Jp(e,t,a){Co(new Blob([t],{type:a}),e)}function ts(e){return JSON.stringify(e??{},null,2)}function ns(e){return`[${e[0].toFixed(3)}, ${e[1].toFixed(3)}, ${e[2].toFixed(3)}]`}function nx(e){return(e.decals??[]).map(t=>t.image).filter(t=>!!t?.trim())}function ox(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 Xp(e){let t=new Set;for(let a of Object.values(e)){for(let i of ox(a))t.add(i);for(let i of nx(a))t.add(i)}return Qp(t)}async function Zp(e){let t=new Set,a=e.background?.imageUrl?.trim();return a&&t.add(a),Qp(t)}async function Qp(e){let t=[],a=[];return await Promise.all(Array.from(e).map(async i=>{let n=nn(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 mn(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){Jp(e,t,a);return}let o={[e]:tx(t)};for(let l of n)o[l.path]=new Uint8Array(await l.blob.arrayBuffer());let d=await Ka(o);Co(new Blob([d],{type:"application/zip"}),i)}async function si(e){let t=e.background?.imageUrl?.trim();if(t)try{let a=await mn(t);a&&Xt(t,URL.createObjectURL(a))}catch(a){console.warn("[BindingBuilder] Could not rehydrate the background image:",a)}}async function Io(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 mn(n.image);o&&Xt(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 El){let d=i[n]?.path;if(d)try{let l=await mn(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);Xt(d,c)}catch(l){console.warn(`[BindingBuilder] Could not rehydrate "${t}"'s ${n}:`,l)}}})),e}async function eb(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 mn(n);o&&Xt(n,URL.createObjectURL(o))})),e}function tb({bindings:e,setBindings:t,sceneConfig:a,setSceneConfig:i,nodeKeys:n,sceneConfigInputRef:o,setIsExporting:d,setStatusMessage:l,setStatusTone:c}){let w=x=>y("bindings",()=>Xp(e),C=>x==="json"?ua("objectBindings.json",Gp(e),"application/json","objectBindings.zip",C):ua("objectBindings.ts",_p(e),"text/typescript","objectBindings-ts.zip",C)),f=x=>y("scene config",()=>Zp(a),C=>x==="json"?ua("sceneConfig.json",Wp(a),"application/json","sceneConfig.zip",C):ua("sceneConfig.ts",Yp(a),"text/typescript","sceneConfig-ts.zip",C)),y=async(x,C,S)=>{d(!0);try{let{assets:h,failedPaths:k}=await C();await S(h),k.length>0?(l(`Exported, but ${k.length} uploaded image${k.length===1?"":"s"} couldn't be bundled: ${k.join(", ")}.`),c("error")):h.length>0&&(l(`Exported with ${h.length} uploaded image${h.length===1?"":"s"} bundled into the zip.`),c("success"))}catch(h){let k=h instanceof Error?h.message:"Unknown export error.";l(`Failed to export ${x}: ${k}`),c("error")}finally{d(!1)}},b=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 h={...e},k={},O=0;for(let M of Object.keys(h)){let j=S.get(M);j&&(h[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 Io(k);Object.assign(h,p),t(h);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 b(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"],h=C;if(h.section!==void 0)try{h.section=Ha(a.section,h.section)}catch(O){l(O instanceof Error?O.message:String(O)),c("error");return}if(h.selectionSets!==void 0)try{h.selectionSets=wo(h.selectionSets)}catch(O){l(O instanceof Error?O.message:String(O)),c("error");return}if(h.measurements!==void 0)try{h.measurements=$a(h.measurements)}catch(O){l(O instanceof Error?O.message:String(O)),c("error");return}let k=S.filter(O=>h[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")&&h.background&&await si({background:h.background}),i(O=>{let p={...O};for(let r of k)p[r]=r==="measurements"||r==="section"?h[r]:ta(O[r],h[r]);return p}),l(`Imported ${k.length} section${k.length===1?"":"s"} from ${x.name}.`),c("success")};return{handleExportBindings:w,handleExportSceneConfig:f,importBindingsFile:b,handleImportBindingsChange:g,openSceneConfigImportPicker:B,importSceneConfigFile:v,handleImportSceneConfigChange:async x=>{let C=x.target.files?.[0];C&&(await v(C),x.target.value="")}}}var os={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"]},nb=Object.keys(os);function ob(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 as(e){if(e)return Object.values(e).some(ob)?e:void 0}function Gt(e,t){return e?os[t].some(a=>ob(e[a])):!1}function is(e){return{pbr:Gt(e,"pbr"),roughness:Gt(e,"roughness"),emission:Gt(e,"emission"),opacity:Gt(e,"opacity"),normalBump:Gt(e,"normalBump"),displacement:Gt(e,"displacement"),ao:Gt(e,"ao"),clearcoat:Gt(e,"clearcoat"),sheen:Gt(e,"sheen"),anisotropy:Gt(e,"anisotropy"),transmission:Gt(e,"transmission"),faces:Gt(e,"faces")}}function rs(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 ab(e,t){if(!e)return;let a={...e};for(let i of os[t])delete a[i];return a}import{Fragment as $n,jsx as V,jsxs as Te}from"react/jsx-runtime";var rb="/room.glb";function ss(){return`${Date.now().toString(36)}-${Math.random().toString(36).slice(2,10)}`}function sb(e){return`Couldn't reload ${e} from your last session. It's still saved in this browser.`}function px({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:[V("input",{type:"checkbox",ref:o=>{o&&(o.indeterminate=n)},checked:i,onChange:o=>a(o.target.checked)}),e]})}function bx({licenseKey:e,licenseValidationUrl:t,arHandoff:a=!0,mobileHandoffUrl:i,dracoDecoderPath:n,ktx2TranscoderPath:o,meshopt:d,project:l,onProjectChange:c,projectChangeDebounceMs:w=350,onModelUpload:f,onTextureUpload:y,onEditLeaseChange:b,allowModelChange:g=!0,hideLicenseCheckingOverlay:B=!1}){let v=de(null),P=de(null),x=de(null),C=de(null),S=de(null),[h]=W(()=>l?ar(l):null),[k,O]=W(h?.url??null),[p,r]=W(()=>l?l.models.filter(s=>s!==h).map(rr):[]),[M,j]=W(()=>l?l.models.map(s=>s.url):[]),[R,E]=W(h?.name??""),[z,pe]=W(h),ke=pt(()=>l&&M.length>1&&z?.tilesetUrl?{...z,tilesetUrl:null}:z,[l,M.length,z]),he=de(l?sr(l):new Map),{selectedItem:I,setSelectedItem:Q,multiSelectMode:G,setMultiSelectMode:L,multiSelectedKeys:oe,setMultiSelectedKeys:tt,groupSelectionActive:me,selectObject:wt,setSelection:Vn,toggleMultiSelect:Do,exitMultiSelect:A,clearSelection:X}=Tp(),bt=de({mode:!1,keys:[]}),be=de({shiftKey:!1,ctrlKey:!1,metaKey:!1}),[Ue,ma]=W(null);bt.current={mode:me,keys:oe};let ie=wp(h?.objectBindings??{}),Z=ie.value,qn=ie.setValue,ga=de("free");Np({bindings:Z,multiSelectMode:me,selectedItem:I,multiSelectedKeys:oe,setSelectedItem:Q,setMultiSelectedKeys:tt});let Je=ie.mergeSources,Sn=ie.setMergeSourcesUntracked;ct(()=>{h?.mergeModels?.length&&Sn(No(h))},[h,Sn]);let[Ie,dn]=W(!1),[fa,Lo]=W(null),lb=pt(()=>fa?{target:fa}:null,[fa]);ct(()=>{Lo(null)},[k]),ct(()=>{L(!1),tt([])},[k]);let[ha,wn]=W(null);ct(()=>wn(null),[I,k]),ct(()=>{yi(null),Si(null)},[k]);let[db,Un]=W(null),[ls,cb]=W(!1),[ds,J]=W("Load the demo model or upload a GLB, GLTF, OBJ, FBX, USDZ, STL, or PLY model to generate bindings."),[xa,te]=W("default"),[pb,zo]=W(!1),[cs,ya]=W("{}"),[ps,va]=W("{}"),[bb,Sa]=W(null),[ub,wa]=W(null),[mb,Fo]=W(!1),[so,bs]=W(!1),[gb,fb]=W(!1),[Qt,us]=W({identity:!0,basics:!0,material:!1,decals:!1,actions:!1,camera:!1,transform:!1,metrics:!1,metadata:!1}),[hb,xb]=W({pbr:!1,roughness:!1,emission:!1,opacity:!1,normalBump:!1,displacement:!1,ao:!1,clearcoat:!1,sheen:!1,anisotropy:!1,transmission:!1,faces:!1}),en=s=>us(u=>({...u,[s]:!u[s]})),yb=s=>xb(u=>({...u,[s]:!u[s]})),[cn,Ho]=W("object"),[Cn,li]=W("General"),[ms,vb]=W(null),[gs,fs]=W(!1),hs=ae(()=>{bs(!1),Ho("scene"),li("General"),fs(!0)},[]),[Sb,wb]=W("metalness"),[Cb,di]=W(is()),xs=de(null),[ys,kb]=W(!1),[ci,Mb]=W(!0),[pi,Nb]=W(!0),[Tb,vs]=W(!1),[$o,Ss]=W(null),[Kn,bi]=W(null),[Pb,ui]=W(!1),Ca=de(null),ka=de({modelUrl:k,modelName:R,modelOrder:M,parkedModels:p});ka.current={modelUrl:k,modelName:R,modelOrder:M,parkedModels:p};let[Bb,lo]=W(!1),[kn,mi]=W(null),[gi,ws]=W(!1),[Cs,ks]=W(!1),[Ms,Rb]=W("world"),Et=de({}),He=na(l&&h?Ja(l.sceneConfig,h):Pn),Xe=na(l?ir(l):Wn),[Ns,co]=W([]),Ct=pt(()=>({...Xe.value,placements:{...Object.fromEntries(Ns.map(s=>[s,{deleted:!0}])),...Xe.value.placements}}),[Xe.value,Ns]),[po,bo]=W(!1),Ts=de(null),Re=He.value,Vo=He.setValue,Ab=ae(s=>{let u=wo(s);He.setValueAsStep(m=>({...m,selectionSets:u}))},[He.setValueAsStep]),Ma=He.setValueUntracked,fi=ae(s=>{let u=mt(Re,s.modelSettings);s.sceneHistory?He.restoreSnapshot({...s.sceneHistory,present:u}):He.reset(u)},[Re,He.restoreSnapshot,He.reset]),{hasEdits:Ob,markSessionEdited:kt,resetSessionEdits:hi}=Bp(ie.edits,He.edits+Xe.edits),[Mn,jb]=W(!1),[Eb,Ib]=W(.5),[xi,Db]=W(!0),[uo,yi]=W(null),mo=uo??{bindings:ie.baseline,sceneConfig:He.baseline},[vi,Lb]=W("modelObjectId"),[Na,Si]=W(null),qo=pt(()=>Mn?nd({objectBindings:mo.bindings,sceneConfig:mo.sceneConfig},{objectBindings:Z,sceneConfig:Re},{matchBy:vi}):null,[Mn,mo.bindings,mo.sceneConfig,Z,Re,vi]),Ps=pt(()=>qo&&xi?{before:Zi(qo,"before",Na),after:Zi(qo,"after",Na)}:null,[qo,Na,xi]),[Bs,wi]=W("orbit"),[zb,Rs]=W(!1),Ci=de(void 0),ki=ae(()=>{Rs(!0),clearTimeout(Ci.current),Ci.current=setTimeout(()=>Rs(!1),5e3)},[]);ct(()=>()=>clearTimeout(Ci.current),[]),ct(()=>{k&&!Ie&&ki()},[k,Ie,ki]);let it=Bs==="pointerLock",[As,Fb]=W(null),Os=de(null),Hb=As?.objectKey===I&&As?.textureKey==="texture",[$b,go]=W(null),[Vb,Mi]=W(null),Uo=ql(e,t),fo=Hl(Uo.tier);ga.current=fo;let js=$l.models[fo],qb=pt(()=>({isInsideEditor:!0,activeTab:cn,activeSubTab:Cn,tier:fo,setActiveTab:Ho,setActiveSubTab:li,measurementPanelTarget:ms,setMeasurementPanelTarget:vb,measurementsPanelOpen:gs,setMeasurementsPanelOpen:fs,openMeasurementsPanel:hs}),[cn,Cn,fo,ms,gs,hs]),ut=de(null),ho=de(0),It=de(0),Es=de(l?`${l.id}:${l.revision}`:null),Is=de(null),ux=de(!1),Ta=de(!1),Pa=de(l?To(l):null),Ni=de(!1),Ba=de(new Set),Ra=de(new Map),Aa=de(void 0),Gn=de(0),rt=de(null),Mt=de(l?{requestId:0,modelName:h.name??"model",modelUrl:h.url,storedBindings:h.objectBindings,streaming:!!h.tilesetUrl}:null),st=de(h?{model:{kind:"url",url:h.url,name:h.name??"model"}}:null),Oa=de(new Set),pn=de(new Map);kp(ie.snapshot,p,{modelUrl:k,modelSourceRef:st,uploadedFilesRef:pn});let Ko=de(null),Ub=de(!1),bn=de(null),Dt=de(new Map),[Ti,Ds]=W(0),Nn=pt(()=>new Map(M.map(s=>{let u=s===k?st.current?.model:p.find(m=>m.url===s)?.sessionModel;return[s,u?on(u):`url:${s}`]})),[M,k,p]),Go=s=>Ct.placements[Nn.get(s)??`url:${s}`]??{},$e=pt(()=>M.map((s,u)=>({id:Nn.get(s)??`url:${s}`,url:s,name:Go(s).label??(s===k?R:p.find(m=>m.url===s)?.name)??`Asset ${u+1}`,placement:Go(s),ready:Dt.current.has(s)})).filter(s=>!s.placement.deleted),[M,k,R,p,Ct,Nn,Ti]),Ls=vt(fo,"models",$e.length),[Pi,Kb]=W(!1),[zs,Fs]=W(null),[Gb,Hs]=W(null),_b=ae(()=>{let s=k?Dt.current.get(k):void 0;!s||!k||Fs({url:k,report:Rl(s,{source:{...Bl(s),name:R},scope:ke?.tilesetUrl?"resident-tiles":"asset"})})},[k,R,ke?.tilesetUrl]);ct(()=>{Hs(null)},[k,Pi]);let{materialVariantGroups:Wb,objectsWithoutUvs:$s,hierarchy:Yb}=Op({modelUrl:k,scenesRef:Dt,sceneRevision:Ti,streaming:!!ke?.tilesetUrl});ct(()=>{let s=new Set($e.map(u=>u.url));for(let u of Dt.current.keys())s.has(u)||Dt.current.delete(u)},[$e]),Ap({enabled:!ke?.tilesetUrl,modelUrl:k,bindings:Z,mergeSources:Je,parkedModels:p,scenesRef:Dt,sceneRevision:Ti,setBindings:ie.setValueUntracked,setParkedModels:r});let xo=de(null),[Jb,Xb]=W(null),[Vs,Zb]=W({}),Qb=pt(()=>{if(!me||oe.length===0||!xo.current)return null;let u=oe.filter(m=>Z[m]&&!Z[m].removed).map(m=>Vs[m]).filter(m=>!!m);return u.length>0?u:null},[me,oe,Vs,Z]),{cameraState:Ve,resetView:qs,focusObject:Us,fitScene:Ks,setCameraState:ja,handleCameraChange:eu,handleViewerReady:tu}=ml(),nu=ae(s=>{it||ja({position:s.position,target:s.target,fov:s.fov??Ve?.fov??null,zoom:s.zoom??Ve?.zoom??1,azimuthAngle:s.azimuthAngle,polarAngle:s.polarAngle},!0)},[it,ja,Ve]),_t=id(),ou=pt(()=>$e.map(s=>s.url),[$e]),yo=zd(ou),Gs=Hd({modelUrl:k,sceneConfig:Re,setSceneConfig:Vo,setSceneConfigUntracked:Ma,parkedModels:p,setParkedModels:r,animations:yo,markSessionEdited:kt}),De=I?Z[I]??null:null,Bi=De?.style?.material,_s=!$s.has(De?.modelObjectId??I??""),au=pt(()=>{if(!($e.length<2))return $e.map(s=>({url:s.url,label:s.name,bindings:s.url===k?Z:p.find(u=>u.url===s.url)?.bindings??{},isActive:s.url===k}))},[$e,k,Z,p]),_o=pt(()=>{let s=[];return $e.forEach((u,m)=>{let T=u.url,N=T===k,F=N?void 0:p.find(_=>_.url===T),q=u.name||`Asset ${m+1}`;s.push({kind:"model",url:T,label:q,name:N?R:F?.name??"Untitled model",isActive:N}),(N?Je:F?.mergedModelSources??[]).forEach(_=>{s.push({kind:"merge",url:_.url,label:"Merged nodes",name:sn(_.namePrefix),ownerLabel:q})})}),l&&$e.length<2?s.filter(u=>u.kind!=="model"):s},[l,$e,k,R,p,Je]),Ri=pt(()=>Je.map(s=>({url:s.url,namePrefix:s.namePrefix})),[Je]),Ws=pt(()=>(l?M.length<2:M.length<1)?void 0:M.map((u,m)=>{let T=Ct.placements[Nn.get(u)??`url:${u}`]??{},N={transform:T,visible:T.visible!==!1&&!T.deleted,label:T.label};if(u===k)return{url:u,label:N.label??(R||`Model ${m+1}`),transform:N.transform,visible:N.visible,objectBindings:Z,originalNodePoses:Et.current,mergeModels:Ri};let q=p.find(U=>U.url===u);return{url:u,label:N.label??(q?.name||`Model ${m+1}`),transform:N.transform,visible:N.visible,objectBindings:q?.bindings??{},originalNodePoses:q?.originalTransforms,sceneConfig:mt(Re,q?.modelSettings),mergeModels:(q?.mergedModelSources??[]).map(U=>({url:U.url,namePrefix:U.namePrefix}))}}).filter(u=>!Ct.placements[Nn.get(u.url)??`url:${u.url}`]?.deleted),[l,M,k,R,Z,p,Ri,Re,Ct,Nn]);ct(()=>{let s=x.current;if(!s)return;let u=s.querySelector(".ri-modelSwitcher"),m=()=>{let N=Mn?48:12,F=u?Math.max(N,u.getBoundingClientRect().bottom-s.getBoundingClientRect().top+8):N;s.style.setProperty("--bb-canvas-hint-top",`${F}px`)};m();let T=new ResizeObserver(m);return T.observe(s),u&&T.observe(u),()=>{T.disconnect(),s.style.removeProperty("--bb-canvas-hint-top")}},[Ws,Mn]);let Tn=De?.cameraState,iu=Ve?{position:ns(Ve.position),target:ns(Ve.target)}:null,ru=ae(s=>{Vo(u=>{let m=u.annotations.map(N=>N.id).join(","),T=s.map(N=>N.id).join(",");return m===T?u:s.length>u.annotations.length&&!vt(ga.current,"annotations",u.annotations.length)?(J(`More annotations require the ${Yi[un("annotations",u.annotations.length)]} plan or higher.`),te("error"),u):{...u,annotations:s}})},[]),su=ae(s=>{go(s?{annotation:s}:null)},[]);ct(()=>{if(!De){ya("{}"),va("{}"),Sa(null),wa(null);return}ya(ts(De.metrics)),va(ts(De.metadata)),Sa(null),wa(null)},[De]),ct(()=>{let s=is(Bi);if(xs.current!==I){xs.current=I,di(s);return}di(u=>{let m=!1,T={...u};for(let N of nb)s[N]&&!u[N]&&(T[N]=!0,m=!0);return m?T:u})},[I,Bi]),ct(()=>()=>{ut.current?.cleanup(),rt.current&&clearTimeout(rt.current)},[]);let Ea=ae((s,u)=>{let m=Xo(s);if(u){let T=new Map(Object.values(u).map(N=>[N.modelObjectId,N]));for(let N of s){let F=T.get(N);F&&(m[N]=F)}}return m},[]);ct(()=>{if(!l)return;let s=`${l.id}:${l.revision}`;if(Es.current===s)return;Es.current=s,he.current=sr(l);let u=l.models.find(le=>le.url===k),m=u&&!l.composition.placements[Zn(u.url)]?.deleted?u:ar(l),T=Ja(l.sceneConfig,m),N=k!==m.url||z?.tilesetUrl!==m.tilesetUrl||z?.assetVersion!==m.assetVersion,F=To(l);if(!N&&Ba.current.delete(F)){Pa.current=F;return}Ba.current.clear();let q=!Xa(Z,m.objectBindings),U=!Xa(Re,T);pe(m),E(m.name??"model");let _=m.objectBindings;if(q){let le=Is.current;_=le?Ea(le,m.objectBindings):m.objectBindings,ie.reset(_)}else _=Z;U&&He.reset(T),r(le=>l.models.filter(Le=>Le.url!==m.url).map(Le=>{let Pt=le.find(Wt=>Wt.url===Le.url);if(!Pt)return rr(Le);let je=JSON.stringify(Pt.mergedModelSources.map(Wt=>Wt.url))===JSON.stringify((Le.mergeModels??[]).map(Wt=>Wt.url));return{...Pt,name:Le.name??Pt.name,bindings:Le.objectBindings,modelSettings:Le.modelSettings,mergedModelSources:je?Pt.mergedModelSources:No(Le),bindingHistory:je?Pt.bindingHistory:void 0}})),j(l.models.map(le=>le.url));let ge=(m.mergeModels??[]).map(le=>le.url);if(JSON.stringify(Je.map(le=>le.url))!==JSON.stringify(ge)&&(Sn(No(m)),ie.clearHistory()),Xa(Xe.value,l.composition)||Xe.reset(ir(l)),N){_t.clearAnimations();let le=++It.current;Mt.current={requestId:le,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"}},bn.current=null,Q(null),dn(!0),O(m.url)}Pa.current=To({models:l.models.map(le=>le===m?{...le,objectBindings:_}:le),composition:l.composition,sceneConfig:l.sceneConfig})},[z,Z,Ea,Xe,Je,l,k,Re,ie,He,Sn,_t.clearAnimations]);let Ai=de(c);Ai.current=c;let Ys=de(y);Ys.current=y,ct(()=>{if(!l||!Ai.current||!k||Mt.current)return;let s=()=>Sd({project:l,modelUrl:k,modelName:R,bindings:Z,sceneConfig:Re,mergedModelSources:Je,parkedModels:p,modelOrder:M,composition:Ct,sources:he.current});if(Ta.current){Ta.current=!1,Pa.current=To(s());return}let u=window.setTimeout(()=>{if(Ni.current)return;let m=s(),T=To(m);if(T===Pa.current||Ba.current.has(T))return;let N=Ys.current,F=N?Xn(m.models).size+Xn(m.sceneConfig).size:0;if(N&&F>0){Ni.current=!0;let q=Xn(m.sceneConfig,Xn(m.models));Promise.all([...q].map(async U=>{if(!Ra.current.has(U))try{Ra.current.set(U,await N(await Cd(U),U))}catch(_){J(_ instanceof Error?_.message:"Could not save an image."),te("error"),Ra.current.set(U,"")}})).then(()=>{Ni.current=!1;let U=_=>Ya(_,Ra.current);ie.setValueUntracked(U),He.setValueUntracked(U),r(_=>_.map(ge=>({...ge,bindings:U(ge.bindings),modelSettings:U(ge.modelSettings)})))});return}Ba.current.add(T),Ai.current?.(m,"local")},w);return()=>window.clearTimeout(u)},[Z,Ct,Je,R,M,k,p,l,w,Re]),ct(()=>{let s=u=>{if(u.key.toLowerCase()!=="z"||!(u.metaKey||u.ctrlKey))return;let m=u.target,T=m?.tagName;if(T==="INPUT"||T==="TEXTAREA"||m?.isContentEditable)return;u.preventDefault();let N=cn==="scene"?Cn==="Assets"?Xe:He:ie;u.shiftKey?N.redo():N.undo()};return window.addEventListener("keydown",s),()=>window.removeEventListener("keydown",s)},[cn,Cn,Xe,ie,He]);let Oi=!l&&g,{handleTextureUpload:lu}=Mp({composition:Ct,autosaveEnabled:Oi,hasEdits:Ob,modelUrl:k,bindings:Z,sceneConfig:Re,parkedModels:p,mergedModelSources:Je,modelOrder:M,onTextureUpload:y,modelSourceRef:st,pendingLoadRef:Mt,storedModelKeysRef:Oa,uploadedFilesRef:pn,pendingAutosaveRef:Ko,autosaveFailureShownRef:Ub,setStatusMessage:J,setStatusTone:te});ct(()=>{if(Ie||xa==="default"||xa==="success")return;zo(!0);let s=window.setTimeout(()=>zo(!1),4e3);return()=>window.clearTimeout(s)},[ds,xa,Ie]);let tn=pt(()=>Object.keys(Z),[Z]),du=pt(()=>!I||!De?null:De.id.trim()?Object.entries(Z).some(([m,T])=>m!==I&&T.id===De.id)?"Another binding already uses this ID.":null:"ID is required.",[Z,I,De]),Lt=(s,u)=>{qn(m=>{let T=bt.current,N=T.mode&&T.keys.includes(s)?T.keys.filter(q=>m[q]):[s];if(N.length<=1)return{...m,[s]:u(m[s],s)};let F={...m};for(let q of N){let U=m[q];F[q]={...u(U,q),id:U.id,modelObjectId:U.modelObjectId}}return F})},ji=(s,u)=>{Lt(s,m=>{let T=as(u(m.style?.material));return rs(m,T)})},cu=(s,u,m)=>{ji(s,T=>({...T,[u]:m?{path:m}:void 0}))},pu=(s,u)=>{di(m=>({...m,[s]:u})),!u&&I&&Lt(I,m=>{let T=as(ab(m.style?.material,s));return rs(m,T)})},Ei=ae((s,u,m)=>{let{bindings:T,originalTransforms:N,nodeNames:F}=ca(s,m);Et.current=N,ie.reset(ro(s,m??{},Je,T)),Q(F[0]??null),m||Ma(q=>({...q,annotations:[]})),J(`Generated ${F.length} bindings from ${u}.`),te("success"),Gn.current=100,Un(100),rt.current&&clearTimeout(rt.current),rt.current=setTimeout(()=>{rt.current=null,dn(!1),Un(null)},400)},[ie,Ma,Je]),Ii=(s,u,m,T)=>{Ko.current?.();let N=++It.current;hi(),Xe.reset(Wn),co([]),l||He.reset(s!==k?mt(Re):Re),s!==k&&_t.clearAnimations(),p.forEach(U=>U.resolved?.cleanup()),r([]),j([s]),Sn([]),dn(!0),Un(null),Gn.current=0,rt.current&&(clearTimeout(rt.current),rt.current=null),Aa.current=m;let F=m?m/1048576:0;J(F>=100?`Reading ${u} (${Math.round(F)}MB \u2014 large file, this can take a while)...`:`Reading ${u} and generating starter bindings...`),te("default"),E(u),pe(T??{url:s,name:u}),go(null);let q=bn.current;if(s===k&&q?.url===s){Mt.current=null,Ei(q.scene,u);return}Mt.current={requestId:N,modelName:u,modelUrl:s,streaming:!!T?.tilesetUrl},O(s),ie.reset({}),Q(null)},bu=ae(s=>{k&&Dt.current.get(k)!==s&&(Dt.current.set(k,s),Ds(m=>m+1));let u=Mt.current;if(!(u&&u.requestId!==It.current)&&(k&&(bn.current={url:k,scene:s}),wn(null),Lo(null),!!u)){if(Mt.current=null,u.streaming){J(`Streaming ${u.modelName}.`),te("success"),dn(!1);return}u.storedBindings&&(Ta.current=!0),Ei(s,u.modelName,u.storedBindings),u.restoring&&J(`Restored your last session with ${u.modelName}.`)}},[Ei,k]),uu=ae(s=>{if(!ke?.tilesetUrl)return;let u=s.map(N=>N.name);if(u.length===0)return;Is.current=u,Ta.current=!0;let m=l?.models.find(N=>N.url===k)?.objectBindings,T=Ea(u,m);ie.reset(T),Q(N=>N??u[0]??null),J(`Streaming ${u.length} bindable objects.`),te("success"),dn(!1)},[Ea,ie,k,l,ke]),mu=ae(s=>{let u=Mt.current;if(!(u&&u.requestId!==It.current)){if(Mt.current=null,console.error(s),u?.restoring)st.current=null,O(null),J(sb(u.modelName));else if(u)J(Al(s)?`${u.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 ${u.modelName}. Make sure the file is a valid GLB, GLTF, OBJ, FBX, USDZ, STL, or PLY asset.`);else{let{detail:m}=Va(s,k??"",ut.current?.format);J(`Could not read ${R||"the model"}. ${m}`)}te("error"),rt.current&&(clearTimeout(rt.current),rt.current=null),Gn.current=0,dn(!1),Un(null)}},[k,R]),gu=ae(s=>{let u=null;if(s.lengthComputable&&s.total>0)u=s.loaded/s.total*100;else{let T=Aa.current;T&&T>0&&(u=s.loaded/T*100)}if(u===null)return;let m=Math.min(90,Math.floor(u/10)*10);m>Gn.current&&(Gn.current=m,Un(m)),u>=99.5&&J(T=>T.startsWith("Finalizing")?T:"Finalizing model \u2014 parsing geometry and textures (large files can take a moment here)...")},[]),fu=ae(s=>{_t.handleAnimationsReady(s),k&&yo.handleModelAnimationsReady(k,s)},[_t,k,yo.handleModelAnimationsReady]),mx=async()=>{ut.current?.cleanup(),ut.current=null,st.current={model:{kind:"url",url:rb,name:"room.glb"}},await Ii(rb,"room.glb")},Js=async s=>{if(!g)return;if(s.name.toLowerCase().endsWith(".ri.zip")){await al(s);return}if(f){try{dn(!0),J(`Uploading ${s.name}...`),te("default");let T=await f(s);he.current.set(T.url,T),st.current={model:{kind:"url",url:T.url,name:T.name??s.name}},await Ii(T.url,T.name??s.name,s.size,T)}catch(T){dn(!1),J(T instanceof Error?T.message:`Could not upload ${s.name}.`),te("error")}return}let u;try{u=await Bn(s)}catch(T){J(T instanceof Error?T.message:"Could not read model file. Upload a .glb, .gltf, .obj, .fbx, .usdz, .stl, .ply, or .zip asset."),te("error");return}ut.current?.cleanup(),ut.current=u;let m=ss();pn.current.set(m,s),st.current={model:{kind:"file",key:m,name:u.name},file:s},await Ii(u.url,u.name,s.size,{url:u.url,name:u.name})},hu=async s=>{let u=s.target.files?.[0];u&&(await Js(u),s.target.value="")},Ia=()=>{Ko.current=null,kt(),ut.current?.cleanup(),ut.current=null,bn.current=null,Mt.current=null,st.current=null,_t.clearAnimations(),Et.current={},ho.current=0,Fo(!1),rt.current&&(clearTimeout(rt.current),rt.current=null),Gn.current=0,Un(null),Aa.current=void 0,O(null),E(""),p.forEach(s=>s.resolved?.cleanup()),r([]),j([]),Xe.reset(Wn),co([]),Sn([]),pe(null),Q(null),go(null),ie.reset({}),ya("{}"),va("{}"),Sa(null),wa(null),Mi(null),ws(!1),ks(!1),Ma(s=>mt(s)),J("Load the demo model or upload a GLB, GLTF, OBJ, FBX, USDZ, STL, or PLY model to generate bindings."),te("default")},Xs=s=>l?{...s,bindingHistory:void 0}:s,xu=()=>{_o.length>1?lo(!0):Ia()},yu=()=>{lo(!1)},vu=s=>{if(lo(!1),M.length<=1){Ia();return}if(!M.includes(s))return;if(kt(),s!==k){let F=p.find(q=>q.url===s);F?.resolved?.cleanup(),r(q=>q.filter(U=>U.url!==s)),j(q=>q.filter(U=>U!==s)),J(`Removed ${F?.name??"the model"}.`),te("success");return}let u=M.filter(F=>F!==s),m=u[0],T=p.findIndex(F=>F.url===m),N=p[T];if(!N){Ia();return}ut.current?.cleanup(),r(F=>F.filter((q,U)=>U!==T)),j(u),ut.current=N.resolved??null,st.current={model:N.sessionModel??{kind:"url",url:N.url,name:N.name}},bn.current=null,Mt.current=null,Et.current=N.originalTransforms,_t.clearAnimations(),fi(N),O(N.url),E(N.name),pe(he.current.get(N.url)??{url:N.url,name:N.name}),ie.restoreModel(N),Q(Object.keys(N.bindings)[0]??null),go(null),J(`Removed the model \u2014 now viewing ${N.name}.`),te("success")},Su=s=>{lo(!1);let u=Je.find(N=>N.url===s);if(u){kt(),ie.removeMerge(s),l&&ie.clearHistory(),J(`Removed ${sn(u.namePrefix)}.`),te("success");return}let m=p.find(N=>N.mergedModelSources.some(F=>F.url===s));if(!m)return;let T=m.mergedModelSources.find(N=>N.url===s);T&&(kt(),r(N=>N.map(F=>F.url!==m.url?F:Xs(Wr(F,q=>_r(q,s))))),J(`Removed ${sn(T.namePrefix)}.`),te("success"))},wu=()=>{v.current?.click()},Zs=()=>{ui(!0)},Cu=s=>{let u=s.target.files?.[0];s.target.value="";let m=Ca.current;Ca.current=null,!(!u||!g||!m)&&(m.mode==="separate"?Nu(u):Tu(u,m.targetUrl))},ku=ae(()=>{Ca.current=null,ui(!1)},[]),Mu=ae(s=>{Ca.current=s,ui(!1),P.current?.click()},[]),Di=ae(async s=>{if(l&&f){J(`Uploading ${s.name}...`),te("default");let T=await f(s);he.current.set(T.url,T);let N=T.name??s.name;return{resolved:{url:T.url,name:N,format:"glb",cleanup:()=>{}},sessionModel:{kind:"url",url:T.url,name:N}}}let u=await Bn(s),m=ss();return pn.current.set(m,s),{resolved:u,sessionModel:{kind:"file",key:m,name:u.name}}},[l,f]),Nu=ae(async s=>{if(!vt(ga.current,"models",ka.current.modelOrder.length)){J("Your plan has no room for another model in this project. Upgrade to add more."),te("error");return}let u,m;try{({resolved:u,sessionModel:m}=await Di(s))}catch(T){J(T instanceof Error?T.message:"Could not read model file. Upload a .glb, .gltf, .obj, .fbx, .usdz, or .zip asset."),te("error");return}r(T=>[...T,{url:u.url,name:u.name,bindings:{},originalTransforms:{},resolved:u,sessionModel:m,mergedModelSources:[]}]),j(T=>[...T,u.url]),kt(),J(`Added ${u.name} as a separate model.`),te("success")},[kt,Di]),Tu=ae(async(s,u)=>{let m,T;try{({resolved:m,sessionModel:T}=await Di(s))}catch(_){J(_ instanceof Error?_.message:"Could not read model file. Upload a .glb, .gltf, .obj, .fbx, .usdz, or .zip asset."),te("error");return}let N=ka.current,F=N.parkedModels.find(_=>_.url===u);if(!N.modelOrder.includes(u)||u!==N.modelUrl&&!F){m.cleanup(),J("The destination model was removed. Choose a model and add the file again."),te("error");return}let q={url:m.url,resolved:m,sessionModel:T,nodeNames:[],loadState:"loading"};u===N.modelUrl?(ie.addMerge(_=>({...q,namePrefix:Kr(m.name,_.mergeSources,_.bindings)})),l&&ie.clearHistory()):r(_=>{let ge=_.findIndex(Le=>Le.url===u);if(ge===-1)return _;let le=[..._];return le[ge]=Xs(Wr(le[ge],Le=>({...Le,mergeSources:[...Le.mergeSources,{...q,namePrefix:Kr(m.name,Le.mergeSources,Le.bindings)}]}))),le});let U=u===N.modelUrl?N.modelName:F?.name;kt(),J(`Merging ${m.name} into ${U||"the model"}...`),te("default")},[ie.addMerge,kt]),Pu=ae((s,u)=>{let m=Je.find(_=>_.url===s);if(m){let{bindings:_,originalTransforms:ge,nodeNames:le}=Gr(u,Z);ie.hydrateMerge(s,{nodeNames:le,loadState:"loaded"},_),Et.current={...Et.current,...ge},J(`Merged ${le.length} node${le.length===1?"":"s"} from ${m.namePrefix||"the added model"} into ${R||"the model"}.`),te("success");return}let T=p.find(_=>_.mergedModelSources.some(ge=>ge.url===s));if(!T)return;let N=T.mergedModelSources.find(_=>_.url===s);if(!N)return;let{bindings:F,originalTransforms:q,nodeNames:U}=Gr(u,T.bindings);r(_=>_.map(ge=>ge.url!==T.url?ge:{...Yr(ge,s,{nodeNames:U,loadState:"loaded"},F),originalTransforms:{...ge.originalTransforms,...q}})),J(`Merged ${U.length} node${U.length===1?"":"s"} from ${N.namePrefix||"the added model"} into ${T.name||"the model"}.`),te("success")},[ie.hydrateMerge,R,Je,Z,p]),Bu=ae((s,u)=>{let m=Je.find(N=>N.url===s)??p.flatMap(N=>N.mergedModelSources).find(N=>N.url===s);if(!m)return;ie.hydrateMerge(s,{loadState:"failed"}),r(N=>N.map(F=>F.mergedModelSources.some(q=>q.url===s)?Yr(F,s,{loadState:"failed"}):F));let{detail:T}=Va(u,s,m.resolved.format);J(`Could not merge ${m.resolved.name}. ${T} Remove the failed file using the Remove model menu.`),te("error")},[Je,p,ie.hydrateMerge]),Ru=ae((s,u)=>{let m=p.find(N=>N.url===s);if(!m)return;let{detail:T}=Va(u,s,m.resolved?.format);J(`Could not read ${m.name}. ${T} Remove the failed file using the Remove model menu.`),te("error")},[p]),Au=ae((s,u)=>{Dt.current.get(s)!==u&&(Dt.current.set(s,u),Ds(m=>m+1)),r(m=>{let T=m.findIndex(U=>U.url===s);if(T===-1)return m;let{bindings:N,originalTransforms:F}=ca(u,m[T].bindings),q=[...m];return q[T]={...Sp(q[T],N),bindings:ro(u,m[T].bindings,m[T].mergedModelSources,N),originalTransforms:{...F,...m[T].originalTransforms}},q})},[]),vo=ae(s=>{if(s===k)return;let u=p.findIndex(N=>N.url===s);if(u===-1)return;let m=p[u];Ko.current?.(),kt();let T=k?{url:k,name:R,bindings:Z,originalTransforms:Et.current,resolved:ut.current??void 0,sessionModel:st.current?.model,mergedModelSources:Je,modelSettings:Rn(Re),bindingHistory:ie.snapshot,sceneHistory:He.snapshot}:null;r(N=>{let F=N.filter((q,U)=>U!==u);return T?[...F,T]:F}),ut.current=m.resolved??null,st.current={model:m.sessionModel??{kind:"url",url:m.url,name:m.name}},bn.current=null,Mt.current=null,_t.clearAnimations(),fi(m),Et.current=m.originalTransforms,O(m.url),E(m.name),pe(he.current.get(m.url)??{url:m.url,name:m.name}),ie.restoreModel(m),Q(Object.keys(m.bindings)[0]??null),go(null)},[k,R,Z,p,ie,Je,Re,He,fi,_t.clearAnimations,kt]),Ou=()=>{C.current?.click()};ct(()=>{k&&$e.length&&!$e.some(s=>s.url===k)&&vo($e[0].url)},[k,$e,vo]);let{handleExportBindings:Qs,handleExportSceneConfig:el,handleImportBindingsChange:ju,openSceneConfigImportPicker:Eu,handleImportSceneConfigChange:Iu}=tb({bindings:Z,setBindings:qn,sceneConfig:Re,setSceneConfig:Vo,nodeKeys:tn,sceneConfigInputRef:S,setIsExporting:cb,setStatusMessage:J,setStatusTone:te}),Du=s=>{s.preventDefault(),s.stopPropagation(),!(Ie||k)&&(ho.current+=1,Fo(!0))},Lu=s=>{s.preventDefault(),s.stopPropagation(),!(Ie||k)&&(s.dataTransfer.dropEffect="copy",Fo(!0))},zu=s=>{s.preventDefault(),s.stopPropagation(),!(Ie||k)&&(ho.current=Math.max(0,ho.current-1),ho.current===0&&Fo(!1))},Fu=async s=>{if(s.preventDefault(),s.stopPropagation(),ho.current=0,Fo(!1),Ie||k)return;let u=s.dataTransfer.files?.[0];u&&await Js(u)},tl=(s,u,m)=>{if(!I)return;let T;try{T=JSON.parse(u)}catch{m("Invalid JSON");return}if(T===null||typeof T!="object"||Array.isArray(T)){m("Expected a JSON object");return}if(s==="metrics"&&Object.values(T).some(F=>typeof F!="number"||!Number.isFinite(F))){m("Metrics values must be numbers");return}Lt(I,N=>({...N,[s]:T})),m(null)},nl=ae((s,u)=>{Oi&&Mo(s,u).catch(m=>console.warn("[BindingBuilder] Could not store decal image for autosave:",m))},[Oi]),Hu=pt(()=>{let s=bn.current?.scene,m=(s&&I?Wo(s,I):null)?.geometry;if(!m)return .2;m.boundingBox||m.computeBoundingBox();let T=m.boundingBox?.getSize(new ax),N=T?Math.max(T.x,T.y,T.z):0;return N>0&&Number.isFinite(N)?N/3:.2},[I,k,Ie]),$u=pt(()=>{if(!ha?.moving)return null;let{nodeKey:s,decal:u}=ha,m=Z[s],T=m?.decals?.find(N=>N.id===u.id);return T?{objectId:m.modelObjectId??s,decal:T,onCancel:()=>wn(null),onCommit:N=>{qn(F=>{let q=F[s];return q?{...F,[s]:{...q,decals:q.decals?.map(U=>U.id===T.id?{...U,...N}:U)}}:F}),wn(null)}}:null},[Z,ha,qn]),Vu=ae((s,u)=>{if(!I)return;let m=Z[I],T=m?.decals?.find(U=>U.id===s);if(!T)return;let N=xo.current,F=N?.raw.nodes[m.modelObjectId??I],q=Xl(F,N?.raw.controls.camera,T,u);if(!q){J("No visible surface in that direction. Try another arrow or rotate the view."),te("error"),zo(!0);return}wn(null),zo(!1),Lt(I,U=>({...U,decals:U.decals?.map(_=>_.id===s?{..._,...q}:_)}))},[Z,I,Lt]),qu=ae(s=>{if(!s||s.moving){wn(s);return}let u=xo.current,m=Z[s.nodeKey],T=u?.raw.nodes[m?.modelObjectId??s.nodeKey],N=Jl(T,u?.raw.controls.camera);if(!N){J("Could not find a surface on this object for the decal."),te("error"),zo(!0);return}let F={...s.decal,...N};qn(q=>{let U=q[s.nodeKey];if(!U)return q;let _=(U.decals??[]).filter(ge=>ge.id!==F.id);return{...q,[s.nodeKey]:{...U,decals:[..._,F]}}}),wn({...s,moving:!0})},[Z,qn]),Uu=ae((s,u)=>{let m=Object.entries(Z).find(([U,_])=>_===s||U===s.modelObjectId||_.modelObjectId===s.modelObjectId)?.[0],T=m?Z[m]?.decals?.find(U=>U.id===u):void 0;if(!m||!T)return;Ho("object"),us(U=>({...U,decals:!0})),Q(m);let{position:N,normal:F,...q}=T;setTimeout(()=>wn({nodeKey:m,decal:q,moving:!0}),0)},[Z]),Ku=ae(s=>{let u=[...new Set(s)].filter(m=>Z[m]&&!Z[m].removed);Vn(u)},[Z,Vn]),Gu=ae(s=>{let u=be.current;if(be.current={shiftKey:!1,ctrlKey:!1,metaKey:!1},it){wi("orbit");return}if(!s){wt(null);return}let m=Object.entries(Z).find(([T,N])=>N===s||T===s.modelObjectId||N.modelObjectId===s.modelObjectId)?.[0]??null;wt(m,u)},[it,Z,wt]),Li=ae(async s=>{if(it){wi("orbit");return}wt(s),!G&&(Mi(null),await Us(s))},[it,Us,G,wt]),_u=ae(s=>{Mi(s?Z[s]??null:null)},[Z]),Wu=ae(s=>fb(!s),[]),Yu=ae(()=>{if(it){J("Camera positions aren't available while Pointer Lock is the active camera controller."),te("error");return}if(!I||!Ve)return;let s={position:Ve.position,target:Ve.target,...Ve.fov!=null?{fov:Ve.fov}:{},zoom:Ve.zoom};Lt(I,u=>({...u,cameraState:s}))},[it,I,Ve]),Ju=ae(()=>{if(it){J("Camera positions aren't available while Pointer Lock is the active camera controller."),te("error");return}!Tn?.position||!Tn?.target||ja({position:Tn.position,target:Tn.target,fov:Tn.fov??Ve?.fov??null,zoom:Tn.zoom??Ve?.zoom??1},!0)},[it,Tn,ja,Ve]),Xu=ae(()=>{it||I&&Lt(I,s=>({...s,cameraState:void 0}))},[it,I]),Zu=ae(async()=>{if(it){J("Reset View isn't available while Pointer Lock is the active camera controller."),te("error");return}await qs()},[it,qs]),Qu=ae(async()=>{if(it){J("Fit Scene isn't available while Pointer Lock is the active camera controller."),te("error");return}await Ks()},[it,Ks]),em=ae(()=>{J("Texture position saved."),te("success"),Os.current?.()},[]),ol=ae(s=>{Ss(s),vs(!0)},[]),Da=ae(()=>{vs(!1),Ss(null)},[]),tm=ae(()=>{if($o==="bindings"){if(!tn.length){Da();return}let s=Xo(tn,$s);ie.reset(s,{asEdit:!0}),Q(tn[0]??null),J("Object bindings reset to default values."),te("success")}else $o==="assets"?(Xe.setValueAsStep(s=>({...s,gridSize:Wn.gridSize,placements:Object.fromEntries(Object.entries(s.placements).map(([u,m])=>{let{position:T,rotation:N,scale:F,...q}=m;return[u,q]}))})),J("Asset placements reset to default values."),te("success")):$o==="scene"&&(He.reset(Pn,{asEdit:!0}),J("Scene config reset to default values."),te("success"));Da()},[$o,tn,ie,He,Xe,Da]),nm=ae(s=>{s.length>0&&mi(s)},[]),om=ae(()=>{mi(null)},[]),am=ae(()=>{let s=kn;if(!s||s.length===0)return;let u=new Set(s);ie.setValueAsStep(m=>{let T={...m};for(let N of s)m[N]&&(T[N]={...m[N],removed:!0});return T}),Q(m=>m&&u.has(m)?null:m),tt(m=>m.filter(T=>!u.has(T))),Lo(m=>m&&u.has(m)?null:m),J(s.length===1?`Deleted ${Z[s[0]]?.label||s[0]}.`:`Deleted ${s.length} objects.`),te("success"),mi(null)},[kn,Z,ie.setValueAsStep]),im=ae(()=>{bi(null)},[]),rm=async()=>{let s;try{s=await yd()}catch(u){console.warn("[BindingBuilder] Could not read the saved session:",u),J("Couldn't read the saved session from this browser."),te("error");return}if(!s){J("No saved session in this browser. Sessions are saved when you edit a model or add another one."),te("error");return}bi(s)},zi=async(s,u)=>(await Promise.all(s.map(async({entry:T,file:N})=>{if(T.model.kind==="url"&&l)return No({url:"",objectBindings:{},mergeModels:[{url:T.model.url,namePrefix:T.namePrefix}]})[0];if(T.model.kind==="url")return console.warn(`[BindingBuilder] Could not restore merged model "${T.model.name}" \u2014 merged models must come from an uploaded file.`),null;if(!N)return console.warn(`[BindingBuilder] Could not restore merged model "${T.model.name}" \u2014 its file is no longer in this browser's storage.`),null;try{let F=await Bn(N);return u.set(T.model.key,N),{url:F.url,namePrefix:T.namePrefix,resolved:F,sessionModel:T.model,nodeNames:[],loadState:"loading"}}catch(F){return console.warn(`[BindingBuilder] Could not restore merged model "${T.model.name}":`,F),null}}))).filter(T=>T!==null),sm=async(s,u,m)=>{let T=await Promise.all(s.map(async({entry:F,file:q,mergeFiles:U})=>{if(F.model.kind==="url")return{url:F.model.url,name:F.model.name,bindings:await Io(F.bindings),originalTransforms:F.originalTransforms,modelSettings:F.modelSettings,sessionModel:F.model,mergedModelSources:await zi(U,m)};if(!q)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 _=await Bn(q);return m.set(F.model.key,q),{url:_.url,name:F.model.name,bindings:await Io(F.bindings),originalTransforms:F.originalTransforms,modelSettings:F.modelSettings,resolved:_,sessionModel:F.model,mergedModelSources:await zi(U,m)}}catch(_){return console.warn(`[BindingBuilder] Could not restore parked model "${F.model.name}":`,_),null}})),N=await zi(u,m);return{parkedModels:T.filter(F=>F!==null),mergedModelSources:N}},Fi=(s,u)=>{Xe.setValue(m=>({...m,placements:{...m.placements,[s]:{...m.placements[s],...u}}}))},lm=async s=>{if(po||!g||!Ls)return;let u=s===k?{url:s,name:R,bindings:Z,originalTransforms:Et.current,resolved:ut.current??void 0,sessionModel:st.current?.model,mergedModelSources:Je,modelSettings:Rn(Re)}:p.find(N=>N.url===s);if(!u?.sessionModel)return;if(l){let N=`${s.split("#")[0]}#copy-${crypto.randomUUID()}`,F=Zn(N),q=he.current.get(s);he.current.set(N,{...q,url:N});let U=`${u.name} copy`,_=structuredClone(u.modelSettings);_?.measurements&&(_.measurements.items=_.measurements.items.map(je=>({...je,modelId:F}))),r(je=>[...je,{...u,url:N,name:U,resolved:void 0,sessionModel:{kind:"url",url:N,name:U},bindings:structuredClone(u.bindings),originalTransforms:structuredClone(u.originalTransforms),modelSettings:_,mergedModelSources:u.mergedModelSources.map(Wt=>({...Wt,loadState:"loading"})),bindingHistory:void 0,sceneHistory:void 0}]),j(je=>[...je,N]),co(je=>[...je,F]);let ge=Go(s),[le,Le,Pt]=ge.position??[0,0,0];Xe.setValueAsStep(je=>({...je,placements:{...je.placements,[F]:{...ge,deleted:!1,label:`${ge.label??u.name} copy`,position:[le+Ct.gridSize,Le,Pt]}}})),kt(),J(`Duplicated ${u.name}.`),te("success");return}bo(!0);let m=It.current,T=[];try{let F=(u.sessionModel.kind==="file"?pn.current.get(u.sessionModel.key):void 0)??new File([await(await fetch(u.url)).blob()],u.name),q=await Bn(F);T.push(q);let U=ss(),_=`file:${U}`,ge=[];for(let Pe of u.mergedModelSources){if(Pe.sessionModel.kind!=="file")throw new Error("Cannot duplicate a merged source without its original file.");let yt=pn.current.get(Pe.sessionModel.key);if(!yt)throw new Error("An added source file is unavailable.");let Yt=await Bn(yt);T.push(Yt),ge.push({...Pe,resolved:Yt,url:Yt.url,loadState:"loading"})}if(m!==It.current||!ka.current.modelOrder.includes(s)){T.forEach(Pe=>Pe.cleanup());return}pn.current.set(U,F);let le=structuredClone(u.modelSettings);le?.measurements&&(le.measurements.items=le.measurements.items.map(Pe=>({...Pe,modelId:_}))),r(Pe=>[...Pe,{...u,url:q.url,name:`${u.name} copy`,resolved:q,sessionModel:{kind:"file",key:U,name:F.name},bindings:structuredClone(u.bindings),originalTransforms:structuredClone(u.originalTransforms),modelSettings:le,mergedModelSources:ge,bindingHistory:void 0,sceneHistory:void 0}]),j(Pe=>[...Pe,q.url]),co(Pe=>[...Pe,_]);let Le=Go(s),[Pt,je,Wt]=Le.position??[0,0,0];Xe.setValueAsStep(Pe=>({...Pe,placements:{...Pe.placements,[_]:{...Le,deleted:!1,label:`${Le.label??u.name} copy`,position:[Pt+Ct.gridSize,je,Wt]}}})),kt(),J(`Duplicated ${u.name}.`),te("success")}catch(N){T.forEach(F=>F.cleanup()),J(N instanceof Error?N.message:"Could not duplicate asset."),te("error")}finally{bo(!1)}},dm=s=>{if($e.length<2||!g)return;let u=$e.find(m=>m.url===s);u&&(s===k&&vo($e.find(m=>m.url!==s).url),Xe.setValueAsStep(m=>({...m,placements:{...m.placements,[u.id]:{...m.placements[u.id],deleted:!0}}})))},al=async s=>{if(!(po||!g)){if(!lt(ga.current,"sceneBundle")){J(`Importing a complete scene requires the ${Yi.starter} plan or higher.`),te("error");return}bo(!0);try{let u=await Pd(s);if(l){if(!f)throw new Error("This project can't accept new models.");let m=T=>u.session.composition?.placements[on(T)]?.deleted;if(1+u.parkedFiles.filter(T=>!m(T.entry.model)).length>js)throw new Error(`Your plan allows ${js} models per project. Upgrade to import this scene.`);J(`Uploading the models in ${s.name}...`),te("default"),u=await kd(u,async T=>{let N=await f(T);return he.current.set(N.url,N),N})}await il(u),kt()}catch(u){J(u instanceof Error?u.message:"Could not load scene bundle."),te("error")}finally{bo(!1)}}},cm=async()=>{let s=st.current;if(!(!s||!k||po)){bo(!0);try{let u=N=>({model:N.sessionModel,namePrefix:N.namePrefix}),m={model:s.model,bindings:Z,sceneConfig:Re,composition:Ct,mergeModels:Je.map(u),parkedModels:p.map(N=>({model:N.sessionModel??{kind:"url",url:N.url,name:N.name},bindings:N.bindings,originalTransforms:N.originalTransforms,modelSettings:N.modelSettings,mergeModels:N.mergedModelSources.map(u)})),modelOrder:M.map(N=>Nn.get(N)).filter(Boolean)},T=await Td(m,new Map(pn.current));Co(T,"scene.ri.zip"),J("Saved complete scene bundle."),te("success")}catch(u){J(u instanceof Error?u.message:"Could not save scene."),te("error")}finally{bo(!1)}}},il=async s=>{let u=s??Kn;if(bi(null),!u)return;let{session:m,file:T}=u,{model:N}=m;Ko.current=null;let F=It.current,q=await eb(ta(Pn,m.sceneConfig)),U=await Io(m.bindings);if(await si(q),It.current!==F)return;let _=new Map,{parkedModels:ge,mergedModelSources:le}=await sm(u.parkedFiles,u.mergeFiles,_);if(It.current!==F){ge.forEach(da),le.forEach(Eo);return}let Le=Pe=>{let yt=new Map;yt.set(on(N),Pe),ge.forEach(Jt=>{Jt.sessionModel&&yt.set(on(Jt.sessionModel),Jt.url)});let Yt=(m.modelOrder??[]).map(Jt=>yt.get(Jt)).filter(Jt=>!!Jt),ll=new Set(Yt);for(let Jt of[Pe,...ge.map(pm=>pm.url)])ll.has(Jt)||(Yt.push(Jt),ll.add(Jt));return Yt},Pt=()=>{for(let[Pe,yt]of _)pn.current.set(Pe,yt),s?Oa.current.delete(Pe):Oa.current.add(Pe)},je;if(N.kind==="file"){if(!T){ge.forEach(da),le.forEach(Eo);return}let Pe=It.current,yt;try{yt=await Bn(T)}catch(Yt){console.warn("[BindingBuilder] Could not read the saved model:",Yt),J(sb(N.name)),te("error"),ge.forEach(da),le.forEach(Eo);return}if(It.current!==Pe){yt.cleanup(),ge.forEach(da),le.forEach(Eo);return}ut.current?.cleanup(),ut.current=yt,je=yt.url,_.set(N.key,T),Pt(),hi(),p.forEach(Yt=>Yt.resolved?.cleanup()),r(ge),Sn(le),j(Le(je)),Xe.reset(m.composition?Yn(m.composition):Wn),co([])}else{je=N.url,Pt(),hi(),p.forEach(yt=>yt.resolved?.cleanup()),r(ge),Sn(le),j(Le(je)),Xe.reset(m.composition?Yn(m.composition):Wn),co([]);let Pe=bn.current;if(je===k&&Pe?.url===je&&!Mt.current){st.current={model:N},ie.reset(ro(Pe.scene,U,le,ca(Pe.scene,U).bindings)),He.reset(q),J(`Restored your last session with ${N.name}.`),te("success");return}ut.current?.cleanup(),ut.current=null}st.current={model:N,file:T??void 0},N.kind==="file"&&!s&&Oa.current.add(N.key);let Wt=++It.current;je!==k&&_t.clearAnimations(),dn(!0),Un(null),Gn.current=0,rt.current&&(clearTimeout(rt.current),rt.current=null),Aa.current=T?.size,J(`Restoring your last session with ${N.name}...`),te("default"),E(N.name),pe({url:je,name:N.name}),go(null),Q(null),bn.current=null,ie.reset({}),He.reset(q),Mt.current={requestId:Wt,modelName:N.name,modelUrl:je,storedBindings:U,restoring:!0},O(je)};if(Uo.status==="checking")return V("div",{className:"bb-root bb-root--licenseChecking",children:!B&&V(Ui,{title:"Verifying License",message:"Checking your license key..."})});if(Uo.status==="invalid")return V("div",{className:"bb-root bb-root--licenseInvalid",children:V(Ui,{tone:"error",title:"Invalid License",message:Uo.isLocalDomain?Uo.reason??"License has been revoked or has expired":"Failed to load. Please contact the site administrator."})});let La=Cn==="Assets",za=La?Xe:He,rl=[{title:"Scene settings",description:"Lighting, camera, environment and the active model's scene settings. No model files or object bindings.",onImport:Eu,onExportJson:()=>el("json"),onExportTs:()=>el("ts"),importDisabled:!tn.length||Ie,exportDisabled:!tn.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:Ou,onExportJson:()=>Qs("json"),onExportTs:()=>Qs("ts"),importDisabled:!tn.length||Ie,exportDisabled:!tn.length||Ie}],sl=g&<(fo,"sceneBundle")?{onImport:()=>Ts.current?.click(),onExport:cm,importDisabled:Ie,exportDisabled:Ie||!$e.length||$e.some(s=>!s.ready)}:void 0,Hi=it?V($n,{children:"Click the preview to look around \xB7 Esc to release"}):gi?V($n,{children:"Select a mesh \xB7 drag the colored arrows, planes, or rings"}):zb&&pi?Te($n,{children:[Te("span",{children:[V("kbd",{children:"W"}),V("kbd",{children:"A"}),V("kbd",{children:"S"}),V("kbd",{children:"D"})," move"]}),Te("span",{children:["\xB7 ",V("kbd",{children:"Space"}),"/",V("kbd",{children:"C"})," up \xB7 down"]}),V("span",{children:"\xB7 drag to look"})]}):null;return Te(Vl.Provider,{value:qb,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(),X())},children:[V("input",{ref:v,type:"file",accept:qi,className:"bb-hiddenInput",onChange:hu,disabled:Ie}),V("input",{ref:P,type:"file",accept:qi,className:"bb-hiddenInput",onChange:Cu,disabled:Ie}),V("input",{ref:C,type:"file",accept:".json,application/json",className:"bb-hiddenInput",onChange:ju,disabled:Ie}),V("input",{ref:S,type:"file",accept:".json,application/json",className:"bb-hiddenInput",onChange:Iu,disabled:Ie}),V("input",{ref:Ts,type:"file",accept:".zip,application/zip",hidden:!0,onChange:async s=>{let u=s.target.files?.[0];s.target.value="",u&&await al(u)}}),Te("aside",{className:`bb-sidebar bb-sidebar--left ${so?"bb-sidebar--collapsed":""}`,children:[Te("div",{className:"bb-header bb-header--sidebar",children:[!so&&V("h1",{className:"bb-title",children:"Binding Builder"}),V("button",{type:"button",className:"bb-sidebarToggle",onClick:()=>bs(s=>!s),"aria-label":so?"Open editor sidebar":"Collapse editor sidebar",title:so?"Open editor":"Collapse editor",children:so?"\u2192":"\u2190"})]}),!so&&Te($n,{children:[Te("div",{className:"bb-tabRow",children:[V("button",{type:"button",className:`bb-tab ${cn==="object"?"bb-tab--active":""}`,onClick:()=>Ho("object"),children:"Object"}),V("button",{type:"button",className:`bb-tab ${cn==="scene"?"bb-tab--active":""}`,onClick:()=>Ho("scene"),children:"Scene"})]}),V("section",{className:"bb-editor",children:cn==="scene"?V($n,{children:k?V(Or,{assets:g?{assets:$e,activeUrl:k,composition:Ct,busy:po||Ie,onFrameAll:()=>{let s=new ib;for(let m of $e){if(m.placement.visible===!1)continue;let T=Dt.current.get(m.url);T&&(T.updateWorldMatrix(!0,!0),s.union(new ib().setFromObject(T)))}let u=xo.current;!s.isEmpty()&&u&&(Ql(s,u.raw.controls),u.raw.controls.fitToBox(s,!0,ed).then(()=>u.invalidate()))},onSelect:vo,onAdd:Zs,addRequiresTier:Ls?void 0:un("models",$e.length),onChange:Fi,onGridSize:s=>Xe.setValue(u=>({...u,gridSize:s})),onDuplicate:s=>{lm(s)},onDelete:l?()=>lo(!0):dm,deleteIsPermanent:!!l,onSnap:s=>Fi(s,Ml(Ct.placements[s]??{},Ct.gridSize)),onGround:s=>{let u=Dt.current.get(s),m=u?Tl(u):null;m&&Fi(Nn.get(s),Nl(Go(s),m))}}:void 0,diagnostics:{report:zs?.url===k?zs.report:null,runtimeStats:Gb,onRefresh:_b,onSelectObject:s=>{let u=Object.keys(Z).find(m=>m===s||Z[m].modelObjectId===s);u&&Li(u)}},onDiagnosticsOpenChange:Kb,config:Re,onChange:Vo,activeSubTab:Cn,onActiveSubTabChange:li,cameraState:(Cn==="Cinematic"||Cn==="Annotations")&&Ve?{position:Ve.position,target:Ve.target,azimuthAngle:Ve.azimuthAngle,polarAngle:Ve.polarAngle,fov:Ve.fov,zoom:Ve.zoom}:null,onPreviewWaypoint:nu,sequenceControls:Jb,sequenceClipDetails:_t.clipDetails,animationClipDetails:yo.clipDetails,animationConfig:Gs.config,onAnimationConfigChange:Gs.onChange,animationPlayback:yo,materialVariantGroups:Wb,onImageFile:nl,objectBindings:Z}):V("div",{className:"bb-emptyEditor",children:"Upload a model to edit its scene settings."})}):!De||!I?V("div",{className:"bb-emptyEditor",children:"Select a generated node binding to edit its values."}):Te($n,{children:[Te("div",{className:"bb-editorHeader",children:[Te("div",{children:[V("div",{className:"bb-sectionKicker",children:"Editing Binding"}),V("h2",{className:"bb-editorTitle",children:me&&oe.length>1?`${oe.length} objects selected`:De.label||I}),V("div",{className:"bb-editorMeta",children:me?V("span",{children:"Changes apply to every selected object"}):Te($n,{children:[V("span",{children:De.type}),V("span",{children:De.modelObjectId})]})})]}),(()=>{let s=me&&oe.length>0?oe:[I],u=s.length>1?`Delete ${s.length} selected objects`:"Delete this object";return V("button",{type:"button",className:"bb-editorDeleteButton",onClick:()=>nm(s),title:u,"aria-label":u,children:V(cx,{size:18})})})()]}),Te("div",{className:"bb-styleClipboard",children:[Te("div",{className:"bb-styleClipboardActions",children:[V("button",{type:"button",className:"bb-button bb-button--ghost",onClick:()=>ma({name:De.label||I,style:dd(De)}),children:"Copy style"}),Te("button",{type:"button",className:"bb-button bb-button--ghost",disabled:!Ue,onClick:()=>{if(!Ue)return;let s=me?oe:[I];ie.setValueAsStep(u=>cd(u,s,Ue.style))},children:["Paste style",me&&oe.length>1?` (${oe.length})`:""]})]}),Ue&&Te("p",{children:["Copied from ",Ue.name]}),me&&oe.length>1&&Te("p",{children:["Values shown for"," ",De.label||I,". Edits apply to all selected objects."]})]}),!me&&V(Zc,{selectedItem:I,selectedBinding:De,open:Qt.identity,onToggle:()=>en("identity"),updateBinding:Lt,idError:du}),!me&&V(ep,{selectedItem:I,selectedBinding:De,open:Qt.basics,onToggle:()=>en("basics"),updateBinding:Lt}),me&&V(ot,{title:"Basics",open:Qt.basics,onToggle:()=>en("basics"),children:V("div",{className:"bb-groupFlags",children:["selectable","hoverable","visible"].map(s=>V(px,{label:s,values:oe.map(u=>Z[u]).filter(u=>u&&!u.removed).map(u=>u[s]!==!1),onChange:u=>ie.setValueAsStep(m=>{let T={...m};for(let N of oe)m[N]&&!m[N].removed&&(T[N]={...m[N],[s]:u});return T})},s))})}),Te(ot,{title:"Material",open:Qt.material,onToggle:()=>en("material"),tooltip:"Edit the selected object's base material, textures, and surface properties.",children:[V(Xc,{disabled:!I,onApply:s=>I&&ji(I,u=>({...u,...s}))}),V(Yc,{selectedItem:I,selectedMaterial:Bi,pbrWorkflow:Sb,onPbrWorkflowChange:wb,openMaterialPanels:hb,materialPanelEnabled:Cb,onToggleMaterialPanel:yb,onSetMaterialPanelState:pu,updateSelectedMaterial:ji,setSelectedTexturePath:cu,isTexturePositioningEnabled:Hb,onConfirmTexturePosition:em,takesImage:_s})]}),!me&&V(ip,{selectedItem:I,selectedBinding:De,open:Qt.decals,onToggle:()=>en("decals"),updateBinding:Lt,placement:ha,onPlacementChange:qu,defaultSize:Hu,onImageFile:nl,onNudge:Vu}),!me&&V(np,{selectedItem:I,selectedBinding:De,open:Qt.actions,onToggle:()=>en("actions"),updateBinding:Lt,takesImage:_s}),!me&&V(rp,{selectedBinding:De,open:Qt.camera,onToggle:()=>en("camera"),cameraState:Ve,formattedCameraState:iu,savedCameraPosition:Tn,onSaveCameraPosition:Yu,onGoToSavedCamera:Ju,onClearSavedCamera:Xu,onResetView:Zu,onFitScene:Qu}),V(cp,{selectedItem:I,selectedBinding:De,open:Qt.transform,onToggle:()=>en("transform"),updateBinding:Lt,moveModeEnabled:gi,onToggleMoveMode:ws,scaleModeEnabled:Cs,onToggleScaleMode:ks,transformSpace:Ms,onTransformSpaceChange:Rb,originalTransform:Et.current[I]??null,originalTransforms:Et.current}),V(qr,{title:"Metrics",label:"Metrics JSON",open:Qt.metrics,onToggle:()=>en("metrics"),draft:cs,error:bb,example:'{"area": 42}',onDraftChange:ya,onCommit:()=>tl("metrics",cs,Sa)}),V(qr,{title:"Metadata",label:"Metadata JSON",open:Qt.metadata,onToggle:()=>en("metadata"),draft:ps,error:ub,example:'{"room": "kitchen"}',onDraftChange:va,onCommit:()=>tl("metadata",ps,wa)})]})}),cn==="object"&&V(Qr,{canUndo:ie.canUndo,canRedo:ie.canRedo,onUndo:ie.undo,onRedo:ie.redo,onReset:()=>ol("bindings"),resetDisabled:!tn.length,resetTitle:"Reset object bindings to default",fileScopes:rl,sceneBundle:sl,busy:po||ls}),cn==="scene"&&V(Qr,{canUndo:za.canUndo,canRedo:za.canRedo,onUndo:za.undo,onRedo:za.redo,onReset:()=>ol(La?"assets":"scene"),resetTitle:La?"Reset asset placements to default":"Reset scene config to default",resetDisabled:La&&(!$e.length||Ie),fileScopes:rl,sceneBundle:sl,busy:po||ls})]})]}),Te("main",{className:"bb-previewShell",children:[Te("div",{className:"bb-previewHeader",children:[V(dr,{label:"View",icon:V(lx,{size:14,"aria-hidden":"true"}),title:"Preview options",children:()=>Te($n,{children:[Te("label",{className:"bb-headerMenuItem",children:[V("input",{type:"checkbox",checked:ys,onChange:s=>kb(s.target.checked)}),"Zoom on selected"]}),Te("label",{className:"bb-headerMenuItem",children:[V("input",{type:"checkbox",checked:ci,onChange:s=>Mb(s.target.checked)}),"Highlight on hover"]}),Te("label",{className:"bb-headerMenuItem",children:[V("input",{type:"checkbox",checked:pi,onChange:s=>Nb(s.target.checked)}),"Camera controller"]})]})}),V("div",{className:"bb-previewMeta",children:V("span",{title:I??void 0,children:I?`Focused: ${I}`:"Select a node to inspect it"})}),k&&Te("button",{type:"button",className:`bb-compareButton ${Mn?"bb-compareButton--active":""}`,onClick:()=>{jb(s=>!s),yi(null)},"aria-pressed":Mn,title:"Compare: drag a divider across the preview to see it before and after your changes",children:[V(dx,{size:14}),"Compare"]}),g&&V(dr,{icon:V(ix,{size:16,"aria-hidden":"true"}),title:"More model actions",align:"right",children:s=>V(Ad,{close:s,onRestore:k||l?void 0:rm,restoreDisabled:Ie,onAddModel:k?Zs:void 0,addModelDisabled:Ie,onRemove:k&&(!l||_o.length>1)?xu:void 0,confirmRemove:_o.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)||ki()},children:[V(Kl,{visible:Ie||pb,message:ds,tone:xa,progress:db??void 0}),k&&V("div",{className:`bb-canvasHint ${Hi?"bb-canvasHint--visible":""} ${Mn?"bb-canvasHint--belowCompare":""}`,"aria-hidden":!Hi,children:Hi}),k?V(Xi,{loading:"eager",enableXR:!0,arHandoff:a,mobileHandoffUrl:i,modelUrl:k,tilesetUrl:ke?.tilesetUrl,models:Ws,onModelChange:vo,onExtraModelLoaded:Au,onExtraModelError:Ru,mergeModels:Ri,onMergeModelLoaded:Pu,onMergeModelError:Bu,originalNodePoses:Et.current,objectBindings:Z,comparisonHighlights:Ps?.after,selectedObject:De,selectedObjectRefs:Qb,selectedObjectOutlineColor:"#22c55e",onObjectSelect:Gu,onSelectionClear:X,onObjectBindingsChange:qn,onTextureUpload:lu,onObjectEditLeaseChange:(s,u)=>b?.(`${k}|${s.modelObjectId||s.id}`,u),showObjectBindingDataPanel:!1,showSceneObjectsPanel:!1,onCameraChange:eu,onViewerReady:s=>{xo.current=s,Zb(s.raw.nodes),tu(s)},onAnnotationsChange:ru,activeAnnotation:$b?.annotation??null,onActiveAnnotationChange:su,onSequencesReady:Xb,showSequenceControls:!1,sequenceAutoPlay:!1,onAnimationsReady:fu,onModelAnimationsReady:yo.handleModelAnimationsReady,onSceneLoaded:bu,onAssetDiagnostics:Pi?s=>Fs({url:k,report:s}):void 0,onRuntimeStats:Pi?Hs:void 0,onLoadError:mu,onObjectCatalog:ke?.tilesetUrl?uu:void 0,onProgress:gu,onCameraControllerChange:wi,cameraControllerType:Bs,onTexturePositioningChange:Fb,endTexturePositioningRef:Os,licenseKey:e,licenseValidationUrl:t,dracoDecoderPath:n,ktx2TranscoderPath:o,meshopt:d,sceneConfig:Re,onSceneConfigChange:Vo,preserveDrawingBuffer:!0,disableZoom:!1,zoomOnSelected:ys,highlightOnHover:ci,enableCameraControls:pi,moveModeEnabled:gi,scaleModeEnabled:Cs,objectTransformSpace:Ms,enableKeyboardNavigation:!0,showViewGizmo:!0,showMeasureTools:!0,measurementModelId:st.current?.model.kind==="file"?on(st.current.model):void 0,showSectionTools:Re.section?.enabled??!1,isolation:lb,onIsolationChange:()=>Lo(null),showIsolateControls:!0,decalMove:$u,onDecalDoubleClick:Uu,panelHoveredObject:ci?Vb:null,showLoadingOverlay:!1,autoRotate:it?!1:Re.model.autoRotate??!1,autoRotateSpeed:Re.model.autoRotateSpeed??1}):V("div",{className:`bb-previewPlaceholder ${mb?"bb-previewPlaceholder--dragActive":""}`,onDragEnter:Du,onDragOver:Lu,onDragLeave:zu,onDrop:Fu,children:Te("div",{children:[V("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?V("button",{type:"button",className:"bb-previewPlaceholderButton",onClick:wu,disabled:Ie,children:"Upload"}):null]})}),k&&Mn?V(Ed,{showOutlines:xi,onShowOutlinesChange:Db,matchBy:vi,onMatchByChange:s=>{Lb(s),Si(null)},report:qo??void 0,selected:Na,onSelect:s=>{Si(s?.id??null),s?.afterKey&&Li(s.afterKey)},liveViewerRef:xo,split:Eb,onSplitChange:Ib,labels:[uo?"Pinned":"Before","Now"],beforeAction:Te("button",{type:"button",className:"ri-compare__labelAction",onClick:()=>yi(s=>s?null:{bindings:Z,sceneConfig:Re}),"aria-pressed":!!uo,title:uo?"Unpin: compare with the project as it was opened again":"Pin as before: compare later changes with how the preview looks now",children:[uo?V(sx,{size:12}):V(rx,{size:12}),uo?"Unpin":"Pin"]}),renderBefore:s=>V(Xi,{loading:"eager",modelUrl:k,tilesetUrl:ke?.tilesetUrl,comparisonHighlights:Ps?.before,objectBindings:mo.bindings,sceneConfig:{...mo.sceneConfig,section:Re.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]})]}),V(gp,{bindings:Z,selectedItem:I,onSelect:Li,onHover:_u,isOpen:!gb,onToggle:Wu,modelGroups:au,onSelectModel:vo,isolatedItem:fa,onIsolate:Lo,multiSelectEnabled:G,onToggleMultiSelect:Do,onExitMultiSelect:A,multiSelectedKeys:oe,onSetMultiSelected:Ku,hierarchy:Yb,selectionSets:Re.selectionSets,onSelectionSetsChange:Ab})]}),Tb&&V($p,{target:$o,onCancel:Da,onConfirm:tm}),Kn&&V(Vp,{modelNames:[Kn.session.model.name,...(Kn.session.parkedModels??[]).map(s=>s.model.name)],mergedSourceCount:(Kn.session.mergeModels?.length??0)+(Kn.session.parkedModels??[]).reduce((s,u)=>s+(u.mergeModels?.length??0),0),savedAt:Kn.session.savedAt,onCancel:im,onConfirm:()=>{il()}}),Pb&&V(Up,{destinations:_o.filter(s=>s.kind==="model"),onCancel:ku,onChoose:Mu}),Bb&&V(Kp,{options:_o,onCancel:yu,onRemoveModel:vu,onRemoveMerge:Su,permanent:!!l,onRemoveAll:l?void 0:()=>{lo(!1),Ia()}}),kn&&V(qp,{nodeLabel:kn.length===1?Z[kn[0]]?.label||kn[0]:`${kn.length} objects`,count:kn.length,onCancel:om,onConfirm:am})]})}export{Ja as a,Px as b,bx as c};
|