@liveroom-tech/react-immersive 5.3.0 → 6.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/binding-builder.css +1 -1
- package/dist/binding-builder.d.mts +5 -1
- package/dist/binding-builder.d.ts +5 -1
- package/dist/binding-builder.js +23 -20
- package/dist/binding-builder.mjs +1 -1
- package/dist/chunk-2JFUMJUP.mjs +1 -0
- package/dist/chunk-4JMJALRO.mjs +2 -0
- package/dist/chunk-OTSCPJWF.mjs +1 -0
- package/dist/chunk-P2JZ5Z7I.mjs +1 -0
- package/dist/chunk-UGPR4EPP.mjs +81 -0
- package/dist/chunk-V7WZUWJ5.mjs +1 -0
- package/dist/chunk-WWUWEPFK.mjs +3 -0
- package/dist/hosted.css +1 -1
- package/dist/hosted.d.mts +44 -17
- package/dist/hosted.d.ts +44 -17
- package/dist/hosted.js +22 -19
- package/dist/hosted.mjs +1 -1
- package/dist/index.css +1 -1
- package/dist/index.d.mts +70 -12
- package/dist/index.d.ts +70 -12
- package/dist/index.js +21 -18
- package/dist/index.mjs +1 -1
- package/dist/{materialVariants-DjTuiWmN.d.mts → modelFileResolver-Co7j1tdQ.d.mts} +122 -29
- package/dist/{materialVariants-DjTuiWmN.d.ts → modelFileResolver-Co7j1tdQ.d.ts} +122 -29
- package/dist/modelViewerProps-BibuMND7.d.ts +1988 -0
- package/dist/modelViewerProps-Ce4-wb57.d.mts +1988 -0
- package/dist/{publicProps-tJuWZgT3.d.ts → publicProps-BaJHCDa_.d.mts} +7 -0
- package/dist/{publicProps-tJuWZgT3.d.mts → publicProps-CP18d_mt.d.ts} +7 -0
- package/dist/simple-model-viewer.d.mts +2 -4
- package/dist/simple-model-viewer.d.ts +2 -4
- package/dist/simple-model-viewer.js +3 -3
- package/dist/simple-model-viewer.mjs +1 -1
- package/dist/utils.d.mts +62 -4
- package/dist/utils.d.ts +62 -4
- package/dist/utils.js +2 -1
- package/dist/utils.mjs +1 -1
- package/package.json +1 -1
- package/dist/chunk-4FDMYUGT.mjs +0 -3
- package/dist/chunk-CV4E7DOO.mjs +0 -79
- package/dist/chunk-F4WT3HEK.mjs +0 -1
- package/dist/chunk-FPJZDEON.mjs +0 -1
- package/dist/chunk-JHKMRMJH.mjs +0 -1
- package/dist/chunk-TW2M4UXT.mjs +0 -1
- package/dist/chunk-W24UP6NM.mjs +0 -1
- package/dist/modelInfo-BQ5UZu95.d.ts +0 -43
- package/dist/modelInfo-CcYpydB7.d.mts +0 -43
- package/dist/modelViewerProps-BalkRDni.d.ts +0 -618
- package/dist/modelViewerProps-DdsJDRB7.d.mts +0 -618
- package/dist/rendererBackend-C_Jb4_Jy.d.mts +0 -917
- package/dist/rendererBackend-C_Jb4_Jy.d.ts +0 -917
package/package.json
CHANGED
package/dist/chunk-4FDMYUGT.mjs
DELETED
|
@@ -1,3 +0,0 @@
|
|
|
1
|
-
import{A as Dr,C as jr,D as zr,a as fa,c as No,e as ir,f as Bo,g as sr,h as tn,i as In,j as Ro,k as lr,l as yr,m as wr,n as wa,o as Sa,p as Sr,q as Cr,r as kr,s as Nr,t as yt,u as Rr,v as Ar,w as Or,x as Lr,y as Er,z as ka}from"./chunk-CV4E7DOO.mjs";import{Q as Oo,R as Tr,v as ha,x as en,y as or}from"./chunk-F4WT3HEK.mjs";import{D as Pr,G as $n,I as Lo,J as Br,K as Ir,L as Fr,a as xa,b as To,c as Po,e as va,f as ar,h as dr,i as cr,j as br,k as pr,l as ur,m as mr,n as Fn,o as gr,p as fr,q as vn,r as Ao,v as Hn,w as Ca,y as Mr}from"./chunk-W24UP6NM.mjs";import{A as vr,B as ya,h as rr,w as hr,x as xr}from"./chunk-JHKMRMJH.mjs";import{useCallback as W,useEffect as _e,useMemo as it,useRef as le,useState as K}from"react";import{Vector3 as gm}from"three";import{Ellipsis as fm,Pin as hm,PinOff as xm,SlidersHorizontal as vm,SquareSplitHorizontal as ym,Trash2 as wm}from"lucide-react";import{useEffect as tb,useId as nb,useRef as Hr,useState as $r}from"react";import{ChevronDown as ob,History as ab,Plus as ib,Trash2 as rb}from"lucide-react";import{Fragment as Ur,jsx as Ht,jsxs as Ot}from"react/jsx-runtime";function Ma({label:e,icon:n,title:i,align:r="left",children:t}){let[o,d]=$r(!1),l=Hr(null),b=Hr(null),k=nb();return tb(()=>{if(!o)return;let M=p=>{l.current?.contains(p.target)||d(!1)},w=p=>{p.key==="Escape"&&(d(!1),b.current?.focus())};return window.addEventListener("pointerdown",M),window.addEventListener("keydown",w),()=>{window.removeEventListener("pointerdown",M),window.removeEventListener("keydown",w)}},[o]),Ot("div",{className:"bb-headerMenuWrapper",ref:l,children:[Ot("button",{ref:b,type:"button",className:`bb-headerButton ${e?"":"bb-headerButton--icon"} ${o?"bb-headerButton--open":""}`,onClick:()=>d(M=>!M),title:i,"aria-label":e?void 0:i,"aria-expanded":o,"aria-controls":o?k:void 0,children:[n,e?Ot(Ur,{children:[e,Ht(ob,{size:12,"aria-hidden":"true"})]}):null]}),o?Ht("div",{id:k,className:`bb-headerMenu bb-headerMenu--${r}`,role:"group","aria-label":i,children:t(()=>d(!1))}):null]})}function Vr({onRestore:e,onRemove:n,onAddModel:i,restoreDisabled:r,addModelDisabled:t,confirmRemove:o=!0,close:d}){let[l,b]=$r(!1);return l&&n?Ot("div",{className:"bb-headerMenuConfirm",role:"alertdialog","aria-label":"Remove model",children:[Ht("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."}),Ot("div",{className:"bb-headerMenuConfirmActions",children:[Ht("button",{type:"button",className:"bb-headerMenuItem",onClick:()=>b(!1),children:"Cancel"}),Ht("button",{type:"button",className:"bb-headerMenuItem bb-headerMenuItem--danger",onClick:()=>{d(),n()},autoFocus:!0,children:"Remove"})]})]}):Ot(Ur,{children:[i?Ot("button",{type:"button",className:"bb-headerMenuItem",disabled:t,onClick:()=>{d(),i()},title:"Add another model, as a separate model or merged into this one",children:[Ht(ib,{size:14,"aria-hidden":"true"}),"Add model\u2026"]}):null,e?Ot("button",{type:"button",className:"bb-headerMenuItem",disabled:r,onClick:()=>{d(),e()},title:"Restore your last session: the model, its object bindings, and scene settings saved in this browser",children:[Ht(ab,{size:14,"aria-hidden":"true"}),"Restore last session"]}):null,n?Ot("button",{type:"button",className:"bb-headerMenuItem bb-headerMenuItem--danger",onClick:()=>{if(o){b(!0);return}d(),n()},children:[Ht(rb,{size:14,"aria-hidden":"true"}),"Remove model\u2026"]}):null]})}import{useCallback as sb,useEffect as lb,useMemo as db,useRef as cb}from"react";import{jsx as Gr,jsxs as bb}from"react/jsx-runtime";function _r({liveViewerRef:e,renderBefore:n,split:i,onSplitChange:r,labels:t,beforeAction:o}){let d=cb(null),l=db(()=>Dr(),[]);lb(()=>()=>l.detach(),[l]);let b=sb(k=>{let M=e.current;M&&l.attach(0,M.raw.controls,M.invalidate),l.attach(1,k.raw.controls,k.invalidate)},[l,e]);return bb("div",{ref:d,className:"ri-compare ri-compare--overlay",style:{"--ri-compare-split":`${i*100}%`},children:[Gr("div",{className:"ri-compare__layer ri-compare__layer--before",children:n(b)}),Gr(jr,{split:i,onSplitChange:r,labels:t,containerRef:d,beforeAction:o})]})}import{useCallback as Lt,useEffect as Kr,useMemo as Wr,useRef as Eo,useState as Yr}from"react";var pb={currentClip:null,isPlaying:!1,speed:1,time:0,duration:0,active:[]};function ub(e,n){let i=[],r=new Map,t=new Map,o=new Map,d=new Set;for(let l of e){let b=n.get(l);if(!b)continue;let k=b.clipDetails??b.clips.map(w=>({sourceName:w,duration:0}));o.set(l,k);let M=new Map;for(let w of k){let p=w.sourceName;for(let h=2;d.has(p);h+=1)p=`${w.sourceName} (${h})`;d.add(p),i.push({sourceName:p,duration:w.duration}),r.set(p,{url:l,sourceName:w.sourceName}),M.set(w.sourceName,p)}t.set(l,M)}return{clipDetails:i,targets:r,displayNamesByUrl:t,clipDetailsByUrl:o}}function mb(e,n,i){let r=[];for(let t of e){let o=n.get(t),d=i.get(t);if(!(!o||!d))for(let l of o.active){let b=d.get(l.clip);b&&r.push({...l,clip:b})}}return r}function qr(e){let n=Eo(new Map),i=Eo(new Map),r=Eo(new Map),[t,o]=Yr(0),[d,l]=Yr(0),b=Lt((a,u)=>{if(n.current.get(a)===u)return;r.current.get(a)?.(),r.current.delete(a),n.current.set(a,u),i.current.set(a,u.getState?.()??pb);let L=u.subscribe?.(P=>{i.current.set(a,P),l(H=>H+1)});L&&r.current.set(a,L),o(P=>P+1)},[]);Kr(()=>{let a=new Set(e),u=!1;for(let L of[...n.current.keys()])a.has(L)||(r.current.get(L)?.(),r.current.delete(L),n.current.delete(L),i.current.delete(L),u=!0);u&&o(L=>L+1)},[e]),Kr(()=>()=>r.current.forEach(a=>a()),[]);let{clipDetails:k,targets:M,displayNamesByUrl:w,clipDetailsByUrl:p,hasModels:h}=Wr(()=>({...ub(e,n.current),hasModels:n.current.size>0}),[e,t]),S=Eo(M);S.current=M;let C=Wr(()=>mb(e,i.current,w),[e,w,d]),g=Lt((a,u,L)=>{L(),!u.subscribe&&u.getState&&(i.current.set(a,u.getState()),l(P=>P+1))},[]),c=Lt(a=>{n.current.forEach((u,L)=>g(L,u,()=>a(u,L)))},[g]),f=Lt((a,u)=>{let L=S.current.get(a);if(!L)return;let P=n.current.get(L.url);P&&g(L.url,P,()=>u(P,L))},[g]),x=Lt((a,u)=>f(a,(L,P)=>L.play(P.sourceName,u)),[f]),N=Lt(a=>a===void 0?c(u=>u.pause()):f(a,(u,L)=>u.pause(L.sourceName)),[c,f]),O=Lt(a=>a===void 0?c(u=>u.stop()):f(a,(u,L)=>u.stop(L.sourceName)),[c,f]),T=Lt((a,u)=>u===void 0?c(L=>L.setSpeed(a)):f(u,(L,P)=>L.setSpeed(a,P.sourceName)),[c,f]),B=Lt((a,u)=>u===void 0?c(L=>L.seek?.(a)):f(u,(L,P)=>L.seek?.(a,P.sourceName)),[c,f]);return{clipDetails:k,clipDetailsByUrl:p,displayNamesByUrl:w,hasModels:h,active:C,play:x,pause:N,stop:O,setSpeed:T,seek:B,handleModelAnimationsReady:b}}import{useEffect as xb,useMemo as vb}from"react";function Do(e){return{annotations:e.annotations,animations:e.animations,activeVariants:e.model.activeVariants}}function wt(e,n){return{...e,model:{...e.model,activeVariants:n?.activeVariants??[]},annotations:n?.annotations??[],animations:n?.animations??vn.animations}}function Vn(e,n){let i=new Map(e.animations.clips.map(o=>[o.sourceName,o])),r=n.map(({sourceName:o})=>i.get(o)??{sourceName:o,displayName:o,hidden:!1,loopMode:"repeat",speed:1}),t=e.animations.autoplayClip&&r.some(o=>o.sourceName===e.animations.autoplayClip&&!o.hidden)?e.animations.autoplayClip:null;return t===e.animations.autoplayClip&&r.length===e.animations.clips.length&&r.every((o,d)=>o===e.animations.clips[d])?e.animations:{clips:r,autoplayClip:t}}function jo(e){return e!==null&&typeof e=="object"&&!Array.isArray(e)}function Un(e,n){if(!jo(e)||!jo(n))return n??e;let i={...e};for(let[r,t]of Object.entries(n)){let o=i[r];i[r]=jo(o)&&jo(t)?Un(o,t):t}return i}import{useCallback as $t,useReducer as gb,useRef as fb}from"react";var hb=100;function Vt(e,n){switch(n.type){case"history":return n.updater(e);case"set":{let i=typeof n.updater=="function"?n.updater(e.present):n.updater;if(i===e.present)return e;let r=n.track?e.edits+1:e.edits,t=!n.track&&e.edits===0?i:e.baseline;return n.track?n.coalesce?{...e,present:i,future:[],edits:r,baseline:t}:{past:[...e.past,e.present].slice(-hb),present:i,future:[],edits:r,baseline:t}:{...e,present:i,baseline:t}}case"undo":{if(e.past.length===0)return e;let i=e.past[e.past.length-1];return{...e,past:e.past.slice(0,-1),present:i,future:[e.present,...e.future],edits:e.edits+1}}case"redo":{if(e.future.length===0)return e;let[i,...r]=e.future;return{...e,past:[...e.past,e.present],present:i,future:r,edits:e.edits+1}}case"reset":return{past:[],present:n.value,future:[],edits:n.track?e.edits+1:0,baseline:n.track?e.baseline:n.value}}}function zo(e,n=600){let[i,r]=gb(Vt,{past:[],present:e,future:[],edits:0,baseline:e}),t=fb(0),o=$t(h=>{let S=Date.now(),C=S-t.current<n;t.current=S,r({type:"set",updater:h,coalesce:C,track:!0})},[n]),d=$t(h=>{let S=Date.now()-t.current<n;r({type:"set",updater:h,coalesce:S,track:!1})},[n]),l=$t(h=>{t.current=0,r({type:"set",updater:h,coalesce:!1,track:!0})},[]),b=$t(h=>{r({type:"history",updater:h})},[]),k=$t(h=>{t.current=0,r({type:"history",updater:typeof h=="function"?h:()=>h})},[]),M=$t(()=>{t.current=0,r({type:"undo"})},[]),w=$t(()=>{t.current=0,r({type:"redo"})},[]),p=$t((h,S)=>{t.current=0,r({type:"reset",value:h,track:S?.asEdit??!1})},[]);return{value:i.present,setValue:o,setValueUntracked:d,setValueAsStep:l,updateHistory:b,restoreSnapshot:k,snapshot:i,undo:M,redo:w,reset:p,canUndo:i.past.length>0,canRedo:i.future.length>0,edits:i.edits,baseline:i.baseline}}function yb(e,n){return e.sourceName===n.sourceName&&e.displayName===n.displayName&&e.hidden===n.hidden&&e.loopMode===n.loopMode&&e.speed===n.speed}function Jr(e,n,i,r){let t=wt(n,e.modelSettings);if(t.animations===i)return e;let o={...t,animations:i},d=e.sceneHistory??{past:[],present:t,future:[],baseline:t,edits:0};return{...e,modelSettings:Do(o),sceneHistory:Vt(d,{type:"set",updater:o,track:r,coalesce:!1})}}function Xr({modelUrl:e,sceneConfig:n,setSceneConfig:i,setSceneConfigUntracked:r,parkedModels:t,setParkedModels:o,animations:d,markSessionEdited:l}){let{clipDetailsByUrl:b,displayNamesByUrl:k}=d;xb(()=>{let p=e?b.get(e):void 0;p&&r(h=>{let S=Vn(h,p);return S===h.animations?h:{...h,animations:S}}),o(h=>{let S=!1,C=h.map(g=>{let c=b.get(g.url);if(!c)return g;let f=wt(n,g.modelSettings),x=Jr(g,n,Vn(f,c),!1);return S||(S=x!==g),x});return S?C:h})},[b,e,n,r,o]);let M=vb(()=>{let p=[],h=null;for(let[S,C]of k){let g=S===e?n:wt(n,t.find(f=>f.url===S)?.modelSettings),c=Vn(g,b.get(S)??[]);for(let f of c.clips){let x=C.get(f.sourceName);x&&p.push({...f,sourceName:x,displayName:f.displayName===f.sourceName?x:f.displayName})}h??(h=c.autoplayClip?C.get(c.autoplayClip)??null:null)}return{clips:p,autoplayClip:h}},[k,b,e,n,t]);return{config:M,onChange:p=>{let h=new Map(M.clips.map(g=>[g.sourceName,g])),S=new Map(p.clips.map(g=>[g.sourceName,g])),C=(g,c)=>{let f=k.get(g);if(!f)return c.animations;let x=Vn(c,b.get(g)??[]),N=x.clips.map(T=>{let B=f.get(T.sourceName),a=B?S.get(B):void 0;if(!a)return T;let u={...a,sourceName:T.sourceName,displayName:a.displayName===h.get(B)?.displayName?T.displayName:a.displayName};return yb(T,u)?T:u}),O=p.autoplayClip===M.autoplayClip?x.autoplayClip:[...f].find(([,T])=>T===p.autoplayClip)?.[0]??null;return O===x.autoplayClip&&N.every((T,B)=>T===x.clips[B])?x:{clips:N,autoplayClip:O}};e&&i(g=>{let c=C(e,g);return c===g.animations?g:{...g,animations:c}}),o(g=>g.map(c=>Jr(c,n,C(c.url,wt(n,c.modelSettings)),!0))),l()}}}var wb="react-immersive:binding-builder";var Ut="session",Gt="model",_t="textures",Ta="current";function Gn(e){return e.kind==="file"?`file:${e.key}`:`url:${e.url}`}var nn=null;function _n(){return nn||(nn=new Promise((e,n)=>{if(typeof indexedDB>"u"){n(new Error("IndexedDB is not available in this environment."));return}let i=indexedDB.open(wb,2);i.onupgradeneeded=()=>{let r=i.result;r.objectStoreNames.contains(Ut)||r.createObjectStore(Ut),r.objectStoreNames.contains(Gt)||r.createObjectStore(Gt),r.objectStoreNames.contains(_t)||r.createObjectStore(_t)},i.onsuccess=()=>{let r=i.result;r.onversionchange=()=>{r.close(),nn=null},e(r)},i.onerror=()=>n(i.error??new Error("Failed to open IndexedDB."))}),nn.catch(()=>{nn=null}),nn)}function yn(e){return new Promise((n,i)=>{e.oncomplete=()=>n(),e.onerror=()=>i(e.error??new Error("IndexedDB transaction failed.")),e.onabort=()=>i(e.error??new Error("IndexedDB transaction aborted."))})}function Pa(e){return new Promise((n,i)=>{e.onsuccess=()=>n(e.result),e.onerror=()=>i(e.error??new Error("IndexedDB request failed."))})}function St(e){return e!==null&&typeof e=="object"&&!Array.isArray(e)}function Ba(e){return!St(e)||typeof e.name!="string"?!1:e.kind==="file"?typeof e.key=="string":e.kind==="url"?typeof e.url=="string":!1}function Qr(e){return St(e)&&Ba(e.model)&&typeof e.namePrefix=="string"}function Sb(e){return!St(e)||!Ba(e.model)||!St(e.bindings)||!St(e.originalTransforms)||e.modelSettings!==void 0&&(!St(e.modelSettings)||!Array.isArray(e.modelSettings.annotations)||!St(e.modelSettings.animations)||!Array.isArray(e.modelSettings.animations.clips)||e.modelSettings.activeVariants!==void 0&&(!Array.isArray(e.modelSettings.activeVariants)||!e.modelSettings.activeVariants.every(n=>typeof n=="string")))?!1:e.mergeModels===void 0?!0:Array.isArray(e.mergeModels)&&e.mergeModels.every(Qr)}function Cb(e){return!(!St(e)||e.version!==1||typeof e.savedAt!="number"||!St(e.bindings)||!St(e.sceneConfig)||!Ba(e.model)||e.parkedModels!==void 0&&(!Array.isArray(e.parkedModels)||!e.parkedModels.every(Sb))||e.mergeModels!==void 0&&(!Array.isArray(e.mergeModels)||!e.mergeModels.every(Qr))||e.modelOrder!==void 0&&(!Array.isArray(e.modelOrder)||!e.modelOrder.every(n=>typeof n=="string")))}function Na(e,n){return e.kind==="url"?Promise.resolve(null):Pa(n.get(e.key)).then(i=>!i||i.key!==e.key?null:new File([i.blob],i.name,{type:i.type,lastModified:i.lastModified}))}async function es(e,n){let i=await _n(),r={...e,version:1,savedAt:Date.now()},t=i.transaction([Ut,Gt],"readwrite"),o=yn(t);t.objectStore(Ut).put(r,Ta);let d=t.objectStore(Gt),l=new Set,b=M=>{M.kind==="file"&&l.add(M.key)};b(r.model),r.mergeModels?.forEach(M=>b(M.model)),r.parkedModels?.forEach(M=>{b(M.model),M.mergeModels?.forEach(w=>b(w.model))});for(let{key:M,file:w}of n??[]){let p={key:M,blob:w,name:w.name,type:w.type,lastModified:w.lastModified};d.put(p,M)}let k=d.getAllKeys();return k.onsuccess=()=>{for(let M of k.result)l.has(M)||d.delete(M)},await o,r}function Zr(e,n){return Promise.all(e.map(async i=>({entry:i,file:await Na(i.model,n)})))}async function ts(){let e=await _n(),n=e.transaction(Ut,"readonly"),i=yn(n),r=await Pa(n.objectStore(Ut).get(Ta));if(await i,!Cb(r))return null;let t=r.parkedModels??[],o=r.mergeModels??[],d=e.transaction(Gt,"readonly"),l=yn(d),b=d.objectStore(Gt),[k,M,w]=await Promise.all([Na(r.model,b),Zr(o,b),Promise.all(t.map(async p=>({entry:p,file:await Na(p.model,b),mergeFiles:await Zr(p.mergeModels??[],b)})))]);return await l,r.model.kind==="file"&&!k?null:{session:{...r,parkedModels:t,mergeModels:o},file:k,parkedFiles:w,mergeFiles:M}}async function ns(){let n=(await _n()).transaction([Ut,Gt,_t],"readwrite"),i=yn(n);n.objectStore(Ut).delete(Ta),n.objectStore(Gt).clear(),n.objectStore(_t).clear(),await i}async function Io(e,n){let r=(await _n()).transaction(_t,"readwrite"),t=yn(r),o={blob:n,name:n.name,type:n.type,savedAt:Date.now()};r.objectStore(_t).put(o,e),await t}async function Kn(e){let i=(await _n()).transaction(_t,"readonly"),r=yn(i),t=await Pa(i.objectStore(_t).get(e));return await r,t?new File([t.blob],t.name,{type:t.type,lastModified:t.savedAt}):null}import{useState as Ep,useEffect as Dp}from"react";import{useState as Lb}from"react";import{ChevronDown as Eb,ChevronLeft as Db,ChevronRight as jb,RotateCcw as zb}from"lucide-react";import{HexColorInput as Ib,HexColorPicker as Fb}from"react-colorful";import{useLayoutEffect as as,useRef as Ra,useState as Aa}from"react";import{createPortal as Mb}from"react-dom";import{ChevronDown as Nb,Info as Tb}from"lucide-react";import{HexColorInput as Pb,HexColorPicker as Bb}from"react-colorful";function Kt(e){let n=e.replace("#","").match(/.{2}/g).map(r=>parseInt(r,16)/255).map(r=>r<=.03928?r/12.92:Math.pow((r+.055)/1.055,2.4));return .2126*n[0]+.7152*n[1]+.0722*n[2]>.179?"#000":"#fff"}import{useEffect as kb}from"react";function os(e,n,i){kb(()=>{if(!i)return;let r=Array.isArray(e)?e:[e],t=o=>{let d=o.target;r.some(b=>b.current?.contains(d))||n()};return document.addEventListener("pointerdown",t,!0),()=>{document.removeEventListener("pointerdown",t,!0)}},[e,n,i])}import{jsx as ie,jsxs as Ge}from"react/jsx-runtime";function Wn({anchorRef:e,onClose:n,children:i}){let r=Ra(null),[t,o]=Aa(null);return os([r,e],n,!0),as(()=>{let d=e.current;if(!d)return;let l=d.getBoundingClientRect(),b=222,k=8,M=Math.min(Math.max(l.right-b,k),window.innerWidth-b-k),w=Math.min(l.bottom+6,window.innerHeight-200);o({top:w,left:M})},[e]),t?Mb(ie("div",{ref:r,className:"se-colorPickerPopover",style:{position:"fixed",top:t.top,left:t.left},children:i}),document.body):null}function Rb(e){return e.replace(/([a-z0-9])([A-Z])/g,"$1 $2").replace(/[_-]+/g," ").replace(/\s+/g," ").trim().replace(/\b\w/g,n=>n.toUpperCase())}function Et({title:e,children:n}){return Ge("section",{className:"se-section",children:[ie("h3",{className:"se-sectionTitle",children:e}),ie("div",{className:"se-sectionBody",children:n})]})}function re({title:e,open:n,onToggle:i,trailing:r,children:t,disabled:o,tooltip:d}){let l=d?`${d}`:e;return Ge("section",{className:"se-panel",children:[Ge("button",{type:"button",className:"se-panelHeader",onClick:i,"aria-expanded":n,title:l,children:[Ge("span",{className:"se-panelHeaderMain",children:[ie(Nb,{size:16,className:`se-panelChevron ${n?"se-panelChevron--open":""}`}),ie("span",{className:"se-panelTitle",children:e}),d?ie("span",{className:"se-panelHelp",title:l,"aria-label":l,role:"img",onClick:b=>b.stopPropagation(),children:ie(Tb,{size:13})}):null]}),r?ie("span",{className:"se-panelTrailing",onClick:b=>b.stopPropagation(),children:r}):null]}),n?ie("div",{className:"se-panelBody",style:o?{opacity:.45,pointerEvents:"none"}:void 0,children:t}):null]})}function ce({checked:e,onChange:n,label:i}){return Ge("label",{className:"se-switch","aria-label":i,children:[ie("input",{type:"checkbox",checked:e,onChange:r=>n(r.target.checked)}),ie("span",{className:"se-switchTrack",children:ie("span",{className:"se-switchThumb"})})]})}function A({label:e,value:n,min:i,max:r,step:t,formatValue:o,onChange:d,disabled:l=!1}){return Ge("label",{className:`se-field ${l?"se-field--disabled":""}`,children:[Ge("span",{className:"se-fieldLabel",children:[e,ie("span",{className:"se-fieldValue",children:o?o(n):n})]}),ie("input",{className:"se-slider",type:"range",min:i,max:r,step:t,value:n,onChange:b=>d(Number(b.target.value)),disabled:l})]})}function de({label:e,checked:n,onChange:i}){return Ge("label",{className:"se-field se-fieldInline",children:[ie("span",{className:"se-fieldLabel",children:e}),ie("input",{type:"checkbox",className:"se-checkbox",checked:n,onChange:r=>i(r.target.checked)})]})}function qe({label:e,value:n,options:i,onChange:r}){return Ge("label",{className:"se-field se-fieldInline",children:[ie("span",{className:"se-fieldLabel",children:e}),ie("select",{className:"se-select",value:n,onChange:t=>r(t.target.value),children:i.map(t=>ie("option",{value:t,children:Rb(t)},t))})]})}function Ye({label:e,value:n,onChange:i}){let[r,t]=Aa(!1),o=Ra(null);return Ge("div",{className:"se-field",children:[Ge("div",{className:"se-fieldInline",children:[ie("span",{className:"se-fieldLabel",children:e}),ie("span",{ref:o,style:{display:"inline-flex"},children:ie(Pb,{prefixed:!0,className:"se-swatch",onClick:()=>t(d=>!d),style:{background:n,color:Kt(n)},color:n,onChange:i})})]}),r?ie(Wn,{anchorRef:o,onClose:()=>t(!1),children:ie(Bb,{color:n,onChange:i})}):null]})}function is({value:e,min:n,max:i,step:r,onChange:t}){let[o,d]=Aa(String(e)),l=Ra(!1);return as(()=>{l.current||d(String(e))},[e]),ie("input",{type:"number",className:"se-numberInput",min:n,max:i,step:r,value:o,onFocus:()=>{l.current=!0},onChange:b=>{let k=b.target.value;d(k),k!==""&&k!=="-"&&!Number.isNaN(Number(k))&&t(Number(k))},onBlur:()=>{l.current=!1,d(String(e))}})}function Wt({label:e,value:n,min:i,max:r,step:t,onChange:o}){return Ge("div",{className:"se-field",children:[ie("span",{className:"se-fieldLabel",children:e}),ie("div",{className:"se-vectorRow",children:["X","Y","Z"].map((l,b)=>Ge("label",{className:"se-vectorAxis",children:[ie("span",{children:l}),ie(is,{value:n[b],min:i,max:r,step:t,onChange:k=>{let M=[...n];M[b]=k,o(M)}})]},l))})]})}function on({label:e,value:n,min:i,max:r,step:t,onChange:o}){return Ge("div",{className:"se-field",children:[ie("span",{className:"se-fieldLabel",children:e}),ie("div",{className:"se-vectorRow",children:["X","Y"].map((l,b)=>Ge("label",{className:"se-vectorAxis",children:[ie("span",{children:l}),ie(is,{value:n[b],min:i,max:r,step:t,onChange:k=>{let M=[...n];M[b]=k,o(M)}})]},l))})]})}var rs={free:0,starter:1,growth:2};function ss(e){return e==="starter"||e==="growth"||e==="scale"?e==="scale"?"growth":e:"free"}function ct(e,n){return rs[e]>=rs[n]}var ls={free:"Free",starter:"Starter",growth:"Growth"};import{Lock as Ab}from"lucide-react";import{jsx as Ob,jsxs as ds}from"react/jsx-runtime";function ze({requiredTier:e,feature:n}){return ds("div",{className:"bb-tierLock",children:[Ob(Ab,{size:16}),ds("p",{className:"bb-tierLockMessage",children:[n," requires the ",ls[e]," plan or higher."]})]})}import{Fragment as Fo,jsx as I,jsxs as pe}from"react/jsx-runtime";var Hb=["lit","unlit","normals"],$b=["color","image","environment"];function cs(e){let n=e%360;return n<0?n+360:n}function wn({title:e,open:n,onToggle:i,children:r,trailing:t}){return pe("section",{className:"se-panel",children:[pe("button",{type:"button",className:"se-panelHeader",onClick:i,"aria-expanded":n,children:[pe("span",{className:"se-panelHeaderMain",children:[I(Eb,{size:16,className:`se-panelChevron ${n?"se-panelChevron--open":""}`}),I("span",{className:"se-panelTitle",children:e})]}),t?I("span",{className:"se-panelTrailing",onClick:o=>o.stopPropagation(),children:t}):null]}),n?I("div",{className:"se-panelBody",children:r}):null]})}function Oa({config:e,onChange:n,materialVariantGroups:i=[]}){let{model:r,camera:t,wireframe:o,background:d,environment:l}=e,b=xr(r),k=i.length>0?b.filter(a=>!i.some(u=>u.variants.some(L=>L.name===a))):[],{tier:M}=yt(),w=ct(M,"starter"),p=Oo(),[h,S]=Lb({general:!0,camera:!0,autoRotate:!1,section:!1,wireframe:!1,background:!1}),C=a=>S(u=>({...u,[a]:!u[a]})),g=a=>n({...e,model:a}),c=a=>n({...e,camera:a}),f=e.section??fr,x=a=>n({...e,section:{...f,...a}}),N=a=>n({...e,wireframe:a}),O=a=>n({...e,background:a}),T=a=>n({...e,environment:a}),B=a=>{T({...l,source:"preset",preset:a})};return pe("div",{className:"se-generalContent",children:[pe(wn,{title:"General",open:h.general,onToggle:()=>C("general"),children:[pe("div",{className:"se-field",children:[pe("div",{className:"se-fieldLabel",children:[I("span",{children:"Straighten model"}),I("button",{type:"button",className:"se-iconButton",onClick:()=>g({...r,rotation:[0,0,0]}),"aria-label":"Reset model rotation",children:I(zb,{size:16})})]}),I("div",{className:"se-axisStepperGrid",children:["X","Y","Z"].map((a,u)=>pe("div",{className:"se-axisStepper",children:[I("button",{type:"button",className:"se-axisStepperButton",onClick:()=>{let L=[...r.rotation];L[u]=cs(L[u]-90),g({...r,rotation:L})},"aria-label":`Rotate ${a} axis backward`,children:I(Db,{size:16})}),I("span",{className:"se-axisStepperLabel",children:a}),I("button",{type:"button",className:"se-axisStepperButton",onClick:()=>{let L=[...r.rotation];L[u]=cs(L[u]+90),g({...r,rotation:L})},"aria-label":`Rotate ${a} axis forward`,children:I(jb,{size:16})})]},a))})]}),I(Wt,{label:"Rotation",value:r.rotation,min:0,max:360,step:1,onChange:a=>g({...r,rotation:a})}),pe("div",{className:"se-field",children:[I("span",{className:"se-fieldLabel",children:"Renderer"}),I("div",{className:"se-segmentedControl se-segmentedControl--renderer",children:br.map(a=>I("button",{type:"button",className:`se-segmentedOption ${r.renderer===a?"se-segmentedOption--active":""}`,onClick:()=>g({...r,renderer:a}),children:a==="uv-checker"?"UV CHECKER":a.toUpperCase()},a))})]}),I(qe,{label:"Shading",value:r.shading,options:Hb,onChange:a=>g({...r,shading:a})}),i.map((a,u)=>{let L=b.find(P=>a.variants.some(H=>H.name===P));return pe("label",{className:"se-field se-fieldInline",children:[I("span",{className:"se-fieldLabel",children:a.name??"Material variant"}),pe("select",{className:"se-select",value:L??"",onChange:P=>{let H=P.target.value,q=b.filter(Ke=>Ke!==L);g(ya(r,H?hr(q,H,i):q))},children:[I("option",{value:"",children:"Model default"}),a.variants.map(P=>I("option",{value:P.name,children:P.label},P.name))]})]},a.name??`group-${u}`)}),k.length>0?pe("div",{className:"se-placeholder se-placeholder--spaced",children:["Not in this model: ",k.join(", "),"."," ",I("button",{type:"button",className:"se-linkButton",onClick:()=>g(ya(r,b.filter(a=>!k.includes(a)))),children:"Remove"})]}):null]}),I(wn,{title:"Camera",open:h.camera,onToggle:()=>C("camera"),children:I(A,{label:"Field Of View",value:t.fieldOfView,min:20,max:100,step:.1,formatValue:a=>`${a.toFixed(3)}\xB0`,onChange:a=>c({...t,fieldOfView:a})})}),pe(wn,{title:"Auto Rotate",open:h.autoRotate,onToggle:()=>C("autoRotate"),trailing:pe("label",{className:"se-switch","aria-label":"Toggle auto rotate",children:[I("input",{type:"checkbox",checked:r.autoRotate??!1,onChange:a=>g({...r,autoRotate:a.target.checked})}),I("span",{className:"se-switchTrack",children:I("span",{className:"se-switchThumb"})})]}),children:[r.autoRotate&&p?I("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,r.autoRotate?I(A,{label:"Rotation Speed",value:r.autoRotateSpeed??1,min:.1,max:3,step:.1,formatValue:a=>`${a.toFixed(1)}x`,onChange:a=>g({...r,autoRotateSpeed:a})}):I("div",{className:"se-placeholder",children:"Enable auto rotate to adjust its speed."})]}),I(wn,{title:"Section Cut",open:h.section,onToggle:()=>C("section"),trailing:pe("label",{className:"se-switch","aria-label":"Toggle section cut",children:[I("input",{type:"checkbox",checked:f.enabled,onChange:a=>x({enabled:a.target.checked})}),I("span",{className:"se-switchTrack",children:I("span",{className:"se-switchThumb"})})]}),children:f.enabled?pe(Fo,{children:[pe("div",{className:"se-field",children:[I("span",{className:"se-fieldLabel",children:"Cut across"}),I("div",{className:"se-segmentedControl",children:gr.map(a=>I("button",{type:"button",className:`se-segmentedOption ${f.axis===a?"se-segmentedOption--active":""}`,onClick:()=>x({axis:a}),children:a.toUpperCase()},a))})]}),I(A,{label:"Position",value:f.position,min:0,max:1,step:.01,formatValue:a=>`${Math.round(a*100)}%`,onChange:a=>x({position:a})}),I(de,{label:"Keep the other side",checked:f.flip,onChange:a=>x({flip:a})})]}):I("div",{className:"se-placeholder",children:"Cut the model open to see inside. Drag the plane in the preview, or set it here."})}),I(wn,{title:"Wireframe",open:h.wireframe,onToggle:()=>C("wireframe"),trailing:pe("label",{className:"se-switch","aria-label":"Toggle wireframe preview",children:[I("input",{type:"checkbox",checked:w&&o.enabled,disabled:!w,onChange:a=>N({...o,enabled:a.target.checked})}),I("span",{className:"se-switchTrack",children:I("span",{className:"se-switchThumb"})})]}),children:w?pe(Fo,{children:[I(A,{label:"Opacity",value:o.opacity,min:0,max:1,step:.01,onChange:a=>N({...o,opacity:a})}),I(Ye,{label:"Wire color",value:o.color,onChange:a=>N({...o,color:a})})]}):I(ze,{requiredTier:"starter",feature:"Wireframe preview"})}),I(wn,{title:"Background",open:h.background,onToggle:()=>C("background"),trailing:pe("label",{className:"se-switch","aria-label":"Toggle scene background",children:[I("input",{type:"checkbox",checked:d.enabled,onChange:a=>O({...d,enabled:a.target.checked})}),I("span",{className:"se-switchTrack",children:I("span",{className:"se-switchThumb"})})]}),children:d.enabled?pe(Fo,{children:[pe("div",{className:"se-field",children:[I("span",{className:"se-fieldLabel",children:"Background type"}),I("div",{className:"se-segmentedControl",children:$b.map(a=>I("button",{type:"button",className:`se-segmentedOption ${d.type===a?"se-segmentedOption--active":""}`,onClick:()=>O({...d,type:a}),children:a},a))})]}),d.type==="environment"?w?pe(Fo,{children:[pe("div",{className:"se-field",children:[I("span",{className:"se-fieldLabel",children:"Environment source"}),pe("div",{className:"se-segmentedControl",children:[I("button",{type:"button",className:`se-segmentedOption ${l.source==="preset"?"se-segmentedOption--active":""}`,onClick:()=>T({...l,source:"preset"}),children:"PRESET"}),I("button",{type:"button",className:`se-segmentedOption ${l.source==="custom"?"se-segmentedOption--active":""}`,onClick:()=>T({...l,source:"custom"}),children:"CUSTOM"})]})]}),l.source==="preset"?I(qe,{label:"Environment preset",value:l.preset,options:pr,onChange:B}):pe("label",{className:"se-field",children:[I("span",{className:"se-fieldLabel",children:"Custom environment URL"}),I("input",{type:"text",className:"se-textInput",placeholder:"https://example.com/environment.hdr",value:l.customEnvironmentUrl,onChange:a=>T({...l,customEnvironmentUrl:a.target.value})}),I("span",{className:"bb-note",children:"Enter a HDR, EXR, JPG, JPEG, PNG, or WEBP URL."}),l.customEnvironmentUrl.trim()&&!dr(l.customEnvironmentUrl)?I("span",{className:"bb-note",style:{color:"#fca5a5"},children:"Invalid image/HDRI URL."}):null]}),I(A,{label:"Environment intensity",value:l.intensity,min:0,max:3,step:.05,onChange:a=>T({...l,intensity:a})})]}):I(ze,{requiredTier:"starter",feature:"Environment backgrounds"}):null,d.type==="image"?pe("label",{className:"se-field",children:[I("span",{className:"se-fieldLabel",children:"Background image URL"}),I("input",{type:"text",className:"se-textInput",placeholder:"https://example.com/background.jpg",value:d.imageUrl,onChange:a=>O({...d,imageUrl:a.target.value})})]}):null,d.type==="color"?pe("div",{className:"se-field",children:[I("span",{className:"se-fieldLabel",children:"Background color"}),I("div",{className:"se-inlineColorPicker",children:I(Fb,{color:d.color,onChange:a=>O({...d,color:a})})}),I("div",{className:"se-fieldInline",children:I(Ib,{prefixed:!0,className:"se-swatch",style:{background:d.color,color:Kt(d.color)},color:d.color,onChange:a=>O({...d,color:a})})})]}):null]}):I("div",{className:"se-placeholder",children:"Background rendering is disabled for this scene preset."})})]})}import{useState as Ub}from"react";import{jsx as V,jsxs as Yn}from"react/jsx-runtime";function bs({pp:e,set:n,open:i,toggle:r}){let{ssao:t}=e;return Yn(re,{title:"SSAO",tooltip:"Adds soft contact shadows in corners, creases, and tight spaces.",open:i.ssao,onToggle:()=>r("ssao"),disabled:!t.enabled,trailing:V(ce,{checked:t.enabled,onChange:o=>n("ssao",{...t,enabled:o}),label:"Toggle SSAO"}),children:[V(A,{label:"Samples",value:t.samples,min:1,max:64,step:1,onChange:o=>n("ssao",{...t,samples:o})}),V(A,{label:"Rings",value:t.rings,min:1,max:12,step:1,onChange:o=>n("ssao",{...t,rings:o})}),V(A,{label:"Intensity",value:t.intensity,min:0,max:20,step:.5,onChange:o=>n("ssao",{...t,intensity:o})}),V(A,{label:"Radius",value:t.radius,min:.01,max:1,step:.01,onChange:o=>n("ssao",{...t,radius:o})}),V(A,{label:"Bias",value:t.bias,min:0,max:.1,step:.001,onChange:o=>n("ssao",{...t,bias:o})}),V(A,{label:"Luminance Influence",value:t.luminanceInfluence,min:0,max:1,step:.01,onChange:o=>n("ssao",{...t,luminanceInfluence:o})}),V(A,{label:"Fade",value:t.fade,min:0,max:.1,step:.001,onChange:o=>n("ssao",{...t,fade:o})}),V(A,{label:"Min Radius Scale",value:t.minRadiusScale,min:0,max:1,step:.01,onChange:o=>n("ssao",{...t,minRadiusScale:o})}),V(A,{label:"World Distance Threshold",value:t.worldDistanceThreshold,min:0,max:100,step:.1,onChange:o=>n("ssao",{...t,worldDistanceThreshold:o})}),V(A,{label:"World Distance Falloff",value:t.worldDistanceFalloff,min:0,max:20,step:.1,onChange:o=>n("ssao",{...t,worldDistanceFalloff:o})}),V(A,{label:"World Proximity Threshold",value:t.worldProximityThreshold,min:0,max:100,step:.1,onChange:o=>n("ssao",{...t,worldProximityThreshold:o})}),V(A,{label:"World Proximity Falloff",value:t.worldProximityFalloff,min:0,max:20,step:.1,onChange:o=>n("ssao",{...t,worldProximityFalloff:o})})]})}function ps({pp:e,set:n,open:i,toggle:r}){let{autofocus:t}=e;return Yn(re,{title:"Auto focus",tooltip:"Keeps the focus plane tracking a subject so the image stays sharp where you want it.",open:i.autofocus,onToggle:()=>r("autofocus"),disabled:!t.enabled,trailing:V(ce,{checked:t.enabled,onChange:o=>n("autofocus",{...t,enabled:o}),label:"Toggle Autofocus"}),children:[V(A,{label:"Focus Distance",value:t.focusDistance,min:0,max:50,step:.1,onChange:o=>n("autofocus",{...t,focusDistance:o})}),V(A,{label:"Focus Range",value:t.focusRange,min:.1,max:50,step:.1,onChange:o=>n("autofocus",{...t,focusRange:o})}),V(A,{label:"Focal Length",value:t.focalLength,min:0,max:1,step:.01,onChange:o=>n("autofocus",{...t,focalLength:o})}),V(A,{label:"Bokeh Scale",value:t.bokehScale,min:0,max:20,step:.1,onChange:o=>n("autofocus",{...t,bokehScale:o})}),V(Wt,{label:"Target",value:t.target,min:-100,max:100,step:.1,onChange:o=>n("autofocus",{...t,target:o})}),V(de,{label:"Mouse Follow",checked:t.mouse,onChange:o=>n("autofocus",{...t,mouse:o})}),V(de,{label:"Manual Update",checked:t.manual,onChange:o=>n("autofocus",{...t,manual:o})}),V(A,{label:"Debug",value:t.debug,min:0,max:1,step:.01,onChange:o=>n("autofocus",{...t,debug:o})}),V(A,{label:"Smooth Time",value:t.smoothTime,min:0,max:2,step:.01,onChange:o=>n("autofocus",{...t,smoothTime:o})})]})}function us({pp:e,set:n,open:i,toggle:r}){let{godRays:t}=e;return Yn(re,{title:"God Rays",tooltip:"Creates light shafts that streak outward from a bright sun or light source.",open:i.godRays,onToggle:()=>r("godRays"),disabled:!t.enabled,trailing:V(ce,{checked:t.enabled,onChange:o=>n("godRays",{...t,enabled:o}),label:"Toggle GodRays"}),children:[V(Wt,{label:"Sun Position",value:t.sunPosition,min:-100,max:100,step:.1,onChange:o=>n("godRays",{...t,sunPosition:o})}),V(A,{label:"Samples",value:t.samples,min:1,max:128,step:1,onChange:o=>n("godRays",{...t,samples:o})}),V(A,{label:"Density",value:t.density,min:0,max:2,step:.01,onChange:o=>n("godRays",{...t,density:o})}),V(A,{label:"Decay",value:t.decay,min:0,max:1,step:.01,onChange:o=>n("godRays",{...t,decay:o})}),V(A,{label:"Weight",value:t.weight,min:0,max:2,step:.01,onChange:o=>n("godRays",{...t,weight:o})}),V(A,{label:"Exposure",value:t.exposure,min:0,max:2,step:.01,onChange:o=>n("godRays",{...t,exposure:o})}),V(A,{label:"Clamp Max",value:t.clampMax,min:0,max:2,step:.01,onChange:o=>n("godRays",{...t,clampMax:o})}),V(de,{label:"Blur",checked:t.blur,onChange:o=>n("godRays",{...t,blur:o})}),V(qe,{label:"Kernel Size",value:t.kernelSize,options:Fn,onChange:o=>n("godRays",{...t,kernelSize:o})})]})}function ms({pp:e,set:n,open:i,toggle:r}){let{lensflare:t}=e;return Yn(re,{title:"Lens Flare",tooltip:"Adds camera flare artifacts and glow from a bright light source.",open:i.lensflare,onToggle:()=>r("lensflare"),disabled:!t.enabled,trailing:V(ce,{checked:t.enabled,onChange:o=>n("lensflare",{...t,enabled:o}),label:"Toggle Lensflare"}),children:[V(Wt,{label:"Lens Position",value:t.lensPosition,min:-100,max:100,step:.1,onChange:o=>n("lensflare",{...t,lensPosition:o})}),V(A,{label:"Smooth Time",value:t.smoothTime,min:0,max:1,step:.01,onChange:o=>n("lensflare",{...t,smoothTime:o})}),V(A,{label:"Glare Size",value:t.glareSize,min:0,max:1,step:.01,onChange:o=>n("lensflare",{...t,glareSize:o})}),V(A,{label:"Flare Size",value:t.flareSize,min:0,max:.1,step:.001,onChange:o=>n("lensflare",{...t,flareSize:o})}),V(A,{label:"Flare Speed",value:t.flareSpeed,min:0,max:.2,step:.001,onChange:o=>n("lensflare",{...t,flareSpeed:o})}),V(A,{label:"Flare Shape",value:t.flareShape,min:0,max:.2,step:.001,onChange:o=>n("lensflare",{...t,flareShape:o})}),V(de,{label:"Animated",checked:t.animated,onChange:o=>n("lensflare",{...t,animated:o})}),V(de,{label:"Anamorphic",checked:t.anamorphic,onChange:o=>n("lensflare",{...t,anamorphic:o})}),V(Ye,{label:"Color Gain",value:t.colorGain,onChange:o=>n("lensflare",{...t,colorGain:o})}),V(A,{label:"Halo Scale",value:t.haloScale,min:0,max:2,step:.01,onChange:o=>n("lensflare",{...t,haloScale:o})}),V(de,{label:"Secondary Ghosts",checked:t.secondaryGhosts,onChange:o=>n("lensflare",{...t,secondaryGhosts:o})}),V(de,{label:"Additional Streaks",checked:t.aditionalStreaks,onChange:o=>n("lensflare",{...t,aditionalStreaks:o})}),V(A,{label:"Ghost Scale",value:t.ghostScale,min:0,max:1,step:.01,onChange:o=>n("lensflare",{...t,ghostScale:o})}),V(A,{label:"Opacity",value:t.opacity,min:0,max:1,step:.01,onChange:o=>n("lensflare",{...t,opacity:o})}),V(de,{label:"Star Burst",checked:t.starBurst,onChange:o=>n("lensflare",{...t,starBurst:o})})]})}function gs({pp:e,set:n,open:i,toggle:r}){let{depthOfField:t}=e;return Yn(re,{title:"Depth Of Field",tooltip:"Blurs areas that sit away from the focal plane for a camera-like look.",open:i.depthOfField,onToggle:()=>r("depthOfField"),disabled:!t.enabled,trailing:V(ce,{checked:t.enabled,onChange:o=>n("depthOfField",{...t,enabled:o}),label:"Toggle DepthOfField"}),children:[V(A,{label:"Focus Distance",value:t.focusDistance,min:0,max:50,step:.1,onChange:o=>n("depthOfField",{...t,focusDistance:o})}),V(A,{label:"Focus Range",value:t.focusRange,min:.1,max:50,step:.1,onChange:o=>n("depthOfField",{...t,focusRange:o})}),V(A,{label:"Focal Length",value:t.focalLength,min:0,max:1,step:.01,onChange:o=>n("depthOfField",{...t,focalLength:o})}),V(A,{label:"Bokeh Scale",value:t.bokehScale,min:0,max:20,step:.1,onChange:o=>n("depthOfField",{...t,bokehScale:o})})]})}import{jsx as oe,jsxs as Sn}from"react/jsx-runtime";var Vb=["linear","reinhard","aces"];function fs({pp:e,set:n,open:i,toggle:r}){let{colorAverage:t}=e;return oe(re,{title:"Color Average",tooltip:"Blends the frame toward a single average color for a washed-out stylized look.",open:i.colorAverage,onToggle:()=>r("colorAverage"),disabled:!t.enabled,trailing:oe(ce,{checked:t.enabled,onChange:o=>n("colorAverage",{...t,enabled:o}),label:"Toggle ColorAverage"}),children:oe("div",{className:"se-placeholder",children:"Averages the frame color using the docs default blend mode."})})}function hs({pp:e,set:n,open:i,toggle:r}){let{brightnessContrast:t}=e;return Sn(re,{title:"Brightness Contrast",tooltip:"Raises or lowers overall brightness and contrast across the scene.",open:i.brightnessContrast,onToggle:()=>r("brightnessContrast"),disabled:!t.enabled,trailing:oe(ce,{checked:t.enabled,onChange:o=>n("brightnessContrast",{...t,enabled:o}),label:"Toggle BrightnessContrast"}),children:[oe(A,{label:"Brightness",value:t.brightness,min:-1,max:1,step:.01,onChange:o=>n("brightnessContrast",{...t,brightness:o})}),oe(A,{label:"Contrast",value:t.contrast,min:-1,max:1,step:.01,onChange:o=>n("brightnessContrast",{...t,contrast:o})})]})}function xs({pp:e,set:n,open:i,toggle:r}){let{hueSaturation:t}=e;return Sn(re,{title:"Hue Saturation",tooltip:"Shifts the hue and saturation to tint the whole image.",open:i.hueSaturation,onToggle:()=>r("hueSaturation"),disabled:!t.enabled,trailing:oe(ce,{checked:t.enabled,onChange:o=>n("hueSaturation",{...t,enabled:o}),label:"Toggle HueSaturation"}),children:[oe(A,{label:"Hue",value:t.hue,min:-Math.PI,max:Math.PI,step:.01,formatValue:o=>`${o.toFixed(2)} rad`,onChange:o=>n("hueSaturation",{...t,hue:o})}),oe(A,{label:"Saturation",value:t.saturation,min:-1,max:1,step:.01,onChange:o=>n("hueSaturation",{...t,saturation:o})})]})}function vs({pp:e,set:n,open:i,toggle:r}){let{vignette:t}=e;return Sn(re,{title:"Vignette",tooltip:"Darkens the edges of the screen so the center feels more focused.",open:i.vignette,onToggle:()=>r("vignette"),disabled:!t.enabled,trailing:oe(ce,{checked:t.enabled,onChange:o=>n("vignette",{...t,enabled:o}),label:"Toggle Vignette"}),children:[oe(A,{label:"Offset",value:t.offset,min:0,max:1,step:.01,onChange:o=>n("vignette",{...t,offset:o})}),oe(A,{label:"Darkness",value:t.darkness,min:0,max:1,step:.01,onChange:o=>n("vignette",{...t,darkness:o})}),oe(de,{label:"Eskil",checked:t.eskil,onChange:o=>n("vignette",{...t,eskil:o})})]})}function ys({pp:e,set:n,open:i,toggle:r}){let{bloom:t}=e;return Sn(re,{title:"Bloom",tooltip:"Makes bright areas glow and bleed softly into nearby pixels.",open:i.bloom,onToggle:()=>r("bloom"),disabled:!t.enabled,trailing:oe(ce,{checked:t.enabled,onChange:o=>n("bloom",{...t,enabled:o}),label:"Toggle Bloom"}),children:[oe(A,{label:"Threshold",value:t.luminanceThreshold,min:0,max:1,step:.01,onChange:o=>n("bloom",{...t,luminanceThreshold:o})}),oe(A,{label:"Smoothing",value:t.luminanceSmoothing,min:0,max:1,step:.01,onChange:o=>n("bloom",{...t,luminanceSmoothing:o})}),oe(A,{label:"Intensity",value:t.intensity,min:0,max:3,step:.05,onChange:o=>n("bloom",{...t,intensity:o})}),oe(de,{label:"Mipmap Blur",checked:t.mipmapBlur,onChange:o=>n("bloom",{...t,mipmapBlur:o})}),oe(A,{label:"Radius",value:t.radius,min:0,max:1,step:.01,onChange:o=>n("bloom",{...t,radius:o})}),oe(A,{label:"Levels",value:t.levels,min:1,max:16,step:1,onChange:o=>n("bloom",{...t,levels:o})})]})}function ws({pp:e,set:n,open:i,toggle:r}){let{toneMapping:t}=e;return Sn(re,{title:"Tone Mapping",tooltip:"Remaps HDR lighting to screen output and controls exposure style.",open:i.toneMapping,onToggle:()=>r("toneMapping"),disabled:!t.enabled,trailing:oe(ce,{checked:t.enabled,onChange:o=>n("toneMapping",{...t,enabled:o}),label:"Toggle ToneMapping"}),children:[Sn("div",{className:"se-field",children:[oe("span",{className:"se-fieldLabel",children:"Mode"}),oe("div",{className:"se-segmentedControl",children:Vb.map(o=>oe("button",{type:"button",className:`se-segmentedOption ${t.mode===o?"se-segmentedOption--active":""}`,onClick:()=>n("toneMapping",{...t,mode:o}),children:o==="aces"?"Filmic":o.charAt(0).toUpperCase()+o.slice(1)},o))})]}),oe(A,{label:"Resolution",value:t.resolution,min:64,max:4096,step:64,onChange:o=>n("toneMapping",{...t,resolution:o})}),oe(A,{label:"White Point",value:t.whitePoint,min:0,max:16,step:.01,onChange:o=>n("toneMapping",{...t,whitePoint:o})}),oe(A,{label:"Middle Grey",value:t.middleGrey,min:0,max:1,step:.01,onChange:o=>n("toneMapping",{...t,middleGrey:o})}),oe(A,{label:"Min Luminance",value:t.minLuminance,min:0,max:1,step:.01,onChange:o=>n("toneMapping",{...t,minLuminance:o})}),oe(A,{label:"Average Luminance",value:t.averageLuminance,min:0,max:4,step:.01,onChange:o=>n("toneMapping",{...t,averageLuminance:o})}),oe(A,{label:"Adaptation Rate",value:t.adaptationRate,min:0,max:10,step:.01,onChange:o=>n("toneMapping",{...t,adaptationRate:o})}),oe(A,{label:"Exposure",value:t.exposure,min:0,max:3,step:.01,onChange:o=>n("toneMapping",{...t,exposure:o})})]})}function Ss({pp:e,set:n,open:i,toggle:r}){let{sepia:t}=e;return oe(re,{title:"Sepia",tooltip:"Adds a warm vintage brown tint to the entire image.",open:i.sepia,onToggle:()=>r("sepia"),disabled:!t.enabled,trailing:oe(ce,{checked:t.enabled,onChange:o=>n("sepia",{...t,enabled:o}),label:"Toggle Sepia"}),children:oe(A,{label:"Intensity",value:t.intensity,min:0,max:1,step:.01,onChange:o=>n("sepia",{...t,intensity:o})})})}import{jsx as ee,jsxs as Cn}from"react/jsx-runtime";function Cs({pp:e,set:n,open:i,toggle:r}){let{dotScreen:t}=e;return Cn(re,{title:"Dot Screen",tooltip:"Overlays a halftone dot pattern for a printed or retro look.",open:i.dotScreen,onToggle:()=>r("dotScreen"),disabled:!t.enabled,trailing:ee(ce,{checked:t.enabled,onChange:o=>n("dotScreen",{...t,enabled:o}),label:"Toggle DotScreen"}),children:[ee(A,{label:"Angle",value:t.angle,min:0,max:Math.PI*2,step:.01,formatValue:o=>`${o.toFixed(2)} rad`,onChange:o=>n("dotScreen",{...t,angle:o})}),ee(A,{label:"Scale",value:t.scale,min:.1,max:10,step:.05,onChange:o=>n("dotScreen",{...t,scale:o})})]})}function ks({pp:e,set:n,open:i,toggle:r}){let{glitch:t}=e;return Cn(re,{title:"Glitch",tooltip:"Introduces digital distortion, tearing, and scan noise.",open:i.glitch,onToggle:()=>r("glitch"),disabled:!t.enabled,trailing:ee(ce,{checked:t.enabled,onChange:o=>n("glitch",{...t,enabled:o}),label:"Toggle Glitch"}),children:[ee(qe,{label:"Mode",value:t.mode,options:ur,onChange:o=>n("glitch",{...t,mode:o})}),ee(on,{label:"Delay",value:t.delay,min:0,max:10,step:.01,onChange:o=>n("glitch",{...t,delay:o})}),ee(on,{label:"Duration",value:t.duration,min:0,max:5,step:.01,onChange:o=>n("glitch",{...t,duration:o})}),ee(on,{label:"Strength",value:t.strength,min:0,max:2,step:.01,onChange:o=>n("glitch",{...t,strength:o})}),ee(on,{label:"Chromatic Aberration Offset",value:t.chromaticAberrationOffset,min:0,max:.02,step:1e-4,onChange:o=>n("glitch",{...t,chromaticAberrationOffset:o})}),ee(A,{label:"Columns",value:t.columns,min:0,max:.5,step:.001,onChange:o=>n("glitch",{...t,columns:o})}),ee(A,{label:"Ratio",value:t.ratio,min:0,max:1,step:.01,onChange:o=>n("glitch",{...t,ratio:o})})]})}function Ms({pp:e,set:n,open:i,toggle:r}){let{grid:t}=e;return Cn(re,{title:"Grid",tooltip:"Adds a visual grid overlay that feels retro or debug-like.",open:i.grid,onToggle:()=>r("grid"),disabled:!t.enabled,trailing:ee(ce,{checked:t.enabled,onChange:o=>n("grid",{...t,enabled:o}),label:"Toggle Grid"}),children:[ee(A,{label:"Scale",value:t.scale,min:.1,max:10,step:.05,onChange:o=>n("grid",{...t,scale:o})}),ee(A,{label:"Line Width",value:t.lineWidth,min:0,max:1,step:.01,onChange:o=>n("grid",{...t,lineWidth:o})})]})}function Ns({pp:e,set:n,open:i,toggle:r}){let{chromaticAberration:t}=e;return Cn(re,{title:"Chromatic Aberration",tooltip:"Separates color channels slightly to mimic lens fringing.",open:i.chromaticAberration,onToggle:()=>r("chromaticAberration"),disabled:!t.enabled,trailing:ee(ce,{checked:t.enabled,onChange:o=>n("chromaticAberration",{...t,enabled:o}),label:"Toggle ChromaticAberration"}),children:[ee(A,{label:"Offset X",value:t.offsetX,min:0,max:.02,step:1e-4,onChange:o=>n("chromaticAberration",{...t,offsetX:o})}),ee(A,{label:"Offset Y",value:t.offsetY,min:0,max:.02,step:1e-4,onChange:o=>n("chromaticAberration",{...t,offsetY:o})}),ee(de,{label:"Radial Modulation",checked:t.radialModulation,onChange:o=>n("chromaticAberration",{...t,radialModulation:o})}),ee(A,{label:"Modulation Offset",value:t.modulationOffset,min:0,max:1,step:.01,onChange:o=>n("chromaticAberration",{...t,modulationOffset:o})})]})}function Ts({pp:e,set:n,open:i,toggle:r}){let{noise:t}=e;return Cn(re,{title:"Noise",tooltip:"Adds film grain or static noise to the rendered image.",open:i.noise,onToggle:()=>r("noise"),disabled:!t.enabled,trailing:ee(ce,{checked:t.enabled,onChange:o=>n("noise",{...t,enabled:o}),label:"Toggle Noise"}),children:[ee(A,{label:"Amount",value:t.opacity,min:0,max:1,step:.01,onChange:o=>n("noise",{...t,opacity:o})}),ee(de,{label:"Premultiply",checked:t.premultiply,onChange:o=>n("noise",{...t,premultiply:o})})]})}function Ps({pp:e,set:n,open:i,toggle:r}){let{scanline:t}=e;return ee(re,{title:"Scan Line",tooltip:"Draws horizontal CRT-style scan lines over the frame.",open:i.scanline,onToggle:()=>r("scanline"),disabled:!t.enabled,trailing:ee(ce,{checked:t.enabled,onChange:o=>n("scanline",{...t,enabled:o}),label:"Toggle Scanline"}),children:ee(A,{label:"Density",value:t.density,min:0,max:10,step:.25,onChange:o=>n("scanline",{...t,density:o})})})}function Bs({pp:e,set:n,open:i,toggle:r}){let{pixelation:t}=e;return ee(re,{title:"Pixelation",tooltip:"Reduces detail into larger pixels for a blocky stylized effect.",open:i.pixelation,onToggle:()=>r("pixelation"),disabled:!t.enabled,trailing:ee(ce,{checked:t.enabled,onChange:o=>n("pixelation",{...t,enabled:o}),label:"Toggle Pixelation"}),children:ee(A,{label:"Granularity",value:t.granularity,min:0,max:20,step:1,onChange:o=>n("pixelation",{...t,granularity:o})})})}function Rs({pp:e,set:n,open:i,toggle:r}){let{ramp:t}=e;return Cn(re,{title:"Ramp",tooltip:"Adds a screen-space color gradient, or masks effects earlier in the stack.",open:i.ramp,onToggle:()=>r("ramp"),disabled:!t.enabled,trailing:ee(ce,{checked:t.enabled,onChange:o=>n("ramp",{...t,enabled:o}),label:"Toggle Ramp"}),children:[ee(qe,{label:"Ramp Type",value:t.rampType,options:mr,onChange:o=>n("ramp",{...t,rampType:o})}),ee(on,{label:"Ramp Start",value:t.rampStart,min:0,max:1,step:.01,onChange:o=>n("ramp",{...t,rampStart:o})}),ee(on,{label:"Ramp End",value:t.rampEnd,min:0,max:1,step:.01,onChange:o=>n("ramp",{...t,rampEnd:o})}),ee(Ye,{label:"Start Color",value:t.startColor,onChange:o=>n("ramp",{...t,startColor:o})}),ee(Ye,{label:"End Color",value:t.endColor,onChange:o=>n("ramp",{...t,endColor:o})}),!t.rampMask&&ee(A,{label:"Gradient Opacity",value:t.opacity??.5,min:0,max:1,step:.01,onChange:o=>n("ramp",{...t,opacity:o})}),ee(A,{label:"Bias",value:t.rampBias,min:0,max:1,step:.01,onChange:o=>n("ramp",{...t,rampBias:o})}),ee(A,{label:"Gain",value:t.rampGain,min:0,max:1,step:.01,onChange:o=>n("ramp",{...t,rampGain:o})}),ee(de,{label:"Mask Earlier Effects",checked:t.rampMask,onChange:o=>n("ramp",{...t,rampMask:o})}),ee(de,{label:"Invert",checked:t.rampInvert,onChange:o=>n("ramp",{...t,rampInvert:o})})]})}import{jsx as ye,jsxs as Es}from"react/jsx-runtime";function As({pp:e,set:n,open:i,toggle:r}){let{outline:t}=e;return Es(re,{title:"Outline",tooltip:"Draws a visible edge around the selected object binding.",open:i.outline,onToggle:()=>r("outline"),disabled:!t.enabled,trailing:ye(ce,{checked:t.enabled,onChange:o=>n("outline",{...t,enabled:o}),label:"Toggle Outline"}),children:[ye("div",{className:"se-placeholder",children:"Outlines the currently selected object binding in the model editor."}),ye(A,{label:"Selection Layer",value:t.selectionLayer,min:0,max:20,step:1,onChange:o=>n("outline",{...t,selectionLayer:o})}),ye(A,{label:"Edge Strength",value:t.edgeStrength,min:0,max:10,step:.1,onChange:o=>n("outline",{...t,edgeStrength:o})}),ye(A,{label:"Pulse Speed",value:t.pulseSpeed,min:0,max:10,step:.1,onChange:o=>n("outline",{...t,pulseSpeed:o})}),ye(Ye,{label:"Visible Edge Color",value:t.visibleEdgeColor,onChange:o=>n("outline",{...t,visibleEdgeColor:o})}),ye(Ye,{label:"Hidden Edge Color",value:t.hiddenEdgeColor,onChange:o=>n("outline",{...t,hiddenEdgeColor:o})}),ye(qe,{label:"Kernel Size",value:t.kernelSize,options:Fn,onChange:o=>n("outline",{...t,kernelSize:o})}),ye(de,{label:"Blur",checked:t.blur,onChange:o=>n("outline",{...t,blur:o})}),ye(de,{label:"X-Ray",checked:t.xRay,onChange:o=>n("outline",{...t,xRay:o})})]})}function Os({pp:e,set:n,open:i,toggle:r}){let{selectiveBloom:t}=e;return Es(re,{title:"Selective Bloom",tooltip:"Applies bloom only to objects assigned to the selected layer.",open:i.selectiveBloom,onToggle:()=>r("selectiveBloom"),disabled:!t.enabled,trailing:ye(ce,{checked:t.enabled,onChange:o=>n("selectiveBloom",{...t,enabled:o}),label:"Toggle SelectiveBloom"}),children:[ye("div",{className:"se-placeholder",children:"Applies bloom to the currently selected object binding."}),ye(A,{label:"Selection Layer",value:t.selectionLayer,min:0,max:20,step:1,onChange:o=>n("selectiveBloom",{...t,selectionLayer:o})}),ye(A,{label:"Intensity",value:t.intensity,min:0,max:5,step:.05,onChange:o=>n("selectiveBloom",{...t,intensity:o})}),ye(A,{label:"Threshold",value:t.luminanceThreshold,min:0,max:1,step:.01,onChange:o=>n("selectiveBloom",{...t,luminanceThreshold:o})}),ye(A,{label:"Smoothing",value:t.luminanceSmoothing,min:0,max:1,step:.01,onChange:o=>n("selectiveBloom",{...t,luminanceSmoothing:o})}),ye(qe,{label:"Kernel Size",value:t.kernelSize,options:Fn,onChange:o=>n("selectiveBloom",{...t,kernelSize:o})}),ye(de,{label:"Mipmap Blur",checked:t.mipmapBlur,onChange:o=>n("selectiveBloom",{...t,mipmapBlur:o})}),ye(de,{label:"Inverted",checked:t.inverted,onChange:o=>n("selectiveBloom",{...t,inverted:o})}),ye(de,{label:"Ignore Background",checked:t.ignoreBackground,onChange:o=>n("selectiveBloom",{...t,ignoreBackground:o})})]})}function Ls({pp:e,set:n,open:i,toggle:r}){let{smaa:t}=e;return ye(re,{title:"SMAA",tooltip:"Reduces jagged edges with subpixel anti-aliasing.",open:i.smaa,onToggle:()=>r("smaa"),trailing:ye(ce,{checked:t.enabled,onChange:o=>n("smaa",{...t,enabled:o}),label:"Toggle SMAA"}),children:ye("div",{className:"se-placeholder",children:"Subpixel Morphological Anti-Aliasing smooths jagged edges in post-process."})})}import{jsx as we,jsxs as Gb}from"react/jsx-runtime";function La({config:e,onChange:n}){let[i,r]=Ub({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}),t=b=>r(k=>({...k,[b]:!k[b]})),o=e.postProcessing,l={pp:o,set:(b,k)=>n({...e,postProcessing:{...o,[b]:k}}),open:i,toggle:t};return Gb("div",{className:"se-generalContent",children:[we(bs,{...l}),we(ps,{...l}),we(fs,{...l}),we(Cs,{...l}),we(ks,{...l}),we(us,{...l}),we(Ms,{...l}),we(ms,{...l}),we(As,{...l}),we(Os,{...l}),we(hs,{...l}),we(xs,{...l}),we(gs,{...l}),we(Ns,{...l}),we(vs,{...l}),we(ys,{...l}),we(ws,{...l}),we(Ts,{...l}),we(Ss,{...l}),we(Ps,{...l}),we(Bs,{...l}),we(Rs,{...l}),we(Ls,{...l})]})}import{useState as Ds,useSyncExternalStore as _b}from"react";import{Eye as Kb,EyeOff as Wb,Plus as Yb,Trash2 as qb}from"lucide-react";import{Fragment as js,jsx as X,jsxs as Je}from"react/jsx-runtime";var Jb=["512","1024","2048","4096"],zs={none:"None",directional:"Direction",point:"Point",spot:"Spot",hemisphere:"Hemi"};function Xb({index:e,light:n,selected:i,onSelect:r,onToggleVisible:t}){return Je("div",{className:`se-lightRow ${i?"se-lightRow--active":""}`,onClick:r,children:[Je("span",{className:"se-lightRowLabel",children:[e+1,": ",zs[n.type]]}),X("button",{type:"button",className:"se-iconButton","aria-label":n.visible?"Hide light":"Show light",onClick:o=>{o.stopPropagation(),t()},children:n.visible?X(Kb,{size:14}):X(Wb,{size:14})})]})}function Zb(){return{id:crypto.randomUUID(),type:"directional",color:"#ffffff",intensity:1,position:[5,10,5],attachedToCamera:!1,castShadow:!1,shadowBias:-5e-4,visible:!0}}function Ea({config:e,onChange:n}){let[i,r]=Ds({lights:!0,shadows:!1,groundShadows:!1,environment:!1,envShadow:!1}),t=_b(Ar,Or),[o,d]=Ds(e.lighting.lights[0]?.id??null),l=t??o,b=a=>{d(a),Rr(a)},k=a=>r(u=>({...u,[a]:!u[a]})),{tier:M}=yt(),w=ct(M,"starter"),{lighting:p,shadows:h,groundShadows:S,environment:C}=e,g=a=>n({...e,lighting:a}),c=a=>n({...e,shadows:a}),f=a=>n({...e,groundShadows:a}),x=a=>n({...e,environment:a}),N=(a,u)=>{g({...p,lights:p.lights.map(L=>L.id===a?{...L,...u}:L)})},O=p.lights.find(a=>a.id===l)??null,T=()=>{let a=Zb();g({...p,lights:[...p.lights,a]}),b(a.id)},B=()=>{if(!O)return;let a=p.lights.filter(u=>u.id!==O.id);g({...p,lights:a}),b(a[0]?.id??null)};return Je("div",{className:"se-generalContent",children:[Je(re,{title:"Lights",open:i.lights,onToggle:()=>k("lights"),children:[X("div",{className:"se-lightList",children:p.lights.map((a,u)=>X(Xb,{index:u,light:a,selected:a.id===l,onSelect:()=>b(a.id),onToggleVisible:()=>N(a.id,{visible:!a.visible})},a.id))}),Je("div",{className:"se-lightActions",children:[X("button",{type:"button",className:"se-iconButton",onClick:T,title:"Add light",children:X(Yb,{size:14})}),O&&p.lights.length>1&&X("button",{type:"button",className:"se-iconButton",onClick:B,title:"Remove selected light",children:X(qb,{size:14})})]}),O?Je("div",{className:"se-lightProps",children:[Je("div",{className:"se-field",children:[X("span",{className:"se-fieldLabel",children:"Type"}),X("div",{className:"se-segmentedControl",style:{gridAutoColumns:"1fr"},children:cr.map(a=>X("button",{type:"button",className:`se-segmentedOption ${O.type===a?"se-segmentedOption--active":""}`,onClick:()=>N(O.id,{type:a}),children:zs[a]},a))})]}),X(Ye,{label:"Color",value:O.color,onChange:a=>N(O.id,{color:a})}),X(A,{label:"Intensity",value:O.intensity,min:0,max:10,step:.1,onChange:a=>N(O.id,{intensity:a})}),O.type!=="hemisphere"&&O.type!=="none"&&X(Wt,{label:"Position",value:O.position,min:-100,max:100,step:.05,onChange:a=>N(O.id,{position:a})}),O.type==="spot"&&Je(js,{children:[X(A,{label:"Angle",value:O.angle??Math.PI/6,min:0,max:Math.PI/2,step:.01,formatValue:a=>`${Math.round(a*180/Math.PI)}\xB0`,onChange:a=>N(O.id,{angle:a})}),X(A,{label:"Penumbra",value:O.penumbra??.2,min:0,max:1,step:.01,onChange:a=>N(O.id,{penumbra:a})}),X(A,{label:"Distance",value:O.distance??0,min:0,max:100,step:.5,onChange:a=>N(O.id,{distance:a})}),X(A,{label:"Decay",value:O.decay??2,min:0,max:4,step:.1,onChange:a=>N(O.id,{decay:a})})]}),X(de,{label:"Attached to camera",checked:O.attachedToCamera,onChange:a=>N(O.id,{attachedToCamera:a})}),X(de,{label:"Cast shadows",checked:O.castShadow,onChange:a=>N(O.id,{castShadow:a})}),X(A,{label:"Shadow bias",value:O.shadowBias,min:-.01,max:.01,step:1e-4,onChange:a=>N(O.id,{shadowBias:a})})]}):null]}),Je(re,{title:"Shadows",open:i.shadows,onToggle:()=>k("shadows"),disabled:!h.enabled,trailing:X(ce,{checked:h.enabled,onChange:a=>c({...h,enabled:a}),label:"Toggle shadows"}),children:[X(qe,{label:"Map size",value:String(h.mapSize),options:Jb,onChange:a=>c({...h,mapSize:Number(a)})}),X(A,{label:"Bias",value:h.bias,min:-.01,max:.01,step:1e-4,onChange:a=>c({...h,bias:a})}),X(A,{label:"Normal bias",value:h.normalBias,min:0,max:.2,step:.01,onChange:a=>c({...h,normalBias:a})}),X(A,{label:"Radius (softness)",value:h.radius,min:0,max:20,step:.5,onChange:a=>c({...h,radius:a})})]}),Je(re,{title:"Ground Shadows",open:i.groundShadows,onToggle:()=>k("groundShadows"),disabled:!S.enabled,trailing:X(ce,{checked:S.enabled,onChange:a=>f({...S,enabled:a}),label:"Toggle ground shadows"}),children:[Je("div",{className:"se-field",children:[X("span",{className:"se-fieldLabel",children:"Mode"}),X("div",{className:"se-segmentedControl",style:{gridAutoColumns:"1fr"},children:["shadowCatcher"].map(a=>X("button",{type:"button",className:`se-segmentedOption ${S.mode===a?"se-segmentedOption--active":""}`,onClick:()=>f({...S,mode:a}),children:a==="shadowCatcher"?"Shadow Catcher":"Baked AO"},a))})]}),S.mode==="bakedAO"&&X("div",{className:"se-placeholder",children:"Requires pre-baked AO textures \u2014 not yet available."}),X(A,{label:"Intensity",value:S.intensity,min:0,max:1,step:.01,onChange:a=>f({...S,intensity:a})}),X(A,{label:"Border fade",value:S.borderFade,min:0,max:10,step:.1,onChange:a=>f({...S,borderFade:a})}),X(A,{label:"Height",value:S.height,min:-5,max:5,step:.1,onChange:a=>f({...S,height:a})}),X(A,{label:"Size",value:S.size,min:1,max:50,step:.5,onChange:a=>f({...S,size:a})})]}),X(re,{title:"Environment",open:i.environment,onToggle:()=>k("environment"),children:w?Je(js,{children:[X(A,{label:"Orientation",value:C.rotation,min:0,max:360,step:1,formatValue:a=>`${a}\xB0`,onChange:a=>x({...C,rotation:a})}),X(A,{label:"Brightness",value:C.intensity,min:0,max:3,step:.05,onChange:a=>x({...C,intensity:a})}),Je(re,{title:"Shadow",open:i.envShadow,onToggle:()=>k("envShadow"),trailing:X(ce,{checked:C.shadowLight.enabled,onChange:a=>x({...C,shadowLight:{...C.shadowLight,enabled:a}}),label:"Toggle environment shadow light"}),disabled:!C.shadowLight.enabled,children:[X(A,{label:"Light intensity",value:C.shadowLight.intensity,min:0,max:20,step:.1,onChange:a=>x({...C,shadowLight:{...C.shadowLight,intensity:a}})}),X(A,{label:"Shadow bias",value:C.shadowLight.bias,min:-.01,max:.01,step:1e-4,onChange:a=>x({...C,shadowLight:{...C.shadowLight,bias:a}})})]})]}):X(ze,{requiredTier:"starter",feature:"Environment lighting"})})]})}import{useMemo as Qb,useState as ep}from"react";import{ChevronDown as tp,Pause as Is,Play as np,Rewind as op,Square as ap,Trash2 as ip}from"lucide-react";import{jsx as te,jsxs as Se}from"react/jsx-runtime";var rp={playing:"Playing",paused:"Paused",finished:"Finished"},Fs={repeat:"Looping",once:"Play once","ping-pong":"Ping-pong"};function sp(e){if(!Number.isFinite(e)||e<=0)return"Unknown duration";let n=Math.round(e*10)/10;if(n<60)return`${n.toFixed(1)}s`;let i=Math.floor(n/60),r=(n%60).toFixed(1).padStart(4,"0");return`${i}:${r}`}function Hs(e){let n=Number.isFinite(e)&&e>0?e:0;if(n<60)return`${n.toFixed(1)}s`;let i=Math.floor(n/60),r=(n%60).toFixed(1).padStart(4,"0");return`${i}:${r}`}function lp(e){return Number.isFinite(e)?Math.min(3,Math.max(.1,Number(e.toFixed(2)))):1}function Da({config:e,onChange:n,clipDetails:i,active:r,play:t,pause:o,stop:d,setSpeed:l,seek:b}){let[k,M]=ep(!1),w=Qb(()=>new Map(i.map(T=>[T.sourceName,T.duration])),[i]),p=e.animations.clips.filter(T=>!T.hidden),h=e.animations.clips.filter(T=>T.hidden),S=(T,B=e.animations.autoplayClip)=>{n({...e,animations:{clips:T(e.animations.clips),autoplayClip:B}})},C=(T,B)=>{S(a=>a.map(u=>u.sourceName===T?B(u):u))},g=(T,B)=>{C(T,a=>({...a,loopMode:B}))},c=(T,B)=>{let a=lp(B);C(T,u=>({...u,speed:a})),r.some(u=>u.clip===T)&&l(a,T)},f=(T,B)=>{C(T,a=>({...a,displayName:B}))},x=T=>{let B=e.animations.autoplayClip===T?null:T;n({...e,animations:{...e.animations,autoplayClip:B}})},N=T=>{S(B=>B.map(a=>a.sourceName===T?{...a,hidden:!0}:a),e.animations.autoplayClip===T?null:e.animations.autoplayClip),r.some(B=>B.clip===T)&&d(T)},O=T=>{S(B=>B.map(a=>a.sourceName===T?{...a,hidden:!1}:a))};return e.animations.clips.length===0?te(Et,{title:"Animations",children:te("div",{className:"se-helperCard",children:"Upload a model with embedded animations to manage playback, naming, autoplay, and per-clip speed here."})}):Se(Et,{title:"Animations",children:[p.length===0&&te("div",{className:"se-helperCard",children:te("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."})}),p.length===0?te("div",{className:"se-placeholder",children:"All animations are currently removed. Restore a clip below to make it available again."}):te("div",{className:"se-animationList",children:p.map(T=>{let B=r.find(H=>H.clip===T.sourceName),a=B?.status==="playing",u=B?.time??0,L=w.get(T.sourceName)??0,P=B?rp[B.status]:"Ready";return Se("article",{className:`se-animationCard ${B?"se-animationCard--active":""}`,children:[Se("div",{className:"se-animationHeader",children:[Se("div",{className:"se-animationHeading",children:[Se("div",{className:"se-animationTitleRow",children:[te("span",{className:"se-animationStatus",children:P}),e.animations.autoplayClip===T.sourceName?te("span",{className:"se-animationBadge",children:"Autoplay"}):null]}),te("div",{className:"se-animationSource",children:T.sourceName})]}),te("button",{type:"button",className:"se-animationDangerButton",onClick:()=>N(T.sourceName),title:"Remove animation",children:te(ip,{size:16})})]}),Se("div",{className:"se-field",children:[te("span",{className:"se-fieldLabel",children:"Display name"}),te("input",{className:"se-textInput",value:T.displayName,onChange:H=>f(T.sourceName,H.target.value),placeholder:"Animation name"})]}),Se("div",{className:"se-animationMeta",children:[te("span",{children:sp(L)}),te("span",{children:Fs[T.loopMode]??Fs.repeat}),Se("span",{children:[T.speed.toFixed(2),"x"]})]}),Se("div",{className:"se-animationButtonRow",children:[te("button",{type:"button",className:"se-animationButton se-animationButton--icon",onClick:()=>a&&!B?.reverse?o(T.sourceName):t(T.sourceName,{alongside:!0}),"aria-label":a&&!B?.reverse?"Pause":"Play",title:a&&!B?.reverse?"Pause":"Play",children:a&&!B?.reverse?te(Is,{size:16}):te(np,{size:16})}),te("button",{type:"button",className:"se-animationButton se-animationButton--icon",onClick:()=>a&&B?.reverse?o(T.sourceName):t(T.sourceName,{alongside:!0,reverse:!0}),"aria-label":a&&B?.reverse?"Pause":"Play backwards",title:a&&B?.reverse?"Pause":"Play backwards",children:a&&B?.reverse?te(Is,{size:16}):te(op,{size:16})}),te("button",{type:"button",className:"se-animationButton se-animationButton--icon",onClick:()=>d(T.sourceName),disabled:!B,"aria-label":"Stop",title:"Stop",children:te(ap,{size:16})})]}),Se("div",{className:"se-animationSeekRow",children:[te("input",{className:"se-slider se-animationSeek",type:"range",min:0,max:Math.max(L,.001),step:.01,value:Math.min(u,L),disabled:!B||L<=0,onChange:H=>b(Number(H.target.value),T.sourceName),"aria-label":"Seek"}),Se("span",{className:"se-animationSeekTime",children:[Hs(Math.min(u,L))," / ",Hs(L)]})]}),Se("div",{className:"se-animationGrid",children:[Se("label",{className:"se-field",children:[te("span",{className:"se-fieldLabel",children:"Loop mode"}),Se("select",{className:"se-select",value:T.loopMode,onChange:H=>g(T.sourceName,H.target.value),children:[te("option",{value:"repeat",children:"Loop"}),te("option",{value:"once",children:"Play Once"}),te("option",{value:"ping-pong",children:"Ping-Pong"})]})]}),Se("label",{className:"se-field",children:[Se("span",{className:"se-fieldLabel",children:["Speed",Se("span",{className:"se-fieldValue",children:[T.speed.toFixed(2),"x"]})]}),Se("div",{className:"se-animationSpeedRow",children:[te("input",{className:"se-slider",type:"range",min:.1,max:3,step:.1,value:T.speed,onChange:H=>c(T.sourceName,Number(H.target.value))}),te("input",{className:"se-numberInput se-animationSpeedInput",type:"number",min:.1,max:3,step:.1,value:T.speed,onChange:H=>c(T.sourceName,Number(H.target.value))})]})]})]}),te("button",{type:"button",className:`se-animationAutoplayButton ${e.animations.autoplayClip===T.sourceName?"se-animationAutoplayButton--active":""}`,onClick:()=>x(T.sourceName),children:e.animations.autoplayClip===T.sourceName?"Disable autoplay":"Set as autoplay"})]},T.sourceName)})}),h.length>0?Se("section",{className:"se-removedAnimations",children:[te("button",{type:"button",className:"se-panelHeader",onClick:()=>M(T=>!T),children:Se("span",{className:"se-panelHeaderMain",children:[te(tp,{size:16,className:`se-panelChevron ${k?"se-panelChevron--open":""}`}),Se("span",{className:"se-panelTitle",children:["Removed Animations (",h.length,")"]})]})}),k?te("div",{className:"se-removedAnimationList",children:h.map(T=>Se("div",{className:"se-removedAnimationRow",children:[Se("div",{children:[te("div",{className:"se-removedAnimationName",children:T.displayName||T.sourceName}),te("div",{className:"se-animationSource",children:T.sourceName})]}),te("button",{type:"button",className:"se-animationButton",onClick:()=>O(T.sourceName),children:"Restore"})]},T.sourceName))}):null]}):null]})}import{useState as ja}from"react";import{Eye as dp,Pencil as cp,Trash2 as bp}from"lucide-react";import{jsx as Z,jsxs as ae}from"react/jsx-runtime";function za({config:e,onChange:n,cameraState:i,onPreviewView:r}){let[t,o]=ja(null),[d,l]=ja(""),[b,k]=ja(""),M=g=>{o(structuredClone(g)),l(g.minDistance?.toString()??""),k(g.maxDistance?.toString()??"")},w=d.trim()===""?void 0:Number(d),p=b.trim()===""?void 0:Number(b),h=[w,p].some(g=>g!==void 0&&(!Number.isFinite(g)||g<0))?"Distances must be non-negative numbers.":w!==void 0&&p!==void 0&&w>p?"Maximum distance must be at least the minimum.":t?.images?.some(g=>g.src.trim()&&!Sa(g.src))||t?.links?.some(g=>g.href.trim()&&!Sa(g.href))?"Use an HTTP(S) URL or a relative path for images and links.":null,S=()=>{if(!t?.title.trim()||h)return;let g={...t,title:t.title.trim(),category:t.category?.trim()||void 0,minDistance:w,maxDistance:p,images:t.images?.filter(c=>c.src.trim()).map(c=>({...c,src:c.src.trim()})),links:t.links?.filter(c=>c.href.trim()).map(c=>({...c,href:c.href.trim(),label:c.label.trim()||"Learn more"}))};n({...e,annotations:e.annotations.map(c=>c.id===t.id?g:c)}),o(null)},C=g=>{window.confirm("Delete this annotation?")&&(n({...e,annotations:e.annotations.filter(c=>c.id!==g).map((c,f)=>({...c,id:f+1}))}),o(null))};return ae(Et,{title:"Annotations",children:[e.annotations.length===0?Z("div",{className:"bb-emptyAnnotations",children:"No annotations yet. Double-click on the model to add one."}):Z("div",{className:"se-annotationList",children:e.annotations.map(g=>ae("div",{className:"se-annotationRow",children:[ae("span",{className:"se-annotationNumber",children:["#",g.id]}),ae("div",{className:"se-annotationSummary",children:[ae("div",{className:"se-annotationHeading",children:[Z("span",{className:"se-annotationTitle",title:g.title,children:g.title}),g.category?.trim()&&Z("span",{className:"se-annotationCategory",title:g.category,children:g.category})]}),g.description&&Z("p",{className:"se-annotationDescription",title:g.description,children:g.description})]}),ae("div",{className:"se-annotationActions",children:[Sr(g.cameraView)&&Z("button",{type:"button",className:"se-annotationAction",disabled:!r,onClick:()=>r?.(g.cameraView),title:"Preview saved view","aria-label":`Preview saved view for ${g.title}`,children:Z(dp,{size:15,"aria-hidden":"true"})}),Z("button",{type:"button",className:"se-annotationAction",onClick:()=>M(g),title:"Edit annotation","aria-label":`Edit ${g.title}`,children:Z(cp,{size:15,"aria-hidden":"true"})}),Z("button",{type:"button",className:"se-annotationAction se-annotationAction--delete",onClick:()=>C(g.id),title:"Delete annotation","aria-label":`Delete ${g.title}`,children:Z(bp,{size:15,"aria-hidden":"true"})})]})]},g.id))}),t&&Z("div",{className:"bb-editAnnotationOverlay",onClick:()=>o(null),children:ae("div",{className:"bb-editAnnotationPopup",onKeyDown:g=>{g.key==="Escape"&&(g.stopPropagation(),o(null))},role:"dialog","aria-modal":"true","aria-labelledby":"annotation-edit-title",onClick:g=>g.stopPropagation(),children:[ae("div",{className:"bb-editAnnotationHeader",children:[Z("h3",{id:"annotation-edit-title",className:"bb-editAnnotationTitle",children:"Edit annotation"}),Z("button",{className:"bb-editAnnotationClose","aria-label":"Close annotation editor",onClick:()=>o(null),children:"\xD7"})]}),ae("div",{className:"bb-editAnnotationBody",children:[ae("label",{className:"bb-field",children:[Z("span",{className:"bb-label",children:"Title"}),Z("input",{className:"bb-input",autoFocus:!0,value:t.title,onChange:g=>o({...t,title:g.target.value})})]}),ae("label",{className:"bb-field",children:[Z("span",{className:"bb-label",children:"Description"}),Z("textarea",{className:"bb-textarea",rows:3,value:t.description,onChange:g=>o({...t,description:g.target.value})})]}),ae("label",{className:"bb-field",children:[Z("span",{className:"bb-label",children:"Category"}),Z("input",{className:"bb-input",value:t.category??"",onChange:g=>o({...t,category:g.target.value}),placeholder:"For example, Features"})]}),ae("p",{className:"se-annotationCoordinates",children:["Position: [",t.worldPosition.map(g=>g.toFixed(2)).join(", "),"]"]}),ae("fieldset",{className:"bb-annotationFields",children:[Z("legend",{children:"Saved camera view"}),Z("p",{children:t.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."}),ae("div",{className:"bb-annotationFieldActions",children:[Z("button",{className:"bb-button",disabled:!i,onClick:()=>i&&o({...t,cameraView:structuredClone(i)}),children:"Capture current view"}),Z("button",{className:"bb-button",disabled:!t.cameraView||!r,onClick:()=>t.cameraView&&r?.(t.cameraView),children:"Preview"}),Z("button",{className:"bb-button",disabled:!t.cameraView,onClick:()=>o({...t,cameraView:void 0}),children:"Clear view"})]})]}),ae("fieldset",{className:"bb-annotationFields",children:[Z("legend",{children:"Marker distance (scene units)"}),Z("p",{children:"Leave blank to show markers at any distance."}),ae("div",{className:"bb-annotationDistanceFields",children:[ae("label",{className:"bb-field",children:[Z("span",{className:"bb-label",children:"Minimum distance"}),Z("input",{className:"bb-input",type:"number",min:"0",step:"any",value:d,onChange:g=>l(g.target.value)})]}),ae("label",{className:"bb-field",children:[Z("span",{className:"bb-label",children:"Maximum distance"}),Z("input",{className:"bb-input",type:"number",min:"0",step:"any",value:b,onChange:g=>k(g.target.value)})]})]})]}),ae("fieldset",{className:"bb-annotationFields",children:[Z("legend",{children:"Images"}),t.images?.map((g,c)=>ae("div",{className:"bb-annotationMediaRow",children:[ae("label",{className:"bb-field",children:[ae("span",{className:"bb-label",children:["Image URL ",c+1]}),Z("input",{className:"bb-input",value:g.src,onChange:f=>o({...t,images:t.images.map((x,N)=>N===c?{...x,src:f.target.value}:x)}),placeholder:"https://example.com/image.jpg"})]}),ae("label",{className:"bb-field",children:[ae("span",{className:"bb-label",children:["Image description ",c+1]}),Z("input",{className:"bb-input",value:g.alt??"",onChange:f=>o({...t,images:t.images.map((x,N)=>N===c?{...x,alt:f.target.value}:x)})})]}),ae("button",{className:"bb-button",onClick:()=>o({...t,images:t.images.filter((f,x)=>x!==c)}),children:["Remove image ",c+1]})]},c)),Z("button",{className:"bb-button",onClick:()=>o({...t,images:[...t.images??[],{src:"",alt:""}]}),children:"Add image"})]}),ae("fieldset",{className:"bb-annotationFields",children:[Z("legend",{children:"Links"}),t.links?.map((g,c)=>ae("div",{className:"bb-annotationMediaRow",children:[ae("label",{className:"bb-field",children:[ae("span",{className:"bb-label",children:["Link URL ",c+1]}),Z("input",{className:"bb-input",value:g.href,onChange:f=>o({...t,links:t.links.map((x,N)=>N===c?{...x,href:f.target.value}:x)}),placeholder:"https://example.com/details"})]}),ae("label",{className:"bb-field",children:[ae("span",{className:"bb-label",children:["Link label ",c+1]}),Z("input",{className:"bb-input",value:g.label,onChange:f=>o({...t,links:t.links.map((x,N)=>N===c?{...x,label:f.target.value}:x)})})]}),ae("button",{className:"bb-button",onClick:()=>o({...t,links:t.links.filter((f,x)=>x!==c)}),children:["Remove link ",c+1]})]},c)),Z("button",{className:"bb-button",onClick:()=>o({...t,links:[...t.links??[],{href:"",label:""}]}),children:"Add link"})]}),h&&Z("p",{role:"alert",children:h}),ae("div",{className:"bb-editAnnotationActions",children:[Z("button",{className:"bb-button",onClick:()=>o(null),children:"Cancel"}),Z("button",{className:"bb-button bb-button--primary",disabled:!t.title.trim()||!!h,onClick:S,children:"Save"}),Z("button",{className:"bb-button bb-button--danger",onClick:()=>C(t.id),children:"Delete"})]})]})]})})]})}import{useState as pp,useCallback as an}from"react";import{ArrowDown as up,ArrowUp as mp,MapPin as gp,Plus as fp,Trash2 as hp,Settings as xp}from"lucide-react";import{Fragment as yp,jsx as ue,jsxs as Re}from"react/jsx-runtime";var vp={enabled:!0,waypoints:[],loop:!0,autoPlay:!1},rn=3.5;function Ia({config:e,onChange:n,cameraState:i,onPreviewWaypoint:r}){let t=e.cinematic??vp,o=Oo(),{waypoints:d}=t,l=an((f,x)=>{if(f.length<2)return 0;let N=0;for(let O=0;O<f.length-1;O++){let T=f[O].segmentDuration??rn;N+=T}return x&&f.length>1&&(N+=f[f.length-1].segmentDuration??rn),Math.max(N,0)},[]),b=an(f=>{n({...e,cinematic:{...t,...f}})},[e,t,n]),k=an(()=>{if(!i)return;let f={position:[...i.position],target:[...i.target],...i.azimuthAngle!=null?{azimuthAngle:i.azimuthAngle}:{},...i.polarAngle!=null?{polarAngle:i.polarAngle}:{},segmentDuration:rn},x=[...d,f],N=l(x,t.loop);b({waypoints:x,duration:N})},[i,d,t.loop,l,b]),M=an(f=>{let x=d.filter((O,T)=>T!==f),N=l(x,t.loop);b({waypoints:x,duration:N})},[d,t.loop,l,b]),w=an((f,x)=>{let N=f+x;if(N<0||N>=d.length)return;let O=[...d];[O[f],O[N]]=[O[N],O[f]];let T=l(O,t.loop);b({waypoints:O,duration:T})},[d,t.loop,l,b]),p=an((f,x)=>{let N=d.map((T,B)=>B===f?{...T,...x}:T),O=l(N,t.loop);b({waypoints:N,duration:O})},[d,t.loop,l,b]),[h,S]=pp(!1),C=d.some(f=>f.segmentDuration!==void 0),g=an(f=>f>=d.length-1?rn:d[f]?.segmentDuration??rn,[d]),c=d.length>=2;return Re(Et,{title:"Cinematic Camera",children:[ue("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."}),Re("button",{type:"button",className:"bb-button bb-button--primary se-cinematicAdd",onClick:k,disabled:!i,title:"Capture the current camera view as a waypoint",children:[ue(fp,{size:15}),"Add waypoint from current view"]}),Re("div",{className:"se-customizeToggle",children:[Re("label",{className:"se-toggleLabel",children:[ue("input",{type:"checkbox",checked:h,onChange:f=>S(f.target.checked)}),ue(xp,{size:14}),ue("span",{children:"Customize durations between waypoints"})]}),h&&Re("span",{className:"se-toggleHint",children:["Set duration for each segment between waypoints: 1\u21922, 2\u21923, etc. Default: ",rn,"s"]})]}),d.length===0?ue("div",{className:"bb-emptyAnnotations",children:"No waypoints yet. Position the camera and add your first one."}):Re(yp,{children:[ue("div",{className:"se-waypointList",children:d.map((f,x)=>{let N=g(x),O=x===d.length-1,T=f.segmentDuration!==void 0&&f.segmentDuration!==rn;return Re("div",{children:[Re("div",{className:"se-waypointCard",children:[ue("div",{className:"se-waypointBadge",children:x+1}),Re("div",{className:"se-waypointBody",children:[Re("div",{className:"se-waypointCoords",children:["pos [",f.position.map(B=>B.toFixed(1)).join(", "),"]"]}),Re("div",{className:"se-waypointCoords",children:["look [",f.target.map(B=>B.toFixed(1)).join(", "),"]"]}),h&&!O&&Re("div",{className:`se-customBadge ${T?"se-customBadge--custom":"se-customBadge--default"}`,children:[N.toFixed(1),"s",!T&&" (default)"]})]}),Re("div",{className:"se-waypointActions",children:[ue("button",{className:"se-waypointAction",onClick:()=>r?.(f),title:"Fly camera to this waypoint",disabled:!r,children:ue(gp,{size:15})}),ue("button",{className:"se-waypointAction",onClick:()=>w(x,-1),title:"Move up",disabled:x===0,children:ue(mp,{size:15})}),ue("button",{className:"se-waypointAction",onClick:()=>w(x,1),title:"Move down",disabled:O,children:ue(up,{size:15})}),ue("button",{className:"se-waypointAction se-waypointAction--delete",onClick:()=>M(x),title:"Delete waypoint",children:ue(hp,{size:15})})]})]}),h&&!O&&Re("div",{className:"se-segmentBetween",children:[Re("div",{className:"se-segmentLabel",children:[x+1," \u2192 ",x+2,!f.segmentDuration&&" (default)"]}),Re("div",{className:"se-segmentControls",children:[ue("span",{className:"se-durationLabel",children:"Duration:"}),ue("input",{type:"range",className:"se-segmentSlider",min:1,max:20,step:.5,value:N,onChange:B=>{let a=parseFloat(B.target.value);p(x,{segmentDuration:a})}}),Re("span",{className:"se-segmentValue",children:[N.toFixed(1),"s"]}),Re("div",{className:"se-presetButtons",children:[[2,4,6,8].map(B=>Re("button",{className:"se-presetButton",onClick:()=>p(x,{segmentDuration:B}),children:[B,"s"]},`preset-${x}-${B}`)),ue("button",{className:"se-presetButton se-presetButton--default",onClick:()=>{let B=d.map((u,L)=>{if(L===x){let{segmentDuration:P,...H}=u;return H}return u}),a=l(B,t.loop);b({waypoints:B,duration:a})},children:"Reset"})]})]})]})]},`waypoint-wrapper-${x}`)})}),Re("div",{className:"se-totalDuration",children:[ue("span",{className:"se-totalLabel",children:"Total duration:"}),ue("span",{className:"se-totalValue",children:c?(t.duration??l(d,t.loop)).toFixed(1)+"s":"-"}),!c&&ue("span",{className:"se-totalHint",children:"(need at least 2 waypoints)"})]})]}),ue(de,{label:"Enable cinematic camera",checked:t.enabled,onChange:f=>b({enabled:f})}),ue(de,{label:"Loop",checked:t.loop,onChange:f=>{let x=f,N=l(d,x);b({loop:x,duration:N})}}),ue(de,{label:"Auto-play on load",checked:t.autoPlay,onChange:f=>b({autoPlay:f})}),t.autoPlay&&o?ue("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,!h&&c&&ue(A,{label:"Duration",value:t.duration??l(d,t.loop),min:4,max:120,step:1,formatValue:f=>`${f}s`,onChange:f=>b({duration:f})})]})}import{useMemo as wp,useRef as Sp,useState as Ws}from"react";import{HexColorInput as Cp,HexColorPicker as kp}from"react-colorful";import{ArrowDown as Mp,ArrowUp as Np,ChevronDown as Tp,Plus as Fa,Trash2 as Pp,X as Vs}from"lucide-react";var $s=["other","body","light","wheel","glass","interior","floor","wall","door","furniture","decor","electronics","seat","table","chair","window","sofa","bed","engine","headlight"],Ho=["normal","hidden","selected","disabled"];import{Fragment as Ks,jsx as F,jsxs as ve}from"react/jsx-runtime";var Ha={all:"All objects",group:"Group",tag:"Tag",type:"Type",object:"One object"},Us={metric:"Metric",status:"Status",metadata:"Metadata"},Bp={metric:"",stops:[[0,"#3b82f6"],[100,"#ef4444"]]};function Rp(e){return e===void 0?"all":typeof e=="string"||Array.isArray(e)?"object":"group"in e?"group":"tag"in e?"tag":"type"}function qn(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 Gs(e,n){if(e!=="all")return e==="object"?n:e==="group"?{group:n}:e==="tag"?{tag:n}:{type:n}}function Ap(e){return"metric"in e?"metric":"status"in e?"status":"metadata"}function _s(e){return e==="metric"?{metric:""}:e==="status"?{status:["disabled"]}:{metadata:"",equals:""}}function Op(e){let n=e.trim();return n==="true"?!0:n==="false"?!1:n==="null"?null:n!==""&&Number.isFinite(Number(n))?Number(n):e}function $a(e){return e.trim()===""||!Number.isFinite(Number(e))?void 0:Number(e)}function Ys(e,n="",i=0){return typeof e!="object"||e===null||Array.isArray(e)?n?[n]:[]:i>2?n?[n]:[]:Object.entries(e).flatMap(([r,t])=>Ys(t,n?`${n}.${r}`:r,i+1))}var Jn=e=>[...new Set(e.filter(n=>!!n))].sort((n,i)=>n.localeCompare(i));function Ct({label:e,children:n}){return ve("label",{className:"se-field",children:[F("span",{className:"se-fieldLabel",children:e}),n]})}function Xn({label:e,checked:n,color:i,onToggle:r,onColorChange:t}){let[o,d]=Ws(!1),l=Sp(null);return ve("div",{className:"se-field se-fieldInline",children:[ve("label",{className:"se-ruleLook",children:[F("input",{type:"checkbox",className:"se-checkbox",checked:n,onChange:b=>r(b.target.checked)}),e]}),n&&i!==void 0&&t?F("span",{ref:l,style:{display:"inline-flex"},children:F(Cp,{prefixed:!0,className:"se-swatch","aria-label":`${e} value`,onClick:()=>d(b=>!b),style:{background:i,color:Kt(i)},color:i,onChange:t})}):null,o?F(Wn,{anchorRef:l,onClose:()=>d(!1),children:F(kp,{color:i,onChange:t})}):null]})}function Lp({title:e,open:n,onToggle:i,actions:r,children:t}){return ve("section",{className:"se-panel",children:[ve("div",{className:"se-ruleHeader",children:[F("button",{type:"button",className:"se-panelHeader",onClick:i,"aria-expanded":n,children:ve("span",{className:"se-panelHeaderMain",children:[F(Tp,{size:16,className:`se-panelChevron ${n?"se-panelChevron--open":""}`}),F("span",{className:"se-panelTitle",children:e})]})}),F("span",{className:"se-ruleActions",children:r})]}),n?F("div",{className:"se-panelBody",children:t}):null]})}function Va({config:e,onChange:n,objectBindings:i}){let r=e.styleRules??[],[t,o]=Ws(r[0]?.id??null),d=wp(()=>{let p=Object.values(i);return{groups:Jn(p.map(h=>h.group)),tags:Jn(p.flatMap(h=>h.tags??[])),types:Jn(p.map(h=>h.type??"other")),objects:p.map(h=>({id:h.id,label:h.label||h.id})).sort((h,S)=>h.label.localeCompare(S.label)),metrics:Jn(p.flatMap(h=>Object.keys(h.metrics??{}))),metadata:Jn(p.flatMap(h=>Ys(h.metadata)))}},[i]),l=p=>n({...e,styleRules:p}),b=(p,h)=>l(r.map(S=>S.id===p?h(S):S)),k=()=>{let p=crypto.randomUUID();l([...r,{id:p,label:`Rule ${r.length+1}`,when:[{status:["disabled"]}],material:{baseColor:"#9ca3af"}}]),o(p)},M=(p,h)=>{let S=[...r],[C]=S.splice(p,1);S.splice(p+h,0,C),l(S)},w=p=>{let h=p.target?Ca(i,p.target):Object.keys(i),S=p.when?Array.isArray(p.when)?p.when:[p.when]:[];return h.filter(C=>S.every(g=>Mr(i[C],g))).length};return ve(Et,{title:"Style rules",children:[F("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."}),F("datalist",{id:"se-ruleMetrics",children:d.metrics.map(p=>F("option",{value:p},p))}),F("datalist",{id:"se-ruleMetadata",children:d.metadata.map(p=>F("option",{value:p},p))}),r.map((p,h)=>{let S=p.when?Array.isArray(p.when)?p.when:[p.when]:[],C=Rp(p.target),g=p.material??{},c=p.pulse===!0?{}:p.pulse||void 0,f=p.target?Ca(i,p.target).length:Object.keys(i).length,x=a=>b(p.id,u=>({...u,when:a.length>0?a:void 0})),N=(a,u)=>x(S.map((L,P)=>P===a?u:L)),O=a=>b(p.id,u=>{let L={...u.material,...a};for(let P of Object.keys(L))L[P]===void 0&&delete L[P];return{...u,material:Object.keys(L).length>0?L:void 0}}),T=a=>b(p.id,u=>({...u,colorScale:a})),B=C==="group"?d.groups:C==="tag"?d.tags:C==="type"?d.types:[];return ve(Lp,{title:p.label||`Rule ${h+1}`,open:t===p.id,onToggle:()=>o(a=>a===p.id?null:p.id),actions:ve(Ks,{children:[F("button",{type:"button",className:"se-iconButton",onClick:()=>M(h,-1),disabled:h===0,"aria-label":"Move rule up",title:"Move up",children:F(Np,{size:14})}),F("button",{type:"button",className:"se-iconButton",onClick:()=>M(h,1),disabled:h===r.length-1,"aria-label":"Move rule down",title:"Move down",children:F(Mp,{size:14})}),F("button",{type:"button",className:"se-iconButton",onClick:()=>l(r.filter(a=>a.id!==p.id)),"aria-label":"Delete rule",title:"Delete rule",children:F(Pp,{size:14})})]}),children:[F(Ct,{label:"Name",children:F("input",{className:"se-textInput",value:p.label??"",placeholder:`Rule ${h+1}`,onChange:a=>b(p.id,u=>({...u,label:a.target.value}))})}),ve("div",{className:"se-ruleGrid",children:[F(Ct,{label:"Applies to",children:F("select",{className:"se-select",value:C,onChange:a=>{let u=a.target.value,L=u==="object"?d.objects[0]?.id:u==="group"?d.groups[0]:u==="tag"?d.tags[0]:u==="type"?d.types[0]:"";b(p.id,P=>({...P,target:Gs(u,L??"")}))},children:Object.keys(Ha).map(a=>F("option",{value:a,children:Ha[a]},a))})}),C!=="all"?F(Ct,{label:Ha[C],children:ve("select",{className:"se-select",value:qn(p.target),onChange:a=>b(p.id,u=>({...u,target:Gs(C,a.target.value)})),children:[C==="object"?d.objects.map(a=>F("option",{value:a.id,children:a.label},a.id)):B.map(a=>F("option",{value:a,children:a},a)),(C==="object"?d.objects.some(a=>a.id===qn(p.target)):B.includes(qn(p.target)))?null:F("option",{value:qn(p.target),children:qn(p.target)||"None in this model"})]})}):null]}),F("div",{className:"se-fieldLabel",children:"When"}),S.length===0?F("div",{className:"se-ruleHint",children:"Always applies."}):null,S.map((a,u)=>{let L=Ap(a);return ve("div",{className:"se-ruleCondition",children:[ve("div",{className:"se-ruleConditionHeader",children:[F("select",{className:"se-select","aria-label":"Condition type",value:L,onChange:P=>N(u,_s(P.target.value)),children:Object.keys(Us).map(P=>F("option",{value:P,children:Us[P]},P))}),F("button",{type:"button",className:"se-iconButton","aria-label":"Remove condition",title:"Remove condition",onClick:()=>x(S.filter((P,H)=>H!==u)),children:F(Vs,{size:14})})]}),"metric"in a?ve("div",{className:"se-ruleGrid se-ruleGrid--three",children:[F(Ct,{label:"Metric",children:F("input",{className:"se-textInput",list:"se-ruleMetrics",value:a.metric,placeholder:"temperature",onChange:P=>N(u,{...a,metric:P.target.value})})}),F(Ct,{label:"Above",children:F("input",{className:"se-numberInput",type:"number",value:a.above??"",placeholder:"any",onChange:P=>N(u,{...a,above:$a(P.target.value)})})}),F(Ct,{label:"Below",children:F("input",{className:"se-numberInput",type:"number",value:a.below??"",placeholder:"any",onChange:P=>N(u,{...a,below:$a(P.target.value)})})})]}):"status"in a?F("div",{className:"se-ruleStatuses",children:Ho.map(P=>{let H=[].concat(a.status).includes(P);return ve("label",{className:"se-ruleStatus",children:[F("input",{type:"checkbox",className:"se-checkbox",checked:H,onChange:()=>{let q=[].concat(a.status),Ke=H?q.filter(Le=>Le!==P):[...q,P];N(u,{status:Ke})}}),P]},P)})}):ve("div",{className:"se-ruleGrid",children:[F(Ct,{label:"Key",children:F("input",{className:"se-textInput",list:"se-ruleMetadata",value:a.metadata,placeholder:"alarm.state",onChange:P=>N(u,{...a,metadata:P.target.value})})}),F(Ct,{label:"Equals",children:F("input",{className:"se-textInput",value:a.equals===null?"null":String(a.equals),placeholder:"fault",onChange:P=>N(u,{...a,equals:Op(P.target.value)})})})]})]},u)}),ve("button",{type:"button",className:"se-animationButton",onClick:()=>x([...S,_s("metric")]),children:[F(Fa,{size:14})," Add condition"]}),F("div",{className:"se-fieldLabel",children:"Look"}),F(Xn,{label:"Colour",checked:g.baseColor!==void 0,color:g.baseColor,onToggle:a=>O({baseColor:a?"#9ca3af":void 0}),onColorChange:a=>O({baseColor:a})}),F(Xn,{label:"Opacity",checked:g.opacity!==void 0,onToggle:a=>O({opacity:a?.4:void 0})}),g.opacity!==void 0?F(A,{label:"Opacity",value:g.opacity,min:0,max:1,step:.05,formatValue:a=>`${Math.round(a*100)}%`,onChange:a=>O({opacity:a})}):null,F(Xn,{label:"Glow",checked:g.emissive!==void 0,color:g.emissive,onToggle:a=>O({emissive:a?"#ff3b30":void 0,emissiveIntensity:a?g.emissiveIntensity??1:void 0}),onColorChange:a=>O({emissive:a})}),F(Xn,{label:"Colour from a metric",checked:p.colorScale!==void 0,onToggle:a=>T(a?{...Bp,metric:d.metrics[0]??""}:void 0)}),p.colorScale?ve("div",{className:"se-ruleCondition",children:[ve("div",{className:"se-ruleGrid",children:[F(Ct,{label:"Metric",children:F("input",{className:"se-textInput",list:"se-ruleMetrics",value:p.colorScale.metric,placeholder:"temperature",onChange:a=>T({...p.colorScale,metric:a.target.value})})}),F(Ct,{label:"Sets",children:ve("select",{className:"se-select",value:p.colorScale.channel??"baseColor",onChange:a=>T({...p.colorScale,channel:a.target.value}),children:[F("option",{value:"baseColor",children:"Colour"}),F("option",{value:"emissive",children:"Glow colour"})]})})]}),p.colorScale.stops.map(([a,u],L)=>{let P=H=>T({...p.colorScale,stops:p.colorScale.stops.map((q,Ke)=>Ke===L?H:q)});return ve("div",{className:"se-ruleStop",children:[F("input",{className:"se-numberInput",type:"number","aria-label":"Stop value",value:a,onChange:H=>P([$a(H.target.value)??0,u])}),F(Ye,{label:`At ${a}`,value:u,onChange:H=>P([a,H])}),F("button",{type:"button",className:"se-iconButton","aria-label":"Remove stop",title:"Remove stop",disabled:p.colorScale.stops.length<=1,onClick:()=>T({...p.colorScale,stops:p.colorScale.stops.filter((H,q)=>q!==L)}),children:F(Vs,{size:14})})]},L)}),ve("button",{type:"button",className:"se-animationButton",onClick:()=>{let a=p.colorScale.stops,u=a[a.length-1];T({...p.colorScale,stops:[...a,[(u?.[0]??0)+10,u?.[1]??"#ffffff"]]})},children:[F(Fa,{size:14})," Add stop"]})]}):null,F(Xn,{label:"Pulse",checked:c!==void 0,color:c?.color??"#ff3b30",onToggle:a=>b(p.id,u=>({...u,pulse:a?{color:"#ff3b30",speed:1}:void 0})),onColorChange:a=>b(p.id,u=>({...u,pulse:{...c,color:a}}))}),c?F(Ks,{children:F(A,{label:"Pulses per second",value:c.speed??1,min:.2,max:4,step:.1,formatValue:a=>a.toFixed(1),onChange:a=>b(p.id,u=>({...u,pulse:{...c,speed:a}}))})}):null,ve("div",{className:"se-ruleHint se-ruleMatches",children:["Matches ",w(p)," of ",f," ",f===1?"object":"objects"," right now."]})]},p.id)}),ve("button",{type:"button",className:"se-animationButton",onClick:k,children:[F(Fa,{size:14})," Add rule"]})]})}import{Box as jp,Clapperboard as zp,MessageSquareText as Ip,Palette as Fp,Sparkles as Hp,Spotlight as $p,Video as Vp}from"lucide-react";import{jsx as Ne,jsxs as Kp}from"react/jsx-runtime";var Up=[{label:"General",icon:Ne(jp,{})},{label:"Lighting",icon:Ne($p,{})},{label:"Animations",icon:Ne(zp,{})},{label:"Post Processing",icon:Ne(Hp,{})},{label:"Annotations",icon:Ne(Ip,{})},{label:"Cinematic",icon:Ne(Vp,{})},{label:"Rules",icon:Ne(Fp,{})}],qs={active:[],play:()=>{},pause:()=>{},stop:()=>{},setSpeed:()=>{},seek:()=>{}},Gp=[],_p={};function Ua({config:e,onChange:n,activeSubTab:i,onActiveSubTabChange:r,cameraState:t=null,onPreviewWaypoint:o,animationClipDetails:d=[],animationConfig:l,onAnimationConfigChange:b,materialVariantGroups:k=Gp,objectBindings:M=_p,animationPlayback:w=qs}){let[p,h]=Ep("General"),S=i??p,C=w??qs,{tier:g}=yt(),c=ct(g,"starter"),f=ct(g,"growth");Dp(()=>{i!==void 0&&h(i)},[i]);let x=N=>{i===void 0&&h(N),r?.(N)};return Kp("div",{className:"se-tabContent",children:[Ne("div",{className:"se-subTabRow",children:Up.map(N=>Ne("button",{type:"button",title:N.label,"aria-label":N.label,"aria-pressed":S===N.label,className:`se-subTab ${S===N.label?"se-subTab--active":""}`,onClick:()=>x(N.label),children:N.icon},N.label))}),S==="General"&&Ne(Oa,{config:e,onChange:n,materialVariantGroups:k}),S==="Lighting"&&Ne(Ea,{config:e,onChange:n}),S==="Animations"&&(c?Ne(Da,{config:l?{...e,animations:l}:e,onChange:b?N=>b(N.animations):n,clipDetails:d,active:C.active,play:C.play,pause:C.pause,stop:C.stop,setSpeed:C.setSpeed,seek:C.seek}):Ne(ze,{requiredTier:"starter",feature:"Animation configuration"})),S==="Post Processing"&&(f?Ne(La,{config:e,onChange:n}):Ne(ze,{requiredTier:"growth",feature:"Post-processing effects"})),S==="Annotations"&&(c?Ne(za,{config:e,onChange:n,cameraState:t,onPreviewView:o}):Ne(ze,{requiredTier:"starter",feature:"Annotations"})),S==="Cinematic"&&(c?Ne(Ia,{config:e,onChange:n,cameraState:t,onPreviewWaypoint:o}):Ne(ze,{requiredTier:"starter",feature:"Cinematic camera"})),S==="Rules"&&(c?Ne(Va,{config:e,onChange:n,objectBindings:M}):Ne(ze,{requiredTier:"starter",feature:"Style rules"}))]})}import{ChevronDown as Js,Info as Xs}from"lucide-react";import{jsx as He,jsxs as sn}from"react/jsx-runtime";function Zs({title:e,trailing:n,children:i,disabled:r,open:t,onToggle:o,tooltip:d}){let l=d?`${d}`:e;return sn("div",{className:"bb-materialPanel",children:[sn("button",{type:"button",className:"bb-materialPanelHeader",onClick:o,"aria-expanded":t,title:l,children:[sn("div",{className:"bb-materialPanelTitleWrap",children:[He(Js,{size:14,className:`bb-materialPanelChevron ${t?"bb-materialPanelChevron--open":""}`}),He("span",{className:"bb-materialPanelTitle",children:e}),d?He("span",{className:"bb-materialPanelHelp",title:l,"aria-label":l,role:"img",onClick:b=>b.stopPropagation(),children:He(Xs,{size:12})}):null]}),n?He("div",{onClick:b=>b.stopPropagation(),children:n}):null]}),t?He("div",{className:"bb-materialPanelBody",style:r?{opacity:.45,pointerEvents:"none"}:void 0,children:i}):null]})}function Ee({title:e,open:n,onToggle:i,trailing:r,children:t,tooltip:o}){let d=o?`${e}: ${o}`:e;return sn("div",{className:"bb-section",children:[sn("div",{className:"bb-sectionHeaderRow",children:[He("button",{type:"button",className:"bb-sectionHeaderButton",onClick:i,"aria-expanded":n,title:d,children:sn("span",{className:"bb-sectionHeaderMain",children:[He(Js,{size:15,className:`bb-sectionChevron ${n?"bb-sectionChevron--open":""}`}),He("h2",{className:"bb-sectionTitle",children:e}),o?He("span",{className:"bb-sectionHelp",title:d,"aria-label":d,role:"img",onClick:l=>l.stopPropagation(),children:He(Xs,{size:13})}):null]})}),r?He("span",{className:"bb-sectionHeaderTrailing",children:r}):null]}),n?He("div",{className:"bb-sectionBody",children:t}):null]})}function Qs({checked:e,onChange:n,label:i}){return sn("label",{className:"se-switch","aria-label":i,children:[He("input",{type:"checkbox",checked:e,onChange:r=>n(r.target.checked)}),He("span",{className:"se-switchTrack",children:He("span",{className:"se-switchThumb"})})]})}import{useState as nl}from"react";import{Trash2 as nu}from"lucide-react";import{jsx as Ga}from"react/jsx-runtime";function Xe({panelKey:e,title:n,tooltip:i,toggleLabel:r,controls:t,children:o,requiredTier:d}){let{openMaterialPanels:l,materialPanelEnabled:b,onToggleMaterialPanel:k,onSetMaterialPanelState:M}=t,w=d?.locked??!1;return Ga(Zs,{title:n,tooltip:i,disabled:w||!b[e],open:l[e],onToggle:()=>k(e),trailing:Ga(Qs,{checked:!w&&b[e],onChange:w?()=>{}:p=>M(e,p),label:r??`Toggle ${n}`}),children:w&&d?Ga(ze,{requiredTier:d.tier,feature:n}):o})}import{createContext as Wp,useContext as Yp,useRef as el,useState as qp}from"react";import{HexColorInput as Jp,HexColorPicker as Xp}from"react-colorful";import{FileUp as Zp,Minus as Qp,Plus as eu}from"lucide-react";import{jsx as me,jsxs as kt}from"react/jsx-runtime";var _a=Wp(null);function Ae({label:e,value:n,placeholder:i,onChange:r}){let t=el(null),o=Yp(_a);return kt("div",{className:"bb-field bb-field--full",children:[me("label",{className:"bb-label",children:e}),kt("div",{className:"bb-fileField",title:o??void 0,children:[me("input",{className:"bb-input bb-fileField-input",placeholder:i,value:n,disabled:!!o&&!n,onChange:d=>{let l=d.target.value;!l&&n&&In(n),r(l)}}),me("button",{type:"button",className:"bb-fileFieldButton",disabled:!!o,onClick:()=>t.current?.click(),"aria-label":`Select file for ${e}`,title:`Select file for ${e}`,children:me(Zp,{size:20})}),me("input",{ref:t,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 b=Bo(l);n&&n!==b&&In(n),tn(b,URL.createObjectURL(l)),r(b),d.target.value=""}})]})]})}function Dt({label:e,value:n,fallback:i="#ffffff",variant:r="swatch",onChange:t}){let[o,d]=qp(!1),l=n||i,b=el(null);return kt("div",{className:"bb-field",children:[me("span",{className:"bb-label",children:e}),me("div",{className:"se-fieldInline",children:me("span",{ref:b,className:r==="input"?"bb-colorFieldAnchor":void 0,style:r==="swatch"?{display:"inline-flex"}:void 0,children:me(Jp,{prefixed:!0,className:r==="input"?"bb-input bb-colorInput":"se-swatch","aria-label":e,onClick:()=>d(k=>!k),style:{background:l,color:Kt(l)},color:l,onChange:t})})}),o?me(Wn,{anchorRef:b,onClose:()=>d(!1),children:me(Xp,{color:l,onChange:t})}):null]})}function Zn({label:e,checked:n,onChange:i}){return kt("label",{className:"bb-checkbox",children:[me("input",{type:"checkbox",checked:n,onChange:r=>i(r.target.checked)}),e]})}function tl({label:e,value:n,min:i,max:r,step:t,placeholder:o,disabled:d,onChange:l}){return kt("div",{className:"bb-field",children:[me("label",{className:"bb-label",children:e}),me("input",{className:"bb-input",type:"number",min:i,max:r,step:t,placeholder:o,disabled:d,value:n??"",onChange:b=>l(b.target.value===""?void 0:Number(b.target.value))})]})}function tu(e,n){let i=n<1?Math.ceil(-Math.log10(n)):0,r=10**Math.max(i,0);return Math.round(e*r)/r}function Ka({label:e,value:n,min:i,max:r,step:t=.01,disabled:o,onChange:d}){let l=n??0,b=M=>{let w=M;return i!==void 0&&(w=Math.max(i,w)),r!==void 0&&(w=Math.min(r,w)),w},k=M=>{d(b(tu(l+M*t,t)))};return kt("div",{className:"bb-field",children:[me("label",{className:"bb-label",children:e}),kt("div",{className:"bb-numberStepper",children:[me("button",{type:"button",className:"bb-numberStepper-btn",disabled:o,onClick:()=>k(-1),"aria-label":`Decrease ${e}`,title:`Decrease ${e}`,children:me(Qp,{size:12})}),me("input",{className:"bb-input bb-numberStepper-input",type:"number",min:i,max:r,step:t,disabled:o,value:l,onChange:M=>{M.target.value!==""&&d(b(Number(M.target.value)))}}),me("button",{type:"button",className:"bb-numberStepper-btn",disabled:o,onClick:()=>k(1),"aria-label":`Increase ${e}`,title:`Increase ${e}`,children:me(eu,{size:12})})]})]})}function kn({label:e,value:n,options:i,onChange:r}){return kt("div",{className:"bb-field",children:[me("label",{className:"bb-label",children:e}),me("select",{className:"bb-select",value:n,onChange:t=>r(t.target.value),children:i.map(t=>me("option",{value:t,children:t},t))})]})}function be({label:e,value:n,min:i,max:r,step:t,onChange:o}){return kt("div",{className:"bb-field bb-field--full",children:[me("label",{className:"bb-label",children:e}),kt("div",{className:"bb-sliderField",children:[me("input",{className:`bb-slider ${n===void 0?"bb-slider--unset":""}`,type:"range",min:i,max:r,step:t,value:n??i,onChange:l=>o(Number(l.target.value))}),me("input",{className:"bb-input bb-input--compact",type:"number",min:i,max:r,step:t,value:n??"",onChange:l=>o(l.target.value===""?void 0:Number(l.target.value))})]})]})}import{Fragment as al,jsx as D,jsxs as Ce}from"react/jsx-runtime";var ol="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 il({selectedItem:e,selectedMaterial:n,pbrWorkflow:i,onPbrWorkflowChange:r,openMaterialPanels:t,materialPanelEnabled:o,onToggleMaterialPanel:d,onSetMaterialPanelState:l,updateSelectedMaterial:b,setSelectedTexturePath:k,isTexturePositioningEnabled:M,onConfirmTexturePosition:w,takesImage:p=!0}){let h={openMaterialPanels:t,materialPanelEnabled:o,onToggleMaterialPanel:d,onSetMaterialPanelState:l},{tier:S}=yt(),C=ct(S,"starter"),g={tier:"starter",locked:!C},[c,f]=nl("roughness"),[x,N]=nl("factor"),O=(a,u)=>{b(e,L=>{if(!L?.texture?.path)return L??{};let P=L.texture.offset??[0,0],H=[P[0],P[1]];return H[a]=u,{...L,texture:{...L.texture,offset:H}}})},T=a=>{b(e,u=>{if(!u?.texture?.path)return u??{};let L=(a%360+360)%360;return{...u,texture:{...u.texture,rotation:L*Math.PI/180}}})},B=()=>{k(e,"texture","")};return Ce(_a.Provider,{value:p?null:ol,children:[p?null:D("p",{className:"bb-note bb-materialNotice",children:ol}),D(Xe,{panelKey:"pbr",title:"PBR Maps",tooltip:"Controls the base color and workflow used for physically based shading.",controls:h,children:C?Ce("div",{className:"bb-grid",children:[D(kn,{label:"Workflow",value:i,options:["metalness","specular"],onChange:r}),D("div",{className:"bb-field bb-field--full",children:D("p",{className:"bb-note",style:{margin:0},children:i==="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."})}),D(Ae,{label:i==="specular"?"Albedo texture path":"Base color texture path",placeholder:"materials/oak-wood.jpg",value:n?.texture?.path??"",onChange:a=>k(e,"texture",a)}),n?.texture?.path?Ce("div",{className:"bb-field bb-field--full",children:[Ce("div",{className:"bb-fieldLabel",style:{display:"flex",alignItems:"center",justifyContent:"space-between"},children:[D("span",{className:"bb-label",children:"Texture position"}),Ce("button",{type:"button",className:"bb-button bb-button--ghost",onClick:B,title:"Remove the base color texture and its position offset",children:[D(nu,{size:14,style:{marginRight:4,verticalAlign:"-2px"}}),"Remove texture"]})]}),Ce("div",{className:"bb-grid",style:{marginTop:6},children:[D(Ka,{label:"Offset X",value:n?.texture?.offset?.[0]??0,step:.01,onChange:a=>O(0,a)}),D(Ka,{label:"Offset Y",value:n?.texture?.offset?.[1]??0,step:.01,onChange:a=>O(1,a)})]}),D(be,{label:"Rotation",value:((n?.texture?.rotation??0)*180/Math.PI%360+360)%360,min:0,max:360,step:1,onChange:a=>T(a??0)}),M?D("button",{type:"button",className:"bb-button bb-button--primary",style:{marginTop:8},onClick:w,title:"Confirm this texture position and exit positioning mode",children:"Done positioning"}):D("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,D(Dt,{label:i==="specular"?"Albedo color":"Base color",value:n?.baseColor??"#ffffff",onChange:a=>b(e,u=>({...u,baseColor:a}))}),i==="metalness"?Ce(al,{children:[D(be,{label:"Metalness",value:n?.metalness,min:0,max:1,step:.01,onChange:a=>b(e,u=>({...u,metalness:a}))}),D(Ae,{label:"Metalness map path",placeholder:"materials/body-metalness.jpg",value:n?.metalnessMap?.path??"",onChange:a=>k(e,"metalnessMap",a)})]}):Ce(al,{children:[D(be,{label:"Specular intensity",value:n?.specularIntensity,min:0,max:1,step:.01,onChange:a=>b(e,u=>({...u,specularIntensity:a}))}),D(Dt,{label:"Specular color",value:n?.specularColor??"#ffffff",onChange:a=>b(e,u=>({...u,specularColor:a}))}),D(Ae,{label:"Specular intensity map path",placeholder:"materials/body-specular-intensity.jpg",value:n?.specularIntensityMap?.path??"",onChange:a=>k(e,"specularIntensityMap",a)}),D(Ae,{label:"Specular color map path",placeholder:"materials/body-specular-color.jpg",value:n?.specularColorMap?.path??"",onChange:a=>k(e,"specularColorMap",a)})]}),D(be,{label:"Specular F0 / reflectivity",value:n?.reflectivity,min:0,max:1,step:.01,onChange:a=>b(e,u=>({...u,reflectivity:a}))})]}):Ce("div",{className:"bb-grid",children:[D(Dt,{label:"Base color",value:n?.baseColor??"#ffffff",onChange:a=>b(e,u=>({...u,baseColor:a}))}),D(be,{label:"Metalness",value:n?.metalness,min:0,max:1,step:.01,onChange:a=>b(e,u=>({...u,metalness:a}))}),D("div",{className:"bb-field bb-field--full",children:D(ze,{requiredTier:"starter",feature:"Texture maps, the specular workflow, and reflectivity"})})]})}),D(Xe,{panelKey:"roughness",requiredTier:g,title:"Roughness / Glossiness",tooltip:"Adjusts how matte or shiny the surface appears.",toggleLabel:"Toggle Roughness and Glossiness",controls:h,children:Ce("div",{className:"bb-grid",children:[D(kn,{label:"Mode",value:c,options:["roughness","glossiness"],onChange:f}),D("div",{className:"bb-field bb-field--full",children:D("p",{className:"bb-note",style:{margin:0},children:c==="roughness"?"Roughness: 0 is glossy, 1 is matte.":"Glossiness is the inverse of roughness (glossiness = 1 \u2212 roughness)"})}),c==="roughness"?D(be,{label:"Roughness",value:n?.roughness,min:0,max:1,step:.01,onChange:a=>b(e,u=>({...u,roughness:a}))}):D(be,{label:"Glossiness",value:n?.roughness===void 0?void 0:1-n.roughness,min:0,max:1,step:.01,onChange:a=>b(e,u=>({...u,roughness:a===void 0?void 0:1-a}))}),D(Ae,{label:c==="glossiness"?"Glossiness map path (applied as roughness)":"Roughness map path",placeholder:"materials/body-roughness.jpg",value:n?.roughnessMap?.path??"",onChange:a=>k(e,"roughnessMap",a)})]})}),D(Xe,{panelKey:"emission",requiredTier:g,title:"Emission",tooltip:"Makes the material self-illuminated with emissive color and intensity.",controls:h,children:Ce("div",{className:"bb-grid",children:[D(Dt,{label:"Emissive color",value:n?.emissive??"#000000",fallback:"#000000",onChange:a=>b(e,u=>({...u,emissive:a}))}),D(be,{label:"Emissive intensity",value:n?.emissiveIntensity,min:0,max:10,step:.1,onChange:a=>b(e,u=>({...u,emissiveIntensity:a}))}),D(Ae,{label:"Emissive map path",placeholder:"materials/body-emissive.jpg",value:n?.emissiveMap?.path??"",onChange:a=>k(e,"emissiveMap",a)})]})}),D(Xe,{panelKey:"opacity",requiredTier:g,title:"Opacity",tooltip:"Controls transparency, alpha testing, and blending behavior.",controls:h,children:Ce("div",{className:"bb-grid",children:[D(be,{label:"Opacity",value:n?.opacity,min:0,max:1,step:.01,onChange:a=>b(e,u=>({...u,opacity:a}))}),D(be,{label:"Alpha test",value:n?.alphaTest,min:0,max:1,step:.01,onChange:a=>b(e,u=>({...u,alphaTest:a}))}),D(Ae,{label:"Alpha map path",placeholder:"materials/body-alpha.png",value:n?.alphaMap?.path??"",onChange:a=>k(e,"alphaMap",a)}),D(kn,{label:"Blending mode",value:n?.blendingMode??"normal",options:Fr,onChange:a=>b(e,u=>({...u,blendingMode:a}))}),Ce("div",{className:"bb-field",children:[D("label",{className:"bb-label",children:"Alpha hash"}),D("div",{className:"bb-checkboxRow",children:D(Zn,{label:"Use alpha hash",checked:n?.alphaHash??!1,onChange:a=>b(e,u=>({...u,alphaHash:a}))})})]}),Ce("div",{className:"bb-field",children:[D("label",{className:"bb-label",children:"Dithering"}),D("div",{className:"bb-checkboxRow",children:D(Zn,{label:"Use dithering",checked:n?.dithering??!1,onChange:a=>b(e,u=>({...u,dithering:a}))})})]})]})}),Ce(Xe,{panelKey:"normalBump",requiredTier:g,title:"Normal & Bump",tooltip:"Adds surface detail without changing the actual mesh shape.",toggleLabel:"Toggle Normal and Bump",controls:h,children:[Ce("div",{className:"bb-grid",children:[D(Ae,{label:"Normal map path",placeholder:"materials/body-normal.jpg",value:n?.normalMap?.path??"",onChange:a=>k(e,"normalMap",a)}),D(be,{label:"Normal scale",value:n?.normalScale,min:0,max:5,step:.01,onChange:a=>b(e,u=>({...u,normalScale:a}))}),D(Ae,{label:"Bump map path",placeholder:"materials/body-bump.jpg",value:n?.bumpMap?.path??"",onChange:a=>k(e,"bumpMap",a)}),D(be,{label:"Bump scale",value:n?.bumpScale,min:0,max:5,step:.01,onChange:a=>b(e,u=>({...u,bumpScale:a}))})]}),D("div",{className:"bb-checkboxRow",style:{marginTop:12},children:D(Zn,{label:"Flip normal Y",checked:n?.flipNormalY??!1,onChange:a=>b(e,u=>({...u,flipNormalY:a}))})})]}),D(Xe,{panelKey:"displacement",requiredTier:g,title:"Displacement",tooltip:"Offsets geometry using a texture to create real surface height.",controls:h,children:Ce("div",{className:"bb-grid",children:[D(Ae,{label:"Displacement map path",placeholder:"materials/body-displacement.jpg",value:n?.displacementMap?.path??"",onChange:a=>k(e,"displacementMap",a)}),D(be,{label:"Displacement scale",value:n?.displacementScale,min:-5,max:5,step:.01,onChange:a=>b(e,u=>({...u,displacementScale:a}))}),D(be,{label:"Displacement bias",value:n?.displacementBias,min:-5,max:5,step:.01,onChange:a=>b(e,u=>({...u,displacementBias:a}))})]})}),D(Xe,{panelKey:"ao",requiredTier:g,title:"Ambient Occlusion",tooltip:"Darkens creases and contact areas to add depth.",controls:h,children:Ce("div",{className:"bb-grid",children:[D(Ae,{label:"AO map path",placeholder:"materials/body-ao.jpg",value:n?.aoMap?.path??"",onChange:a=>k(e,"aoMap",a)}),D(be,{label:"AO intensity",value:n?.aoMapIntensity,min:0,max:5,step:.01,onChange:a=>b(e,u=>({...u,aoMapIntensity:a}))})]})}),Ce(Xe,{panelKey:"clearcoat",requiredTier:g,title:"Clearcoat",tooltip:"Adds a glossy protective layer on top of the base material.",controls:h,children:[Ce("div",{className:"bb-grid",children:[D(Ae,{label:"Clearcoat map path",placeholder:"materials/body-clearcoat.jpg",value:n?.clearcoatMap?.path??"",onChange:a=>k(e,"clearcoatMap",a)}),D(be,{label:"Clearcoat",value:n?.clearcoat,min:0,max:1,step:.01,onChange:a=>b(e,u=>({...u,clearcoat:a}))}),D(Ae,{label:"Clearcoat roughness map path",placeholder:"materials/body-clearcoat-roughness.jpg",value:n?.clearcoatRoughnessMap?.path??"",onChange:a=>k(e,"clearcoatRoughnessMap",a)}),D(be,{label:"Clearcoat roughness",value:n?.clearcoatRoughness,min:0,max:1,step:.01,onChange:a=>b(e,u=>({...u,clearcoatRoughness:a}))}),D(Ae,{label:"Clearcoat normal map path",placeholder:"materials/body-clearcoat-normal.jpg",value:n?.clearcoatNormalMap?.path??"",onChange:a=>k(e,"clearcoatNormalMap",a)}),D(be,{label:"Clearcoat normal scale",value:n?.clearcoatNormalScale,min:0,max:5,step:.01,onChange:a=>b(e,u=>({...u,clearcoatNormalScale:a}))})]}),D("div",{className:"bb-checkboxRow",style:{marginTop:12},children:D(Zn,{label:"Flip clearcoat normal Y",checked:n?.flipClearcoatNormalY??!1,onChange:a=>b(e,u=>({...u,flipClearcoatNormalY:a}))})})]}),D(Xe,{panelKey:"sheen",requiredTier:g,title:"Sheen",tooltip:"Adds a soft fabric-like sheen on grazing angles.",controls:h,children:Ce("div",{className:"bb-grid",children:[D(be,{label:"Sheen",value:n?.sheen,min:0,max:1,step:.01,onChange:a=>b(e,u=>({...u,sheen:a}))}),D(Dt,{label:"Sheen color",value:n?.sheenColor??"#ffffff",onChange:a=>b(e,u=>({...u,sheenColor:a}))}),D(Ae,{label:"Sheen color map path",placeholder:"materials/body-sheen-color.jpg",value:n?.sheenColorMap?.path??"",onChange:a=>k(e,"sheenColorMap",a)}),D(be,{label:"Sheen roughness",value:n?.sheenRoughness,min:0,max:1,step:.01,onChange:a=>b(e,u=>({...u,sheenRoughness:a}))}),D(Ae,{label:"Sheen roughness map path",placeholder:"materials/body-sheen-roughness.jpg",value:n?.sheenRoughnessMap?.path??"",onChange:a=>k(e,"sheenRoughnessMap",a)})]})}),D(Xe,{panelKey:"anisotropy",requiredTier:g,title:"Anisotropy",tooltip:"Stretches reflections in one direction for brushed or fiber-like surfaces.",controls:h,children:Ce("div",{className:"bb-grid",children:[D(be,{label:"Intensity",value:n?.anisotropy,min:0,max:1,step:.01,onChange:a=>b(e,u=>({...u,anisotropy:a}))}),D(kn,{label:"Tilt direction",value:x,options:["factor","texture"],onChange:N}),x==="factor"?D(be,{label:"Rotation (rad)",value:n?.anisotropyRotation,min:0,max:6.28,step:.01,onChange:a=>b(e,u=>({...u,anisotropyRotation:a}))}):D(Ae,{label:"Anisotropy map path",placeholder:"materials/body-anisotropy.jpg",value:n?.anisotropyMap?.path??"",onChange:a=>k(e,"anisotropyMap",a)})]})}),D(Xe,{panelKey:"transmission",requiredTier:g,title:"Transmission & Volume",tooltip:"Controls glass-like transmission and how light travels through volume.",toggleLabel:"Toggle Transmission and Volume",controls:h,children:Ce("div",{className:"bb-grid",children:[D(be,{label:"Transmission",value:n?.transmission,min:0,max:1,step:.01,onChange:a=>b(e,u=>({...u,transmission:a}))}),D(Ae,{label:"Transmission map path",placeholder:"materials/body-transmission.jpg",value:n?.transmissionMap?.path??"",onChange:a=>k(e,"transmissionMap",a)}),D(be,{label:"Thickness",value:n?.thickness,min:0,max:5,step:.01,onChange:a=>b(e,u=>({...u,thickness:a}))}),D(Ae,{label:"Thickness map path",placeholder:"materials/body-thickness.jpg",value:n?.thicknessMap?.path??"",onChange:a=>k(e,"thicknessMap",a)}),D(Dt,{label:"Volume tint",value:n?.attenuationColor??"#ffffff",onChange:a=>b(e,u=>({...u,attenuationColor:a}))}),D(tl,{label:"Attenuation distance",value:n?.attenuationDistance,min:0,step:.01,placeholder:"Infinity when unset",onChange:a=>b(e,u=>({...u,attenuationDistance:a}))})]})}),D(Xe,{panelKey:"faces",requiredTier:g,title:"Faces Rendering",tooltip:"Chooses which side of the mesh renders and how backfaces are handled.",controls:h,children:D("div",{className:"bb-grid",children:D(kn,{label:"Side",value:n?.side??"front",options:Ir,onChange:a=>b(e,u=>({...u,side:a}))})})})]})}import{Ban as iu}from"lucide-react";var $o="default",Wa=[{id:$o,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}}],ou=Array.from(new Set(Wa.flatMap(e=>Object.keys(e.material)))),au=Object.fromEntries(ou.map(e=>[e,void 0]));function rl(e){return e.id===$o?au:e.material}import{jsx as Vo,jsxs as ru}from"react/jsx-runtime";function sl({disabled:e,onApply:n}){return Vo("div",{className:"bb-presetGallery",children:Wa.map(i=>ru("button",{type:"button",className:"bb-presetSwatch",disabled:e,title:`Apply ${i.label} preset`,onClick:()=>n(rl(i)),children:[Vo("span",{className:"bb-presetSwatchColor",style:{background:i.swatch,display:"flex",alignItems:"center",justifyContent:"center"},children:i.id===$o?Vo(iu,{size:28,strokeWidth:2,color:"#ffffff"}):null}),Vo("span",{className:"bb-presetSwatchLabel",children:i.label})]},i.id))})}import{jsx as ln,jsxs as Ya}from"react/jsx-runtime";function ll({selectedItem:e,selectedBinding:n,open:i,onToggle:r,updateBinding:t,idError:o}){return ln(Ee,{title:"Identity",open:i,onToggle:r,children:Ya("div",{className:"bb-grid",children:[Ya("div",{className:"bb-field bb-field--full",children:[ln("label",{className:"bb-label",children:"Model Node ID"}),ln("span",{className:"bb-note",children:"This is the exact mesh name from the imported model and stays locked."}),ln("input",{className:"bb-input bb-readonly",value:n.modelObjectId,readOnly:!0})]}),Ya("div",{className:"bb-field bb-field--full",children:[ln("label",{className:"bb-label",children:"ID"}),ln("input",{className:`bb-input ${o?"bb-input--error":""}`,value:n.id,onChange:d=>t(e,l=>({...l,id:d.target.value}))}),o?ln("span",{className:"bb-status bb-status--error",children:o}):null]})]})})}import{useEffect as su,useState as dl}from"react";import{jsx as $e,jsxs as bt}from"react/jsx-runtime";function cl({selectedItem:e,selectedBinding:n,open:i,onToggle:r,updateBinding:t}){let[o,d]=dl(n.group??""),[l,b]=dl(n.tags?.join(", ")??"");su(()=>{d(n.group??""),b(n.tags?.join(", ")??"")},[e,n.group,n.tags]);let k=()=>{t(e,w=>({...w,group:o.trim()||void 0}))},M=()=>{let w=[...new Set(l.split(",").map(p=>p.trim()).filter(Boolean))];t(e,p=>({...p,tags:w.length>0?w:void 0}))};return bt(Ee,{title:"Basics",open:i,onToggle:r,children:[bt("div",{className:"bb-grid",children:[bt("div",{className:"bb-field",children:[$e("label",{className:"bb-label",children:"Label"}),$e("input",{className:"bb-input",value:n.label??"",onChange:w=>t(e,p=>({...p,label:w.target.value}))})]}),bt("div",{className:"bb-field",children:[$e("label",{className:"bb-label",children:"Type"}),$e("input",{className:"bb-input",list:"binding-type-suggestions",value:n.type??"other",onChange:w=>t(e,p=>({...p,type:w.target.value}))}),$e("datalist",{id:"binding-type-suggestions",children:$s.map(w=>$e("option",{value:w},w))})]}),bt("div",{className:"bb-field",children:[$e("label",{className:"bb-label",children:"Status"}),$e("select",{className:"bb-select",value:n.status??"normal",onChange:w=>t(e,p=>({...p,status:w.target.value})),children:Ho.map(w=>$e("option",{value:w,children:w},w))})]}),bt("div",{className:"bb-field",children:[$e("label",{className:"bb-label",children:"Group"}),$e("input",{className:"bb-input",placeholder:"paint",value:o,onChange:w=>d(w.target.value),onBlur:k,onKeyDown:w=>{w.key==="Enter"&&w.currentTarget.blur()}})]}),bt("div",{className:"bb-field",children:[$e("label",{className:"bb-label",children:"Tags"}),$e("input",{className:"bb-input",placeholder:"exterior, configurable",value:l,onChange:w=>b(w.target.value),onBlur:M,onKeyDown:w=>{w.key==="Enter"&&w.currentTarget.blur()}})]})]}),bt("div",{className:"bb-checkboxRow",style:{marginTop:12},children:[bt("label",{className:"bb-checkbox",children:[$e("input",{type:"checkbox",checked:n.selectable??!1,onChange:w=>t(e,p=>({...p,selectable:w.target.checked}))}),"selectable"]}),bt("label",{className:"bb-checkbox",children:[$e("input",{type:"checkbox",checked:n.hoverable??!1,onChange:w=>t(e,p=>({...p,hoverable:w.target.checked}))}),"hoverable"]}),bt("label",{className:"bb-checkbox",children:[$e("input",{type:"checkbox",checked:n.visible??!1,onChange:w=>t(e,p=>({...p,visible:w.target.checked}))}),"visible"]})]})]})}import{useEffect as lu,useState as du}from"react";import{Fragment as bu,jsx as Te,jsxs as nt}from"react/jsx-runtime";var bl=xa.filter(e=>e.handling==="viewer"),cu=xa.filter(e=>e.handling==="host");function pl({selectedItem:e,selectedBinding:n,open:i,onToggle:r,updateBinding:t,takesImage:o=!0}){let[d,l]=du(new Set);lu(()=>{l(new Set)},[e]);let b=n.actions??[],k=(p,h)=>t(e,S=>({...S,actions:(S.actions??[]).map((C,g)=>g===p?h(C):C)})),M=p=>{t(e,h=>({...h,actions:(h.actions??[]).filter((S,C)=>C!==p)})),l(h=>{let S=new Set;return h.forEach(C=>{C<p?S.add(C):C>p&&S.add(C-1)}),S})},w=(p,h)=>l(S=>{let C=new Set(S);return h?C.add(p):C.delete(p),C});return nt(Ee,{title:"Actions",open:i,onToggle:r,children:[Te("div",{className:"bb-actionList",children:b.map((p,h)=>{let S=Po(p.id),C=d.has(h)||!S,g=p.id.trim(),c=S?null:ar(p.id),f=g.length>0&&b.some((x,N)=>N!==h&&x.id.trim()===g);return nt("div",{className:"bb-actionCard",children:[nt("div",{className:"bb-actionCardHeader",children:[nt("div",{className:"bb-actionCardTitle",children:["Action ",h+1]}),Te("div",{className:"bb-actionCardMeta",children:p.type})]}),nt("div",{className:"bb-actionGrid",children:[nt("div",{className:"bb-field",children:[Te("label",{className:"bb-label",children:"Action ID"}),nt("select",{className:"bb-select",value:C?To:p.id,onChange:x=>{let N=x.target.value;if(N===To){w(h,!0);return}w(h,!1);let O=Po(N);k(h,T=>({...T,id:N,label:O&&va(T.label)?O.label:T.label}))},children:[Te("optgroup",{label:"Handled by the viewer",children:bl.map(x=>Te("option",{value:x.id,children:x.id},x.id))}),Te("optgroup",{label:"Handled by your app",children:cu.map(x=>Te("option",{value:x.id,children:x.id},x.id))}),Te("option",{value:To,children:"Custom\u2026"})]})]}),C?nt("div",{className:"bb-field",children:[Te("label",{className:"bb-label",children:"Custom action ID"}),Te("input",{className:"bb-input",value:p.id,placeholder:"open-datasheet",onChange:x=>{w(h,!0),k(h,N=>({...N,id:x.target.value}))}})]}):null,nt("div",{className:"bb-field",children:[Te("label",{className:"bb-label",children:"Label"}),Te("input",{className:"bb-input",value:p.label,onChange:x=>k(h,N=>({...N,label:x.target.value}))})]}),S?.id==="change-material"&&!o?Te("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."}):S?Te("span",{className:"bb-note",children:S.description}):g.length===0?Te("span",{className:"bb-note",style:{color:"#fca5a5"},children:"An action ID is required, the button renders but can never be identified in onAction."}):nt("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.",c?nt(bu,{children:[" Did you mean ",Te("button",{type:"button",className:"bb-linkButton",onClick:()=>{w(h,!1);let x=Po(c);k(h,N=>({...N,id:c,label:x&&va(N.label)?x.label:N.label}))},children:c}),"?"]}):null]}),p.effects?.length?nt("span",{className:"bb-note",children:[p.effects.length," declarative effect",p.effects.length===1?"":"s",", execute with useViewerActions."]}):null,f?Te("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]}),Te("div",{className:"bb-actionFooter",children:Te("button",{type:"button",className:"bb-button bb-button--ghost bb-actionRemove",onClick:()=>M(h),children:"Remove Action"})})]},h)})}),Te("div",{style:{marginTop:10},children:Te("button",{type:"button",className:"bb-button",onClick:()=>{let p=bl.find(h=>!b.some(S=>S.id===h.id));t(e,h=>({...h,actions:[...h.actions??[],{id:p?.id??"",label:p?.label??"New Action",type:"command"}]})),p||w(b.length,!0)},children:"Add Action"})})]})}import{useRef as pu}from"react";import{ImagePlus as uu,Trash2 as mu,Type as gu}from"lucide-react";import{Fragment as ml,jsx as Oe,jsxs as pt}from"react/jsx-runtime";var ul=()=>`decal-${Date.now().toString(36)}-${Math.random().toString(36).slice(2,8)}`;function gl({selectedItem:e,selectedBinding:n,open:i,onToggle:r,updateBinding:t,placement:o,onPlacementChange:d,defaultSize:l,onImageFile:b,onNudge:k}){let{tier:M}=yt(),w=pu(null),p=n.decals??[],h=o?.nodeKey===e?o:null,S=c=>t(e,f=>({...f,decals:c.length>0?c:void 0})),C=(c,f)=>S(p.map(x=>x.id===c?{...x,...f}:x)),g=c=>{c.image&&In(c.image),h?.decal.id===c.id&&d(null),S(p.filter(f=>f.id!==c.id))};return Oe(Ee,{title:"Decals",open:i,onToggle:r,tooltip:"Print a logo, image, or text on the selected object's surface.",children:ct(M,"starter")?pt(ml,{children:[pt("div",{className:"bb-decalActions",children:[pt("button",{type:"button",className:"bb-button bb-button--ghost",onClick:()=>w.current?.click(),children:[Oe(uu,{size:15})," Add image"]}),pt("button",{type:"button",className:"bb-button bb-button--ghost",onClick:()=>d({nodeKey:e,decal:{id:ul(),text:"Your text",color:"#ffffff",size:l}}),children:[Oe(gu,{size:15})," Add text"]}),Oe("input",{ref:w,type:"file",accept:"image/png,image/jpeg,image/webp,image/avif,image/svg+xml",className:"bb-hiddenInput",onChange:c=>{let f=c.target.files?.[0];if(c.target.value="",!f)return;let x=Bo(f);tn(x,URL.createObjectURL(f)),b?.(x,f),d({nodeKey:e,decal:{id:ul(),image:x,size:l}})}})]}),p.length===0&&!h?Oe("div",{className:"bb-decalEmpty",children:"No decals on this object yet."}):null,p.map(c=>pt("div",{className:"bb-decalCard",children:[pt("div",{className:"bb-decalCardHeader",children:[Oe("span",{className:"bb-decalKind",children:c.image?"Image":"Text"}),Oe("span",{className:"bb-decalName",title:c.image??c.text,children:c.image??c.text}),Oe("button",{type:"button",className:"bb-iconButton bb-iconButton--danger",title:"Delete decal","aria-label":"Delete decal",onClick:()=>g(c),children:Oe(mu,{size:15})})]}),Oe(ir,{onNudge:f=>k(c.id,f)}),pt("div",{className:"bb-grid",children:[c.image?null:pt(ml,{children:[pt("div",{className:"bb-field bb-field--full",children:[Oe("label",{className:"bb-label",children:"Text"}),Oe("input",{className:"bb-input",value:c.text??"",onChange:f=>C(c.id,{text:f.target.value})})]}),Oe(Dt,{label:"Colour",variant:"input",value:c.color??"#ffffff",onChange:f=>C(c.id,{color:f})}),pt("div",{className:"bb-field",children:[Oe("label",{className:"bb-label",children:"Weight"}),pt("select",{className:"bb-input bb-decalWeight",value:c.fontWeight??"bold",onChange:f=>C(c.id,{fontWeight:f.target.value}),children:[Oe("option",{value:"bold",children:"Bold"}),Oe("option",{value:"normal",children:"Regular"})]})]})]}),Oe(be,{label:"Size",value:Number(c.size.toFixed(4)),min:Number((l/20).toPrecision(2)),max:Number((l*6).toPrecision(2)),step:Number((l/50).toPrecision(1)),onChange:f=>f!==void 0&&f>0&&C(c.id,{size:f})}),Oe(be,{label:"Rotation (\xB0)",value:Math.round((c.rotation??0)*180/Math.PI),min:-180,max:180,step:1,onChange:f=>C(c.id,{rotation:(f??0)*Math.PI/180})}),Oe(be,{label:"Opacity",value:c.opacity??1,min:0,max:1,step:.05,onChange:f=>C(c.id,{opacity:f??1})})]})]},c.id))]}):Oe(ze,{requiredTier:"starter",feature:"Decals"})})}import{MapPin as fu,Trash2 as hu}from"lucide-react";import{Fragment as xu,jsx as ot,jsxs as Ze}from"react/jsx-runtime";function fl({selectedBinding:e,open:n,onToggle:i,cameraState:r,formattedCameraState:t,savedCameraPosition:o,onSaveCameraPosition:d,onGoToSavedCamera:l,onClearSavedCamera:b,onResetView:k,onFitScene:M}){return Ze(Ee,{title:"Camera Position",open:n,onToggle:i,children:[Ze("div",{className:"se-waypointCard bb-cameraWaypoint",children:[ot("span",{className:"bb-cameraLiveBadge",children:"LIVE"}),Ze("div",{className:"se-waypointBody",children:[ot("div",{className:"bb-cameraWaypointLabel",children:"Current view"}),r?Ze(xu,{children:[Ze("div",{className:"se-waypointCoords",children:["pos ",t?.position]}),Ze("div",{className:"se-waypointCoords",children:["look ",t?.target]})]}):ot("div",{className:"se-waypointCoords",children:"Move the camera to see live position"})]})]}),Ze("div",{className:"bb-cameraControls bb-cameraControls--centered",children:[ot("button",{type:"button",className:"bb-button bb-button--primary",onClick:d,disabled:!r,children:"Save"}),ot("button",{type:"button",className:"bb-button bb-button--ghost",onClick:k,children:"Reset View"}),ot("button",{type:"button",className:"bb-button bb-button--ghost",onClick:M,children:"Fit Scene"})]}),o?.position&&o?.target&&Ze("div",{className:"se-waypointCard bb-cameraWaypoint",children:[ot("span",{className:"bb-cameraSavedBadge",children:"SAVED"}),Ze("div",{className:"se-waypointBody",children:[Ze("div",{className:"bb-cameraWaypointLabel",children:["For ",e.label]}),Ze("div",{className:"se-waypointCoords",children:["pos [",o.position.map(w=>w.toFixed(1)).join(", "),"]"]}),Ze("div",{className:"se-waypointCoords",children:["look [",o.target.map(w=>w.toFixed(1)).join(", "),"]"]})]}),Ze("div",{className:"se-waypointActions",children:[ot("button",{className:"se-waypointAction",onClick:l,title:"Fly camera to the saved position",children:ot(fu,{size:15})}),ot("button",{className:"se-waypointAction se-waypointAction--delete",onClick:b,title:"Delete saved position",children:ot(hu,{size:15})})]})]}),ot("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 vu,useRef as yu,useState as wu}from"react";import{Maximize2 as Su,Move3d as Cu,RotateCcw as ku}from"lucide-react";import{Fragment as Ru,jsx as se,jsxs as Ie}from"react/jsx-runtime";var xl=["X","Y","Z"],Mu=.1,Nu=.1,hl=.01;function vl(e){let n=e%360;return n<0?n+360:n}function Tu(e){return vl(e*180/Math.PI)}function Pu(e){return e*Math.PI/180}function qa({value:e,min:n=-1/0,max:i=1/0,step:r=.1,disabled:t=!1,onChange:o,formatValue:d=k=>Number(k.toFixed(3)),ariaLabel:l,className:b}){let k=d(e),[M,w]=wu(String(k)),p=yu(!1);return vu(()=>{p.current||w(String(k))},[k]),se("input",{type:"number",className:b,step:r,min:n===-1/0?void 0:n,max:i===1/0?void 0:i,value:M,disabled:t,"aria-label":l,onFocus:()=>{p.current=!0},onChange:h=>{let S=h.target.value;if(w(S),S===""||S==="-")return;let C=Number(S);if(Number.isFinite(C)){let g=Math.max(n,Math.min(i,C));o(g)}},onBlur:()=>{p.current=!1,w(String(d(e)))}})}function Bu({value:e,min:n=-1/0,max:i=1/0,step:r=.1,disabled:t=!1,onChange:o,formatValue:d=b=>Number(b.toFixed(3)),label:l}){return se("div",{className:"bb-transformAxesGrid",children:xl.map((b,k)=>Ie("div",{className:"bb-transformAxis",children:[se("span",{className:"se-axisStepperLabel bb-transformAxisLabel",children:b}),se("div",{className:"bb-transformAxisControl",children:se(qa,{className:"se-numberInput bb-transformNumberInput",step:r,min:n,max:i,value:e[k],disabled:t,formatValue:d,ariaLabel:`${b} ${l?.toLowerCase()||""}`,onChange:M=>{let w=[...e];w[k]=M,o(w,k)}})})]},b))})}function yl({selectedItem:e,selectedBinding:n,open:i,onToggle:r,updateBinding:t,moveModeEnabled:o,onToggleMoveMode:d,scaleModeEnabled:l,onToggleScaleMode:b,transformSpace:k,onTransformSpaceChange:M,originalTransform:w,originalTransforms:p}){let h=n.transform?.rotation??w?.rotation??[0,0,0],S=n.transform?.position??w?.position??[0,0,0],C=w?.scale??[1,1,1],g=wa(n.transform?.scale??C,C),c=(B=e??"")=>p?.[B]??(B===e?w:null),f=(B,a)=>B.transform?.pivot??wr(a?.pivotLocal??[0,0,0],B.transform?.rotation??a?.rotation??[0,0,0],B.transform?.scale??a?.scale??[1,1,1],a?.rotationOrder??"XYZ",B.transform?.shear),x=(B,a)=>{e&&t(e,(u,L)=>{let P=c(L),q=[...u.transform?.rotation??P?.rotation??[0,0,0]];return q[B]=Pu(vl(a)),{...u,transform:{...u.transform,rotation:q,pivot:f(u,P)}}})},N=(B,a)=>{e&&t(e,(u,L)=>{let P=c(L),q=[...u.transform?.position??P?.position??[0,0,0]];return q[B]=a,{...u,transform:{...u.transform,position:q}}})},O=B=>{if(!e)return;let a=Math.max(hl,B);t(e,(u,L)=>{let P=c(L),H=P?.scale??[1,1,1],q=u.transform?.scale??H,Ke=wa(q,H),Le=Ke>0?q:H,Qe=a/(Ke||1);return{...u,transform:{...u.transform,scale:Le.map(cn=>cn*Qe),pivot:f(u,P)}}})},T=()=>{!e||!w||t(e,B=>{let a={...B.transform};return delete a.position,delete a.rotation,delete a.scale,delete a.pivot,delete a.shear,{...B,transform:Object.keys(a).length>0?a:void 0}})};return Ie(Ee,{title:"Move, Rotate & Scale",open:i,onToggle:r,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:[Ie("div",{className:"se-field",children:[Ie("div",{className:"se-fieldLabel",children:[Ie("span",{children:[se(Cu,{size:14,style:{marginRight:6,verticalAlign:"-2px"}}),"Transform Gizmo"]}),Ie("label",{className:"se-switch","aria-label":"Toggle transform gizmo",children:[se("input",{type:"checkbox",checked:o,onChange:B=>d(B.target.checked)}),se("span",{className:"se-switchTrack",children:se("span",{className:"se-switchThumb"})})]})]}),se("span",{className:"bb-note",children:"Select a mesh \xB7 drag the colored arrows or planes to move"})]}),Ie("div",{className:"se-field",style:{marginTop:10},children:[se("div",{className:"se-fieldLabel",children:se("span",{children:"Axis space"})}),se("div",{className:"se-segmentedControl",children:["world","local"].map(B=>se("button",{type:"button",className:`se-segmentedOption ${k===B?"se-segmentedOption--active":""}`,onClick:()=>M(B),children:B},B))})]}),Ie("div",{className:"se-field",style:{marginTop:10},children:[se("div",{className:"se-fieldLabel",children:se("span",{children:"Rotation (degrees)"})}),se("div",{className:"bb-transformAxesGrid",children:xl.map((B,a)=>{let u=Math.round(Tu(h[a]));return Ie("div",{className:"bb-transformAxis",children:[se("span",{className:"se-axisStepperLabel bb-transformAxisLabel",children:B}),se("div",{className:"bb-transformAxisControl",children:se(qa,{className:"se-numberInput bb-transformNumberInput",step:1,min:0,max:359,value:u,disabled:!e,formatValue:L=>Math.round(L),ariaLabel:`${B} rotation in degrees`,onChange:L=>x(a,L)})})]},B)})})]}),Ie("div",{className:"se-field",style:{marginTop:10},children:[se("div",{className:"se-fieldLabel",children:se("span",{children:"Position"})}),se(Bu,{value:S,min:-1/0,max:1/0,step:Mu,disabled:!e,label:"position",onChange:(B,a)=>N(a,B[a])})]}),Ie("div",{className:"se-field",style:{marginTop:10},children:[Ie("div",{className:"se-fieldLabel",children:[Ie("span",{children:[se(Su,{size:14,style:{marginRight:6,verticalAlign:"-2px"}}),"Scale"]}),Ie("label",{className:"se-switch","aria-label":"Toggle scale controls",children:[se("input",{type:"checkbox",checked:l,onChange:B=>b(B.target.checked)}),se("span",{className:"se-switchTrack",children:se("span",{className:"se-switchThumb"})})]})]}),l?Ie(Ru,{children:[Ie("div",{className:"bb-transformAxis",style:{marginTop:8},children:[se("span",{className:"se-axisStepperLabel bb-transformAxisLabel",children:"\xD7"}),se("div",{className:"bb-transformAxisControl",children:se(qa,{className:"se-numberInput bb-transformNumberInput",step:Nu,min:hl,value:g,disabled:!e,formatValue:B=>Number(B.toFixed(2)),ariaLabel:"Uniform scale factor",onChange:O})})]}),se("span",{className:"bb-note",children:"1 is the model's original size \xB7 smaller shrinks, larger grows it"})]}):se("span",{className:"bb-note",children:"Enable to resize this object independently of the others"})]}),Ie("button",{type:"button",className:"bb-button bb-button--ghost",style:{marginTop:10,display:"inline-flex",alignItems:"center",gap:6},disabled:!e||!w,onClick:T,title:"Restore this node's position, rotation, and scale to what they were in the original model",children:[se(ku,{size:14}),"Restore original transform"]})]})}import{memo as Au,useMemo as wl,useState as Ou}from"react";import{Focus as Lu,ListChecks as Eu}from"lucide-react";import{Fragment as zu,jsx as Pe,jsxs as jt}from"react/jsx-runtime";var Uo=[],Sl=Au(Du);function Ja(e){let n=0;for(let i of Object.values(e))i.removed||(n+=1);return n}function Du({bindings:e,selectedItem:n,onSelect:i,onHover:r,isOpen:t=!0,onToggle:o,modelGroups:d,onSelectModel:l,isolatedItem:b=null,onIsolate:k,multiSelectEnabled:M=!1,onToggleMultiSelect:w,multiSelectedKeys:p=Uo,onSetMultiSelected:h}){let S=d&&d.length>=2?d:null,C=S?S.reduce((g,c)=>g+Ja(c.bindings),0):Ja(e);return jt("aside",{className:`bb-sidebar bb-sidebar--right ${t?"":"bb-sidebar--collapsed"}`,children:[jt("div",{className:"bb-header bb-header--sidebar",children:[!t&&Pe("button",{type:"button",className:"bb-sidebarToggle",onClick:()=>o?.(!0),"aria-label":"Open scene nodes sidebar",title:"Open scene nodes",children:"\u2190"}),t&&jt(zu,{children:[jt("div",{className:"bb-sidebarHeadingText",children:[Pe("div",{className:"bb-sectionKicker",children:M?`Scene Nodes \xB7 ${C}`:"Scene Nodes"}),Pe("div",{className:"bb-sectionHeading",style:M?{fontSize:15}:void 0,children:M?`${p.length} selected`:`${C} ${C===1?"node":"nodes"}`})]}),jt("div",{className:"bb-sidebarActions",children:[w?Pe("button",{type:"button",className:`bb-sidebarToggle ${M?"bb-sidebarToggle--active":""}`,onClick:w,"aria-pressed":M,"aria-label":"Toggle multi-select",title:M?"Multi-select on: edits apply to every selected node":"Select multiple nodes",children:Pe(Eu,{size:16,"aria-hidden":"true"})}):null,Pe("button",{type:"button",className:"bb-sidebarToggle",onClick:()=>o?.(!1),"aria-label":"Close scene nodes sidebar",title:"Close scene nodes",children:"\u2192"})]})]})]}),t&&(S?Pe(ju,{groups:S,selectedItem:n,onSelect:i,onHover:r,onSelectModel:l,isolatedItem:b,onIsolate:k,multiSelectEnabled:M,multiSelectedKeys:p,onSetMultiSelected:h}):Pe(Cl,{bindings:e,selectedItem:n,onSelect:i,onHover:r,isolatedItem:b,onIsolate:k,multiSelectEnabled:M,multiSelectedKeys:p,onSetMultiSelected:h}))]})}function Cl({bindings:e,selectedItem:n,onSelect:i,onHover:r,fill:t=!1,isolatedItem:o=null,onIsolate:d,multiSelectEnabled:l=!1,multiSelectedKeys:b=Uo,onSetMultiSelected:k}){let[M,w]=Ou(""),p=wl(()=>Object.keys(e).filter(g=>!e[g].removed),[e]),h=wl(()=>{let g=M.trim().toLowerCase();return g?p.filter(c=>{let f=e[c];return c.toLowerCase().includes(g)||f.label?.toLowerCase().includes(g)||(f.type??"other").toLowerCase().includes(g)}):p},[e,p,M]),S=h.length>0&&h.every(g=>b.includes(g));return jt("section",{className:`bb-nodeList ${t?"bb-nodeList--fill":""}`,children:[Pe("div",{className:"bb-search",children:Pe("input",{className:"bb-input",placeholder:"Search nodes, labels, or types",value:M,onChange:g=>w(g.target.value)})}),l&&k?Pe("div",{style:{padding:"8px 16px",borderBottom:"1px solid rgba(255, 255, 255, 0.07)"},children:Pe("button",{type:"button",className:"bb-button bb-button--ghost",onClick:()=>{if(!k)return;if(S){let c=new Set(h);k(b.filter(f=>!c.has(f)));return}let g=[...b];for(let c of h)g.includes(c)||g.push(c);k(g)},disabled:h.length===0,style:{width:"100%"},children:S?`Clear (${h.length})`:`Select all (${h.length})`})}):null,Pe("div",{className:`bb-nodeItems ${t?"bb-nodeItems--fill":""}`,children:h.map(g=>{let c=e[g],f=l&&b.includes(g),x=l?f:g===n,N=g===o;return jt("div",{className:`bb-nodeRow ${l?"bb-nodeRow--multi":""} ${o&&!N?"bb-nodeRow--setAside":""}`,children:[l?Pe("input",{type:"checkbox",className:"bb-nodeCheckbox",checked:f,onChange:()=>i(g),"aria-label":`Select ${g}`}):null,jt("button",{type:"button",className:`bb-nodeButton ${x?"bb-nodeButton--active":""}`,onClick:()=>i(g),onMouseEnter:()=>r?.(g),onMouseLeave:()=>r?.(null),children:[Pe("span",{className:"bb-nodeName",children:g}),jt("span",{className:"bb-nodeMeta",children:[c.type??"other",c.label===Pr(g)?"":` \xB7 ${c.label||"Untitled"}`]})]}),d?Pe("button",{type:"button",className:`bb-nodeIsolate ${N?"bb-nodeIsolate--active":""}`,onClick:()=>d(N?null:g),title:N?"Show all":"Isolate in the preview","aria-label":`${N?"Show all":"Isolate"} ${g}`,"aria-pressed":N,children:Pe(Lu,{size:14,"aria-hidden":"true"})}):null]},g)})})]})}function ju({groups:e,selectedItem:n,onSelect:i,onHover:r,onSelectModel:t,isolatedItem:o=null,onIsolate:d,multiSelectEnabled:l=!1,multiSelectedKeys:b=Uo,onSetMultiSelected:k}){return Pe("section",{className:"bb-nodeList bb-nodeList--grouped",children:e.map(M=>{let w=M.isActive,p=Ja(M.bindings),h=`${M.label} (${p})${M.isActive?" \xB7 Active":""}`,S=w;return Pe("div",{className:`bb-groupItem ${S?"bb-groupItem--fill":""}`,children:Pe(Ee,{title:h,open:w,onToggle:()=>{t?.(M.url)},children:Pe(Cl,{bindings:M.bindings,selectedItem:n,onSelect:C=>{t?.(M.url),i(C)},onHover:r,fill:S,isolatedItem:M.isActive?o:null,onIsolate:M.isActive?d:void 0,multiSelectEnabled:M.isActive&&l,multiSelectedKeys:M.isActive?b:Uo,onSetMultiSelected:M.isActive?k:void 0})})},M.url)})})}import{jsx as Go,jsxs as kl}from"react/jsx-runtime";function Xa({title:e,label:n,open:i,onToggle:r,draft:t,error:o,example:d,onDraftChange:l,onCommit:b}){return Go(Ee,{title:e,open:i,onToggle:r,children:kl("div",{className:"bb-field",children:[Go("label",{className:"bb-label",children:n}),Go("textarea",{className:"bb-textarea",value:t,onChange:k=>l(k.target.value),onBlur:b}),o?Go("span",{className:"bb-status bb-status--error",children:o}):kl("span",{className:"bb-note",children:["Use a JSON object like ",d,"."]})]})})}import{useCallback as Nt}from"react";import{PropertyBinding as Nl}from"three";import{PropertyBinding as Za}from"three";function dn(e,n,i=[],r={},t=new Set(Object.keys(Ao(e).nodesById))){let o=new Map(Object.entries(n).filter(([,p])=>p.removed===!0).map(([p,h])=>[h.modelObjectId??p,h])),d=new Set(Object.entries(r).map(([p,h])=>h.modelObjectId??p)),l=i.filter(p=>p.loadState==="loading").map(p=>Za.sanitizeNodeName(`${Mt(p.namePrefix)}_`)),b=Object.fromEntries(Object.entries(n).filter(([p,h])=>{let S=h.modelObjectId??p;return!d.has(S)&&(h.removed===!0||t.has(S)||l.some(C=>S.startsWith(C)))})),k=Object.fromEntries(Object.entries(r).map(([p,h])=>[p,o.get(h.modelObjectId??p)??h])),M={...b,...k},w=Object.keys(M);return w.length===Object.keys(n).length&&w.every(p=>M[p]===n[p])?n:M}function Mt(e){return e.replace(/\.[^./\\]+$/,"")}function Qa(e,n,i={}){let r=Za.sanitizeNodeName(Mt(e)).replace(/_/g,"-")||"Model",t=n.map(l=>Za.sanitizeNodeName(Mt(l.namePrefix))),o=Object.entries(i).map(([l,b])=>b.modelObjectId??l),d=r;for(let l=2;;l++){let b=`${d}_`;if(!t.some(k=>k===d||k.startsWith(b))&&!o.some(k=>k.startsWith(b)))return d;d=`${r}-${l}`}}function Mn(e){e.resolved.cleanup()}function Qn(e){e.resolved?.cleanup(),e.mergedModelSources.forEach(Mn)}function eo(e,n){let i=Br(e),r=$n(i,Lo(e));if(n){let o=new Map(Object.values(n).map(d=>[d.modelObjectId,d]));for(let d of i){let l=o.get(d);l&&(r[d]=l)}}e.updateMatrixWorld(!0);let t={};for(let o of i){let d=Hn(e,o);if(!d){t[o]={position:[0,0,0],rotation:[0,0,0],scale:[1,1,1],pivotLocal:[0,0,0],rotationOrder:"XYZ"};continue}let l=yr(d);t[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:r,originalTransforms:t,nodeNames:i}}function Iu(e,n){let i=e;for(;i;){if(i===n)return!0;i=i.parent}return!1}function ei(e,n){let i=e.parent??e,r=eo(i,n),t=r.nodeNames.filter(o=>{let d=Hn(i,o);return d?Iu(d,e):!1});return{bindings:Object.fromEntries(t.map(o=>[o,r.bindings[o]])),originalTransforms:Object.fromEntries(t.map(o=>[o,r.originalTransforms[o]])),nodeNames:t}}function _o(e,n=[]){let i={bindings:e,mergeSources:n};return{past:[],present:i,future:[],baseline:i,edits:0}}function Tl(e,n){let i=n(e.present),r=e.past.map(n),t=e.future.map(n),o=n(e.baseline);return i===e.present&&o===e.baseline&&r.every((d,l)=>d===e.past[l])&&t.every((d,l)=>d===e.future[l])?e:{...e,present:i,past:r,future:t,baseline:o}}function Pl(e,n,i,r={}){return Tl(e,t=>{if(!t.mergeSources.some(l=>l.url===n))return t;let o=new Map(Object.entries(t.bindings).map(([l,b])=>[b.modelObjectId??l,b])),d={...t.bindings};for(let[l,b]of Object.entries(r))d[l]=o.get(b.modelObjectId??l)??b;return{bindings:d,mergeSources:t.mergeSources.map(l=>l.url===n?{...l,...i}:l)}})}function ti(e,n){let i=e.mergeSources.find(o=>o.url===n);if(!i)return e;let r=new Set(i.nodeNames),t=Nl.sanitizeNodeName(`${Mt(i.namePrefix)}_`);return{mergeSources:e.mergeSources.filter(o=>o.url!==n),bindings:Object.fromEntries(Object.entries(e.bindings).filter(([o,d])=>{let l=d.modelObjectId??o;return!r.has(l)&&!r.has(o)&&!l.startsWith(t)}))}}function ni(e,n){let i=Vt(e.bindingHistory??_o(e.bindings,e.mergedModelSources),{type:"set",updater:n,track:!0,coalesce:!1});return{...e,bindings:i.present.bindings,mergedModelSources:i.present.mergeSources,bindingHistory:i}}function oi(e,n,i,r){let t=Pl(e.bindingHistory??_o(e.bindings,e.mergedModelSources),n,i,r);return{...e,bindings:t.present.bindings,mergedModelSources:t.present.mergeSources,bindingHistory:t}}function Bl(e,n){let i=e.bindingHistory??_o(e.bindings,e.mergedModelSources),t=[i.present,...i.past,...i.future].flatMap(l=>l.mergeSources).map(l=>Nl.sanitizeNodeName(`${Mt(l.namePrefix)}_`)),o=Object.fromEntries(Object.entries(n).filter(([l,b])=>!t.some(k=>(b.modelObjectId??l).startsWith(k)))),d=Tl(i,l=>({...l,bindings:{...o,...l.bindings}}));return{...e,bindings:d.present.bindings,bindingHistory:d}}function Ml(e,n){let i=new Set(n.mergeSources.map(r=>r.url));return{...e,present:{...e.present,mergeSources:e.present.mergeSources.map(r=>i.has(r.url)?r:{...r,loadState:"loading"})}}}function Rl(e,n=[]){let i=zo({bindings:e,mergeSources:n}),{setValue:r,setValueAsStep:t,updateHistory:o,restoreSnapshot:d}=i,l=Nt(c=>r(f=>{let x=typeof c=="function"?c(f.bindings):c;return x===f.bindings?f:{...f,bindings:x}}),[r]),b=Nt(c=>o(f=>{let x=typeof c=="function"?c(f.present.bindings):c;if(x===f.present.bindings)return f;let N={...f.present,bindings:x};return{...f,present:N,baseline:f.edits===0?N:f.baseline}}),[o]),k=Nt(c=>o(f=>{let x=typeof c=="function"?c(f.present.mergeSources):c,N={...f.present,mergeSources:x};return{...f,present:N,baseline:f.edits===0?N:f.baseline}}),[o]),M=Nt(c=>t(f=>({...f,mergeSources:[...f.mergeSources,typeof c=="function"?c(f):c]})),[t]),w=Nt(c=>t(f=>ti(f,c)),[t]),p=Nt((c,f,x)=>{o(N=>Pl(N,c,f,x))},[o]),h=Nt(()=>d(c=>{let f=Vt(c,{type:"undo"});return f===c?c:Ml(f,c.present)}),[d]),S=Nt(()=>d(c=>{let f=Vt(c,{type:"redo"});return f===c?c:Ml(f,c.present)}),[d]),C=Nt((c,f)=>d(x=>Vt(x,{type:"reset",value:{bindings:c,mergeSources:x.present.mergeSources},track:f?.asEdit??!1})),[d]),g=Nt(c=>d({...c.bindingHistory??_o(c.bindings,c.mergedModelSources),present:{bindings:c.bindings,mergeSources:c.mergedModelSources}}),[d]);return{value:i.value.bindings,baseline:i.baseline.bindings,mergeSources:i.value.mergeSources,snapshot:i.snapshot,edits:i.edits,canUndo:i.canUndo,canRedo:i.canRedo,setValue:l,setValueUntracked:b,setMergeSourcesUntracked:k,addMerge:M,removeMerge:w,hydrateMerge:p,undo:h,redo:S,reset:C,restoreModel:g}}import{useEffect as Al,useRef as Fu}from"react";function Ol(e,n,{modelUrl:i,modelSourceRef:r,uploadedFilesRef:t}={}){let o=Fu(new Map);Al(()=>{let d=new Map,l=M=>{for(let w of[M.present,...M.past,...M.future])w.mergeSources.forEach(p=>d.set(p.url,p))};l(e);for(let M of n)M.bindingHistory&&l(M.bindingHistory),M.mergedModelSources.forEach(w=>d.set(w.url,w));for(let[M,w]of o.current)d.has(M)||w.resolved.cleanup();o.current=d;let b=new Set,k=M=>{M?.kind==="file"&&b.add(M.key)};i&&k(r?.current?.model),n.forEach(M=>k(M.sessionModel)),d.forEach(M=>k(M.sessionModel));for(let M of t?.current.keys()??[])b.has(M)||t?.current.delete(M)},[e,n,i,r,t]),Al(()=>()=>{o.current.forEach(d=>d.resolved.cleanup()),o.current.clear(),t?.current.clear()},[t])}import{useCallback as Hu,useEffect as ai,useRef as $u}from"react";var Vu=500;function Ll({autosaveEnabled:e,hasEdits:n,modelUrl:i,bindings:r,sceneConfig:t,parkedModels:o,mergedModelSources:d,modelOrder:l,onTextureUpload:b,modelSourceRef:k,pendingLoadRef:M,storedModelKeysRef:w,uploadedFilesRef:p,pendingAutosaveRef:h,autosaveFailureShownRef:S,setStatusMessage:C,setStatusTone:g}){let c=$u(0),f=Hu(async(x,N)=>{if(b)return b(x,N);let O=URL.createObjectURL(x);if(e)try{await Io(O,x)}catch(T){console.warn("[BindingBuilder] Could not store texture file for autosave:",T)}return O},[b,e]);return ai(()=>{if(!e||!n){h.current=null;return}let x=k.current;if(i&&!x){h.current=null;return}let N=i,O=()=>{if(h.current!==O||M.current)return;h.current=null;let B=++c.current,a=z=>{console.warn("[BindingBuilder] Autosave failed:",z),!S.current&&(S.current=!0,C("Couldn't autosave this session \u2014 the browser refused to store it, possibly for lack of space. Export your work to keep it."),g("error"))};if(!N||!x){w.current.clear(),ns().then(()=>{B===c.current&&(S.current=!1)}).catch(a);return}let{model:u}=x,L=[],P=new Set,H=z=>{if(!z||z.kind!=="file"||(P.add(z.key),w.current.has(z.key)))return;let $=p.current.get(z.key);$&&L.push({key:z.key,file:$})};H(u),o.forEach(z=>{H(z.sessionModel),z.mergedModelSources.forEach($=>H($.sessionModel))}),d.forEach(z=>H(z.sessionModel)),w.current=new Set([...w.current].filter(z=>P.has(z)));let q=z=>({model:z.sessionModel,namePrefix:z.namePrefix}),Ke=o.filter(z=>!!z.sessionModel).map(z=>({model:z.sessionModel,bindings:z.bindings,originalTransforms:z.originalTransforms,modelSettings:z.modelSettings,mergeModels:z.mergedModelSources.map(q)})),Le=d.map(q),Qe=new Map;Qe.set(N,u),o.forEach(z=>{z.sessionModel&&Qe.set(z.url,z.sessionModel)});let cn=l.map(z=>{let $=Qe.get(z);return $?Gn($):null}).filter(z=>z!==null);es({model:u,bindings:r,sceneConfig:t,parkedModels:Ke,mergeModels:Le,modelOrder:cn},L).then(()=>{B===c.current&&(w.current=P,S.current=!1)}).catch(a)};if(h.current=O,!N){O();return}let T=window.setTimeout(O,Vu);return()=>window.clearTimeout(T)},[e,n,i,r,t,o,d,l]),ai(()=>{if(!e)return;let x=()=>h.current?.(),N=()=>{document.visibilityState==="hidden"&&x()};return window.addEventListener("pagehide",x),document.addEventListener("visibilitychange",N),()=>{window.removeEventListener("pagehide",x),document.removeEventListener("visibilitychange",N),x()}},[e]),ai(()=>{if(!e||!i||!n)return;let x=N=>{h.current?.(),N.preventDefault(),N.returnValue=""};return window.addEventListener("beforeunload",x),()=>window.removeEventListener("beforeunload",x)},[e,i,n]),{handleTextureUpload:f}}import{useLayoutEffect as Uu}from"react";function El({bindings:e,multiSelectMode:n,selectedItem:i,multiSelectedKeys:r,setSelectedItem:t,setMultiSelectedKeys:o}){Uu(()=>{let d=b=>!!(e[b]&&!e[b].removed),l=r.filter(d);l.length!==r.length&&o(l),i&&(!d(i)||n&&!l.includes(i))&&t(n?l[l.length-1]??null:null)},[e,n,i,r,t,o])}import{useCallback as Dl,useEffect as Gu,useState as _u}from"react";function jl(e,n){let[i,r]=_u(!1),t=e>0||n>0,o=Dl(()=>r(!0),[]),d=Dl(()=>r(!1),[]);return Gu(()=>{t&&o()},[t,o]),{hasEdits:i||t,markSessionEdited:o,resetSessionEdits:d}}import{useEffect as zl,useReducer as Ku,useRef as Wu}from"react";function Il({enabled:e=!0,modelUrl:n,bindings:i,mergeSources:r,parkedModels:t,scenesRef:o,sceneRevision:d,setBindings:l,setParkedModels:b}){let[k,M]=Ku(p=>p+1,0),w=Wu(new WeakMap);zl(()=>{if(!e)return;let p=[n,...t.map(C=>C.url)],h=new Set(p.flatMap(C=>{let g=C?o.current.get(C):void 0;return g?[g]:[]})),S=C=>{C.target&&w.current.delete(C.target),M()};for(let C of h)C.addEventListener("childadded",S),C.addEventListener("childremoved",S);return()=>{for(let C of h)C.removeEventListener("childadded",S),C.removeEventListener("childremoved",S)}},[e,n,t,o,d]),zl(()=>{if(!e)return;let p=S=>{let C=w.current.get(S);return C||(C=new Set(Object.keys(Ao(S).nodesById)),w.current.set(S,C)),C},h=n?o.current.get(n):void 0;if(h){let S=p(h);l(C=>dn(h,C,r,{},S))}b(S=>{let C=!1,g=S.map(c=>{let f=o.current.get(c.url);if(!f)return c;let x=dn(f,c.bindings,c.mergedModelSources,{},p(f));return x===c.bindings?c:(C=!0,{...c,bindings:x})});return C?g:S})},[e,n,i,r,t,o,d,k,l,b])}import{useEffect as Yu,useMemo as qu,useReducer as Ju}from"react";function Fl({modelUrl:e,scenesRef:n,sceneRevision:i,streaming:r=!1}){let t=e?n.current.get(e):void 0,[o,d]=Ju(l=>l+1,0);return Yu(()=>{if(!t||r)return;let l=()=>d();return t.addEventListener("childadded",l),t.addEventListener("childremoved",l),()=>{t.removeEventListener("childadded",l),t.removeEventListener("childremoved",l)}},[t,r]),qu(()=>({materialVariantGroups:t?vr(t):[],objectsWithoutUvs:t&&!r?Lo(t):new Set}),[t,i,o,r])}import{ListRestart as am,Redo2 as im,Undo2 as rm,Upload as sm}from"lucide-react";import{useEffect as Xu,useId as Hl,useRef as Zu,useState as Qu}from"react";import{ChevronDown as em,Download as tm,FileCode2 as nm,FileJson as om}from"lucide-react";import{jsx as Nn,jsxs as to}from"react/jsx-runtime";function $l({disabled:e,exporting:n,exportTitle:i,exportDescription:r,onExportJson:t,onExportTs:o}){let[d,l]=Qu(!1),b=Zu(null),k=Hl(),M=Hl();return Xu(()=>{if(!d)return;let w=p=>{b.current?.contains(p.target)||l(!1)};return window.addEventListener("pointerdown",w),()=>window.removeEventListener("pointerdown",w)},[d]),to("div",{className:"bb-exportMenuWrapper",ref:b,children:[to("button",{type:"button",className:"bb-button bb-button--ghost",disabled:e||n,onClick:()=>l(w=>!w),title:`Export ${i.toLowerCase()}`,"aria-label":`Export ${i.toLowerCase()}`,"aria-expanded":d,"aria-controls":d?k:void 0,children:[Nn(tm,{size:14}),n?"Exporting\u2026":"Export",Nn(em,{size:12})]}),d&&to("div",{className:"bb-exportMenu",id:k,role:"group","aria-label":i,children:[Nn("div",{className:"bb-exportMenuTitle",children:i}),Nn("p",{className:"bb-exportMenuDescription",id:M,children:r}),to("button",{type:"button",className:"bb-exportMenuItem","aria-label":`Export ${i.toLowerCase()} as JSON`,"aria-describedby":M,onClick:()=>{l(!1),t()},children:[Nn(om,{size:14}),"JSON"]}),to("button",{type:"button",className:"bb-exportMenuItem","aria-label":`Export ${i.toLowerCase()} as TypeScript`,"aria-describedby":M,onClick:()=>{l(!1),o()},children:[Nn(nm,{size:14}),"TypeScript"]})]})]})}import{jsx as Tt,jsxs as ii}from"react/jsx-runtime";function ri({canUndo:e,canRedo:n,onUndo:i,onRedo:r,onReset:t,resetDisabled:o,resetTitle:d,onImport:l,importDisabled:b,importTitle:k,exportDisabled:M,exporting:w,exportTitle:p,exportDescription:h,onExportJson:S,onExportTs:C}){return ii("div",{className:"bb-toolbar",children:[ii("div",{className:"bb-toolbarGroup",children:[Tt("button",{type:"button",className:"bb-iconButton",disabled:!e,onClick:i,title:"Undo (Cmd/Ctrl+Z)",children:Tt(rm,{size:16})}),Tt("button",{type:"button",className:"bb-iconButton",disabled:o,onClick:t,title:d,children:Tt(am,{size:16})}),Tt("button",{type:"button",className:"bb-iconButton",disabled:!n,onClick:r,title:"Redo (Cmd/Ctrl+Shift+Z)",children:Tt(im,{size:16})})]}),Tt("div",{className:"bb-toolbarDivider"}),ii("button",{type:"button",className:"bb-button bb-button--ghost",disabled:b,onClick:l,title:k,children:[Tt(sm,{size:14}),"Import"]}),Tt("div",{className:"bb-toolbarDivider"}),Tt($l,{disabled:M,exporting:w,exportTitle:p,exportDescription:h,onExportJson:S,onExportTs:C})]})}import{AlertTriangle as si,History as lm,Upload as dm,X as oo}from"lucide-react";import{useId as no,useState as cm}from"react";import{jsx as _,jsxs as ne}from"react/jsx-runtime";function bm(e){let n=new Date(e);return n.toDateString()===new Date().toDateString()?`today at ${n.toLocaleTimeString([],{hour:"numeric",minute:"2-digit"})}`:n.toLocaleString([],{dateStyle:"medium",timeStyle:"short"})}function Vl({target:e,onCancel:n,onConfirm:i}){return _("div",{className:"bb-reset-overlay",onClick:n,children:ne("div",{className:"bb-reset-dialog",onClick:r=>r.stopPropagation(),children:[ne("div",{className:"bb-reset-header",children:[ne("h3",{className:"bb-reset-title",children:[_(si,{size:20,className:"bb-icon-warning"}),"Confirm Reset"]}),_("button",{className:"bb-reset-close",onClick:n,children:_(oo,{size:20})})]}),ne("div",{className:"bb-reset-body",children:[ne("p",{className:"bb-reset-message",children:["Are you sure you want to reset"," ",_("strong",{children:e==="bindings"?"Object Bindings":"Scene Config"}),"?"]}),_("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.":"This will restore all scene settings (camera, lighting, environment, background, animations, annotations, etc.) to their default values."}),_("p",{className:"bb-reset-warning",children:"This action cannot be undone!"})]}),ne("div",{className:"bb-reset-footer",children:[_("button",{className:"bb-reset-btn",onClick:n,children:"Cancel"}),_("button",{className:"bb-reset-btn-danger",onClick:i,children:"Reset"})]})]})})}function Ul({modelNames:e,mergedSourceCount:n,savedAt:i,onCancel:r,onConfirm:t}){let o=no();return _("div",{className:"bb-reset-overlay",onClick:r,children:ne("div",{className:"bb-reset-dialog",role:"dialog","aria-modal":"true","aria-labelledby":o,onClick:d=>d.stopPropagation(),children:[ne("div",{className:"bb-reset-header",children:[ne("h3",{className:"bb-reset-title",id:o,children:[_(lm,{size:20,className:"bb-icon-restore"}),"Restore Last Session"]}),_("button",{className:"bb-reset-close",onClick:r,children:_(oo,{size:20})})]}),ne("div",{className:"bb-reset-body",children:[ne("p",{className:"bb-reset-message",children:["Restore the session saved ",bm(i),"?"]}),ne("p",{className:"bb-reset-message",children:[ne("strong",{children:[e.length," ",e.length===1?"model":"models"]})," \xB7 ",n," merged ",n===1?"source":"sources"]}),_("ul",{className:"bb-restoreModelNames","aria-label":"Saved models",children:e.map((d,l)=>_("li",{children:d},l))}),_("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."})]}),ne("div",{className:"bb-reset-footer",children:[_("button",{className:"bb-reset-btn",onClick:r,children:"Cancel"}),_("button",{className:"bb-reset-btn-restore",onClick:t,children:"Restore"})]})]})})}function Gl({nodeLabel:e,onCancel:n,onConfirm:i}){return _("div",{className:"bb-reset-overlay",onClick:n,children:ne("div",{className:"bb-reset-dialog",onClick:r=>r.stopPropagation(),children:[ne("div",{className:"bb-reset-header",children:[ne("h3",{className:"bb-reset-title",children:[_(si,{size:20,className:"bb-icon-warning"}),"Delete Object"]}),_("button",{className:"bb-reset-close",onClick:n,children:_(oo,{size:20})})]}),ne("div",{className:"bb-reset-body",children:[ne("p",{className:"bb-reset-message",children:["Delete ",_("strong",{children:e}),"?"]}),_("p",{className:"bb-reset-details",children:"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."}),_("p",{className:"bb-reset-warning",children:"This action cannot be undone!"})]}),ne("div",{className:"bb-reset-footer",children:[_("button",{className:"bb-reset-btn",onClick:n,children:"Cancel"}),_("button",{className:"bb-reset-btn-danger",onClick:i,children:"Delete"})]})]})})}function _l({destinations:e,onCancel:n,onChoose:i}){let[r,t]=cm(e.find(b=>b.isActive)?.url??e[0]?.url??""),o=e.find(b=>b.url===r),d=no(),l=no();return _("div",{className:"bb-reset-overlay",onClick:n,children:ne("div",{className:"bb-reset-dialog",role:"dialog","aria-modal":"true","aria-labelledby":d,onClick:b=>b.stopPropagation(),children:[ne("div",{className:"bb-reset-header",children:[ne("h3",{className:"bb-reset-title",id:d,children:[_(dm,{size:20,className:"bb-icon-restore"}),"Add Model"]}),_("button",{className:"bb-reset-close",onClick:n,children:_(oo,{size:20})})]}),ne("div",{className:"bb-reset-body",children:[_("p",{className:"bb-reset-message",children:"Add this as a separate model or add its nodes to an existing model?"}),_("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."}),_("label",{className:"bb-label",htmlFor:l,children:"Destination model for added nodes"}),_("select",{className:"bb-select",id:l,value:r,onChange:b=>t(b.target.value),children:e.map(b=>ne("option",{value:b.url,children:[b.label,": ",b.name,b.isActive?" (active)":""]},b.url))})]}),ne("div",{className:"bb-reset-footer",children:[_("button",{className:"bb-reset-btn",onClick:n,children:"Cancel"}),_("button",{className:"bb-reset-btn-secondary",onClick:()=>i({mode:"separate"}),children:"Add as Separate Model"}),_("button",{className:"bb-reset-btn-restore",disabled:!o,title:o?`Add nodes to ${o.name}`:void 0,onClick:()=>o&&i({mode:"merge",targetUrl:r}),children:"Add Nodes"})]})]})})}function Kl({options:e,onCancel:n,onRemoveModel:i,onRemoveMerge:r,onRemoveAll:t}){let o=no(),d=no();return _("div",{className:"bb-reset-overlay",onClick:n,children:ne("div",{className:"bb-reset-dialog",role:"dialog","aria-modal":"true","aria-labelledby":o,onClick:l=>l.stopPropagation(),children:[ne("div",{className:"bb-reset-header",children:[ne("h3",{className:"bb-reset-title",id:o,children:[_(si,{size:20,className:"bb-icon-warning"}),"Remove Model"]}),_("button",{className:"bb-reset-close",onClick:n,children:_(oo,{size:20})})]}),ne("div",{className:"bb-reset-body",children:[_("p",{className:"bb-reset-message",children:"Which model do you want to remove?"}),_("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."}),_("div",{className:"bb-removeModelList",children:e.map(l=>l.kind==="model"?ne("button",{type:"button",className:"bb-removeModelOption",onClick:()=>i(l.url),children:[ne("span",{className:"bb-removeModelOptionLabel",children:[l.label,l.isActive&&_("span",{className:"bb-removeModelOptionActive",children:"active"})]}),_("span",{className:"bb-removeModelOptionName",children:l.name})]},l.url):ne("button",{type:"button",className:"bb-removeModelOption bb-removeModelOptionMerge",onClick:()=>r(l.url),children:[ne("span",{className:"bb-removeModelOptionLabel",children:[l.label,ne("span",{className:"bb-removeModelOptionActive",children:["merged into ",l.ownerLabel]})]}),_("span",{className:"bb-removeModelOptionName",children:l.name})]},l.url))}),_("p",{className:"bb-reset-warning",id:d,children:"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."})]}),ne("div",{className:"bb-reset-footer",children:[_("button",{className:"bb-reset-btn",onClick:n,children:"Cancel"}),_("button",{className:"bb-reset-btn-danger","aria-describedby":d,onClick:t,children:"Remove All Models"})]})]})})}import{strToU8 as pm}from"fflate";function Wl(e){return JSON.stringify(e,null,2)}function Yl(e){return['import { defineObjectBindings } from "@liveroom-tech/react-immersive/utils";',"",`export const objectBindings = defineObjectBindings(${JSON.stringify(e,null,2)});`,""].join(`
|
|
2
|
-
`)}function ql(e){return JSON.stringify(e,null,2)}function Jl(e){return['import type { SceneConfig } from "@liveroom-tech/react-immersive/utils";',"",`export const sceneConfig: SceneConfig = ${JSON.stringify(e,null,2)};`,""].join(`
|
|
3
|
-
`)}function ao(e,n,i){Ro(new Blob([n],{type:i}),e)}function li(e){return JSON.stringify(e??{},null,2)}function di(e){return`[${e[0].toFixed(3)}, ${e[1].toFixed(3)}, ${e[2].toFixed(3)}]`}function um(e){return(e.decals??[]).map(n=>n.image).filter(n=>!!n?.trim())}function mm(e){let n=e.style?.material;return n?Object.values(n).filter(i=>!!i&&typeof i=="object"&&typeof i.path=="string"&&i.path.trim().length>0).map(i=>i.path):[]}async function Xl(e){let n=new Set;for(let t of Object.values(e)){for(let o of mm(t))n.add(o);for(let o of um(t))n.add(o)}let i=[],r=[];return await Promise.all(Array.from(n).map(async t=>{let o=sr(t);if(o)try{let d=await fetch(o);if(!d.ok)throw new Error(String(d.status));i.push({path:t,blob:await d.blob()});return}catch{r.push(t);return}try{let d=await Kn(t);d&&i.push({path:t,blob:d})}catch{}})),{assets:i,failedPaths:r}}async function ci(e,n,i,r,t){if(t.length===0){ao(e,n,i);return}let o={[e]:pm(n)};for(let l of t)o[l.path]=new Uint8Array(await l.blob.arrayBuffer());let d=await lr(o);Ro(new Blob([d],{type:"application/zip"}),r)}async function Tn(e){return await Promise.all(Object.entries(e).map(async([n,i])=>{for(let t of i.decals??[])if(t.image)try{let o=await Kn(t.image);o&&tn(t.image,URL.createObjectURL(o))}catch(o){console.warn(`[BindingBuilder] Could not rehydrate a decal image on "${n}":`,o)}let r=i.style?.material;if(r)for(let t of rr){let d=r[t]?.path;if(d)try{let l=await Kn(d);if(!l){console.warn(`[BindingBuilder] No stored texture found for "${n}"'s ${t} ("${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 b=URL.createObjectURL(l);tn(d,b)}catch(l){console.warn(`[BindingBuilder] Could not rehydrate "${n}"'s ${t}:`,l)}}})),e}function Zl({bindings:e,setBindings:n,setSceneConfig:i,nodeKeys:r,sceneConfigInputRef:t,setIsExporting:o,setStatusMessage:d,setStatusTone:l}){let b=async S=>{o(!0);try{let{assets:C,failedPaths:g}=await Xl(e);S==="json"?await ci("objectBindings.json",Wl(e),"application/json","objectBindings.zip",C):await ci("objectBindings.ts",Yl(e),"text/typescript","objectBindings-ts.zip",C),g.length>0?(d(`Exported, but ${g.length} uploaded image${g.length===1?"":"s"} couldn't be bundled: ${g.join(", ")}.`),l("error")):C.length>0&&(d(`Exported with ${C.length} uploaded image${C.length===1?"":"s"} bundled into the zip.`),l("success"))}catch(C){let g=C instanceof Error?C.message:"Unknown export error.";d(`Failed to export bindings: ${g}`),l("error")}finally{o(!1)}},k=async S=>{if(!r.length){d("Load a model before importing bindings."),l("error");return}let C;try{C=JSON.parse(await S.text())}catch{d(`${S.name} is not valid JSON.`),l("error");return}if(C===null||typeof C!="object"||Array.isArray(C)){d("Expected a JSON object mapping object IDs to bindings."),l("error");return}let g=new Map;for(let T of Object.values(C))if(T!==null&&typeof T=="object"&&typeof T.id=="string"&&typeof T.type=="string"&&typeof T.modelObjectId=="string"){let B=T;g.set(B.modelObjectId,B)}if(g.size===0){d(`${S.name} doesn't look like an exported bindings file.`),l("error");return}let c={...e},f={},x=0;for(let T of Object.keys(c)){let B=g.get(T);B&&(c[T]=B,f[T]=B,x++)}if(x===0){d(`None of the object IDs in ${S.name} match this model \u2014 nothing imported.`),l("error");return}let N=await Tn(f);Object.assign(c,N),n(c);let O=g.size-x;d(O>0?`Imported ${x} binding${x===1?"":"s"} from ${S.name} (${O} skipped \u2014 not in this model).`:`Imported ${x} binding${x===1?"":"s"} from ${S.name}.`),l("success")},M=async S=>{let C=S.target.files?.[0];C&&(await k(C),S.target.value="")},w=()=>{t.current?.click()},p=async S=>{let C;try{C=JSON.parse(await S.text())}catch{d(`${S.name} is not valid JSON.`),l("error");return}if(C===null||typeof C!="object"||Array.isArray(C)){d("Expected a JSON object with scene config sections."),l("error");return}let g=["model","camera","lighting","wireframe","shadows","environment","background","groundShadows","postProcessing","animations","annotations","cinematic","styleRules","section"],c=C,f=g.filter(x=>c[x]!==void 0);if(f.length===0){d(`${S.name} doesn't look like an exported scene config file.`),l("error");return}i(x=>{let N={...x};for(let O of f)N[O]=Un(x[O],c[O]);return N}),d(`Imported ${f.length} section${f.length===1?"":"s"} from ${S.name}.`),l("success")};return{handleExportBindings:b,importBindingsFile:k,handleImportBindingsChange:M,openSceneConfigImportPicker:w,importSceneConfigFile:p,handleImportSceneConfigChange:async S=>{let C=S.target.files?.[0];C&&(await p(C),S.target.value="")}}}var bi={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"]},Ql=Object.keys(bi);function ed(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 n=e.path;return typeof n=="string"&&n.trim().length>0}return!1}function pi(e){if(e)return Object.values(e).some(ed)?e:void 0}function at(e,n){return e?bi[n].some(i=>ed(e[i])):!1}function ui(e){return{pbr:at(e,"pbr"),roughness:at(e,"roughness"),emission:at(e,"emission"),opacity:at(e,"opacity"),normalBump:at(e,"normalBump"),displacement:at(e,"displacement"),ao:at(e,"ao"),clearcoat:at(e,"clearcoat"),sheen:at(e,"sheen"),anisotropy:at(e,"anisotropy"),transmission:at(e,"transmission"),faces:at(e,"faces")}}function mi(e,n){if(n)return{...e,style:{...e.style,material:n}};if(!e.style)return e;let{material:i,...r}=e.style;return{...e,style:Object.keys(r).length>0?r:void 0}}function td(e,n){if(!e)return;let i={...e};for(let r of bi[n])delete i[r];return i}import{Fragment as Yt,jsx as j,jsxs as ge}from"react/jsx-runtime";var nd="/room.glb";function gi(){return`${Date.now().toString(36)}-${Math.random().toString(36).slice(2,10)}`}function od(e){return`Couldn't reload ${e} from your last session. It's still saved in this browser.`}function Sm({label:e,values:n,onChange:i}){let r=n.length>0&&n.every(Boolean),t=!r&&n.some(Boolean);return ge("label",{className:"bb-groupFlag",children:[j("input",{type:"checkbox",ref:o=>{o&&(o.indeterminate=t)},checked:r,onChange:o=>i(o.target.checked)}),e]})}function Cm({licenseKey:e,licenseValidationUrl:n,dracoDecoderPath:i,ktx2TranscoderPath:r,meshopt:t,project:o,onProjectChange:d,projectChangeDebounceMs:l=350,onModelUpload:b,onTextureUpload:k,onEditLeaseChange:M,allowModelChange:w=!0}){let p=le(null),h=le(null),S=le(null),C=le(null),g=le(null),[c,f]=K(o?.model.url??null),[x,N]=K([]),[O,T]=K(()=>o?.model.url?[o.model.url]:[]),[B,a]=K(o?.model.name??""),[u,L]=K(o?.model??null),[P,H]=K(null),[q,Ke]=K(!1),[Le,Qe]=K([]),cn=le({mode:!1,keys:[]});cn.current={mode:q,keys:Le};let z=Rl(o?.objectBindings??{}),$=z.value,qt=z.setValue;El({bindings:$,multiSelectMode:q,selectedItem:P,multiSelectedKeys:Le,setSelectedItem:H,setMultiSelectedKeys:Qe});let Ve=z.mergeSources,io=z.setMergeSourcesUntracked,[Be,Pt]=K(!1),[ro,Pn]=K(null),ad=it(()=>ro?{target:ro}:null,[ro]);_e(()=>{Pn(null)},[c]),_e(()=>{Ke(!1),Qe([])},[c]);let[so,zt]=K(null);_e(()=>zt(null),[P,c]),_e(()=>ta(null),[c]);let[id,Jt]=K(null),[fi,rd]=K(!1),[hi,J]=K("Load the demo model or upload a GLB, GLTF, OBJ, FBX, USDZ, STL, or PLY model to generate bindings."),[lo,Q]=K("default"),[sd,Bn]=K(!1),[xi,co]=K("{}"),[vi,bo]=K("{}"),[ld,po]=K(null),[dd,uo]=K(null),[cd,Rn]=K(!1),[bn,bd]=K(!1),[pd,ud]=K(!1),[ut,yi]=K({identity:!0,basics:!0,material:!1,decals:!1,actions:!1,camera:!1,transform:!1,metrics:!1,metadata:!1}),[md,gd]=K({pbr:!1,roughness:!1,emission:!1,opacity:!1,normalBump:!1,displacement:!1,ao:!1,clearcoat:!1,sheen:!1,anisotropy:!1,transmission:!1,faces:!1}),mt=s=>yi(m=>({...m,[s]:!m[s]})),fd=s=>gd(m=>({...m,[s]:!m[s]})),[Bt,mo]=K("object"),[An,wi]=K("General"),[hd,xd]=K("metalness"),[vd,Ko]=K(ui()),Si=le(null),[Ci,yd]=K(!1),[Wo,wd]=K(!0),[Yo,Sd]=K(!0),[Cd,ki]=K(!1),[go,Mi]=K(null),[Xt,qo]=K(null),[kd,Jo]=K(!1),fo=le(null),Ni=le({modelUrl:c,modelName:B,modelOrder:O,parkedModels:x});Ni.current={modelUrl:c,modelName:B,modelOrder:O,parkedModels:x};let[Md,On]=K(!1),[Ln,Xo]=K(null),[Zo,Ti]=K(!1),[Pi,Bi]=K(!1),[Ri,Nd]=K("world"),rt=le({}),fe=zo(o?.sceneConfig??vn),he=fe.value,En=fe.setValue,ho=fe.setValueUntracked,Qo=W(s=>{let m=wt(he,s.modelSettings);s.sceneHistory?fe.restoreSnapshot({...s.sceneHistory,present:m}):fe.reset(m)},[he,fe.restoreSnapshot,fe.reset]),{hasEdits:Td,markSessionEdited:st,resetSessionEdits:ea}=jl(z.edits,fe.edits),[pn,Pd]=K(!1),[Bd,Rd]=K(.5),[un,ta]=K(null),Ai=un??{bindings:z.baseline,sceneConfig:fe.baseline},[Oi,na]=K("orbit"),[Ad,Li]=K(!1),oa=le(void 0),aa=W(()=>{Li(!0),clearTimeout(oa.current),oa.current=setTimeout(()=>Li(!1),5e3)},[]);_e(()=>()=>clearTimeout(oa.current),[]),_e(()=>{c&&!Be&&aa()},[c,Be,aa]);let De=Oi==="pointerLock",[Ei,Od]=K(null),Di=le(null),Ld=Ei?.objectKey===P&&Ei?.textureKey==="texture",[Ed,mn]=K(null),[Dd,ia]=K(null),Dn=Cr(e,n),ji=ss(Dn.tier),jd=it(()=>({isInsideEditor:!0,activeTab:Bt,activeSubTab:An,tier:ji,setActiveTab:mo,setActiveSubTab:wi}),[Bt,An,ji]),Fe=le(null),gn=le(0),gt=le(0),zi=le(o?`${o.id}:${o.revision}`:null),Ii=le(null),Fi=le(!1),fn=le(!1),xo=le(o?{modelUrl:o.model.url,bindings:o.objectBindings,sceneConfig:o.sceneConfig}:null),vo=le(void 0),Zt=le(0),je=le(null),We=le(o?{requestId:0,modelName:o.model.name??"model",modelUrl:o.model.url,storedBindings:o.objectBindings,streaming:!!o.model.tilesetUrl}:null),et=le(null),ra=le(new Set),hn=le(new Map);Ol(z.snapshot,x,{modelUrl:c,modelSourceRef:et,uploadedFilesRef:hn});let jn=le(null),zd=le(!1),Rt=le(null),It=le(new Map),[Hi,$i]=K(0),{materialVariantGroups:Id,objectsWithoutUvs:Vi}=Fl({modelUrl:c,scenesRef:It,sceneRevision:Hi,streaming:!!u?.tilesetUrl});_e(()=>{let s=new Set(o?c?[c]:[]:O);for(let m of It.current.keys())s.has(m)||It.current.delete(m)},[o,c,O]),Il({enabled:!u?.tilesetUrl,modelUrl:c,bindings:$,mergeSources:Ve,parkedModels:x,scenesRef:It,sceneRevision:Hi,setBindings:z.setValueUntracked,setParkedModels:N});let zn=le(null),[Ui,Fd]=K({}),Hd=it(()=>{if(!q||Le.length===0||!zn.current)return null;let m=Le.filter(v=>$[v]&&!$[v].removed).map(v=>Ui[v]).filter(v=>!!v);return m.length>0?m:null},[q,Le,Ui,$]),{cameraState:xe,resetView:Gi,focusObject:_i,fitScene:Ki,setCameraState:yo,handleCameraChange:$d,handleViewerReady:Vd}=kr(),Ud=W(s=>{De||yo({position:s.position,target:s.target,fov:s.fov??xe?.fov??null,zoom:s.zoom??xe?.zoom??1,azimuthAngle:s.azimuthAngle,polarAngle:s.polarAngle},!0)},[De,yo,xe]),ft=zr(),Gd=it(()=>o?c?[c]:[]:O,[o,c,O]),xn=qr(Gd),Wi=Xr({modelUrl:c,sceneConfig:he,setSceneConfig:En,setSceneConfigUntracked:ho,parkedModels:x,setParkedModels:N,animations:xn,markSessionEdited:st}),ke=P?$[P]??null:null,sa=ke?.style?.material,Yi=!Vi.has(ke?.modelObjectId??P??""),_d=it(()=>{if(!o&&!(O.length<2))return O.map((s,m)=>{let v=s===c,y=v?void 0:x.find(R=>R.url===s);return{url:s,label:`Model ${m+1}`,bindings:v?$:y?.bindings??{},isActive:v}})},[o,O,c,$,x]),wo=it(()=>{let s=[];return O.forEach((m,v)=>{let y=m===c,R=y?void 0:x.find(G=>G.url===m),E=`Model ${v+1}`;s.push({kind:"model",url:m,label:E,name:y?B:R?.name??"Untitled model",isActive:y}),(y?Ve:R?.mergedModelSources??[]).forEach(G=>{s.push({kind:"merge",url:G.url,label:"Merged nodes",name:Mt(G.namePrefix),ownerLabel:E})})}),s},[O,c,B,x,Ve]),la=it(()=>Ve.map(s=>({url:s.url,namePrefix:s.namePrefix})),[Ve]),qi=it(()=>{if(!o&&!(O.length<1))return O.map((s,m)=>{if(s===c)return{url:s,label:B||`Model ${m+1}`,objectBindings:$,originalNodePoses:rt.current,mergeModels:la};let y=x.find(R=>R.url===s);return{url:s,label:y?.name||`Model ${m+1}`,objectBindings:y?.bindings??{},originalNodePoses:y?.originalTransforms,sceneConfig:wt(he,y?.modelSettings),mergeModels:(y?.mergedModelSources??[]).map(R=>({url:R.url,namePrefix:R.namePrefix}))}})},[o,O,c,B,$,x,la,he]);_e(()=>{let s=S.current;if(!s)return;let m=s.querySelector(".ri-modelSwitcher"),v=()=>{let R=pn?48:12,E=m?Math.max(R,m.getBoundingClientRect().bottom-s.getBoundingClientRect().top+8):R;s.style.setProperty("--bb-canvas-hint-top",`${E}px`)};v();let y=new ResizeObserver(v);return y.observe(s),m&&y.observe(m),()=>{y.disconnect(),s.style.removeProperty("--bb-canvas-hint-top")}},[qi,pn]);let Ft=ke?.cameraState,Kd=xe?{position:di(xe.position),target:di(xe.target)}:null,Wd=W(s=>{En(m=>{let v=m.annotations.map(R=>R.id).join(","),y=s.map(R=>R.id).join(",");return v===y?m:{...m,annotations:s}})},[]),Yd=W(s=>{mn(s?{annotation:s}:null)},[]);_e(()=>{if(!ke){co("{}"),bo("{}"),po(null),uo(null);return}co(li(ke.metrics)),bo(li(ke.metadata)),po(null),uo(null)},[ke]),_e(()=>{let s=ui(sa);if(Si.current!==P){Si.current=P,Ko(s);return}Ko(m=>{let v=!1,y={...m};for(let R of Ql)s[R]&&!m[R]&&(y[R]=!0,v=!0);return v?y:m})},[P,sa]),_e(()=>()=>{Fe.current?.cleanup(),je.current&&clearTimeout(je.current)},[]);let So=W((s,m)=>{let v=$n(s);if(m){let y=new Map(Object.values(m).map(R=>[R.modelObjectId,R]));for(let R of s){let E=y.get(R);E&&(v[R]=E)}}return v},[]);_e(()=>{if(!o)return;let s=`${o.id}:${o.revision}`;if(zi.current===s)return;zi.current=s;let m=c!==o.model.url||u?.tilesetUrl!==o.model.tilesetUrl||u?.assetVersion!==o.model.assetVersion,v=$!==o.objectBindings,y=he!==o.sceneConfig;(m||v||y)&&(fn.current=!0),L(o.model),a(o.model.name??"model");let R=o.objectBindings;if(v){let E=Ii.current;R=E?So(E,o.objectBindings):o.objectBindings,z.reset(R)}if(y&&fe.reset(o.sceneConfig),m){ft.clearAnimations();let E=++gt.current;We.current={requestId:E,modelName:o.model.name??"model",modelUrl:o.model.url,storedBindings:o.objectBindings,streaming:!!o.model.tilesetUrl},Rt.current=null,H(null),Pt(!0),f(o.model.url)}xo.current={modelUrl:o.model.url,bindings:R,sceneConfig:o.sceneConfig}},[$,So,o,c,he,u,z,fe,ft.clearAnimations]);let da=le(d);da.current=d,_e(()=>{if(!o||!da.current||!c)return;if(!Fi.current){Fi.current=!0;return}let s=xo.current;if(c===o.model.url&&$===o.objectBindings&&he===o.sceneConfig||s!==null&&c===s.modelUrl&&$===s.bindings&&he===s.sceneConfig){fn.current=!1;return}if(We.current)return;if(fn.current){fn.current=!1;return}let m=window.setTimeout(()=>{da.current?.({projectId:o.id,baseRevision:o.revision,model:{...u??o.model,url:c,name:B||o.model.name},objectBindings:$,sceneConfig:he},"local")},l);return()=>window.clearTimeout(m)},[$,B,c,o,l,u,he]),_e(()=>{let s=m=>{if(m.key.toLowerCase()!=="z"||!(m.metaKey||m.ctrlKey))return;let v=m.target,y=v?.tagName;if(y==="INPUT"||y==="TEXTAREA"||v?.isContentEditable)return;m.preventDefault();let R=Bt==="scene"?fe:z;m.shiftKey?R.redo():R.undo()};return window.addEventListener("keydown",s),()=>window.removeEventListener("keydown",s)},[Bt,z,fe]);let ca=!o&&w,{handleTextureUpload:qd}=Ll({autosaveEnabled:ca,hasEdits:Td,modelUrl:c,bindings:$,sceneConfig:he,parkedModels:x,mergedModelSources:Ve,modelOrder:O,onTextureUpload:k,modelSourceRef:et,pendingLoadRef:We,storedModelKeysRef:ra,uploadedFilesRef:hn,pendingAutosaveRef:jn,autosaveFailureShownRef:zd,setStatusMessage:J,setStatusTone:Q});_e(()=>{if(Be||lo==="default"||lo==="success")return;Bn(!0);let s=window.setTimeout(()=>Bn(!1),4e3);return()=>window.clearTimeout(s)},[hi,lo,Be]);let ht=it(()=>Object.keys($),[$]),Jd=it(()=>!P||!ke?null:ke.id.trim()?Object.entries($).some(([v,y])=>v!==P&&y.id===ke.id)?"Another binding already uses this ID.":null:"ID is required.",[$,P,ke]),Ue=(s,m)=>{qt(v=>{let y=cn.current,R=y.mode&&y.keys.includes(s)?y.keys.filter(U=>v[U]):[s];if(R.length<=1)return{...v,[s]:m(v[s],s)};let E={...v};for(let U of R){let G=v[U];E[U]={...m(G,U),id:G.id,modelObjectId:G.modelObjectId}}return E})},ba=(s,m)=>{Ue(s,v=>{let y=pi(m(v.style?.material));return mi(v,y)})},Xd=(s,m,v)=>{ba(s,y=>({...y,[m]:v?{path:v}:void 0}))},Zd=(s,m)=>{Ko(v=>({...v,[s]:m})),!m&&P&&Ue(P,v=>{let y=pi(td(v.style?.material,s));return mi(v,y)})},pa=W((s,m,v)=>{let{bindings:y,originalTransforms:R,nodeNames:E}=eo(s,v);rt.current=R,z.reset(dn(s,v??{},Ve,y)),H(E[0]??null),v||ho(U=>({...U,annotations:[]})),J(`Generated ${E.length} bindings from ${m}.`),Q("success"),Zt.current=100,Jt(100),je.current&&clearTimeout(je.current),je.current=setTimeout(()=>{je.current=null,Pt(!1),Jt(null)},400)},[z,ho,Ve]),ua=(s,m,v,y)=>{jn.current?.();let R=++gt.current;ea(),o||fe.reset(s!==c?wt(he):he),s!==c&&ft.clearAnimations(),x.forEach(G=>G.resolved?.cleanup()),N([]),T([s]),io([]),Pt(!0),Jt(null),Zt.current=0,je.current&&(clearTimeout(je.current),je.current=null),vo.current=v;let E=v?v/1048576:0;J(E>=100?`Reading ${m} (${Math.round(E)}MB \u2014 large file, this can take a while)...`:`Reading ${m} and generating starter bindings...`),Q("default"),a(m),L(y??{url:s,name:m}),mn(null);let U=Rt.current;if(s===c&&U?.url===s){We.current=null,pa(U.scene,m);return}We.current={requestId:R,modelName:m,modelUrl:s,streaming:!!y?.tilesetUrl},f(s),z.reset({}),H(null)},Qd=W(s=>{c&&It.current.get(c)!==s&&(It.current.set(c,s),$i(v=>v+1));let m=We.current;if(!(m&&m.requestId!==gt.current)&&(c&&(Rt.current={url:c,scene:s}),zt(null),Pn(null),!!m)){if(We.current=null,m.streaming){J(`Streaming ${m.modelName}.`),Q("success"),Pt(!1);return}m.storedBindings&&(fn.current=!0),pa(s,m.modelName,m.storedBindings),m.restoring&&J(`Restored your last session with ${m.modelName}.`)}},[pa,c]),ec=W(s=>{if(!u?.tilesetUrl)return;let m=s.map(y=>y.name);if(m.length===0)return;Ii.current=m,fn.current=!0;let v=So(m,o?.objectBindings);if(z.reset(v),o){let y=xo.current;xo.current={modelUrl:y?.modelUrl??o.model.url,bindings:v,sceneConfig:y?.sceneConfig??o.sceneConfig}}H(y=>y??m[0]??null),J(`Streaming ${m.length} bindable objects.`),Q("success"),Pt(!1)},[So,z,o,u]),tc=W(s=>{let m=We.current;if(!(m&&m.requestId!==gt.current)){if(We.current=null,console.error(s),m?.restoring)et.current=null,f(null),J(od(m.modelName));else if(m)J(or(s)?`${m.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 ${m.modelName}. Make sure the file is a valid GLB, GLTF, OBJ, FBX, USDZ, STL, or PLY asset.`);else{let{detail:v}=No(s,c??"",Fe.current?.format);J(`Could not read ${B||"the model"}. ${v}`)}Q("error"),je.current&&(clearTimeout(je.current),je.current=null),Zt.current=0,Pt(!1),Jt(null)}},[c,B]),nc=W(s=>{let m=null;if(s.lengthComputable&&s.total>0)m=s.loaded/s.total*100;else{let y=vo.current;y&&y>0&&(m=s.loaded/y*100)}if(m===null)return;let v=Math.min(90,Math.floor(m/10)*10);v>Zt.current&&(Zt.current=v,Jt(v)),m>=99.5&&J(y=>y.startsWith("Finalizing")?y:"Finalizing model \u2014 parsing geometry and textures (large files can take a moment here)...")},[]),oc=W(s=>{ft.handleAnimationsReady(s),c&&xn.handleModelAnimationsReady(c,s)},[ft,c,xn.handleModelAnimationsReady]),km=async()=>{Fe.current?.cleanup(),Fe.current=null,et.current={model:{kind:"url",url:nd,name:"room.glb"}},await ua(nd,"room.glb")},Ji=async s=>{if(!w)return;if(b){try{Pt(!0),J(`Uploading ${s.name}...`),Q("default");let y=await b(s);et.current={model:{kind:"url",url:y.url,name:y.name??s.name}},await ua(y.url,y.name??s.name,s.size,y)}catch(y){Pt(!1),J(y instanceof Error?y.message:`Could not upload ${s.name}.`),Q("error")}return}let m;try{m=await en(s)}catch(y){J(y instanceof Error?y.message:"Could not read model file. Upload a .glb, .gltf, .obj, .fbx, .usdz, .stl, .ply, or .zip asset."),Q("error");return}Fe.current?.cleanup(),Fe.current=m;let v=gi();hn.current.set(v,s),et.current={model:{kind:"file",key:v,name:m.name},file:s},await ua(m.url,m.name,s.size,{url:m.url,name:m.name})},ac=async s=>{let m=s.target.files?.[0];m&&(await Ji(m),s.target.value="")},Co=()=>{jn.current=null,st(),Fe.current?.cleanup(),Fe.current=null,Rt.current=null,We.current=null,et.current=null,ft.clearAnimations(),rt.current={},gn.current=0,Rn(!1),je.current&&(clearTimeout(je.current),je.current=null),Zt.current=0,Jt(null),vo.current=void 0,f(null),a(""),x.forEach(s=>s.resolved?.cleanup()),N([]),T([]),io([]),L(null),H(null),mn(null),z.reset({}),co("{}"),bo("{}"),po(null),uo(null),ia(null),Ti(!1),Bi(!1),ho(s=>wt(s)),J("Load the demo model or upload a GLB, GLTF, OBJ, FBX, USDZ, STL, or PLY model to generate bindings."),Q("default")},ic=()=>{wo.length>1?On(!0):Co()},rc=()=>{On(!1)},sc=s=>{if(On(!1),O.length<=1){Co();return}if(!O.includes(s))return;if(st(),s!==c){let E=x.find(U=>U.url===s);E?.resolved?.cleanup(),N(U=>U.filter(G=>G.url!==s)),T(U=>U.filter(G=>G!==s)),J(`Removed ${E?.name??"the model"}.`),Q("success");return}let m=O.filter(E=>E!==s),v=m[0],y=x.findIndex(E=>E.url===v),R=x[y];if(!R){Co();return}Fe.current?.cleanup(),N(E=>E.filter((U,G)=>G!==y)),T(m),Fe.current=R.resolved??null,et.current={model:R.sessionModel??{kind:"url",url:R.url,name:R.name}},Rt.current=null,We.current=null,rt.current=R.originalTransforms,ft.clearAnimations(),Qo(R),f(R.url),a(R.name),L({url:R.url,name:R.name}),z.restoreModel(R),H(Object.keys(R.bindings)[0]??null),mn(null),J(`Removed the model \u2014 now viewing ${R.name}.`),Q("success")},lc=s=>{On(!1);let m=Ve.find(R=>R.url===s);if(m){st(),z.removeMerge(s),J(`Removed ${Mt(m.namePrefix)}.`),Q("success");return}let v=x.find(R=>R.mergedModelSources.some(E=>E.url===s));if(!v)return;let y=v.mergedModelSources.find(R=>R.url===s);y&&(st(),N(R=>R.map(E=>E.url!==v.url?E:ni(E,U=>ti(U,s)))),J(`Removed ${Mt(y.namePrefix)}.`),Q("success"))},dc=()=>{p.current?.click()},cc=()=>{Jo(!0)},bc=s=>{let m=s.target.files?.[0];s.target.value="";let v=fo.current;fo.current=null,!(!m||!w||!v)&&(v.mode==="separate"?mc(m):gc(m,v.targetUrl))},pc=W(()=>{fo.current=null,Jo(!1)},[]),uc=W(s=>{fo.current=s,Jo(!1),h.current?.click()},[]),mc=W(async s=>{let m;try{m=await en(s)}catch(y){J(y instanceof Error?y.message:"Could not read model file. Upload a .glb, .gltf, .obj, .fbx, .usdz, or .zip asset."),Q("error");return}let v=gi();hn.current.set(v,s),N(y=>[...y,{url:m.url,name:m.name,bindings:{},originalTransforms:{},resolved:m,sessionModel:{kind:"file",key:v,name:m.name},mergedModelSources:[]}]),T(y=>[...y,m.url]),st(),J(`Added ${m.name} as a separate model.`),Q("success")},[st]),gc=W(async(s,m)=>{let v;try{v=await en(s)}catch(Y){J(Y instanceof Error?Y.message:"Could not read model file. Upload a .glb, .gltf, .obj, .fbx, .usdz, or .zip asset."),Q("error");return}let y=Ni.current,R=y.parkedModels.find(Y=>Y.url===m);if(!y.modelOrder.includes(m)||m!==y.modelUrl&&!R){v.cleanup(),J("The destination model was removed. Choose a model and add the file again."),Q("error");return}let E=gi();hn.current.set(E,s);let U={url:v.url,resolved:v,sessionModel:{kind:"file",key:E,name:v.name},nodeNames:[],loadState:"loading"};m===y.modelUrl?z.addMerge(Y=>({...U,namePrefix:Qa(v.name,Y.mergeSources,Y.bindings)})):N(Y=>{let Me=Y.findIndex(At=>At.url===m);if(Me===-1)return Y;let xt=[...Y];return xt[Me]=ni(xt[Me],At=>({...At,mergeSources:[...At.mergeSources,{...U,namePrefix:Qa(v.name,At.mergeSources,At.bindings)}]})),xt});let G=m===y.modelUrl?y.modelName:R?.name;st(),J(`Merging ${v.name} into ${G||"the model"}...`),Q("default")},[z.addMerge,st]),fc=W((s,m)=>{let v=Ve.find(Y=>Y.url===s);if(v){let{bindings:Y,originalTransforms:Me,nodeNames:xt}=ei(m,$);z.hydrateMerge(s,{nodeNames:xt,loadState:"loaded"},Y),rt.current={...rt.current,...Me},J(`Merged ${xt.length} node${xt.length===1?"":"s"} from ${v.namePrefix||"the added model"} into ${B||"the model"}.`),Q("success");return}let y=x.find(Y=>Y.mergedModelSources.some(Me=>Me.url===s));if(!y)return;let R=y.mergedModelSources.find(Y=>Y.url===s);if(!R)return;let{bindings:E,originalTransforms:U,nodeNames:G}=ei(m,y.bindings);N(Y=>Y.map(Me=>Me.url!==y.url?Me:{...oi(Me,s,{nodeNames:G,loadState:"loaded"},E),originalTransforms:{...Me.originalTransforms,...U}})),J(`Merged ${G.length} node${G.length===1?"":"s"} from ${R.namePrefix||"the added model"} into ${y.name||"the model"}.`),Q("success")},[z.hydrateMerge,B,Ve,$,x]),hc=W((s,m)=>{let v=Ve.find(R=>R.url===s)??x.flatMap(R=>R.mergedModelSources).find(R=>R.url===s);if(!v)return;z.hydrateMerge(s,{loadState:"failed"}),N(R=>R.map(E=>E.mergedModelSources.some(U=>U.url===s)?oi(E,s,{loadState:"failed"}):E));let{detail:y}=No(m,s,v.resolved.format);J(`Could not merge ${v.resolved.name}. ${y} Remove the failed file using the Remove model menu.`),Q("error")},[Ve,x,z.hydrateMerge]),xc=W((s,m)=>{let v=x.find(R=>R.url===s);if(!v)return;let{detail:y}=No(m,s,v.resolved?.format);J(`Could not read ${v.name}. ${y} Remove the failed file using the Remove model menu.`),Q("error")},[x]),vc=W((s,m)=>{It.current.get(s)!==m&&(It.current.set(s,m),$i(v=>v+1)),N(v=>{let y=v.findIndex(G=>G.url===s);if(y===-1)return v;let{bindings:R,originalTransforms:E}=eo(m,v[y].bindings),U=[...v];return U[y]={...Bl(U[y],R),bindings:dn(m,v[y].bindings,v[y].mergedModelSources,R),originalTransforms:{...E,...v[y].originalTransforms}},U})},[]),Xi=W(s=>{if(o||s===c)return;let m=x.findIndex(R=>R.url===s);if(m===-1)return;let v=x[m];jn.current?.(),st();let y=c?{url:c,name:B,bindings:$,originalTransforms:rt.current,resolved:Fe.current??void 0,sessionModel:et.current?.model,mergedModelSources:Ve,modelSettings:Do(he),bindingHistory:z.snapshot,sceneHistory:fe.snapshot}:null;N(R=>{let E=R.filter((U,G)=>G!==m);return y?[...E,y]:E}),Fe.current=v.resolved??null,et.current={model:v.sessionModel??{kind:"url",url:v.url,name:v.name}},Rt.current=null,We.current=null,ft.clearAnimations(),Qo(v),rt.current=v.originalTransforms,f(v.url),a(v.name),L({url:v.url,name:v.name}),z.restoreModel(v),H(Object.keys(v.bindings)[0]??null),mn(null)},[o,c,B,$,x,z,Ve,he,fe,Qo,ft.clearAnimations,st]),yc=()=>{C.current?.click()},{handleExportBindings:Zi,handleImportBindingsChange:wc,openSceneConfigImportPicker:Sc,handleImportSceneConfigChange:Cc}=Zl({bindings:$,setBindings:qt,setSceneConfig:En,nodeKeys:ht,sceneConfigInputRef:g,setIsExporting:rd,setStatusMessage:J,setStatusTone:Q}),kc=s=>{s.preventDefault(),s.stopPropagation(),!(Be||c)&&(gn.current+=1,Rn(!0))},Mc=s=>{s.preventDefault(),s.stopPropagation(),!(Be||c)&&(s.dataTransfer.dropEffect="copy",Rn(!0))},Nc=s=>{s.preventDefault(),s.stopPropagation(),!(Be||c)&&(gn.current=Math.max(0,gn.current-1),gn.current===0&&Rn(!1))},Tc=async s=>{if(s.preventDefault(),s.stopPropagation(),gn.current=0,Rn(!1),Be||c)return;let m=s.dataTransfer.files?.[0];m&&await Ji(m)},Qi=(s,m,v)=>{if(!P)return;let y;try{y=JSON.parse(m)}catch{v("Invalid JSON");return}if(y===null||typeof y!="object"||Array.isArray(y)){v("Expected a JSON object");return}if(s==="metrics"&&Object.values(y).some(E=>typeof E!="number"||!Number.isFinite(E))){v("Metrics values must be numbers");return}Ue(P,R=>({...R,[s]:y})),v(null)},Pc=W((s,m)=>{ca&&Io(s,m).catch(v=>console.warn("[BindingBuilder] Could not store decal image for autosave:",v))},[ca]),Bc=it(()=>{let s=Rt.current?.scene,v=(s&&P?Hn(s,P):null)?.geometry;if(!v)return .2;v.boundingBox||v.computeBoundingBox();let y=v.boundingBox?.getSize(new gm),R=y?Math.max(y.x,y.y,y.z):0;return R>0&&Number.isFinite(R)?R/3:.2},[P,c,Be]),Rc=it(()=>{if(!so?.moving)return null;let{nodeKey:s,decal:m}=so,v=$[s],y=v?.decals?.find(R=>R.id===m.id);return y?{objectId:v.modelObjectId??s,decal:y,onCancel:()=>zt(null),onCommit:R=>{qt(E=>{let U=E[s];return U?{...E,[s]:{...U,decals:U.decals?.map(G=>G.id===y.id?{...G,...R}:G)}}:E}),zt(null)}}:null},[$,so,qt]),Ac=W((s,m)=>{if(!P)return;let v=$[P],y=v?.decals?.find(G=>G.id===s);if(!y)return;let R=zn.current,E=R?.raw.nodes[v.modelObjectId??P],U=Er(E,R?.raw.controls.camera,y,m);if(!U){J("No visible surface in that direction. Try another arrow or rotate the view."),Q("error"),Bn(!0);return}zt(null),Bn(!1),Ue(P,G=>({...G,decals:G.decals?.map(Y=>Y.id===s?{...Y,...U}:Y)}))},[$,P,Ue]),Oc=W(s=>{if(!s||s.moving){zt(s);return}let m=zn.current,v=$[s.nodeKey],y=m?.raw.nodes[v?.modelObjectId??s.nodeKey],R=Lr(y,m?.raw.controls.camera);if(!R){J("Could not find a surface on this object for the decal."),Q("error"),Bn(!0);return}let E={...s.decal,...R};qt(U=>{let G=U[s.nodeKey];if(!G)return U;let Y=(G.decals??[]).filter(Me=>Me.id!==E.id);return{...U,[s.nodeKey]:{...G,decals:[...Y,E]}}}),zt({...s,moving:!0})},[$,qt]),Lc=W((s,m)=>{let v=Object.entries($).find(([G,Y])=>Y===s||G===s.modelObjectId||Y.modelObjectId===s.modelObjectId)?.[0],y=v?$[v]?.decals?.find(G=>G.id===m):void 0;if(!v||!y)return;mo("object"),yi(G=>({...G,decals:!0})),H(v);let{position:R,normal:E,...U}=y;setTimeout(()=>zt({nodeKey:v,decal:U,moving:!0}),0)},[$]),ko=W(s=>{let m=Le.includes(s),v=m?Le.filter(y=>y!==s):[...Le,s];Qe(v),m?P===s&&H(v[v.length-1]??null):H(s)},[Le,P]),Ec=W(()=>{if(q){Ke(!1),Qe([]);return}Ke(!0),Qe(P?[P]:[])},[q,P]),er=W(s=>{Qe(s),H(m=>m&&s.includes(m)?m:s[s.length-1]??null)},[]),Dc=W(s=>{if(De){na("orbit");return}if(!s){if(q)return;H(null);return}let m=Object.entries($).find(([v,y])=>y===s||v===s.modelObjectId||y.modelObjectId===s.modelObjectId)?.[0]??null;if(q){m&&ko(m);return}H(m)},[De,$,q,ko]),jc=W(async s=>{if(De){na("orbit");return}if(q){ko(s);return}H(s),ia(null),await _i(s)},[De,_i,q,ko]),zc=W(s=>{ia(s?$[s]??null:null)},[$]),Ic=W(s=>ud(!s),[]),Fc=W(()=>{if(De){J("Camera positions aren't available while Pointer Lock is the active camera controller."),Q("error");return}if(!P||!xe)return;let s={position:xe.position,target:xe.target,...xe.fov!=null?{fov:xe.fov}:{},zoom:xe.zoom};Ue(P,m=>({...m,cameraState:s}))},[De,P,xe]),Hc=W(()=>{if(De){J("Camera positions aren't available while Pointer Lock is the active camera controller."),Q("error");return}!Ft?.position||!Ft?.target||yo({position:Ft.position,target:Ft.target,fov:Ft.fov??xe?.fov??null,zoom:Ft.zoom??xe?.zoom??1},!0)},[De,Ft,yo,xe]),$c=W(()=>{De||P&&Ue(P,s=>({...s,cameraState:void 0}))},[De,P]),Vc=W(async()=>{if(De){J("Reset View isn't available while Pointer Lock is the active camera controller."),Q("error");return}await Gi()},[De,Gi]),Uc=W(async()=>{if(De){J("Fit Scene isn't available while Pointer Lock is the active camera controller."),Q("error");return}await Ki()},[De,Ki]),Gc=W(()=>{J("Texture position saved."),Q("success"),Di.current?.()},[]),tr=W(s=>{Mi(s),ki(!0)},[]),Mo=W(()=>{ki(!1),Mi(null)},[]),_c=W(()=>{if(go==="bindings"){if(!ht.length){Mo();return}let s=$n(ht,Vi);z.reset(s,{asEdit:!0}),H(ht[0]??null),J("Object bindings reset to default values."),Q("success")}else go==="scene"&&(fe.reset(vn,{asEdit:!0}),J("Scene config reset to default values."),Q("success"));Mo()},[go,ht,z,fe,Mo]),Kc=W(s=>{Xo(s)},[]),Wc=W(()=>{Xo(null)},[]),Yc=W(()=>{let s=Ln;if(!s)return;let m=$[s]?.label||s;Ue(s,v=>({...v,removed:!0})),H(v=>v===s?null:v),Pn(v=>v===s?null:v),J(`Deleted ${m}.`),Q("success"),Xo(null)},[Ln,$,Ue]),qc=W(()=>{qo(null)},[]),Jc=async()=>{let s;try{s=await ts()}catch(m){console.warn("[BindingBuilder] Could not read the saved session:",m),J("Couldn't read the saved session from this browser."),Q("error");return}if(!s){J("No saved session in this browser. Sessions are saved when you edit a model or add another one."),Q("error");return}qo(s)},ma=async(s,m)=>(await Promise.all(s.map(async({entry:y,file:R})=>{if(y.model.kind==="url")return console.warn(`[BindingBuilder] Could not restore merged model "${y.model.name}" \u2014 merged models must come from an uploaded file.`),null;if(!R)return console.warn(`[BindingBuilder] Could not restore merged model "${y.model.name}" \u2014 its file is no longer in this browser's storage.`),null;try{let E=await en(R);return m.set(y.model.key,R),{url:E.url,namePrefix:y.namePrefix,resolved:E,sessionModel:y.model,nodeNames:[],loadState:"loading"}}catch(E){return console.warn(`[BindingBuilder] Could not restore merged model "${y.model.name}":`,E),null}}))).filter(y=>y!==null),Xc=async(s,m,v)=>{let y=await Promise.all(s.map(async({entry:E,file:U,mergeFiles:G})=>{if(E.model.kind==="url")return{url:E.model.url,name:E.model.name,bindings:await Tn(E.bindings),originalTransforms:E.originalTransforms,modelSettings:E.modelSettings,sessionModel:E.model,mergedModelSources:await ma(G,v)};if(!U)return console.warn(`[BindingBuilder] Could not restore parked model "${E.model.name}" \u2014 its file is no longer in this browser's storage.`),null;try{let Y=await en(U);return v.set(E.model.key,U),{url:Y.url,name:E.model.name,bindings:await Tn(E.bindings),originalTransforms:E.originalTransforms,modelSettings:E.modelSettings,resolved:Y,sessionModel:E.model,mergedModelSources:await ma(G,v)}}catch(Y){return console.warn(`[BindingBuilder] Could not restore parked model "${E.model.name}":`,Y),null}})),R=await ma(m,v);return{parkedModels:y.filter(E=>E!==null),mergedModelSources:R}},Zc=async()=>{let s=Xt;if(qo(null),!s)return;let{session:m,file:v}=s,{model:y}=m;jn.current=null;let R=Un(vn,m.sceneConfig),E=gt.current,U=await Tn(m.bindings);if(gt.current!==E)return;let G=new Map,{parkedModels:Y,mergedModelSources:Me}=await Xc(s.parkedFiles,s.mergeFiles,G);if(gt.current!==E){Y.forEach(Qn),Me.forEach(Mn);return}let xt=lt=>{let tt=new Map;tt.set(Gn(y),lt),Y.forEach(dt=>{dt.sessionModel&&tt.set(Gn(dt.sessionModel),dt.url)});let Qt=(m.modelOrder??[]).map(dt=>tt.get(dt)).filter(dt=>!!dt),nr=new Set(Qt);for(let dt of[lt,...Y.map(eb=>eb.url)])nr.has(dt)||(Qt.push(dt),nr.add(dt));return Qt},At=()=>{for(let[lt,tt]of G)hn.current.set(lt,tt),ra.current.add(lt)},vt;if(y.kind==="file"){if(!v){Y.forEach(Qn),Me.forEach(Mn);return}let lt=gt.current,tt;try{tt=await en(v)}catch(Qt){console.warn("[BindingBuilder] Could not read the saved model:",Qt),J(od(y.name)),Q("error"),Y.forEach(Qn),Me.forEach(Mn);return}if(gt.current!==lt){tt.cleanup(),Y.forEach(Qn),Me.forEach(Mn);return}Fe.current?.cleanup(),Fe.current=tt,vt=tt.url,G.set(y.key,v),At(),ea(),x.forEach(Qt=>Qt.resolved?.cleanup()),N(Y),io(Me),T(xt(vt))}else{vt=y.url,At(),ea(),x.forEach(tt=>tt.resolved?.cleanup()),N(Y),io(Me),T(xt(vt));let lt=Rt.current;if(vt===c&<?.url===vt&&!We.current){et.current={model:y},z.reset(dn(lt.scene,U,Me,eo(lt.scene,U).bindings)),fe.reset(R),J(`Restored your last session with ${y.name}.`),Q("success");return}Fe.current?.cleanup(),Fe.current=null}et.current={model:y,file:v??void 0},y.kind==="file"&&ra.current.add(y.key);let Qc=++gt.current;vt!==c&&ft.clearAnimations(),Pt(!0),Jt(null),Zt.current=0,je.current&&(clearTimeout(je.current),je.current=null),vo.current=v?.size,J(`Restoring your last session with ${y.name}...`),Q("default"),a(y.name),L({url:vt,name:y.name}),mn(null),H(null),Rt.current=null,z.reset({}),fe.reset(R),We.current={requestId:Qc,modelName:y.name,modelUrl:vt,storedBindings:U,restoring:!0},f(vt)};if(Dn.status==="checking")return j("div",{className:"bb-root bb-root--licenseChecking",children:j(fa,{title:"Verifying License",message:"Checking your license key..."})});if(Dn.status==="invalid")return j("div",{className:"bb-root bb-root--licenseInvalid",children:j(fa,{tone:"error",title:"Invalid License",message:Dn.isLocalDomain?Dn.reason??"License has been revoked or has expired":"Failed to load. Please contact the site administrator."})});let ga=De?j(Yt,{children:"Click the preview to look around \xB7 Esc to release"}):Zo?j(Yt,{children:"Select a mesh \xB7 drag the colored arrows, planes, or rings"}):Ad&&Yo?ge(Yt,{children:[ge("span",{children:[j("kbd",{children:"W"}),j("kbd",{children:"A"}),j("kbd",{children:"S"}),j("kbd",{children:"D"})," move"]}),ge("span",{children:["\xB7 ",j("kbd",{children:"Space"}),"/",j("kbd",{children:"C"})," up \xB7 down"]}),j("span",{children:"\xB7 drag to look"})]}):null;return ge(Nr.Provider,{value:jd,children:[ge("div",{className:"bb-root",children:[j("input",{ref:p,type:"file",accept:ha,className:"bb-hiddenInput",onChange:ac,disabled:Be}),j("input",{ref:h,type:"file",accept:ha,className:"bb-hiddenInput",onChange:bc,disabled:Be}),j("input",{ref:C,type:"file",accept:".json,application/json",className:"bb-hiddenInput",onChange:wc,disabled:Be}),j("input",{ref:g,type:"file",accept:".json,application/json",className:"bb-hiddenInput",onChange:Cc,disabled:Be}),ge("aside",{className:`bb-sidebar bb-sidebar--left ${bn?"bb-sidebar--collapsed":""}`,children:[ge("div",{className:"bb-header bb-header--sidebar",children:[!bn&&j("h1",{className:"bb-title",children:"Binding Builder"}),j("button",{type:"button",className:"bb-sidebarToggle",onClick:()=>bd(s=>!s),"aria-label":bn?"Open editor sidebar":"Collapse editor sidebar",title:bn?"Open editor":"Collapse editor",children:bn?"\u2192":"\u2190"})]}),!bn&&ge(Yt,{children:[ge("div",{className:"bb-tabRow",children:[j("button",{type:"button",className:`bb-tab ${Bt==="object"?"bb-tab--active":""}`,onClick:()=>mo("object"),children:"Object"}),j("button",{type:"button",className:`bb-tab ${Bt==="scene"?"bb-tab--active":""}`,onClick:()=>mo("scene"),children:"Scene"})]}),j("section",{className:"bb-editor",children:Bt==="scene"?j(Yt,{children:c?j(Ua,{config:he,onChange:En,activeSubTab:An,onActiveSubTabChange:wi,cameraState:(An==="Cinematic"||An==="Annotations")&&xe?{position:xe.position,target:xe.target,azimuthAngle:xe.azimuthAngle,polarAngle:xe.polarAngle,fov:xe.fov,zoom:xe.zoom}:null,onPreviewWaypoint:Ud,animationClipDetails:xn.clipDetails,animationConfig:Wi.config,onAnimationConfigChange:Wi.onChange,animationPlayback:xn,materialVariantGroups:Id,objectBindings:$}):j("div",{className:"bb-emptyEditor",children:"Upload a model to edit its scene settings."})}):!ke||!P?j("div",{className:"bb-emptyEditor",children:"Select a generated node binding to edit its values."}):ge(Yt,{children:[ge("div",{className:"bb-editorHeader",children:[ge("div",{children:[j("div",{className:"bb-sectionKicker",children:"Editing Binding"}),j("h2",{className:"bb-editorTitle",children:q&&Le.length>1?`${Le.length} objects selected`:ke.label||P}),j("div",{className:"bb-editorMeta",children:q?j("span",{children:"Changes apply to every selected object"}):ge(Yt,{children:[j("span",{children:ke.type}),j("span",{children:ke.modelObjectId})]})})]}),!q&&j("button",{type:"button",className:"bb-editorDeleteButton",onClick:()=>Kc(P),title:"Delete this object","aria-label":"Delete this object",children:j(wm,{size:18})})]}),!q&&j(ll,{selectedItem:P,selectedBinding:ke,open:ut.identity,onToggle:()=>mt("identity"),updateBinding:Ue,idError:Jd}),!q&&j(cl,{selectedItem:P,selectedBinding:ke,open:ut.basics,onToggle:()=>mt("basics"),updateBinding:Ue}),q&&j(Ee,{title:"Basics",open:ut.basics,onToggle:()=>mt("basics"),children:j("div",{className:"bb-groupFlags",children:["selectable","hoverable","visible"].map(s=>j(Sm,{label:s,values:Le.map(m=>$[m]).filter(m=>m&&!m.removed).map(m=>m[s]!==!1),onChange:m=>Ue(P,v=>({...v,[s]:m}))},s))})}),ge(Ee,{title:"Material",open:ut.material,onToggle:()=>mt("material"),tooltip:"Edit the selected object's base material, textures, and surface properties.",children:[j(sl,{disabled:!P,onApply:s=>P&&ba(P,m=>({...m,...s}))}),j(il,{selectedItem:P,selectedMaterial:sa,pbrWorkflow:hd,onPbrWorkflowChange:xd,openMaterialPanels:md,materialPanelEnabled:vd,onToggleMaterialPanel:fd,onSetMaterialPanelState:Zd,updateSelectedMaterial:ba,setSelectedTexturePath:Xd,isTexturePositioningEnabled:Ld,onConfirmTexturePosition:Gc,takesImage:Yi})]}),!q&&j(gl,{selectedItem:P,selectedBinding:ke,open:ut.decals,onToggle:()=>mt("decals"),updateBinding:Ue,placement:so,onPlacementChange:Oc,defaultSize:Bc,onImageFile:Pc,onNudge:Ac}),!q&&j(pl,{selectedItem:P,selectedBinding:ke,open:ut.actions,onToggle:()=>mt("actions"),updateBinding:Ue,takesImage:Yi}),!q&&j(fl,{selectedBinding:ke,open:ut.camera,onToggle:()=>mt("camera"),cameraState:xe,formattedCameraState:Kd,savedCameraPosition:Ft,onSaveCameraPosition:Fc,onGoToSavedCamera:Hc,onClearSavedCamera:$c,onResetView:Vc,onFitScene:Uc}),j(yl,{selectedItem:P,selectedBinding:ke,open:ut.transform,onToggle:()=>mt("transform"),updateBinding:Ue,moveModeEnabled:Zo,onToggleMoveMode:Ti,scaleModeEnabled:Pi,onToggleScaleMode:Bi,transformSpace:Ri,onTransformSpaceChange:Nd,originalTransform:rt.current[P]??null,originalTransforms:rt.current}),j(Xa,{title:"Metrics",label:"Metrics JSON",open:ut.metrics,onToggle:()=>mt("metrics"),draft:xi,error:ld,example:'{"area": 42}',onDraftChange:co,onCommit:()=>Qi("metrics",xi,po)}),j(Xa,{title:"Metadata",label:"Metadata JSON",open:ut.metadata,onToggle:()=>mt("metadata"),draft:vi,error:dd,example:'{"room": "kitchen"}',onDraftChange:bo,onCommit:()=>Qi("metadata",vi,uo)})]})}),Bt==="object"&&j(ri,{canUndo:z.canUndo,canRedo:z.canRedo,onUndo:z.undo,onRedo:z.redo,onReset:()=>tr("bindings"),resetDisabled:!ht.length,resetTitle:"Reset object bindings to default",onImport:yc,importDisabled:!ht.length||Be,importTitle:"Re-apply a previously exported objectBindings.json onto this model",exportDisabled:!ht.length||fi,exporting:fi,exportTitle:"Active model bindings",exportDescription:"Object bindings for the active model only. Other models, model files and scene settings are not included.",onExportJson:()=>Zi("json"),onExportTs:()=>Zi("ts")}),Bt==="scene"&&j(ri,{canUndo:fe.canUndo,canRedo:fe.canRedo,onUndo:fe.undo,onRedo:fe.redo,onReset:()=>tr("scene"),resetTitle:"Reset scene config to default",onImport:Sc,importDisabled:!ht.length||Be,importTitle:"Re-apply a previously exported sceneConfig.json",exportDisabled:!ht.length||Be,exportTitle:"Scene settings",exportDescription:"Shared scene settings and the active model's annotations, variants and animation settings. Model files and object bindings are not included.",onExportJson:()=>ao("sceneConfig.json",ql(he),"application/json"),onExportTs:()=>ao("sceneConfig.ts",Jl(he),"text/typescript")})]})]}),ge("main",{className:"bb-previewShell",children:[ge("div",{className:"bb-previewHeader",children:[j(Ma,{label:"View",icon:j(vm,{size:14,"aria-hidden":"true"}),title:"Preview options",children:()=>ge(Yt,{children:[ge("label",{className:"bb-headerMenuItem",children:[j("input",{type:"checkbox",checked:Ci,onChange:s=>yd(s.target.checked)}),"Zoom on selected"]}),ge("label",{className:"bb-headerMenuItem",children:[j("input",{type:"checkbox",checked:Wo,onChange:s=>wd(s.target.checked)}),"Highlight on hover"]}),ge("label",{className:"bb-headerMenuItem",children:[j("input",{type:"checkbox",checked:Yo,onChange:s=>Sd(s.target.checked)}),"Camera controller"]})]})}),j("div",{className:"bb-previewMeta",children:j("span",{title:P??void 0,children:P?`Focused: ${P}`:"Select a node to inspect it"})}),c&&ge("button",{type:"button",className:`bb-compareButton ${pn?"bb-compareButton--active":""}`,onClick:()=>{Pd(s=>!s),ta(null)},"aria-pressed":pn,title:"Compare: drag a divider across the preview to see it before and after your changes",children:[j(ym,{size:14}),"Compare"]}),w&&!o&&j(Ma,{icon:j(fm,{size:16,"aria-hidden":"true"}),title:"More model actions",align:"right",children:s=>j(Vr,{close:s,onRestore:c?void 0:Jc,restoreDisabled:Be,onAddModel:c?cc:void 0,addModelDisabled:Be,onRemove:c?ic:void 0,confirmRemove:wo.length<=1})})]}),ge("div",{className:"bb-preview",ref:S,onFocus:s=>{s.currentTarget.contains(s.relatedTarget)||aa()},children:[j(Tr,{visible:Be||sd,message:hi,tone:lo,progress:id??void 0}),c&&j("div",{className:`bb-canvasHint ${ga?"bb-canvasHint--visible":""} ${pn?"bb-canvasHint--belowCompare":""}`,"aria-hidden":!ga,children:ga}),c?j(ka,{loading:"eager",modelUrl:c,tilesetUrl:u?.tilesetUrl,models:qi,onModelChange:Xi,onExtraModelLoaded:vc,onExtraModelError:xc,mergeModels:la,onMergeModelLoaded:fc,onMergeModelError:hc,originalNodePoses:rt.current,objectBindings:$,selectedObject:ke,selectedObjectRefs:Hd,selectedObjectOutlineColor:"#22c55e",onObjectSelect:Dc,onSelectionClear:()=>er([]),onObjectBindingsChange:qt,onTextureUpload:qd,onObjectEditLeaseChange:(s,m)=>M?.(s.modelObjectId||s.id,m),showObjectBindingDataPanel:!1,showSceneObjectsPanel:!1,onCameraChange:$d,onViewerReady:s=>{zn.current=s,Fd(s.raw.nodes),Vd(s)},onAnnotationsChange:Wd,activeAnnotation:Ed?.annotation??null,onActiveAnnotationChange:Yd,onAnimationsReady:oc,onModelAnimationsReady:xn.handleModelAnimationsReady,onSceneLoaded:Qd,onLoadError:tc,onObjectCatalog:u?.tilesetUrl?ec:void 0,onProgress:nc,onCameraControllerChange:na,cameraControllerType:Oi,onTexturePositioningChange:Od,endTexturePositioningRef:Di,licenseKey:e,licenseValidationUrl:n,dracoDecoderPath:i,ktx2TranscoderPath:r,meshopt:t,sceneConfig:he,onSceneConfigChange:En,preserveDrawingBuffer:!0,disableZoom:!1,zoomOnSelected:Ci,highlightOnHover:Wo,enableCameraControls:Yo,moveModeEnabled:Zo,scaleModeEnabled:Pi,objectTransformSpace:Ri,enableKeyboardNavigation:!0,showViewGizmo:!0,showSectionTools:he.section?.enabled??!1,isolation:ad,onIsolationChange:()=>Pn(null),showIsolateControls:!0,decalMove:Rc,onDecalDoubleClick:Lc,panelHoveredObject:Wo?Dd:null,showLoadingOverlay:!1,autoRotate:De?!1:he.model.autoRotate??!1,autoRotateSpeed:he.model.autoRotateSpeed??1}):j("div",{className:`bb-previewPlaceholder ${cd?"bb-previewPlaceholder--dragActive":""}`,onDragEnter:kc,onDragOver:Mc,onDragLeave:Nc,onDrop:Tc,children:ge("div",{children:[j("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."}),w?j("button",{type:"button",className:"bb-previewPlaceholderButton",onClick:dc,disabled:Be,children:"Upload"}):null]})}),c&&pn?j(_r,{liveViewerRef:zn,split:Bd,onSplitChange:Rd,labels:[un?"Pinned":"Before","Now"],beforeAction:ge("button",{type:"button",className:"ri-compare__labelAction",onClick:()=>ta(s=>s?null:{bindings:$,sceneConfig:he}),"aria-pressed":!!un,title:un?"Unpin: compare with the project as it was opened again":"Pin as before: compare later changes with how the preview looks now",children:[un?j(xm,{size:12}):j(hm,{size:12}),un?"Unpin":"Pin"]}),renderBefore:s=>j(ka,{loading:"eager",modelUrl:c,tilesetUrl:u?.tilesetUrl,objectBindings:Ai.bindings,sceneConfig:Ai.sceneConfig,licenseKey:e,licenseValidationUrl:n,dracoDecoderPath:i,ktx2TranscoderPath:r,meshopt:t,preset:"minimal",showLoadingOverlay:!1,showObjectNavigator:!1,selectedObject:null,zoomOnSelected:!1,highlightOnHover:!1,autoRotate:!1,cinematic:!1,onViewerReady:s})}):null]})]}),j(Sl,{bindings:$,selectedItem:P,onSelect:jc,onHover:zc,isOpen:!pd,onToggle:Ic,modelGroups:_d,onSelectModel:Xi,isolatedItem:ro,onIsolate:Pn,multiSelectEnabled:q,onToggleMultiSelect:Ec,multiSelectedKeys:Le,onSetMultiSelected:er})]}),Cd&&j(Vl,{target:go,onCancel:Mo,onConfirm:_c}),Xt&&j(Ul,{modelNames:[Xt.session.model.name,...(Xt.session.parkedModels??[]).map(s=>s.model.name)],mergedSourceCount:(Xt.session.mergeModels?.length??0)+(Xt.session.parkedModels??[]).reduce((s,m)=>s+(m.mergeModels?.length??0),0),savedAt:Xt.session.savedAt,onCancel:qc,onConfirm:Zc}),kd&&j(_l,{destinations:wo.filter(s=>s.kind==="model"),onCancel:pc,onChoose:uc}),Md&&j(Kl,{options:wo,onCancel:rc,onRemoveModel:sc,onRemoveMerge:lc,onRemoveAll:()=>{On(!1),Co()}}),Ln&&j(Gl,{nodeLabel:$[Ln]?.label||Ln,onCancel:Wc,onConfirm:Yc})]})}export{Cm as a};
|