@liveroom-tech/react-immersive 6.0.1 → 6.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (67) hide show
  1. package/README.md +26 -2
  2. package/dist/AnimationsTab-NUJTEMZ5.mjs +1 -0
  3. package/dist/AnnotationsTab-OHRVWRKI.mjs +1 -0
  4. package/dist/CinematicTab-IJAY2BS6.mjs +1 -0
  5. package/dist/ConfigureTab-UQRRATCY.mjs +6 -0
  6. package/dist/RulesTab-YVBZGJZX.mjs +1 -0
  7. package/dist/SequencesTab-IC5LWQ6N.css +1 -0
  8. package/dist/SequencesTab-RPJAG26Z.mjs +1 -0
  9. package/dist/binding-builder.css +1 -1
  10. package/dist/binding-builder.d.mts +3 -3
  11. package/dist/binding-builder.d.ts +3 -3
  12. package/dist/binding-builder.js +76 -23
  13. package/dist/binding-builder.mjs +1 -1
  14. package/dist/chunk-2DV2UCQH.mjs +1 -0
  15. package/dist/chunk-37YITTIK.mjs +1 -0
  16. package/dist/chunk-5FLX45O5.mjs +2 -0
  17. package/dist/chunk-6CTCV2Q5.mjs +1 -0
  18. package/dist/chunk-7JCFNZJM.mjs +1 -0
  19. package/dist/chunk-7OWHW66D.mjs +1 -0
  20. package/dist/chunk-AL6UIGWP.mjs +1 -0
  21. package/dist/chunk-BNKTI3CY.mjs +1 -0
  22. package/dist/chunk-CCBFMNAU.mjs +1 -0
  23. package/dist/chunk-E24EFHB5.mjs +1 -0
  24. package/dist/chunk-EV6THDXD.mjs +1 -0
  25. package/dist/chunk-F5QSXMME.mjs +1 -0
  26. package/dist/chunk-FGAJ2UT7.mjs +1 -0
  27. package/dist/chunk-FXV4CLAK.mjs +1 -0
  28. package/dist/chunk-GV4ZRXL6.mjs +1 -0
  29. package/dist/chunk-KHN55ZM7.mjs +3 -0
  30. package/dist/chunk-LX3GXQNU.mjs +1 -0
  31. package/dist/chunk-OPZJDP7T.mjs +1 -0
  32. package/dist/chunk-OREKYGO3.mjs +83 -0
  33. package/dist/chunk-PBVBZYOG.mjs +47 -0
  34. package/dist/chunk-T6AYLPCC.mjs +1 -0
  35. package/dist/hosted.css +1 -1
  36. package/dist/hosted.d.mts +22 -6
  37. package/dist/hosted.d.ts +22 -6
  38. package/dist/hosted.js +75 -22
  39. package/dist/hosted.mjs +1 -1
  40. package/dist/index.css +1 -1
  41. package/dist/index.d.mts +66 -6
  42. package/dist/index.d.ts +66 -6
  43. package/dist/index.js +69 -21
  44. package/dist/index.mjs +1 -1
  45. package/dist/{modelFileResolver-Co7j1tdQ.d.mts → modelFileResolver-BEW_95id.d.mts} +52 -7
  46. package/dist/{modelFileResolver-Co7j1tdQ.d.ts → modelFileResolver-BEW_95id.d.ts} +52 -7
  47. package/dist/{modelViewerProps-BibuMND7.d.ts → modelViewerProps-C7saa0i2.d.mts} +173 -3
  48. package/dist/{modelViewerProps-Ce4-wb57.d.mts → modelViewerProps-CbK_4uZj.d.ts} +173 -3
  49. package/dist/{publicProps-BaJHCDa_.d.mts → publicProps-NKTiohZO.d.mts} +1 -1
  50. package/dist/{publicProps-CP18d_mt.d.ts → publicProps-z7cJhUH8.d.ts} +1 -1
  51. package/dist/simple-model-viewer.css +1 -1
  52. package/dist/simple-model-viewer.d.mts +25 -3
  53. package/dist/simple-model-viewer.d.ts +25 -3
  54. package/dist/simple-model-viewer.js +49 -3
  55. package/dist/simple-model-viewer.mjs +1 -1
  56. package/dist/utils.d.mts +47 -4
  57. package/dist/utils.d.ts +47 -4
  58. package/dist/utils.js +2 -2
  59. package/dist/utils.mjs +1 -1
  60. package/package.json +5 -1
  61. package/dist/chunk-2JFUMJUP.mjs +0 -1
  62. package/dist/chunk-4JMJALRO.mjs +0 -2
  63. package/dist/chunk-OTSCPJWF.mjs +0 -1
  64. package/dist/chunk-P2JZ5Z7I.mjs +0 -1
  65. package/dist/chunk-UGPR4EPP.mjs +0 -81
  66. package/dist/chunk-V7WZUWJ5.mjs +0 -1
  67. package/dist/chunk-VQGYZOMX.mjs +0 -3
package/README.md CHANGED
@@ -4,7 +4,7 @@
4
4
  assets in React. Use its components and hooks for mesh selection, materials,
5
5
  visibility, camera control, animations, annotations, and scene authoring.
6
6
 
7
- **Documentation baseline: 5.2.0 · React 19.**
7
+ **Requires React 19.**
8
8
 
9
9
  [Documentation](https://react-immersive.liveroom.dev/docs) ·
10
10
  [AI Agent Guide](https://react-immersive.liveroom.dev/docs/agent-guide.md) ·
@@ -28,7 +28,7 @@ height. The package does not require Tailwind in the consuming application.
28
28
  In a React 19 application:
29
29
 
30
30
  ```bash
31
- npm install @liveroom-tech/react-immersive@5.2.0 three@^0.184.0 @react-three/fiber@^9.6.1
31
+ npm install @liveroom-tech/react-immersive three@^0.184.0 @react-three/fiber@^9.6.1
32
32
  ```
33
33
 
34
34
  | Peer | Supported range |
@@ -104,6 +104,30 @@ Pure data helpers, including `defineObjectBindings`, `patchBindings`,
104
104
  `patchSceneConfig`, and `selectBindings`, are available from the server-safe
105
105
  `@liveroom-tech/react-immersive/utils` entry.
106
106
 
107
+ ## Embed a hosted project without React
108
+
109
+ For Shopify, WordPress, Webflow, or plain HTML, open a hosted project's **Share**
110
+ menu, set **General access** to **Anyone with the link**, and choose **Copy embed
111
+ code**. Paste that iframe into an HTML/embed block. No npm package or license key
112
+ is needed on the parent page. The embed shows the saved viewer without editing
113
+ or collaboration controls; restricted projects cannot be embedded.
114
+
115
+ ```html
116
+ <iframe
117
+ src="https://react-immersive.liveroom.dev/embed/projects/YOUR_PROJECT_ID"
118
+ title="Interactive 3D viewer"
119
+ width="100%"
120
+ height="600"
121
+ style="display:block;width:100%;height:600px;border:0;"
122
+ loading="lazy"
123
+ allow="fullscreen; xr-spatial-tracking"
124
+ allowfullscreen
125
+ ></iframe>
126
+ ```
127
+
128
+ See [Embedding outside React](https://react-immersive.liveroom.dev/docs/embedding)
129
+ for platform instructions, sizing, updates, and access behavior.
130
+
107
131
  ## Find the API for your task
108
132
 
109
133
  - [ModelViewer](https://react-immersive.liveroom.dev/docs/reference/model-viewer.md): props, bindings, materials, annotations, exports, XR, performance.
@@ -0,0 +1 @@
1
+ import{b as w,f as C,k as M,l as k}from"./chunk-AL6UIGWP.mjs";import{c as S,h as A,i as P}from"./chunk-FGAJ2UT7.mjs";import"./chunk-JR557W27.mjs";import{useMemo as q,useState as D}from"react";import{ChevronRight as I,EyeOff as V,Pause as L,Play as G,Rewind as J,Square as K}from"lucide-react";import{Fragment as Y,jsx as n,jsxs as i}from"react/jsx-runtime";var Q={playing:"Playing",paused:"Paused",finished:"Finished"};function R(o){let r=Number.isFinite(o)&&o>0?o:0;if(r<60)return`${r.toFixed(1)}s`;let u=Math.floor(r/60),m=(r%60).toFixed(1).padStart(4,"0");return`${u}:${m}`}function W(o){return Number.isFinite(o)?Math.min(3,Math.max(.1,Number(o.toFixed(2)))):1}function X({config:o,onChange:r,clipDetails:u,active:m,play:b,pause:y,stop:h,setSpeed:x,seek:T}){let v=S(A().tier,"animationConfig"),[c,$]=D(!1),F=q(()=>new Map(u.map(e=>[e.sourceName,e.duration])),[u]),f=o.animations.clips.filter(e=>!e.hidden),d=o.animations.clips.filter(e=>e.hidden),N=(e,a=o.animations.autoplayClip)=>{r({...o,animations:{clips:e(o.animations.clips),autoplayClip:a}})},g=(e,a)=>{N(t=>t.map(l=>l.sourceName===e?a(l):l))},B=(e,a)=>{g(e,t=>({...t,loopMode:a}))},z=(e,a)=>{let t=W(a);g(e,l=>({...l,speed:t})),m.some(l=>l.clip===e)&&x(t,e)},O=(e,a)=>{g(e,t=>({...t,displayName:a}))},H=e=>{let a=o.animations.autoplayClip===e?null:e;r({...o,animations:{...o.animations,autoplayClip:a}})},E=e=>{N(a=>a.map(t=>t.sourceName===e?{...t,hidden:!0}:t),o.animations.autoplayClip===e?null:o.animations.autoplayClip),m.some(a=>a.clip===e)&&h(e)},U=e=>{N(a=>a.map(t=>t.sourceName===e?{...t,hidden:!1}:t))};return o.animations.clips.length===0?n(C,{title:"Clips",children:n("div",{className:"se-helperCard",children:"This model has no animation clips. Open one that does to set playback, names, and autoplay here."})}):i(C,{title:"Clips",children:[v?null:n(P,{requiredTier:"starter",feature:"Autoplay, looping, speed and clip names"}),f.length===0?n("p",{className:"se-listEmpty",children:"All clips are hidden. Show one below to use it again."}):n("div",{className:"se-animationList",children:f.map(e=>{let a=m.find(s=>s.clip===e.sourceName),t=a?.status==="playing",l=a?.time??0,p=F.get(e.sourceName)??0,_=a?Q[a.status]:"Ready";return i("article",{className:`se-clip ${a?"se-clip--active":""}`,children:[i("div",{className:"se-clipHeader",children:[n("input",{className:"se-clipName","aria-label":`Name of ${e.sourceName}`,title:e.sourceName,value:e.displayName,onChange:s=>O(e.sourceName,s.target.value),placeholder:e.sourceName}),o.animations.autoplayClip===e.sourceName?n("span",{className:"rui-chip",children:"Autoplay"}):null,n("span",{className:"rui-chip",children:_}),n("button",{type:"button",className:"se-iconButton",onClick:()=>E(e.sourceName),title:"Hide clip","aria-label":`Hide ${e.sourceName}`,children:n(V,{size:13})})]}),i("div",{className:"se-clipTransport",children:[n("button",{type:"button",className:"se-iconButton",onClick:()=>t&&!a?.reverse?y(e.sourceName):b(e.sourceName,{alongside:!0}),"aria-label":t&&!a?.reverse?"Pause":"Play",title:t&&!a?.reverse?"Pause":"Play",children:t&&!a?.reverse?n(L,{size:13}):n(G,{size:13})}),n("button",{type:"button",className:"se-iconButton",onClick:()=>t&&a?.reverse?y(e.sourceName):b(e.sourceName,{alongside:!0,reverse:!0}),"aria-label":t&&a?.reverse?"Pause":"Play backwards",title:t&&a?.reverse?"Pause":"Play backwards",children:t&&a?.reverse?n(L,{size:13}):n(J,{size:13})}),n("button",{type:"button",className:"se-iconButton",onClick:()=>h(e.sourceName),disabled:!a,"aria-label":"Stop",title:"Stop",children:n(K,{size:13})}),n("input",{className:"se-slider se-clipSeek",type:"range",min:0,max:Math.max(p,.001),step:.01,value:Math.min(l,p),disabled:!a||p<=0,onChange:s=>T(Number(s.target.value),e.sourceName),"aria-label":"Seek"}),i("code",{className:"se-clipTime",children:[R(Math.min(l,p))," / ",R(p)]})]}),v?i(Y,{children:[n(w,{label:"Loop",path:"sceneConfig.animations.clips[\u2026].loopMode",children:i("select",{className:"se-select",value:e.loopMode,onChange:s=>B(e.sourceName,s.target.value),children:[n("option",{value:"repeat",children:"Loop"}),n("option",{value:"once",children:"Play once"}),n("option",{value:"ping-pong",children:"Ping-pong"})]})}),n(M,{label:"Speed",path:"sceneConfig.animations.clips[\u2026].speed",value:e.speed,min:.1,max:3,step:.1,formatValue:s=>`${s.toFixed(2)}x`,onChange:s=>z(e.sourceName,s)}),n(k,{label:"Autoplay",path:"sceneConfig.animations.autoplayClip",checked:o.animations.autoplayClip===e.sourceName,onChange:()=>H(e.sourceName)})]}):null]},e.sourceName)})}),d.length>0?i("section",{className:"se-removedAnimations",children:[n("div",{className:"se-panelHeaderRow",children:i("button",{type:"button",className:"se-panelHeader","aria-expanded":c,onClick:()=>$(e=>!e),children:[n(I,{size:13,className:`se-panelChevron ${c?"se-panelChevron--open":""}`}),i("span",{className:"se-panelTitle",children:["Hidden clips (",d.length,")"]})]})}),c?n("div",{className:"rui-list",children:d.map(e=>i("div",{className:"rui-listRow",children:[i("span",{className:"rui-listRowMain",children:[n("span",{className:"rui-listRowTitle",children:e.displayName||e.sourceName}),n("code",{className:"rui-listRowMeta",children:e.sourceName})]}),n("button",{type:"button",className:"bb-button bb-button--small",onClick:()=>U(e.sourceName),children:"Show"})]},e.sourceName))}):null]}):null]})}export{X as default};
@@ -0,0 +1 @@
1
+ import{a as f}from"./chunk-FXV4CLAK.mjs";import{b as u,c as L,d as M,e as c}from"./chunk-AL6UIGWP.mjs";import{a as k,e as B}from"./chunk-7OWHW66D.mjs";import"./chunk-JR557W27.mjs";import{useState as v}from"react";import{Eye as I,Pencil as E,Plus as V,Trash2 as G,X as P}from"lucide-react";import{Fragment as $,jsx as t,jsxs as o}from"react/jsx-runtime";function H({config:r,onChange:w,cameraState:N,onPreviewView:b}){let[a,n]=v(null),[h,y]=v(""),[C,R]=v(""),z=e=>{n(structuredClone(e)),y(e.minDistance?.toString()??""),R(e.maxDistance?.toString()??"")},p=h.trim()===""?void 0:Number(h),d=C.trim()===""?void 0:Number(C),g=[p,d].some(e=>e!==void 0&&(!Number.isFinite(e)||e<0))?"Distances must be non-negative numbers.":p!==void 0&&d!==void 0&&p>d?"Maximum distance must be at least the minimum.":a?.images?.some(e=>e.src.trim()&&!k(e.src))||a?.links?.some(e=>e.href.trim()&&!k(e.href))?"Use an HTTP(S) URL or a relative path for images and links.":null,T=()=>{if(!a?.title.trim()||g)return;let e={...a,title:a.title.trim(),category:a.category?.trim()||void 0,minDistance:p,maxDistance:d,images:a.images?.filter(i=>i.src.trim()).map(i=>({...i,src:i.src.trim()})),links:a.links?.filter(i=>i.href.trim()).map(i=>({...i,href:i.href.trim(),label:i.label.trim()||"Learn more"}))};w({...r,annotations:r.annotations.map(i=>i.id===a.id?e:i)}),n(null)},[D,m]=v(null),F=e=>{w({...r,annotations:r.annotations.filter(i=>i.id!==e).map((i,l)=>({...i,id:l+1}))}),n(null)},S=(e,i)=>a&&n({...a,images:a.images.map((l,s)=>s===e?{...l,...i}:l)}),A=(e,i)=>a&&n({...a,links:a.links.map((l,s)=>s===e?{...l,...i}:l)});return o("div",{className:"se-annotations",children:[t(M,{title:"Annotations",children:t("span",{className:"se-listHeaderHint",children:"Double-click the model to add"})}),D!==null?t(f,{title:"Delete this annotation?",onCancel:()=>m(null),footer:o($,{children:[t("button",{type:"button",className:"bb-dialogButton",onClick:()=>m(null),children:"Cancel"}),t("button",{type:"button",className:"bb-dialogButton bb-dialogButton--danger",autoFocus:!0,onClick:()=>{F(D),m(null)},children:"Delete"})]}),children:t("p",{children:"You can undo this."})}):null,r.annotations.length===0?t("p",{className:"se-listEmpty",children:"No annotations yet."}):t("div",{className:"rui-list",children:r.annotations.map(e=>o("div",{className:"rui-listRow",children:[t("span",{className:"rui-listRowIndex",children:e.id}),o("span",{className:"rui-listRowMain",children:[t("span",{className:"rui-listRowTitle",title:e.title,children:e.title}),e.description||e.category?.trim()?t("span",{className:"rui-listRowMeta",title:e.description,children:[e.category?.trim(),e.description].filter(Boolean).join(" \xB7 ")}):null]}),o("span",{className:"rui-listRowActions",children:[B(e.cameraView)&&t("button",{type:"button",className:"se-iconButton",disabled:!b,onClick:()=>b?.(e.cameraView),title:"Preview saved view","aria-label":`Preview saved view for ${e.title}`,children:t(I,{size:13,"aria-hidden":"true"})}),t("button",{type:"button",className:"se-iconButton",onClick:()=>z(e),title:"Edit annotation","aria-label":`Edit ${e.title}`,children:t(E,{size:13,"aria-hidden":"true"})}),t("button",{type:"button",className:"se-iconButton",onClick:()=>m(e.id),title:"Delete annotation","aria-label":`Delete ${e.title}`,children:t(G,{size:13,"aria-hidden":"true"})})]})]},e.id))}),a&&t(f,{title:"Edit annotation",onCancel:()=>n(null),footer:o($,{children:[t("button",{type:"button",className:"bb-dialogButton bb-dialogFooterStart",onClick:()=>{m(a.id),n(null)},children:"Delete"}),t("button",{type:"button",className:"bb-dialogButton",onClick:()=>n(null),children:"Cancel"}),t("button",{type:"button",className:"bb-dialogButton bb-dialogButton--primary",disabled:!a.title.trim()||!!g,onClick:T,children:"Save"})]}),children:o("div",{className:"rui-dialogRows",children:[t(u,{label:"Title",children:t("input",{className:"bb-input",autoFocus:!0,value:a.title,onChange:e=>n({...a,title:e.target.value})})}),t(u,{label:"Description",children:t("textarea",{className:"bb-textarea bb-textarea--short",rows:2,value:a.description,onChange:e=>n({...a,description:e.target.value})})}),t(u,{label:"Category",children:t("input",{className:"bb-input",value:a.category??"",placeholder:"Features",onChange:e=>n({...a,category:e.target.value})})}),t(u,{label:"Position",children:t("code",{className:"rui-readout",children:a.worldPosition.map(e=>e.toFixed(2)).join(", ")})}),o(c,{title:"Camera view",children:[t("p",{className:"rui-note",children:a.cameraView?"Tours fly to this view.":"Tours zoom in on the marker unless you capture a view."}),o(L,{children:[t("button",{type:"button",className:"bb-button",disabled:!N,onClick:()=>N&&n({...a,cameraView:structuredClone(N)}),children:"Capture"}),t("button",{type:"button",className:"bb-button",disabled:!a.cameraView||!b,onClick:()=>a.cameraView&&b?.(a.cameraView),children:"Preview"}),t("button",{type:"button",className:"bb-button",disabled:!a.cameraView,onClick:()=>n({...a,cameraView:void 0}),children:"Clear"})]})]}),t(c,{title:"Visible between",children:t(u,{label:"Distance",title:"In scene units. Leave blank to show the marker at any distance.",children:o("span",{className:"rui-pair",children:[t("input",{className:"bb-input",type:"number",min:"0",step:"any","aria-label":"Minimum distance",placeholder:"Min",value:h,onChange:e=>y(e.target.value)}),t("input",{className:"bb-input",type:"number",min:"0",step:"any","aria-label":"Maximum distance",placeholder:"Max",value:C,onChange:e=>R(e.target.value)})]})})}),t(c,{title:"Images",actions:t("button",{type:"button",className:"se-iconButton",title:"Add image","aria-label":"Add image",onClick:()=>n({...a,images:[...a.images??[],{src:"",alt:""}]}),children:t(V,{size:14})}),children:a.images?.map((e,i)=>o("div",{className:"rui-mediaRow",children:[t("input",{className:"bb-input","aria-label":`Image URL ${i+1}`,placeholder:"https://example.com/image.jpg",value:e.src,onChange:l=>S(i,{src:l.target.value})}),t("input",{className:"bb-input","aria-label":`Image description ${i+1}`,placeholder:"Description",value:e.alt??"",onChange:l=>S(i,{alt:l.target.value})}),t("button",{type:"button",className:"se-iconButton",title:"Remove image","aria-label":`Remove image ${i+1}`,onClick:()=>n({...a,images:a.images.filter((l,s)=>s!==i)}),children:t(P,{size:13})})]},i))}),t(c,{title:"Links",actions:t("button",{type:"button",className:"se-iconButton",title:"Add link","aria-label":"Add link",onClick:()=>n({...a,links:[...a.links??[],{href:"",label:""}]}),children:t(V,{size:14})}),children:a.links?.map((e,i)=>o("div",{className:"rui-mediaRow",children:[t("input",{className:"bb-input","aria-label":`Link URL ${i+1}`,placeholder:"https://example.com/details",value:e.href,onChange:l=>A(i,{href:l.target.value})}),t("input",{className:"bb-input","aria-label":`Link label ${i+1}`,placeholder:"Learn more",value:e.label,onChange:l=>A(i,{label:l.target.value})}),t("button",{type:"button",className:"se-iconButton",title:"Remove link","aria-label":`Remove link ${i+1}`,onClick:()=>n({...a,links:a.links.filter((l,s)=>s!==i)}),children:t(P,{size:13})})]},i))}),g?t("p",{className:"bb-note bb-note--error",role:"alert",children:g}):null]})})]})}export{H as default};
@@ -0,0 +1 @@
1
+ import{b as A,d as h,k as C,l as d}from"./chunk-AL6UIGWP.mjs";import{a as N}from"./chunk-37YITTIK.mjs";import"./chunk-JR557W27.mjs";import{useState as T,useCallback as p}from"react";import{ArrowDown as M,ArrowUp as E,MapPin as F,Plus as L,Trash2 as B}from"lucide-react";import{jsx as n,jsxs as m}from"react/jsx-runtime";var I={enabled:!0,waypoints:[],loop:!0,autoPlay:!1},b=3.5;function U({config:g,onChange:w,cameraState:r,onPreviewWaypoint:f}){let i=g.cinematic??I,W=N(),{waypoints:o}=i,u=p((t,e)=>{if(t.length<2)return 0;let s=0;for(let a=0;a<t.length-1;a++){let c=t[a].segmentDuration??b;s+=c}return e&&t.length>1&&(s+=t[t.length-1].segmentDuration??b),Math.max(s,0)},[]),l=p(t=>{w({...g,cinematic:{...i,...t}})},[g,i,w]),R=p(()=>{if(!r)return;let t={position:[...r.position],target:[...r.target],...r.azimuthAngle!=null?{azimuthAngle:r.azimuthAngle}:{},...r.polarAngle!=null?{polarAngle:r.polarAngle}:{},segmentDuration:b},e=[...o,t],s=u(e,i.loop);l({waypoints:e,duration:s})},[r,o,i.loop,u,l]),k=p(t=>{let e=o.filter((a,c)=>c!==t),s=u(e,i.loop);l({waypoints:e,duration:s})},[o,i.loop,u,l]),v=p((t,e)=>{let s=t+e;if(s<0||s>=o.length)return;let a=[...o];[a[t],a[s]]=[a[s],a[t]];let c=u(a,i.loop);l({waypoints:a,duration:c})},[o,i.loop,u,l]),z=p((t,e)=>{let s=o.map((c,P)=>P===t?{...c,...e}:c),a=u(s,i.loop);l({waypoints:s,duration:a})},[o,i.loop,u,l]),[y,S]=T(!1),_=o.some(t=>t.segmentDuration!==void 0),$=p(t=>t>=o.length-1?b:o[t]?.segmentDuration??b,[o]),D=o.length>=2;return m("div",{className:"se-cinematic",children:[m("div",{className:"se-cinematicSettings",children:[n(h,{title:"Playback"}),n(d,{label:"Enabled",path:"sceneConfig.cinematic.enabled",checked:i.enabled,onChange:t=>l({enabled:t})}),n(d,{label:"Loop",path:"sceneConfig.cinematic.loop",checked:i.loop,onChange:t=>{l({loop:t,duration:u(o,t)})}}),n(d,{label:"Autoplay",path:"sceneConfig.cinematic.autoPlay",checked:i.autoPlay,onChange:t=>l({autoPlay:t})}),i.autoPlay&&W?n("p",{className:"rui-note",children:"Your device reduces motion, so this preview won't play on its own. Visitors without that setting will see it."}):null,n(d,{label:"Segment timing",checked:y,onChange:S}),!y&&D?n(C,{label:"Duration",path:"sceneConfig.cinematic.duration",value:i.duration??u(o,i.loop),min:4,max:120,step:1,formatValue:t=>`${t}s`,onChange:t=>l({duration:t})}):n(A,{label:"Total",children:n("code",{className:"rui-readout",children:D?`${(i.duration??u(o,i.loop)).toFixed(1)}s`:"Add at least 2 waypoints"})})]}),m("div",{className:"se-cinematicWaypoints",children:[n(h,{title:`Waypoints${o.length?` (${o.length})`:""}`,children:m("button",{type:"button",className:"bb-button bb-button--small",onClick:R,disabled:!r,title:"Capture the current camera view as a waypoint",children:[n(L,{size:13,"aria-hidden":"true"}),"Add from view"]})}),o.length===0?n("p",{className:"se-listEmpty",children:"Frame the model, then add it as a waypoint. The camera glides through them in order."}):n("div",{className:"rui-list",children:o.map((t,e)=>{let s=e===o.length-1;return m("div",{children:[m("div",{className:"rui-listRow",children:[n("span",{className:"rui-listRowIndex",children:e+1}),n("span",{className:"rui-listRowMain",children:n("code",{className:"rui-listRowCode",title:"Camera position",children:t.position.map(a=>a.toFixed(2)).join(", ")})}),m("span",{className:"rui-listRowActions rui-listRowActions--visible",children:[n("button",{type:"button",className:"se-iconButton",disabled:!f,onClick:()=>f?.(t),title:"Fly to this waypoint","aria-label":`Fly to waypoint ${e+1}`,children:n(F,{size:13})}),n("button",{type:"button",className:"se-iconButton",disabled:e===0,onClick:()=>v(e,-1),title:"Move up","aria-label":`Move waypoint ${e+1} up`,children:n(E,{size:13})}),n("button",{type:"button",className:"se-iconButton",disabled:s,onClick:()=>v(e,1),title:"Move down","aria-label":`Move waypoint ${e+1} down`,children:n(M,{size:13})}),n("button",{type:"button",className:"se-iconButton",onClick:()=>k(e),title:"Delete waypoint","aria-label":`Delete waypoint ${e+1}`,children:n(B,{size:13})})]})]}),y&&!s?n(C,{label:`${e+1} \u2192 ${e+2}`,path:"sceneConfig.cinematic.waypoints[\u2026].segmentDuration",value:$(e),min:1,max:20,step:.5,formatValue:a=>`${a.toFixed(1)}s`,onChange:a=>z(e,{segmentDuration:a})}):null]},`waypoint-${e}`)})})]})]})}export{U as default};
@@ -0,0 +1,6 @@
1
+ import{b as B,d as X,g as q,l as Q,m as le,o as ce}from"./chunk-AL6UIGWP.mjs";import{c as Ne,e as ke,f as we,h as Oe,i as _}from"./chunk-FGAJ2UT7.mjs";import{d as re,e as fe,f as ve,m as ye,n as Ce}from"./chunk-7JCFNZJM.mjs";import"./chunk-GV4ZRXL6.mjs";import"./chunk-BNKTI3CY.mjs";import"./chunk-JR557W27.mjs";import{useEffect as ne,useState as T}from"react";import{ArrowDown as Me,ArrowUp as Be,Check as qe,ChevronRight as ze,Copy as De,Crosshair as Ee,EyeOff as je,MousePointerClick as Ue,Palette as Ke,Play as Le,Plus as pe,Trash2 as ee,X as Fe}from"lucide-react";import{Fragment as Z,jsx as t,jsxs as c}from"react/jsx-runtime";var Je=["list","chips","swatches"],de=["USD","EUR","GBP","SGD","AUD","CAD","INR","JPY"],We="https://shop.example.com/cart/add?sku={sku}&qty={quantity}";function te(o,n){let r=1;for(;n.includes(`${o}-${r}`);)r++;return`${o}-${r}`}function z(o,n,r){let a=o.toLowerCase().trim().replace(/[^a-z0-9]+/g,"-").replace(/^-|-$/g,"")||n;return r.includes(a)?te(a,r):a}function Pe(o,n="New choice"){return{id:z(n,"choice",o),label:n,required:!0,defaultOptionId:"option-1",options:[{id:"option-1",label:"Option 1"},{id:"option-2",label:"Option 2"}]}}function oe(o,n){return o[n]?.label||n}function Ae(o){let n=o?.style?.material?.baseColor;return typeof n=="string"&&/^#[0-9a-f]{3,8}$/i.test(n)?n:"#888888"}function Se(o,n,r){let a=`${oe(o,n)} color`,h=Ae(o[n]);return{id:z(a,"color",r),label:a,required:!0,display:"swatches",defaultOptionId:"original",options:[{id:"original",label:"Original",swatch:h},{id:"color-2",label:"New color",swatch:"#2457c5",appearance:[{target:n,material:{baseColor:"#2457c5"}}]}]}}function Ie(o,n,r){let a=oe(o,n);return{id:z(a,"part",r),label:a,required:!0,display:"chips",defaultOptionId:"included",options:[{id:"included",label:"Included",appearance:[{target:n,visible:!0}]},{id:"not-included",label:"Not included",appearance:[{target:n,visible:!1}]}]}}function Ve(o){try{return new Intl.NumberFormat(void 0,{style:"currency",currency:o}).resolvedOptions().maximumFractionDigits??2}catch{return 2}}function He(o){return typeof o=="string"?`object:${o}`:Array.isArray(o)?`object:${o[0]??""}`:"group"in o?`group:${o.group}`:"tag"in o?`tag:${o.tag}`:"type"in o?`type:${o.type}`:""}function Ye(o){let n=o.indexOf(":"),r=o.slice(0,n),a=o.slice(n+1);return r==="group"?{group:a}:r==="tag"?{tag:a}:r==="type"?{type:a}:a}function _e(o){let n=Object.entries(o).filter(([,a])=>!a.removed),r=a=>[...new Set(a.filter(h=>!!h))].sort();return{groups:r(n.map(([,a])=>a.group)),tags:r(n.flatMap(([,a])=>a.tags??[])),objects:n.map(([a,h])=>({key:a,label:h.label||a}))}}function $({label:o,value:n,placeholder:r,onCommit:a,path:h}){let[w,v]=T(n);ne(()=>v(n),[n]);let N=()=>{w.trim()!==n&&a(w.trim())};return t(B,{label:o,path:h,children:t("input",{className:"se-textInput","aria-label":o,value:w,placeholder:r,onChange:m=>v(m.target.value),onBlur:N,onKeyDown:m=>{m.key==="Enter"&&N()}})})}function Te({label:o,valueMinor:n,currency:r,signed:a,onCommit:h,path:w}){let v=Ve(r),N=n===void 0?"":(n/10**v).toFixed(v),[m,M]=T(N);ne(()=>M(N),[N]);let O=()=>{if(m.trim()===N)return;let y=Number(m);if(!m.trim()||!Number.isFinite(y)||!a&&y<0){M(N),m.trim()||h(void 0);return}h(Math.round(y*10**v))};return t(B,{label:o,path:w,children:c("span",{className:"se-productMoney",children:[t("input",{className:"se-textInput","aria-label":o,inputMode:"decimal",value:m,placeholder:"0",onChange:y=>M(y.target.value),onBlur:O,onKeyDown:y=>{y.key==="Enter"&&O()}}),t("span",{children:r})]})})}function P({label:o,onClick:n,disabled:r,children:a}){return t("button",{type:"button",className:"se-iconButton","aria-label":o,title:o,disabled:r,onClick:n,children:a})}function ue(o,n,r){let a=[...o],[h]=a.splice(n,1);return a.splice(n+r,0,h),a}function Xe(o){return o.visible===!1?"hide":o.visible===!0?"show":"color"}function Qe({edit:o,bindings:n,selectedKey:r,onChange:a,onRemove:h}){let{groups:w,tags:v,objects:N}=_e(n),m=He(o.target),M=m.startsWith("group:")?w.includes(m.slice(6)):m.startsWith("tag:")?v.includes(m.slice(4)):m.startsWith("object:")?N.some(u=>u.key===m.slice(7)):!1,O=Xe(o),y=o.material?.baseColor;return c("div",{className:"se-productChange",children:[t(B,{label:"Part",children:c("span",{className:"se-productInline",children:[c("select",{className:"se-select","aria-label":"Part of the model",value:m,onChange:u=>a({...o,target:Ye(u.target.value)}),children:[M?null:t("option",{value:m,children:m||"Choose a part"}),t("optgroup",{label:"Objects",children:N.map(u=>t("option",{value:`object:${u.key}`,children:u.label},u.key))}),w.length?t("optgroup",{label:"Groups",children:w.map(u=>t("option",{value:`group:${u}`,children:u},u))}):null,v.length?t("optgroup",{label:"Tags",children:v.map(u=>t("option",{value:`tag:${u}`,children:u},u))}):null]}),r&&m!==`object:${r}`?t(P,{label:`Use the selected object: ${oe(n,r)}`,onClick:()=>a({...o,target:r}),children:t(Ee,{size:13})}):null,t(P,{label:"Remove this change",onClick:h,children:t(Fe,{size:13})})]})}),t(B,{label:"Does",children:c("select",{className:"se-select","aria-label":"What this does",value:O,onChange:u=>{let k=u.target.value;a(k==="color"?{target:o.target,material:{...o.material,baseColor:typeof y=="string"?y:"#888888"}}:{target:o.target,visible:k==="show"})},children:[t("option",{value:"color",children:"Changes its color"}),t("option",{value:"hide",children:"Hides it"}),t("option",{value:"show",children:"Shows it"})]})}),O==="color"?t(ce,{label:"Color",value:typeof y=="string"?y:"#888888",onChange:u=>a({...o,material:{...o.material,baseColor:u}})}):null]})}function Ze({group:o,option:n,index:r,definition:a,bindings:h,variantGroups:w,canSell:v,selectedKey:N,isStart:m,isShown:M,open:O,onToggleOpen:y,onSetStart:u,onChange:k,onRemove:E,onMove:j,onDuplicate:F}){let D=n.appearance??[],U=w.flatMap(p=>p.variants.map(R=>R.name)),K=N??Object.keys(h)[0]??"",x=[m?"customers start here":"",!D.length&&!n.variants?.length?"changes nothing":""].filter(Boolean).join(" \xB7 "),L=p=>{let R=n.appearance?.[0]?.material?.baseColor,S=p[0]?.material?.baseColor,I=n.swatch!==void 0&&n.swatch===R&&typeof S=="string";k({appearance:p.length?p:void 0,...I?{swatch:S}:{}})};return c("div",{className:`se-productOption ${O?"se-productOption--open":""} ${M?"se-productOption--shown":""}`,children:[t("div",{className:"se-productOptionHeader",children:c("button",{type:"button",className:"se-productOptionToggle","aria-expanded":O,title:"Edit this option and show it on the model",onClick:y,children:[t(ze,{size:12,"aria-hidden":"true",className:O?"se-productChevron--open":""}),n.swatch?t("span",{className:"se-productSwatch",style:{background:n.swatch},"aria-hidden":"true"}):null,t("span",{className:"se-productOptionName",children:n.label}),x?t("small",{children:x}):null]})}),O?c("div",{className:"se-productOptionBody",children:[t($,{label:"Name",value:n.label,onCommit:p=>{p&&k({label:p})}}),v&&a.pricing?t(Te,{label:"Price change",signed:!0,currency:a.pricing.currency,valueMinor:n.priceDeltaMinor,onCommit:p=>k({priceDeltaMinor:p})}):null,D.map((p,R)=>t(Qe,{edit:p,bindings:h,selectedKey:N,onChange:S=>L(D.map((I,C)=>C===R?S:I)),onRemove:()=>L(D.filter((S,I)=>I!==R))},R)),c("div",{className:"se-productActions",children:[c("button",{type:"button",className:"bb-button",disabled:!K,onClick:()=>L([...D,{target:K,material:{baseColor:Ae(h[K])}}]),children:[t(pe,{size:13,"aria-hidden":"true"})," ",D.length?"Change another part":"Change a part"]}),m?null:t("button",{type:"button",className:"bb-button",onClick:u,children:"Start here"})]}),c("details",{className:"se-productMore",children:[t("summary",{children:"More"}),t($,{label:"Description",value:n.description??"",placeholder:"Shown under the name",onCommit:p=>k({description:p||void 0})}),t(Q,{label:"Swatch",checked:!!n.swatch,onChange:p=>k({swatch:p?"#888888":void 0})}),n.swatch?t(ce,{label:"Swatch color",value:n.swatch,onChange:p=>k({swatch:p})}):null,U.length?t(B,{label:"Material variant",children:c("select",{className:"se-select","aria-label":"Material variant",value:n.variants?.[0]??"",onChange:p=>k({variants:p.target.value?[p.target.value]:void 0}),children:[t("option",{value:"",children:"None"}),U.map(p=>t("option",{value:p,children:p},p))]})}):null,v?t($,{label:"SKU",value:n.sku??"",placeholder:"Your stock code",onCommit:p=>k({sku:p||void 0})}):null,c("div",{className:"se-productActions",children:[t(P,{label:`Move ${n.label} up`,disabled:r===0,onClick:()=>j(-1),children:t(Be,{size:13})}),t(P,{label:`Move ${n.label} down`,disabled:r===o.options.length-1,onClick:()=>j(1),children:t(Me,{size:13})}),t(P,{label:`Duplicate ${n.label}`,onClick:F,children:t(De,{size:13})}),t(P,{label:`Delete ${n.label}`,disabled:o.options.length<=1,onClick:E,children:t(ee,{size:13})})]})]})]}):null]})}function Re(o,n){let r=o.groups.find(a=>a.id===n.groupId);return`${r?.label??n.groupId}: ${r?.options.find(a=>a.id===n.optionId)?.label??n.optionId}`}function $e({bindings:o,selectedKey:n,disabled:r,onColor:a,onVisibility:h}){return!n||!o[n]?c("p",{className:"se-productHint",children:[t(Ue,{size:14,"aria-hidden":"true"}),"Click a part of the model to let customers change it."]}):c("div",{className:"se-productStarter",children:[c("p",{children:["Let customers change ",t("strong",{children:oe(o,n)}),":"]}),c("div",{className:"se-productActions",children:[c("button",{type:"button",className:"bb-button",disabled:r,onClick:()=>a(n),children:[t(Ke,{size:13,"aria-hidden":"true"})," Its color"]}),c("button",{type:"button",className:"bb-button",disabled:r,onClick:()=>h(n),children:[t(je,{size:13,"aria-hidden":"true"})," Show or hide it"]})]})]})}function et({code:o}){let[n,r]=T(!1);return ne(()=>{if(!n)return;let a=setTimeout(()=>r(!1),2e3);return()=>clearTimeout(a)},[n]),c("div",{className:"se-productCode",children:[t("pre",{children:o}),t(P,{label:n?"Copied":"Copy code",onClick:()=>{navigator.clipboard.writeText(o).then(()=>r(!0)).catch(()=>{})},children:n?t(qe,{size:13}):t(De,{size:13})})]})}function tt({config:o,onChange:n,objectBindings:r,materialVariantGroups:a,selectedKey:h,previewSelections:w,onPreviewChange:v,onPreviewAsCustomer:N,publish:m,modelFileName:M}){let{tier:O}=Oe(),y=Ne(O,"productCommerce"),u=o.product,[k,E]=T(null),[j,F]=T(null),[D,U]=T({}),[K,x]=T(null),L=JSON.stringify(u?.definition??null),[p,R]=T("");ne(()=>{R(u?JSON.stringify(u.definition,null,2):"")},[L]);let S=(e,l=!1)=>D[e]??l,I=(e,l=!1)=>U(s=>({...s,[e]:!(s[e]??l)})),C=e=>{try{let l=re(e),s=Object.fromEntries(l.groups.map(d=>{let b=u?.selections[d.id];return[d.id,b===null||d.options.some(g=>g.id===b)?b??null:d.defaultOptionId??null]}));n({...o,product:{definition:l,selections:s}}),E(null)}catch(l){E(l instanceof Error?l.message:String(l))}},be=M.replace(/\.[a-z0-9]+$/i,"").replace(/[-_]+/g," ").trim()||"My product",J=e=>{let l={id:z(be,"product",[]),label:be,revision:"1",groups:e};n({...o,product:{definition:l,selections:fe(l)}})};if(!u)return c("div",{className:"se-productEmpty",children:[t("h3",{children:"Let customers customize this model"}),t("p",{children:"They pick from your options beside the model and watch it change, with a price and a button to buy."}),c("div",{className:"se-productExample","aria-hidden":"true",children:[t("span",{children:"Wood"}),t("i",{style:{background:"#b89063"}}),t("i",{className:"is-on",style:{background:"#453025"}}),t("i",{style:{background:"#d7c4a3"}}),t("span",{children:"Fabric"}),t("b",{children:"Linen"}),t("b",{className:"is-on",children:"Leather"}),t("em",{children:"$304.00"}),t("u",{children:"Buy"})]}),t($e,{bindings:r,selectedKey:h,onColor:e=>{let l=Se(r,e,[]);J([l]),x(`${l.id}/color-2`),v({[l.id]:"color-2"})},onVisibility:e=>J([Ie(r,e,[])])}),a.length?c("button",{type:"button",className:"bb-button",onClick:()=>{let e=[];J(a.map(l=>{let s=z(l.name??"","variants",e);e.push(s);let d=[],b=l.variants.map(f=>{let Y=z(f.label,"option",d);return d.push(Y),{id:Y,label:f.label,variants:[f.name],...f.swatch?.startsWith("#")?{swatch:f.swatch}:{}}}),g=b.every(f=>f.swatch)?"swatches":"list";return{id:s,label:l.name??"Variant",required:!0,defaultOptionId:b[0]?.id,display:g,options:b}}))},children:["Use this model's ",a.flatMap(e=>e.variants).length," material variants"]}):null,t("button",{type:"button",className:"se-productLink",onClick:()=>J([Pe([],"Finish")]),children:"Or start with a blank choice"})]});let i=u.definition,ie=i.groups.map(e=>e.id),xe=ke(O,"productGroups",i.groups.length),W=i.groups.flatMap(e=>e.options.map(l=>({groupId:e.id,optionId:l.id}))),G=e=>JSON.stringify([e.groupId,e.optionId]),me=e=>{let[l,s]=JSON.parse(e);return{groupId:l,optionId:s}},he=ve(i,u.selections),ge=Ce(i,r,a.length?a.flatMap(e=>e.variants.map(l=>l.name)):void 0),V=w??u.selections,se=e=>{let l=b=>e.some(g=>g.id===b.groupId&&g.options.some(f=>f.id===b.optionId)),s=(i.rules??[]).filter(b=>l(b.when)).map(b=>({...b,requires:b.requires?.filter(l),excludes:b.excludes?.filter(l)})).filter(b=>b.requires?.length||b.excludes?.length),d=b=>JSON.stringify(b.map(g=>[g.id,g.required,g.options.map(f=>f.id)]));C({...i,groups:e,rules:s,skus:d(e)===d(i.groups)?i.skus:void 0})},ae=(e,l)=>{se([...i.groups,e]),U(s=>({...s,[`group:${e.id}`]:!0})),l&&(x(`${e.id}/${l}`),v({...V,[e.id]:l}))},A=(e,l)=>se(i.groups.map(s=>s.id===e?{...s,...l}:s)),Ge=(e,l,s)=>A(e.id,{options:e.options.map(d=>d.id===l?{...d,...s}:d)}),H=(e,l)=>C({...i,rules:i.rules.map(s=>s.id===e?{...s,...l}:s)});return c("div",{className:"se-generalContent",children:[c("div",{className:"se-productTop",children:[t($,{label:"Product",path:"sceneConfig.product.definition.label",value:i.label,onCommit:e=>{e&&C({...i,label:e})}}),t("div",{className:"se-productActions",children:c("button",{type:"button",className:"bb-button bb-button--primary",onClick:N,children:[t(Le,{size:13,"aria-hidden":"true"})," Preview as a customer"]})})]}),ge.length?t("ul",{className:"se-productWarnings","aria-label":"Problems to fix",children:ge.map((e,l)=>t("li",{children:e.message},l))}):null,k?t("p",{className:"bb-note bb-note--error se-productError",role:"alert",children:k}):null,t(X,{title:"What customers can choose"}),i.groups.map(e=>{let l=u.selections[e.id]??null;return c(q,{title:e.label,open:S(`group:${e.id}`,i.groups.length===1),onToggle:()=>I(`group:${e.id}`,i.groups.length===1),trailing:c("small",{className:"se-productCount",children:[e.options.length," options"]}),children:[t("div",{className:"se-productOptions",children:e.options.map((s,d)=>{let b=`${e.id}/${s.id}`;return t(Ze,{group:e,option:s,index:d,definition:i,bindings:r,variantGroups:a,canSell:y,selectedKey:h,isStart:l===s.id,isShown:V[e.id]===s.id,open:K===b,onToggleOpen:()=>{x(g=>g===b?null:b),v({...V,[e.id]:s.id})},onSetStart:()=>{let g={...i,groups:i.groups.map(f=>f.id===e.id?{...f,defaultOptionId:s.id}:f)};n({...o,product:{definition:g,selections:{...u.selections,[e.id]:s.id}}})},onChange:g=>Ge(e,s.id,g),onMove:g=>A(e.id,{options:ue(e.options,d,g)}),onDuplicate:()=>{let g=e.options.map(Y=>Y.id),f=[...e.options];f.splice(d+1,0,{...structuredClone(s),id:te("option",g),label:`${s.label} copy`,sku:void 0}),A(e.id,{options:f})},onRemove:()=>{let g=e.options.filter(f=>f.id!==s.id);A(e.id,{options:g,defaultOptionId:e.defaultOptionId===s.id?e.required?g[0]?.id:void 0:e.defaultOptionId})}},s.id)})}),t("div",{className:"se-productActions",children:c("button",{type:"button",className:"bb-button",onClick:()=>{let s=te("option",e.options.map(b=>b.id)),d=e.display==="swatches";A(e.id,{options:[...e.options,{id:s,label:d?"New color":`Option ${e.options.length+1}`,...d?{swatch:"#888888"}:{}}]}),x(`${e.id}/${s}`),v({...V,[e.id]:s})},children:[t(pe,{size:13,"aria-hidden":"true"})," Add option"]})}),c("details",{className:"se-productMore",children:[t("summary",{children:"Choice settings"}),t($,{label:"Name",value:e.label,onCommit:s=>{s&&A(e.id,{label:s})}}),t(le,{label:"Show as",value:e.display??"list",options:Je,onChange:s=>A(e.id,{display:s})}),t(Q,{label:"Customers can skip it",checked:!e.required,onChange:s=>A(e.id,{required:!s,defaultOptionId:e.defaultOptionId??(s?void 0:e.options[0]?.id)})}),c("div",{className:"se-productActions",children:[t(P,{label:`Move ${e.label} up`,disabled:i.groups.indexOf(e)===0,onClick:()=>{let s=i.groups.indexOf(e);C({...i,groups:ue(i.groups,s,-1)})},children:t(Be,{size:13})}),t(P,{label:`Move ${e.label} down`,disabled:i.groups.indexOf(e)===i.groups.length-1,onClick:()=>{let s=i.groups.indexOf(e);C({...i,groups:ue(i.groups,s,1)})},children:t(Me,{size:13})}),t(P,{label:`Delete ${e.label}`,disabled:i.groups.length<=1,onClick:()=>se(i.groups.filter(s=>s.id!==e.id)),children:t(ee,{size:13})})]})]})]},e.id)}),xe?c("div",{className:"se-productAdd",children:[t($e,{bindings:r,selectedKey:h,onColor:e=>ae(Se(r,e,ie),"color-2"),onVisibility:e=>ae(Ie(r,e,ie))}),t("button",{type:"button",className:"se-productLink",onClick:()=>ae(Pe(ie)),children:"Or add a blank choice"})]}):t(_,{requiredTier:we("productGroups",i.groups.length),feature:"More choices"}),t(q,{title:"Prices and buying",open:S("selling"),onToggle:()=>I("selling"),children:y?c(Z,{children:[t(Q,{label:"Show a price",checked:!!i.pricing,onChange:e=>C({...i,pricing:e?{currency:"USD",basePriceMinor:0}:void 0})}),i.pricing?c(Z,{children:[t(le,{label:"Currency",path:"sceneConfig.product.definition.pricing.currency",value:i.pricing.currency,options:de.includes(i.pricing.currency)?de:[...de,i.pricing.currency],onChange:e=>C({...i,pricing:{...i.pricing,currency:e}})}),t(Te,{label:"Base price",path:"sceneConfig.product.definition.pricing.basePriceMinor",currency:i.pricing.currency,valueMinor:i.pricing.basePriceMinor,onCommit:e=>C({...i,pricing:{...i.pricing,basePriceMinor:e??0}})}),t("p",{className:"bb-note",children:"Open an option to add what it costs extra. This price is for show: always charge from your own store."})]}):null,t($,{label:"Buy link",path:"sceneConfig.product.definition.checkout.urlTemplate",placeholder:We,value:i.checkout?.urlTemplate??"",onCommit:e=>C({...i,checkout:e?{...i.checkout,urlTemplate:e}:void 0})}),i.checkout?t($,{label:"Button text",placeholder:"Buy now",value:i.checkout.label??"",onCommit:e=>C({...i,checkout:{...i.checkout,label:e||void 0}})}):null,c("p",{className:"bb-note",children:["Where the button goes. The link can include ","{sku}",", ","{quantity}",", ","{productId}"," and ","{selections}","."]})]}):t(_,{requiredTier:"starter",feature:"Prices and buy links"})}),t(q,{title:`Restrictions${i.rules?.length?` (${i.rules.length})`:""}`,open:S("rules"),onToggle:()=>I("rules"),children:y?c(Z,{children:[t("p",{className:"bb-note",children:"For combinations you don't sell. Customers see your message, and picking a blocked option changes the others to fit."}),i.rules?.map(e=>{let l=e.excludes?.length?"excludes":"requires",s=(e[l]??[])[0];return c("div",{className:"se-productRule",children:[t(B,{label:"When",children:t("select",{className:"se-select","aria-label":`Condition for ${e.id}`,value:G(e.when),onChange:d=>H(e.id,{when:me(d.target.value)}),children:W.map(d=>t("option",{value:G(d),children:Re(i,d)},G(d)))})}),t(B,{label:"Then",children:c("select",{className:"se-select","aria-label":`Kind of rule for ${e.id}`,value:l,onChange:d=>{let b=d.target.value;H(e.id,b==="requires"?{requires:e.excludes,excludes:void 0}:{excludes:e.requires,requires:void 0})},children:[t("option",{value:"requires",children:"Must have"}),t("option",{value:"excludes",children:"Can't have"})]})}),t(B,{label:"Option",children:t("select",{className:"se-select","aria-label":`Choice for ${e.id}`,value:s?G(s):"",onChange:d=>H(e.id,{[l]:[me(d.target.value)]}),children:W.filter(d=>d.groupId!==e.when.groupId).map(d=>t("option",{value:G(d),children:Re(i,d)},G(d)))})}),t($,{label:"Message",placeholder:"Shown when it's blocked",value:e.message??"",onCommit:d=>H(e.id,{message:d||void 0})}),t("div",{className:"se-productActions",children:t(P,{label:`Delete restriction ${e.id}`,onClick:()=>C({...i,rules:i.rules.filter(d=>d.id!==e.id)}),children:t(ee,{size:13})})})]},e.id)}),i.groups.length<2?t("p",{className:"bb-note",children:"Add a second choice to restrict combinations."}):t("div",{className:"se-productActions",children:c("button",{type:"button",className:"bb-button",onClick:()=>{let e=W[0],l=W.find(s=>s.groupId!==e.groupId);C({...i,rules:[...i.rules??[],{id:te("rule",(i.rules??[]).map(s=>s.id)),when:e,requires:[l]}]})},children:[t(pe,{size:13,"aria-hidden":"true"})," Add restriction"]})})]}):t(_,{requiredTier:"starter",feature:"Restrictions"})}),t(q,{title:"Publish",open:S("publish"),onToggle:()=>I("publish"),children:m?c("div",{className:"se-productPublish",children:[t("p",{className:"bb-note",children:"Customers can choose wherever this project is shared or embedded. Set access to Anyone with the link, then copy the embed code."}),m]}):c("div",{className:"se-productPublish",children:[c("p",{className:"bb-note",children:["Use ",t("strong",{children:"Export \u203A Scene settings"})," in the top bar, then show it with the options panel on:"]}),t(et,{code:`<ModelViewer
2
+ modelUrl="/model.glb"
3
+ licenseKey={licenseKey}
4
+ sceneConfig={sceneConfig}
5
+ productOptions
6
+ />`})]})}),c(q,{title:"Advanced",open:S("advanced"),onToggle:()=>I("advanced"),children:[t($,{label:"Product ID",path:"sceneConfig.product.definition.id",value:i.id,onCommit:e=>{e&&C({...i,id:e})}}),t($,{label:"Revision",path:"sceneConfig.product.definition.revision",value:i.revision,onCommit:e=>{e&&C({...i,revision:e})}}),y?c(Z,{children:[t(X,{title:`SKU combinations (${i.skus?.length??0})`}),t("p",{className:"bb-note",children:"Once this list has entries, combinations not on it can't be bought."}),c("div",{className:"se-productActions",children:[t("button",{type:"button",className:"bb-button",onClick:()=>{try{let e=ye({...i,skus:void 0});F(e.length?`Generated ${e.length} ${e.length===1?"combination":"combinations"}.`:"Give each option an SKU first, under More."),e.length&&C({...i,skus:e})}catch(e){F(e instanceof Error?e.message:String(e))}},children:"Generate from option SKUs"}),i.skus?.length?t(P,{label:"Clear SKU combinations",onClick:()=>C({...i,skus:void 0}),children:t(ee,{size:13})}):null]}),j?t("p",{className:"bb-note",role:"status",children:j}):null,he.sku?c("p",{className:"bb-note",children:["Customers start on: ",he.sku]}):null]}):null,t(X,{title:"Definition JSON"}),t("p",{className:"bb-note",children:"For textures and anything else without a control. It's checked before it's applied."}),t("div",{className:"se-productJson",children:t("textarea",{className:"bb-textarea","aria-label":"Product definition JSON",rows:10,value:p,spellCheck:!1,onChange:e=>R(e.target.value)})}),c("div",{className:"se-productActions",children:[t("button",{type:"button",className:"bb-button",onClick:()=>{try{C(re(p))}catch(e){E(e instanceof Error?e.message:String(e))}},children:"Apply JSON"}),t("button",{type:"button",className:"bb-button",onClick:()=>{v(null),n({...o,product:void 0})},children:"Remove all of this"})]})]})]})}export{tt as default};
@@ -0,0 +1 @@
1
+ import{b as _}from"./chunk-E24EFHB5.mjs";import{c as F,d as D,k as L,n as z}from"./chunk-AL6UIGWP.mjs";import{a as P}from"./chunk-CCBFMNAU.mjs";import{b as K}from"./chunk-GV4ZRXL6.mjs";import"./chunk-JR557W27.mjs";import{useMemo as ee,useState as te}from"react";import{ArrowDown as ae,ArrowUp as ne,ChevronRight as le,Plus as G,Trash2 as se,X as U}from"lucide-react";import{Fragment as J,jsx as a,jsxs as r}from"react/jsx-runtime";var H={all:"All objects",group:"Group",tag:"Tag",type:"Type",object:"One object"},V={metric:"Metric",status:"Status",metadata:"Metadata"},oe={metric:"",stops:[[0,"#3b82f6"],[100,"#ef4444"]]};function ie(n){return n===void 0?"all":typeof n=="string"||Array.isArray(n)?"object":"group"in n?"group":"tag"in n?"tag":"type"}function w(n){return n===void 0?"":typeof n=="string"?n:Array.isArray(n)?n[0]??"":"group"in n?n.group:"tag"in n?n.tag:n.type}function W(n,s){if(n!=="all")return n==="object"?s:n==="group"?{group:s}:n==="tag"?{tag:s}:{type:s}}function re(n){return"metric"in n?"metric":"status"in n?"status":"metadata"}function X(n){return n==="metric"?{metric:""}:n==="status"?{status:["disabled"]}:{metadata:"",equals:""}}function ce(n){let s=n.trim();return s==="true"?!0:s==="false"?!1:s==="null"?null:s!==""&&Number.isFinite(Number(s))?Number(s):n}function I(n){return n.trim()===""||!Number.isFinite(Number(n))?void 0:Number(n)}function Q(n,s="",c=0){return typeof n!="object"||n===null||Array.isArray(n)?s?[s]:[]:c>2?s?[s]:[]:Object.entries(n).flatMap(([d,h])=>Q(h,s?`${s}.${d}`:d,c+1))}var j=n=>[...new Set(n.filter(s=>!!s))].sort((s,c)=>s.localeCompare(c));function y({label:n,children:s}){return r("label",{className:"se-field se-fieldInline",children:[a("span",{className:"se-fieldLabel",title:n,children:n}),s]})}function O({label:n,checked:s,color:c,onToggle:d,onColorChange:h}){return r("div",{className:"se-field se-fieldInline",children:[r("label",{className:"se-ruleLook",children:[a("input",{type:"checkbox",className:"se-checkbox",checked:s,onChange:T=>d(T.target.checked)}),n]}),s&&c!==void 0&&h?a(z,{label:n,value:c,onChange:h}):null]})}function ue({title:n,open:s,onToggle:c,actions:d,children:h}){return r("section",{className:"se-panel",children:[r("div",{className:"se-panelHeaderRow",children:[r("button",{type:"button",className:"se-panelHeader",onClick:c,"aria-expanded":s,children:[a(le,{size:13,className:`se-panelChevron ${s?"se-panelChevron--open":""}`}),a("span",{className:"se-panelTitle",children:n})]}),a("span",{className:"se-listHeaderActions",children:d})]}),s?a("div",{className:"se-panelBody",children:h}):null]})}function de({config:n,onChange:s,objectBindings:c}){let d=n.styleRules??[],[h,T]=te(d[0]?.id??null),b=ee(()=>{let t=Object.values(c);return{groups:j(t.map(i=>i.group)),tags:j(t.flatMap(i=>i.tags??[])),types:j(t.map(i=>i.type??"other")),objects:t.map(i=>({id:i.id,label:i.label||i.id})).sort((i,u)=>i.label.localeCompare(u.label)),metrics:j(t.flatMap(i=>Object.keys(i.metrics??{}))),metadata:j(t.flatMap(i=>Q(i.metadata)))}},[c]),A=t=>s({...n,styleRules:t}),v=(t,i)=>A(d.map(u=>u.id===t?i(u):u)),Y=()=>{let t=crypto.randomUUID();A([...d,{id:t,label:`Rule ${d.length+1}`,when:[{status:["disabled"]}],material:{baseColor:"#9ca3af"}}]),T(t)},$=(t,i)=>{let u=[...d],[m]=u.splice(t,1);u.splice(t+i,0,m),A(u)},Z=t=>{let i=t.target?K(c,t.target):Object.keys(c),u=t.when?Array.isArray(t.when)?t.when:[t.when]:[];return i.filter(m=>u.every(f=>P(c[m],f))).length};return r("div",{className:"se-rules",children:[a(D,{title:"Rules",children:r("button",{type:"button",className:"bb-button bb-button--small",onClick:Y,children:[a(G,{size:13,"aria-hidden":"true"})," Add rule"]})}),a("p",{className:"rui-note",children:"Restyle objects from their metrics, status, or metadata while the app runs. Later rules win."}),a("datalist",{id:"se-ruleMetrics",children:b.metrics.map(t=>a("option",{value:t},t))}),a("datalist",{id:"se-ruleMetadata",children:b.metadata.map(t=>a("option",{value:t},t))}),d.map((t,i)=>{let u=t.when?Array.isArray(t.when)?t.when:[t.when]:[],m=ie(t.target),f=t.material??{},S=t.pulse===!0?{}:t.pulse||void 0,q=t.target?K(c,t.target).length:Object.keys(c).length,M=e=>v(t.id,l=>({...l,when:e.length>0?e:void 0})),C=(e,l)=>M(u.map((p,o)=>o===e?l:p)),N=e=>v(t.id,l=>{let p={...l.material,...e};for(let o of Object.keys(p))p[o]===void 0&&delete p[o];return{...l,material:Object.keys(p).length>0?p:void 0}}),k=e=>v(t.id,l=>({...l,colorScale:e})),E=m==="group"?b.groups:m==="tag"?b.tags:m==="type"?b.types:[];return r(ue,{title:t.label||`Rule ${i+1}`,open:h===t.id,onToggle:()=>T(e=>e===t.id?null:t.id),actions:r(J,{children:[a("button",{type:"button",className:"se-iconButton",onClick:()=>$(i,-1),disabled:i===0,"aria-label":"Move rule up",title:"Move up",children:a(ne,{size:13})}),a("button",{type:"button",className:"se-iconButton",onClick:()=>$(i,1),disabled:i===d.length-1,"aria-label":"Move rule down",title:"Move down",children:a(ae,{size:13})}),a("button",{type:"button",className:"se-iconButton",onClick:()=>A(d.filter(e=>e.id!==t.id)),"aria-label":"Delete rule",title:"Delete rule",children:a(se,{size:13})})]}),children:[a(y,{label:"Name",children:a("input",{className:"se-textInput",value:t.label??"",placeholder:`Rule ${i+1}`,onChange:e=>v(t.id,l=>({...l,label:e.target.value}))})}),r("div",{className:"se-ruleGrid",children:[a(y,{label:"Applies to",children:a("select",{className:"se-select",value:m,onChange:e=>{let l=e.target.value,p=l==="object"?b.objects[0]?.id:l==="group"?b.groups[0]:l==="tag"?b.tags[0]:l==="type"?b.types[0]:"";v(t.id,o=>({...o,target:W(l,p??"")}))},children:Object.keys(H).map(e=>a("option",{value:e,children:H[e]},e))})}),m!=="all"?a(y,{label:H[m],children:r("select",{className:"se-select",value:w(t.target),onChange:e=>v(t.id,l=>({...l,target:W(m,e.target.value)})),children:[m==="object"?b.objects.map(e=>a("option",{value:e.id,children:e.label},e.id)):E.map(e=>a("option",{value:e,children:e},e)),(m==="object"?b.objects.some(e=>e.id===w(t.target)):E.includes(w(t.target)))?null:a("option",{value:w(t.target),children:w(t.target)||"None in this model"})]})}):null]}),a("div",{className:"rui-groupHeader",children:a("span",{children:"When"})}),u.length===0?a("p",{className:"rui-note",children:"Always applies."}):null,u.map((e,l)=>{let p=re(e);return r("div",{className:"se-ruleCondition",children:[r("div",{className:"se-ruleConditionHeader",children:[a("select",{className:"se-select","aria-label":"Condition type",value:p,onChange:o=>C(l,X(o.target.value)),children:Object.keys(V).map(o=>a("option",{value:o,children:V[o]},o))}),a("button",{type:"button",className:"se-iconButton","aria-label":"Remove condition",title:"Remove condition",onClick:()=>M(u.filter((o,g)=>g!==l)),children:a(U,{size:13})})]}),"metric"in e?r("div",{className:"se-ruleGrid se-ruleGrid--three",children:[a(y,{label:"Metric",children:a("input",{className:"se-textInput",list:"se-ruleMetrics",value:e.metric,placeholder:"temperature",onChange:o=>C(l,{...e,metric:o.target.value})})}),a(y,{label:"Above",children:a("input",{className:"se-numberInput",type:"number",value:e.above??"",placeholder:"any",onChange:o=>C(l,{...e,above:I(o.target.value)})})}),a(y,{label:"Below",children:a("input",{className:"se-numberInput",type:"number",value:e.below??"",placeholder:"any",onChange:o=>C(l,{...e,below:I(o.target.value)})})})]}):"status"in e?a("div",{className:"se-ruleStatuses",children:_.map(o=>{let g=[].concat(e.status).includes(o);return r("label",{className:"se-ruleStatus",children:[a("input",{type:"checkbox",className:"se-checkbox",checked:g,onChange:()=>{let R=[].concat(e.status),B=g?R.filter(x=>x!==o):[...R,o];C(l,{status:B})}}),o]},o)})}):r("div",{className:"se-ruleGrid",children:[a(y,{label:"Key",children:a("input",{className:"se-textInput",list:"se-ruleMetadata",value:e.metadata,placeholder:"alarm.state",onChange:o=>C(l,{...e,metadata:o.target.value})})}),a(y,{label:"Equals",children:a("input",{className:"se-textInput",value:e.equals===null?"null":String(e.equals),placeholder:"fault",onChange:o=>C(l,{...e,equals:ce(o.target.value)})})})]})]},l)}),a(F,{children:r("button",{type:"button",className:"bb-button",onClick:()=>M([...u,X("metric")]),children:[a(G,{size:13,"aria-hidden":"true"})," Add condition"]})}),a("div",{className:"rui-groupHeader",children:a("span",{children:"Look"})}),a(O,{label:"Color",checked:f.baseColor!==void 0,color:f.baseColor,onToggle:e=>N({baseColor:e?"#9ca3af":void 0}),onColorChange:e=>N({baseColor:e})}),a(O,{label:"Opacity",checked:f.opacity!==void 0,onToggle:e=>N({opacity:e?.4:void 0})}),f.opacity!==void 0?a(L,{label:"Opacity",value:f.opacity,min:0,max:1,step:.05,formatValue:e=>`${Math.round(e*100)}%`,onChange:e=>N({opacity:e})}):null,a(O,{label:"Glow",checked:f.emissive!==void 0,color:f.emissive,onToggle:e=>N({emissive:e?"#ff3b30":void 0,emissiveIntensity:e?f.emissiveIntensity??1:void 0}),onColorChange:e=>N({emissive:e})}),a(O,{label:"Color from a metric",checked:t.colorScale!==void 0,onToggle:e=>k(e?{...oe,metric:b.metrics[0]??""}:void 0)}),t.colorScale?r("div",{className:"se-ruleCondition",children:[r("div",{className:"se-ruleGrid",children:[a(y,{label:"Metric",children:a("input",{className:"se-textInput",list:"se-ruleMetrics",value:t.colorScale.metric,placeholder:"temperature",onChange:e=>k({...t.colorScale,metric:e.target.value})})}),a(y,{label:"Sets",children:r("select",{className:"se-select",value:t.colorScale.channel??"baseColor",onChange:e=>k({...t.colorScale,channel:e.target.value}),children:[a("option",{value:"baseColor",children:"Color"}),a("option",{value:"emissive",children:"Glow color"})]})})]}),t.colorScale.stops.map(([e,l],p)=>{let o=g=>k({...t.colorScale,stops:t.colorScale.stops.map((R,B)=>B===p?g:R)});return r("div",{className:"se-ruleStop",children:[a("input",{className:"se-numberInput",type:"number","aria-label":"Stop value",value:e,onChange:g=>o([I(g.target.value)??0,l])}),a(z,{label:`Color at ${e}`,value:l,onChange:g=>o([e,g])}),a("button",{type:"button",className:"se-iconButton","aria-label":"Remove stop",title:"Remove stop",disabled:t.colorScale.stops.length<=1,onClick:()=>k({...t.colorScale,stops:t.colorScale.stops.filter((g,R)=>R!==p)}),children:a(U,{size:13})})]},p)}),a(F,{children:r("button",{type:"button",className:"bb-button",onClick:()=>{let e=t.colorScale.stops,l=e[e.length-1];k({...t.colorScale,stops:[...e,[(l?.[0]??0)+10,l?.[1]??"#ffffff"]]})},children:[a(G,{size:13,"aria-hidden":"true"})," Add stop"]})})]}):null,a(O,{label:"Pulse",checked:S!==void 0,color:S?.color??"#ff3b30",onToggle:e=>v(t.id,l=>({...l,pulse:e?{color:"#ff3b30",speed:1}:void 0})),onColorChange:e=>v(t.id,l=>({...l,pulse:{...S,color:e}}))}),S?a(J,{children:a(L,{label:"Pulses per second",value:S.speed??1,min:.2,max:4,step:.1,formatValue:e=>e.toFixed(1),onChange:e=>v(t.id,l=>({...l,pulse:{...S,speed:e}}))})}):null,r("p",{className:"rui-note",children:["Matches ",Z(t)," of ",q," ",q===1?"object":"objects"," right now."]})]},t.id)})]})}export{de as default};
@@ -0,0 +1 @@
1
+ .sq-editor{color:var(--ri-ui-text-2);padding:12px;font-size:12px}.sq-header,.sq-picker,.sq-inspectorTitle,.sq-settings{display:flex;align-items:center;gap:10px}.sq-header{justify-content:space-between;margin-bottom:16px}.sq-header h2{margin:0;font-size:13px}.sq-header p,.sq-hint{color:var(--ri-ui-text-2);font-size:11px;line-height:1.5}.sq-header p{margin:6px 0 0}.sq-picker .sq-field{flex:1;min-width:0}.sq-field{display:flex;flex-direction:column;gap:6px;margin-bottom:12px;min-width:0}.sq-field>span{font-size:11px;color:var(--ri-ui-text-2)}.sq-field input,.sq-field select{width:100%;min-width:0;box-sizing:border-box;border:1px solid var(--ri-ui-line);border-radius:var(--ri-ui-radius-m);padding:8px;color:var(--ri-ui-text);background:var(--ri-ui-raised);font:inherit}.sq-field input:focus-visible,.sq-field select:focus-visible,.sq-editor button:focus-visible{outline:2px solid var(--ri-ui-accent);outline-offset:2px}.sq-settings{flex-wrap:wrap;align-items:center;margin:10px 0}.sq-settings .sq-field{width:105px;margin:0}.sq-check{display:flex;align-items:center;gap:6px;color:var(--ri-ui-text-2);font-size:11px}.sq-editor input[type=checkbox]{accent-color:var(--ri-ui-accent)}.sq-twoFields{display:grid;grid-template-columns:1fr 1fr;gap:10px}.sq-vector{border:0;padding:0;margin:10px 0;min-width:0}.sq-vector legend{color:var(--ri-ui-text-2);margin-bottom:8px}.sq-vector>div{display:grid;grid-template-columns:repeat(3,minmax(0,1fr));gap:7px}.sq-color{flex-direction:row;align-items:center;gap:12px}.sq-color input{width:40px;height:32px;padding:3px}.sq-empty{padding:24px 12px;border:1px dashed var(--ri-ui-line-strong);border-radius:var(--ri-ui-radius-m);text-align:center;line-height:1.6;color:var(--ri-ui-text-2)}.sq-empty button{margin-top:8px}.sq-timeline{margin-top:16px;padding:10px;border:1px solid var(--ri-ui-line);border-radius:var(--ri-ui-radius-m);background:transparent}.sq-ruler{display:flex;justify-content:space-between;color:var(--ri-ui-text-2);font-size:11px;padding-bottom:10px;font-variant-numeric:tabular-nums}.sq-track{margin-bottom:10px;border-radius:var(--ri-ui-radius-s);padding:7px 8px;background:var(--ri-ui-hover);border:1px solid transparent}.sq-track--active{border-color:var(--ri-ui-accent);background:var(--ri-ui-accent-dim)}.sq-trackLabel{display:flex;align-items:center;justify-content:space-between;gap:8px;margin-bottom:8px}.sq-trackLabel>button{min-width:0;border:0;padding:0;color:var(--ri-ui-text-2);background:none;text-align:left;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;font:inherit;cursor:pointer}.sq-trackLabel label{display:flex;gap:4px;align-items:center;font-size:11px;color:var(--ri-ui-text-2)}.sq-lane{position:relative;height:28px;margin:0 8px;background:repeating-linear-gradient(90deg,transparent,transparent calc(25% - 1px),rgba(148,163,184,.12) calc(25% - 1px),rgba(148,163,184,.12) 25%);border-bottom:1px solid var(--ri-ui-line)}.sq-key{position:absolute;top:8px;width:12px;height:12px;padding:0;border:1px solid var(--ri-ui-line-strong);background:var(--ri-ui-field);border-radius:2px;transform:translate(-50%) rotate(45deg);cursor:ew-resize;touch-action:none}.sq-key--active{background:var(--ri-ui-accent);border-color:var(--ri-ui-accent)}.sq-playhead{position:absolute;top:0;bottom:-1px;width:1px;background:var(--ri-ui-warning);pointer-events:none}.sq-addTrack,.sq-inspector{border-top:1px solid var(--ri-ui-line);padding-top:14px;margin-top:18px}.sq-editor h3{margin:0 0 12px;font-size:12px;font-weight:600}.sq-inspectorTitle{justify-content:space-between;margin-bottom:10px}.sq-inspectorTitle h3{margin:0}.sq-inspector>button{margin-bottom:16px}.sq-error{border:1px solid var(--ri-ui-warning);border-radius:var(--ri-ui-radius-m);padding:10px;color:var(--ri-ui-warning);background:var(--ri-ui-warning-dim);line-height:1.5}.sq-key{top:3px;width:22px;height:22px;border:0;background:transparent;transform:translate(-50%)}.sq-key:before{content:"";position:absolute;left:5px;top:5px;width:10px;height:10px;border:1px solid var(--ri-ui-line-strong);border-radius:2px;background:var(--ri-ui-field);transform:rotate(45deg)}.sq-key--active:before{background:var(--ri-ui-accent);border-color:var(--ri-ui-accent)}
@@ -0,0 +1 @@
1
+ import{e as ce}from"./chunk-AL6UIGWP.mjs";import{a as re,b as ne}from"./chunk-OPZJDP7T.mjs";import{e as U,f as se,h as oe,i as le}from"./chunk-FGAJ2UT7.mjs";import"./chunk-T6AYLPCC.mjs";import{a as ee,b as te,c as $,d as ae,e as L,g as ie}from"./chunk-LX3GXQNU.mjs";import"./chunk-6CTCV2Q5.mjs";import"./chunk-JR557W27.mjs";import{useEffect as be,useMemo as Te,useRef as we,useState as S}from"react";import{Copy as je,DiamondPlus as Ie,Plus as _,ScanLine as Ee,Trash2 as G}from"lucide-react";import{useEffect as de,useState as pe}from"react";import{Fragment as ue,jsx as g,jsxs as T}from"react/jsx-runtime";function j({label:p,value:o,onChange:r,min:l,max:u,step:f=.1,disabled:q=!1}){let[y,d]=pe(String(Number(o.toFixed(5))));return de(()=>d(String(Number(o.toFixed(5)))),[o]),T("label",{className:"sq-field",children:[g("span",{children:p}),g("input",{type:"number","aria-label":p,value:y,step:f,min:l,max:u,disabled:q,onChange:m=>d(m.target.value),onBlur:()=>{let m=y.trim()?Number(y):NaN;Number.isFinite(m)&&(l===void 0||m>=l)&&(u===void 0||m<=u)&&m!==o&&r(m),d(String(Number(o.toFixed(5))))},onKeyDown:m=>{m.stopPropagation(),m.key==="Enter"&&m.currentTarget.blur(),m.key==="Escape"&&(m.preventDefault(),d(String(o)))}})]})}function X({label:p,value:o,onChange:r}){let[l,u]=pe(o);return de(()=>u(o),[o]),T("label",{className:"sq-field",children:[g("span",{children:p}),g("input",{"aria-label":p,value:l,maxLength:256,onChange:f=>u(f.target.value),onBlur:()=>{l.trim()&&l.trim()!==o?r(l.trim()):u(o)},onKeyDown:f=>{f.stopPropagation(),f.key==="Enter"&&f.currentTarget.blur()}})]})}function H({label:p,value:o,onChange:r,degrees:l=!1}){return T("fieldset",{className:"sq-vector",children:[T("legend",{children:[p,l?" (\xB0)":""]}),g("div",{children:o.map((u,f)=>g(j,{label:["X","Y","Z"][f],value:l?u*180/Math.PI:u,onChange:q=>r(o.map((y,d)=>f===d?l?q*Math.PI/180:q:y))},f))})]})}function me({target:p,value:o,onChange:r}){if(p.kind==="camera"){let l=o;return T(ue,{children:[g(H,{label:"Camera position",value:l.position,onChange:u=>r({...l,position:u})}),g(H,{label:"Camera target",value:l.target,onChange:u=>r({...l,target:u})}),T(ue,{children:[l.fov!==null&&g(j,{label:"FOV (\xB0)",min:1,max:179,value:l.fov,onChange:u=>r({...l,fov:u})}),g(j,{label:"Zoom",min:.001,value:l.zoom,onChange:u=>r({...l,zoom:u})})]})]})}return Array.isArray(o)?g(H,{label:p.kind==="object"?p.property[0].toUpperCase()+p.property.slice(1):"Value",value:o,degrees:p.kind==="object"&&p.property==="rotation",onChange:r}):typeof o=="boolean"?T("label",{className:"sq-check",children:[g("input",{type:"checkbox",checked:o,onChange:l=>r(l.target.checked)}),"Visible"]}):typeof o=="string"?T("label",{className:"sq-field sq-color",children:[g("span",{children:"Color"}),g("input",{type:"color","aria-label":"Keyframe color",value:o,onChange:l=>r(l.target.value)}),g("code",{children:o})]}):g(j,{label:p.kind==="clip"?"Clip time (s)":"Value",min:0,max:p.kind==="object"&&p.property!=="emissiveIntensity"?1:void 0,step:.01,value:o,onChange:r})}import{Fragment as fe,jsx as t,jsxs as s}from"react/jsx-runtime";var I=()=>crypto.randomUUID(),ge={position:"Position",rotation:"Rotation",scale:"Scale",visible:"Visibility",baseColor:"Color",emissive:"Emissive color",opacity:"Opacity",roughness:"Roughness",metalness:"Metalness",emissiveIntensity:"Emissive intensity"},Pe={linear:"Linear","ease-in":"Ease in","ease-out":"Ease out","ease-in-out":"Ease in / out",step:"Hold / step"};function Ae({config:p,onChange:o,controls:r,bindings:l,clipDetails:u}){let{tier:f}=oe(),q=re(r),y=Te(()=>{try{return{sequences:L(p.sequences??[]),error:""}}catch(e){return{sequences:[],error:e instanceof Error?e.message:"Invalid sequence data."}}},[p.sequences]),d=y.sequences,[Q,m]=S(null),[qe,N]=S(null),[ke,x]=S(null),[w,he]=S("object"),[ve,ye]=S(""),[V,xe]=S("position"),[Y,Se]=S(""),[Z,P]=S(""),[D,K]=S(null),A=we(null),i=d.find(e=>e.id===Q)??d[0],c=i?.tracks.find(e=>e.id===qe)??i?.tracks[0],h=c?.keyframes.find(e=>e.id===ke)??c?.keyframes[0],B=Object.values(l).filter((e,a,k)=>!e.removed&&k.findIndex(n=>n.modelObjectId===e.modelObjectId)===a),M=B.find(e=>e.modelObjectId===ve)??B[0],R=u.some(e=>e.sourceName===Y)?Y:u[0]?.sourceName;be(()=>{i&&r&&q.sequenceId!==i.id&&r.select(i.id)},[r,i?.id,q]),be(()=>()=>r?.stop(),[r]);let O=e=>{try{let a=L(e);o({...p,sequences:a}),P("")}catch(a){P(a instanceof Error?a.message:"Invalid sequence.")}},E=e=>O(d.map(a=>a.id===e.id?e:a)),z=e=>{i&&E({...i,tracks:i.tracks.map(a=>a.id===e.id?e:a)})},C=(e,a)=>{if(!i||!ae(a.value,e.target)){P("Use a valid value; scale components must be nonzero.");return}z(ie(e,{...a,time:Math.max(0,Math.min(i.duration,a.time))})),N(e.id),x(a.id),r?.pause(),r?.seek(a.time)},J=()=>{if(d.length>=64)return;let e={id:I(),name:`Sequence ${d.length+1}`,duration:5,loop:!1,autoPlay:!1,tracks:[]};O([...d,e]),m(e.id),N(null),x(null)},v=w==="camera"?{kind:"camera"}:w==="clip"?R?{kind:"clip",clip:R}:null:M?{kind:"object",objectId:M.modelObjectId,property:V}:null,F=!!v&&i?.tracks.some(e=>$(e.target)===$(v)),Ne=()=>{if(!i||!v||F)return;let e=r?.capture(v);if(e==null){P("That target is not ready. Wait for the model, or choose another object/clip.");return}let a=v.kind==="clip"?Math.min(i.duration,u.find(n=>n.sourceName===v.clip)?.duration??i.duration):structuredClone(e),k={id:I(),name:v.kind==="camera"?"Camera":v.kind==="clip"?v.clip:`${M?.label||M?.modelObjectId} \xB7 ${ge[V]}`,target:v,keyframes:[{id:I(),time:0,value:e,easing:V==="visible"&&w==="object"?"step":"ease-in-out"},{id:I(),time:i.duration,value:a}]};E({...i,tracks:[...i.tracks,k]}),N(k.id),x(k.keyframes[1].id),r?.seek(i.duration)},Ce=()=>{if(!c||!i||c.keyframes.length>=2048)return;let e=r?.capture(c.target);if(e==null){P("The selected target is unavailable.");return}let a={id:I(),time:Math.min(q.time,i.duration),value:e,easing:"ease-in-out"};C(c,a)};return s("section",{className:"sq-editor","aria-label":"Visual sequence authoring",children:[y.error&&t("p",{role:"alert",className:"sq-error",children:y.error}),U(f,"sequences",d.length)?null:t(le,{requiredTier:se("sequences",d.length),feature:"More sequences"}),i?s(fe,{children:[s("div",{className:"sq-toolbar",children:[t("select",{className:"se-select sq-toolbarPicker","aria-label":"Authored sequence",value:i.id,onChange:e=>{m(e.target.value),N(null),x(null),r?.select(e.target.value)},children:d.map(e=>t("option",{value:e.id,children:e.name},e.id))}),t("button",{type:"button",className:"se-iconButton",title:"Add sequence","aria-label":"Add sequence",disabled:d.length>=64||!U(f,"sequences",d.length),onClick:J,children:t(_,{size:14})}),t("button",{type:"button",className:"se-iconButton",title:"Duplicate sequence","aria-label":"Duplicate sequence",disabled:d.length>=64,onClick:()=>{let e={...structuredClone(i),id:I(),name:`${i.name} copy`.slice(0,256),autoPlay:!1};O([...d,e]),m(e.id)},children:t(je,{size:13})}),t("button",{type:"button",className:"se-iconButton",title:"Delete sequence","aria-label":"Delete sequence",onClick:()=>{r?.stop(),O(d.filter(e=>e.id!==i.id)),m(null)},children:t(G,{size:13})}),t("span",{className:"sq-toolbarDivider"}),t(X,{label:"Name",value:i.name,onChange:e=>E({...i,name:e})}),t(j,{label:"Duration",min:.1,max:3600,value:i.duration,onChange:e=>E({...i,duration:e,tracks:i.tracks.map(a=>({...a,keyframes:a.keyframes.map(k=>({...k,time:k.time/i.duration*e}))}))})}),s("label",{className:"sq-check",children:[t("input",{type:"checkbox",checked:i.loop,onChange:e=>E({...i,loop:e.target.checked})}),"Loop"]}),s("label",{className:"sq-check",children:[t("input",{type:"checkbox",checked:i.autoPlay,onChange:e=>O(d.map(a=>({...a,autoPlay:a.id===i.id?e.target.checked:!1})))}),"Autoplay"]})]}),s("div",{className:"sq-body",children:[s("div",{className:"sq-main",children:[t(ne,{controls:r,duration:i.duration,hasTracks:i.tracks.some(e=>!e.muted&&e.keyframes.length>0)}),s("div",{className:"sq-timeline","aria-label":"Sequence timeline",title:"Drag keys to retime. Arrow keys move 0.1s; Shift moves 0.01s. A key at the same time is replaced.",children:[s("div",{className:"sq-ruler",children:[t("span",{className:"sq-rulerTitle",children:"Tracks"}),t("div",{className:"sq-rulerScale",children:[0,.25,.5,.75,1].map(e=>s("span",{children:[(i.duration*e).toFixed(1),"s"]},e))})]}),!i.tracks.length&&t("p",{className:"sq-hint",children:"Add a track to create its start and end keyframes."}),i.tracks.map(e=>s("div",{className:`sq-track ${c?.id===e.id?"sq-track--active":""}`,children:[s("div",{className:"sq-trackLabel",children:[t("button",{type:"button",title:e.name,onClick:()=>{N(e.id),x(e.keyframes[0]?.id??null)},children:e.name}),s("label",{title:"Mute track",children:[t("input",{"aria-label":`Mute ${e.name}`,type:"checkbox",checked:!!e.muted,onChange:a=>z({...e,muted:a.target.checked})}),"Mute"]})]}),s("div",{className:"sq-lane",role:"group","aria-label":`${e.name} keyframes`,onDoubleClick:a=>{if(a.target!==a.currentTarget)return;let k=a.currentTarget.getBoundingClientRect(),n=Math.round(Math.max(0,Math.min(1,(a.clientX-k.left)/k.width))*i.duration*100)/100,b=r?.capture(e.target);b!=null&&C(e,{id:I(),time:n,value:b})},children:[t("span",{className:"sq-playhead",style:{left:`${q.time/i.duration*100}%`}}),e.keyframes.map(a=>{let k=D?.frameId===a.id&&D.trackId===e.id?D.time:a.time;return t("button",{type:"button",className:`sq-key ${h?.id===a.id&&c?.id===e.id?"sq-key--active":""}`,style:{left:`${k/i.duration*100}%`},"aria-label":`${e.name} keyframe at ${k.toFixed(2)} seconds`,"aria-pressed":h?.id===a.id&&c?.id===e.id,onClick:n=>{n.detail===0&&(N(e.id),x(a.id),r?.pause(),r?.seek(a.time))},onPointerDown:n=>{if(n.button!==0)return;n.preventDefault(),n.stopPropagation(),n.currentTarget.focus(),n.currentTarget.setPointerCapture(n.pointerId);let b=n.currentTarget.parentElement.getBoundingClientRect();A.current={track:e,frame:a,left:b.left,width:b.width,time:a.time},N(e.id),x(a.id),r?.pause(),r?.seek(a.time)},onPointerMove:n=>{let b=A.current;if(!b||b.frame.id!==a.id||b.track.id!==e.id)return;let W=n.shiftKey?.01:.1;b.time=Math.min(i.duration,Math.max(0,Math.round((n.clientX-b.left)/b.width*i.duration/W)*W)),K({trackId:e.id,frameId:a.id,time:b.time}),r?.seek(b.time)},onPointerUp:()=>{let n=A.current;n&&(n.time!==n.frame.time&&C(n.track,{...n.frame,time:n.time}),A.current=null,K(null))},onPointerCancel:()=>{A.current=null,K(null),r?.seek(a.time)},onKeyDown:n=>{if(!["ArrowLeft","ArrowRight","Home","End"].includes(n.key))return;n.preventDefault(),n.stopPropagation();let b=n.key==="Home"?0:n.key==="End"?i.duration:a.time+(n.key==="ArrowLeft"?-1:1)*(n.shiftKey?.01:.1);C(e,{...a,time:b})}},a.id)})]})]},e.id))]})]}),s("aside",{className:"sq-side",children:[s(ce,{title:"Add track",children:[s("label",{className:"sq-field",children:[t("span",{children:"Type"}),s("select",{"aria-label":"Track type",value:w,onChange:e=>he(e.target.value),children:[t("option",{value:"object",children:"Object"}),t("option",{value:"camera",children:"Camera"}),t("option",{value:"clip",children:"Animation clip"})]})]}),w==="object"&&s("label",{className:"sq-field",children:[t("span",{children:"Property"}),t("select",{"aria-label":"Track property",value:V,onChange:e=>xe(e.target.value),children:ee.map(e=>t("option",{value:e,children:ge[e]},e))})]}),w==="object"&&s("label",{className:"sq-field",children:[t("span",{children:"Object"}),t("select",{"aria-label":"Track object",value:M?.modelObjectId??"",onChange:e=>ye(e.target.value),children:B.map(e=>t("option",{value:e.modelObjectId,children:e.label||e.modelObjectId},e.modelObjectId))})]}),w==="clip"&&s("label",{className:"sq-field",children:[t("span",{children:"Clip"}),t("select",{"aria-label":"Track animation clip",value:R??"",onChange:e=>Se(e.target.value),children:u.map(e=>t("option",{value:e.sourceName,children:e.sourceName},e.sourceName))}),!u.length&&t("small",{children:"This model has no animation clips."})]}),t("div",{className:"rui-actions",children:s("button",{type:"button",className:"bb-button",onClick:Ne,disabled:!v||!q.ready||F||i.tracks.length>=128,children:[t(_,{size:13,"aria-hidden":"true"}),"Add track"]})}),F&&t("p",{className:"rui-note",children:"That property already has a track."})]}),c&&s("section",{className:"sq-inspector","aria-label":"Selected track and keyframe",children:[s("div",{className:"rui-groupHeader",children:[t("span",{children:"Selected track"}),t("button",{type:"button",className:"se-iconButton",title:"Delete track","aria-label":"Delete track",onClick:()=>{E({...i,tracks:i.tracks.filter(e=>e.id!==c.id)}),N(null),x(null)},children:t(G,{size:13})})]}),t(X,{label:"Name",value:c.name,onChange:e=>z({...c,name:e})}),t("div",{className:"rui-actions",children:s("button",{type:"button",className:"bb-button",disabled:!q.ready||c.keyframes.length>=2048,onClick:Ce,children:[t(Ie,{size:13,"aria-hidden":"true"}),"Add keyframe at playhead"]})}),h&&s(fe,{children:[s("div",{className:"rui-groupHeader",children:[t("span",{children:"Keyframe"}),t("button",{type:"button",className:"se-iconButton",title:"Delete keyframe","aria-label":"Delete keyframe",onClick:()=>{z({...c,keyframes:c.keyframes.filter(e=>e.id!==h.id)}),x(null)},children:t(G,{size:14})})]}),t(j,{label:"Time",min:0,max:i.duration,value:h.time,step:.01,onChange:e=>C(c,{...h,time:e})}),s("label",{className:"sq-field",children:[t("span",{children:"Easing"}),t("select",{"aria-label":"Keyframe easing",value:c.target.kind==="object"&&c.target.property==="visible"?"step":h.easing??"ease-in-out",disabled:c.target.kind==="object"&&c.target.property==="visible",onChange:e=>C(c,{...h,easing:e.target.value}),children:te.map(e=>t("option",{value:e,children:Pe[e]},e))})]}),t(me,{target:c.target,value:h.value,onChange:e=>C(c,{...h,value:e})}),t("div",{className:"rui-actions",children:s("button",{type:"button",className:"bb-button",disabled:!q.ready,onClick:()=>{let e=r?.capture(c.target);e!=null&&C(c,{...h,value:e})},children:[t(Ee,{size:13,"aria-hidden":"true"}),"Capture current value"]})})]})]})]})]})]}):s("div",{className:"sq-empty",children:[t("p",{children:"Add a sequence, then add tracks and capture keyframes on the timeline."}),s("button",{type:"button",className:"bb-button bb-button--primary",onClick:J,children:[t(_,{size:13,"aria-hidden":"true"}),"Create sequence"]})]}),(Z||q.issues.length>0)&&t("div",{role:"status",className:"sq-error",children:Z||q.issues.join(" ")})]})}export{Ae as default};