three-live 1.3.2 → 1.4.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 (58) hide show
  1. package/README.md +4 -1
  2. package/dist/index.d.ts +190 -0
  3. package/dist/three-author-engine.js +171 -163
  4. package/dist/three-author.cjs +145 -163
  5. package/dist/three-author.d.ts +190 -0
  6. package/dist/three-author.js +145 -163
  7. package/dist/three-convert.cjs +142 -160
  8. package/dist/three-convert.d.ts +190 -0
  9. package/dist/three-convert.js +142 -160
  10. package/dist/three-live-ai.cjs +41 -0
  11. package/dist/three-live-ai.d.ts +759 -0
  12. package/dist/three-live-ai.js +41 -0
  13. package/dist/three-live-ai.min.js +41 -0
  14. package/dist/three-live-animation.cjs +6 -6
  15. package/dist/three-live-animation.d.ts +190 -0
  16. package/dist/three-live-animation.js +5 -5
  17. package/dist/three-live-animation.min.js +5 -5
  18. package/dist/three-live-cad.cjs +2 -2
  19. package/dist/three-live-cad.d.ts +190 -0
  20. package/dist/three-live-cad.js +2 -2
  21. package/dist/three-live-cad.min.js +2 -2
  22. package/dist/three-live-element.cjs +50 -85
  23. package/dist/three-live-element.d.ts +190 -0
  24. package/dist/three-live-element.js +50 -85
  25. package/dist/three-live-full.cjs +907 -189
  26. package/dist/three-live-full.js +907 -189
  27. package/dist/three-live-full.min.js +907 -189
  28. package/dist/three-live-procedural.cjs +16 -0
  29. package/dist/three-live-procedural.d.ts +759 -0
  30. package/dist/three-live-procedural.js +16 -0
  31. package/dist/three-live-procedural.min.js +16 -0
  32. package/dist/three-live-sandbox.html +11 -1
  33. package/dist/three-live-studio.cjs +72 -17
  34. package/dist/three-live-studio.d.ts +190 -0
  35. package/dist/three-live-studio.js +72 -17
  36. package/dist/three-live-studio.min.js +73 -18
  37. package/dist/three-live-tsl.cjs +103 -0
  38. package/dist/three-live-tsl.d.ts +759 -0
  39. package/dist/three-live-tsl.js +103 -0
  40. package/dist/three-live-tsl.min.js +103 -0
  41. package/dist/three-live-viewer.cjs +50 -85
  42. package/dist/three-live-viewer.d.ts +190 -0
  43. package/dist/three-live-viewer.js +50 -85
  44. package/dist/three-live-viewer.min.js +50 -85
  45. package/dist/three-live-webgpu.cjs +585 -0
  46. package/dist/three-live-webgpu.d.ts +759 -0
  47. package/dist/three-live-webgpu.js +585 -0
  48. package/dist/three-live-webgpu.min.js +585 -0
  49. package/dist/three-live.cjs +147 -165
  50. package/dist/three-live.js +147 -165
  51. package/dist/three-live.min.js +147 -165
  52. package/dist/three-view.cjs +49 -84
  53. package/dist/three-view.d.ts +190 -0
  54. package/dist/three-view.js +50 -85
  55. package/dist/three-xr.cjs +141 -159
  56. package/dist/three-xr.d.ts +190 -0
  57. package/dist/three-xr.js +140 -158
  58. package/package.json +21 -1
@@ -0,0 +1,41 @@
1
+ "use strict";/**
2
+ * @license
3
+ * Copyright 2026 Google LLC
4
+ *
5
+ * Licensed under the Apache License, Version 2.0 (the "License");
6
+ * you may not use this file except in compliance with the License.
7
+ * You may obtain a copy of the License at
8
+ *
9
+ * http://www.apache.org/licenses/LICENSE-2.0
10
+ *
11
+ * Unless required by applicable law or agreed to in writing, software
12
+ * distributed under the License is distributed on an "AS IS" BASIS,
13
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14
+ * See the License for the specific language governing permissions and
15
+ * limitations under the License.
16
+ */var Pe=Object.defineProperty,ln=Object.getOwnPropertyDescriptor,cn=Object.getOwnPropertyNames,un=Object.prototype.hasOwnProperty,dn=(e,t)=>{for(var r in t)Pe(e,r,{get:t[r],enumerable:!0})},pn=(e,t,r,n)=>{if(t&&typeof t=="object"||typeof t=="function")for(let i of cn(t))!un.call(e,i)&&i!==r&&Pe(e,i,{get:()=>t[i],enumerable:!(n=ln(t,i))||n.enumerable});return e},mn=e=>pn(Pe({},"__esModule",{value:!0}),e),xr={};dn(xr,{AIVoiceSession:()=>Q,IMAGE_SYSTEM_PROMPT:()=>Ge,TEXTURE_PROMPT_SUFFIX:()=>ot,aiPlugin:()=>_e,browserImageCodec:()=>Z,buildImageMessages:()=>Xe,buildImageUserText:()=>He,buildSelectIndex:()=>G,compileFromImage:()=>ye,connectVoice:()=>ee,createAIChatProvider:()=>xt,createAIImageProvider:()=>it,createWebSpeechRecognizer:()=>yt,describeEditResult:()=>Ce,describeSelection:()=>H,describeVoiceSelection:()=>q,detectImageMime:()=>Ye,editScene:()=>wt,extractScript:()=>J,formatSpatialPriors:()=>he,geminiLiveAdapter:()=>ft,getSelection:()=>k,hideSelectionChips:()=>$,imageRepairMessage:()=>Je,indexedDbTextureCache:()=>ct,isAllowedImageUrl:()=>_,matchSelection:()=>le,normalizeImageInput:()=>fe,parseSelectReply:()=>We,parseTexturePack:()=>at,parseVoiceCommand:()=>ce,prepareAlbedo:()=>st,realtimeAdapter:()=>ht,resolveSelection:()=>de,resolveSelectionWithModel:()=>pe,sceneSelectEntries:()=>F,selectByVoice:()=>W,selectCamera:()=>ue,selectMessages:()=>qe,selectNamesByVoice:()=>bt,serializeTexturePack:()=>lt,setSelectOnTap:()=>ne,setSelection:()=>T,showSelectionChips:()=>Te,speakableName:()=>Re,startVoiceEdit:()=>te,textureRequests:()=>ve,undoEdit:()=>St}),module.exports=mn(xr);var re="__THREE_LIVE_REGISTRY__";function O(){let e=typeof globalThis<"u"?globalThis:{};if(!e[re]){let t={plugins:[],decoders:new Map};try{Object.defineProperty(e,re,{value:t,writable:!1,configurable:!1,enumerable:!1})}catch{e[re]=t}}return e[re]}var Sr=O().plugins;function vt(e){let t=O().plugins;t.some(r=>r.name===e.name)||t.push(e),e.onRegister?.()}var Ne={eye:[0,1.6,5],target:[0,.8,0]},Rt=new Set("the a an please can could would you will i want wanna to me my that this those these of one ones object objects thing things item items mesh meshes piece pieces part parts just only also too is are there here which select pick choose highlight grab focus on in at by some most side hand them it its and s now again as well other others".split(" ")),gn=["sofa couch settee","lamp light lantern","door gate doorway","table desk","chair seat stool","rug carpet mat","cup mug","tv television screen monitor","car vehicle automobile","box crate cube","ball sphere orb","floor ground","plant tree bush","cabinet cupboard closet"].map(e=>e.split(" ")),se=[["red",[220,40,40],"red"],["orange",[245,140,30],"orange"],["yellow",[240,220,40],"yellow"],["gold",[212,175,55],"yellow"],["green",[50,170,60],"green"],["teal",[0,128,128],"green"],["cyan",[40,200,220],"blue"],["blue",[40,80,220],"blue"],["navy",[20,30,100],"blue"],["purple",[130,50,180],"purple"],["magenta",[220,40,200],"pink"],["pink",[240,120,180],"pink"],["brown",[130,80,40],"brown"],["beige",[225,205,160],"brown"],["white",[245,245,245],"white"],["silver",[192,192,192],"gray"],["gray",[128,128,128],"gray"],["black",[20,20,20],"black"]],At={grey:"gray",golden:"gold",crimson:"red",maroon:"red",violet:"purple",aqua:"cyan",turquoise:"cyan",tan:"beige"},je={};function C(e,t){for(let r of e.split(" "))je[r]=t}C("left leftmost",["right",!1]),C("right rightmost",["right",!0]),C("front nearest closest frontmost",["depth",!1]),C("back farthest furthest rear far backmost",["depth",!0]),C("top highest upper topmost",["up",!0]),C("bottom lowest lower bottommost",["up",!1]),C("biggest largest big large huge bigger larger",["size",!0]),C("smallest small tiny little smaller",["size",!1]),C("tallest tall taller",["height",!0]),C("shortest short shorter",["height",!1]),C("middle center centre central","middle");var Et={first:0,second:1,third:2,fourth:3,fifth:4,last:-1},It={two:2,pair:2,three:3,four:4,five:5,six:6,seven:7,eight:8,nine:9,ten:10},Ct=new Set(["all","every","everything","each","everybody"]),Ue=e=>/^[0-9]+$/.test(e),ae=(e,t)=>Object.prototype.hasOwnProperty.call(e,t),$e=e=>ae(je,e)?je[e]:null,_t=e=>ae(Et,e)?Et[e]:null;function Pt(e){let t;if(ae(It,e))t=It[e];else if(/^[0-9]{1,3}$/.test(e))t=Number(e);else return null;return t>=1&&t<=50?t:null}function Lt(e){return ae(At,e)?At[e]:se.some(t=>t[0]===e)?e:null}function hn(e){for(let t=0;t<e.length;t++){let r=e[t],n=e[t+1]??"";if(/^(near|nearby|beside|behind|under|underneath|beneath|above|below|between|inside|within|against|with|beyond|around)$/.test(r)||(r==="next"||r==="close")&&n==="to"||(r==="front"||r==="top")&&n==="of")return!0;if(r==="on"||r==="by"){let i=t+1;for(;i<e.length&&/^(the|a|an|its|my)$/.test(e[i]);)i++;let o=e[i];if(o!==void 0&&!$e(o)&&o!=="side"&&o!=="end")return!0}}return!1}function fn(e){return String(e??"").toLowerCase().split(/[^a-z0-9]+/).filter(Boolean)}function Vt(e){let t=e.length;if(t>4&&e.endsWith("ies"))return e.slice(0,-3)+"y";if(t>4&&e.endsWith("ves"))return e.slice(0,-3)+"f";for(let r of["ches","shes","xes","sses","zes"])if(t>r.length+1&&e.endsWith(r))return e.slice(0,-2);return t>3&&e.endsWith("s")&&!e.endsWith("ss")&&!e.endsWith("us")?e.slice(0,-1):e}function yn(e){let t=[],r="",n="",i=s=>s>="a"&&s<="z",o=s=>s>="A"&&s<="Z",a=s=>s>="0"&&s<="9";for(let s of String(e)){if(!(i(s)||o(s)||a(s))){r&&t.push(r),r="",n="";continue}n&&r&&(i(n)&&o(s)||a(n)!==a(s))&&(t.push(r),r=""),r+=s.toLowerCase(),n=s}return r&&t.push(r),t.map(Vt)}var bn=e=>e.replace(/[^A-Za-z0-9]/g,"").toLowerCase(),xn=(e,t)=>gn.some(r=>r.includes(e)&&r.includes(t));function kt(e,t){return e===t||xn(e,t)||t.length>=4&&e.length>=4&&(e.startsWith(t)||t.startsWith(e))}function Le(e){let t=Math.min(1,Math.max(0,Number.isFinite(e)?e:0));return(t<=.0031308?12.92*t:1.055*Math.pow(t,1/2.4)-.055)*255}function wn(e){let t=[Le(e[0]),Le(e[1]),Le(e[2])],r=se[0][0],n=1/0;for(let[i,o]of se){let a=(t[0]-o[0])**2+(t[1]-o[1])**2+(t[2]-o[2])**2;a<n&&(n=a,r=i)}return r}var Sn=e=>se.find(t=>t[0]===e)?.[2]??"";function vn(e,t){return e.words.includes(t)?!0:e.colorName!=null&&(e.colorName===t||Sn(e.colorName)===t)}function G(e){return e.map((t,r)=>{let n=[0,1,2].map(i=>Math.abs(t.max[i]-t.min[i]));return{id:r,name:t.name,words:yn(t.name),colorName:t.color?wn(t.color):null,size:Math.max(n[0],.01)*Math.max(n[1],.01)*Math.max(n[2],.01),height:n[1],center:[0,1,2].map(i=>(t.min[i]+t.max[i])/2)}})}function An(e){let t=[0,1,2].map(a=>e.target[a]-e.eye[a]),r=Math.hypot(t[0],t[1],t[2]),n=r<1e-9?[0,0,-1]:t.map(a=>a/r),i=[-n[2],0,n[0]],o=Math.hypot(i[0],i[1],i[2]);return{eye:e.eye,right:o<1e-9?[1,0,0]:i.map(a=>a/o)}}function U(e,t,r){let n=[0,1,2].map(i=>e.center[i]-r.eye[i]);switch(t){case"right":return n[0]*r.right[0]+n[1]*r.right[1]+n[2]*r.right[2];case"depth":return Math.sqrt(n[0]*n[0]+n[1]*n[1]+n[2]*n[2]);case"up":return e.center[1];case"size":return e.size;default:return e.height}}var Ot=e=>e.length?e.reduce((t,r)=>t+r,0)/e.length:0;function Ve(e,t,r){let n;if(t==="middle"){if(e.length<3)return e;let i=e.map(s=>U(s,"right",r)),o=Math.min(...i),a=Math.max(...i);n=e.filter((s,l)=>i[l]>o+1e-6&&i[l]<a-1e-6)}else{let i=e.map(a=>U(a,t[0],r)),o=Ot(i);n=e.filter((a,s)=>t[1]?i[s]>o+1e-6:i[s]<o-1e-6)}return n.length?n:e}function Tt(e,t,r){let n;if(t==="middle"){let i=Ot(e.map(o=>U(o,"right",r)));n=e.map(o=>[o,Math.abs(U(o,"right",r)-i)])}else n=e.map(i=>[i,t[1]?-U(i,t[0],r):U(i,t[0],r)]);return n.sort((i,o)=>i[1]-o[1])}function M(e,t,r){let n=[...e].sort((a,s)=>a.id-s.id),i=[...new Set(n.map(a=>a.id))],o=[];for(let a of n)!o.includes(a.name)&&o.length<50&&o.push(a.name);return t==="high"?{ids:i,names:o,confidence:t,candidates:[],reason:r}:t==="ambiguous"?{ids:[],names:[],confidence:t,candidates:o.slice(0,10),reason:r}:{ids:[],names:[],confidence:t,candidates:[],reason:r}}var j=e=>M([],"none",e);function le(e,t,r=Ne,n){let i=n?e.filter(a=>n.includes(a.name)):[...e],o=fn(t);for(let a=0;a<o.length;a++){let s=o[a],l=o[a+1]??"",c=s==="except"||s==="excluding";if(!(c||s==="but"&&l==="not"||s==="other"&&l==="than"))continue;let u=Oe(i,o.slice(0,a),r);if(u.confidence!=="high")return u;let d=i.filter(p=>u.ids.includes(p.id)),m=Oe(d,o.slice(a+(c?1:2)),r);if(m.confidence!=="high")return M(d,"ambiguous","except");let h=d.filter(p=>!m.ids.includes(p.id));return h.length?M(h,"high","match"):j("no_match")}return Oe(i,o,r)}function En(e){return!(Rt.has(e)||Ct.has(e)||e==="both"||Pt(e)!==null||_t(e)!==null||Lt(e)!==null||$e(e)!==null||Ue(e))}function Oe(e,t,r){let n=[[]];for(let l of t)l==="and"?n.push([]):n[n.length-1].push(l);let i=n.filter(l=>l.length);if(i.length<2||!i.every(l=>l.some(En)))return Mt(e,t,r);let o=[],a=!1;for(let l of i){let c=Mt(e,l,r);if(c.confidence==="none")return c;c.confidence==="ambiguous"?(a=!0,o.push(...e.filter(u=>c.candidates.includes(u.name)))):o.push(...e.filter(u=>c.ids.includes(u.id)))}let s=[...new Map(o.map(l=>[l.id,l])).values()];return a?M(s,"ambiguous","multiple"):M(s,"high","match")}function Mt(e,t,r){if(!e.length)return j("no_match");let n=0;for(;n<t.length&&/^(select|pick|choose|highlight|grab|the|a|an|just|only)$/.test(t[n]);)n++;let i=t.slice(n).join("");if(i){let f=e.filter(g=>bn(g.name)===i);if(f.length)return M(f,"high","exact")}if(hn(t))return j("relation");let o=[],a=!1,s=!1,l=null,c=null,u=[],d=[],m=!1;for(let f of t){if(m&&Ue(f)){o.push(f);continue}m=!1;let g,x,w;if(Ct.has(f))s=!0,a=!0;else if(f==="both")l=2,a=!0;else if((g=Pt(f))!==null)l=g,a=a||g>1;else if((g=_t(f))!==null)c=g;else if((x=Lt(f))!==null)u.push(x);else if((w=$e(f))!==null)d.push(w);else if(!Rt.has(f)){let b=Vt(f);b!==f&&(a=!0),o.push(b),m=!0}}if(!o.length&&!u.length&&!d.length&&c===null&&!s&&l===null)return j("empty");let h=An(r),p=e;if(o.length){let f=p.map(b=>({e:b,n:o.filter(E=>b.words.some(A=>kt(A,E))).length})),g=Math.max(0,...f.map(b=>b.n));if(g===0)return j("no_match");p=f.filter(b=>b.n===g).map(b=>b.e);let x=b=>b.words.filter(E=>!Ue(E)&&!o.some(A=>kt(E,A))).length,w=Math.min(...p.map(x));p=p.filter(b=>x(b)===w)}if(u.length&&(p=p.filter(f=>u.some(g=>vn(f,g)))),!p.length)return j("no_match");if(c!==null){for(let w of d)p=Ve(p,w,h);let f=Tt(p,["right",!1],h),g=Math.min(l??1,f.length),x;if(c<0)x=f.slice(f.length-g);else{let w=c*(l!==null?g:1);if(w>=f.length)return j("no_match");x=f.slice(w,w+g)}return M(x.map(w=>w[0]),"high","match")}let y=!a&&l===null,v=y?1:s?null:l;if(v!==null&&d.length){for(let x of d.slice(0,-1))p=Ve(p,x,h);let f=Tt(p,d[d.length-1],h),g=v;if(f.length<g)return M(f.map(x=>x[0]),"ambiguous","count_mismatch");if(f.length>g&&Math.abs(f[g][1]-f[g-1][1])<=1e-6){let x=f[g-1][1];return M(f.filter(w=>Math.abs(w[1]-x)<=1e-6).map(w=>w[0]),"ambiguous","multiple")}return M(f.slice(0,g).map(x=>x[0]),"high","match")}for(let f of d)p=Ve(p,f,h);return y?p.length===1?M(p,"high","match"):M(p,"ambiguous","multiple"):l!==null&&p.length!==l?M(p,"ambiguous","count_mismatch"):M(p,"high","match")}var jt="make paint color colour turn move rotate scale resize delete remove change set add put give raise lower shrink enlarge hide show swap replace spin flip double halve duplicate copy animate brighten darken".split(" "),oe=(e,t)=>{for(let r of t)if(e.startsWith(r))return e.slice(r.length).trim()||null;return null},De=(e,t)=>{for(let r of t)if(e.endsWith(r))return e.slice(0,-r.length).trim()||null;return null},Fe=e=>e.replace(/[.!?,]+$/,"");function In(e){let t=e.split(" ");for(let r=0;r<t.length;r++){let n=t[r].endsWith(","),i=r>0&&(t[r]==="and"||t[r]==="then");if(!(n||i))continue;let o=r+1;for(;o<t.length&&(t[o]==="then"||t[o]==="and");)o++;if(o>=t.length||!jt.includes(t[o]))continue;let a=(i?t.slice(0,r):t.slice(0,r+1)).join(" ").replace(/,+$/,"").trim();if(a)return[a,t.slice(o).join(" ")]}return[e,null]}function Ut(e,t){let r=e.split(/\s+/).filter(Boolean);return r.length&&Fe(r[r.length-1]).toLowerCase()==="please"&&r.pop(),Fe(r.slice(Math.max(0,r.length-t)).join(" "))}function ie(e,t,r){let[n,i]=In(t),o=De(n,[" too"," as well"," also"]);if(o!==null&&e==="replace"&&(e="add",n=o),i!==null){let a=i.split(/\s+/).filter(Boolean).length;return{kind:"mixed",mode:e,query:n,instruction:Ut(r,a)}}return{kind:"select",mode:e,query:n}}var kn=["please ","ok ","ok, ","okay ","okay, ","now ","now, ","hey ","um ","um, ","uh ","uh, ","so ","so, ","and "],Tn=new Set(["clear selection","clear the selection","reset selection","reset the selection","select nothing","select none","deselect","deselect all","deselect everything","unselect","unselect all","unselect everything","clear","clear all"]),Mn=["select only ","select just ","only select ","just select ","select ","pick ","choose ","highlight ","grab ","focus on "];function ce(e){let t=String(e??"").trim(),r=t.toLowerCase().replace(/[\u2018\u2019]/g,"'").split(/\s+/).filter(Boolean).join(" ");for(r=Fe(r);;){let i=r.length;for(let o of kn)r.startsWith(o)&&(r=r.slice(o.length));if(r.endsWith(" please")&&(r=r.slice(0,-7).replace(/,+$/,"")),r.length===i)break}if(r=r.trim(),Tn.has(r))return{kind:"clear",mode:"clear"};let n=oe(r,["deselect ","unselect ","don't select ","do not select "]);if(n!==null)return ie("remove",n,t);for(let i of["remove ","take "])if(r.startsWith(i)){let o=De(r.slice(i.length),[" from the selection"," from selection"," out of the selection"]);if(o!==null)return{kind:"select",mode:"remove",query:o}}if(n=oe(r,["also select ","also pick ","also choose ","also add "]),n!==null)return ie("add",n,t);if(r.startsWith("add ")){let i=De(r.slice(4),[" to the selection"," to selection"]);if(i!==null)return{kind:"select",mode:"add",query:i}}return n=oe(r,Mn),n!==null||(n=oe(r,["just ","only "]),n!==null&&!jt.includes(n.split(" ")[0]))?ie("replace",n,t):{kind:"edit",instruction:Ut(t,1/0)}}var Dt=50;function Be(e){let t=[];for(let r of e){let n=typeof r=="string"?r.slice(0,200):"";if(n&&!t.includes(n)&&t.push(n),t.length>=Dt)break}return t}function k(e){let t=e.__tlSelection??[],r=e.selectedMesh||null;return(t[0]??null)!==r?r?[r]:[]:[...t]}function T(e,t,r={}){let n=r.mode??"replace",i=k(e),o=Be(typeof t=="string"?[t]:t??[]),a;switch(n){case"clear":a=[];break;case"add":a=Be([...i,...o]);break;case"remove":a=i.filter(u=>!o.includes(u));break;case"toggle":a=Be([...i.filter(u=>!o.includes(u)),...o.filter(u=>!i.includes(u))]);break;default:a=o}let s=a.filter(u=>!i.includes(u)),l=i.filter(u=>!a.includes(u));if(!s.length&&!l.length&&a.join(`
17
+ `)===i.join(`
18
+ `))return null;e.__tlSelection=a,e.selectedMesh=a[0]??null,e.viewer?.setSelectedMeshes?.(a);let c={mesh:a[0]??null,meshes:a,added:s,removed:l,source:r.source??"api",...r.query?{query:String(r.query).slice(0,2e3)}:{}};return e.fireEvent?.("three-live-select",c),c}function Ft(e){!e||e.__tlSelectionInstalled||(e.__tlSelectionInstalled=!0,"selectedMeshes"in e||Object.defineProperty(e,"selectedMeshes",{get:()=>k(e),set:t=>{T(e,t??[],{mode:"replace",source:"api"})},configurable:!0}),e.addEventListener?.("three-load",()=>{let t=k(e);t.length>1&&e.viewer?.setSelectedMeshes?.(t)}))}function H(e){if(!e.length)return"The user cleared the selection.";if(e.length===1)return`The user selected the mesh "${e[0]}". "This" or "it" now refers to it.`;let t=e.slice(0,20).map(n=>`"${n}"`),r=e.length>20?` and ${e.length-20} more`:"";return`The user selected ${e.length} meshes: ${t.join(", ")}${r}. "These", "them", or "it" refer to them.`}var ze=new WeakMap;function Rn(e){let t=e;if(ze.has(t))return ze.get(t);let r=[1/0,1/0,1/0],n=[-1/0,-1/0,-1/0];for(let o=0;o+2<e.length;o+=3)for(let a=0;a<3;a++){let s=e[o+a];s<r[a]&&(r[a]=s),s>n[a]&&(n[a]=s)}let i=Number.isFinite(r[0])?[r,n]:null;return ze.set(t,i),i}function F(e){let t=e.viewer?.meshes??[],r=[];for(let n of t.slice(0,5e3)){if(!n?.name||n.visible===!1)continue;let i=n.transform,o=[1/0,1/0,1/0],a=[-1/0,-1/0,-1/0];for(let l of n.primitives??[]){let c=l.positions?Rn(l.positions):null;if(c)for(let u=0;u<8;u++){let d=c[u&1?1:0][0],m=c[u&2?1:0][1],h=c[u&4?1:0][2];for(let p=0;p<3;p++){let y=i?i[p]*d+i[4+p]*m+i[8+p]*h+i[12+p]:[d,m,h][p];y<o[p]&&(o[p]=y),y>a[p]&&(a[p]=y)}}}if(!Number.isFinite(o[0]))continue;let s=n.primitives?.[0]?.baseColor;r.push({name:n.name,min:o,max:a,color:s?[s[0],s[1],s[2]]:null})}return r}function ue(e){let t=e.viewer,r=t?.getCameraOrbit?.(),n=t?.getCameraTarget?.();if(!r||!n||![r.theta,r.phi,r.radius,n.x,n.y,n.z].every(Number.isFinite))return Ne;let i=r.radius*Math.cos(r.phi);return{eye:[n.x+i*Math.sin(r.theta),n.y+r.radius*Math.sin(r.phi),n.z+i*Math.cos(r.theta)],target:[n.x,n.y,n.z]}}function de(e,t,r={}){let n=G(F(e));return le(n,t,ue(e),r.within??null)}var Cn=["You find the objects a user means in a 3D scene.",'Reply with JSON only: {"ids": [numbers], "confidence": "high" or "low", "question": "text"}.',"Use only ids from the objects list.",`Left and right are as seen from the camera: "right" is the camera's right direction.`,'If several objects fit equally, or none fits, set confidence to "low" and ask one short question that names the options.'].join(" "),D=e=>Math.round(e*100)/100;function qe(e,t,r,n=[]){let i=[0,1,2].map(s=>r.target[s]-r.eye[s]),o=Math.hypot(i[2],i[0])||1,a={camera:{eye:r.eye.map(D),target:r.target.map(D),right:[D(-i[2]/o),0,D(i[0]/o)]},objects:e.slice(0,300).map(s=>({id:s.id,name:s.name,color:s.colorName,center:s.center.map(D),size:D(Math.cbrt(s.size))})),selected:n.slice(0,50),request:String(t).slice(0,500)};return[{role:"system",content:Cn},{role:"user",content:JSON.stringify(a)}]}function We(e,t){let r=String(e??""),n=r.indexOf("{"),i=r.lastIndexOf("}"),o={};if(n>=0&&i>n)try{o=JSON.parse(r.slice(n,i+1))??{}}catch{}let a=[];for(let l of Array.isArray(o.ids)?o.ids:[]){let c=Number.isInteger(l)?t[l]:void 0;c&&!a.includes(c.name)&&a.length<Dt&&a.push(c.name)}let s=(typeof o.question=="string"?o.question:"").replace(/[\u0000-\u001f\u007f]+/g," ").trim().slice(0,300);return{names:a,confidence:o.confidence==="high"&&a.length?"high":"low",question:s}}async function pe(e,t,r,n={}){let i=F(e);n.within&&(i=i.filter(s=>n.within.includes(s.name)));let o=G(i);if(!o.length)return{names:[],confidence:"low",question:""};let a=await r.complete({messages:qe(o,t,ue(e),k(e)),signal:n.signal});return We(a,o)}var _n=32,Pn=32,Ln=80,Bt=2e3,ge=32*1024*1024,Vn=1024,On=256,jn=2048,Ge=["You reconstruct a 3D scene from a reference image into a Three.js script for Three-Live, which compiles it to glTF for Web, Android, and iOS.","Reply with the COMPLETE script in a single ```js code block and nothing else.","Rules:","- Use the pre-defined globals `THREE`, `scene`, and `camera`. No imports, renderer, loaders, DOM, network, or timers.","- Decompose visible objects into `THREE.Group` and `THREE.Mesh` hierarchies with a unique, descriptive `.name` on every Mesh and Group (for example `Table`, `Chair_Left`, `Desk_Lamp`) before attaching `userData.xr` or `userData.interactivity`.","- Use real-world meters (1 unit = 1 m), +Y up, with the floor or resting surface at y = 0 (or the given metric floorY).","- When metric spatial priors (floor height, camera pose, planes, or 3D object boxes) are provided, place meshes at those exact metric [x, y, z] coordinates, dimensions, and yaw angles, and set `mesh.userData.xr = { grab: true }` on movable props.","- Supported: core geometries (`BoxGeometry`, `SphereGeometry`, `CylinderGeometry`, `ConeGeometry`, `CapsuleGeometry`, `PlaneGeometry`, `TorusGeometry`, `LatheGeometry`, `ExtrudeGeometry`, `TubeGeometry`, `Shape`, `Path`), `THREE.CSG`, `MeshStandardMaterial` / `MeshPhysicalMaterial` / `MeshStandardNodeMaterial` (loop-free `THREE.TSL`), `THREE.CanvasTexture`, `THREE.ProceduralTexture` presets (`wood`, `marble`, `brick`, `concrete`, `brushedMetal`, `rust`, `leather`, `fabric`, `carbonFiber`, `checkerboard`, `grid`), lights (`AmbientLight`, `HemisphereLight`, `DirectionalLight`, `PointLight`, `SpotLight`), and canonical `node.userData.xr` traits (`grab`, `anchor`, `physics`, `joint`, `handles`, `dimensions`, `billboard`, `orbit`, `follow`).","- Always include balanced lighting (`AmbientLight` or `HemisphereLight` plus a `DirectionalLight` or `PointLight`) and frame `camera.position.set(x, y, z)` and `camera.lookAt(tx, ty, tz)` so 100% of meshes are inside the camera frustum."].join(`
19
+ `);function Nt(e){if(typeof e!="string")return"";let t="",r=!0;for(let n of e){let i=n.charCodeAt(0);i<=32||i===127||n==='"'||/\s/.test(n)?r||(t+=" ",r=!0):(t+=n,r=!1)}return Array.from(t.trim()).slice(0,Ln).join("")}function V(e){let t=Math.round(e*100)/100;return(Object.is(t,-0)||Math.abs(t)<1e-9?0:t).toFixed(2)}function $t(e){let t=Math.round(e),r=Object.is(t,-0)?0:t;return String(r)}function N(e){if(!Array.isArray(e)||e.length<3)return null;let t=Number(e[0]),r=Number(e[1]),n=Number(e[2]);return!Number.isFinite(t)||!Number.isFinite(r)||!Number.isFinite(n)?null:[t,r,n]}function Un(e){if(!Array.isArray(e)||e.length<2)return null;let t=Number(e[0]),r=Number(e[1]);return!Number.isFinite(t)||!Number.isFinite(r)||t<=0||r<=0?null:[t,r]}function Dn(e){let t=N(e);return!t||t[0]<=0||t[1]<=0||t[2]<=0?null:t}function X(e){return`[${V(e[0])}, ${V(e[1])}, ${V(e[2])}]`}function he(e){if(!e||typeof e!="object")return"";let t=[];if(typeof e.floorY=="number"&&Number.isFinite(e.floorY)&&t.push(`- Floor height: y = ${V(e.floorY)} m`),e.camera&&typeof e.camera=="object"){let r=N(e.camera.eye),n=N(e.camera.target);if(r&&n){let i=`- Camera: eye ${X(r)}, target ${X(n)}`,o=Number(e.camera.fovDeg);Number.isFinite(o)&&o>=1&&o<=179&&(i+=`, fov ${$t(o)} deg`),t.push(i)}}if(Array.isArray(e.planes)){let r=[];for(let n of e.planes){if(r.length>=_n)break;if(!n||typeof n!="object")continue;let i=N(n.center);if(!i)continue;let o=String(n.orientation??"").toLowerCase()==="vertical"?"vertical":"horizontal",a=Nt(n.label),s=Un(n.extent),l=N(n.normal),c=` ${r.length+1}. ${o}`;a&&(c+=` "${a}"`),c+=` at ${X(i)}`,s&&(c+=`, extent ${V(s[0])}m x ${V(s[1])}m`),l&&(c+=`, normal ${X(l)}`),r.push(c)}r.length>0&&t.push("- Planes:",...r)}if(Array.isArray(e.objects)){let r=[];for(let n of e.objects){if(r.length>=Pn)break;if(!n||typeof n!="object")continue;let i=Nt(n.label),o=N(n.center);if(!i||!o)continue;let a=Dn(n.size),s=typeof n.yawDeg=="number"&&Number.isFinite(n.yawDeg)?n.yawDeg:null,l=` ${r.length+1}. "${i}" at ${X(o)}`;a&&(l+=`, size ${V(a[0])}m x ${V(a[1])}m x ${V(a[2])}m`),s!==null&&(l+=`, yaw ${$t(s)} deg`),r.push(l)}r.length>0&&t.push("- Detected 3D objects (place meshes at these metric bounds):",...r)}return t.length===0?"":`Metric spatial priors (world meters, +Y up):
20
+ ${t.join(`
21
+ `)}
22
+ `}function _(e){let t=String(e??"").trim();if(!t)return!1;if(/^data:image\/(png|jpeg|jpg|webp);base64,[A-Za-z0-9+/=\s]+$/i.test(t)){let r=t.indexOf(",");return r>0&&t.slice(r+1).trim().length>0}if(/[\s\x00-\x1f\x7f]/.test(t))return!1;try{let r=new URL(t);return r.protocol==="https:"?!!r.hostname:r.protocol==="http:"&&["localhost","127.0.0.1","[::1]"].includes(r.hostname)}catch{return!1}}function He(e,t){let r=`Reconstruct the 3D scene shown in this reference image as a complete Three-Live script.
23
+ `;r+=he(t);let n=Array.from(String(e??"").trim()).slice(0,Bt).join("");return n&&(r+=`Additional instructions: ${n}
24
+ `),r+="Return only the complete script in a single ```js code block.",r}function Xe(e,t,r){let n=String(e??"").trim();if(!_(n))throw new Error("compileFromImage: imageUrl must be a base64 data:image/(png|jpeg|webp) URI or an https:// URL.");let i=He(t,r);return[{role:"system",content:Ge},{role:"user",content:[{type:"image_url",image_url:{url:n}},{type:"text",text:i}]}]}function Je(e,t){let r=String(e??"").trim(),n=(t??[]).map(i=>String(i??"").trim()).filter(Boolean).slice(0,20);if(r){let i=`That script was rejected by the Three-Live sandbox: ${r}
25
+ `;return n.length>0&&(i+=`Additional diagnostics:
26
+ ${n.map(o=>`- ${o}`).join(`
27
+ `)}
28
+ `),i+="Return the complete corrected script in a single ```js code block.",i}return n.length>0?`The script compiled, but the Three-Live linter reported warnings that should be fixed:
29
+ ${n.map(i=>`- ${i}`).join(`
30
+ `)}
31
+ Fix every warning above (assign unique \`.name\` values before attaching \`userData.xr\`, use only canonical \`userData.xr\` traits, replace unsupported classes with supported Three-Live primitives, and frame \`camera.position\` and \`camera.lookAt\` so all meshes are inside the frustum) while keeping the full scene intact.
32
+ Return the complete corrected script in a single \`\`\`js code block.`:"Return the complete corrected script in a single ```js code block."}function Ye(e){return e.length>=8&&e[0]===137&&e[1]===80&&e[2]===78&&e[3]===71&&e[4]===13&&e[5]===10&&e[6]===26&&e[7]===10?"image/png":e.length>=3&&e[0]===255&&e[1]===216&&e[2]===255?"image/jpeg":e.length>=12&&e[0]===82&&e[1]===73&&e[2]===70&&e[3]===70&&e[8]===87&&e[9]===69&&e[10]===66&&e[11]===80?"image/webp":null}function Fn(e){let t=globalThis;if(t.Buffer&&typeof t.Buffer.from=="function")return t.Buffer.from(e.buffer,e.byteOffset,e.byteLength).toString("base64");let r="",n=8192;for(let i=0;i<e.length;i+=n){let o=e.subarray(i,Math.min(i+n,e.length));r+=String.fromCharCode(...o)}return btoa(r)}function Nn(e){let t=Number(e);return Number.isFinite(t)?Math.max(On,Math.min(jn,Math.round(t))):Vn}function me(e){if(e.byteLength===0)throw new Error("compileFromImage: image buffer is empty.");if(e.byteLength>ge)throw new Error("compileFromImage: image exceeds the 32 MB limit.");let t=Ye(e);if(!t)throw new Error("compileFromImage: unsupported image format (expected PNG, JPEG, or WebP magic bytes).");return`data:${t};base64,${Fn(e)}`}function $n(e,t,r,n){let i=Math.max(t,r),o=i>n?n/i:1,a=Math.max(1,Math.round(t*o)),s=Math.max(1,Math.round(r*o)),l=e;if(o===1&&typeof l.toDataURL=="function")try{let c=l.toDataURL("image/jpeg",.88);if(_(c))return c}catch{}if(typeof document<"u"&&typeof document.createElement=="function")try{let c=document.createElement("canvas");if(c&&typeof c.getContext=="function"){c.width=a,c.height=s;let u=c.getContext("2d");if(u&&typeof u.drawImage=="function"&&(u.drawImage(e,0,0,a,s),typeof c.toDataURL=="function")){let d=c.toDataURL("image/jpeg",.88);if(_(d))return d}}}catch{}if(typeof l.toDataURL=="function")try{let c=l.toDataURL("image/jpeg",.88);if(_(c))return c}catch{}return null}async function fe(e,t={}){if(t.signal?.aborted)throw t.signal.reason??new Error("compileFromImage aborted");if(e==null)throw new Error("compileFromImage: image input is required.");let r=Nn(t.maxEdge);if(typeof e=="string"){let a=e.trim();if(!a)throw new Error("compileFromImage: image input is empty.");if(/^data:/i.test(a)){if(!_(a))throw new Error("compileFromImage: data URI must be a base64-encoded image/png, image/jpeg, or image/webp.");let h=a.indexOf(","),p=a.slice(0,h).toLowerCase().replace("image/jpg","image/jpeg"),y=a.slice(h+1).replace(/\s+/g,"");if(Math.floor(y.length*3/4)>ge)throw new Error("compileFromImage: image exceeds the 32 MB limit.");return`${p},${y}`}if(/^(javascript|vbscript|file|ftp|ws|wss):/i.test(a))throw new Error("compileFromImage: unsupported or unsafe image URL scheme.");if(/^http:/i.test(a)&&!_(a))throw new Error("compileFromImage: remote image URLs must use https:// (or http:// on localhost).");let s=/^https?:/i.test(a)&&_(a);if(s&&!t.fetch)return a;let l=a;if(!/^https?:|^blob:/i.test(a)){let h=globalThis.location?.href;if(!h)throw new Error("compileFromImage: imageUrl must be a base64 data:image/(png|jpeg|webp) URI or an https:// URL.");if(l=new URL(a,h).href,!/^blob:/i.test(l)&&!_(l))throw new Error("compileFromImage: resolved image URL must use https:// (or http:// on localhost).")}let c=t.fetch??globalThis.fetch?.bind(globalThis);if(typeof c!="function"){if(s)return a;throw new Error("compileFromImage: no fetch() implementation is available.")}let u=await c(l,{mode:"cors",credentials:"omit",signal:t.signal});if(!u.ok)throw new Error(`compileFromImage: failed to fetch image (HTTP ${u.status}).`);let d=Number(u.headers?.get?.("content-length"));if(Number.isFinite(d)&&d>ge)throw new Error("compileFromImage: image exceeds the 32 MB limit.");let m=await u.arrayBuffer();if(t.signal?.aborted)throw t.signal.reason??new Error("compileFromImage aborted");return me(new Uint8Array(m))}if(e instanceof ArrayBuffer||Object.prototype.toString.call(e)==="[object ArrayBuffer]")return me(new Uint8Array(e));if(ArrayBuffer.isView(e))return me(new Uint8Array(e.buffer,e.byteOffset,e.byteLength));if(typeof Blob<"u"&&e instanceof Blob||typeof e.arrayBuffer=="function"){let a=e;if(typeof a.size=="number"&&a.size>ge)throw new Error("compileFromImage: image exceeds the 32 MB limit.");let s=await a.arrayBuffer();if(t.signal?.aborted)throw t.signal.reason??new Error("compileFromImage aborted");return me(new Uint8Array(s))}let n=e,i=Number(n.videoWidth||n.naturalWidth||n.width||0),o=Number(n.videoHeight||n.naturalHeight||n.height||0);if(i>0&&o>0){let a=$n(e,i,o,r);if(a)return a}if(typeof n.toDataURL=="function"){let a=n.toDataURL("image/jpeg",.88);if(_(a))return a}if(typeof n.src=="string"&&n.src.trim())return fe(n.src,t);throw new Error("compileFromImage: unsupported or unloaded image source.")}async function ye(e,t,r={}){if(!e?.allowClientScripts)throw new Error("compileFromImage requires client scripts: add the allow-client-scripts attribute.");let n=be(e,r,"compileFromImage"),i=xe(e);e.__tlAiAbort?.abort(new Error("compileFromImage superseded by a newer call"));let o=new AbortController;e.__tlAiAbort=o;let a=()=>o.abort(r.signal?.reason);r.signal?.aborted&&a(),r.signal?.addEventListener("abort",a,{once:!0});let s=o.signal,l=Array.from(String(r.prompt??"").trim()).slice(0,Bt).join(""),c=he(r.priors).length>0,u=Math.max(0,Math.min(3,Math.floor(Number(r.maxRepairs??1))||0)),d="",m="",h=[],p=0,y=null;try{let f=await fe(t,{maxEdge:r.maxEdge,signal:s,fetch:r.fetch});if(s.aborted)throw s.reason;let g=Xe(f,l,r.priors);e.fireEvent?.("three-live-image-start",{prompt:l,hasPriors:c});for(let x=0;x<=u;x++){let w=await n.complete({messages:g,signal:s});if(s.aborted)throw s.reason;if(d=J(w),h=[],!d)m="The model reply did not contain a scene script.";else if(new TextEncoder().encode(d).length>Ke)m="The generated script exceeds the 1 MB script limit.";else try{let b=await et(e,d,s,"compileFromImage");h=[...b.warnings];let E=Qe(b.model);E.unnamedXrNodes>0&&!h.some(A=>A.includes("TL204"))&&h.push("[TL204] Node with userData.xr is missing a unique .name."),E.meshes===0?m="The generated scene contains no meshes.":(m="",y={code:d,warnings:[...h]})}catch(b){if(s.aborted)throw s.reason;let E=b,A=String(E?.message||b);m=E?.name&&E.name!=="Error"&&!A.startsWith(E.name)?`${E.name}: ${A}`:A}if(!m&&h.length===0)break;x<u&&(p++,g.push({role:"assistant",content:w},{role:"user",content:Je(m,h)}))}}finally{r.signal?.removeEventListener("abort",a),e.__tlAiAbort===o&&(e.__tlAiAbort=null)}if(m&&y&&(d=y.code,h=y.warnings,m=""),!m&&!r.dryRun)try{if(await e.executeScript(d),i.trim()){let f=e.__tlAiHistory??(e.__tlAiHistory=[]);f.push(i),f.length>Ze&&f.shift()}e.__tlAiSource=d,T(e,[],{mode:"clear",source:"api"})}catch(f){m=`The generated scene compiled but failed to load: ${f?.message||String(f)}`,e.__tlAiSource=i,i.trim()&&e.executeScript(i).catch(()=>{})}let v={applied:!m,code:d,repairs:p,warnings:h,...m?{error:m}:{}};return e.fireEvent?.("three-live-image",{prompt:l,...v}),v}var tt="three-live-texture-pack",nt=1,zt=64,qt=6*1024*1024,we=16*1024*1024,Bn=64*1024*1024,ot=" Seamless tileable PBR albedo texture, flat even lighting, orthographic top-down view, no perspective, no shadows, no text.";function Ht(){return O()}function Xt(e){let t=Ht().canonicalTextureSpec;if(typeof t!="function")throw new Error("AI textures need the procedural plugin (three-live-procedural.min.js or a full bundle).");return t(e)}function zn(e){try{let t=new URL(e);return t.protocol==="https:"?!0:t.protocol==="http:"&&["localhost","127.0.0.1","[::1]"].includes(t.hostname)}catch{return!1}}function Se(e,t){let r=e.replace(/\s+/g,"");if(r.length>Math.ceil(t*4/3)+4)throw new Error("image exceeds the size limit");let n=atob(r),i=new Uint8Array(n.length);for(let o=0;o<n.length;o++)i[o]=n.charCodeAt(o);return i}function qn(e){let t="";for(let r=0;r<e.length;r+=32768)t+=String.fromCharCode(...e.subarray(r,r+32768));return btoa(t)}async function Wn(e){if(e instanceof Uint8Array)return e;if(e instanceof ArrayBuffer)return new Uint8Array(e);if(e&&typeof e.arrayBuffer=="function")return new Uint8Array(await e.arrayBuffer());throw new Error("image provider returned no image bytes")}function it(e){let t=String(e?.endpoint??"");if(!zn(t))throw new Error("ai-image: endpoint must be an https:// URL (or http:// on localhost).");let r=e.fetch??globalThis.fetch?.bind(globalThis);if(typeof r!="function")throw new Error("ai-image: no fetch() implementation is available.");let n=Math.max(1e3,Number(e.timeoutMs)||12e4),i=new URL(t).origin;return{name:"openai-images",model:e.model,async generateImage({prompt:o,signal:a}){let s=new AbortController,l=()=>s.abort(a?.reason);a?.aborted&&l(),a?.addEventListener("abort",l,{once:!0});let c=setTimeout(()=>s.abort(new Error(`ai-image: timed out after ${n} ms`)),n);try{let u={prompt:o+ot,n:1,size:e.imageSize||"1024x1024"};e.model&&(u.model=e.model),e.responseFormat!==null&&(u.response_format=e.responseFormat??"b64_json");let d=await r(t,{method:"POST",headers:{"Content-Type":"application/json",...e.headers},body:JSON.stringify(u),signal:s.signal}),m=await d.text();if(!d.ok)throw new Error(`ai-image: HTTP ${d.status} from endpoint: ${m.slice(0,300)}`);let h;try{h=JSON.parse(m)}catch{throw new Error("ai-image: endpoint returned non-JSON content.")}let p=h?.data?.[0];if(typeof p?.b64_json=="string")return Se(p.b64_json,we);let y=typeof p?.url=="string"?p.url:"";if(y.startsWith("data:image/"))return Se(y.slice(y.indexOf(",")+1),we);if(y){let v=!1;try{v=new URL(y,t).origin===i}catch{}if(!e.allowResponseUrls||!v)throw new Error('ai-image: the endpoint returned an image URL; use response_format "b64_json" (or allowResponseUrls for same-origin URLs).');let f=await r(new URL(y,t).href,{signal:s.signal});if(!f.ok)throw new Error(`ai-image: HTTP ${f.status} fetching the image.`);let g=new Uint8Array(await f.arrayBuffer());if(g.length>we)throw new Error("ai-image: image exceeds 16 MB.");return g}throw new Error("ai-image: response had no image.")}finally{clearTimeout(c),a?.removeEventListener("abort",l)}}}}function Jt(e){return e.length>=8&&e[0]===137&&e[1]===80&&e[2]===78&&e[3]===71?"png":e.length>=3&&e[0]===255&&e[1]===216&&e[2]===255?"jpeg":e.length>=12&&e[0]===82&&e[1]===73&&e[2]===70&&e[3]===70&&e[8]===87&&e[9]===69&&e[10]===66&&e[11]===80?"webp":null}var Z={async decode(e){let t=Jt(e);if(!t)throw new Error("image must be PNG, JPEG, or WebP");let r=new Blob([e],{type:`image/${t}`}),n=await createImageBitmap(r,{premultiplyAlpha:"none",colorSpaceConversion:"none"}),{width:i,height:o}=n,a=(typeof OffscreenCanvas<"u"?new OffscreenCanvas(i,o):Object.assign(document.createElement("canvas"),{width:i,height:o})).getContext("2d",{willReadFrequently:!0});if(!a)throw new Error("2D canvas unavailable for image decoding");a.drawImage(n,0,0),n.close?.();let s=a.getImageData(0,0,i,o).data;return{width:i,height:o,rgba:new Uint8Array(s.buffer,s.byteOffset,s.byteLength)}},async encodePng(e,t){let r=Ht().encodeRgbaPngDataUri;if(typeof r=="function"){let n=r(e,t,t),i=Se(n.slice(n.indexOf(",")+1),1/0),o=O().makePngDeflater?.(globalThis.CompressionStream);return o?o.png(i):i}throw new Error("PNG encoding needs the procedural plugin")}};function Gn(e,t,r,n,i){let o=new Uint8Array(n*i*4);for(let a=0;a<i;a++){let s=Math.floor(a*r/i),l=Math.min(r,Math.max(s+1,Math.floor((a+1)*r/i)));for(let c=0;c<n;c++){let u=Math.floor(c*t/n),d=Math.min(t,Math.max(u+1,Math.floor((c+1)*t/n))),m=0,h=0,p=0,y=0,v=0;for(let g=s;g<l;g++)for(let x=u;x<d;x++){let w=(g*t+x)*4;m+=e[w],h+=e[w+1],p+=e[w+2],y+=e[w+3],v++}let f=(a*n+c)*4;o[f]=Math.floor((m+v/2)/v),o[f+1]=Math.floor((h+v/2)/v),o[f+2]=Math.floor((p+v/2)/v),o[f+3]=Math.floor((y+v/2)/v)}}return o}function Hn(e,t){let r=Math.max(1,Math.floor(t/8)),n=Math.floor(t/2),i=a=>{let s=Math.max(0,Math.min(1,a));return s*s*(3-2*s)},o=new Uint8Array(t*t*4);for(let a=0;a<t;a++){let s=(Math.min(a,t-1-a)+.5)/r;for(let l=0;l<t;l++){let c=(Math.min(l,t-1-l)+.5)/r,u=1-i(Math.min(c,s)),d=(a*t+l)*4,m=((a+n)%t*t+(l+n)%t)*4;for(let h=0;h<3;h++){let p=e[d+h];o[d+h]=Math.max(0,Math.min(255,Math.floor(p+(e[m+h]-p)*u+.5)))}o[d+3]=255}}return o}function st(e,t){let r=Math.min(e.width,e.height);if(!(r>0))throw new Error("generated image is empty");let n=Math.floor((e.width-r)/2),i=Math.floor((e.height-r)/2),o=new Uint8Array(r*r*4);for(let s=0;s<r;s++){let l=((i+s)*e.width+n)*4;o.set(e.rgba.subarray(l,l+r*4),s*r*4)}let a=r===t?o:Gn(o,r,r,t,t);for(let s=3;s<a.length;s+=4)a[s]=255;return Hn(a,t)}async function at(e,t=Z){let r=typeof e=="string"?JSON.parse(e):e;if(!r||r.format!==tt)throw new Error(`texture pack: format must be "${tt}"`);if(r.version!==nt)throw new Error(`texture pack: version must be ${nt}`);if(!r.entries||typeof r.entries!="object"||Array.isArray(r.entries))throw new Error("texture pack: entries must be an object");let n=Object.keys(r.entries);if(n.length>zt)throw new Error(`texture pack: more than ${zt} entries`);let i=new Map;for(let o of n){let a=r.entries[o];if(!/^[0-9a-f]{16}$/.test(o))throw new Error(`texture pack: invalid key '${o}'`);let s=Xt(a?.spec);if(!s)throw new Error(`texture pack: entry ${o}: invalid spec`);if(s.key!==o)throw new Error(`texture pack: entry ${o}: key does not match its spec (${s.key})`);let l=typeof a?.albedo=="string"?a.albedo:"",c="data:image/png;base64,";if(!l.startsWith(c))throw new Error(`texture pack: entry ${o}: albedo must be a data:image/png;base64 URL`);let u=Se(l.slice(c.length),qt);if(u.length>qt||Jt(u)!=="png")throw new Error(`texture pack: entry ${o}: albedo is not a PNG within 6 MB`);let d=await t.decode(u);if(d.width!==s.size||d.height!==s.size)throw new Error(`texture pack: entry ${o}: albedo is ${d.width}x${d.height}, expected ${s.size}x${s.size}`);let m=new Uint8Array(d.rgba);for(let p=3;p<m.length;p+=4)m[p]=255;let h=a.provenance&&typeof a.provenance=="object"?a.provenance:void 0;i.set(o,{key:o,spec:{prompt:s.prompt,size:s.size,seed:s.seed},rgba:m,...h?{provenance:h}:{}})}return i}async function lt(e,t=Z){let r={};for(let n of[...e.keys()].sort()){let i=e.get(n),o=await t.encodePng(i.rgba,i.spec.size);r[n]={spec:i.spec,albedo:`data:image/png;base64,${qn(o)}`,...i.provenance?{provenance:i.provenance}:{}}}return{format:tt,version:nt,entries:r}}function Xn(e){let t=e?.gltf;if(t)return t;if(e instanceof ArrayBuffer&&e.byteLength>=20){let r=new DataView(e);if(r.getUint32(0,!0)===1179937895)try{return JSON.parse(new TextDecoder().decode(new Uint8Array(e,20,r.getUint32(12,!0))))}catch{}}return null}function ve(e){let t=new Map;for(let r of Xn(e)?.nodes??[]){let n=r?.extras?.xr?.material;if(!n||typeof n!="object"||n.prompt==null)continue;let i=Xt(n);if(!i)continue;let o=t.get(i.key)??{spec:{prompt:i.prompt,size:i.size,seed:i.seed},meshes:[]};typeof r.name=="string"&&r.name&&o.meshes.push(r.name),t.set(i.key,o)}return[...t].map(([r,n])=>({key:r,spec:n.spec,meshes:n.meshes}))}function ct(e=Bn){if(typeof indexedDB>"u")return null;let t=null,r=()=>t??(t=new Promise((i,o)=>{let a=indexedDB.open("three-live-textures",1);a.onupgradeneeded=()=>{a.result.createObjectStore("textures",{keyPath:"key"})},a.onsuccess=()=>i(a.result),a.onerror=()=>o(a.error)})),n=(i,o)=>r().then(a=>new Promise((s,l)=>{let c=a.transaction("textures",i),u=o(c.objectStore("textures"));c.oncomplete=()=>s(u?u.result:void 0),c.onerror=()=>l(c.error)}));return{async get(i){try{let o=await n("readonly",a=>a.get(i));return!o||!(o.rgba instanceof Uint8Array)?null:(n("readwrite",a=>a.put({...o,t:Date.now()})).catch(()=>{}),o)}catch{return null}},async put(i){try{await n("readwrite",l=>l.put({...i,t:Date.now()}));let o=await n("readonly",l=>l.getAll())??[],a=o.reduce((l,c)=>l+(c.rgba?.byteLength??0),0);o.sort((l,c)=>l.t-c.t);let s=[];for(let l of o){if(a<=e)break;a-=l.rgba?.byteLength??0,s.push(l.key)}s.length&&await n("readwrite",l=>{for(let c of s)l.delete(c)})}catch{}}}}var Y=null,Wt=!1;function P(e){return e.__tlTex??(e.__tlTex={pack:new Map,packJson:null,failed:new Set,inflight:new Map,lastModel:null,lastRun:null,cache:void 0,loadSeq:0})}function Jn(e){let t=e.__tlTex;if(!t||t.pack.size===0)return null;let r={};for(let[n,i]of t.pack)r[n]={size:i.spec.size,rgba:i.rgba};return r}function Yn(){let e=O(),t=e.scriptRunner;if(!t||t.__tlTexWrapped)return;let r=n=>Y&&!n?.texturePack?{...n,texturePack:Y}:n;e.scriptRunner={__tlTexWrapped:!0,execute:(n,i,o,a)=>t.execute(n,i,o,r(a)),...typeof t.executeUrl=="function"?{executeUrl:(n,i,o,a)=>t.executeUrl(n,i,o,r(a))}:{}}}function ut(e,t){Yn();let r=Y;Y=Jn(e);try{return t()}finally{Y=r}}function Yt(e,t){let r=t??e.aiImageProvider;if(r&&typeof r.generateImage=="function")return r;let n=e.getAttribute?.("ai-image-endpoint");return n?it({endpoint:n,model:e.getAttribute?.("ai-image-model")||void 0}):null}function Kt(e){if(e.textureCache!==void 0)return e.textureCache;let t=P(e);return t.cache===void 0&&(t.cache=ct()),t.cache}function dt(e){return e.textureCodec??Z}function K(e){let t=e.querySelector?.('script[type="text/three"], script[type="text/three-live"]')?.textContent,r=P(e).lastRun??(t?{kind:"script",value:t}:null);return r?r.kind==="url"&&typeof e.loadScriptFromSrc=="function"?e.loadScriptFromSrc(r.value):e.executeScript(r.value):Promise.resolve()}function Zt(e,t){let r=P(e);r.pack.set(t.key,t),r.packJson=null,r.failed.delete(t.key)}async function Qt(e,t){let r=Kt(e);if(!r)return[];let n=[];for(let i of t){let o=await r.get(i.key);o&&o.spec?.size===i.spec.size&&o.rgba?.length===i.spec.size*i.spec.size*4&&(Zt(e,{key:i.key,spec:i.spec,rgba:o.rgba,provenance:o.provenance}),e.fireEvent?.("three-live-texture",{key:i.key,meshes:i.meshes,source:"cache"}),n.push(i.key))}return n}async function en(e,t,r,n){let i=P(e),o=i.inflight.get(r.key);if(o)return o;let a=(async()=>{try{let s=await Wn(await t.generateImage({...r.spec,signal:n}));if(s.length>we)throw new Error("generated image exceeds 16 MB");let l=st(await dt(e).decode(s),r.spec.size),c={provider:t.name??"custom",...t.model?{model:t.model}:{},createdAt:new Date().toISOString()};return Zt(e,{key:r.key,spec:r.spec,rgba:l,provenance:c}),Kt(e)?.put({key:r.key,spec:r.spec,rgba:l,provenance:c}),e.fireEvent?.("three-live-texture",{key:r.key,meshes:r.meshes,source:"provider"}),!0}catch(s){return i.failed.add(r.key),e.fireEvent?.("three-live-texture-error",{key:r.key,meshes:r.meshes,error:String(s?.message||s)}),!1}finally{i.inflight.delete(r.key)}})();return i.inflight.set(r.key,a),a}async function Kn(e,t,r){let n=0,i=Array.from({length:Math.min(t,e.length)},async()=>{for(;n<e.length;)await r(e[n++])});await Promise.all(i)}function pt(e,t){let r=P(e);r.lastModel=t;let n;try{n=ve(t).filter(o=>!r.pack.has(o.key))}catch{return}let i=n.filter(o=>!r.failed.has(o.key)&&!r.inflight.has(o.key));i.length&&(async()=>{if((await Qt(e,i)).length){await K(e).catch(()=>{});return}if((e.getAttribute?.("ai-textures")||"auto").toLowerCase()==="manual")return;let o=Yt(e);if(!o)return;e.fireEvent?.("three-live-texture-start",{keys:i.map(s=>s.key)});let a=(await Promise.all(i.map(s=>en(e,o,s)))).filter(Boolean).length;a&&(Wt||(Wt=!0,console.info(`[three-live] Generated ${a} AI texture(s) at runtime. Each visitor without a cached copy triggers new (and different) generations. For consistent results, save el.exportTexturePack() and load it via texture-pack.`)),await K(e).catch(()=>{}))})()}function mt(e,t){P(e).lastRun=t}async function rt(e,t){let r=P(e),n=++r.loadSeq;if(t==null){r.pack=new Map,r.packJson=null,await K(e).catch(()=>{});return}try{let i=await at(t,dt(e));if(n!==r.loadSeq)return;r.pack=i,r.packJson=typeof t=="string"?JSON.parse(t):t,r.failed.clear(),await K(e).catch(()=>{})}catch(i){e.fireEvent?.("three-live-texture-error",{key:null,meshes:[],error:String(i?.message||i)})}}async function Gt(e,t){try{let r=typeof document<"u"?document.baseURI:void 0,n=await fetch(new URL(t,r).href,{credentials:"same-origin"});if(!n.ok)throw new Error(`HTTP ${n.status} loading texture-pack "${t}"`);await rt(e,await n.json())}catch(r){e.fireEvent?.("three-live-texture-error",{key:null,meshes:[],error:String(r?.message||r)})}}async function Zn(e,t={}){let r=P(e),n=t.meshes?new Set(t.meshes):null,i=ve(r.lastModel).filter(c=>(t.force||!r.pack.has(c.key))&&(!n||c.meshes.some(u=>n.has(u)))),o=[],a=[],s=[],l=i;if(!t.force){let c=new Set(await Qt(e,i));o.push(...c),l=i.filter(u=>!c.has(u.key))}if(l.length){let c=Yt(e,t.provider);if(!c)throw new Error("generateTextures: no image provider. Set el.aiImageProvider, or the ai-image-endpoint (and ai-image-model) attributes.");e.fireEvent?.("three-live-texture-start",{keys:l.map(m=>m.key)});let u=Math.max(1,Math.min(4,Math.floor(Number(t.concurrency??2))||2)),d=m=>s.push(m);await Kn(l,u,async m=>{r.failed.delete(m.key),t.force&&r.pack.delete(m.key),await en(e,c,m,t.signal)?a.push(m.key):d({key:m.key,error:"generation failed (see three-live-texture-error)"})})}return(o.length||a.length)&&await K(e).catch(()=>{}),{generated:a,cached:o,failed:s,pack:await tn(e)}}async function tn(e){let t=P(e);return t.packJson??(t.packJson=await lt(t.pack,dt(e)))}function nn(e){if(!e||e.__tlTexInstalled)return;e.__tlTexInstalled=!0,P(e),Object.defineProperty(e,"texturePack",{get:()=>e.__tlTex?.packJson??null,set:i=>{rt(e,i)},configurable:!0}),e.generateTextures=i=>Zn(e,i),e.exportTexturePack=()=>tn(e);let t=e.querySelector?.('script[type="application/three-live-texture-pack"]');t?.textContent?.trim()&&rt(e,t.textContent);let r=e.getAttribute?.("texture-pack");r&&Gt(e,r);let n=e;typeof MutationObserver<"u"&&n&&typeof n.nodeType=="number"&&new MutationObserver(()=>{let i=e.getAttribute?.("texture-pack");i&&Gt(e,i)}).observe(n,{attributes:!0,attributeFilter:["texture-pack"]})}var Ae=12;function Ee(e){return String(e).replace(/([a-z])([A-Z])/g,"$1 $2").replace(/([A-Za-z])([0-9])/g,"$1 $2").replace(/[_\-.]+/g," ").trim().slice(0,60)}function Qn(e){if(typeof document>"u")return!1;let t=(e.getAttribute?.("ai-select-chips")??"").toLowerCase();return t!=="off"&&t!=="false"}function Ie(e,t,r,n=!1){let i=document.createElement("button");return i.type="button",i.textContent=e,i.setAttribute("aria-label",t),Object.assign(i.style,{border:"none",borderRadius:"14px",padding:"4px 10px",font:"13px system-ui, sans-serif",cursor:"pointer",background:n?"#1a73e8":"rgba(255,255,255,0.92)",color:n?"#fff":"#202124"}),i.addEventListener("click",o=>{o.stopPropagation(),r()}),i}function $(e){let t=e.__tlChips;t&&(t.off(),t.root.remove(),e.__tlChips=null)}function Te(e,t,r){if(!Qn(e))return null;let n=e.__tlChips;if(!n){let i=document.createElement("div");i.setAttribute("role","status"),i.setAttribute("aria-live","polite"),i.setAttribute("part","selection-chips"),Object.assign(i.style,{position:"absolute",left:"64px",bottom:"12px",maxWidth:"calc(100% - 76px)",boxSizing:"border-box",display:"flex",flexWrap:"wrap",alignItems:"center",gap:"6px",padding:"6px 8px",borderRadius:"18px",background:"rgba(32,33,36,0.85)",boxShadow:"0 1px 4px rgba(0,0,0,0.3)",zIndex:"10",font:"13px system-ui, sans-serif",color:"#fff",pointerEvents:"auto"});let o=()=>{e.__tlChips&&!e.__tlChips.state.question&&ke(e,e.__tlChips.state,r)};e.addEventListener?.("three-live-select",o),e.appendChild?.(i),n={root:i,off:()=>e.removeEventListener?.("three-live-select",o),state:t},e.__tlChips=n}return ke(e,t,r),n.root}function ke(e,t,r){let n=e.__tlChips;if(!n)return;n.state=t;let i=n.root;i.replaceChildren();let o=a=>{let s=document.createElement("span");s.textContent=a,i.appendChild(s)};if(t.question){o(t.question);for(let a of(t.candidates??[]).slice(0,Ae))i.appendChild(Ie(Ee(a),`Select ${Ee(a)}`,()=>{T(e,[a],{mode:t.mode==="add"||t.mode==="remove"?t.mode:"replace",source:"tap",query:t.query}),ke(e,{pending:t.pending},r)}))}else{let a=k(e);if(!a.length&&!t.pending){$(e);return}o(a.length?"Selected:":"Nothing selected");for(let s of a.slice(0,Ae))i.appendChild(Ie(`${Ee(s)} \xD7`,`Remove ${Ee(s)} from the selection`,()=>T(e,[s],{mode:"remove",source:"tap"})));if(a.length>Ae&&o(`+${a.length-Ae} more`),t.pending&&r&&a.length){let s=t.pending;i.appendChild(Ie(`Apply: ${s.slice(0,40)}`,`Apply: ${s.slice(0,200)}`,()=>{ke(e,{},r),r(s)},!0))}}i.appendChild(Ie("\u2715","Dismiss",()=>$(e)))}var er=500,z=2e3,tr=8,nr=[{name:"edit_scene",description:'Change the 3D scene the user is looking at. Call this whenever the user asks to add, remove, move, resize, recolor, or otherwise modify anything. Pass their request as a clear, self-contained instruction. If they selected a mesh, "this" or "it" refers to that mesh; the tool knows which one.',parameters:{type:"object",properties:{instruction:{type:"string",description:'The requested change, e.g. "make the roof red".'}},required:["instruction"]}},{name:"undo_edit",description:"Undo the last scene change.",parameters:{type:"object",properties:{}}},{name:"select_meshes",description:'Select objects in the scene so the user can see what an edit will change. Call this when the user refers to objects by name, color, or position ("the two red chairs on the left"). Pass their words as query, or exact mesh names as names. The result lists the selection, or a question to ask when the reference was unclear.',parameters:{type:"object",properties:{query:{type:"string",description:`The user's words for the objects, e.g. "the lamp next to the sofa".`},names:{type:"array",items:{type:"string"},description:"Exact mesh names, when known."},mode:{type:"string",enum:["replace","add","remove","clear"],description:"replace (default), add, remove, or clear."}}}}],rr=["You are a voice assistant inside a live 3D scene editor.","Keep spoken replies short: one sentence.","To change the scene, call edit_scene with the request; never describe code.","After a tool result, say briefly what changed, or why it could not be done.","When the user refers to objects by name, color, or position, call select_meshes with their words first.","If its result has a question, ask it and wait; otherwise say what is selected, and if they also asked for a change, call edit_scene."].join(" ");function or(e){try{let t=new URL(e);return t.protocol==="wss:"?!0:t.protocol==="ws:"&&["localhost","127.0.0.1","[::1]"].includes(t.hostname)}catch{return!1}}function ir(e){if(!or(e))throw new Error("connectVoice: url must be wss:// (or ws:// on localhost).");let t=new WebSocket(e),r=[],n={send(i){let o=JSON.stringify(i);t.readyState===1?t.send(o):t.readyState===0&&r.length<256&&r.push(o)},close(){r.length=0,t.onopen=t.onmessage=t.onclose=null,t.close(),n.onClose?.()}};return t.onopen=()=>{for(let i of r.splice(0))t.send(i)},t.onmessage=async i=>{let o=n.onMessage;try{let a=typeof i.data=="string"?i.data:await i.data.text(),s=JSON.parse(a);s&&typeof s=="object"&&o?.(s)}catch{}},t.onclose=()=>n.onClose?.(),n}function S(e){return typeof e=="string"?e:""}function R(e){return e&&typeof e=="object"&&!Array.isArray(e)?e:{}}function gt(e,t){let r={...e};for(let[n,i]of Object.entries(t??{})){if(n==="__proto__"||n==="constructor"||n==="prototype")continue;let o=r[n];r[n]=i&&typeof i=="object"&&!Array.isArray(i)&&o&&typeof o=="object"&&!Array.isArray(o)?gt(o,i):i}return r}function rn(e){if(e&&typeof e=="object")return R(e);try{return R(JSON.parse(S(e)||"{}"))}catch{return{}}}var ht={name:"ai-realtime",inputRate:24e3,setup(e){let t={type:"realtime",instructions:e.instructions,audio:{input:{format:{type:"audio/pcm",rate:24e3},turn_detection:{type:"server_vad"}},output:{format:{type:"audio/pcm",rate:24e3},...e.voice?{voice:e.voice}:{}}},tools:e.tools.map(r=>({type:"function",...r})),tool_choice:"auto",...e.model?{model:e.model}:{}};return[{type:"session.update",session:gt(t,e.overrides)}]},audio(e){return{type:"input_audio_buffer.append",audio:e}},text(e,t){let r=[{type:"conversation.item.create",item:{type:"message",role:t?"user":"system",content:[{type:"input_text",text:e}]}}];return t&&r.push({type:"response.create"}),r},toolResult(e,t,r){return[{type:"conversation.item.create",item:{type:"function_call_output",call_id:e,output:JSON.stringify(r)}},{type:"response.create"}]},parse(e){switch(S(e.type)){case"response.output_audio.delta":case"response.audio.delta":return S(e.delta)?[{type:"audio",base64:S(e.delta),rate:24e3}]:[];case"response.output_audio_transcript.delta":case"response.audio_transcript.delta":return[{type:"transcript",speaker:"model",text:S(e.delta),isFinal:!1}];case"response.output_audio_transcript.done":case"response.audio_transcript.done":return[{type:"transcript",speaker:"model",text:S(e.transcript),isFinal:!0}];case"conversation.item.input_audio_transcription.delta":return[{type:"transcript",speaker:"user",text:S(e.delta),isFinal:!1}];case"conversation.item.input_audio_transcription.completed":return[{type:"transcript",speaker:"user",text:S(e.transcript),isFinal:!0}];case"response.function_call_arguments.done":return[{type:"toolCall",id:S(e.call_id)||S(e.item_id),name:S(e.name),args:rn(e.arguments)}];case"input_audio_buffer.speech_started":return[{type:"interrupted"}];case"response.done":return[{type:"turnComplete"}];case"error":return[{type:"error",message:S(R(e.error).message)||"Realtime server error"}];default:return[]}}},ft={name:"gemini-live",inputRate:16e3,setup(e){let t={...e.model?{model:e.model}:{},generationConfig:{responseModalities:["AUDIO"],...e.voice?{speechConfig:{voiceConfig:{prebuiltVoiceConfig:{voiceName:e.voice}}}}:{}},systemInstruction:{parts:[{text:e.instructions}]},tools:[{functionDeclarations:e.tools.map(r=>({...r}))}],inputAudioTranscription:{},outputAudioTranscription:{}};return[{setup:gt(t,e.overrides)}]},audio(e){return{realtimeInput:{audio:{mimeType:"audio/pcm;rate=16000",data:e}}}},text(e,t){return[{clientContent:{turns:[{role:"user",parts:[{text:e}]}],turnComplete:t}}]},toolResult(e,t,r){return[{toolResponse:{functionResponses:[{id:e,name:t,response:r}]}}]},parse(e){let t=[],r=R(e.serverContent);r.interrupted&&t.push({type:"interrupted"});let n=R(r.inputTranscription);S(n.text)&&t.push({type:"transcript",speaker:"user",text:S(n.text),isFinal:!1});let i=R(r.outputTranscription);S(i.text)&&t.push({type:"transcript",speaker:"model",text:S(i.text),isFinal:!1});let o=R(r.modelTurn).parts;for(let l of Array.isArray(o)?o:[]){let c=R(R(l).inlineData),u=S(c.mimeType);if(u.startsWith("audio/pcm")&&S(c.data)){let d=Number(/rate=(\d+)/.exec(u)?.[1])||24e3;t.push({type:"audio",base64:S(c.data),rate:d})}}r.turnComplete&&t.push({type:"turnComplete"});let a=R(e.toolCall).functionCalls;for(let l of Array.isArray(a)?a:[]){let c=R(l);t.push({type:"toolCall",id:S(c.id),name:S(c.name),args:rn(c.args)})}let s=R(e.error);return S(s.message)&&t.push({type:"error",message:S(s.message)}),t}},sr={"ai-realtime":ht,"gemini-live":ft};function ar(e){let t=new Uint8Array(e.buffer,e.byteOffset,e.byteLength),r="";for(let n=0;n<t.length;n+=32768)r+=String.fromCharCode(...t.subarray(n,n+32768));return btoa(r)}function lr(e,t,r){let n=t/r,i=Math.max(0,Math.floor(e.length/n)),o=new Int16Array(i);for(let a=0;a<i;a++){let s=a*n,l=Math.floor(s),c=Math.min(l+1,e.length-1),u=e[l]+(e[c]-e[l])*(s-l),d=Math.max(-1,Math.min(1,u));o[a]=d<0?d*32768:d*32767}return o}function cr(e){let t=atob(e),r=t.length>>1,n=new Float32Array(r);for(let i=0;i<r;i++){let o=t.charCodeAt(i*2)|t.charCodeAt(i*2+1)<<8;o&32768&&(o-=65536),n[i]=o/32768}return n}function on(){let e=globalThis;return e.AudioContext??e.webkitAudioContext}function ur(){let e=null,t=null,r=null;return{async start(n,i){let o=on(),a=globalThis.navigator?.mediaDevices;if(!o||!a?.getUserMedia)throw new Error("connectVoice: microphone capture is not available here.");e=await a.getUserMedia({audio:{echoCancellation:!0,noiseSuppression:!0,channelCount:1}}),t=new o;let s=t.createMediaStreamSource(e);r=t.createScriptProcessor(4096,1,1);let l=t.sampleRate;r.onaudioprocess=c=>{let u=lr(c.inputBuffer.getChannelData(0),l,n);u.length&&i(ar(u))},s.connect(r),r.connect(t.destination)},stop(){r&&(r.onaudioprocess=null),r?.disconnect();for(let n of e?.getTracks()??[])n.stop();t?.close(),r=null,e=null,t=null}}}function dr(){let e=null,t=0,r=new Set,n={play(i,o){let a=on();if(!e&&a)try{e=new a}catch{return}if(!e)return;e.state==="suspended"&&e.resume?.();let s=cr(i);if(!s.length)return;let l=e.createBuffer(1,s.length,o);l.getChannelData(0).set(s);let c=e.createBufferSource();c.buffer=l,c.connect(e.destination);let u=Math.max(e.currentTime,t);c.start(u),t=u+l.duration,r.add(c),c.onended=()=>r.delete(c)},flush(){for(let i of r)try{i.stop()}catch{}r.clear(),t=0},close(){n.flush(),e?.close(),e=null}};return n}function I(e,t){e.fireEvent?.("three-live-voice",t)}var Q=class{constructor(e,t){this.el=e,this.options=t,this.state="connecting",this.userText="",this.modelText="",this.onSelect=i=>{let o=i.detail;if(o?.source==="voice")return;let a=Array.isArray(o?.meshes)?o.meshes:o?.mesh?[o.mesh]:[];this.sendContext(H(a))};let r=t.provider??"ai-realtime",n=sr[r];if(!n)throw new Error(`connectVoice: unknown provider '${r}' (use ai-realtime or gemini-live).`);if(this.adapter=n,t.transport)this.transport=t.transport;else if(t.url)this.transport=ir(t.url);else throw new Error("connectVoice: pass a wss:// url or a transport.");this.mic=t.microphone===!1?null:t.microphoneSource??ur(),this.sink=t.playAudio===!1?null:t.audioSink??dr()}async start(){this.transport.onMessage=r=>this.handle(r),this.transport.onClose=()=>this.shutdown();let e=[rr,this.options.instructions].filter(Boolean).join(`
33
+ `);for(let r of this.adapter.setup({instructions:e,tools:nr,model:this.options.model,voice:this.options.voice,overrides:this.options.session}))this.transport.send(r);this.sink?.play("",24e3),this.el.addEventListener?.("three-live-select",this.onSelect);let t=k(this.el);t.length&&this.sendContext(H(t));try{await this.mic?.start(this.adapter.inputRate,r=>{this.state!=="closed"&&this.transport.send(this.adapter.audio(r))})}catch(r){throw this.setState("error",{error:r?.message||String(r)}),this.close(),r}return this.setState("listening"),this}sendText(e){let t=String(e??"").trim().slice(0,z);if(!(!t||this.state==="closed"))for(let r of this.adapter.text(t,!0))this.transport.send(r)}close(){this.state!=="closed"&&(this.transport.onClose=void 0,this.transport.close(),this.shutdown())}shutdown(){this.state!=="closed"&&(this.mic?.stop(),this.sink?.close(),this.el.removeEventListener?.("three-live-select",this.onSelect),this.el.__tlVoiceSession===this&&(this.el.__tlVoiceSession=null),this.setState("closed"))}sendContext(e){if(this.state!=="closed")for(let t of this.adapter.text(e,!1))this.transport.send(t)}setState(e,t={}){this.state=e,I(this.el,{state:e,...t})}handle(e){if(this.state==="closed")return;let t=0;for(let r of this.adapter.parse(e))switch(r.type){case"audio":this.state!=="editing"&&(this.state="speaking"),this.sink?.play(r.base64,r.rate);break;case"interrupted":this.sink?.flush();break;case"transcript":r.speaker==="user"?(this.userText=(r.isFinal?r.text:this.userText+r.text).slice(-z),I(this.el,{state:this.state,transcript:this.userText,isFinal:r.isFinal}),r.isFinal&&(this.userText="")):(this.modelText=(r.isFinal?r.text:this.modelText+r.text).slice(-z),I(this.el,{state:this.state,reply:this.modelText,isFinal:r.isFinal}),r.isFinal&&(this.modelText=""));break;case"turnComplete":this.userText&&(I(this.el,{state:this.state,transcript:this.userText,isFinal:!0}),this.userText=""),this.modelText&&(I(this.el,{state:this.state,reply:this.modelText,isFinal:!0}),this.modelText=""),(this.state==="speaking"||this.state==="thinking")&&this.setState("listening");break;case"toolCall":++t<=tr&&this.runTool(r.id,r.name,r.args);break;case"error":I(this.el,{state:this.state,error:r.message});break}}async runTool(e,t,r){let n;try{if(t==="edit_scene"){let i=S(r.instruction).trim().slice(0,z);if(!i)throw new Error("instruction is empty");if(typeof this.el.editScene!="function")throw new Error("scene editing is not available on this element");this.setState("editing",{transcript:i});let o=await this.el.editScene(i,{provider:this.options.editProvider});n=o.applied?{applied:!0,repairs:o.repairs}:{applied:!1,error:o.error??"edit rejected"},this.setState("thinking",{result:o})}else if(t==="select_meshes"){let i=S(r.mode),o=["replace","add","remove","clear"].includes(i)?i:"replace",a=Array.isArray(r.names)?r.names.filter(l=>typeof l=="string"):[],s=a.length&&o!=="clear"?bt(this.el,a,o):await W(this.el,S(r.query),{mode:o,provider:this.options.editProvider??this.el.__tlSelectProvider?.()??null});n={changed:s.applied,selected:s.meshes.slice(0,50),say:s.say,...s.applied?{}:{question:s.say,candidates:s.match?.candidates??[]}}}else t==="undo_edit"?n=await this.el.undoEdit?.()??!1?{undone:!0}:{undone:!1,error:"nothing to undo"}:n={error:`unknown tool ${t}`}}catch(i){n={applied:!1,error:i?.message||String(i)},this.state==="editing"&&this.setState("thinking")}if(this.state!=="closed")for(let i of this.adapter.toolResult(e,t,n))this.transport.send(i)}};async function ee(e,t){if(!t?.editProvider&&!e.aiProvider&&!e.getAttribute?.("ai-endpoint"))throw new Error("connectVoice: edits need a code model. Set el.aiProvider, the ai-endpoint attribute, or options.editProvider.");e.__tlVoiceSession?.close();let r=new Q(e,t??{});return e.__tlVoiceSession=r,I(e,{state:"connecting"}),r.start()}function yt(){let e=globalThis,t=e.SpeechRecognition??e.webkitSpeechRecognition;return t?{listen({lang:r,signal:n,onPartial:i}){return new Promise((o,a)=>{let s=new t;s.lang=r||globalThis.document?.documentElement?.lang||"en-US",s.interimResults=!0,s.continuous=!1,s.maxAlternatives=1;let l="",c="",u=!1,d=h=>{u||(u=!0,n?.removeEventListener("abort",m),h())},m=()=>{try{s.abort()}catch{}d(()=>a(n?.reason??new Error("voice edit aborted")))};if(s.onresult=h=>{let p="";for(let y=h.resultIndex;y<h.results.length;y++){let v=h.results[y];v.isFinal?l+=v[0].transcript:p+=v[0].transcript}c=(l+p).trim(),i?.(c)},s.onerror=h=>{h?.error==="no-speech"||h?.error==="aborted"||d(()=>a(new Error(`Speech recognition failed: ${h?.error||"unknown error"}`)))},s.onend=()=>d(()=>o((l||c).trim())),n?.aborted)return m();n?.addEventListener("abort",m,{once:!0});try{s.start()}catch(h){d(()=>a(h))}})}}:null}function Me(e,t){let r=globalThis;if(!(!r.speechSynthesis||!r.SpeechSynthesisUtterance))try{r.speechSynthesis.cancel();let n=new r.SpeechSynthesisUtterance(e);t&&(n.lang=t),r.speechSynthesis.speak(n)}catch{}}function Re(e){return String(e).replace(/([a-z])([A-Z])/g,"$1 $2").replace(/([A-Za-z])([0-9])/g,"$1 $2").replace(/[_\-.]+/g," ").replace(/\s+/g," ").trim()}function B(e,t="and"){let r=e.slice(0,5).map(Re),n=e.length-r.length;return n>0?`${r.join(", ")} ${t} ${n} more`:r.length<2?r.join(""):`${r.slice(0,-1).join(", ")} ${t} ${r[r.length-1]}`}function q(e,t,r,n){if(e==="clear")return"Selection cleared.";if(!t)return"Which object?";if(t.confidence==="high")return e==="remove"?r.length?`Removed ${B(t.names)}. ${r.length} selected.`:`Removed ${B(t.names)}. Nothing is selected.`:e==="add"?`Added ${B(t.names)}. ${r.length} selected.`:t.names.length===1?`Selected ${Re(t.names[0])}.`:`Selected ${t.names.length}: ${B(t.names)}.`;if(t.confidence==="ambiguous")return t.reason==="count_mismatch"?`I found ${t.candidates.length}: ${B(t.candidates)}. Which ones?`:`Which one: ${B(t.candidates,"or")}?`;let i=String(n).replace(/\s+/g," ").trim().slice(0,80);return t.reason==="relation"?`I can't tell which one "${i}" is yet. Try its name or color, or tap it.`:t.reason==="empty"?"Which object?":`I couldn't find "${i}".`}async function W(e,t,r={}){let n=r.mode??"replace",i=String(t??"").slice(0,z);if(n==="clear")return T(e,[],{mode:"clear",source:"voice",query:i||"clear"}),{mode:n,query:i,match:null,applied:!0,tier:1,meshes:[],say:q(n,null,[],i)};let o=n==="remove"?k(e):null;if(o&&!o.length)return{mode:n,query:i,match:null,applied:!1,tier:1,meshes:[],say:"Nothing is selected."};let a=de(e,i,{within:o}),s=1,l="",c=r.provider===void 0?e.__tlSelectProvider?.()??null:r.provider;if(c&&i.trim()&&a.confidence==="none"&&(a.reason==="relation"||a.reason==="no_match"))try{let h=await pe(e,i,c,{within:o,signal:r.signal});s=2,l=h.question,a=h.confidence==="high"?{ids:[],names:h.names,confidence:"high",candidates:[],reason:"model"}:{ids:[],names:[],confidence:h.names.length?"ambiguous":"none",candidates:h.names.slice(0,10),reason:"model"}}catch(h){if(r.signal?.aborted)throw h}let u=!1;a.confidence==="high"&&a.names.length&&(T(e,a.names,{mode:n,source:"voice",query:i}),u=!0);let d=k(e),m=!u&&l?l:q(n,a,d,i);return{mode:n,query:i,match:a,applied:u,tier:s,meshes:d,say:m}}function bt(e,t,r="replace"){let n=new Set(F(e).map(l=>l.name)),i=t.filter(l=>typeof l=="string"&&n.has(l)).slice(0,50),o=t.filter(l=>typeof l=="string").join(", ").slice(0,200);if(!i.length){let l={ids:[],names:[],confidence:"none",candidates:[],reason:"no_match"},c=k(e);return{mode:r,query:o,match:l,applied:!1,tier:1,meshes:c,say:q(r,l,c,o)}}T(e,i,{mode:r,source:"voice",query:o});let a={ids:[],names:i,confidence:"high",candidates:[],reason:"exact"},s=k(e);return{mode:r,query:o,match:a,applied:!0,tier:1,meshes:s,say:q(r,a,s,o)}}function Ce(e){return e.applied?"Done.":`Sorry, I couldn't apply that: ${String(e.error??"the edit was rejected").replace(/\s+/g," ").slice(0,160)}`}async function pr(e,t,r){if(typeof e.editScene!="function")return;I(e,{state:"editing",transcript:t,isFinal:!0});let n;try{n=await e.editScene(t)}catch(i){n={applied:!1,code:"",repairs:0,warnings:[],error:i?.message||String(i)}}I(e,{state:"idle",transcript:t,isFinal:!0,result:n}),r.speak!==!1&&Me(Ce(n),r.lang)}async function te(e,t={}){if(typeof e.editScene!="function")throw new Error("startVoiceEdit needs three-live-ai.min.js (el.editScene).");let r=t.recognizer??yt();if(!r)throw new Error("startVoiceEdit: this browser has no speech recognition; use el.connectVoice() (ai-realtime or gemini-live) instead.");I(e,{state:"listening"});let n="";try{n=(await r.listen({lang:t.lang,signal:t.signal,onPartial:l=>I(e,{state:"listening",transcript:l,isFinal:!1})})).trim().slice(0,z)}catch(l){throw I(e,{state:"error",error:l?.message||String(l)}),l}if(!n){let l="I didn't catch that.";throw I(e,{state:"idle",transcript:n,isFinal:!0,error:l}),t.speak!==!1&&Me(l,t.lang),new Error(`startVoiceEdit: ${l}`)}let i=n,o,a=t.talkToSelect===!1?null:ce(n);if(a&&a.kind!=="edit"){I(e,{state:"thinking",transcript:n,isFinal:!0});try{o=await W(e,a.kind==="clear"?"":a.query,{mode:a.mode,signal:t.signal})}catch(d){throw I(e,{state:"error",error:d?.message||String(d)}),d}let l=a.kind==="mixed"?a.instruction:void 0,c=l!==void 0&&o.applied&&o.tier===1,u=t.chips!==!1&&!e.__tlVoiceSession;if(u){let d=o;Te(e,d.applied||d.mode==="clear"?{pending:c?void 0:l}:d.match?.candidates.length?{question:d.say,candidates:d.match.candidates,mode:d.mode,query:d.query,pending:l}:{},m=>pr(e,m,t))}if(!c){if(I(e,{state:"idle",transcript:n,isFinal:!0,selection:o}),t.speak!==!1){let d=l!==void 0&&o.applied?u&&e.__tlChips?" Tap Apply to make the change.":" Say the change again to apply it.":"";Me(o.say+d,t.lang)}return{transcript:n,result:null,selection:o}}i=l}else t.chips!==!1&&e.__tlChips&&$(e);I(e,{state:"editing",transcript:n,isFinal:!0,...o?{selection:o}:{}});let s;try{s=await e.editScene(i,{signal:t.signal})}catch(l){s={applied:!1,code:"",repairs:0,warnings:[],error:l?.message||String(l)}}if(I(e,{state:"idle",transcript:n,isFinal:!0,result:s,...o?{selection:o}:{}}),t.speak!==!1){let l=Ce(s);Me(o?`${o.say} ${l}`:l,t.lang)}return{transcript:n,result:s,...o?{selection:o}:{}}}function ne(e,t){if(!t){e.__tlTapHandler&&e.removeEventListener?.("meshclick",e.__tlTapHandler),e.__tlTapDown&&e.removeEventListener?.("pointerdown",e.__tlTapDown),e.__tlTapHandler=null,e.__tlTapDown=null;return}if(e.__tlTapHandler)return;let r=!1,n=0,i=o=>{let a=o;r=!!(a.shiftKey||a.ctrlKey||a.metaKey),n=Date.now()};e.__tlTapDown=i,e.addEventListener?.("pointerdown",i),e.__tlTapHandler=o=>{let a=o.detail?.meshName;if(typeof a!="string"||!a)return;let s=n>0&&Date.now()-n>=er,l=k(e);r||s?T(e,[a],{mode:"toggle",source:"tap"}):l.length===1&&l[0]===a?T(e,[],{mode:"clear",source:"tap"}):T(e,[a],{mode:"replace",source:"tap"}),r=!1,n=0},e.addEventListener?.("meshclick",e.__tlTapHandler)}var mr='<svg viewBox="0 0 24 24" width="22" height="22" aria-hidden="true" fill="currentColor"><path d="M12 14a3 3 0 0 0 3-3V5a3 3 0 0 0-6 0v6a3 3 0 0 0 3 3zm5-3a5 5 0 0 1-10 0H5a7 7 0 0 0 6 6.92V21h2v-3.08A7 7 0 0 0 19 11h-2z"/></svg>';function sn(e){if(e.__tlVoiceButton||typeof document>"u")return;let t=e.querySelector?.('[slot="voice-button"]'),r=t??document.createElement("button");t||(r.setAttribute("type","button"),r.setAttribute("aria-label","Edit the scene by voice"),r.innerHTML=mr,Object.assign(r.style,{position:"absolute",left:"12px",bottom:"12px",width:"44px",height:"44px",borderRadius:"22px",border:"none",background:"rgba(32,33,36,0.85)",color:"#fff",display:"flex",alignItems:"center",justifyContent:"center",cursor:"pointer",zIndex:"10",boxShadow:"0 1px 4px rgba(0,0,0,0.3)"}),e.appendChild?.(r)),e.__tlVoiceButton=r;let n=null,i=o=>{r.setAttribute("aria-pressed",o?"true":"false"),t||(r.style.background=o?"rgba(217,48,37,0.9)":"rgba(32,33,36,0.85)")};r.addEventListener("click",o=>{o.stopPropagation();let a=e.getAttribute?.("ai-voice-url");if(a){if(e.__tlVoiceSession){e.__tlVoiceSession.close(),i(!1);return}i(!0);let s=e.getAttribute?.("ai-voice-provider")||"ai-realtime";ee(e,{provider:s,url:a,model:e.getAttribute?.("ai-voice-model")||void 0}).then(l=>{e.addEventListener?.("three-live-voice",function c(u){u.detail?.state==="closed"&&(e.removeEventListener?.("three-live-voice",c),e.__tlVoiceSession!==l&&i(!1))})}).catch(()=>i(!1));return}if(n){n.abort(new Error("voice edit cancelled"));return}n=new AbortController,i(!0),te(e,{signal:n.signal}).catch(()=>{}).finally(()=>{n=null,i(!1)})})}var Ke=1048576,Ze=20,an=15e3,gr=["You edit Three.js scene scripts for Three-Live, which compiles them to glTF for Web, Android, and iOS.","Reply with the COMPLETE updated script in a single ```js code block and nothing else.","Rules:","- Use the pre-defined globals `THREE`, `scene`, and `camera`. No imports, renderer, loaders, DOM, network, or timers.","- Change only what the instruction asks; keep every other object, name, and value as it is.","- Give new meshes and groups descriptive `.name` values; keep existing names stable.","- Keep objects resting on y = 0 and within view of the camera.","- Supported: core geometries and materials (MeshStandardMaterial / MeshPhysicalMaterial with PBR maps, and MeshStandardNodeMaterial with loop-free THREE.TSL colorNode / emissiveNode / roughnessNode / metalnessNode / opacityNode / bumpNode / positionNode), lights, Group, InstancedMesh, THREE.CSG, THREE.CanvasTexture, THREE.ProceduralTexture presets (wood, marble, brick, concrete, brushedMetal, rust, leather, fabric, carbonFiber, checkerboard, grid), and declarative mesh.userData.xr traits. Optional per-frame motion: function animate(t) { ... }.","- Keep every userData.xr.material preset; add a prompt (AI texture) only when the instruction asks for a specific surface."].join(`
34
+ `);function hr(e){try{let t=new URL(e);return t.protocol==="https:"?!0:t.protocol==="http:"&&["localhost","127.0.0.1","[::1]"].includes(t.hostname)}catch{return!1}}function xt(e){let t=String(e?.endpoint??"");if(!hr(t))throw new Error("ai-chat: endpoint must be an https:// URL (or http:// on localhost).");let r=e.fetch??globalThis.fetch?.bind(globalThis);if(typeof r!="function")throw new Error("ai-chat: no fetch() implementation is available.");let n=Number.isFinite(e.temperature)?Number(e.temperature):.2,i=Math.max(1e3,Number(e.timeoutMs)||12e4);return{async complete({messages:o,signal:a}){let s=new AbortController,l=()=>s.abort(a?.reason);a?.aborted&&l(),a?.addEventListener("abort",l,{once:!0});let c=setTimeout(()=>s.abort(new Error(`ai-chat: timed out after ${i} ms`)),i);try{let u={messages:o,temperature:n,stream:!1};e.model&&(u.model=e.model);let d=await r(t,{method:"POST",headers:{"Content-Type":"application/json",...e.headers},body:JSON.stringify(u),signal:s.signal}),m=await d.text();if(!d.ok)throw new Error(`ai-chat: HTTP ${d.status} from endpoint: ${m.slice(0,300)}`);let h;try{h=JSON.parse(m)}catch{throw new Error("ai-chat: endpoint returned non-JSON content.")}let p=h?.choices?.[0]?.message?.content,y=Array.isArray(p)?p.map(v=>typeof v=="string"?v:String(v?.text??"")).join(""):p;if(typeof y!="string"||!y.trim())throw new Error("ai-chat: response had no message content.");return y}finally{clearTimeout(c),a?.removeEventListener("abort",l)}}}}function J(e){let t=String(e??""),r=/```[ \t]*([A-Za-z0-9_+-]*)[^\n]*\n([\s\S]*?)```/g,n,i="";for(;n=r.exec(t);){let a=n[1].toLowerCase();if(i||(i=n[2]),["js","javascript","ts","typescript","mjs"].includes(a))return n[2].trim()}if(i)return i.trim();let o=/```[^\n]*\n([\s\S]*)$/.exec(t);return o?o[1].trim():/\bscene\b/.test(t)?t.trim():""}function Qe(e){let t=new Set,r=e?.gltf;if(!r&&e instanceof ArrayBuffer&&e.byteLength>=20){let o=new DataView(e);if(o.getUint32(0,!0)===1179937895){let a=o.getUint32(12,!0);try{r=JSON.parse(new TextDecoder().decode(new Uint8Array(e,20,a)))}catch{}}}let n=0,i=0;for(let o of r?.nodes??[]){let a=typeof o?.name=="string"?o.name.trim():"",s=/^Node_\d+$/.test(a),l=a.length>0&&!s;l&&t.add(a),o?.mesh!==void 0&&n++,!l&&(o?.extras?.xr!=null||o?.extras?.interactivity!=null)&&i++}return{meshNames:t,meshes:n,unnamedXrNodes:i}}function et(e,t,r,n="editScene"){let i=O().scriptRunner;if(!i||typeof i.execute!="function")return Promise.reject(new Error(`${n} needs a script runner (load three-live.min.js or three-live-full.min.js).`));let o=[];return new Promise((a,s)=>{let l,c=!1,u=h=>{if(!c){c=!0,clearTimeout(m),r?.removeEventListener("abort",d);try{l?.terminate?.()}catch{}h()}},d=()=>u(()=>s(r?.reason??new Error("editScene aborted"))),m=setTimeout(()=>u(()=>s(new Error(`Scene did not finish compiling within ${an} ms.`))),an);if(r?.aborted)return d();r?.addEventListener("abort",d,{once:!0}),Promise.resolve(i.execute(t,e.sandbox??"worker",{onModelReady:h=>u(()=>a({model:h,warnings:o})),onError:h=>u(()=>s(h instanceof Error?h:new Error(String(h)))),onToast:h=>{o.length<20&&o.push(String(h))}},{allowClientScripts:!0})).then(h=>{if(l=h,c)try{h?.terminate?.()}catch{}},h=>u(()=>s(h instanceof Error?h:new Error(String(h)))))})}var fr=50;function yr(e){let t=typeof e=="string"?[e]:Array.isArray(e)?e:[],r=[];for(let n of t){let i=typeof n=="string"?n.slice(0,200):"";if(i&&!r.includes(i)&&r.push(i),r.length>=fr)break}return r}function br(e){return e.length===0?"":e.length===1?`The user selected the mesh named "${e[0]}"; the instruction refers to it.
35
+ `:`The user selected the meshes named ${e.map(t=>`"${t}"`).join(", ")}; the instruction refers to them.
36
+ `}function be(e,t,r="editScene"){let n=t.provider??e.aiProvider;if(n&&typeof n.complete=="function")return n;let i=e.getAttribute?.("ai-endpoint");if(!i)throw new Error(`${r}: no AI provider. Set el.aiProvider, or the ai-endpoint (and ai-model) attributes.`);let o=(e.getAttribute?.("ai-provider")||"ai-chat").toLowerCase();if(o!=="ai-chat")throw new Error(`${r}: unknown ai-provider '${o}' (supported: ai-chat, or set el.aiProvider).`);return xt({endpoint:i,model:e.getAttribute?.("ai-model")||void 0})}function xe(e){return typeof e.__tlAiSource=="string"?e.__tlAiSource:e.querySelector?.('script[type="text/three"], script[type="text/three-live"]')?.textContent??""}async function wt(e,t,r={}){let n=String(t??"").trim();if(!n)throw new Error("editScene: instruction is empty.");if(!e?.allowClientScripts)throw new Error("editScene requires client scripts: add the allow-client-scripts attribute.");let i=r.source??xe(e);if(!i.trim())throw new Error('editScene needs a Three.js scene script (inline <script type="text/three"> or a prior editScene/executeScript).');let o=be(e,r);e.__tlAiAbort?.abort(new Error("editScene superseded by a newer call"));let a=new AbortController;e.__tlAiAbort=a;let s=()=>a.abort(r.signal?.reason);r.signal?.aborted&&s(),r.signal?.addEventListener("abort",s,{once:!0});let l=a.signal,c=yr(r.selection===void 0?e.selectedMeshes??e.selectedMesh:r.selection),u=c.length>1?c:c[0]??null,d=Math.max(0,Math.min(3,Math.floor(Number(r.maxRepairs??1))||0)),m=[{role:"system",content:gr},{role:"user",content:`Current scene script:
37
+ \`\`\`js
38
+ ${i}
39
+ \`\`\`
40
+ `+br(c)+`Instruction: ${n}`}];e.fireEvent?.("three-live-edit-start",{instruction:n,selection:u});let h="",p="",y=[],v=0;try{for(let g=0;g<=d;g++){let x=await o.complete({messages:m,signal:l});if(l.aborted)throw l.reason;if(h=J(x),!h)p="The model reply did not contain a scene script.";else if(new TextEncoder().encode(h).length>Ke)p="The generated script exceeds the 1 MB script limit.";else try{let w=await et(e,h,l);y=w.warnings;let b=Qe(w.model);if(b.meshes===0)p="The edited scene contains no meshes.";else if(c.some(E=>!b.meshNames.has(E))&&!/\b(remove|delete|rename)\b/i.test(n)){let E=c.filter(A=>!b.meshNames.has(A));p=E.length===1?`The edited scene no longer contains the selected mesh "${E[0]}".`:`The edited scene no longer contains the selected meshes ${E.map(A=>`"${A}"`).join(", ")}.`}else p=""}catch(w){if(l.aborted)throw l.reason;let b=w,E=String(b?.message||w);p=b?.name&&b.name!=="Error"&&!E.startsWith(b.name)?`${b.name}: ${E}`:E}if(!p)break;g<d&&(v++,m.push({role:"assistant",content:x},{role:"user",content:`That script was rejected by the Three-Live sandbox: ${p}
41
+ Return the complete corrected script in a single \`\`\`js code block.`}))}}finally{r.signal?.removeEventListener("abort",s),e.__tlAiAbort===a&&(e.__tlAiAbort=null)}if(!p&&!r.dryRun)try{await e.executeScript(h);let g=e.__tlAiHistory??(e.__tlAiHistory=[]);g.push(i),g.length>Ze&&g.shift(),e.__tlAiSource=h}catch(g){p=`The edit compiled but failed to load: ${g?.message||String(g)}`,e.__tlAiSource=i,e.executeScript(i).catch(()=>{})}let f={applied:!p,code:h,repairs:v,warnings:y,...p?{error:p}:{}};return e.fireEvent?.("three-live-edit",{instruction:n,...f}),f}async function St(e){let t=e?.__tlAiHistory?.pop();return typeof t!="string"?!1:(e.__tlAiSource=t,await e.executeScript(t),!0)}var _e={name:"ai",onRegister(){typeof document>"u"||document.querySelectorAll?.("three-live, xr-live").forEach(e=>_e.onElementConnected?.(e))},onElementConnected(e){let t=e;if(!t||t.__tlAiInstalled)return;t.__tlAiInstalled=!0,t.editScene=(a,s)=>wt(t,a,s),t.compileFromImage=(a,s)=>ye(t,a,s),t.undoEdit=()=>St(t),Ft(t);let r=t;t.startVoiceEdit=a=>te(r,a),r.__tlSelectProvider=()=>{try{return be(t,{})}catch{return null}},t.selectByVoice=(a,s)=>W(r,a,s),t.connectVoice=a=>ee(r,a),t.setSelectOnTap=a=>ne(r,a),t.hasAttribute?.("ai-select-on-tap")&&ne(r,!0),t.hasAttribute?.("ai-voice-button")&&sn(r),"sceneSource"in t||Object.defineProperty(t,"sceneSource",{get:()=>xe(t),configurable:!0});let n=t;nn(n);let i=t.executeScript;typeof i=="function"&&(t.executeScript=a=>(mt(n,{kind:"script",value:String(a)}),ut(n,()=>i.call(t,a)).then(s=>(t.__tlAiSource=String(a),pt(n,s),s))));let o=n.loadScriptFromSrc;typeof o=="function"&&(n.loadScriptFromSrc=a=>(mt(n,{kind:"url",value:String(a)}),ut(n,()=>o.call(t,a)).then(s=>(pt(n,s),s))))}};vt(_e);