@omrips/viewstl 2.0.0-rc.6 → 2.0.0-rc.7

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.
@@ -1,7 +1,8 @@
1
- (()=>{var Dt=["size-details","size-fields","size-x","size-y","size-z","size-lock","size-percent","size-apply","size-cancel","size-reset","size-error","file-units","file-units-note","display-units","size-unit-label","duplicate-model","camera-preset","bookmark-name","bookmark-list","bookmark-save","bookmark-restore","bookmark-rename","bookmark-delete","camera-error","info-area","info-volume","measure-model","measure-cancel","measure-status"],Oe=["x","y","z"],yi=new Intl.NumberFormat(void 0,{maximumSignificantDigits:7});function bi({$:t,listen:e,window:i,getViewer:o,getState:s,changeSize:n,duplicate:r,refresh:d,announce:l}){let c=null,m=0,f=null,b=null,p=null,g=!1,h=(k,_="")=>{t(k).textContent=_,t(k).hidden=!_},v=()=>o()?.display_units==="inch"?25.4:1,y=k=>Number(k.toPrecision(10));function M(){let k=o(),{selectedId:_,busy:A}=s(),I=k?._models.get(_),E=I?.scaleVector,L=I?._measurements,T=L&&L.positions===I.geometry.positions&&L.key===E.join(","),j=v()===1?"mm":"in",S=T?L.result.area_mm2:E&&E[0]===E[1]&&E[1]===E[2]?I.geometry.area*E[0]**2:null;t("info-area").textContent=S==null?"Calculate":yi.format(S/v()**2)+" "+j+"\xB2",t("info-volume").textContent=T?L.result.volume_valid?yi.format(L.result.volume_mm3/v()**3)+" "+j+"\xB3":"Unavailable":"Not checked",p||(t("measure-status").textContent=T?L.result.volume_reason:"Calculate to check enclosed volume. Runs on your device."),t("measure-model").disabled=A||!I||!!p,t("measure-cancel").hidden=!p}function P(){let k=o(),_=t("bookmark-list").value,A=k?.get_camera_bookmarks()||[];t("bookmark-list").replaceChildren(...A.map(I=>{let E=i.document.createElement("option");return E.value=I.name,E.textContent=I.name,E})),A.some(I=>I.name===_)&&(t("bookmark-list").value=_);for(let I of["bookmark-restore","bookmark-rename","bookmark-delete","bookmark-list"])t(I).disabled=!A.length;t("bookmark-save").disabled=!k||A.length>=32}function C(){if(g)return;let{selectedId:k,busy:_}=s(),A=o(),I=A?._models.get(k);k!==b&&(p?.abort(),b=k),c=null,f=I?.geometry?A.get_model_size(k):null,t("size-fields").disabled=_||!f,t("duplicate-model").disabled=_||!f,t("display-units").value=A?.display_units||"mm",t("size-unit-label").textContent=v()===1?"Dimensions in mm":"Dimensions in inches",t("file-units").value=f?.file_units||"mm",t("file-units").disabled=_||!f?.editable,t("file-units-note").textContent=f?.editable?"STL/OBJ have no units. Millimetres are assumed; choose inches to correct the physical size.":"Explicit file units were converted to millimetres on import.",Oe.forEach((L,T)=>{t("size-"+L).value=f?y(f.dimensions_mm[T]/v()):"",t("size-"+L).disabled=!f||f.dimensions_mm[T]===0});let E=f?.baseline_mm.map((L,T)=>L?f.dimensions_mm[T]/L:null).filter(L=>L!=null)||[];t("size-percent").value=E.length&&E.every(L=>Math.abs(L/E[0]-1)<1e-8)?y(E[0]*100):"",h("size-error"),M(),P()}let w=(k,_)=>{try{_(),h(k)}catch(A){h(k,A.message)}};Oe.forEach((k,_)=>e(t("size-"+k),"input",()=>{if(!f)return;c="axis",m=_;let A=t("size-"+k).valueAsNumber;!Number.isFinite(A)||A<=0||(t("size-lock").checked&&Oe.forEach((I,E)=>{_!==E&&(t("size-"+I).value=y(A*f.dimensions_mm[E]/f.dimensions_mm[_]))}),t("size-percent").value="")})),e(t("size-percent"),"input",()=>{c="percent";let k=t("size-percent").valueAsNumber;f&&Number.isFinite(k)&&k>0&&Oe.forEach((_,A)=>t("size-"+_).value=y(f.baseline_mm[A]*k/100/v()))}),e(t("size-apply"),"click",()=>w("size-error",()=>{if(!f||!c)return;let k=o().get_model_size(b).dimensions_mm,_=Oe.map(I=>t("size-"+I).valueAsNumber*v());if(c==="percent"){let I=t("size-percent").valueAsNumber;if(!Number.isFinite(I)||I<=0)throw new Error("Enter a positive scale percentage.");_=f.baseline_mm.map(E=>E*I/100)}else if(t("size-lock").checked){let I=_[m]/f.dimensions_mm[m];_=f.dimensions_mm.map(E=>E*I)}let A=_.map((I,E)=>{if(!Number.isFinite(I)||I<0||k[E]>0&&I===0)throw new Error("Enter positive dimensions for each non-flat axis.");return k[E]?I/k[E]:1});A.every(I=>Math.abs(I/A[0]-1)<1e-12)&&(A=A.map(()=>A[0])),n(()=>o().resize_model(b,A)),l("Model size updated.")})),e(t("size-cancel"),"click",C),e(t("size-reset"),"click",()=>w("size-error",()=>{n(()=>o().reset_model_size(b)),l("Original size restored; file-unit correction retained.")})),e(t("file-units"),"change",()=>w("size-error",()=>{n(()=>o().set_file_units(b,t("file-units").value)),l("File units corrected.")})),e(t("display-units"),"change",()=>{o()?.set_display_units(t("display-units").value),d()}),e(t("duplicate-model"),"click",()=>w("size-error",r)),e(t("camera-preset"),"change",()=>w("camera-error",()=>{t("camera-preset").value&&o().set_camera_view(t("camera-preset").value),l("Camera view updated."),t("camera-preset").value=""}));let R=k=>w("camera-error",()=>{let _=o(),A=_.get_camera_bookmarks();k(A,_),_.set_camera_bookmarks(A),P()});return e(t("bookmark-save"),"click",()=>R((k,_)=>{k.push({name:t("bookmark-name").value,camera:_.get_camera_state()})})),e(t("bookmark-rename"),"click",()=>R(k=>{k.find(_=>_.name===t("bookmark-list").value).name=t("bookmark-name").value})),e(t("bookmark-delete"),"click",()=>R(k=>{k.splice(k.findIndex(_=>_.name===t("bookmark-list").value),1)})),e(t("bookmark-restore"),"click",()=>w("camera-error",()=>{let k=o().get_camera_bookmarks().find(_=>_.name===t("bookmark-list").value);k&&(o().set_camera_state(k.camera),l("Saved view restored."))})),e(t("bookmark-list"),"change",()=>t("bookmark-name").value=t("bookmark-list").value),e(t("measure-cancel"),"click",()=>p?.abort()),e(t("measure-model"),"click",async()=>{let k=b,_=o(),A=new i.AbortController;p=A,M(),t("measure-status").textContent="Calculating area and checking volume\u2026";try{await _.measure_model(k,{signal:A.signal,on_progress:I=>{b===k&&!g&&(t("measure-status").textContent=I.phase+"\u2026")}}),!g&&b===k&&l("Measurements ready.")}catch(I){!g&&b===k&&(t("measure-status").textContent=I.name==="AbortError"?"Calculation cancelled.":I.message)}finally{let I=t("measure-status").textContent;p===A&&(p=null),g||(M(),!_._models.get(k)?._measurements&&b===k&&(t("measure-status").textContent=I))}}),{sync:C,syncInfo:M,dispose(){g=!0,p?.abort()}}}function vi(t){let e=typeof t=="number"&&Number.isFinite(t)&&t>=.25&&t<=128,i=(e?t:2)*1073741824,o=Math.floor(i/2);return{budget:o,reported:e,estimated:i,limits:{max_memory_bytes:o,max_file_bytes:Math.floor(o/3),max_triangles:Math.max(1,Math.floor((o-64*1048576)/224)),max_uncompressed_bytes:Math.max(1,Math.floor((o-64*1048576)/4))}}}async function wi(t){if(/\.(step|stp|iges|igs)$/i.test(t.name))return 128*1048576+(t.size||0)*40;if(/\.stl$/i.test(t.name)&&t.size>=84&&t.slice){let e=await t.slice(0,84).arrayBuffer(),i=new DataView(e).getUint32(80,!0);if(i&&84+i*50===t.size)return 64*1048576+i*224}return 64*1048576+(t.size||0)*3}var lt=["x","y","z"],De=t=>lt.map(e=>t[e]),jt=t=>Object.fromEntries(lt.map((e,i)=>[e,t[i]])),Ei=(t,e)=>t.reduce((i,o,s)=>i+o*e[s],0),Mi=t=>{let e=Math.hypot(...t)||1;return t.map(i=>i/e)},xi=(t,e)=>Array.from({length:9},(i,o)=>[0,1,2].reduce((s,n)=>s+t[Math.floor(o/3)*3+n]*e[n*3+o%3],0)),zi=(t,e)=>[0,1,2].map(i=>Ei(t.slice(i*3,i*3+3),e));function je(t={x:0,y:0,z:0}){let[e,i,o]=De(t).map(m=>m%360*Math.PI/180),s=Math.cos(e),n=Math.sin(e),r=Math.cos(i),d=Math.sin(i),l=Math.cos(o),c=Math.sin(o);return[r*l,-r*c,d,s*c+n*l*d,s*l-n*d*c,-n*r,n*c-s*l*d,n*l+s*d*c,s*r]}var Bt=t=>t.min.map((e,i)=>(e+t.max[i])/2);function Ai(t){return jt(Bt(t.bounds).map((e,i)=>e+t.position[lt[i]]))}function Si(t){return Math.max(Math.hypot(...t.bounds.max.map((e,i)=>e-t.bounds.min[i]))/2,1e-6)}function Be(t){let e=Bt(t.bounds),i=zi(je(t.rotation),e);return jt(e.map((o,s)=>t.position[lt[s]]+o-i[s]))}function Ut(t){if(!t.rotation||!Object.values(t.rotation).some(n=>n%360))return t.bounds;let e=Bt(t.bounds),i=je(t.rotation),o=[1/0,1/0,1/0],s=[-1/0,-1/0,-1/0];for(let n=0;n<8;n++)zi(i,e.map((d,l)=>t.bounds[n&1<<l?"max":"min"][l]-d)).forEach((d,l)=>{o[l]=Math.min(o[l],d+e[l]),s[l]=Math.max(s[l],d+e[l])});return{min:o,max:s}}function ki(t,e){let[i,o,s]=Mi(t),n=Math.cos(e),r=Math.sin(e),d=1-n;return[d*i*i+n,d*i*o-r*s,d*i*s+r*o,d*i*o+r*s,d*o*o+n,d*o*s-r*i,d*i*s-r*o,d*o*s+r*i,d*s*s+n]}function Ii(t,e,i,o,s){let n=Math.PI/Math.max(1,s),r=xi(ki(e.right,o*n),xi(ki(e.up,i*n),je(t))),d=Math.asin(Math.max(-1,Math.min(1,r[2]))),l=Math.abs(Math.cos(d))>1e-10;return{x:(l?Math.atan2(-r[5],r[8]):Math.atan2(r[7],r[4]))*180/Math.PI,y:d*180/Math.PI,z:(l?Math.atan2(-r[1],r[0]):0)*180/Math.PI}}function Ue(t,e,i){if(i===0)return{...t.position};let o=De(e.position),s=De(t.center),n=s.map((b,p)=>b-o[p]),r=Mi(De(e.target).map((b,p)=>b-o[p])),d=Math.hypot(...n),l=d>1e-9?n.map(b=>b/d):r,c=Math.max(t.radius||1e-6,1e-6)*1.1/Math.max(.05,Ei(l,r)),m=(d||c)*Math.exp(Math.max(-6,Math.min(6,i))),f=i<0?Math.max(Math.min(d,c),m):Math.max(d,Math.min(1e12,m));return jt(De(t.position).map((b,p)=>b+l[p]*(f-d)))}function Ci(t,e){if(e==="custom")return t.map(n=>({id:n.id,...n.position||{x:0,y:0,z:0}}));if(e==="original")return t.map(n=>({id:n.id,...n.originalPosition||{x:0,y:0,z:0}}));t=t.map(n=>({...n,bounds:Ut(n)}));let i=t.map(n=>n.bounds.max[0]-n.bounds.min[0]),o=t.reduce((n,r)=>Math.max(n,...r.bounds.max.map((d,l)=>d-r.bounds.min[l])),1)*.12,s=-(i.reduce((n,r)=>n+r,0)+o*Math.max(0,t.length-1))/2;return t.map((n,r)=>{let d={id:n.id,x:s-n.bounds.min[0],y:-(n.bounds.min[1]+n.bounds.max[1])/2,z:-n.bounds.min[2]};return s+=i[r]+o,d})}function Ri(t,e){let i=new Map(e.map(o=>[o.id,o.z]));return t.length?t.reduce((o,s)=>Math.min(o,Ut(s).min[2]+(i.get(s.id)||0)),1/0):0}var ct=t=>[t.x,t.y,t.z],Pi=(t,e)=>t.map((i,o)=>i-e[o]),wo=(t,e)=>t.reduce((i,o,s)=>i+o*e[s],0),Vt=(t,e)=>[t[1]*e[2]-t[2]*e[1],t[2]*e[0]-t[0]*e[2],t[0]*e[1]-t[1]*e[0]],Gt=t=>{let e=Math.hypot(...t);return t.map(i=>i/(e||1))};function xo(t,e,i){let o=ct(t.position),s=ct(t.target),n=Gt(Pi(o,s)),r=Gt(Vt(ct(t.up),n));Math.hypot(...r)<.5&&(r=Gt(Vt(Math.abs(n[1])<.9?[0,1,0]:[1,0,0],n)));let d=Vt(n,r),l=wo(Pi(o,ct(e)),n),c=2*Math.max(l,1e-6)*Math.tan(Math.PI/8)/Math.max(i,1);return{right:r,up:d,scale:c}}function ko(t,e,i,o){return Object.fromEntries(["x","y","z"].map((s,n)=>[s,t[s]+(e.right[n]*i-e.up[n]*o)*e.scale]))}function Li(t,{getModel:e,getCamera:i,getTool:o=()=>"move",onMove:s,onRotate:n,onStart:r,onEnd:d}){let l=!1,c=null,m=new Set,f=[],b=(h,v)=>{t.addEventListener(h,v,{capture:!0,passive:!1}),f.push(()=>t.removeEventListener(h,v,!0))},p=h=>{h.preventDefault(),h.stopImmediatePropagation()},g=(h=!1)=>{if(!c)return;let v=c;c=null,h&&(v.tool==="rotate"?n?.(v.id,v.rotation):s(v.id,v.position)),t.classList.remove("moving-model"),t.hasPointerCapture(v.pointer)&&t.releasePointerCapture(v.pointer),d?.(v.id,h)};b("pointerdown",h=>{if(!l||h.button!==0||h.shiftKey)return;if(p(h),c||h.isPrimary===!1){m.add(h.pointerId);return}let v=e();v&&(c={tool:o(),rotation:{...v.rotation||{x:0,y:0,z:0}},model:{...v,position:{...v.position},center:{...v.center}},camera:i(),height:t.getBoundingClientRect().height,id:v.id,position:{...v.position},pointer:h.pointerId,x:h.clientX,y:h.clientY,basis:xo(i(),v.center,t.getBoundingClientRect().height)},r?.(v.id),t.setPointerCapture(h.pointerId),t.classList.add("moving-model"),t.focus({preventScroll:!0}))}),b("pointermove",h=>{if(m.has(h.pointerId)){p(h);return}if(!c||c.pointer!==h.pointerId)return;p(h);let v=h.clientX-c.x,y=h.clientY-c.y;c.tool==="rotate"?n?.(c.id,Ii(c.rotation,c.basis,v,y,c.height)):c.tool==="depth"?s(c.id,Ue(c.model,c.camera,y*3/Math.max(1,c.height))):s(c.id,ko(c.position,c.basis,v,y))});for(let h of["pointerup","pointercancel","lostpointercapture"])b(h,v=>{if(m.delete(v.pointerId)){p(v);return}!c||c.pointer!==v.pointerId||(p(v),g(h!=="pointerup"))});b("wheel",h=>{if(!l||(p(h),c))return;let v=e();if(!v)return;let y=h.deltaY*(h.deltaMode===1?16:h.deltaMode===2?t.getBoundingClientRect().height:1);s(v.id,Ue(v,i(),Math.max(-.5,Math.min(.5,y*.0015))))});for(let h of["keydown","dblclick"])b(h,v=>{c&&v.key!=="Escape"&&p(v)});return{setEnabled(h){g(!0),m.clear(),l=h,t.classList.toggle("model-move-ready",h)},dispose(){g(!0),f.forEach(h=>h())}}}function qt(t){let e=Array.from(t?.types||[],i=>i.toLowerCase());return e.includes("files")||t?.files?.length?"files":e.includes("text/uri-list")||e.includes("text/x-moz-url")?"url":e.includes("text/plain")?"text":null}function Ti(t){if(qt(t)==="files")return[];let e=t?.getData("text/uri-list")?.trim(),i=!e&&t?.getData("text/x-moz-url")?.trim(),o=!e&&!i&&t?.getData("text/plain")?.trim(),s;if(e)s=e.split(/\r?\n/).map(r=>r.trim()).filter(r=>r&&!r.startsWith("#"));else if(i)s=[i.split(/\r?\n/)[0]];else if(o){if(s=o.split(/\r?\n/).map(r=>r.trim()).filter(Boolean),!s.every(r=>/^https?:\/\/\S+$/i.test(r)))return[]}else return[];let n=new Set;for(let r of s){let d;try{d=new URL(r)}catch{}if(!d||!["https:","http:"].includes(d.protocol)||d.username||d.password)throw new Error("Drop a public HTTP or HTTPS file URL without login credentials.");d.hash="",n.add(d.href)}return[...n]}var ae=(t,e)=>t.map((i,o)=>i+e[o]),H=(t,e)=>t.map((i,o)=>i-e[o]),re=(t,e)=>t.map(i=>i*e),ne=(t,e)=>t[0]*e[0]+t[1]*e[1]+t[2]*e[2],se=(t,e)=>[t[1]*e[2]-t[2]*e[1],t[2]*e[0]-t[0]*e[2],t[0]*e[1]-t[1]*e[0]],W=t=>re(t,1/(Math.hypot(...t)||1));function Ve(t,e){let i=new Float64Array(16);for(let o=0;o<4;o++)for(let s=0;s<4;s++)for(let n=0;n<4;n++)i[o*4+s]+=t[n*4+s]*e[o*4+n];return i}function Q(t,e,i=1){let o=t[3]*e[0]+t[7]*e[1]+t[11]*e[2]+t[15]*i;return[0,1,2].map(s=>(t[s]*e[0]+t[4+s]*e[1]+t[8+s]*e[2]+t[12+s]*i)/(i&&o?o:1))}function Eo(t,e,i){let o=Math.cos(t),s=Math.sin(t),n=Math.cos(e),r=Math.sin(e),d=Math.cos(i),l=Math.sin(i);return new Float64Array([n*d,o*l+s*d*r,s*l-o*d*r,0,-n*l,o*d-s*l*r,s*d+o*l*r,0,r,-s*n,o*n,0,0,0,0,1])}function J(t){let e=Eo(t.rotationx,t.rotationy,t.rotationz),i=t.scaleVector;for(let s=0;s<3;s++)for(let n=0;n<3;n++)e[s*4+n]*=i[s];let o=t.center||[0,0,0];for(let s=0;s<3;s++)e[12+s]=[t.x,t.y,t.z][s]-e[s]*o[0]-e[4+s]*o[1]-e[8+s]*o[2];return e}function we(t){let e=Array.from({length:4},(i,o)=>[...Array.from({length:4},(s,n)=>t[n*4+o]),...Array.from({length:4},(s,n)=>+(n===o))]);for(let i=0;i<4;i++){let o=i;for(let n=i+1;n<4;n++)Math.abs(e[n][i])>Math.abs(e[o][i])&&(o=n);if(Math.abs(e[o][i])<1e-30)throw new Error("Singular transform");[e[o],e[i]]=[e[i],e[o]];let s=e[i][i];e[i]=e[i].map(n=>n/s);for(let n=0;n<4;n++)if(n!==i){let r=e[n][i];e[n]=e[n].map((d,l)=>d-r*e[i][l])}}return new Float64Array(Array.from({length:16},(i,o)=>e[o%4][4+Math.floor(o/4)]))}function dt(t,e){let i=W(H(t.position,t.target)),o=W(se(t.up,i));Math.hypot(...o)<.5&&(o=W(se(Math.abs(i[1])<.9?[0,1,0]:[1,0,0],i)));let s=se(i,o),n=t.position,r=new Float64Array([o[0],s[0],i[0],0,o[1],s[1],i[1],0,o[2],s[2],i[2],0,-ne(o,n),-ne(s,n),-ne(i,n),1]),d=1/Math.tan(Math.PI/8),l=t.near,c=t.far,m=new Float64Array([d/e,0,0,0,0,d,0,0,0,0,(c+l)/(l-c),-1,0,0,2*c*l/(l-c),0]);return Ve(m,r)}function mt(t,e,i){let o=W(e),s=Math.cos(i),n=Math.sin(i);return ae(ae(re(t,s),re(se(o,t),n)),re(o,ne(o,t)*(1-s)))}function Ht(t,e,i,o){let s=0,n=1/0;for(let r=0;r<3;r++){if(Math.abs(e[r])<1e-15){if(t[r]<i[r]||t[r]>o[r])return!1;continue}let d=(i[r]-t[r])/e[r],l=(o[r]-t[r])/e[r];if(d>l&&([d,l]=[l,d]),s=Math.max(s,d),n=Math.min(n,l),n<s)return!1}return!0}function Fi(t,e,i,o){let s=[i[o],i[o+1],i[o+2]],n=H([i[o+3],i[o+4],i[o+5]],s),r=H([i[o+6],i[o+7],i[o+8]],s),d=se(e,r),l=ne(n,d);if(Math.abs(l)<1e-12)return 1/0;let c=H(t,s),m=ne(c,d)/l;if(m<0||m>1)return 1/0;let f=se(c,n),b=ne(e,f)/l;if(b<0||m+b>1)return 1/0;let p=ne(r,f)/l;return p>=0?p:1/0}var Ge=["x","y","z","rotationx","rotationy","rotationz","scalex","scaley","scalez"],le=t=>t.startsWith("scale"),ue=(t,e,i=!1)=>{if(typeof t!="number"||!Number.isFinite(t)||Math.abs(t)>Number.MAX_SAFE_INTEGER||i&&t<=0)throw new Error(`Invalid animation ${e}`);return t},ut=(t,e)=>{if(!t||typeof t!="object"||Array.isArray(t))throw new Error(`Invalid animation ${e}`);return t};function Ni(t){return Object.fromEntries(Ge.map(e=>[e,ue(t[e]??(le(e)?t.scale??1:0),e,le(e))]))}function qe(t){ut(t,"definition");let e={},i=new Set;for(let o of["delta","exact"]){if(t[o]==null)continue;let s=ut(t[o],o),n={},r=ue(s.msec??300,"duration",!0);if(s.loop!==void 0&&typeof s.loop!="boolean")throw new Error("Animation loop must be a boolean");let d=o==="delta"&&!!s.loop;for(let l of Ge){let c=s[l]??(le(l)?s.scale:void 0);if(c!==void 0){if(i.has(l))throw new Error(`Animation delta/exact conflict: ${l}`);if(ue(c,l,o==="exact"&&le(l)),d&&le(l)&&c<0)throw new Error("Looping scale deltas cannot be negative");n[l]=c,i.add(l)}}if(!Object.keys(n).length)throw new Error("Animation track needs a transform");e[o]={...n,msec:r,...d?{loop:!0}:{}}}if(!Object.keys(e).length)throw new Error("Animation needs delta or exact");return e}function He(t){if(ut(t,"playback state"),t.version!==1||typeof t.paused!="boolean")throw new Error("Invalid animation playback state version or paused flag");let e=ue(t.elapsed_ms,"elapsed time");if(e<0)throw new Error("Invalid animation elapsed time");ut(t.origin,"origin");for(let i of Ge)ue(t.origin[i],i,le(i));if(!Array.isArray(t.center)||t.center.length!==3)throw new Error("Invalid animation pivot");return{version:1,elapsed_ms:e,paused:t.paused,origin:Ni(t.origin),center:t.center.map(i=>ue(i,"pivot"))}}function We(t,e,i){let o=qe(t),s=i==null?null:He(i),n=s?.origin??Ni(e),r=Object.entries(o).map(([l,c])=>{let m=Object.entries(c).filter(([f])=>Ge.includes(f));if(l==="delta")for(let[f,b]of m)ue(n[f]+b,`${f} endpoint`,le(f));return{mode:l,values:m,duration:c.msec,loop:!!c.loop,done:!1}}),d={animation:o,origin:n,tracks:r,elapsed_ms:s?.elapsed_ms??0,paused:s?.paused??!1,last_time:null};return ht({...d,tracks:r.map(l=>({...l}))},{}),d}function ht(t,e){let i=[];for(let s of t.tracks){if(s.done)continue;let n=t.elapsed_ms/s.duration,r=s.loop?n:Math.min(n,1);for(let[d,l]of s.values){let c=t.origin[d],m=s.mode==="delta"?c+l*r:c*(1-r)+l*r;i.push([d,ue(m,`${d} result`,le(d))])}}let o=!1;for(let[s,n]of i)o||=le(s)&&e[s]!==n,e[s]=n;for(let s of t.tracks)!s.loop&&t.elapsed_ms>=s.duration&&(s.done=!0);return o&&(e._stats=null),t.tracks.some(s=>!s.done)}function Oi(t,e,i){return t.paused?!0:(t.last_time!==null&&(t.elapsed_ms=ue(t.elapsed_ms+Math.max(0,i-t.last_time),"elapsed time")),t.last_time=i,ht(t,e))}function Di(t,e=!1){return{status:t.paused?"paused":"running",elapsed_ms:t.elapsed_ms,suspended:e,tracks:t.tracks.filter(i=>!i.done).map(i=>({mode:i.mode,msec:i.duration,loop:i.loop,progress:i.loop?t.elapsed_ms%i.duration/i.duration:Math.min(1,t.elapsed_ms/i.duration)}))}}function ft(t){let e=t._animation;if(!e)return null;let i=t.unitScale??1,o=structuredClone(e.animation),s={...e.origin};for(let r of Ge.filter(le)){s[r]*=i;for(let d of Object.values(o))d[r]!==void 0&&(d[r]*=i)}let n=He({version:1,origin:s,elapsed_ms:e.elapsed_ms,paused:e.paused,center:[...t.center]});return{animation:qe(o),animation_state:n}}function Je(t){return t?t.triangles*224+(t.smoothNormals?.byteLength||0)*4+((t.edges?.byteLength||0)+(t.wire?.byteLength||0))*2:0}function Y(t,e,i="model"){if(e>(t.max_memory_bytes??Number.MAX_SAFE_INTEGER))throw new Error(`Estimated memory for this ${i} exceeds the device safety budget. Use a smaller model or a device with more memory.`)}function ji(t,e){return 67108864+t*(224+(e.smooth?1536:0)+(e.edges||e.wire?2048:0))}function Bi(t={}){let e=t.level??"basic";if(!["basic","detailed"].includes(e))throw new Error("Choose basic or detailed print checks");let i=(n,r,d=1e9)=>{if(!Number.isFinite(n)||n<=0||n>d)throw new Error(`Invalid ${r}`);return n},o=null;if(t.profile!=null){if(t.profile.technology!=="fdm")throw new Error("Only FDM profiles are supported");o={technology:"fdm"};for(let n of["min_wall_mm","line_width_mm"])t.profile[n]!=null&&(o[n]=i(t.profile[n],n));if(t.profile.overhang_degrees!=null&&(o.overhang_degrees=i(t.profile.overhang_degrees,"overhang angle",89.9)),t.profile.build_volume_mm!=null){if(!Array.isArray(t.profile.build_volume_mm)||t.profile.build_volume_mm.length!==3)throw new Error("Build volume requires X, Y and Z");o.build_volume_mm=t.profile.build_volume_mm.map(n=>i(n,"build volume"))}}let s=i(t.max_time_ms??3e4,"check time limit",12e4);return{level:e,profile:o,apply_transforms:t.apply_transforms!==!1,units_confirmed:t.units_confirmed===!0,max_time_ms:s}}var pt=t=>64*1024**2+t*2400,ye=t=>JSON.stringify([t.x,t.y,t.z,t.rotationx,t.rotationy,t.rotationz,t.scaleVector,t.center,t.units,t.unitScale]);var he=["x","y","z"];function Se(t){if(!["mm","inch"].includes(t))throw new Error("Choose mm or inch");return t}function Wt(t){if(!t||t.version!==1||!Array.isArray(t.baseline_mm)||t.baseline_mm.length!==3||t.baseline_mm.some(e=>!Number.isFinite(e)||e<0||e>1e12)||typeof t.editable!="boolean"||t.unit_factor!==void 0&&(!Number.isFinite(t.unit_factor)||t.unit_factor<=0||t.unit_factor>1e12))throw new Error("Invalid saved model size");return{version:1,baseline_mm:[...t.baseline_mm],file_units:Se(t.file_units),editable:t.editable,unit_factor:t.unit_factor??1}}function Ie(t){return t.size_state??={version:1,baseline_mm:t.geometry.bounds.max.map((e,i)=>(e-t.geometry.bounds.min[i])*t.unitScale),file_units:"mm",editable:!t.geometry.units,unit_factor:1}}function xe(t){if(!t.geometry)throw new Error("Wait for the model to finish opening");let e=Ie(t);return{...structuredClone(e),dimensions_mm:t.geometry.bounds.max.map((i,o)=>(i-t.geometry.bounds.min[o])*t.scaleVector[o])}}function _t(t,e){let i=this._model(t);if(xe(i),!Array.isArray(e)||e.length!==3||e.some(c=>!Number.isFinite(c)||c<=0))throw new Error("Scale must be a positive finite number");let o=he.map((c,m)=>i["scale"+c]*e[m]);if(o.some(c=>!Number.isFinite(c)||c<1e-12||c>1e12))throw new Error("Scale is outside the supported range");let s=i.geometry.bounds.min.map((c,m)=>(c+i.geometry.bounds.max[m])/2),n=Q(J(i),s),r=i._measurements,d=i.scaleVector.join(",");this._stopAnimation(i,"manual"),he.forEach((c,m)=>i["scale"+c]=o[m]);let l=Q(J(i),s);return he.forEach((c,m)=>i[c]+=n[m]-l[m]),i._stats=null,r?.key===d&&r.positions===i.geometry.positions&&e.every(c=>c===e[0])&&(i._measurements={...r,key:i.scaleVector.join(","),result:{...r.result,area_mm2:r.result.area_mm2*e[0]**2,volume_mm3:r.result.volume_mm3==null?null:r.result.volume_mm3*e[0]**3}}),this._invalidate(),xe(i)}function Ui(t,e){Se(e);let i=this._model(t),o=Ie(i);if(!o.editable)throw new Error("This model has explicit file units, already converted to millimetres");if(o.file_units===e)return xe(i);let s=e==="inch"?25.4:1/25.4,n=_t.call(this,t,[s,s,s]);return o.baseline_mm=o.baseline_mm.map(r=>r*s),o.file_units=e,o.unit_factor=(o.unit_factor??1)*s,{...n,...structuredClone(o)}}function Vi(t){let e=xe(this._model(t));return _t.call(this,t,e.dimensions_mm.map((i,o)=>i?e.baseline_mm[o]/i:1))}function Gi(t){let e=this._model(t);if(xe(e),e._sceneImportPending)throw new Error("Wait for the scene to finish opening");if(this._models.size+1>this.limits.max_archive_entries||[...this._models.values()].reduce((s,n)=>s+(n.geometry?.triangles||0),e.geometry.triangles)>this.limits.max_triangles)throw new Error("Scene model or triangle limit exceeded");Y(this.limits,this._occupiedMemory()+Je(e.geometry),"duplicate");let i={};for(let s of["filename","orig_filename","local_file","x","y","z","rotationx","rotationy","rotationz","opacity","units","display","view_edges","smooth_shading","color"])i[s]=e[s];if(i.id=this.max_model_id+1,!Number.isSafeInteger(i.id))throw new Error("Model ID limit exceeded");i.display_name=(e.display_name||e.orig_filename||e.filename||"Model").split(/[\\/]/).pop()+" \u2014 copy",i.center=[...e.center],i.unitScale=1,he.forEach((s,n)=>i["scale"+s]=e.scaleVector[n]),Object.defineProperty(i,"scaleVector",{get:()=>he.map(s=>i["scale"+s]*i.unitScale)}),i.geometry={...e.geometry},i.section=e.section?{...e.section}:null,i.size_state=structuredClone(Ie(e)),i.size_state.unit_factor=(i.size_state.unit_factor??1)*e.unitScale;let o=ft(e);return this.max_model_id=i.id,this._models.set(i.id,i),this.models_ref[i.id]=this.models.length,this.models.push(i),this.models_count=this._models.size,o&&this._startAnimation(i,o.animation,{...o.animation_state,paused:!0}),this._invalidate(),i.id}var Mo={front:[[0,-1,0],[0,0,1]],back:[[0,1,0],[0,0,1]],left:[[-1,0,0],[0,0,1]],right:[[1,0,0],[0,0,1]],top:[[0,0,1],[0,1,0]],bottom:[[0,0,-1],[0,-1,0]],isometric:[[1,-1,1],[0,0,1]]};function qi(t){let e=Mo[t];if(!e)throw new Error("Unknown camera view");this.camera.position=this.camera.target.map((i,o)=>i+e[0][o]),this.camera.up=[...e[1]],this.set_auto_zoom()}function Ae(t){if(!Array.isArray(t)||t.length>32)throw new Error("Save up to 32 camera views");let e=new Set;return t.map(i=>{let o=typeof i?.name=="string"?i.name.trim():"";if(!o||o.length>80||/[\x00-\x1f]/.test(o)||e.has(o))throw new Error("Use a unique view name of 1\u201380 characters");e.add(o);let s={};for(let d of["position","target","up"]){if(!i.camera?.[d]||he.some(l=>!Number.isFinite(i.camera[d][l])||Math.abs(i.camera[d][l])>1e15))throw new Error("Invalid saved camera");s[d]=Object.fromEntries(he.map(l=>[l,i.camera[d][l]]))}let n=he.map(d=>s.position[d]-s.target[d]),r=he.map(d=>s.up[d]);if(Math.hypot(n[1]*r[2]-n[2]*r[1],n[2]*r[0]-n[0]*r[2],n[0]*r[1]-n[1]*r[0])<1e-12)throw new Error("Degenerate saved camera");return{name:o,camera:s}})}function gt(t,e){let i=Ae(t),o=new Set(i.map(s=>s.name));for(let s of Ae(e)){let n=s.name,r=2;for(;o.has(n);)n=s.name.slice(0,70)+` (${r++})`;o.add(n),i.push({...s,name:n})}return Ae(i)}async function Hi(t,e={}){await this.when_ready;let i=this._model(t),o=i.geometry;if(!o||i._sceneImportPending)throw new Error("Wait for the model to finish opening");let s=i.scaleVector,n=s.join(","),r=i._measurements;if(e.signal?.aborted)throw new DOMException("Measurement cancelled","AbortError");if(r?.positions===o.positions&&r.key===n)return{...r.result};let d=pt(o.triangles),l=this._occupiedMemory();Y(this.limits,l+d,"measurements");let c=this._reserveMemory(i,d+Je(o),"measurements"),m=new AbortController,f=()=>m.abort();this._aborters.add(m),(i._measureJobs??=new Set).add(m),e.signal?.addEventListener("abort",f,{once:!0});let b,p,g=()=>{if(m.signal.aborted||this.killsign)throw new DOMException("Measurement cancelled","AbortError");if(this._models.get(t)!==i||i.geometry.positions!==o.positions||i.scaleVector.join(",")!==n)throw new Error("Model size changed. Calculate again.")};try{let h=new Float32Array(o.positions.length);for(let y=0;y<h.length;y+=262144)g(),h.set(o.positions.subarray(y,y+262144),y),y+262144<h.length&&await new Promise(M=>setTimeout(M,0));b=this._pool.run({kind:"measure",positions:h,scale:s,area:o.area,max_time_ms:e.max_time_ms??3e4,limits:{...this.limits,max_memory_bytes:this.limits.max_memory_bytes-l}},y=>{try{e.on_progress?.(y)}catch(M){p=M,m.abort()}},[h.buffer]),m.signal.addEventListener("abort",()=>b.cancel(),{once:!0}),g();let v;try{v=await b}catch(y){throw p||y}return g(),i._measurements={positions:o.positions,key:n,result:v},{...v}}finally{b?.cancel?.(),c(),this._aborters.delete(m),i._measureJobs.delete(m),e.signal?.removeEventListener("abort",f)}}var zo=["flat","smooth","wireframe","edges","mesh","xray","studio","orientation"];function yt(t,e){if(!zo.includes(t))throw new Error("Invalid display mode");if(typeof e!="boolean")throw new Error("smooth_shading must be a boolean");return{display:t,smooth_shading:t==="smooth"||e}}function Jt(t){return{smooth:(t.smooth_shading||t.display==="smooth")&&t.display!=="wireframe",edges:t.view_edges||t.display==="edges",wire:t.display==="wireframe",edgeAngle:t.display==="edges"?30:1}}function bt(t){if(t==null)return null;if(!["x","y","z"].includes(t.axis))throw new Error("Section axis must be x, y or z");if(!Number.isFinite(t.position)||t.position<0||t.position>1)throw new Error("Section position must be between 0 and 1");if(t.flip!==void 0&&typeof t.flip!="boolean")throw new Error("Section flip must be a boolean");return{axis:t.axis,position:t.position,flip:t.flip??!1}}function vt(t,e){if(!e)return[0,0,0,0];let i=["x","y","z"].indexOf(e.axis),o=e.flip?-1:1,s=[0,0,0,0];return s[i]=o,s[3]=-o*(t.min[i]+(t.max[i]-t.min[i])*e.position),s}var Wi=Object.freeze({max_file_bytes:256*1024*1024,max_triangles:5e6,max_uncompressed_bytes:256*1024*1024,max_archive_entries:1024,max_memory_bytes:Number.MAX_SAFE_INTEGER});function Ji(t={}){let e={...Wi};for(let i of Object.keys(e))if(t[i]!==void 0){if(!Number.isSafeInteger(t[i])||t[i]<1)throw new Error(`Invalid ${i}`);e[i]=t[i]}return e}function Z(t){if(typeof t!="string"||!/^#[\da-f]{6}$/i.test(t))throw new Error("Color must be #RRGGBB");return[1,3,5].map(e=>parseInt(t.slice(e,e+2),16)/255)}function wt(t,e=null,i=Wi){if(!(t instanceof Float32Array)||!t.length||t.length%9)throw new Error("Geometry must contain complete triangles");if(t.length/9>i.max_triangles)throw new Error("Triangle limit exceeded");if(Y(i,67108864+t.length/9*224),e&&(!(e instanceof Float32Array)||e.length!==t.length))throw new Error("Invalid vertex colors");let o={min:[1/0,1/0,1/0],max:[-1/0,-1/0,-1/0]};for(let c=0;c<t.length;c++){let m=t[c],f=c%3;if(!Number.isFinite(m))throw new Error("Non-finite vertex coordinate");if(o.min[f]=Math.min(o.min[f],m),o.max[f]=Math.max(o.max[f],m),e&&(!Number.isFinite(e[c])||e[c]<0||e[c]>1))throw new Error("Invalid vertex color")}let s=new Float32Array(t.length),n=new Float32Array(Math.ceil(t.length/9/64)*6),r=0,d=0,l=0;for(let c=0;c<t.length;c+=9){let m=t[c+3]-t[c],f=t[c+4]-t[c+1],b=t[c+5]-t[c+2],p=t[c+6]-t[c],g=t[c+7]-t[c+1],h=t[c+8]-t[c+2],v=f*h-b*g,y=b*p-m*h,M=m*g-f*p,P=Math.hypot(v,y,M);r+=P/2,d+=(t[c]*v+t[c+1]*y+t[c+2]*M)/6,P||l++;for(let w=0;w<9;w+=3)s[c+w]=v/(P||1),s[c+w+1]=y/(P||1),s[c+w+2]=M/(P||1);let C=Math.floor(c/9/64)*6;c/9%64===0&&n.set([1/0,1/0,1/0,-1/0,-1/0,-1/0],C);for(let w=0;w<9;w++){let R=w%3;n[C+R]=Math.min(n[C+R],t[c+w]),n[C+3+R]=Math.max(n[C+3+R],t[c+w])}}if(!Number.isFinite(r)||!Number.isFinite(d))throw new Error("Geometry magnitude exceeds numeric limits");return{positions:t,normals:s,colors:e,blocks:n,bounds:o,triangles:t.length/9,area:r,volume:Math.abs(d),degenerateTriangles:l}}function Yi(t,e,i,o=[0,0,0,0]){if(!Ht(e,i,t.bounds.min,t.bounds.max))return 1/0;let s=1/0;for(let n=0;n<t.blocks.length;n+=6){if(!Ht(e,i,t.blocks.subarray(n,n+3),t.blocks.subarray(n+3,n+6)))continue;let r=n/6*64*9,d=Math.min(r+576,t.positions.length);for(let l=r;l<d;l+=9){let c=Fi(e,i,t.positions,l);c<s&&o[3]+o[0]*(e[0]+i[0]*c)+o[1]*(e[1]+i[1]*c)+o[2]*(e[2]+i[2]*c)<=0&&(s=c)}}return s}function Xi(t,e){if(e[0]===e[1]&&e[1]===e[2])return{area:t.area*e[0]*e[0],volume:t.volume*Math.abs(e[0]**3)};let i=0,o=t.positions;for(let s=0;s<o.length;s+=9){let n=(o[s+3]-o[s])*e[0],r=(o[s+4]-o[s+1])*e[1],d=(o[s+5]-o[s+2])*e[2],l=(o[s+6]-o[s])*e[0],c=(o[s+7]-o[s+1])*e[1],m=(o[s+8]-o[s+2])*e[2];i+=Math.hypot(r*m-d*c,d*l-n*m,n*c-r*l)/2}return{area:i,volume:t.volume*Math.abs(e[0]*e[1]*e[2])}}function Yt(t,e=[1,1,1],i=[0,0,0]){let o=new ArrayBuffer(84+t.triangles*50),s=new DataView(o),n=t.positions;new Uint8Array(o).set(new TextEncoder().encode("Binary STL by ViewSTL 2")),s.setUint32(80,t.triangles,!0);for(let r=0;r<t.triangles;r++){let d=84+r*50,l=Array.from({length:9},(p,g)=>(n[r*9+g]-i[g%3])*e[g%3]),c=[l[3]-l[0],l[4]-l[1],l[5]-l[2]],m=[l[6]-l[0],l[7]-l[1],l[8]-l[2]],f=[c[1]*m[2]-c[2]*m[1],c[2]*m[0]-c[0]*m[2],c[0]*m[1]-c[1]*m[0]],b=Math.hypot(...f)||1;for(let p=0;p<3;p++)s.setFloat32(d+p*4,f[p]/b,!0);for(let p=0;p<9;p++)s.setFloat32(d+12+p*4,l[p],!0);if(t.colors){let p=[0,1,2].map(g=>Math.round(t.colors[r*9+g]*31));s.setUint16(d+48,32768|p[0]<<10|p[1]<<5|p[2],!0)}}return o}var ke=t=>String(t||"").match(/\.(vsb|vsj)(?:[?#]|$)/i)?.[1].toLowerCase()||"";function Ki(t,e){let i;try{i=decodeURIComponent(t.split(/[?#]/)[0]).replaceAll("\\","/")}catch{throw new Error("Invalid scene filename encoding")}let o=[...new Set(e)],s=o.filter(r=>(r.webkitRelativePath||r.name)===i);if(s.length===1)return s[0];let n=o.filter(r=>r.name===i.split("/").pop());if(n.length>1||s.length>1)throw new Error("More than one supplied file matches "+i);return n[0]||null}function Xt(t,e){let i;try{i=e?new URL(t,e):new URL(t)}catch{return null}if(!["http:","https:"].includes(i.protocol)||i.username||i.password)throw new Error("Scene references must be HTTP/HTTPS URLs without login credentials");return i.hash="",i.href}var Kt=["save-button","save-dialog","save-form","save-fields","save-name","save-format","save-scope","save-colors","save-colors-row","save-format-note","save-cad-note","save-progress","save-status","save-error","save-submit","save-cancel","save-close"];function Zi({$:t,listen:e,window:i,getState:o,getViewer:s,onOpen:n,announce:r}){let d=t("save-dialog"),l=null,c=!1,m="",f=()=>o(),b=()=>!c&&!f().busy&&f().models.length>0,p=()=>["vsb","vsj"].includes(t("save-format").value),g=()=>{t("save-error").hidden=!0,t("save-error").textContent=""};function h(){let C=t("save-format").value;(!t("save-name").value||t("save-name").value===m)&&v(),t("save-mesh-note")&&(t("save-mesh-note").hidden=p()),t("save-scene-note")&&(t("save-scene-note").hidden=!p()),t("save-colors-row").hidden=!["obj","3mf"].includes(C),t("save-cad-note").hidden=!["step","iges"].includes(C),t("save-format-note").textContent=t("save-format").selectedOptions[0]?.dataset.note||"",t("save-submit").textContent=C==="obj"&&t("save-colors").checked?"Download ZIP":"Download file",y()}function v(){let{models:C,selectedId:w}=f();t("save-name").value=p()?"viewstl-scene":(C.find(R=>R.id===w)?.name||"model").replace(/\.[^.]+$/,""),m=t("save-name").value}function y(){t("save-button").disabled=!b()||!!l,t("save-fields").disabled=!!l,t("save-submit").disabled=!b()||!!l,t("save-progress").hidden=!l,t("save-cancel").textContent=l?"Cancel saving":"Cancel";let{models:C,selectedId:w}=f(),R=p()?`Entire scene \xB7 ${C.length} ${C.length===1?"model":"models"}`:"Selected model: "+(C.find(k=>k.id===w)?.name||"model");t("save-scope").textContent!==R&&(t("save-scope").textContent=R)}function M(){if(l){let C=l;l=null,C.abort(),r("Saving cancelled.")}t("save-status").textContent="",y()}function P(){M(),d.open&&d.close()}return e(t("save-button"),"click",()=>{!b()||l||(n(),g(),t("save-status").textContent="",v(),h(),y(),d.showModal())}),e(t("save-format"),"change",()=>{g(),h()}),e(t("save-colors"),"change",h),e(t("save-cancel"),"click",P),e(t("save-close"),"click",P),e(d,"cancel",C=>{C.preventDefault(),P()}),e(d,"close",()=>{d.open||M()}),e(t("save-form"),"submit",async C=>{if(C.preventDefault(),l||!b())return;g();let{selectedId:w}=f(),R=new i.AbortController;l=R,t("save-progress").removeAttribute("value"),t("save-status").textContent="Preparing your file\u2026",y();try{let k={format:t("save-format").value,filename:t("save-name").value.trim()||"model",model_ids:[w],units:"mm",apply_transforms:!0,colors:t("save-colors").checked,signal:R.signal,on_progress({loaded:A,total:I,phase:E}){if(l!==R||R.signal.aborted)return;let L=I?Math.min(100,Math.floor(100*A/I)):0;t("save-progress").value=L,t("save-status").textContent=E==="packaging"?"Packing your scene\u2026":L===100?"Finishing your file\u2026":`Saving\u2026 ${L}%`}},_=p()?await s().download_scene({format:k.format,filename:k.filename,signal:k.signal,on_progress:k.on_progress,force_basename:!0}):await s().download_models(k);if(l!==R||c)return;l=null,P(),r(_.filename+" ready to download.")}catch(k){if(l!==R||c)return;l=null,t("save-status").textContent="",k?.name!=="AbortError"&&(t("save-error").textContent=k?.message||"This file could not be saved. Try another format.",t("save-error").hidden=!1)}finally{!c&&(!l||l===R)&&y()}}),h(),y(),{sync:y,close:P,dispose(){P(),c=!0}}}var Zt=["print-button","print-panel","print-close","print-form","print-fields","print-scope","print-level","print-units","print-fdm","print-wall","print-angle","print-bed-x","print-bed-y","print-bed-z","print-run","print-cancel","print-status","print-results","print-clear","print-target"];function Qi({$:t,listen:e,window:i,getState:o,getViewer:s,onOpen:n,announce:r}){let d=null,l=null,c=null,m=!1,f="",b="",p=!1,g=t("print-panel"),h=g.ownerDocument,v=new Set,y={issues_found:"Issues found",incomplete:"Check incomplete",no_issues_found:"No issues found in completed checks"},M=(E,L)=>{let T=h.createElement(E);return T.textContent=L,T},P=()=>t("print-scope").value==="all"?o().models.map(E=>E.id):[o().selectedId],C=()=>JSON.stringify(P()),w=()=>{s()?.clear_printability(),t("print-clear").hidden=!0};function R(){if(m)return;let E=o();if(t("print-button").disabled=E.busy||!E.models.length,g.hidden)return;for(let T of v)(!E.models.some(j=>j.id===T)||s()?.get_model_animation_state(T)?.status!=="paused")&&v.delete(T);t("print-resume")&&(t("print-resume").hidden=!v.size,t("print-resume").disabled=!!d||E.busy),t("print-animation-note")&&(t("print-animation-note").hidden=!v.size);let L=p;p=E.busy||!E.models.length,t("print-run").disabled=!!d||p,b!==C()&&(t("print-units").checked=!1,b=C()),t("print-target").textContent=t("print-scope").value==="all"?`All ${E.models.length} models, checked separately`:E.models.find(T=>T.id===E.selectedId)?.name||"No model selected",d&&(p||f!==C())&&_(),l&&(!s()?.is_printability_current(l)||f!==C())&&(l=null,t("print-units").checked=!1,w(),t("print-results").replaceChildren(),t("print-status").textContent="Model or selection changed. Run the check again."),p?(E.models.length||(l=null,w(),t("print-results").replaceChildren()),t("print-status").textContent=E.busy?"Opening models. Checks will be available when loading finishes.":"Open a model to run a print check."):L&&!d&&(t("print-status").textContent=l?y[l.summary]:"Ready to check. Choose Run check to analyze the current model selection.")}function k(E){let L=[];for(let T of E.models){let j=h.createElement("section");j.append(M("h3",o().models.find(S=>S.id===T.model_id)?.name||T.name)),j.append(M("p",`${T.dimensions_mm?.map(S=>Number(S.toPrecision(5))).join(" \xD7 ")||"Unknown size"} mm \xB7 ${(T.elapsed_ms/1e3).toFixed(2)} s`)),T.volume_valid&&j.append(M("p",`Enclosed volume at current mm scale: ${Number(T.volume_mm3.toPrecision(6))} mm\xB3`));for(let S of T.checks){let F=h.createElement("details");F.dataset.check=S.code,F.dataset.status=S.status;let N={pass:"Passed",issue:S.severity==="info"?"Information":"Review",inconclusive:"Inconclusive",not_run:"Not run"}[S.status];if(F.append(M("summary",`${N} \xB7 ${S.label}${S.count?` (${S.count})`:""}${S.estimated?" \u2014 estimate":""}`)),F.append(M("p",S.message)),S.area_mm2!=null&&F.append(M("p",`Area: ${Number(S.area_mm2.toPrecision(5))} mm\xB2`)),S.minimum_sampled_mm!=null&&F.append(M("p",`Smallest sampled distance: ${Number(S.minimum_sampled_mm.toPrecision(5))} mm`)),S.triangle_ids.length||S.edge_vertices.length){let D=M("button","Show locations");D.type="button",D.dataset.issue=S.code,D.dataset.model=T.model_id,F.append(D),F.append(M("p","Highlights show a bounded sample, including edges hidden behind surfaces."))}j.append(F)}L.push(j)}t("print-results").replaceChildren(...L)}function _(){d?.abort()}function A(E=!0){_(),g.hidden=!0,t("workspace")?.classList.remove("print-check-open"),w(),i.clearInterval(c),c=null,t("print-button").setAttribute("aria-expanded","false"),E&&!m&&(t("print-button").offsetParent&&!t("print-button").disabled?t("print-button"):t("info-button").offsetParent?t("info-button"):t("sample-button"))?.focus()}function I(){_(),l=null,w(),t("print-results").replaceChildren(),t("print-status").textContent="Settings changed. Run the check again.",R()}return e(t("print-button"),"click",()=>{if(!g.hidden){n(),R(),g.scrollTop=0,t("print-run").focus();return}n(),g.hidden=!1,t("workspace")?.classList.add("print-check-open"),t("print-button").setAttribute("aria-expanded","true"),R(),c=i.setInterval(R,400),t("print-run").focus()}),e(t("print-close"),"click",()=>A()),e(g,"keydown",E=>{E.key==="Escape"&&(E.stopPropagation(),E.preventDefault(),A())}),e(t("print-fields"),"change",I),e(t("print-clear"),"click",w),e(t("print-cancel"),"click",_),t("print-resume")&&e(t("print-resume"),"click",()=>{if(!(d||o().busy)){for(let E of v)o().models.some(L=>L.id===E)&&s().get_model_animation_state(E)?.status==="paused"&&s().resume_model_animation(E);v.clear(),l=null,w(),t("print-results").replaceChildren(),t("print-status").textContent="Animation resumed. Pause and run the check again for the new pose.",R()}}),e(t("print-results"),"click",E=>{let L=E.target.closest("button[data-issue]");if(!(!L||!l))try{s().show_printability(l,{issue:L.dataset.issue,model_id:Number(L.dataset.model)}),t("print-clear").hidden=!1}catch(T){t("print-status").textContent=T.message}}),e(t("print-form"),"submit",async E=>{if(E.preventDefault(),d||o().busy||!o().models.length)return;let L=new i.AbortController;d=L,l=null,w(),t("print-results").replaceChildren(),t("print-status").textContent="Checking on your device\u2026",t("print-fields").disabled=!0,t("print-run").disabled=!0,t("print-cancel").hidden=!1;try{let T=null;if(t("print-fdm").checked){T={technology:"fdm"},t("print-wall").value&&(T.min_wall_mm=Number(t("print-wall").value)),t("print-angle").value&&(T.overhang_degrees=Number(t("print-angle").value));let S=["x","y","z"].map(F=>t("print-bed-"+F).value);if(S.some(Boolean)){if(!S.every(Boolean))throw new Error("Enter all three build-volume dimensions, or leave all three empty.");T.build_volume_mm=S.map(Number)}}f=C();for(let S of P())s().get_model_animation_state(S)?.status==="running"&&(s().pause_model_animation(S),v.add(S));R();let j=await s().check_printability({model_ids:P(),level:t("print-level").value,units_confirmed:t("print-units").checked,profile:T,signal:L.signal,on_progress:S=>{d===L&&(t("print-status").textContent=`${S.phase} \xB7 model ${(S.model_index??0)+1} of ${S.total_models}`)}});if(m||L.signal.aborted)return;l=j,k(l),t("print-status").textContent=y[l.summary],r(y[l.summary])}catch(T){m||(t("print-status").textContent=T.name==="AbortError"?"Check cancelled. Your model is unchanged.":T.message)}finally{d===L&&(d=null),m||(t("print-fields").disabled=!1,t("print-run").disabled=!1,t("print-cancel").hidden=!0,R())}}),R(),{sync:R,close:A,dispose(){m=!0,A(!1),l=null,v.clear()}}}var Qt=["animation-details","animation-fields","animation-axis","animation-seconds","animation-direction","animation-play","animation-pause","animation-stop","animation-status","animation-error"],Ye=["x","y","z"];function te(t,e){if(!t||!e?.geometry)return;t.bounds=Object.fromEntries(["min","max"].map(o=>[o,e.geometry.bounds[o].map((s,n)=>(s-e.center[n])*e.scaleVector[n])])),t.rotation=Object.fromEntries(Ye.map(o=>[o,e["rotation"+o]*180/Math.PI%360])),t.position={x:0,y:0,z:0};let i=Be(t);for(let o of Ye)t.position[o]=e[o]-i[o]}function $i(t,e){te(t,e);let i=e.geometry.bounds.min.map((r,d)=>(r+e.geometry.bounds.max[d])/2),o=i.map((r,d)=>(r-e.center[d])*e.scaleVector[d]),s=je(t.rotation),n=t.originalPosition||{x:0,y:0,z:0};t.originalPosition=Object.fromEntries(Ye.map((r,d)=>[r,n[r]+o[d]]));for(let r=0;r<3;r++)e[Ye[r]]+=o.reduce((d,l,c)=>d+s[r*3+c]*l,0);e.center=i,t.animationPivot=!0,te(t,e)}function So(t,e,i){if(!Ye.includes(t)||!Number.isFinite(e)||e<.1||e>3600||!["1","-1"].includes(i))throw new Error("Choose an axis and a duration from 0.1 to 3,600 seconds.");return{delta:{["rotation"+t]:2*Math.PI*Number(i),msec:e*1e3,loop:!0}}}function eo({$:t,listen:e,window:i,getState:o,getViewer:s,beforePlay:n,refreshPose:r,announce:d}){let l=new Map,c=null,m=null,f=!1,b=()=>{let h=o();return{...h,playback:h.selectedId==null?null:s()?.get_model_animation_state(h.selectedId)}};function p(){if(f)return;let h=b(),v=h.models.some(w=>w.id===h.selectedId);for(let w of l.keys())h.models.some(R=>R.id===w)||l.delete(w);if(t("animation-details").hidden=!v,t("animation-fields").disabled=h.busy||!v,c!==h.selectedId){c=h.selectedId;let w=l.get(c);if(!w){w={axis:"z",seconds:5,direction:"1"};let R=s()?._models.get(c)?.animation,k=Object.entries(R?.delta||{}).filter(([_,A])=>_.startsWith("rotation")&&A!==0);R?.delta?.loop&&!R.exact&&k.length===1&&(w={axis:k[0][0].slice(-1),seconds:R.delta.msec*2*Math.PI/Math.abs(k[0][1])/1e3,direction:k[0][1]<0?"-1":"1"}),l.set(c,w)}t("animation-axis").value=w.axis,t("animation-seconds").value=w.seconds,t("animation-direction").value=w.direction,t("animation-error").hidden=!0}let y=h.playback?.status||"idle",M=["running","paused"].includes(y);t("animation-play").textContent=M?"Restart spin":"Play",t("animation-pause").textContent=y==="paused"?"Resume":"Pause",t("animation-pause").disabled=!M,t("animation-stop").disabled=!M;let C=`${{idle:"Ready",running:"Playing",paused:"Paused",stopped:"Stopped",completed:"Finished"}[y]}. ${M?"Stop keeps the current pose.":"Spin the selected model around its center."}`;t("animation-status").textContent!==C&&(t("animation-status").textContent=C),y==="running"&&!m&&(m=i.setInterval(()=>{!f&&!i.document.hidden&&r()},250)),y!=="running"&&m&&(i.clearInterval(m),m=null)}function g(h=!1){let v=b();if(!(v.busy||v.selectedId==null))try{let y={axis:t("animation-axis").value,seconds:t("animation-seconds").valueAsNumber,direction:t("animation-direction").value},M=So(y.axis,y.seconds,y.direction);n(v.selectedId),s().animate_model(v.selectedId,M),h&&v.playback?.status==="paused"&&s().pause_model_animation(v.selectedId),l.set(v.selectedId,y),t("animation-error").hidden=!0,d(h&&v.playback?.status==="paused"?"Spin updated. Still paused.":"Animation playing."),p()}catch(y){t("animation-error").textContent=y.message,t("animation-error").hidden=!1}}e(t("animation-play"),"click",()=>g()),e(t("animation-pause"),"click",()=>{let h=b();h.busy||h.selectedId==null||(s()[h.playback?.status==="paused"?"resume_model_animation":"pause_model_animation"](h.selectedId),p())}),e(t("animation-stop"),"click",()=>{let h=b();!h.busy&&h.selectedId!=null&&s().animate_model(h.selectedId,null),p()});for(let h of["animation-axis","animation-seconds","animation-direction"])e(t(h),"change",()=>{["running","paused"].includes(b().playback?.status)?g(!0):l.set(c,{axis:t("animation-axis").value,seconds:t("animation-seconds").valueAsNumber,direction:t("animation-direction").value})});return p(),{sync:p,dispose(){f=!0,i.clearInterval(m),l.clear()}}}var Io=`#version 300 es
1
+ //=========== Stl Viewer v2.0.0-rc.7, by Omri Rips, Viewstl.com, November 2026 ; admin@viewstl.com ===========
2
+ (()=>{var Vt=["size-details","size-fields","size-x","size-y","size-z","size-lock","size-percent","size-apply","size-cancel","size-reset","size-error","file-units","file-units-note","display-units","size-unit-label","duplicate-model","camera-preset","bookmark-name","bookmark-list","bookmark-save","bookmark-restore","bookmark-rename","bookmark-delete","camera-error","info-area","info-volume","measure-model","measure-cancel","measure-status"],Be=["x","y","z"],Ei=new Intl.NumberFormat(void 0,{maximumSignificantDigits:7});function Mi({$:t,listen:e,window:i,getViewer:o,getState:s,changeSize:n,duplicate:r,refresh:d,announce:l}){let c=null,m=0,f=null,b=null,_=null,p=!1,h=(k,g="")=>{t(k).textContent=g,t(k).hidden=!g},w=()=>o()?.display_units==="inch"?25.4:1,y=k=>Number(k.toPrecision(10));function M(){let k=o(),{selectedId:g,busy:A}=s(),I=k?._models.get(g),E=I?.scaleVector,L=I?._measurements,T=L&&L.positions===I.geometry.positions&&L.key===E.join(","),D=w()===1?"mm":"in",S=T?L.result.area_mm2:E&&E[0]===E[1]&&E[1]===E[2]?I.geometry.area*E[0]**2:null;t("info-area").textContent=S==null?"Calculate":Ei.format(S/w()**2)+" "+D+"\xB2",t("info-volume").textContent=T?L.result.volume_valid?Ei.format(L.result.volume_mm3/w()**3)+" "+D+"\xB3":"Unavailable":"Not checked",_||(t("measure-status").textContent=T?L.result.volume_reason:"Calculate to check enclosed volume. Runs on your device."),t("measure-model").disabled=A||!I||!!_,t("measure-cancel").hidden=!_}function P(){let k=o(),g=t("bookmark-list").value,A=k?.get_camera_bookmarks()||[];t("bookmark-list").replaceChildren(...A.map(I=>{let E=i.document.createElement("option");return E.value=I.name,E.textContent=I.name,E})),A.some(I=>I.name===g)&&(t("bookmark-list").value=g);for(let I of["bookmark-restore","bookmark-rename","bookmark-delete","bookmark-list"])t(I).disabled=!A.length;t("bookmark-save").disabled=!k||A.length>=32}function C(){if(p)return;let{selectedId:k,busy:g}=s(),A=o(),I=A?._models.get(k);k!==b&&(_?.abort(),b=k),c=null,f=I?.geometry?A.get_model_size(k):null,t("size-fields").disabled=g||!f,t("duplicate-model").disabled=g||!f,t("display-units").value=A?.display_units||"mm",t("size-unit-label").textContent=w()===1?"Dimensions in mm":"Dimensions in inches",t("file-units").value=f?.file_units||"mm",t("file-units").disabled=g||!f?.editable,t("file-units-note").textContent=f?.editable?"STL/OBJ have no units. Millimetres are assumed; choose inches to correct the physical size.":"Explicit file units were converted to millimetres on import.",Be.forEach((L,T)=>{t("size-"+L).value=f?y(f.dimensions_mm[T]/w()):"",t("size-"+L).disabled=!f||f.dimensions_mm[T]===0});let E=f?.baseline_mm.map((L,T)=>L?f.dimensions_mm[T]/L:null).filter(L=>L!=null)||[];t("size-percent").value=E.length&&E.every(L=>Math.abs(L/E[0]-1)<1e-8)?y(E[0]*100):"",h("size-error"),M(),P()}let v=(k,g)=>{try{g(),h(k)}catch(A){h(k,A.message)}};Be.forEach((k,g)=>e(t("size-"+k),"input",()=>{if(!f)return;c="axis",m=g;let A=t("size-"+k).valueAsNumber;!Number.isFinite(A)||A<=0||(t("size-lock").checked&&Be.forEach((I,E)=>{g!==E&&(t("size-"+I).value=y(A*f.dimensions_mm[E]/f.dimensions_mm[g]))}),t("size-percent").value="")})),e(t("size-percent"),"input",()=>{c="percent";let k=t("size-percent").valueAsNumber;f&&Number.isFinite(k)&&k>0&&Be.forEach((g,A)=>t("size-"+g).value=y(f.baseline_mm[A]*k/100/w()))}),e(t("size-apply"),"click",()=>v("size-error",()=>{if(!f||!c)return;let k=o().get_model_size(b).dimensions_mm,g=Be.map(I=>t("size-"+I).valueAsNumber*w());if(c==="percent"){let I=t("size-percent").valueAsNumber;if(!Number.isFinite(I)||I<=0)throw new Error("Enter a positive scale percentage.");g=f.baseline_mm.map(E=>E*I/100)}else if(t("size-lock").checked){let I=g[m]/f.dimensions_mm[m];g=f.dimensions_mm.map(E=>E*I)}let A=g.map((I,E)=>{if(!Number.isFinite(I)||I<0||k[E]>0&&I===0)throw new Error("Enter positive dimensions for each non-flat axis.");return k[E]?I/k[E]:1});A.every(I=>Math.abs(I/A[0]-1)<1e-12)&&(A=A.map(()=>A[0])),n(()=>o().resize_model(b,A)),l("Model size updated.")})),e(t("size-cancel"),"click",C),e(t("size-reset"),"click",()=>v("size-error",()=>{n(()=>o().reset_model_size(b)),l("Original size restored; file-unit correction retained.")})),e(t("file-units"),"change",()=>v("size-error",()=>{n(()=>o().set_file_units(b,t("file-units").value)),l("File units corrected.")})),e(t("display-units"),"change",()=>{o()?.set_display_units(t("display-units").value),d()}),e(t("duplicate-model"),"click",()=>v("size-error",r)),e(t("camera-preset"),"change",()=>v("camera-error",()=>{t("camera-preset").value&&o().set_camera_view(t("camera-preset").value),l("Camera view updated."),t("camera-preset").value=""}));let R=k=>v("camera-error",()=>{let g=o(),A=g.get_camera_bookmarks();k(A,g),g.set_camera_bookmarks(A),P()});return e(t("bookmark-save"),"click",()=>R((k,g)=>{k.push({name:t("bookmark-name").value,camera:g.get_camera_state()})})),e(t("bookmark-rename"),"click",()=>R(k=>{k.find(g=>g.name===t("bookmark-list").value).name=t("bookmark-name").value})),e(t("bookmark-delete"),"click",()=>R(k=>{k.splice(k.findIndex(g=>g.name===t("bookmark-list").value),1)})),e(t("bookmark-restore"),"click",()=>v("camera-error",()=>{let k=o().get_camera_bookmarks().find(g=>g.name===t("bookmark-list").value);k&&(o().set_camera_state(k.camera),l("Saved view restored."))})),e(t("bookmark-list"),"change",()=>t("bookmark-name").value=t("bookmark-list").value),e(t("measure-cancel"),"click",()=>_?.abort()),e(t("measure-model"),"click",async()=>{let k=b,g=o(),A=new i.AbortController;_=A,M(),t("measure-status").textContent="Calculating area and checking volume\u2026";try{await g.measure_model(k,{signal:A.signal,on_progress:I=>{b===k&&!p&&(t("measure-status").textContent=I.phase+"\u2026")}}),!p&&b===k&&l("Measurements ready.")}catch(I){!p&&b===k&&(t("measure-status").textContent=I.name==="AbortError"?"Calculation cancelled.":I.message)}finally{let I=t("measure-status").textContent;_===A&&(_=null),p||(M(),!g._models.get(k)?._measurements&&b===k&&(t("measure-status").textContent=I))}}),{sync:C,syncInfo:M,dispose(){p=!0,_?.abort()}}}function zi(t){let e=typeof t=="number"&&Number.isFinite(t)&&t>=.25&&t<=128,i=(e?t:2)*1073741824,o=Math.floor(i/2);return{budget:o,reported:e,estimated:i,limits:{max_memory_bytes:o,max_file_bytes:Math.floor(o/3),max_triangles:Math.max(1,Math.floor((o-64*1048576)/224)),max_uncompressed_bytes:Math.max(1,Math.floor((o-64*1048576)/4))}}}async function Ai(t){if(/\.(step|stp|iges|igs)$/i.test(t.name))return 128*1048576+(t.size||0)*40;if(/\.stl$/i.test(t.name)&&t.size>=84&&t.slice){let e=await t.slice(0,84).arrayBuffer(),i=new DataView(e).getUint32(80,!0);if(i&&84+i*50===t.size)return 64*1048576+i*224}return 64*1048576+(t.size||0)*3}var mt=["x","y","z"],Ue=t=>mt.map(e=>t[e]),Gt=t=>Object.fromEntries(mt.map((e,i)=>[e,t[i]])),Ci=(t,e)=>t.reduce((i,o,s)=>i+o*e[s],0),Ri=t=>{let e=Math.hypot(...t)||1;return t.map(i=>i/e)},Si=(t,e)=>Array.from({length:9},(i,o)=>[0,1,2].reduce((s,n)=>s+t[Math.floor(o/3)*3+n]*e[n*3+o%3],0)),Pi=(t,e)=>[0,1,2].map(i=>Ci(t.slice(i*3,i*3+3),e));function Ve(t={x:0,y:0,z:0}){let[e,i,o]=Ue(t).map(m=>m%360*Math.PI/180),s=Math.cos(e),n=Math.sin(e),r=Math.cos(i),d=Math.sin(i),l=Math.cos(o),c=Math.sin(o);return[r*l,-r*c,d,s*c+n*l*d,s*l-n*d*c,-n*r,n*c-s*l*d,n*l+s*d*c,s*r]}var qt=t=>t.min.map((e,i)=>(e+t.max[i])/2);function Li(t){return Gt(qt(t.bounds).map((e,i)=>e+t.position[mt[i]]))}function Ti(t){return Math.max(Math.hypot(...t.bounds.max.map((e,i)=>e-t.bounds.min[i]))/2,1e-6)}function Ge(t){let e=qt(t.bounds),i=Pi(Ve(t.rotation),e);return Gt(e.map((o,s)=>t.position[mt[s]]+o-i[s]))}function Ht(t){if(!t.rotation||!Object.values(t.rotation).some(n=>n%360))return t.bounds;let e=qt(t.bounds),i=Ve(t.rotation),o=[1/0,1/0,1/0],s=[-1/0,-1/0,-1/0];for(let n=0;n<8;n++)Pi(i,e.map((d,l)=>t.bounds[n&1<<l?"max":"min"][l]-d)).forEach((d,l)=>{o[l]=Math.min(o[l],d+e[l]),s[l]=Math.max(s[l],d+e[l])});return{min:o,max:s}}function Ii(t,e){let[i,o,s]=Ri(t),n=Math.cos(e),r=Math.sin(e),d=1-n;return[d*i*i+n,d*i*o-r*s,d*i*s+r*o,d*i*o+r*s,d*o*o+n,d*o*s-r*i,d*i*s-r*o,d*o*s+r*i,d*s*s+n]}function Fi(t,e,i,o,s){let n=Math.PI/Math.max(1,s),r=Si(Ii(e.right,o*n),Si(Ii(e.up,i*n),Ve(t))),d=Math.asin(Math.max(-1,Math.min(1,r[2]))),l=Math.abs(Math.cos(d))>1e-10;return{x:(l?Math.atan2(-r[5],r[8]):Math.atan2(r[7],r[4]))*180/Math.PI,y:d*180/Math.PI,z:(l?Math.atan2(-r[1],r[0]):0)*180/Math.PI}}function qe(t,e,i){if(i===0)return{...t.position};let o=Ue(e.position),s=Ue(t.center),n=s.map((b,_)=>b-o[_]),r=Ri(Ue(e.target).map((b,_)=>b-o[_])),d=Math.hypot(...n),l=d>1e-9?n.map(b=>b/d):r,c=Math.max(t.radius||1e-6,1e-6)*1.1/Math.max(.05,Ci(l,r)),m=(d||c)*Math.exp(Math.max(-6,Math.min(6,i))),f=i<0?Math.max(Math.min(d,c),m):Math.max(d,Math.min(1e12,m));return Gt(Ue(t.position).map((b,_)=>b+l[_]*(f-d)))}function Ni(t,e){if(e==="custom")return t.map(n=>({id:n.id,...n.position||{x:0,y:0,z:0}}));if(e==="original")return t.map(n=>({id:n.id,...n.originalPosition||{x:0,y:0,z:0}}));t=t.map(n=>({...n,bounds:Ht(n)}));let i=t.map(n=>n.bounds.max[0]-n.bounds.min[0]),o=t.reduce((n,r)=>Math.max(n,...r.bounds.max.map((d,l)=>d-r.bounds.min[l])),1)*.12,s=-(i.reduce((n,r)=>n+r,0)+o*Math.max(0,t.length-1))/2;return t.map((n,r)=>{let d={id:n.id,x:s-n.bounds.min[0],y:-(n.bounds.min[1]+n.bounds.max[1])/2,z:-n.bounds.min[2]};return s+=i[r]+o,d})}function Oi(t,e){let i=new Map(e.map(o=>[o.id,o.z]));return t.length?t.reduce((o,s)=>Math.min(o,Ht(s).min[2]+(i.get(s.id)||0)),1/0):0}var ut=t=>[t.x,t.y,t.z],Di=(t,e)=>t.map((i,o)=>i-e[o]),Ao=(t,e)=>t.reduce((i,o,s)=>i+o*e[s],0),Wt=(t,e)=>[t[1]*e[2]-t[2]*e[1],t[2]*e[0]-t[0]*e[2],t[0]*e[1]-t[1]*e[0]],Yt=t=>{let e=Math.hypot(...t);return t.map(i=>i/(e||1))};function So(t,e,i){let o=ut(t.position),s=ut(t.target),n=Yt(Di(o,s)),r=Yt(Wt(ut(t.up),n));Math.hypot(...r)<.5&&(r=Yt(Wt(Math.abs(n[1])<.9?[0,1,0]:[1,0,0],n)));let d=Wt(n,r),l=Ao(Di(o,ut(e)),n),c=2*Math.max(l,1e-6)*Math.tan(Math.PI/8)/Math.max(i,1);return{right:r,up:d,scale:c}}function Io(t,e,i,o){return Object.fromEntries(["x","y","z"].map((s,n)=>[s,t[s]+(e.right[n]*i-e.up[n]*o)*e.scale]))}function ji(t,{getModel:e,getCamera:i,getTool:o=()=>"move",onMove:s,onRotate:n,onStart:r,onEnd:d}){let l=!1,c=null,m=new Set,f=[],b=(h,w)=>{t.addEventListener(h,w,{capture:!0,passive:!1}),f.push(()=>t.removeEventListener(h,w,!0))},_=h=>{h.preventDefault(),h.stopImmediatePropagation()},p=(h=!1)=>{if(!c)return;let w=c;c=null,h&&(w.tool==="rotate"?n?.(w.id,w.rotation):s(w.id,w.position)),t.classList.remove("moving-model"),t.hasPointerCapture(w.pointer)&&t.releasePointerCapture(w.pointer),d?.(w.id,h)};b("pointerdown",h=>{if(!l||h.button!==0||h.shiftKey)return;if(_(h),c||h.isPrimary===!1){m.add(h.pointerId);return}let w=e();w&&(c={tool:o(),rotation:{...w.rotation||{x:0,y:0,z:0}},model:{...w,position:{...w.position},center:{...w.center}},camera:i(),height:t.getBoundingClientRect().height,id:w.id,position:{...w.position},pointer:h.pointerId,x:h.clientX,y:h.clientY,basis:So(i(),w.center,t.getBoundingClientRect().height)},r?.(w.id),t.setPointerCapture(h.pointerId),t.classList.add("moving-model"),t.focus({preventScroll:!0}))}),b("pointermove",h=>{if(m.has(h.pointerId)){_(h);return}if(!c||c.pointer!==h.pointerId)return;_(h);let w=h.clientX-c.x,y=h.clientY-c.y;c.tool==="rotate"?n?.(c.id,Fi(c.rotation,c.basis,w,y,c.height)):c.tool==="depth"?s(c.id,qe(c.model,c.camera,y*3/Math.max(1,c.height))):s(c.id,Io(c.position,c.basis,w,y))});for(let h of["pointerup","pointercancel","lostpointercapture"])b(h,w=>{if(m.delete(w.pointerId)){_(w);return}!c||c.pointer!==w.pointerId||(_(w),p(h!=="pointerup"))});b("wheel",h=>{if(!l||(_(h),c))return;let w=e();if(!w)return;let y=h.deltaY*(h.deltaMode===1?16:h.deltaMode===2?t.getBoundingClientRect().height:1);s(w.id,qe(w,i(),Math.max(-.5,Math.min(.5,y*.0015))))});for(let h of["keydown","dblclick"])b(h,w=>{c&&w.key!=="Escape"&&_(w)});return{setEnabled(h){p(!0),m.clear(),l=h,t.classList.toggle("model-move-ready",h)},dispose(){p(!0),f.forEach(h=>h())}}}function Jt(t){let e=Array.from(t?.types||[],i=>i.toLowerCase());return e.includes("files")||t?.files?.length?"files":e.includes("text/uri-list")||e.includes("text/x-moz-url")?"url":e.includes("text/plain")?"text":null}function Bi(t){if(Jt(t)==="files")return[];let e=t?.getData("text/uri-list")?.trim(),i=!e&&t?.getData("text/x-moz-url")?.trim(),o=!e&&!i&&t?.getData("text/plain")?.trim(),s;if(e)s=e.split(/\r?\n/).map(r=>r.trim()).filter(r=>r&&!r.startsWith("#"));else if(i)s=[i.split(/\r?\n/)[0]];else if(o){if(s=o.split(/\r?\n/).map(r=>r.trim()).filter(Boolean),!s.every(r=>/^https?:\/\/\S+$/i.test(r)))return[]}else return[];let n=new Set;for(let r of s){let d;try{d=new URL(r)}catch{}if(!d||!["https:","http:"].includes(d.protocol)||d.username||d.password)throw new Error("Drop a public HTTP or HTTPS file URL without login credentials.");d.hash="",n.add(d.href)}return[...n]}var ce=(t,e)=>t.map((i,o)=>i+e[o]),H=(t,e)=>t.map((i,o)=>i-e[o]),ae=(t,e)=>t.map(i=>i*e),se=(t,e)=>t[0]*e[0]+t[1]*e[1]+t[2]*e[2],le=(t,e)=>[t[1]*e[2]-t[2]*e[1],t[2]*e[0]-t[0]*e[2],t[0]*e[1]-t[1]*e[0]],Y=t=>ae(t,1/(Math.hypot(...t)||1));function He(t,e){let i=new Float64Array(16);for(let o=0;o<4;o++)for(let s=0;s<4;s++)for(let n=0;n<4;n++)i[o*4+s]+=t[n*4+s]*e[o*4+n];return i}function Q(t,e,i=1){let o=t[3]*e[0]+t[7]*e[1]+t[11]*e[2]+t[15]*i;return[0,1,2].map(s=>(t[s]*e[0]+t[4+s]*e[1]+t[8+s]*e[2]+t[12+s]*i)/(i&&o?o:1))}function Co(t,e,i){let o=Math.cos(t),s=Math.sin(t),n=Math.cos(e),r=Math.sin(e),d=Math.cos(i),l=Math.sin(i);return new Float64Array([n*d,o*l+s*d*r,s*l-o*d*r,0,-n*l,o*d-s*l*r,s*d+o*l*r,0,r,-s*n,o*n,0,0,0,0,1])}function J(t){let e=Co(t.rotationx,t.rotationy,t.rotationz),i=t.scaleVector;for(let s=0;s<3;s++)for(let n=0;n<3;n++)e[s*4+n]*=i[s];let o=t.center||[0,0,0];for(let s=0;s<3;s++)e[12+s]=[t.x,t.y,t.z][s]-e[s]*o[0]-e[4+s]*o[1]-e[8+s]*o[2];return e}function ke(t){let e=Array.from({length:4},(i,o)=>[...Array.from({length:4},(s,n)=>t[n*4+o]),...Array.from({length:4},(s,n)=>+(n===o))]);for(let i=0;i<4;i++){let o=i;for(let n=i+1;n<4;n++)Math.abs(e[n][i])>Math.abs(e[o][i])&&(o=n);if(Math.abs(e[o][i])<1e-30)throw new Error("Singular transform");[e[o],e[i]]=[e[i],e[o]];let s=e[i][i];e[i]=e[i].map(n=>n/s);for(let n=0;n<4;n++)if(n!==i){let r=e[n][i];e[n]=e[n].map((d,l)=>d-r*e[i][l])}}return new Float64Array(Array.from({length:16},(i,o)=>e[o%4][4+Math.floor(o/4)]))}function ht(t,e){let i=Y(H(t.position,t.target)),o=Y(le(t.up,i));Math.hypot(...o)<.5&&(o=Y(le(Math.abs(i[1])<.9?[0,1,0]:[1,0,0],i)));let s=le(i,o),n=t.position,r=new Float64Array([o[0],s[0],i[0],0,o[1],s[1],i[1],0,o[2],s[2],i[2],0,-se(o,n),-se(s,n),-se(i,n),1]),d=1/Math.tan(Math.PI/8),l=t.near,c=t.far,m=new Float64Array([d/e,0,0,0,0,d,0,0,0,0,(c+l)/(l-c),-1,0,0,2*c*l/(l-c),0]);return He(m,r)}function ft(t,e,i){let o=Y(e),s=Math.cos(i),n=Math.sin(i);return ce(ce(ae(t,s),ae(le(o,t),n)),ae(o,se(o,t)*(1-s)))}function Xt(t,e,i,o){let s=0,n=1/0;for(let r=0;r<3;r++){if(Math.abs(e[r])<1e-15){if(t[r]<i[r]||t[r]>o[r])return!1;continue}let d=(i[r]-t[r])/e[r],l=(o[r]-t[r])/e[r];if(d>l&&([d,l]=[l,d]),s=Math.max(s,d),n=Math.min(n,l),n<s)return!1}return!0}function Ui(t,e,i,o){let s=[i[o],i[o+1],i[o+2]],n=H([i[o+3],i[o+4],i[o+5]],s),r=H([i[o+6],i[o+7],i[o+8]],s),d=le(e,r),l=se(n,d);if(Math.abs(l)<1e-12)return 1/0;let c=H(t,s),m=se(c,d)/l;if(m<0||m>1)return 1/0;let f=le(c,n),b=se(e,f)/l;if(b<0||m+b>1)return 1/0;let _=se(r,f)/l;return _>=0?_:1/0}var We=["x","y","z","rotationx","rotationy","rotationz","scalex","scaley","scalez"],de=t=>t.startsWith("scale"),fe=(t,e,i=!1)=>{if(typeof t!="number"||!Number.isFinite(t)||Math.abs(t)>Number.MAX_SAFE_INTEGER||i&&t<=0)throw new Error(`Invalid animation ${e}`);return t},pt=(t,e)=>{if(!t||typeof t!="object"||Array.isArray(t))throw new Error(`Invalid animation ${e}`);return t};function Vi(t){return Object.fromEntries(We.map(e=>[e,fe(t[e]??(de(e)?t.scale??1:0),e,de(e))]))}function Ye(t){pt(t,"definition");let e={},i=new Set;for(let o of["delta","exact"]){if(t[o]==null)continue;let s=pt(t[o],o),n={},r=fe(s.msec??300,"duration",!0);if(s.loop!==void 0&&typeof s.loop!="boolean")throw new Error("Animation loop must be a boolean");let d=o==="delta"&&!!s.loop;for(let l of We){let c=s[l]??(de(l)?s.scale:void 0);if(c!==void 0){if(i.has(l))throw new Error(`Animation delta/exact conflict: ${l}`);if(fe(c,l,o==="exact"&&de(l)),d&&de(l)&&c<0)throw new Error("Looping scale deltas cannot be negative");n[l]=c,i.add(l)}}if(!Object.keys(n).length)throw new Error("Animation track needs a transform");e[o]={...n,msec:r,...d?{loop:!0}:{}}}if(!Object.keys(e).length)throw new Error("Animation needs delta or exact");return e}function Je(t){if(pt(t,"playback state"),t.version!==1||typeof t.paused!="boolean")throw new Error("Invalid animation playback state version or paused flag");let e=fe(t.elapsed_ms,"elapsed time");if(e<0)throw new Error("Invalid animation elapsed time");pt(t.origin,"origin");for(let i of We)fe(t.origin[i],i,de(i));if(!Array.isArray(t.center)||t.center.length!==3)throw new Error("Invalid animation pivot");return{version:1,elapsed_ms:e,paused:t.paused,origin:Vi(t.origin),center:t.center.map(i=>fe(i,"pivot"))}}function Xe(t,e,i){let o=Ye(t),s=i==null?null:Je(i),n=s?.origin??Vi(e),r=Object.entries(o).map(([l,c])=>{let m=Object.entries(c).filter(([f])=>We.includes(f));if(l==="delta")for(let[f,b]of m)fe(n[f]+b,`${f} endpoint`,de(f));return{mode:l,values:m,duration:c.msec,loop:!!c.loop,done:!1}}),d={animation:o,origin:n,tracks:r,elapsed_ms:s?.elapsed_ms??0,paused:s?.paused??!1,last_time:null};return _t({...d,tracks:r.map(l=>({...l}))},{}),d}function _t(t,e){let i=[];for(let s of t.tracks){if(s.done)continue;let n=t.elapsed_ms/s.duration,r=s.loop?n:Math.min(n,1);for(let[d,l]of s.values){let c=t.origin[d],m=s.mode==="delta"?c+l*r:c*(1-r)+l*r;i.push([d,fe(m,`${d} result`,de(d))])}}let o=!1;for(let[s,n]of i)o||=de(s)&&e[s]!==n,e[s]=n;for(let s of t.tracks)!s.loop&&t.elapsed_ms>=s.duration&&(s.done=!0);return o&&(e._stats=null),t.tracks.some(s=>!s.done)}function Gi(t,e,i){return t.paused?!0:(t.last_time!==null&&(t.elapsed_ms=fe(t.elapsed_ms+Math.max(0,i-t.last_time),"elapsed time")),t.last_time=i,_t(t,e))}function qi(t,e=!1){return{status:t.paused?"paused":"running",elapsed_ms:t.elapsed_ms,suspended:e,tracks:t.tracks.filter(i=>!i.done).map(i=>({mode:i.mode,msec:i.duration,loop:i.loop,progress:i.loop?t.elapsed_ms%i.duration/i.duration:Math.min(1,t.elapsed_ms/i.duration)}))}}function gt(t){let e=t._animation;if(!e)return null;let i=t.unitScale??1,o=structuredClone(e.animation),s={...e.origin};for(let r of We.filter(de)){s[r]*=i;for(let d of Object.values(o))d[r]!==void 0&&(d[r]*=i)}let n=Je({version:1,origin:s,elapsed_ms:e.elapsed_ms,paused:e.paused,center:[...t.center]});return{animation:Ye(o),animation_state:n}}function Ke(t){return t?t.triangles*224+(t.smoothNormals?.byteLength||0)*4+((t.edges?.byteLength||0)+(t.wire?.byteLength||0))*2:0}function X(t,e,i="model"){if(e>(t.max_memory_bytes??Number.MAX_SAFE_INTEGER))throw new Error(`Estimated memory for this ${i} exceeds the device safety budget. Use a smaller model or a device with more memory.`)}function Hi(t,e){return 67108864+t*(224+(e.smooth?1536:0)+(e.edges||e.wire?2048:0))}function Wi(t={}){let e=t.level??"basic";if(!["basic","detailed"].includes(e))throw new Error("Choose basic or detailed print checks");let i=(n,r,d=1e9)=>{if(!Number.isFinite(n)||n<=0||n>d)throw new Error(`Invalid ${r}`);return n},o=null;if(t.profile!=null){if(t.profile.technology!=="fdm")throw new Error("Only FDM profiles are supported");o={technology:"fdm"};for(let n of["min_wall_mm","line_width_mm"])t.profile[n]!=null&&(o[n]=i(t.profile[n],n));if(t.profile.overhang_degrees!=null&&(o.overhang_degrees=i(t.profile.overhang_degrees,"overhang angle",89.9)),t.profile.build_volume_mm!=null){if(!Array.isArray(t.profile.build_volume_mm)||t.profile.build_volume_mm.length!==3)throw new Error("Build volume requires X, Y and Z");o.build_volume_mm=t.profile.build_volume_mm.map(n=>i(n,"build volume"))}}let s=i(t.max_time_ms??3e4,"check time limit",12e4);return{level:e,profile:o,apply_transforms:t.apply_transforms!==!1,units_confirmed:t.units_confirmed===!0,max_time_ms:s}}var yt=t=>64*1024**2+t*2400,be=t=>JSON.stringify([t.x,t.y,t.z,t.rotationx,t.rotationy,t.rotationz,t.scaleVector,t.center,t.units,t.unitScale]);var pe=["x","y","z"];function Pe(t){if(!["mm","inch"].includes(t))throw new Error("Choose mm or inch");return t}function Kt(t){if(!t||t.version!==1||!Array.isArray(t.baseline_mm)||t.baseline_mm.length!==3||t.baseline_mm.some(e=>!Number.isFinite(e)||e<0||e>1e12)||typeof t.editable!="boolean"||t.unit_factor!==void 0&&(!Number.isFinite(t.unit_factor)||t.unit_factor<=0||t.unit_factor>1e12))throw new Error("Invalid saved model size");return{version:1,baseline_mm:[...t.baseline_mm],file_units:Pe(t.file_units),editable:t.editable,unit_factor:t.unit_factor??1}}function Le(t){return t.size_state??={version:1,baseline_mm:t.geometry.bounds.max.map((e,i)=>(e-t.geometry.bounds.min[i])*t.unitScale),file_units:"mm",editable:!t.geometry.units,unit_factor:1}}function Ee(t){if(!t.geometry)throw new Error("Wait for the model to finish opening");let e=Le(t);return{...structuredClone(e),dimensions_mm:t.geometry.bounds.max.map((i,o)=>(i-t.geometry.bounds.min[o])*t.scaleVector[o])}}function bt(t,e){let i=this._model(t);if(Ee(i),!Array.isArray(e)||e.length!==3||e.some(c=>!Number.isFinite(c)||c<=0))throw new Error("Scale must be a positive finite number");let o=pe.map((c,m)=>i["scale"+c]*e[m]);if(o.some(c=>!Number.isFinite(c)||c<1e-12||c>1e12))throw new Error("Scale is outside the supported range");let s=i.geometry.bounds.min.map((c,m)=>(c+i.geometry.bounds.max[m])/2),n=Q(J(i),s),r=i._measurements,d=i.scaleVector.join(",");this._stopAnimation(i,"manual"),pe.forEach((c,m)=>i["scale"+c]=o[m]);let l=Q(J(i),s);return pe.forEach((c,m)=>i[c]+=n[m]-l[m]),i._stats=null,r?.key===d&&r.positions===i.geometry.positions&&e.every(c=>c===e[0])&&(i._measurements={...r,key:i.scaleVector.join(","),result:{...r.result,area_mm2:r.result.area_mm2*e[0]**2,volume_mm3:r.result.volume_mm3==null?null:r.result.volume_mm3*e[0]**3}}),this._invalidate(),Ee(i)}function Yi(t,e){Pe(e);let i=this._model(t),o=Le(i);if(!o.editable)throw new Error("This model has explicit file units, already converted to millimetres");if(o.file_units===e)return Ee(i);let s=e==="inch"?25.4:1/25.4,n=bt.call(this,t,[s,s,s]);return o.baseline_mm=o.baseline_mm.map(r=>r*s),o.file_units=e,o.unit_factor=(o.unit_factor??1)*s,{...n,...structuredClone(o)}}function Ji(t){let e=Ee(this._model(t));return bt.call(this,t,e.dimensions_mm.map((i,o)=>i?e.baseline_mm[o]/i:1))}function Xi(t){let e=this._model(t);if(Ee(e),e._sceneImportPending)throw new Error("Wait for the scene to finish opening");if(this._models.size+1>this.limits.max_archive_entries||[...this._models.values()].reduce((s,n)=>s+(n.geometry?.triangles||0),e.geometry.triangles)>this.limits.max_triangles)throw new Error("Scene model or triangle limit exceeded");X(this.limits,this._occupiedMemory()+Ke(e.geometry),"duplicate");let i={};for(let s of["filename","orig_filename","local_file","x","y","z","rotationx","rotationy","rotationz","opacity","units","display","view_edges","smooth_shading","color"])i[s]=e[s];if(i.id=this.max_model_id+1,!Number.isSafeInteger(i.id))throw new Error("Model ID limit exceeded");i.display_name=(e.display_name||e.orig_filename||e.filename||"Model").split(/[\\/]/).pop()+" \u2014 copy",i.center=[...e.center],i.unitScale=1,pe.forEach((s,n)=>i["scale"+s]=e.scaleVector[n]),Object.defineProperty(i,"scaleVector",{get:()=>pe.map(s=>i["scale"+s]*i.unitScale)}),i.geometry={...e.geometry},i.section=e.section?{...e.section}:null,i.size_state=structuredClone(Le(e)),i.size_state.unit_factor=(i.size_state.unit_factor??1)*e.unitScale;let o=gt(e);return this.max_model_id=i.id,this._models.set(i.id,i),this.models_ref[i.id]=this.models.length,this.models.push(i),this.models_count=this._models.size,o&&this._startAnimation(i,o.animation,{...o.animation_state,paused:!0}),this._invalidate(),i.id}var Ro={front:[[0,-1,0],[0,0,1]],back:[[0,1,0],[0,0,1]],left:[[-1,0,0],[0,0,1]],right:[[1,0,0],[0,0,1]],top:[[0,0,1],[0,1,0]],bottom:[[0,0,-1],[0,-1,0]],isometric:[[1,-1,1],[0,0,1]]};function Ki(t){let e=Ro[t];if(!e)throw new Error("Unknown camera view");this.camera.position=this.camera.target.map((i,o)=>i+e[0][o]),this.camera.up=[...e[1]],this.set_auto_zoom()}function Re(t){if(!Array.isArray(t)||t.length>32)throw new Error("Save up to 32 camera views");let e=new Set;return t.map(i=>{let o=typeof i?.name=="string"?i.name.trim():"";if(!o||o.length>80||/[\x00-\x1f]/.test(o)||e.has(o))throw new Error("Use a unique view name of 1\u201380 characters");e.add(o);let s={};for(let d of["position","target","up"]){if(!i.camera?.[d]||pe.some(l=>!Number.isFinite(i.camera[d][l])||Math.abs(i.camera[d][l])>1e15))throw new Error("Invalid saved camera");s[d]=Object.fromEntries(pe.map(l=>[l,i.camera[d][l]]))}let n=pe.map(d=>s.position[d]-s.target[d]),r=pe.map(d=>s.up[d]);if(Math.hypot(n[1]*r[2]-n[2]*r[1],n[2]*r[0]-n[0]*r[2],n[0]*r[1]-n[1]*r[0])<1e-12)throw new Error("Degenerate saved camera");return{name:o,camera:s}})}function vt(t,e){let i=Re(t),o=new Set(i.map(s=>s.name));for(let s of Re(e)){let n=s.name,r=2;for(;o.has(n);)n=s.name.slice(0,70)+` (${r++})`;o.add(n),i.push({...s,name:n})}return Re(i)}async function Zi(t,e={}){await this.when_ready;let i=this._model(t),o=i.geometry;if(!o||i._sceneImportPending)throw new Error("Wait for the model to finish opening");let s=i.scaleVector,n=s.join(","),r=i._measurements;if(e.signal?.aborted)throw new DOMException("Measurement cancelled","AbortError");if(r?.positions===o.positions&&r.key===n)return{...r.result};let d=yt(o.triangles),l=this._occupiedMemory();X(this.limits,l+d,"measurements");let c=this._reserveMemory(i,d+Ke(o),"measurements"),m=new AbortController,f=()=>m.abort();this._aborters.add(m),(i._measureJobs??=new Set).add(m),e.signal?.addEventListener("abort",f,{once:!0});let b,_,p=()=>{if(m.signal.aborted||this.killsign)throw new DOMException("Measurement cancelled","AbortError");if(this._models.get(t)!==i||i.geometry.positions!==o.positions||i.scaleVector.join(",")!==n)throw new Error("Model size changed. Calculate again.")};try{let h=new Float32Array(o.positions.length);for(let y=0;y<h.length;y+=262144)p(),h.set(o.positions.subarray(y,y+262144),y),y+262144<h.length&&await new Promise(M=>setTimeout(M,0));b=this._pool.run({kind:"measure",positions:h,scale:s,area:o.area,max_time_ms:e.max_time_ms??3e4,limits:{...this.limits,max_memory_bytes:this.limits.max_memory_bytes-l}},y=>{try{e.on_progress?.(y)}catch(M){_=M,m.abort()}},[h.buffer]),m.signal.addEventListener("abort",()=>b.cancel(),{once:!0}),p();let w;try{w=await b}catch(y){throw _||y}return p(),i._measurements={positions:o.positions,key:n,result:w},{...w}}finally{b?.cancel?.(),c(),this._aborters.delete(m),i._measureJobs.delete(m),e.signal?.removeEventListener("abort",f)}}var Po=["flat","smooth","wireframe","edges","mesh","xray","studio","orientation"];function wt(t,e){if(!Po.includes(t))throw new Error("Invalid display mode");if(typeof e!="boolean")throw new Error("smooth_shading must be a boolean");return{display:t,smooth_shading:t==="smooth"||e}}function Zt(t){return{smooth:(t.smooth_shading||t.display==="smooth")&&t.display!=="wireframe",edges:t.view_edges||t.display==="edges",wire:t.display==="wireframe",edgeAngle:t.display==="edges"?30:1}}function xt(t){if(t==null)return null;if(!["x","y","z"].includes(t.axis))throw new Error("Section axis must be x, y or z");if(!Number.isFinite(t.position)||t.position<0||t.position>1)throw new Error("Section position must be between 0 and 1");if(t.flip!==void 0&&typeof t.flip!="boolean")throw new Error("Section flip must be a boolean");return{axis:t.axis,position:t.position,flip:t.flip??!1}}function kt(t,e){if(!e)return[0,0,0,0];let i=["x","y","z"].indexOf(e.axis),o=e.flip?-1:1,s=[0,0,0,0];return s[i]=o,s[3]=-o*(t.min[i]+(t.max[i]-t.min[i])*e.position),s}var Qi=Object.freeze({max_file_bytes:256*1024*1024,max_triangles:5e6,max_uncompressed_bytes:256*1024*1024,max_archive_entries:1024,max_memory_bytes:Number.MAX_SAFE_INTEGER});function $i(t={}){let e={...Qi};for(let i of Object.keys(e))if(t[i]!==void 0){if(!Number.isSafeInteger(t[i])||t[i]<1)throw new Error(`Invalid ${i}`);e[i]=t[i]}return e}function Z(t){if(typeof t!="string"||!/^#[\da-f]{6}$/i.test(t))throw new Error("Color must be #RRGGBB");return[1,3,5].map(e=>parseInt(t.slice(e,e+2),16)/255)}function Et(t,e=null,i=Qi){if(!(t instanceof Float32Array)||!t.length||t.length%9)throw new Error("Geometry must contain complete triangles");if(t.length/9>i.max_triangles)throw new Error("Triangle limit exceeded");if(X(i,67108864+t.length/9*224),e&&(!(e instanceof Float32Array)||e.length!==t.length))throw new Error("Invalid vertex colors");let o={min:[1/0,1/0,1/0],max:[-1/0,-1/0,-1/0]};for(let c=0;c<t.length;c++){let m=t[c],f=c%3;if(!Number.isFinite(m))throw new Error("Non-finite vertex coordinate");if(o.min[f]=Math.min(o.min[f],m),o.max[f]=Math.max(o.max[f],m),e&&(!Number.isFinite(e[c])||e[c]<0||e[c]>1))throw new Error("Invalid vertex color")}let s=new Float32Array(t.length),n=new Float32Array(Math.ceil(t.length/9/64)*6),r=0,d=0,l=0;for(let c=0;c<t.length;c+=9){let m=t[c+3]-t[c],f=t[c+4]-t[c+1],b=t[c+5]-t[c+2],_=t[c+6]-t[c],p=t[c+7]-t[c+1],h=t[c+8]-t[c+2],w=f*h-b*p,y=b*_-m*h,M=m*p-f*_,P=Math.hypot(w,y,M);r+=P/2,d+=(t[c]*w+t[c+1]*y+t[c+2]*M)/6,P||l++;for(let v=0;v<9;v+=3)s[c+v]=w/(P||1),s[c+v+1]=y/(P||1),s[c+v+2]=M/(P||1);let C=Math.floor(c/9/64)*6;c/9%64===0&&n.set([1/0,1/0,1/0,-1/0,-1/0,-1/0],C);for(let v=0;v<9;v++){let R=v%3;n[C+R]=Math.min(n[C+R],t[c+v]),n[C+3+R]=Math.max(n[C+3+R],t[c+v])}}if(!Number.isFinite(r)||!Number.isFinite(d))throw new Error("Geometry magnitude exceeds numeric limits");return{positions:t,normals:s,colors:e,blocks:n,bounds:o,triangles:t.length/9,area:r,volume:Math.abs(d),degenerateTriangles:l}}function eo(t,e,i,o=[0,0,0,0]){if(!Xt(e,i,t.bounds.min,t.bounds.max))return 1/0;let s=1/0;for(let n=0;n<t.blocks.length;n+=6){if(!Xt(e,i,t.blocks.subarray(n,n+3),t.blocks.subarray(n+3,n+6)))continue;let r=n/6*64*9,d=Math.min(r+576,t.positions.length);for(let l=r;l<d;l+=9){let c=Ui(e,i,t.positions,l);c<s&&o[3]+o[0]*(e[0]+i[0]*c)+o[1]*(e[1]+i[1]*c)+o[2]*(e[2]+i[2]*c)<=0&&(s=c)}}return s}function to(t,e){if(e[0]===e[1]&&e[1]===e[2])return{area:t.area*e[0]*e[0],volume:t.volume*Math.abs(e[0]**3)};let i=0,o=t.positions;for(let s=0;s<o.length;s+=9){let n=(o[s+3]-o[s])*e[0],r=(o[s+4]-o[s+1])*e[1],d=(o[s+5]-o[s+2])*e[2],l=(o[s+6]-o[s])*e[0],c=(o[s+7]-o[s+1])*e[1],m=(o[s+8]-o[s+2])*e[2];i+=Math.hypot(r*m-d*c,d*l-n*m,n*c-r*l)/2}return{area:i,volume:t.volume*Math.abs(e[0]*e[1]*e[2])}}function Qt(t,e=[1,1,1],i=[0,0,0]){let o=new ArrayBuffer(84+t.triangles*50),s=new DataView(o),n=t.positions;new Uint8Array(o).set(new TextEncoder().encode("Binary STL by ViewSTL 2")),s.setUint32(80,t.triangles,!0);for(let r=0;r<t.triangles;r++){let d=84+r*50,l=Array.from({length:9},(_,p)=>(n[r*9+p]-i[p%3])*e[p%3]),c=[l[3]-l[0],l[4]-l[1],l[5]-l[2]],m=[l[6]-l[0],l[7]-l[1],l[8]-l[2]],f=[c[1]*m[2]-c[2]*m[1],c[2]*m[0]-c[0]*m[2],c[0]*m[1]-c[1]*m[0]],b=Math.hypot(...f)||1;for(let _=0;_<3;_++)s.setFloat32(d+_*4,f[_]/b,!0);for(let _=0;_<9;_++)s.setFloat32(d+12+_*4,l[_],!0);if(t.colors){let _=[0,1,2].map(p=>Math.round(t.colors[r*9+p]*31));s.setUint16(d+48,32768|_[0]<<10|_[1]<<5|_[2],!0)}}return o}var Me=t=>String(t||"").match(/\.(vsb|vsj)(?:[?#]|$)/i)?.[1].toLowerCase()||"";function io(t,e){let i;try{i=decodeURIComponent(t.split(/[?#]/)[0]).replaceAll("\\","/")}catch{throw new Error("Invalid scene filename encoding")}let o=[...new Set(e)],s=o.filter(r=>(r.webkitRelativePath||r.name)===i);if(s.length===1)return s[0];let n=o.filter(r=>r.name===i.split("/").pop());if(n.length>1||s.length>1)throw new Error("More than one supplied file matches "+i);return n[0]||null}function $t(t,e){let i;try{i=e?new URL(t,e):new URL(t)}catch{return null}if(!["http:","https:"].includes(i.protocol)||i.username||i.password)throw new Error("Scene references must be HTTP/HTTPS URLs without login credentials");return i.hash="",i.href}var ei=["save-button","save-dialog","save-form","save-fields","save-name","save-format","save-scope","save-colors","save-colors-row","save-format-note","save-cad-note","save-progress","save-status","save-error","save-submit","save-cancel","save-close"];function oo({$:t,listen:e,window:i,getState:o,getViewer:s,onOpen:n,announce:r}){let d=t("save-dialog"),l=null,c=!1,m="",f=()=>o(),b=()=>!c&&!f().busy&&f().models.length>0,_=()=>["vsb","vsj"].includes(t("save-format").value),p=()=>{t("save-error").hidden=!0,t("save-error").textContent=""};function h(){let C=t("save-format").value;(!t("save-name").value||t("save-name").value===m)&&w(),t("save-mesh-note")&&(t("save-mesh-note").hidden=_()),t("save-scene-note")&&(t("save-scene-note").hidden=!_()),t("save-colors-row").hidden=!["obj","3mf"].includes(C),t("save-cad-note").hidden=!["step","iges"].includes(C),t("save-format-note").textContent=t("save-format").selectedOptions[0]?.dataset.note||"",t("save-submit").textContent=C==="obj"&&t("save-colors").checked?"Download ZIP":"Download file",y()}function w(){let{models:C,selectedId:v}=f();t("save-name").value=_()?"viewstl-scene":(C.find(R=>R.id===v)?.name||"model").replace(/\.[^.]+$/,""),m=t("save-name").value}function y(){t("save-button").disabled=!b()||!!l,t("save-fields").disabled=!!l,t("save-submit").disabled=!b()||!!l,t("save-progress").hidden=!l,t("save-cancel").textContent=l?"Cancel saving":"Cancel";let{models:C,selectedId:v}=f(),R=_()?`Entire scene \xB7 ${C.length} ${C.length===1?"model":"models"}`:"Selected model: "+(C.find(k=>k.id===v)?.name||"model");t("save-scope").textContent!==R&&(t("save-scope").textContent=R)}function M(){if(l){let C=l;l=null,C.abort(),r("Saving cancelled.")}t("save-status").textContent="",y()}function P(){M(),d.open&&d.close()}return e(t("save-button"),"click",()=>{!b()||l||(n(),p(),t("save-status").textContent="",w(),h(),y(),d.showModal())}),e(t("save-format"),"change",()=>{p(),h()}),e(t("save-colors"),"change",h),e(t("save-cancel"),"click",P),e(t("save-close"),"click",P),e(d,"cancel",C=>{C.preventDefault(),P()}),e(d,"close",()=>{d.open||M()}),e(t("save-form"),"submit",async C=>{if(C.preventDefault(),l||!b())return;p();let{selectedId:v}=f(),R=new i.AbortController;l=R,t("save-progress").removeAttribute("value"),t("save-status").textContent="Preparing your file\u2026",y();try{let k={format:t("save-format").value,filename:t("save-name").value.trim()||"model",model_ids:[v],units:"mm",apply_transforms:!0,colors:t("save-colors").checked,signal:R.signal,on_progress({loaded:A,total:I,phase:E}){if(l!==R||R.signal.aborted)return;let L=I?Math.min(100,Math.floor(100*A/I)):0;t("save-progress").value=L,t("save-status").textContent=E==="packaging"?"Packing your scene\u2026":L===100?"Finishing your file\u2026":`Saving\u2026 ${L}%`}},g=_()?await s().download_scene({format:k.format,filename:k.filename,signal:k.signal,on_progress:k.on_progress,force_basename:!0}):await s().download_models(k);if(l!==R||c)return;l=null,P(),r(g.filename+" ready to download.")}catch(k){if(l!==R||c)return;l=null,t("save-status").textContent="",k?.name!=="AbortError"&&(t("save-error").textContent=k?.message||"This file could not be saved. Try another format.",t("save-error").hidden=!1)}finally{!c&&(!l||l===R)&&y()}}),h(),y(),{sync:y,close:P,dispose(){P(),c=!0}}}var ti=["print-button","print-panel","print-close","print-form","print-fields","print-scope","print-level","print-units","print-fdm","print-wall","print-angle","print-bed-x","print-bed-y","print-bed-z","print-run","print-cancel","print-status","print-results","print-clear","print-target"];function no({$:t,listen:e,window:i,getState:o,getViewer:s,onOpen:n,announce:r}){let d=null,l=null,c=null,m=!1,f="",b="",_=!1,p=t("print-panel"),h=p.ownerDocument,w=new Set,y={issues_found:"Issues found",incomplete:"Check incomplete",no_issues_found:"No issues found in completed checks"},M=(E,L)=>{let T=h.createElement(E);return T.textContent=L,T},P=()=>t("print-scope").value==="all"?o().models.map(E=>E.id):[o().selectedId],C=()=>JSON.stringify(P()),v=()=>{s()?.clear_printability(),t("print-clear").hidden=!0};function R(){if(m)return;let E=o();if(t("print-button").disabled=E.busy||!E.models.length,p.hidden)return;for(let T of w)(!E.models.some(D=>D.id===T)||s()?.get_model_animation_state(T)?.status!=="paused")&&w.delete(T);t("print-resume")&&(t("print-resume").hidden=!w.size,t("print-resume").disabled=!!d||E.busy),t("print-animation-note")&&(t("print-animation-note").hidden=!w.size);let L=_;_=E.busy||!E.models.length,t("print-run").disabled=!!d||_,b!==C()&&(t("print-units").checked=!1,b=C()),t("print-target").textContent=t("print-scope").value==="all"?`All ${E.models.length} models, checked separately`:E.models.find(T=>T.id===E.selectedId)?.name||"No model selected",d&&(_||f!==C())&&g(),l&&(!s()?.is_printability_current(l)||f!==C())&&(l=null,t("print-units").checked=!1,v(),t("print-results").replaceChildren(),t("print-status").textContent="Model or selection changed. Run the check again."),_?(E.models.length||(l=null,v(),t("print-results").replaceChildren()),t("print-status").textContent=E.busy?"Opening models. Checks will be available when loading finishes.":"Open a model to run a print check."):L&&!d&&(t("print-status").textContent=l?y[l.summary]:"Ready to check. Choose Run check to analyze the current model selection.")}function k(E){let L=[];for(let T of E.models){let D=h.createElement("section");D.append(M("h3",o().models.find(S=>S.id===T.model_id)?.name||T.name)),D.append(M("p",`${T.dimensions_mm?.map(S=>Number(S.toPrecision(5))).join(" \xD7 ")||"Unknown size"} mm \xB7 ${(T.elapsed_ms/1e3).toFixed(2)} s`)),T.volume_valid&&D.append(M("p",`Enclosed volume at current mm scale: ${Number(T.volume_mm3.toPrecision(6))} mm\xB3`));for(let S of T.checks){let N=h.createElement("details");N.dataset.check=S.code,N.dataset.status=S.status;let F={pass:"Passed",issue:S.severity==="info"?"Information":"Review",inconclusive:"Inconclusive",not_run:"Not run"}[S.status];if(N.append(M("summary",`${F} \xB7 ${S.label}${S.count?` (${S.count})`:""}${S.estimated?" \u2014 estimate":""}`)),N.append(M("p",S.message)),S.area_mm2!=null&&N.append(M("p",`Area: ${Number(S.area_mm2.toPrecision(5))} mm\xB2`)),S.minimum_sampled_mm!=null&&N.append(M("p",`Smallest sampled distance: ${Number(S.minimum_sampled_mm.toPrecision(5))} mm`)),S.triangle_ids.length||S.edge_vertices.length){let j=M("button","Show locations");j.type="button",j.dataset.issue=S.code,j.dataset.model=T.model_id,N.append(j),N.append(M("p","Highlights show a bounded sample, including edges hidden behind surfaces."))}D.append(N)}L.push(D)}t("print-results").replaceChildren(...L)}function g(){d?.abort()}function A(E=!0){g(),p.hidden=!0,t("workspace")?.classList.remove("print-check-open"),v(),i.clearInterval(c),c=null,t("print-button").setAttribute("aria-expanded","false"),E&&!m&&(t("print-button").offsetParent&&!t("print-button").disabled?t("print-button"):t("info-button").offsetParent?t("info-button"):t("sample-button"))?.focus()}function I(){g(),l=null,v(),t("print-results").replaceChildren(),t("print-status").textContent="Settings changed. Run the check again.",R()}return e(t("print-button"),"click",()=>{if(!p.hidden){n(),R(),p.scrollTop=0,t("print-run").focus();return}n(),p.hidden=!1,t("workspace")?.classList.add("print-check-open"),t("print-button").setAttribute("aria-expanded","true"),R(),c=i.setInterval(R,400),t("print-run").focus()}),e(t("print-close"),"click",()=>A()),e(p,"keydown",E=>{E.key==="Escape"&&(E.stopPropagation(),E.preventDefault(),A())}),e(t("print-fields"),"change",I),e(t("print-clear"),"click",v),e(t("print-cancel"),"click",g),t("print-resume")&&e(t("print-resume"),"click",()=>{if(!(d||o().busy)){for(let E of w)o().models.some(L=>L.id===E)&&s().get_model_animation_state(E)?.status==="paused"&&s().resume_model_animation(E);w.clear(),l=null,v(),t("print-results").replaceChildren(),t("print-status").textContent="Animation resumed. Pause and run the check again for the new pose.",R()}}),e(t("print-results"),"click",E=>{let L=E.target.closest("button[data-issue]");if(!(!L||!l))try{s().show_printability(l,{issue:L.dataset.issue,model_id:Number(L.dataset.model)}),t("print-clear").hidden=!1}catch(T){t("print-status").textContent=T.message}}),e(t("print-form"),"submit",async E=>{if(E.preventDefault(),d||o().busy||!o().models.length)return;let L=new i.AbortController;d=L,l=null,v(),t("print-results").replaceChildren(),t("print-status").textContent="Checking on your device\u2026",t("print-fields").disabled=!0,t("print-run").disabled=!0,t("print-cancel").hidden=!1;try{let T=null;if(t("print-fdm").checked){T={technology:"fdm"},t("print-wall").value&&(T.min_wall_mm=Number(t("print-wall").value)),t("print-angle").value&&(T.overhang_degrees=Number(t("print-angle").value));let S=["x","y","z"].map(N=>t("print-bed-"+N).value);if(S.some(Boolean)){if(!S.every(Boolean))throw new Error("Enter all three build-volume dimensions, or leave all three empty.");T.build_volume_mm=S.map(Number)}}f=C();for(let S of P())s().get_model_animation_state(S)?.status==="running"&&(s().pause_model_animation(S),w.add(S));R();let D=await s().check_printability({model_ids:P(),level:t("print-level").value,units_confirmed:t("print-units").checked,profile:T,signal:L.signal,on_progress:S=>{d===L&&(t("print-status").textContent=`${S.phase} \xB7 model ${(S.model_index??0)+1} of ${S.total_models}`)}});if(m||L.signal.aborted)return;l=D,k(l),t("print-status").textContent=y[l.summary],r(y[l.summary])}catch(T){m||(t("print-status").textContent=T.name==="AbortError"?"Check cancelled. Your model is unchanged.":T.message)}finally{d===L&&(d=null),m||(t("print-fields").disabled=!1,t("print-run").disabled=!1,t("print-cancel").hidden=!0,R())}}),R(),{sync:R,close:A,dispose(){m=!0,A(!1),l=null,w.clear()}}}var ii=["animation-details","animation-fields","animation-axis","animation-seconds","animation-direction","animation-play","animation-pause","animation-stop","animation-status","animation-error"],Ze=["x","y","z"];function ie(t,e){if(!t||!e?.geometry)return;t.bounds=Object.fromEntries(["min","max"].map(o=>[o,e.geometry.bounds[o].map((s,n)=>(s-e.center[n])*e.scaleVector[n])])),t.rotation=Object.fromEntries(Ze.map(o=>[o,e["rotation"+o]*180/Math.PI%360])),t.position={x:0,y:0,z:0};let i=Ge(t);for(let o of Ze)t.position[o]=e[o]-i[o]}function ro(t,e){ie(t,e);let i=e.geometry.bounds.min.map((r,d)=>(r+e.geometry.bounds.max[d])/2),o=i.map((r,d)=>(r-e.center[d])*e.scaleVector[d]),s=Ve(t.rotation),n=t.originalPosition||{x:0,y:0,z:0};t.originalPosition=Object.fromEntries(Ze.map((r,d)=>[r,n[r]+o[d]]));for(let r=0;r<3;r++)e[Ze[r]]+=o.reduce((d,l,c)=>d+s[r*3+c]*l,0);e.center=i,t.animationPivot=!0,ie(t,e)}function To(t,e,i){if(!Ze.includes(t)||!Number.isFinite(e)||e<.1||e>3600||!["1","-1"].includes(i))throw new Error("Choose an axis and a duration from 0.1 to 3,600 seconds.");return{delta:{["rotation"+t]:2*Math.PI*Number(i),msec:e*1e3,loop:!0}}}function so({$:t,listen:e,window:i,getState:o,getViewer:s,beforePlay:n,refreshPose:r,announce:d}){let l=new Map,c=null,m=null,f=!1,b=()=>{let h=o();return{...h,playback:h.selectedId==null?null:s()?.get_model_animation_state(h.selectedId)}};function _(){if(f)return;let h=b(),w=h.models.some(v=>v.id===h.selectedId);for(let v of l.keys())h.models.some(R=>R.id===v)||l.delete(v);if(t("animation-details").hidden=!w,t("animation-fields").disabled=h.busy||!w,c!==h.selectedId){c=h.selectedId;let v=l.get(c);if(!v){v={axis:"z",seconds:5,direction:"1"};let R=s()?._models.get(c)?.animation,k=Object.entries(R?.delta||{}).filter(([g,A])=>g.startsWith("rotation")&&A!==0);R?.delta?.loop&&!R.exact&&k.length===1&&(v={axis:k[0][0].slice(-1),seconds:R.delta.msec*2*Math.PI/Math.abs(k[0][1])/1e3,direction:k[0][1]<0?"-1":"1"}),l.set(c,v)}t("animation-axis").value=v.axis,t("animation-seconds").value=v.seconds,t("animation-direction").value=v.direction,t("animation-error").hidden=!0}let y=h.playback?.status||"idle",M=["running","paused"].includes(y);t("animation-play").textContent=M?"Restart spin":"Play",t("animation-pause").textContent=y==="paused"?"Resume":"Pause",t("animation-pause").disabled=!M,t("animation-stop").disabled=!M;let C=`${{idle:"Ready",running:"Playing",paused:"Paused",stopped:"Stopped",completed:"Finished"}[y]}. ${M?"Stop keeps the current pose.":"Spin the selected model around its center."}`;t("animation-status").textContent!==C&&(t("animation-status").textContent=C),y==="running"&&!m&&(m=i.setInterval(()=>{!f&&!i.document.hidden&&r()},250)),y!=="running"&&m&&(i.clearInterval(m),m=null)}function p(h=!1){let w=b();if(!(w.busy||w.selectedId==null))try{let y={axis:t("animation-axis").value,seconds:t("animation-seconds").valueAsNumber,direction:t("animation-direction").value},M=To(y.axis,y.seconds,y.direction);n(w.selectedId),s().animate_model(w.selectedId,M),h&&w.playback?.status==="paused"&&s().pause_model_animation(w.selectedId),l.set(w.selectedId,y),t("animation-error").hidden=!0,d(h&&w.playback?.status==="paused"?"Spin updated. Still paused.":"Animation playing."),_()}catch(y){t("animation-error").textContent=y.message,t("animation-error").hidden=!1}}e(t("animation-play"),"click",()=>p()),e(t("animation-pause"),"click",()=>{let h=b();h.busy||h.selectedId==null||(s()[h.playback?.status==="paused"?"resume_model_animation":"pause_model_animation"](h.selectedId),_())}),e(t("animation-stop"),"click",()=>{let h=b();!h.busy&&h.selectedId!=null&&s().animate_model(h.selectedId,null),_()});for(let h of["animation-axis","animation-seconds","animation-direction"])e(t(h),"change",()=>{["running","paused"].includes(b().playback?.status)?p(!0):l.set(c,{axis:t("animation-axis").value,seconds:t("animation-seconds").valueAsNumber,direction:t("animation-direction").value})});return _(),{sync:_,dispose(){f=!0,i.clearInterval(m),l.clear()}}}var Fo=`#version 300 es
2
3
  precision highp float;
3
4
  out vec2 screen;
4
- void main(){vec2 p=vec2((gl_VertexID<<1)&2,gl_VertexID&2);screen=p*2.0-1.0;gl_Position=vec4(screen,0,1);}`,Co=`#version 300 es
5
+ void main(){vec2 p=vec2((gl_VertexID<<1)&2,gl_VertexID&2);screen=p*2.0-1.0;gl_Position=vec4(screen,0,1);}`,No=`#version 300 es
5
6
  precision highp float;
6
7
  in vec2 screen;
7
8
  uniform mat4 inverseVP;uniform mat4 vp;uniform vec3 eye;uniform float height;uniform float spacing;uniform vec3 color;
@@ -20,7 +21,7 @@ void main(){
20
21
  if(alpha<0.003)discard;
21
22
  gl_FragDepth=clamp(clip.z/clip.w*0.5+0.5+0.000001,0.0,0.999999);
22
23
  result=vec4(color,alpha);
23
- }`,xt=class{constructor(e){this.gl=e;let i=[],o;try{for(let[s,n]of[[e.VERTEX_SHADER,Io],[e.FRAGMENT_SHADER,Co]]){let r=e.createShader(s);if(i.push(r),e.shaderSource(r,n),e.compileShader(r),!e.getShaderParameter(r,e.COMPILE_STATUS))throw Error("Grid shader: "+e.getShaderInfoLog(r))}if(o=e.createProgram(),i.forEach(s=>e.attachShader(o,s)),e.linkProgram(o),!e.getProgramParameter(o,e.LINK_STATUS))throw Error("Grid program: "+e.getProgramInfoLog(o));if(this.program=o,this.vao=e.createVertexArray(),!this.vao)throw Error("Graphics memory unavailable for grid");this.uniforms=Object.fromEntries(["inverseVP","vp","eye","height","spacing","color"].map(s=>[s,e.getUniformLocation(o,s)]))}catch(s){throw o&&e.deleteProgram(o),s}finally{i.forEach(s=>e.deleteShader(s))}}draw(e,i,o,s){let n=this.gl,r=this.uniforms;n.useProgram(this.program),n.bindVertexArray(this.vao),n.uniformMatrix4fv(r.inverseVP,!1,new Float32Array(we(e))),n.uniformMatrix4fv(r.vp,!1,new Float32Array(e)),n.uniform3fv(r.eye,i.position),n.uniform1f(r.height,o.height),n.uniform1f(r.spacing,o.spacing);let d=s==="transparent"?[1,1,1]:Z(s),l=d[0]*.2126+d[1]*.7152+d[2]*.0722<.45;n.uniform3fv(r.color,l?[.68,.77,.81]:[.37,.46,.5]),n.enable(n.BLEND),n.blendFuncSeparate(n.SRC_ALPHA,n.ONE_MINUS_SRC_ALPHA,n.ONE,n.ONE_MINUS_SRC_ALPHA),n.depthMask(!1),n.drawArrays(n.TRIANGLES,0,3),n.depthMask(!0),n.disable(n.BLEND)}dispose(){this.gl.deleteProgram(this.program),this.gl.deleteVertexArray(this.vao)}};function to(t){let e=Math.max(Math.max(...t.max.map((s,n)=>s-t.min[n]))*.015,...[...t.min,...t.max].map(s=>Math.abs(s)*2e-7),1e-7),i=s=>[0,1,2].map(n=>s&1<<n?t.max[n]+e:t.min[n]-e),o=[];for(let s=0;s<8;s++)for(let n=0;n<3;n++)s&1<<n||o.push(...i(s),...i(s|1<<n));return new Float32Array(o)}var Ro=`#version 300 es
24
+ }`,Mt=class{constructor(e){this.gl=e;let i=[],o;try{for(let[s,n]of[[e.VERTEX_SHADER,Fo],[e.FRAGMENT_SHADER,No]]){let r=e.createShader(s);if(i.push(r),e.shaderSource(r,n),e.compileShader(r),!e.getShaderParameter(r,e.COMPILE_STATUS))throw Error("Grid shader: "+e.getShaderInfoLog(r))}if(o=e.createProgram(),i.forEach(s=>e.attachShader(o,s)),e.linkProgram(o),!e.getProgramParameter(o,e.LINK_STATUS))throw Error("Grid program: "+e.getProgramInfoLog(o));if(this.program=o,this.vao=e.createVertexArray(),!this.vao)throw Error("Graphics memory unavailable for grid");this.uniforms=Object.fromEntries(["inverseVP","vp","eye","height","spacing","color"].map(s=>[s,e.getUniformLocation(o,s)]))}catch(s){throw o&&e.deleteProgram(o),s}finally{i.forEach(s=>e.deleteShader(s))}}draw(e,i,o,s){let n=this.gl,r=this.uniforms;n.useProgram(this.program),n.bindVertexArray(this.vao),n.uniformMatrix4fv(r.inverseVP,!1,new Float32Array(ke(e))),n.uniformMatrix4fv(r.vp,!1,new Float32Array(e)),n.uniform3fv(r.eye,i.position),n.uniform1f(r.height,o.height),n.uniform1f(r.spacing,o.spacing);let d=s==="transparent"?[1,1,1]:Z(s),l=d[0]*.2126+d[1]*.7152+d[2]*.0722<.45;n.uniform3fv(r.color,l?[.68,.77,.81]:[.37,.46,.5]),n.enable(n.BLEND),n.blendFuncSeparate(n.SRC_ALPHA,n.ONE_MINUS_SRC_ALPHA,n.ONE,n.ONE_MINUS_SRC_ALPHA),n.depthMask(!1),n.drawArrays(n.TRIANGLES,0,3),n.depthMask(!0),n.disable(n.BLEND)}dispose(){this.gl.deleteProgram(this.program),this.gl.deleteVertexArray(this.vao)}};function ao(t){let e=Math.max(Math.max(...t.max.map((s,n)=>s-t.min[n]))*.015,...[...t.min,...t.max].map(s=>Math.abs(s)*2e-7),1e-7),i=s=>[0,1,2].map(n=>s&1<<n?t.max[n]+e:t.min[n]-e),o=[];for(let s=0;s<8;s++)for(let n=0;n<3;n++)s&1<<n||o.push(...i(s),...i(s|1<<n));return new Float32Array(o)}var Oo=`#version 300 es
24
25
  precision highp float;
25
26
  layout(location=0) in vec3 position;
26
27
  layout(location=1) in vec3 normal;
@@ -30,7 +31,7 @@ out vec3 vNormal; out vec3 vColor; out vec3 vPosition; out vec3 vWorld; out vec3
30
31
  void main(){vNormal=normalMatrix*normal;vColor=color;vPosition=position;
31
32
  vWorld=(modelMatrix*vec4(position,1.0)).xyz;
32
33
  int corner=gl_VertexID%3;vBary=corner==0?vec3(1,0,0):(corner==1?vec3(0,1,0):vec3(0,0,1));
33
- gl_Position=mvp*vec4(position,1.0);}`,Po=`#version 300 es
34
+ gl_Position=mvp*vec4(position,1.0);}`,Do=`#version 300 es
34
35
  precision highp float;
35
36
  in vec3 vNormal;in vec3 vColor;in vec3 vPosition;in vec3 vWorld;in vec3 vBary;
36
37
  uniform vec3 tint;uniform vec3 light;uniform float opacity;uniform bool unlit;uniform bool useColors;
@@ -48,4 +49,4 @@ if(!unlit){
48
49
  if(appearance==4)color=(gl_FrontFacing?vec3(0.12,0.55,0.72):vec3(0.9,0.24,0.32))*(0.55+0.45*l);
49
50
  if(dot(section.xyz,section.xyz)>0.0 && abs(cut)<max(fwidth(cut)*1.2,0.0000001)){color=vec3(0.93,0.57,0.17);alpha=opacity;}
50
51
  }
51
- result=vec4(color,alpha);}`,kt=class{constructor(e,i,o,s){if(this.canvas=e,this.domElement=e,this.resources=new Map,this.sharedResources=new WeakMap,this.frames=0,this.lost=!1,this.gl=e.getContext("webgl2",{alpha:!0,antialias:!0,premultipliedAlpha:!1,preserveDrawingBuffer:!1}),!this.gl)throw new Error("WebGL2 is unavailable. Enable browser graphics acceleration or try another browser/device.");this.lostHandler=n=>{n.preventDefault(),this.lost=!0,this.resources.clear(),this.sharedResources=new WeakMap,this.gridResource=null,this.infiniteGrid=null,this.selectionResource=null,this.diagnosticResource=null,i()},this.restoredHandler=()=>{try{this.initialize(),this.lost=!1,o()}catch(n){s(n)}},e.addEventListener("webglcontextlost",this.lostHandler),e.addEventListener("webglcontextrestored",this.restoredHandler),this.initialize()}initialize(){let e=this.gl,i=[],o;try{for(let[s,n]of[[e.VERTEX_SHADER,Ro],[e.FRAGMENT_SHADER,Po]]){let r=e.createShader(s);if(i.push(r),e.shaderSource(r,n),e.compileShader(r),!e.getShaderParameter(r,e.COMPILE_STATUS))throw new Error(`Shader compilation failed: ${e.getShaderInfoLog(r)}`)}o=e.createProgram();for(let s of i)e.attachShader(o,s);if(e.linkProgram(o),!e.getProgramParameter(o,e.LINK_STATUS))throw new Error(`Shader link failed: ${e.getProgramInfoLog(o)}`);this.program=o,this.uniforms=Object.fromEntries(["mvp","modelMatrix","normalMatrix","tint","light","eye","opacity","unlit","section","appearance","useColors"].map(s=>[s,e.getUniformLocation(o,s)]))}catch(s){throw o&&e.deleteProgram(o),s}finally{for(let s of i)e.deleteShader(s)}}upload(e,i,o){let s=this.gl,n=s.createVertexArray(),r=[];if(!n)throw new Error("Graphics memory is unavailable for this model.");s.bindVertexArray(n);try{for(let[d,l]of[[0,e],[1,i],[2,o]])if(l){let c=s.createBuffer();if(!c)throw new Error("Graphics memory is unavailable for this model.");r.push(c),s.bindBuffer(s.ARRAY_BUFFER,c),s.bufferData(s.ARRAY_BUFFER,l,s.STATIC_DRAW);let m=s.getError();if(m!==s.NO_ERROR)throw new Error(m===s.OUT_OF_MEMORY?"Not enough graphics memory for this model. Try closing other tabs or using another device.":"The browser could not upload this model to the graphics device.");s.enableVertexAttribArray(d),s.vertexAttribPointer(d,3,s.FLOAT,!1,0,0)}return s.bindVertexArray(null),{vao:n,buffers:r,count:e.length/3}}catch(d){s.bindVertexArray(null);for(let l of r)s.deleteBuffer(l);throw s.deleteVertexArray(n),d}}free(e){if(e){for(let i of e.buffers)this.gl.deleteBuffer(i);this.gl.deleteVertexArray(e.vao)}}remove(e){this.diagnostic?.model===e&&this.setDiagnostic(null);let i=this.resources.get(e);if(i)for(let o of Object.values(i))--o.users===0&&(this.sharedResources.get(o.source)?.delete(o),this.free(o));this.resources.delete(e)}clear(){this.setDiagnostic(null),this.setSelection(null);for(let e of this.resources.keys())this.remove(e);this.free(this.gridResource),this.gridResource=null,this.infiniteGrid?.dispose(),this.infiniteGrid=null}get liveBuffers(){let e=(this.gridResource?.buffers.length||0)+(this.selectionResource?.buffers.length||0)+(this.diagnosticResource?.buffers.length||0),i=new Set;for(let o of this.resources.values())for(let s of Object.values(o))i.add(s);for(let o of i)e+=o.buffers.length;return e}setDiagnostic(e){this.free(this.diagnosticResource),this.diagnosticResource=null,this.diagnostic=e}drawDiagnostic(e){let i=this.gl,o=this.uniforms,s=this.diagnostic,n=J(s.model);this.diagnosticResource??=this.upload(s.positions),i.uniformMatrix4fv(o.mvp,!1,new Float32Array(Ve(e,n))),i.uniformMatrix4fv(o.modelMatrix,!1,new Float32Array(n)),i.uniform4fv(o.section,[0,0,0,0]),i.uniform1i(o.appearance,0),i.uniform1i(o.useColors,0),i.uniform1i(o.unlit,1),i.uniform3fv(o.tint,[.85,.16,.06]),i.uniform1f(o.opacity,1),i.bindVertexArray(this.diagnosticResource.vao),i.disable(i.DEPTH_TEST),i.drawArrays(i.LINES,0,this.diagnosticResource.count),i.enable(i.DEPTH_TEST)}setSelection(e){this.selection!==e&&(this.free(this.selectionResource),this.selectionResource=null,this.selection=e)}drawSelection(e,i){let o=this.gl,s=this.uniforms,n=J(this.selection);this.selectionResource??=this.upload(to(this.selection.geometry.bounds)),o.uniformMatrix4fv(s.mvp,!1,new Float32Array(Ve(e,n))),o.uniformMatrix4fv(s.modelMatrix,!1,new Float32Array(n)),o.uniformMatrix3fv(s.normalMatrix,!1,new Float32Array([1,0,0,0,1,0,0,0,1])),o.uniform4fv(s.section,[0,0,0,0]),o.uniform1i(s.appearance,0),o.uniform1i(s.useColors,0),o.uniform1i(s.unlit,1);let r=i==="transparent"?[1,1,1]:Z(i);o.uniform3fv(s.tint,r[0]+r[1]+r[2]<1.5?[.42,.81,.96]:[.08,.43,.65]),o.bindVertexArray(this.selectionResource.vao),o.disable(o.DEPTH_TEST),o.uniform1f(s.opacity,.18),o.drawArrays(o.LINES,0,this.selectionResource.count),o.enable(o.DEPTH_TEST),o.uniform1f(s.opacity,.9),o.drawArrays(o.LINES,0,this.selectionResource.count)}resource(e,i){let o=this.resources.get(e);if(o||(o={},this.resources.set(e,o)),!o[i]){let s=e.geometry,n=i==="edges"||i==="wire",r=n?s[i]:s.positions,d=n?void 0:i==="smooth"?s.smoothNormals:s.normals,l=n?void 0:s.colors,c=this.sharedResources.get(r);c||this.sharedResources.set(r,c=new Set);let m=[...c].find(f=>f.normals===d&&f.colors===l);m||(m=Object.assign(this.upload(r,d,l),{source:r,normals:d,colors:l,users:0}),c.add(m)),m.users++,o[i]=m}return o[i]}setGrid(e){this.grid=e,this.free(this.gridResource),this.gridResource=null}resize(e,i,o=1){let s=this.gl,n=s.getParameter(s.MAX_RENDERBUFFER_SIZE);this.canvas.width=Math.min(n,Math.max(1,Math.round(e*o))),this.canvas.height=Math.min(n,Math.max(1,Math.round(i*o)))}draw(e,i,o,s=!0){if(this.lost)return;let n=this.gl,r=this.uniforms;n.viewport(0,0,this.canvas.width,this.canvas.height),n.clearColor(...o==="transparent"?[0,0,0,0]:[...Z(o),1]),n.depthMask(!0),n.clear(n.COLOR_BUFFER_BIT|n.DEPTH_BUFFER_BIT),n.enable(n.DEPTH_TEST),n.disable(n.CULL_FACE),n.useProgram(this.program),n.vertexAttrib3f(1,0,0,1),n.vertexAttrib3f(2,1,1,1),n.uniform3fv(r.light,W(H(i.position,i.target))),n.uniform3fv(r.eye,i.position);let d=dt(i,this.canvas.width/this.canvas.height),l=e.filter(p=>p.geometry&&p.opacity>0&&p.color!=="transparent"),c=p=>{let g=Q(J(p),p.geometry.bounds.min.map((v,y)=>(v+p.geometry.bounds.max[y])/2)),h=H(g,i.position);return ne(h,h)},m=l.filter(p=>p.opacity>=1&&p.display!=="xray"),f=l.filter(p=>p.opacity<1||p.display==="xray").sort((p,g)=>c(g)-c(p)),b=p=>{let g=J(p),h=we(g),v=p.geometry;n.uniformMatrix4fv(r.mvp,!1,new Float32Array(Ve(d,g))),n.uniformMatrix4fv(r.modelMatrix,!1,new Float32Array(g)),n.uniform4fv(r.section,vt(v.bounds,p.section)),n.uniform1i(r.appearance,{mesh:1,xray:2,studio:3,orientation:4}[p.display]||0),n.uniformMatrix3fv(r.normalMatrix,!1,new Float32Array([h[0],h[4],h[8],h[1],h[5],h[9],h[2],h[6],h[10]])),n.uniform3fv(r.tint,p.color&&p.color!=="transparent"?Z(p.color):v.colors?[1,1,1]:Z("#909090")),n.uniform1f(r.opacity,p.opacity),n.uniform1i(r.useColors,+(!p.color&&!!v.colors));let y=p.display==="wireframe"&&v.wire,M=y?"wire":(p.smooth_shading||p.display==="smooth")&&v.smoothNormals?"smooth":"flat";n.uniform1i(r.unlit,+!!y);let P=p.view_edges||p.display==="edges";P&&(n.enable(n.POLYGON_OFFSET_FILL),n.polygonOffset(1,1));let C=this.resource(p,M);if(n.bindVertexArray(C.vao),p.display==="xray"?(n.enable(n.CULL_FACE),n.cullFace(n.FRONT),n.drawArrays(n.TRIANGLES,0,C.count),n.cullFace(n.BACK),n.drawArrays(n.TRIANGLES,0,C.count),n.disable(n.CULL_FACE)):n.drawArrays(y?n.LINES:n.TRIANGLES,0,C.count),n.disable(n.POLYGON_OFFSET_FILL),P&&v.edges){n.uniform1i(r.useColors,0),n.uniform3fv(r.tint,[.08,.09,.11]),n.uniform1i(r.unlit,1);let w=this.resource(p,"edges");n.bindVertexArray(w.vao),n.drawArrays(n.LINES,0,w.count)}};n.disable(n.BLEND);for(let p of m)b(p);if(this.grid?.infinite)this.infiniteGrid??=new xt(n),this.infiniteGrid.draw(d,i,this.grid,o),n.useProgram(this.program);else if(this.grid){if(!this.gridResource){let{size:p,divisions:g}=this.grid,h=[];for(let v=0;v<=g;v++){let y=-p/2+p*v/g;h.push(-p/2,y,0,p/2,y,0,y,-p/2,0,y,p/2,0)}this.gridResource=this.upload(new Float32Array(h))}n.uniformMatrix4fv(r.mvp,!1,new Float32Array(d)),n.uniform4fv(r.section,[0,0,0,0]),n.uniform1i(r.appearance,0),n.uniform1i(r.useColors,0),n.uniform3fv(r.tint,[.7,.73,.78]),n.uniform1f(r.opacity,1),n.uniform1i(r.unlit,1),n.bindVertexArray(this.gridResource.vao),n.drawArrays(n.LINES,0,this.gridResource.count)}n.enable(n.BLEND),n.blendFuncSeparate(n.SRC_ALPHA,n.ONE_MINUS_SRC_ALPHA,n.ONE,n.ONE_MINUS_SRC_ALPHA),n.depthMask(!1);for(let p of f)b(p);s&&this.selection&&l.includes(this.selection)&&this.drawSelection(d,o),s&&this.diagnostic&&e.includes(this.diagnostic.model)&&this.drawDiagnostic(d),n.depthMask(!0),n.disable(n.BLEND),n.bindVertexArray(null),this.frames++}dispose(){this.canvas.removeEventListener("webglcontextlost",this.lostHandler),this.canvas.removeEventListener("webglcontextrestored",this.restoredHandler),this.clear(),this.gl.deleteProgram(this.program),this.gl.getExtension("WEBGL_lose_context")?.loseContext()}};var Et=class{constructor(e,i,o,s,n=0){this.enabled=!0,this.noZoom=!1,this.type=n,this.camera=i,this.invalidate=o,this.pointers=new Map,this.cleanups=[],this.canvas=e;let r=(l,c,m)=>{e.addEventListener(l,c,m),this.cleanups.push(()=>e.removeEventListener(l,c,m))};r("pointerdown",l=>{this.enabled&&(l.preventDefault(),e.focus({preventScroll:!0}),e.setPointerCapture(l.pointerId),this.pointers.set(l.pointerId,{x:l.clientX,y:l.clientY,button:l.button}),s(l,l.pointerType==="touch"?20:l.button===2?3:1))}),r("pointermove",l=>{let c=this.pointers.get(l.pointerId);if(!c||!this.enabled)return;let m={x:l.clientX,y:l.clientY,button:c.button};if(this.pointers.size===2){let f=[...this.pointers.entries()].find(([g])=>g!==l.pointerId)[1],b=Math.hypot(c.x-f.x,c.y-f.y),p=Math.hypot(m.x-f.x,m.y-f.y);b>0&&p>0&&this.zoom(b/p),this.pan((m.x-c.x)/2,(m.y-c.y)/2)}else c.button===2||l.shiftKey||c.button===1?this.pan(m.x-c.x,m.y-c.y):this.orbit((m.x-c.x)/Math.max(1,e.clientHeight)*Math.PI,(m.y-c.y)/Math.max(1,e.clientHeight)*Math.PI);this.pointers.set(l.pointerId,m)});let d=l=>{this.pointers.delete(l.pointerId),e.hasPointerCapture(l.pointerId)&&e.releasePointerCapture(l.pointerId)};r("pointerup",d),r("pointercancel",d),r("lostpointercapture",l=>this.pointers.delete(l.pointerId)),r("wheel",l=>{if(!this.enabled||this.noZoom)return;l.preventDefault();let c=l.deltaY*(l.deltaMode===1?16:l.deltaMode===2?e.clientHeight:1);this.zoom(Math.exp(Math.max(-1,Math.min(1,c*.001))))},{passive:!1}),r("dblclick",l=>{this.enabled&&s(l,11)}),r("contextmenu",l=>l.preventDefault())}orbit(e,i){let o=this.camera,s=H(o.position,o.target),n=W(o.up);s=mt(s,n,-e);let r=W(se(n,s)),d=mt(s,r,-i);if(this.type===1)s=d,o.up=W(mt(n,r,-i));else{let l=W(d),c=l.reduce((m,f,b)=>m+f*n[b],0);Math.abs(c)<.9995&&(s=d)}o.position=ae(o.target,s),this.invalidate()}zoom(e){if(this.noZoom)return;let i=this.camera,o=H(i.position,i.target),s=Math.hypot(...o),n=Math.max(1e-6,Math.min(1e15,s*e));i.position=ae(i.target,re(o,n/(s||1))),this.invalidate()}pan(e,i){let o=this.camera,s=H(o.position,o.target),n=W(se(o.up,s)),r=W(se(s,n)),d=2*Math.hypot(...s)*Math.tan(Math.PI/8)/Math.max(1,this.canvas.clientHeight),l=ae(re(n,-e*d),re(r,i*d));o.target=ae(o.target,l),o.position=ae(o.position,l),this.invalidate()}dispose(){for(let e of this.cleanups)e();this.pointers.clear()}};var Mt=class{constructor(e,{count:i=2,timeout:o=12e4,factory:s}={}){this.url=e,this.count=Math.max(1,Math.min(4,i)),this.timeout=o,this.factory=s,this.queue=[],this.active=new Set,this.next=0,this.disposed=!1}run(e,i,o=[]){if(this.disposed)return Promise.reject(new Error("Viewer disposed"));let s=++this.next,n,r=new Promise((d,l)=>{n={id:s,task:e,progress:i,transfer:o,resolve:d,reject:l},this.queue.push(n)});return r.cancel=()=>this.cancel(n),this.pump(),r}cancel(e){e.done||(e.done=!0,this.queue=this.queue.filter(i=>i!==e),clearTimeout(e.timer),e.worker?.terminate(),this.active.delete(e),e.reject(new DOMException("Loading cancelled","AbortError")),this.pump())}pump(){for(;!this.disposed&&this.active.size<this.count&&this.queue.length;){let e=this.queue.shift();this.active.add(e);let i=(o,s)=>{e.done||(e.done=!0,clearTimeout(e.timer),e.worker?.terminate(),this.active.delete(e),o?e.reject(o):e.resolve(s),this.pump())};try{e.worker=this.factory?this.factory():new Worker(this.url,{type:"module",name:"ViewSTL parser"}),e.worker.onmessage=({data:o})=>{if(o.id===e.id){if(o.progress){e.progress?.(o.progress);return}i(o.error?new Error(o.error):null,o.result)}},e.worker.onerror=o=>{o.preventDefault(),i(new Error(o.message||"Worker failed; check worker URL and Content Security Policy"))},e.worker.onmessageerror=()=>i(new Error("Invalid worker response")),e.timer=setTimeout(()=>i(new Error("File processing timed out")),this.timeout),e.worker.postMessage({id:e.id,task:e.task},e.transfer)}catch(o){i(o)}}}clear(){for(let e of[...this.queue,...this.active])this.cancel(e)}dispose(){this.disposed=!0,this.clear()}};function io(t,e={}){let i=new AbortController,o=i.signal,s=this._generation,n=[],r=new Map,d=new Set,l=this._models.size>0,c,m=0,f,b=!1,p,g=()=>{i.abort(),c?.cancel?.();for(let[M,P]of r)this._models.get(M)===P&&this.remove_model(M)},h=()=>{if(o.aborted||s!==this._generation||this.killsign)throw new DOMException("Scene opening cancelled","AbortError")},v=M=>e.on_progress?.(M);e.signal?.addEventListener("abort",g,{once:!0}),e.signal?.aborted&&g(),o.addEventListener("abort",()=>c?.cancel?.(),{once:!0}),this._aborters.add(i);let y=(async()=>{await this.when_ready,h(),f=this.get_camera_state();let M=e.format||ke(typeof t=="string"?t:t.name);if(!["vsb","vsj"].includes(M))throw new Error("Choose VSB or VSJ for a scene");let P,C;if(typeof t=="string"){if(P=Xt(t,document.baseURI),!this.options.url_import_endpoint)throw new Error("Configure url_import_endpoint for scene URL imports");if(C=new URL(this.options.url_import_endpoint,document.baseURI).href,new URL(C).origin!==location.origin)throw new Error("The URL relay must use the same origin as this page")}let w=this.limits.max_memory_bytes-this._occupiedMemory();Y(this.limits,this._occupiedMemory()+67108864,"scene opening");let R={...this.limits,max_memory_bytes:w,max_file_bytes:Math.min(this.limits.max_file_bytes,Math.floor((w-67108864)/4))};m=Math.max(0,w-67108864),this._sceneBytes=(this._sceneBytes||0)+m,c=this._pool.run({kind:"read-scene",source:t,remote:P,relay:C,format:M,name:`scene.${M}`,limits:R},S=>{try{v({...S,phase:"reading-scene"})}catch(F){p=F,c.cancel()}});let k;try{k=await c}catch(S){throw p||S}c=null,h();let{scene:_,files:A,base:I}=k,E=gt(this.get_camera_bookmarks(),_.camera_bookmarks||[]);this._sceneBytes-=m,m=Object.values(A||{}).reduce((S,F)=>S+F.byteLength,0)+JSON.stringify(_).length*2,this._sceneBytes+=m;let L=e.files||[],T=[],j=_.models.map(S=>{let F={...S};if(A)F.local_file=new File([A[S.filename]],S.filename);else{let N=Ki(S.filename,L);if(N)F.local_file=N,d.add(N);else{let D=Xt(S.filename,P?I:void 0);D?F.remote_url=D:T.push(S.filename)}}if(F.remote_url&&!this.options.url_import_endpoint)throw new Error("Scene URL references require a configured URL relay");return F});if(T.length)throw new Error("Choose the VSJ together with these model files: "+T.slice(0,8).join(", ")+(T.length>8?"\u2026":""));if(j.length+this._models.size>this.limits.max_archive_entries)throw new Error("Scene model count limit exceeded");for(let S=0;S<j.length;S++){h(),v({phase:"opening-model",loaded:S,total:j.length}),h();let F=j[S],N=this.max_model_id+1;this.add_model({...F,id:N,animation:null,animation_state:null});let D=this._models.get(N);if(!D)throw new Error(this.error||"Invalid scene model");if(n.push(N),r.set(N,D),D._sceneImportPending=!0,await this._pending.get(N),h(),this._models.get(N)!==D||!D.geometry)throw new Error(this.error||"A scene model could not be opened");let be=_.center_models??this.center_models?D.geometry.bounds.min.map((G,K)=>(G+D.geometry.bounds.max[K])/2):[0,0,0],Re=D.center.map((G,K)=>G-be[K]),X=Q(J({...D,x:0,y:0,z:0,center:[0,0,0],scaleVector:D.scaleVector}),Re);if(F.animation?D.center=[...F.animation_state?.center??be]:["x","y","z"].forEach((G,K)=>D[G]+=X[K]),[...this._models.values()].reduce((G,K)=>G+(K.geometry?.triangles||0),0)>this.limits.max_triangles)throw new Error("Scene triangle limit exceeded")}v({phase:"complete",loaded:j.length,total:j.length}),h();for(let S=0;S<n.length;S++){let F=r.get(n[S]),N=j[S];N.animation&&this._startAnimation(F,N.animation,N.animation_state),F._sceneImportPending=!1}return _.bg_color!==void 0&&this.set_bg_color(_.bg_color),_.infinite_grid?this.set_infinite_grid(!0,_.infinite_grid.spacing,_.infinite_grid.height):this.set_grid(!!_.grid),_.auto_rotate!==void 0&&this.set_auto_rotate(_.auto_rotate),this._restoreCamera=_.camera_state||(l?f:null),this.camera_bookmarks=E,_.display_units&&(this.display_units=_.display_units),b=!0,{model_ids:n,scene:_,used_files:[...d]}})().catch(M=>{throw g(),M}).finally(()=>{e.signal?.removeEventListener("abort",g),this._aborters.delete(i),this._sceneBytes=(this._sceneBytes||0)-m,this._sceneLoads.delete(y),s===this._generation&&!this.killsign&&(!b&&f&&(this._restoreCamera=f),this._finishSession())});return this._sessionActive=!0,this._sceneLoads.add(y),y}var Xe=new WeakMap;function zt(t,e){let i=Xe.get(e);return!!i&&i.viewer.deref()===t&&i.models.every(({model:o,geometry:s,signature:n})=>{let r=o.deref();return r&&t._models.get(r.id)===r&&r.geometry===s.deref()&&ye(r)===n})}async function oo(t={}){await this.when_ready;let e=Bi(t);if(this.killsign)throw new Error("Viewer disposed");let i=t.model_ids;if(i==="selected"&&(i=this.renderer?.selection?[this.renderer.selection.id]:[]),i??=[...this._models.keys()],!Array.isArray(i)||!i.length||new Set(i).size!==i.length||i.some(g=>!Number.isSafeInteger(g)))throw new Error("Choose one or more unique model IDs");if(i.length>this.limits.max_archive_entries)throw new Error("Print check model limit exceeded");let o=i.map(g=>{let h=this._model(g);if(!h.geometry||h._sceneImportPending)throw new Error("Wait for models to finish opening");return{model:h,geometry:h.geometry,signature:ye(h)}}),s=JSON.stringify([i,e]);if(t.signal?.aborted)throw new DOMException("Print check cancelled","AbortError");if(this._printCache?.key===s&&zt(this,this._printCache.report)){let g=structuredClone(this._printCache.report);return Xe.set(g,Xe.get(this._printCache.report)),g}if(this._printJobs?.size)throw new Error("A print check is already running");this._printJobs??=new Map;let n=new AbortController,r=()=>n.abort();t.signal?.addEventListener("abort",r,{once:!0}),this._aborters.add(n),this._printJobs.set(n,new Set(o.map(g=>g.model)));let d,l=0,c,m=()=>d?.cancel?.();n.signal.addEventListener("abort",m);let f=()=>{if(n.signal.aborted||this.killsign)throw new DOMException("Print check cancelled","AbortError");if(o.some(({model:g,geometry:h,signature:v})=>this._models.get(g.id)!==g||g.geometry!==h||ye(g)!==v))throw new Error("Model changed. Run the print check again.")},b=g=>{f(),t.on_progress?.(g)},p=[];try{this._printCache=null;let g=o.length*256*1024;Y(this.limits,this._occupiedMemory()+g,"print report"),l=g,this._printBytes=(this._printBytes||0)+l;for(let M=0;M<o.length;M++){f();let{model:P,geometry:C}=o[M],w=pt(C.triangles),R=this._occupiedMemory();Y(this.limits,R+w,"print check"),this._printBytes+=w,l+=w;let k=new Float32Array(C.positions.length);for(let A=0;A<k.length;A+=262144)f(),k.set(C.positions.subarray(A,A+262144),A),A+262144<k.length&&await new Promise(I=>setTimeout(I,0));let _=e.apply_transforms?P:{...P,x:0,y:0,z:0,rotationx:0,rotationy:0,rotationz:0,center:[0,0,0],scaleVector:[1,1,1].map(()=>P.unitScale*(P.size_state?.unit_factor??1))};b({phase:"Starting",model_id:P.id,model_index:M,total_models:o.length}),d=this._pool.run({kind:"print-check",model:{id:P.id,name:P.orig_filename||P.filename||`Model ${P.id}`,positions:k,matrix:J(_),source_units:C.units||null},options:e,limits:{...this.limits,max_memory_bytes:this.limits.max_memory_bytes-R}},A=>{try{b({...A,model_id:P.id,model_index:M,total_models:o.length})}catch(I){c=I,n.abort()}},[k.buffer]);try{p.push(await d)}catch(A){throw c||A}finally{d=null,this._printBytes-=w,l-=w}}f();let h={version:1,model_ids:i.slice(),settings:e,models:p,summary:p.some(M=>M.summary==="issues_found")?"issues_found":p.some(M=>M.summary==="incomplete")?"incomplete":"no_issues_found",scope:"Each model checked separately; no cross-model union or collision analysis.",estimated:!!e.profile},v={viewer:new WeakRef(this),models:o.map(({model:M,geometry:P,signature:C})=>({model:new WeakRef(M),geometry:new WeakRef(P),signature:C}))};Xe.set(h,v);let y=structuredClone(h);return Xe.set(y,v),JSON.stringify(y).length<2*1024*1024&&this._occupiedMemory()+4*1024**2<=this.limits.max_memory_bytes&&(this._printCache={key:s,report:y}),b({phase:"Complete",total_models:o.length}),h}finally{d?.cancel?.(),this._printBytes=(this._printBytes||0)-l,t.signal?.removeEventListener("abort",r),this._aborters.delete(n),this._printJobs.delete(n)}}function no(t,{issue:e,model_id:i=t.model_ids[0]}={}){if(!zt(this,t))throw new Error("Print report is stale. Run the check again.");let o=t.models.find(l=>l.model_id===i),s=o?.checks.find(l=>l.code===e);if(!s)throw new Error("Unknown print check issue");let n=this._model(i),r=n.geometry.positions,d=[];if(s.edge_vertices?.length)d.push(...s.edge_vertices.slice(0,1536));else for(let l of s.triangle_ids.slice(0,128))if(!(!Number.isInteger(l)||l<0||l>=n.geometry.triangles))for(let c=0;c<3;c++)d.push(...r.subarray(l*9+c*3,l*9+c*3+3),...r.subarray(l*9+(c+1)%3*3,l*9+(c+1)%3*3+3));if(d.some(l=>!Number.isFinite(l)))throw new Error("Invalid print highlight");return this.renderer.setDiagnostic(d.length?{model:n,positions:new Float32Array(d),signature:ye(n)}:null),this._invalidate(),d.length/6}function $t(t,e){return`${String(t||"scene").split(/[\\/]/).pop().split(/[?#]/)[0].replace(/[<>:"|*\x00-\x1f\x7f]/g,"_").replace(/\.(?:stl|obj|3mf|step|stp|iges|igs|zip|vsb|vsj)$/i,"").replace(/[. ]+$/g,"").slice(0,160)||"scene"}.${e}`}function ro(t={}){let e={stp:"step",igs:"iges"},i=String(t.format||"").toLowerCase(),o=e[i]||i;if(!["stl","obj","3mf","step","iges"].includes(o))throw new Error("Export format must be stl, obj, 3mf, step or iges");let s=t.units??"mm";if(!["mm","inch"].includes(s))throw new Error("Export units must be mm or inch");for(let d of["apply_transforms","colors"])if(t[d]!==void 0&&typeof t[d]!="boolean")throw new Error(`${d} must be a boolean`);if(t.on_progress!==void 0&&typeof t.on_progress!="function")throw new Error("on_progress must be a function");let n=t.colors!==!1&&["obj","3mf"].includes(o),r=o==="obj"&&n?"zip":o;return{format:o,units:s,colors:n,apply_transforms:t.apply_transforms!==!1,filename:$t(t.filename,r)}}function so(t,e){let i=t.reduce((s,n)=>s+n.geometry.triangles,0);return 67108864+i*{stl:192,obj:2400,"3mf":3e3,step:12e3,iges:4e3}[e.format]+t.length*4096}async function ao(t,e,i=()=>{},o){let s,n=0;if(t instanceof ArrayBuffer){if(t.byteLength>e)throw new Error("File size limit exceeded");return i(t.byteLength,t.byteLength),t}if(t instanceof Blob){if(n=t.size,n>e)throw new Error("File size limit exceeded");if(o?.aborted)throw new DOMException("Loading cancelled","AbortError");i(0,n);let f=await t.arrayBuffer();if(o?.aborted)throw new DOMException("Loading cancelled","AbortError");return i(n,n),f}else{let f=new URL(String(t),globalThis.location?.href);if(!["http:","https:","blob:"].includes(f.protocol))throw new Error("Unsupported file URL protocol");let b=await fetch(f,{signal:o,credentials:"same-origin"});if(!b.ok)throw new Error(`HTTP ${b.status}: ${f.pathname}`);n=Number(b.headers.get("content-length"))||0,s=b.body}if(n>e)throw new Error("File size limit exceeded");if(!s)throw new Error("Empty response body");let r=s.getReader(),d=[],l=0;try{for(;;){if(o?.aborted)throw new DOMException("Loading cancelled","AbortError");let{done:f,value:b}=await r.read();if(f)break;if(l+=b.length,l>e)throw new Error("File size limit exceeded");d.push(b),i(l,Math.max(n,l))}}catch(f){throw await r.cancel().catch(()=>{}),f}finally{r.releaseLock()}let c=new Uint8Array(l),m=0;for(let f of d)c.set(f,m),m+=f.length;return i(l,l),c.buffer}function lo(t,e){if(!t?.isMesh&&!t?.geometry)throw new Error("Expected a Three.js mesh");if(t.isSkinnedMesh||t.isInstancedMesh||t.children?.length||t.morphTargetInfluences?.some(Boolean))throw new Error("Only a static standalone Three.js mesh is supported");let i=t.material;if(Array.isArray(i)||i?.isShaderMaterial||i?.map)throw new Error("Multiple, textured or shader materials need an application adapter");let o=t.geometry,s,n=null;if(o?.attributes?.position){let r=o.attributes.position,d=o.index,l=d?.count??r.count;if(l%3||l/3>e.max_triangles)throw new Error("Invalid or oversized mesh");s=new Float32Array(l*3),o.attributes.color&&(n=new Float32Array(l*3));for(let c=0;c<l;c++){let m=d?d.getX(c):c;for(let[f,b]of["getX","getY","getZ"].entries())s[c*3+f]=r[b](m),n&&(n[c*3+f]=o.attributes.color[b](m))}}else if(o?.vertices&&o?.faces){if(o.faces.length>e.max_triangles)throw new Error("Triangle limit exceeded");s=new Float32Array(o.faces.length*9),i?.vertexColors&&(n=new Float32Array(s.length)),o.faces.forEach((r,d)=>{for(let[l,c]of[r.a,r.b,r.c].entries()){let m=o.vertices[c];if(!m)throw new Error("Invalid mesh index");s.set([m.x,m.y,m.z],d*9+l*3),n&&n.set([r.color.r,r.color.g,r.color.b],d*9+l*3)}})}else throw new Error("Unsupported Three.js geometry");return wt(s,n,e)}function co(t,e){if(!e?.Mesh||!e?.BufferGeometry||!e?.BufferAttribute)throw new Error("get_model_mesh requires options.three or globalThis.THREE; use get_model_data for native geometry");let i=t.geometry,o=new e.BufferGeometry,s=i.positions.slice(),n=t.scaleVector,r=t.center;for(let m=0;m<s.length;m++)s[m]=(s[m]-r[m%3])*n[m%3];let d=(m,f)=>{let b=new e.BufferAttribute(f,3);o.setAttribute?o.setAttribute(m,b):o.addAttribute(m,b)};d("position",s),i.colors&&!t.color&&d("color",i.colors.slice()),o.computeVertexNormals();let l=new e.MeshLambertMaterial({color:t.color==="transparent"?"#909090":t.color||(i.colors?"#ffffff":"#909090"),vertexColors:i.colors&&!t.color?e.VertexColors??!0:!1,side:e.DoubleSide,transparent:t.opacity<1||t.color==="transparent",opacity:t.color==="transparent"?0:t.opacity,wireframe:t.display==="wireframe",flatShading:t.display!=="smooth"}),c=new e.Mesh(o,l);return c.position.set(t.x,t.y,t.z),c.rotation.set(t.rotationx,t.rotationy,t.rotationz),c}var ei=["x","y","z","rotationx","rotationy","rotationz","scalex","scaley","scalez"],Lo=["id","filename","remote_url","remote_format","orig_filename","local_file","mesh","data","x","y","z","display","color","scale","scalex","scaley","scalez","rotationx","rotationy","rotationz","opacity","view_edges","smooth_shading","section","units","animation","animation_state","size_state","display_name"],$=(t,e)=>{if(typeof t!="number"||!Number.isFinite(t))throw new Error(`${e} must be a finite number`);return t},Ce=(t,e)=>{if($(t,e),t<=0)throw new Error(`${e} must be positive`);return t},ti=(t,e)=>[$(t.x,`${e}.x`),$(t.y,`${e}.y`),$(t.z,`${e}.z`)],At=t=>({x:t[0],y:t[1],z:t[2]}),St=t=>String(t||"model.stl").split(/[\\/]/).pop().split(/[?#]/)[0];function Ke(t,e){let i=document.createElement("a"),o=URL.createObjectURL(t);i.href=o,i.download=St(e),i.click(),setTimeout(()=>URL.revokeObjectURL(o),1e3)}function mo(t){let e={};for(let i of Lo)Object.hasOwn(t,i)&&(e[i]=t[i]);return e}var Ee=class t{static version="2.0.0-rc.6";static workerURL=null;constructor(e,i={}){if(!e?.appendChild)throw new TypeError("StlViewer requires a DOM container");this.parent_element=e,this.options={...i},this.error=null,this.ready=!1,this.killsign=!1,this.models=[],this.models_ref=Object.create(null),this.models_count=0,this.max_model_id=-1,this.load_status=Object.create(null),this.load_session=0,this._models=new Map,this._pending=new Map,this._jobs=new Map,this._derived=new Set,this._memoryReservations=new Map,this._exportBytes=0,this._loadTail=Promise.resolve(),this._sceneLoads=new Set,this._aborters=new Set,this._generation=0,this._sessionActive=!1,this._frame=0,this._lastTime=0,this.camera_bookmarks=[],this.display_units="mm",this.grid=null,this._gridAuto=!1,this.camera={position:[0,0,100],target:[0,0,0],up:[0,1,0],near:.01,far:1e4},this.when_ready=new Promise((o,s)=>{this._readyResolve=o,this._readyReject=s}),this.when_ready.catch(()=>{});for(let o of["ready_callback","all_loaded_callback","model_loaded_callback","load_error_callback","loading_progress_callback","on_model_drop","animation_state_callback","animation_complete_callback"])this[o]=i[o]??null;this.onmousedown_callback=i.on_model_mousedown??i.on_model_mouseclick??null,queueMicrotask(()=>this._initialize())}_initialize(){if(!this.killsign)try{let e=this.options;if(this.limits=Ji(e),this.bg_color=e.bg_color??e.bgcolor??"transparent",this.bg_color!=="transparent"&&Z(this.bg_color),e.worker_count!==void 0&&(!Number.isInteger(e.worker_count)||e.worker_count<1||e.worker_count>4))throw new Error("worker_count must be 1\u20134");if(e.worker_timeout!==void 0&&Ce(e.worker_timeout,"worker_timeout"),e.pixel_ratio!==void 0&&Ce(e.pixel_ratio,"pixel_ratio"),e.controls!==void 0&&e.controls!==0&&e.controls!==1)throw new Error("controls must be 0 or 1");this.center_models=e.center_models??!0,this.auto_resize=e.auto_resize??!0,this.auto_rotate=e.auto_rotate??!1,this.mouse_zoom=e.mouse_zoom??!0,this.send_no_model_click_event=e.send_no_model_click_event??!1,this.zoom=e.zoom??-1,this.canvas_width=e.width??e.canvas_width??"100%",this.canvas_height=e.height??e.canvas_height??"100%",this.canvas=document.createElement("canvas"),this.canvas.style.cssText="display:block;touch-action:none;outline-offset:3px;",this._setSizeStyle(),this.canvas.tabIndex=0,this.canvas.setAttribute("aria-label","3D model viewer. Drag to rotate, shift-drag to pan, scroll to zoom."),this.parent_element.appendChild(this.canvas),this.renderer=new kt(this.canvas,()=>{this._suspendAnimations(!0),this._message("Graphics interrupted. Waiting for the browser to restore rendering\u2026")},()=>{this._removeMessage(),this._suspendAnimations(this.canvas.ownerDocument.hidden),this._invalidate()},o=>this._error(o)),this.controls=new Et(this.canvas,this.camera,()=>this._invalidate(),(o,s)=>this._pick(o,s),e.controls??0),this.controls.noZoom=!this.mouse_zoom;let i=e.worker_url??t.workerURL;if(e.worker_url===void 0&&typeof e.load_three_files=="string"&&(i=new URL("viewstl.worker.js",new URL(e.load_three_files||"./",document.baseURI)).href),!i&&!e.worker_factory)throw new Error("Specify worker_url when using the CommonJS build");this._pool=new Mt(i,{count:e.worker_count??2,timeout:e.worker_timeout??12e4,factory:e.worker_factory}),this._drop=o=>{o.preventDefault();let s=[...o.dataTransfer.files];for(let n of s)this._callback("on_model_drop",n.name),this.add_model({local_file:n})},this._drag=o=>o.preventDefault(),this.set_drag_and_drop(e.allow_drag_and_drop??!0),this.set_auto_resize(this.auto_resize),this.do_resize(),this.camera.position=[e.camerax??0,e.cameray??0,this.zoom>=0?Math.max(this.zoom,1e-6):e.cameraz??100],e.camera_state&&(this.set_camera_state(e.camera_state),this._restoreCamera=e.camera_state),e.grid&&this.set_grid(!0),this._key=o=>{if(!this.controls.enabled)return;let s={ArrowLeft:()=>this.controls.orbit(-.12,0),ArrowRight:()=>this.controls.orbit(.12,0),ArrowUp:()=>this.controls.orbit(0,-.12),ArrowDown:()=>this.controls.orbit(0,.12),"+":()=>this.controls.zoom(.9),"-":()=>this.controls.zoom(1.1),f:()=>this.set_auto_zoom()};s[o.key]&&(o.preventDefault(),s[o.key]())},this.canvas.addEventListener("keydown",this._key),this._visibility=()=>this._suspendAnimations(this.canvas.ownerDocument.hidden||this.renderer.lost),this.canvas.ownerDocument.addEventListener("visibilitychange",this._visibility),this._animationSuspended=this.canvas.ownerDocument.hidden,this.ready=!0,this._readyResolve(this),this._callback("ready_callback"),e.models&&this.add_models(e.models),this._invalidate()}catch(e){this.ready=!1,this._readyReject(e),this._error(e),this._message(e.message),this._pool?.dispose(),this.controls?.dispose(),this.renderer?.dispose(),this._resizeObserver?.disconnect(),this._visibility&&this.canvas.ownerDocument.removeEventListener("visibilitychange",this._visibility)}}_callback(e,...i){let o=this[e];if(typeof o=="function")try{o(...i)}catch(s){console.error(`ViewSTL ${e} callback failed`,s)}}_error(e){return this.error=e?.message??String(e),this._callback("load_error_callback",this.error),null}_message(e){this._removeMessage(),this._messageElement=document.createElement("p"),this._messageElement.setAttribute("role","status"),this._messageElement.textContent=e,this.parent_element.appendChild(this._messageElement)}_removeMessage(){this._messageElement?.remove(),this._messageElement=null}_setSizeStyle(){this.canvas.style.width=typeof this.canvas_width=="number"?`${this.canvas_width}px`:this.canvas_width,this.canvas.style.height=typeof this.canvas_height=="number"?`${this.canvas_height}px`:this.canvas_height}_guard(e){if(this.killsign)return null;try{return e()}catch(i){return this._error(i)}}_model(e){let i=this._models.get(Number(e));if(!i)throw new Error(`Model id not found: ${e}`);return i}_invalidate(){let e=this.renderer?.diagnostic;e&&ye(e.model)!==e.signature&&this.renderer.setDiagnostic(null),!(this.killsign||!this.renderer||this.renderer.lost||this._frame||this._animationSuspended)&&(this._frame=requestAnimationFrame(i=>{this._frame=0,this._render(i)}))}_render(e){let i=this._lastTime?Math.min((e-this._lastTime)/1e3,.1):0;this._lastTime=e;let o=!1;for(let n of this._models.values())n.geometry&&!n._sceneImportPending&&n._animation&&!n._animation.paused&&(this._animate(n,e),o||=!!n._animation&&!n._animation.paused);this.auto_rotate&&this.controls.enabled&&this.controls.orbit(i*.3,0);let s=this.renderer.diagnostic;s&&ye(s.model)!==s.signature&&this.renderer.setDiagnostic(null),this._clip();try{this.renderer.draw([...this._models.values()].filter(n=>!n._sceneImportPending),this.camera,this.bg_color)}catch(n){this.renderer.clear(),this._error(n);return}o||this.auto_rotate&&this.controls.enabled?this._invalidate():this._lastTime=0}_bounds(){let e=[1/0,1/0,1/0],i=[-1/0,-1/0,-1/0],o=0;for(let s of this._models.values())if(s.geometry&&!s._sceneImportPending){o++;let{bounds:n}=s.geometry,r=J(s);for(let d=0;d<8;d++){let l=Q(r,[0,1,2].map(c=>n[d&1<<c?"max":"min"][c]));for(let c=0;c<3;c++)e[c]=Math.min(e[c],l[c]),i[c]=Math.max(i[c],l[c])}}return o?{min:e,max:i,center:e.map((s,n)=>(s+i[n])/2),radius:Math.max(Math.hypot(...H(i,e))/2,1e-6)}:null}_clip(){let e=this._bounds(),i=Math.hypot(...H(this.camera.position,e?.center??this.camera.target)),o=e?.radius??10;this.camera.near=Math.max(1e-6,Math.min(o*.001,Math.max(i-o,1e-6)*.1)),this.camera.far=Math.max(this.camera.near*100,i+o*4,100)}_progress(e,i){!this._models.has(e)||this.killsign||(this.load_status[e]=i,this._callback("loading_progress_callback",this.load_status,this.load_session))}add_models(e){return this._guard(()=>{if(!Array.isArray(e))throw new Error("models must be an array");for(let i of e)this.add_model(i)})}add_model(e){return this._guard(()=>{if(!e||typeof e!="object")throw new Error("Invalid model");let i=mo(e),o=i.filename??i.local_file?.name??"model.stl";if(/\.vsj(?:[?#]|$)/i.test(o))return this.load_vsj(i.local_file??o);if(/\.vsb(?:[?#]|$)/i.test(o))return this.load_vsb(i.local_file??o);let s=i.id===void 0||i.id===-1?this.max_model_id+1:i.id;if(!Number.isSafeInteger(s)||s<0||this._models.has(s))throw new Error(`Invalid or duplicate model id: ${s}`);let n={...i,id:s,filename:i.filename??i.local_file?.name??"",x:0,y:0,z:0,rotationx:0,rotationy:0,rotationz:0,scalex:1,scaley:1,scalez:1,opacity:1,units:"mm",display:"flat",view_edges:!1,color:null,unitScale:1,center:[0,0,0],geometry:null};for(let l of ei)n[l]=i[l]??(l.startsWith("scale")?i.scale??1:0);for(let l of ei)$(n[l],l),l.startsWith("scale")&&Ce(n[l],l);if(i.size_state&&(n.size_state=Wt(i.size_state)),i.display_name!=null){if(typeof i.display_name!="string"||i.display_name.length>1024)throw new Error("Invalid model name");n.display_name=i.display_name}if(n.opacity=i.opacity??i.mesh?.material?.opacity??1,$(n.opacity,"opacity"),n.opacity<0||n.opacity>1)throw new Error("Opacity must be between 0 and 1");if(n.display=i.display??"flat",Object.assign(n,yt(n.display,i.smooth_shading??n.display==="smooth")),n.section=bt(i.section),n.units=i.units??"mm",!["mm","inch"].includes(n.units))throw new Error("Invalid units");if(n.color=i.color??(i.mesh?.material?.color?.getHexString?"#"+i.mesh.material.color.getHexString():null),n.color&&n.color!=="transparent"&&Z(n.color),n.view_edges=!!i.view_edges,n.animation=i.animation==null?null:qe(i.animation),n.animation_state=i.animation_state==null?null:He(i.animation_state),n.animation_state&&!n.animation)throw new Error("Playback state needs an animation");n.animation&&We(n.animation,n,n.animation_state),Object.defineProperty(n,"scaleVector",{get:()=>[n.scalex*n.unitScale,n.scaley*n.unitScale,n.scalez*n.unitScale]}),this.max_model_id=Math.max(s,this.max_model_id),this._models.set(s,n),this.models_ref[s]=this.models.length,this.models.push(n),this.models_count=this._models.size,this._sessionActive=!0,this.load_status[s]={loaded:0,total:0};let r=this._generation,d=this._loadModel(n,i,r).then(()=>{r!==this._generation||this._models.get(s)!==n||(this._pending.delete(s),this._finishSession(),this._callback("model_loaded_callback",s))}).catch(l=>{r===this._generation&&this._models.get(s)===n&&(this._pending.delete(s),this._deleteModel(n),l.name!=="AbortError"&&this._error(l),this._finishSession())}).finally(()=>{this._jobs.delete(n)});this._pending.set(s,d)})}_occupiedMemory(e){let i=(this._exportBytes||0)+(this._sceneBytes||0)+(this._printBytes||0)+(this._printCache?4194304:0);for(let o of this._models.values())if(o!==e){let s=this._memoryReservations?.get(o);i+=Math.max(Je(o.geometry),[...s?.values()||[]].reduce((n,r)=>n+r.bytes,0))}return i}_reserveMemory(e,i,o="derive"){this._memoryReservations??=new Map;let s=this._memoryReservations.get(e);s||this._memoryReservations.set(e,s=new Map);let n={};return s.set(n,{bytes:i,kind:o}),()=>{s.delete(n),!s.size&&this._memoryReservations.get(e)===s&&this._memoryReservations.delete(e)}}async _loadModel(e,i,o){let s=()=>{};if(this.options.max_memory_bytes!==void 0){let n=this._loadTail;this._loadTail=new Promise(r=>{s=r}),await n}try{await this._readModel(e,i,o)}finally{s()}}async _readModel(e,i,o){if(await this.when_ready,this.killsign||o!==this._generation||this._models.get(e.id)!==e)return;let s=Math.max(1,this.limits.max_memory_bytes-this._occupiedMemory(e)),n={...this.limits,max_memory_bytes:s};Y(n,67108864,"scene");let r=this.limits.max_memory_bytes<Number.MAX_SAFE_INTEGER?this._reserveMemory(e,s-67108864,"parse"):()=>{};try{let d=Jt(e);if(i.mesh)e.geometry=lo(i.mesh,n);else if(i.data)e.geometry=wt(new Float32Array(i.data.positions),i.data.colors?new Float32Array(i.data.colors):null,n);else{let l=i.local_file??i.filename??i.remote_url;if(!l)throw new Error("A filename, local_file or mesh is required");let c;if(i.remote_url){let f=new URL(i.remote_url);if(!["https:","http:"].includes(f.protocol)||f.username||f.password)throw new Error("Use a public HTTP or HTTPS file URL without login credentials.");if(!this.options.url_import_endpoint)throw new Error("Configure url_import_endpoint to import remote URLs through a relay.");if(c=new URL(this.options.url_import_endpoint,document.baseURI).href,new URL(c).origin!==location.origin)throw new Error("The URL relay must use the same origin as this page.")}let m=this._pool.run({kind:"parse",remote:i.remote_url,format:i.remote_format,relay:c,source:typeof l=="string"?new URL(l,document.baseURI).href:l,name:e.display_name||e.filename,limits:n,features:d.smooth||d.edges||d.wire?d:null},f=>this._progress(e.id,f));this._jobs.set(e,m),e.geometry=await m,i.remote_url&&(e.filename=e.geometry.source_name,delete e.remote_url,delete e.remote_format)}if(this.killsign||o!==this._generation||this._models.get(e.id)!==e){e.geometry=null;return}this.center_models&&(e.center=e.geometry.bounds.min.map((l,c)=>(l+e.geometry.bounds.max[c])/2)),(i.mesh||i.data)&&(d.smooth||d.edges||d.wire)&&await this._derive(e,d),e.animation_state&&(e.center=[...e.animation_state.center]),e.animation&&!e._animation&&this._startAnimation(e,e.animation,e.animation_state),delete e.animation_state,delete e.mesh,delete e.data,this._invalidate()}finally{r()}}_finishSession(){this.killsign||this._pending.size||this._sceneLoads.size||!this._sessionActive||(this._sessionActive=!1,this._restoreCamera?(this.set_camera_state(this._restoreCamera),this._restoreCamera=null):this.zoom===-1&&this.set_auto_zoom(),this._gridAuto&&this.set_grid(!0),this.load_session++,this._callback("all_loaded_callback"),this._invalidate())}_deleteModel(e){this._stopAnimation(e,"removed");for(let i of e._measureJobs||[])i.abort();for(let[i,o]of this._printJobs||[])o.has(e)&&i.abort();this._printCache=null,this.renderer?.selection===e&&this.renderer.setSelection(null),this.renderer?.remove(e),this._jobs.get(e)?.cancel?.();for(let i of e._deriveJobs||[])i.cancel?.();this._models.delete(e.id),this._memoryReservations.delete(e),this.models[this.models_ref[e.id]]=null,delete this.models_ref[e.id],delete this.load_status[e.id],this.models_count=this._models.size,this._invalidate()}remove_model(e){return this._guard(()=>{let i=this._model(e);this._deleteModel(i),this._pending.delete(i.id),this._finishSession()})}clean(){if(!this.killsign){this._generation++,this._printCache=null,this.camera_bookmarks=[],this.display_units="mm",this._pool?.clear();for(let e of this._aborters)e.abort();this._aborters.clear();for(let e of this._models.values())this._stopAnimation(e,"clean");this._models.clear(),this._pending.clear(),this._jobs.clear(),this._derived.clear(),this._memoryReservations.clear(),this._sceneLoads.clear(),this.models=[],this.models_ref=Object.create(null),this.models_count=0,this.max_model_id=-1,this.load_status=Object.create(null),this._sessionActive=!1,this.renderer?.clear(),this._restoreCamera=null,this._invalidate()}}dispose(){if(!this.killsign){this.clean(),this.killsign=!0,this.ready=!1,this._readyReject(new Error("Viewer disposed")),cancelAnimationFrame(this._frame),this._frame=0,this._pool?.dispose(),this.controls?.dispose(),this._resizeObserver?.disconnect(),this._windowResize&&window.removeEventListener("resize",this._windowResize),this.renderer?.dispose(),this.canvas&&(this._visibility&&this.canvas.ownerDocument.removeEventListener("visibilitychange",this._visibility),this.canvas.removeEventListener("drop",this._drop),this.canvas.removeEventListener("dragover",this._drag),this.canvas.removeEventListener("keydown",this._key),this.canvas.remove()),this._removeMessage();for(let e of Object.keys(this))e.endsWith("_callback")&&(this[e]=null);this.options={}}}async when_idle(){for(await this.when_ready;this._pending.size||this._sceneLoads.size||this._derived.size;)await Promise.allSettled([...this._pending.values(),...this._sceneLoads,...this._derived]);return this}_derive(e,i){let o=this._occupiedMemory(e)+[...this._memoryReservations?.get(e)?.values()||[]].filter(m=>m.kind==="derive").reduce((m,f)=>m+f.bytes,0),s=ji(e.geometry.triangles,{...i,smooth:i.smooth||!!e.geometry.smoothNormals,edges:i.edges||!!e.geometry.edges,wire:i.wire||!!e.geometry.wire});Y(this.limits,o+s,"view mode");let n=this._reserveMemory(e,s-67108864),r=this._generation,d=e._deriveRevision=(e._deriveRevision||0)+1,l;try{let m=e.geometry.positions.slice();l=this._pool.run({kind:"derive",positions:m,features:i,limits:{...this.limits,max_memory_bytes:this.limits.max_memory_bytes-o}},null,[m.buffer])}catch(m){throw n(),m}(e._deriveJobs??=new Set).add(l);let c=l.then(m=>!this.killsign&&r===this._generation&&d===e._deriveRevision&&this._models.get(e.id)===e?(Object.assign(e.geometry,m),this.renderer.remove(e),this._invalidate(),!0):!1).catch(m=>{m.name!=="AbortError"&&r===this._generation&&this._error(m)}).finally(()=>{n(),e._deriveJobs.delete(l),this._derived.delete(c)});return this._derived.add(c),c}set_view(e,i){return this._guard(()=>{let o=this._model(e),s=o._requestedView||o,n=yt(i.display??s.display,i.smooth_shading??s.smooth_shading),r=Jt({...o,...n}),d=o.geometry,c=d&&(r.smooth&&!d.smoothNormals||r.wire&&!d.wire||r.edges&&(!d.edges||d.edgeAngle!==r.edgeAngle))?this._derive(o,r):null,m=(o._viewRevision||0)+1;o._viewRevision=m,o._requestedView=n;let f=b=>{this._models.get(e)!==o||o._viewRevision!==m||(b&&Object.assign(o,n),delete o._requestedView,this._invalidate())};if(!c)f(!0);else{let b=c.then(f).finally(()=>this._derived.delete(b));this._derived.add(b)}})}set_display(e,i){return this.set_view(e,{display:i,...i==="flat"||i==="smooth"?{smooth_shading:i==="smooth"}:{}})}set_smooth(e,i){return this._guard(()=>{let o=this._model(e),s=o._requestedView||o;return this.set_view(e,{display:s.display==="smooth"?"flat":s.display,smooth_shading:i})})}set_section(e,i){return this._guard(()=>{this._model(e).section=bt(i),this._invalidate()})}set_color(e,i){return this._guard(()=>{i!==null&&i!=="transparent"&&Z(i);let o=this._model(e);o.color=i,this._invalidate()})}set_opacity(e,i){return this._guard(()=>{if($(i,"opacity"),i<0||i>1)throw new Error("Opacity must be between 0 and 1");this._model(e).opacity=i,this._invalidate()})}set_position(e,i,o,s){return this._guard(()=>{let n=this._model(e);[i,o,s].forEach(r=>{r!==void 0&&$(r,"position")}),this._stopAnimation(n,"manual"),[i,o,s].forEach((r,d)=>{r!==void 0&&(n[["x","y","z"][d]]=$(r,"position"))}),this._invalidate()})}set_scale(e,i,o=i,s=i,n=!1){return this._guard(()=>{let r=this._model(e);if([i,o,s].forEach(d=>Ce(d,"scale")),n){if(i/r.scalex!==o/r.scaley||i/r.scalex!==s/r.scalez)throw new Error("keep_prev_scale requires a uniform geometry factor");this._stopAnimation(r,"manual"),r.unitScale*=i/r.scalex}else this._stopAnimation(r,"manual"),[r.scalex,r.scaley,r.scalez]=[i,o,s];r._stats=null,this._invalidate()})}set_selection(e){return this._guard(()=>{this.renderer?.setSelection(e===null?null:this._model(e)),this._invalidate()})}set_rotation(e,i,o,s,n=!1){return this._guard(()=>{let r=this._model(e);[i,o,s].forEach(d=>{d!==void 0&&$(d,"rotation")}),this._stopAnimation(r,"manual"),[i,o,s].forEach((d,l)=>{let c=["rotationx","rotationy","rotationz"][l];d!==void 0&&(r[c]=$(d,"rotation")+(n?r[c]:0))}),this._invalidate()})}rotate(e,i,o,s){return this.set_rotation(e,i,o,s,!0)}set_edges(e,i){return this._guard(()=>{let o=this._model(e);o.view_edges=!!i,i&&o.geometry&&!o.geometry.edges&&this._derive(o,{edges:!0}),this._invalidate()})}set_grid(e,i,o=10){return this._guard(()=>{if(this._gridAuto=!!e&&i===void 0,!e)this.grid=null,this.renderer?.setGrid(null);else{let s=this._bounds();if(i??=s&&Math.max(...H(s.max,s.min))*1.2||10,Ce(i,"grid size"),!Number.isInteger(o)||o<1||o>1e3)throw new Error("Grid divisions must be 1\u20131000");this.grid={size:i,divisions:o},this.renderer?.setGrid(this.grid)}this._invalidate()})}set_infinite_grid(e,i=1,o=0){return this._guard(()=>{Ce(i,"grid spacing"),$(o,"grid height"),this._gridAuto=!1,this.grid=e?{infinite:!0,spacing:i,height:o}:null,this.renderer?.setGrid(this.grid),this._invalidate()})}set_model_units(e,i,o=!1){return this._guard(()=>{if(!["mm","inch"].includes(i))throw new Error("Units must be mm or inch");let s=this._model(e);this._stopAnimation(s,"manual"),o&&s.units!==i&&(s.unitScale*=i==="inch"?25.4:1/25.4),s.units=i,s._stats=null,this._invalidate()})}set_bg_color(e){return this._guard(()=>{e!=="transparent"&&Z(e),this.bg_color=e,this._invalidate()})}set_center_models(e){this.center_models=!!e}set_zoom(e=-1){return this._guard(()=>{if($(e,"zoom"),e===-1)this.zoom=-1,this.set_auto_zoom();else{if(e<0)throw new Error("Zoom must be non-negative or -1");this.zoom=e,this.camera.position[2]=Math.max(e,1e-6),this._invalidate()}})}set_auto_zoom(){let e=this._bounds();if(!e)return;this.zoom=-1;let i=(this.canvas?.clientWidth||1)/(this.canvas?.clientHeight||1),o=Math.min(Math.PI/8,Math.atan(Math.tan(Math.PI/8)*i)),s=W(H(this.camera.position,this.camera.target));this.camera.target=e.center,this.camera.position=ae(e.center,re(Math.hypot(...s)?s:[0,0,1],e.radius/Math.sin(o)*1.08)),this._invalidate()}set_auto_rotate(e){this.auto_rotate=!!e,this._invalidate()}set_mouse_zoom(e){this.mouse_zoom=!!e,this.controls&&(this.controls.noZoom=!e)}set_auto_resize(e){this.auto_resize=!!e,this._resizeObserver?.disconnect(),this._windowResize&&window.removeEventListener("resize",this._windowResize),!(!e||!this.canvas)&&(typeof ResizeObserver<"u"&&(this._resizeObserver=new ResizeObserver(()=>this.do_resize()),this._resizeObserver.observe(this.parent_element)),this._windowResize=()=>this.do_resize(),window.addEventListener("resize",this._windowResize))}do_resize(){if(!this.renderer||this.killsign)return;let e=this.canvas.getBoundingClientRect();this.renderer.resize(e.width||this.parent_element.clientWidth||300,e.height||this.parent_element.clientHeight||150,this.options.pixel_ratio??Math.min(globalThis.devicePixelRatio||1,2)),this._invalidate()}set_on_model_mousedown(e){this.onmousedown_callback=e}set_on_model_mouseclick(e){this.set_on_model_mousedown(e)}set_drag_and_drop(e){this.allow_drag_and_drop=!!e,this.canvas&&(this.canvas.removeEventListener("drop",this._drop),this.canvas.removeEventListener("dragover",this._drag),e&&(this.canvas.addEventListener("drop",this._drop),this.canvas.addEventListener("dragover",this._drag)))}get_camera_state(){return{position:At(this.camera.position),up:At(this.camera.up),target:At(this.camera.target)}}set_camera_state(e){return this._guard(()=>{let i=e.position?ti(e.position,"position"):this.camera.position,o=e.up?ti(e.up,"up"):this.camera.up,s=e.target?ti(e.target,"target"):this.camera.target;if(!Math.hypot(...o)||!Math.hypot(...H(i,s)))throw new Error("Degenerate camera state");this.camera.position=i,this.camera.up=W(o),this.camera.target=s,this._invalidate()})}set_camera(e,i,o){return this.set_camera_state({position:{x:e??this.camera.position[0],y:i??this.camera.position[1],z:o??this.camera.position[2]}})}pick_model(e,i){if(!this.ready||this.killsign||!Number.isFinite(e)||!Number.isFinite(i))return null;let o=this.canvas.getBoundingClientRect();if(!o.width||!o.height||e<o.left||e>o.right||i<o.top||i>o.bottom)return null;let s=we(dt(this.camera,o.width/o.height)),n=Q(s,[(e-o.left)/o.width*2-1,1-(i-o.top)/o.height*2,1]),r=W(H(n,this.camera.position)),d=null,l=1/0;for(let c of this._models.values())if(c.geometry&&c.opacity>0&&c.color!=="transparent"){let m=we(J(c)),f=Yi(c.geometry,Q(m,this.camera.position),Q(m,r,0),vt(c.geometry.bounds,c.section));f<l&&(l=f,d=c.id)}return d===null?null:{id:d,distance:l}}_pick(e,i){if(!this.onmousedown_callback)return;let o=this.pick_model(e.clientX,e.clientY);(o||this.send_no_model_click_event)&&this._callback("onmousedown_callback",o?.id??null,e,o?.distance??0,i)}get_model_size(e){return xe(this._model(e))}resize_model(e,i){return _t.call(this,e,i)}set_file_units(e,i){return Ui.call(this,e,i)}reset_model_size(e){return Vi.call(this,e)}duplicate_model(e){return Gi.call(this,e)}set_camera_view(e){return qi.call(this,e)}set_display_units(e){this.display_units=Se(e)}get_camera_bookmarks(){return structuredClone(this.camera_bookmarks||[])}set_camera_bookmarks(e){this.camera_bookmarks=Ae(e)}measure_model(e,i){return Hi.call(this,e,i)}get_model_info(e,i={}){return this._guard(()=>{let o=this._model(e),s=o.geometry;if(!s)return null;let n=o.scaleVector,r=n.join(",");i.measurements!==!1&&(!o._stats||o._stats.key!==r)&&(o._stats={key:r,...Xi(s,n)});let d=o.units==="inch"?1/25.4:1;return{name:o.filename,orig_filename:o.orig_filename??null,position:{x:o.x,y:o.y,z:o.z},dims:At(s.bounds.min.map((l,c)=>(s.bounds.max[c]-l)*n[c])),rotation:{x:o.rotationx,y:o.rotationy,z:o.rotationz},display:o.display,smooth_shading:o.smooth_shading,section:o.section?{...o.section}:null,color:o.color??(s.colors?"#ffffff":"#909090"),scale:{x:o.scalex,y:o.scaley,z:o.scalez},volume:i.measurements===!1?null:o._stats.volume*d**3,area:i.measurements===!1?null:o._stats.area*d**2,triangles:s.triangles,bounds:{min:[...s.bounds.min],max:[...s.bounds.max]},has_colors:!!s.colors,source_units:s.units||null,units:o.units,opacity:o.opacity,file_bytes:s.file_bytes??null}})}get_model_data(e){return this._guard(()=>{let i=this._model(e);return i.geometry?{positions:i.geometry.positions.slice(),colors:i.geometry.colors?.slice()??null}:null})}get_model_mesh(e){return this._guard(()=>{let i=this._model(e);return i.geometry?co(i,this.options.three??globalThis.THREE):null})}get_stl_bin(e){return this._guard(()=>{let i=this._model(e);return i.geometry?Yt(i.geometry,i.scaleVector,i.center):null})}check_printability(e={}){return oo.call(this,e)}is_printability_current(e){return zt(this,e)}show_printability(e,i){return no.call(this,e,i)}clear_printability(){this.renderer?.setDiagnostic(null),this._invalidate()}async export_models(e={}){let i=ro(e),o=e.signal,s=()=>{throw new DOMException("Export cancelled","AbortError")};if(o?.aborted&&s(),await this.when_ready,o?.aborted&&s(),this.killsign)throw new Error("Viewer disposed");let n=e.model_ids;if(n==="selected"){let p=this.renderer?.selection;n=p?[p.id]:[]}else n===void 0&&(n=[...this._models.keys()]);if(!Array.isArray(n)||n.some(p=>!Number.isSafeInteger(p))||new Set(n).size!==n.length)throw new Error("model_ids must be an array of unique model IDs or 'selected'");if(!n.length)throw new Error("No models to export");let r=n.map(p=>{let g=this._model(p);if(!g.geometry)throw new Error(`Model ${p} has not finished loading`);return g});if(r.reduce((p,g)=>p+g.geometry.triangles,0)>this.limits.max_triangles)throw new Error("Export triangle limit exceeded");let l=so(r,i),c=this._occupiedMemory();Y(this.limits,c+l,"export"),this._exportBytes=(this._exportBytes||0)+l;let m,f,b;try{let p=r.map(h=>{let v=i.apply_transforms?h:{...h,center:[0,0,0],x:0,y:0,z:0,rotationx:0,rotationy:0,rotationz:0,scaleVector:[1,1,1].map(()=>h.unitScale*(h.size_state?.unit_factor??1))},y=J(v),M=i.units==="inch"?1/25.4:1;for(let P=0;P<4;P++)for(let C=0;C<3;C++)y[P*4+C]*=M;return{id:h.id,name:St(h.filename),matrix:y,positions:h.geometry.positions.slice(),colors:i.colors?h.geometry.colors?.slice():null,color:i.colors&&h.color&&h.color!=="transparent"?Z(h.color):null,opacity:h.color==="transparent"?0:h.opacity}}),g=p.flatMap(h=>[h.positions.buffer,...h.colors?[h.colors.buffer]:[]]);m=this._pool.run({kind:"export",models:p,options:i,limits:{...this.limits,max_memory_bytes:this.limits.max_memory_bytes-c}},h=>{try{e.on_progress?.(h)}catch(v){b=v,m.cancel()}},g),f=()=>m.cancel(),o?.addEventListener("abort",f,{once:!0}),o?.aborted&&f();try{return await m}catch(h){throw b||h}}finally{f&&o?.removeEventListener("abort",f),this._exportBytes-=l}}async download_models(e={}){let i=await this.export_models(e);if(e.signal?.aborted)throw new DOMException("Export cancelled","AbortError");return Ke(i.blob,i.filename),i}download_model(e,i){let o=this.get_stl_bin(e);o&&Ke(new Blob([o],{type:"model/stl"}),i??this._model(e).filename??"model.stl")}async export_scene(e={}){let i=String(e.format||"").toLowerCase();if(!["vsb","vsj"].includes(i))throw new Error("Scene format must be vsb or vsj");if(e.force_basename!==void 0&&typeof e.force_basename!="boolean")throw new Error("force_basename must be a boolean");if(e.on_progress!==void 0&&typeof e.on_progress!="function")throw new Error("on_progress must be a function");let o=e.signal,s=()=>{if(o?.aborted)throw new DOMException("Export cancelled","AbortError")};if(s(),await this.when_ready,s(),this.killsign)throw new Error("Viewer disposed");if(this._pending.size||this._sceneLoads.size)throw new Error("Wait for models to finish opening before saving the scene");let n=[...this._models.values()];if(!n.length)throw new Error("No models to export");if(n.some(g=>!g.geometry))throw new Error("A model has not finished loading");if(n.length+(i==="vsb"?1:0)>this.limits.max_archive_entries)throw new Error("Scene model count limit exceeded");let r=n.reduce((g,h)=>g+h.geometry.triangles,0);if(r>this.limits.max_triangles)throw new Error("Scene triangle limit exceeded");let d=this.get_vsj(!0,!!e.force_basename,i==="vsb"),l=JSON.stringify(d),c=new Blob([l]).size;if(c>this.limits.max_file_bytes)throw new Error("Scene manifest size limit exceeded");if(i==="vsb"&&c+n.length*84+r*50>this.limits.max_uncompressed_bytes)throw new Error("Scene archive limit exceeded");let m=67108864+l.length*8+(i==="vsb"?r*512:0);Y(this.limits,this._occupiedMemory()+m,"scene export"),this._exportBytes+=m;let f,b,p;try{let g=i==="vsb"?n.map((v,y)=>({id:v.id,triangles:v.geometry.triangles,positions:v.geometry.positions.slice(),colors:v.geometry.colors?.slice()||null,scale:d.models[y].animation_state?[1,1,1]:v.scaleVector,center:d.models[y].animation_state?[0,0,0]:[...v.center]})):null;e.on_progress?.({loaded:0,total:n.length,phase:"exporting"}),s();let h;if(i==="vsj")h=new Blob([l],{type:"application/json"}),e.on_progress?.({loaded:n.length,total:n.length,phase:"complete"});else{f=this._pool.run({kind:"export-scene",scene:d,models:g,limits:this.limits},v=>{try{e.on_progress?.(v)}catch(y){p=y,f.cancel()}},g.flatMap(v=>[v.positions.buffer,...v.colors?[v.colors.buffer]:[]])),b=()=>f.cancel(),o?.addEventListener("abort",b,{once:!0}),o?.aborted&&b();try{h=await f}catch(v){throw p||v}}return s(),{blob:h,format:i,filename:$t(e.filename,i),model_ids:n.map(v=>v.id),triangles:r,representation:"scene"}}finally{b&&o?.removeEventListener("abort",b),this._exportBytes-=m}}async download_scene(e={}){let i=await this.export_scene(e);if(e.signal?.aborted||this.killsign)throw new DOMException("Export cancelled","AbortError");return Ke(i.blob,i.filename),i}get_vsj(e=!1,i=!1,o=!1){let s={canvas_height:this.canvas_height,bg_color:this.bg_color,camera_state:this.get_camera_state(),camera_bookmarks:this.get_camera_bookmarks(),display_units:this.display_units||"mm",auto_rotate:this.auto_rotate,mouse_zoom:this.mouse_zoom,auto_resize:this.auto_resize,center_models:this.center_models,models:[]};this.grid&&(s.grid=!0,this.grid.infinite&&(s.infinite_grid={spacing:this.grid.spacing,height:this.grid.height}));for(let n of this._models.values())if(n.geometry){let r={id:o?-1:n.id,filename:o?`${n.id}.stl`:i?St(n.filename):n.filename,units:n.units,size_state:{...structuredClone(Ie(n)),unit_factor:o&&!n._animation?1:n.unitScale*(Ie(n).unit_factor??1)},...n.display_name?{display_name:n.display_name}:{},display:n.display,opacity:n.opacity,view_edges:n.view_edges,smooth_shading:n.smooth_shading,section:n.section?{...n.section}:null};o&&(r.orig_filename=St(n.orig_filename||n.filename));for(let l of ei)l.startsWith("scale")||(r[l]=n[l]);(!o||n._animation)&&(r.scalex=n.scalex*n.unitScale,r.scaley=n.scaley*n.unitScale,r.scalez=n.scalez*n.unitScale),n.color&&(r.color=n.color);let d=ft(n);if(d)Object.assign(r,d);else if(!o){let l=this.center_models?n.geometry.bounds.min.map((m,f)=>(m+n.geometry.bounds.max[f])/2):[0,0,0],c=Q(J(n),l);["x","y","z"].forEach((m,f)=>r[m]=c[f])}s.models.push(r)}return e?s:JSON.stringify(s)}download_vsj(e="1.vsj"){Ke(new Blob([this.get_vsj()],{type:"application/json"}),e)}get_vsb(){return{vsj:this.get_vsj(!0,!0,!0),files:[...this._models.values()].filter(e=>e.geometry).map(e=>({id:e.id,bin:e._animation?Yt(e.geometry,[1,1,1],[0,0,0]):this.get_stl_bin(e.id)}))}}async get_vsb_blob(){await this.when_ready;let e=this.get_vsb(),i=this._pool.run({kind:"zip",scene:e,limits:this.limits},null,e.files.map(o=>o.bin));return new Blob([await i],{type:"application/zip"})}download_vsb(e="1.vsb"){return this.get_vsb_blob().then(i=>Ke(i,/\.vsb$/i.test(e)?e:`${e}.vsb`)).catch(i=>this._error(i))}import_scene(e,i={}){return io.call(this,e,i)}_sceneLoad(e,i){let o=this._generation;this._sessionActive=!0;let s=(async()=>{if(await this.when_ready,o!==this._generation||this.killsign)return;let n,r,d=document.baseURI;if(typeof e=="string"&&(d=new URL(e,document.baseURI).href),i){if(r=await this._pool.run({kind:"unzip",source:typeof e=="string"?d:e,limits:this.limits}),!Object.hasOwn(r,"json_data.vsj"))throw new Error("VSB manifest json_data.vsj is missing");n=JSON.parse(new TextDecoder().decode(r["json_data.vsj"]))}else{let f=new AbortController;this._aborters.add(f);try{n=JSON.parse(new TextDecoder().decode(await ao(typeof e=="string"?d:e,this.limits.max_file_bytes,()=>{},f.signal)))}finally{this._aborters.delete(f)}}if(o!==this._generation||this.killsign)return;if(!n||!Array.isArray(n.models)||n.models.length>this.limits.max_archive_entries)throw new Error("Invalid or oversized scene manifest");n.bg_color!==void 0&&this.set_bg_color(n.bg_color),n.center_models!==void 0&&this.set_center_models(n.center_models),n.auto_rotate!==void 0&&this.set_auto_rotate(n.auto_rotate),n.mouse_zoom!==void 0&&this.set_mouse_zoom(n.mouse_zoom),n.auto_resize!==void 0&&this.set_auto_resize(n.auto_resize),n.canvas_height!==void 0&&(this.canvas_height=n.canvas_height,this._setSizeStyle(),this.do_resize()),n.infinite_grid?this.set_infinite_grid(!0,n.infinite_grid.spacing,n.infinite_grid.height):n.grid&&this.set_grid(!0),n.camera_state&&(this._restoreCamera=n.camera_state);let l=gt(this.get_camera_bookmarks(),n.camera_bookmarks||[]),c=Se(n.display_units||this.display_units||"mm"),m=[];try{for(let f of n.models){if(!f||typeof f!="object")throw new Error("Invalid scene model");let b=mo(f);if(delete b.mesh,delete b.data,delete b.local_file,r){if(typeof b.filename!="string"||!Object.hasOwn(r,b.filename))throw new Error("VSB model file is missing");b.local_file=new File([r[b.filename]],b.filename)}else b.filename&&(b.filename=new URL(b.filename,d).href);let p=b.id===void 0||b.id===-1?this.max_model_id+1:b.id;if(this._models.has(p))throw new Error(`Invalid or duplicate model id: ${p}`);this.add_model({...b,id:p,animation:null,animation_state:null});let g=this._models.get(p);if(!g)throw new Error(this.error||"Invalid scene model");g._sceneImportPending=!0,m.push({m:g,model:b,pending:this._pending.get(p)})}if(await Promise.all(m.map(f=>f.pending)),o!==this._generation||this.killsign)return;for(let{m:f,model:b}of m){if(this._models.get(f.id)!==f||!f.geometry)throw new Error("A scene model could not be opened");if(b.animation)We(b.animation,f,b.animation_state);else if(b.animation_state)throw new Error("Playback state needs an animation")}for(let{m:f,model:b}of m)b.animation&&this._startAnimation(f,b.animation,b.animation_state),f._sceneImportPending=!1;this.camera_bookmarks=l,this.display_units=c}catch(f){for(let{m:b}of m)this._models.get(b.id)===b&&this.remove_model(b.id);throw f}})().catch(n=>{o===this._generation&&n.name!=="AbortError"&&this._error(n)}).finally(()=>{this._sceneLoads.delete(s),this._finishSession()});this._sceneLoads.add(s)}load_vsj(e){return this._sceneLoad(e,!1)}load_vsb(e){return this._sceneLoad(e,!0)}animate_model(e,i){return this._guard(()=>{let o=this._model(e);if(!i){this._stopAnimation(o,"stopped"),this._invalidate();return}this._startAnimation(o,i),this._invalidate()})}_startAnimation(e,i,o){let s=We(i,e,o);e._animation&&this._stopAnimation(e,"replaced"),o&&(e.center=[...o.center]),e.animation=s.animation,e._animation=s,delete e.animation_state,e._animationResult=null,ht(s,e)?this._animationEvent(e,o?"restored":"started"):this._completeAnimation(e)}_animationEvent(e,i){let o=this._animationState(e);queueMicrotask(()=>{this._callback("animation_state_callback",e.id,o,i),i==="completed"&&this._callback("animation_complete_callback",e.id,o)})}_animationState(e){return e._animation?Di(e._animation,!!this._animationSuspended):{...e._animationResult??{status:"idle",elapsed_ms:0},suspended:!1,tracks:[]}}_stopAnimation(e,i){!e._animation&&!e.animation||(e._animationResult={status:"stopped",elapsed_ms:e._animation?.elapsed_ms??0},e._animation=null,e.animation=null,delete e.animation_state,this._animationEvent(e,i))}_completeAnimation(e){e._animationResult={status:"completed",elapsed_ms:e._animation.elapsed_ms},e._animation=null,e.animation=null,this._animationEvent(e,"completed")}pause_model_animation(e){return this._guard(()=>{let i=this._model(e);!i._animation||i._animation.paused||(i._animation.paused=!0,i._animation.last_time=null,this._animationEvent(i,"paused"),this._invalidate())})}resume_model_animation(e){return this._guard(()=>{let i=this._model(e);!i._animation||!i._animation.paused||(i._animation.paused=!1,i._animation.last_time=null,this._animationEvent(i,"resumed"),this._invalidate())})}get_model_animation_state(e){return this._guard(()=>this._animationState(this._model(e)))}_suspendAnimations(e){this._animationSuspended=!!e,this._lastTime=0;for(let i of this._models.values())i._animation&&(i._animation.last_time=null);e?(cancelAnimationFrame(this._frame),this._frame=0):this._invalidate()}_animate(e,i){if(!(this._animationSuspended||!e._animation))try{Oi(e._animation,e,i)||this._completeAnimation(e)}catch(o){this._stopAnimation(e,"error"),this._error(o)}}async get_image_blob(e="image/png"){await this.when_idle(),this._clip(),this.renderer.draw([...this._models.values()],this.camera,this.bg_color,!1);let i=new Promise((o,s)=>this.canvas.toBlob(n=>n?o(n):s(new Error("Screenshot failed")),e));return this._invalidate(),i}};var ii=new WeakMap,To=["background-color","background-value","cancel-load","clear-scene","close-colors","close-info","close-model","close-scene","close-section","close-view","color-mode-note","colors-button","colors-panel","depth-controls","depth-model-button","dismiss-notice","drop-message","drop-overlay","empty-state","file-heading","file-input","filename","finish-move","fit-button","grid-button","image-button","info-button","info-dimensions","info-panel","info-size","info-triangles","live-status","loading-label","loading-state","memory-budget","model-color","model-color-value","model-controls","model-list","model-tool","move-controls","move-gesture-message","move-mode","move-mode-name","move-model-button","notice","notice-message","open-label","position-details","position-error","position-units","position-x","position-y","position-z","reset-position","reset-rotation","restore-color","rotate-controls","rotate-model-button","rotation-error","rotation-x","rotation-y","rotation-z","sample-button","scene-arrangement","scene-button","scene-count","scene-panel","section-axis","section-button","section-enabled","section-flip","section-panel","section-position","section-value","smooth-shading","unit-note","view-button","view-description","view-label","view-panel","view-status","viewer","workspace"];function uo(t,e={}){if(!t?.querySelectorAll)throw new TypeError("A Document or HTMLElement root is required");if(ii.has(t))throw new Error("ViewSTL app is already mounted on this root");let i=t.ownerDocument||t,o=i.defaultView,s=o.URL,n=new Map([...t.querySelectorAll("[id]")].map(a=>[a.id,a])),r=a=>n.get((e.id_prefix||"")+a),d=To.filter(a=>!r(a));if(Kt.some(a=>r(a))&&d.push(...Kt.filter(a=>!r(a))),Zt.some(a=>r(a))&&d.push(...Zt.filter(a=>!r(a))),Qt.some(a=>r(a))&&d.push(...Qt.filter(a=>!r(a))),Dt.some(a=>r(a))&&d.push(...Dt.filter(a=>!r(a))),d.length)throw new Error("Missing ViewSTL controls: "+d.join(", "));let l=new o.AbortController,c=t===i?o:t,m=!1,f=null,b=null,p=()=>{if(m)throw new Error("ViewSTL app is disposed")},g=(a,u,x,z={})=>a.addEventListener(u,x,{...z,signal:l.signal}),h=vi(o.navigator.deviceMemory),v=["view","section","info","scene","colors"],y=new Map,M=[],P=["#64a5b2","#dd766b","#edb14c","#7ca984","#927fbc","#5a8ec7","#89949d"],C,w,R=0,k=0,_=null,A=0,I=null,E,L,T,j,S,F=!1,N=!1,D=!1,be=0,Re=1,X=!1,G="move",K,oi,ve="transparent",ni={flat:"Solid",edges:"Solid + edges",wireframe:"Wireframe",xray:"X-ray",mesh:"Mesh overlay",studio:"Studio",orientation:"Face orientation"},Me=[...t.querySelectorAll('[name="view-mode"]')];e.id_prefix&&Me.forEach(a=>a.name=e.id_prefix+"view-mode");let It=e.sample_url,Ze=new Intl.NumberFormat(void 0,{maximumFractionDigits:2});function B(a){m||(r("live-status").textContent=a)}function ce(a){m||(r("notice-message").textContent=a,r("notice").hidden=!1)}function Pe(){w?.set_selection(!N&&y.has(_)&&(X||!r("scene-panel").hidden)?_:null)}function ri(a){r(a+"-panel").hidden=!0,r(a+"-button").setAttribute("aria-expanded","false"),Pe()}function fe(){v.forEach(ri)}function Qe(a){let u=r(a+"-panel").hidden;fe(),r(a+"-panel").hidden=!u,r(a+"-button").setAttribute("aria-expanded",String(u)),Pe(),u&&a==="info"&&$e(),u&&(a==="scene"||a==="view")&&j?.sync()}function Le(a){return a==null?"Sample model":a<1024**2?`${Ze.format(a/1024)} KiB`:a<1024**3?`${Ze.format(a/1024**2)} MiB`:`${Ze.format(a/1024**3)} GiB`}function Ct(){let a=y.get(_),u=/^#[a-f0-9]{6}$/i.test(a?.color)?a.color:"#ffffff";r("model-color").value=u,r("model-color-value").textContent=a?.color===null?"File colors":u.toUpperCase(),r("restore-color").textContent=a?.embedded?"Restore file colors":"Restore original color",t.querySelectorAll("[data-model-color]").forEach(x=>x.setAttribute("aria-pressed",String(x.dataset.modelColor===a?.color))),t.querySelectorAll("[data-background]").forEach(x=>x.setAttribute("aria-pressed",String(x.dataset.background===ve))),r("background-color").value=ve==="transparent"?"#fafbfb":ve,r("background-value").textContent=ve==="transparent"?"Default":ve.toUpperCase()}function si(){te(y.get(_),w?._models.get(_));let a=_===null?null:w.get_model_info(_,{measurements:!1}),u=a?.display==="smooth"?"flat":a?.display||"flat";for(let O of Me)O.checked=O.value===u,O.disabled=N;r("view-label").textContent=j?"View":ni[u],r("view-button").title="View \xB7 "+ni[u],r("smooth-shading").checked=a?.smooth_shading||!1,r("smooth-shading").disabled=N||u==="wireframe",r("view-status").textContent=u==="wireframe"?"Smooth shading is available in surface views.":"Shading changes the appearance, not the geometry.";let x=u==="orientation"?"Blue: front faces \xB7 Red: back faces":"";r("view-description").textContent=x,r("view-description").hidden=!x,r("color-mode-note").hidden=u!=="orientation";let z=a?.section;r("section-enabled").checked=!!z,r("section-axis").value=z?.axis||"z",r("section-position").value=(z?.position??.5)*100,r("section-value").textContent=r("section-position").value+"%",r("section-flip").setAttribute("aria-pressed",String(z?.flip||!1)),r("section-button").setAttribute("aria-pressed",String(!!z)),t.querySelectorAll("[data-selected-name]").forEach(O=>O.textContent=y.get(_)?.name||""),Ct(),it(),E?.sync(),L?.sync(),T?.sync(),j?.sync()}function $e(){if(_===null)return;let a=w.get_model_info(_,{measurements:!1}),u=y.get(_),x=w.display_units==="inch"?25.4:1;r("info-triangles").textContent=a.triangles.toLocaleString(),r("info-dimensions").textContent=[a.dims.x,a.dims.y,a.dims.z].map(O=>Ze.format(O/x)).join(" \xD7 ")+(x===1?" mm":" in"),r("info-size").textContent=Le(u.size);let z=w.get_model_size(_);r("unit-note").textContent=z.editable?"File coordinates interpreted as "+(z.file_units==="inch"?"inches.":"millimetres (assumed).")+" Change file units in Models \u2192 Size & units.":"Explicit file units were converted to millimetres on import.",j?.syncInfo()}function ai(){r("model-list").replaceChildren(...[...y.values()].map(a=>{let u=i.createElement("li"),x=i.createElement("button"),z=i.createElement("button"),O=i.createElement("button");return u.className="model-row",u.classList.toggle("selected",a.id===_),x.className="model-swatch",x.dataset.colorModel=a.id,x.style.backgroundColor=a.color||"#b7c5c9",x.setAttribute("aria-label","Color for "+a.name),x.title="Change color",z.className="model-pick",z.dataset.selectModel=a.id,z.textContent=a.name,z.title=a.name,z.setAttribute("aria-pressed",String(a.id===_)),O.className="icon-button",O.dataset.removeModel=a.id,O.textContent="\xD7",O.setAttribute("aria-label","Remove "+a.name),u.append(x,z,O),u})),r("scene-count").textContent=y.size,r("scene-arrangement").disabled=y.size===0}function pe(){let a=y.size>0;r("workspace").classList.toggle("has-models",a),r("viewer").hidden=!a&&!N,r("empty-state").hidden=a||N,r("file-heading").hidden=!a,r("model-controls").hidden=!a,r("filename").textContent=y.get(_)?.name||"",r("filename").title=r("filename").textContent,r("open-label").textContent=a?"Add models":"Open files",r("drop-message").textContent=a?"Add to your scene.":"Drop it here.",ai(),si(),$e(),a||fe(),Pe()}function et(a){a&&E?.close(),!m&&(a&&q(!1),N=a,r("loading-state").hidden=!a,r("workspace").setAttribute("aria-busy",String(a)),pe())}function Te(a){E?.close(),y.has(a)&&(q(!1),k++,_=a,pe())}function ho(){return Ci([...y.values()],r("scene-arrangement").value)}function tt(){w?.set_infinite_grid(D,Re,be),r("grid-button").setAttribute("aria-pressed",String(D))}function Rt(){q(!1);for(let u of y.values())te(u,w?._models.get(u.id));if(r("scene-arrangement").value==="custom")return;for(let u of y.values())oe(u.id);if(r("scene-arrangement").value==="original")for(let u of y.values())u.rotation={...u.originalRotation||{x:0,y:0,z:0}};let a=ho();for(let u of a)y.get(u.id).position={x:u.x,y:u.y,z:u.z},Pt(y.get(u.id));(r("scene-arrangement").value!=="custom"||!y.size)&&(be=Ri([...y.values()],a)),it(),tt(),w?.set_auto_zoom()}function it(a=!1){let u=y.get(_);for(let x of["x","y","z"]){let z=r("position-"+x);(!a||i.activeElement!==z)&&(z.value=Number((u?.position?.[x]||0).toPrecision(12))),z.disabled=!u,z.removeAttribute("aria-invalid")}r("position-error").hidden=!0,r("position-units").textContent=u?.animationPivot?"Position of the model center in the scene, in mm.":"Offset from file coordinates, in mm.",r("move-model-button").disabled=!u||N,r("reset-position").disabled=!u,ci(a);for(let x of["rotate-model-button","depth-model-button","depth-nearer","depth-farther"])r(x).disabled=!u||N}function Fe(a,u,x=!0){return!y.has(a)||!Object.values(u).every(z=>Number.isFinite(z)&&Math.abs(z)<=1e12)?!1:(y.get(a).position={...u},Pt(y.get(a)),r("scene-arrangement").value="custom",a===_&&x&&it(),!0)}function Pt(a){let u=Be(a),x=a.rotation;w.set_rotation(a.id,...["x","y","z"].map(z=>x[z]%360*Math.PI/180)),w.set_position(a.id,u.x,u.y,u.z)}function li(){oe(_);let a=y.get(_);return a?{...a,center:Ai(a),radius:Si(a)}:null}function ci(a=!1){let u=y.get(_);for(let x of["x","y","z"]){let z=r("rotation-"+x);(!a||i.activeElement!==z)&&(z.value=Number((u?.rotation?.[x]||0).toPrecision(10))),z.disabled=!u,z.removeAttribute("aria-invalid")}r("rotation-error").hidden=!0,r("reset-rotation").disabled=!u}function ot(a,u,x=!0){return!y.has(a)||!Object.values(u).every(z=>Number.isFinite(z)&&Math.abs(z)<=36e4)?!1:(y.get(a).rotation={...u},Pt(y.get(a)),r("scene-arrangement").value="custom",x&&a===_&&ci(),!0)}let fo={move:"Move",rotate:"Rotate",depth:"Depth"},di={move:"Drag to move the selected model",rotate:"Drag to rotate the selected model",depth:"Drag up for nearer, down for farther"};function po(){w?.canvas&&(w.canvas.dataset.modelTool=G),t.querySelectorAll("[data-transform-tab]").forEach(a=>a.setAttribute("aria-pressed",String(a.dataset.transformTab===G)));for(let a of["move","rotate","depth"])r(a+"-controls").hidden=a!==G,r(a+"-model-button").setAttribute("aria-pressed",String(X&&a===G));r("model-tool").value=G,r("move-gesture-message").textContent=di[G]+" \xB7 Scroll to adjust depth"}function q(a,u=G,x=!1){K?.setEnabled(!1),G=u,X=!!a&&_!==null&&!N,X&&!x&&oe(_),K?.setEnabled(X),po(),r("move-mode").hidden=!X,r("move-mode-name").textContent=y.get(_)?.name||"",r("workspace").classList.toggle("moving-model-mode",X),w?.canvas&&w.canvas.setAttribute("aria-label",X?di[G]+". Scroll changes only its depth. Escape exits.":"3D model viewer. Drag to rotate, shift-drag to pan, scroll to zoom."),X&&(fe(),w.canvas.focus({preventScroll:!0}),B(fo[G]+" tool for "+y.get(_).name+". Done or Escape returns to viewing.")),Pe()}for(let a of["x","y","z"]){let u=r("rotation-"+a);g(u,"input",()=>{_===null||!u.value.trim()||(oe(_),ot(_,{...y.get(_).rotation,[a]:u.valueAsNumber},!1)&&(u.removeAttribute("aria-invalid"),r("rotation-error").hidden=!0))}),g(u,"change",()=>{_!==null&&(oe(_),!u.value.trim()||!ot(_,{...y.get(_).rotation,[a]:u.valueAsNumber})?(u.setAttribute("aria-invalid","true"),r("rotation-error").hidden=!1):B("Model rotation updated."))})}g(r("reset-rotation"),"click",()=>{q(!1),_!==null&&(oe(_),ot(_,{...y.get(_).originalRotation||{x:0,y:0,z:0}}),B("Selected model rotation reset."))});for(let a of["move","rotate","depth"])g(r(a+"-model-button"),"click",()=>q(!X||G!==a,a));for(let[a,u]of[["depth-nearer",-.12],["depth-farther",.12]])g(r(a),"click",()=>{let x=li();x&&(Fe(x.id,Ue(x,w.get_camera_state(),u)),B(u<0?"Selected model moved nearer.":"Selected model moved farther."))});t.querySelectorAll("[data-transform-tab]").forEach(a=>g(a,"click",()=>q(!1,a.dataset.transformTab))),g(r("model-tool"),"change",()=>q(!0,r("model-tool").value));for(let a of["x","y","z"]){let u=r("position-"+a);g(u,"input",()=>{_===null||!u.value.trim()||(oe(_),Fe(_,{...y.get(_).position,[a]:u.valueAsNumber},!1)&&(u.removeAttribute("aria-invalid"),r("position-error").hidden=!0))}),g(u,"change",()=>{_!==null&&(oe(_),!u.value.trim()||!Fe(_,{...y.get(_).position,[a]:u.valueAsNumber})?(u.setAttribute("aria-invalid","true"),r("position-error").hidden=!1):B("Model position updated."))})}g(r("finish-move"),"click",()=>{q(!1),w?.canvas.focus({preventScroll:!0})}),g(r("reset-position"),"click",()=>{q(!1),_!==null&&(oe(_),Fe(_,{...y.get(_).originalPosition||{x:0,y:0,z:0}}),B("Selected model restored to its original position."))}),g(o,"blur",()=>{X&&q(!1)});function nt(){R++,M.length=0,S?.abort(),I!==null&&(w?.remove_model(I),I=null),et(!1),B("Opening cancelled.")}function mi(){E?.close(),q(!1),nt(),k++,w?.clean(),y.clear(),_=null,D=!1,be=0,Re=1,r("scene-arrangement").value="original",tt(),r("notice").hidden=!0,pe(),B("Scene cleared.")}function Lt(a){if(!y.has(a))return;E?.close();let u=y.get(a).name;q(!1),w.remove_model(a),y.delete(a),k++,_===a&&(_=[...y.keys()].at(-1)??null),Rt(),pe(),B(u+" removed.")}function oe(a){y.has(a)&&(te(y.get(a),w?._models.get(a)),w?.animate_model(a,null))}function ui(){m||_===null||(te(y.get(_),w?._models.get(_)),r("info-panel").hidden||$e(),!r("scene-panel").hidden&&r("position-details").open&&it(!0))}function _o(a,u,x){m||(x==="restored"&&u.status==="running"&&o.matchMedia?.("(prefers-reduced-motion: reduce)").matches&&w.pause_model_animation(a),te(y.get(a),w?._models.get(a)),["started","restored","resumed"].includes(x)&&(r("scene-arrangement").value="custom"),a===_&&ui(),T?.sync(),L?.sync(),e.animation_state_callback?.(a,u,x))}async function hi(){return C||(C=Promise.resolve().then(async()=>{if(m)throw new Error("ViewSTL app is disposed");if(w=new Ee(r("viewer"),{...h.limits,worker_count:1,worker_timeout:e.worker_timeout??6e5,worker_url:e.worker_url,worker_factory:e.worker_factory,url_import_endpoint:e.url_import_endpoint,center_models:!1,bg_color:ve,allow_drag_and_drop:!1,animation_state_callback:_o,animation_complete_callback:(...a)=>{m||e.animation_complete_callback?.(...a)},camera_state:{position:{x:90,y:-130,z:90},target:{x:0,y:0,z:0},up:{x:0,y:0,z:1}},loading_progress_callback:a=>{if(m||!N||S)return;let u=a[I];r("loading-label").textContent=u?.phase==="loading-cad"?"Loading the CAD reader\u2026":u?.phase==="parsing-cad"?"Preparing CAD surfaces\u2026":u?.loaded&&!u.total?`Downloading your file\u2026 ${Le(u.loaded)}`:u?.total&&u.loaded<u.total?`Reading your file\u2026 ${Math.min(99,Math.floor(100*u.loaded/u.total))}%`:"Preparing your model\u2026"},model_loaded_callback:a=>{b=a},load_error_callback:a=>{ce(/limit exceeded|safety budget/i.test(a)?`This scene or view mode exceeds the estimated memory budget for this device (${Le(h.budget)}). Remove a model, use Solid view without smoothing, or try a device with more memory.`:`Couldn\u2019t display this model. ${a}`)}}),await w.when_ready,m)throw new Error("ViewSTL app is disposed");return K=Li(w.canvas,{getCamera:()=>w.get_camera_state(),getModel:li,getTool:()=>G,onRotate:(a,u)=>ot(a,u),onMove:(a,u)=>Fe(a,u),onStart:()=>{oi=r("scene-arrangement").value},onEnd:(a,u)=>{u&&(r("scene-arrangement").value=oi),B(u?"Move cancelled.":"Model updated.")}}),g(w.canvas,"dblclick",a=>{if(N||a.button!==0)return;let u=w.pick_model(a.clientX,a.clientY);!u||!y.has(u.id)||(a.preventDefault(),Te(u.id),fe(),r("scene-panel").hidden=!1,r("scene-button").setAttribute("aria-expanded","true"),r("position-details").open=!0,Pe(),B(y.get(u.id).name+" selected. Choose Move, Rotate or Depth."))}),w}).catch(a=>{throw K?.dispose(),K=null,w?.dispose(),w=null,C=null,a})),C}function rt(a){p();let u=[];for(let z of a){if(!/\.(stl|obj|3mf|step|stp|iges|igs|vsb|vsj)$/i.test(z.name)){ce("Choose STL, OBJ, 3MF, STEP/STP, IGES/IGS, VSB or VSJ files.");continue}if(z.size===0){ce("This file is empty. Choose a file containing a 3D model.");continue}u.push(z)}let x=u.filter(z=>ke(z.name));if(x.length){let z={files:u.filter(O=>!ke(O.name)),used:new Set,failed:!1};for(let O of x)M.push({name:O.name,sceneFile:O,batch:z});M.push({remaining:z})}else M.push(...u);return M.length&&!F&&(f=fi()),f||Promise.resolve()}function Tt(a,u=""){if(p(),!e.url_import_endpoint)throw new Error("URL imports are not configured.");let x=new s(a.trim());if(!["https:","http:"].includes(x.protocol)||x.username||x.password)throw new Error("Use a public HTTP or HTTPS file URL without login credentials.");if(u&&!/^(stl|obj|3mf|step|stp|iges|igs|vsb|vsj)$/.test(u))throw new Error("Choose a supported 3D format.");x.hash="";let z=decodeURIComponent(x.pathname.split("/").at(-1)||"Remote model").slice(0,200);return M.push({name:z,remote:x.href,format:u,size:0,scene:["vsb","vsj"].includes(u)?u:ke(z)}),F||(f=fi()),f||Promise.resolve()}r("url-form")&&r("url-dialog")&&g(r("url-form"),"submit",a=>{a.preventDefault();try{let u=Tt(r("url-input").value,r("url-format").value);r("url-input").value="",r("url-error").hidden=!0,r("url-dialog").close(),u.catch(x=>ce(x.message))}catch(u){r("url-error").textContent=u.message,r("url-error").hidden=!1}});async function fi(){if(!F){F=!0;try{for(;M.length;){let a=M.shift(),u=R;if(a.remaining){a.remaining.failed||M.unshift(...a.remaining.files.filter(x=>!a.remaining.used.has(x)));continue}et(!0),r("notice").hidden=!0,r("loading-label").textContent="Opening "+a.name+"\u2026",B("Opening "+a.name);try{if(a.sceneFile||a.scene){await go(a,u);continue}let x=await wi(a);if(u!==R)continue;let z=[...y.values()].reduce((V,ge)=>V+ge.estimated,0);if(x+z>h.budget||a.size>h.limits.max_file_bytes)throw Error(`Adding this file would exceed the estimated ${Le(h.budget)} scene memory budget. Remove a model or try a device with more memory.`);let O=await hi();if(u!==R)continue;O.do_resize(),A=Math.max(A,O.max_model_id+1);let ie=A++;if(I=ie,b=null,O.add_model({id:ie,display:"flat",...a.remote?{remote_url:a.remote,remote_format:a.format}:a.url?{filename:a.url}:{local_file:a}}),await O.when_idle(),u!==R)continue;I=null;let de=b===ie?O.get_model_info(ie,{measurements:!1}):null;if(!de){B(a.name+" could not be opened.");continue}a.remote&&(a.name=de.name,a.size=de.file_bytes,delete a.remote);let _e=de.has_colors,U=_e?null:P[y.size%P.length];U&&O.set_color(ie,U),y.set(ie,{id:ie,name:a.name,size:a.size,units:de.source_units||(/\.3mf$/i.test(a.name)?"mm":null),bounds:de.bounds,position:{x:0,y:0,z:0},rotation:{x:0,y:0,z:0},embedded:_e,originalColor:U,color:U,estimated:de.triangles*224,sourceFile:a instanceof o.File?a:null}),_=ie,k++,Rt(),pe(),B(a.name+" is ready."),O.canvas.focus({preventScroll:!0})}catch(x){a.batch&&(a.batch.failed=!0),u===R&&(I!==null&&(w?.remove_model(I),I=null),ce(/WebGL/i.test(x.message)?"3D viewing needs WebGL 2. Try enabling hardware acceleration in your browser, or use another device.":x.message))}}}finally{F=!1,et(!1)}}}async function go(a,u){let x=await hi();if(u!==R)return;let z=new o.AbortController;S=z;try{let O=a.batch?.files||[],ie=[...new Set([...y.values()].map(U=>U.sourceFile).filter(Boolean))],de=[...O,...a.sceneFile?ie.filter(U=>!O.some(V=>V.name===U.name)&&ie.filter(V=>V.name===U.name).length===1):[]],_e=await x.import_scene(a.sceneFile||a.remote,{format:a.scene||ke(a.name),signal:z.signal,files:de,on_progress(U){u!==R||m||(r("loading-label").textContent=U.phase==="opening-model"?`Opening scene model ${U.loaded+1} of ${U.total}\u2026`:U.phase==="complete"?"Restoring scene\u2026":U.total?`Reading scene\u2026 ${Math.min(99,Math.floor(U.loaded/U.total*100))}%`:"Reading scene\u2026")}});if(u!==R)return;for(let U of _e.used_files)a.batch?.used.add(U);for(let U of _e.model_ids){let V=x._models.get(U),ge=V.geometry,yo=Object.fromEntries(["min","max"].map(ze=>[ze,ge.bounds[ze].map((vo,gi)=>(vo-V.center[gi])*V.scaleVector[gi])])),me={id:U,name:String(V.display_name||V.orig_filename||V.filename).split(/[\\/]/).pop().split(/[?#]/)[0],size:ge.file_bytes??V.local_file?.size??null,units:ge.units||V.units,bounds:yo,position:{x:0,y:0,z:0},rotation:{x:V.rotationx*180/Math.PI,y:V.rotationy*180/Math.PI,z:V.rotationz*180/Math.PI},embedded:!!ge.colors,color:V.color||(ge.colors?null:"#909090"),estimated:ge.triangles*224,sourceFile:_e.used_files.includes(V.local_file)?V.local_file:null},bo=Be(me);for(let ze of["x","y","z"])me.position[ze]=V[ze]-bo[ze];me.originalPosition={...me.position},me.originalRotation={...me.rotation},me.originalColor=me.color,y.set(U,me)}A=Math.max(A,x.max_model_id+1),_=_e.model_ids.at(-1),k++,r("scene-arrangement").value="custom",D=!!x.grid,be=x.grid?.height||0,Re=x.grid?.spacing||1,r("grid-button").setAttribute("aria-pressed",String(D)),Nt(x.bg_color),pe(),B(a.name+" opened. "+_e.model_ids.length+" models added."),x.canvas.focus({preventScroll:!0})}finally{S===z&&(S=null)}}t.querySelectorAll("[data-open-file]").forEach(a=>g(a,"click",()=>r("file-input").click())),g(r("file-input"),"change",()=>{let a=[...r("file-input").files];r("file-input").value="",rt(a)}),r("sample-button").hidden=!It,g(r("sample-button"),"click",()=>{It&&rt([{name:e.sample_name||"Sample.stl",url:It}])}),g(r("close-model"),"click",()=>Lt(_)),g(r("cancel-load"),"click",nt),g(r("clear-scene"),"click",mi),g(r("dismiss-notice"),"click",()=>{r("notice").hidden=!0}),g(r("fit-button"),"click",()=>w?.set_auto_zoom()),g(r("scene-arrangement"),"change",Rt),g(r("model-list"),"click",a=>{let u=a.target.closest("button");u&&(u.dataset.removeModel!==void 0?Lt(Number(u.dataset.removeModel)):u.dataset.selectModel!==void 0?Te(Number(u.dataset.selectModel)):u.dataset.colorModel!==void 0&&(Te(Number(u.dataset.colorModel)),Qe("colors")))});async function pi(){if(_===null||N)return;let a=++k,u=Me.find(x=>x.checked).value;Me.forEach(x=>{x.disabled=!0}),r("smooth-shading").disabled=!0,r("view-status").textContent="Preparing view\u2026",r("notice").hidden=!0;try{w.set_view(_,{display:u,smooth_shading:r("smooth-shading").checked}),await w.when_idle()}finally{a===k&&(si(),B(r("view-label").textContent+" view ready."))}}Me.forEach(a=>g(a,"change",pi)),g(r("smooth-shading"),"change",pi);for(let a of v)g(r(a+"-button"),"click",()=>{a==="info"&&$e(),Qe(a),a==="section"&&!r("section-panel").hidden&&!r("section-enabled").checked&&(r("section-enabled").checked=!0,Ne())}),g(r("close-"+a),"click",()=>{ri(a),a==="colors"&&Qe("view"),r(a+"-button").focus()});function Ne(){if(_===null)return;let a=r("section-enabled").checked;w.set_section(_,a?{axis:r("section-axis").value,position:Number(r("section-position").value)/100,flip:r("section-flip").getAttribute("aria-pressed")==="true"}:null),r("section-value").textContent=r("section-position").value+"%",r("section-button").setAttribute("aria-pressed",String(a))}g(r("section-enabled"),"change",Ne),g(r("section-axis"),"change",Ne),g(r("section-position"),"input",Ne),g(r("section-flip"),"click",()=>{r("section-flip").setAttribute("aria-pressed",String(r("section-flip").getAttribute("aria-pressed")!=="true")),Ne()}),g(r("grid-button"),"click",()=>{D=!D,tt()});function Ft(a){_!==null&&(w.set_color(_,a),y.get(_).color=a,Ct(),ai())}g(r("model-color"),"input",()=>Ft(r("model-color").value)),g(r("restore-color"),"click",()=>Ft(y.get(_)?.originalColor)),t.querySelectorAll("[data-model-color]").forEach(a=>g(a,"click",()=>Ft(a.dataset.modelColor)));function Nt(a){ve=a;let u=a==="transparent"?[255,255,255]:[1,3,5].map(x=>parseInt(a.slice(x,x+2),16));r("workspace").classList.toggle("dark-background",u[0]*.2126+u[1]*.7152+u[2]*.0722<115),w?.set_bg_color(a),Ct()}g(r("background-color"),"input",()=>Nt(r("background-color").value)),t.querySelectorAll("[data-background]").forEach(a=>g(a,"click",()=>Nt(a.dataset.background))),g(r("image-button"),"click",async()=>{if(_===null)return;let a=y.size>1?"viewstl-scene.png":y.get(_).name.replace(/\.[^.]+$/,"")+".png";try{let u=await w.get_image_blob("image/png");if(m)return;let x=s.createObjectURL(u),z=i.createElement("a");z.href=x,z.download=a,z.click(),setTimeout(()=>s.revokeObjectURL(x),1e3),B("Image ready to download.")}catch{ce("The image could not be saved. Please try again.")}});let st=0,Ot=a=>{let u=qt(a.dataTransfer);return u==="files"?u:!e.url_import_endpoint||a.target?.isContentEditable||a.target?.closest?.("input, textarea")?null:u},at=()=>{st=0,r("drop-overlay").hidden=!0};g(c,"dragenter",a=>{Ot(a)&&(a.preventDefault(),st++,r("drop-overlay").hidden=!1)}),g(c,"dragover",a=>{Ot(a)&&(a.preventDefault(),a.dataTransfer.dropEffect="copy")}),g(c,"dragleave",a=>{st>0&&--st===0&&at()}),g(c,"drop",a=>{let u=Ot(a);if(at(),!!u){a.preventDefault();try{if(u==="files")rt([...a.dataTransfer.files]).catch(x=>ce(x.message));else for(let x of Ti(a.dataTransfer))Tt(x).catch(z=>ce(z.message))}catch(x){ce(x.message)}}}),g(c,"dragend",at),g(o,"blur",at),t.querySelectorAll("[data-dialog]").forEach(a=>g(a,"click",()=>r(a.dataset.dialog).showModal())),t.querySelectorAll("dialog").forEach(a=>g(a,"click",u=>{if(u.target===a){let x=a.getBoundingClientRect();(u.clientX<x.left||u.clientX>x.right||u.clientY<x.top||u.clientY>x.bottom)&&(a===r("save-dialog")?E.close():a.close())}})),g(t,"keydown",a=>{if(a.key!=="Escape"||r("save-dialog")?.open)return;if(X){q(!1),B("Move tool closed.");return}let u=v.find(x=>!r(x+"-panel").hidden);u&&(fe(),u==="colors"&&Qe("view"),r(u+"-button").focus())}),g(t,"pointerdown",a=>{a.target.closest(".view-panel,.info-panel,.toolbar,.scene-heading-button,.move-mode")||fe()}),r("memory-budget").textContent=`Scene memory budget: ${Le(h.budget)}. Half of ${h.reported?"the memory estimate reported by your browser":"a conservative 2 GiB estimate because this browser does not report device memory"} is kept in reserve. This is an estimate, not a guarantee of available memory.`,r("scene-arrangement").value="original",r("notice").hidden=!0,r("drop-overlay").hidden=!0,r("save-button")&&(E=Zi({$:r,listen:g,window:o,getState:()=>({busy:N,selectedId:_,models:[...y.values()]}),getViewer:()=>w,onOpen:()=>{q(!1),fe()},announce:B})),r("print-button")&&(L=Qi({$:r,listen:g,window:o,getState:()=>({busy:N,selectedId:_,models:[...y.values()]}),getViewer:()=>w,onOpen:()=>{q(!1),fe()},announce:B})),r("animation-details")&&(T=eo({$:r,listen:g,window:o,getState:()=>({busy:N,selectedId:_,models:[...y.values()]}),getViewer:()=>w,beforePlay(a){q(!1),oe(a),$i(y.get(a),w._models.get(a)),r("scene-arrangement").value="custom"},refreshPose:ui,announce:B})),r("size-details")&&(j=bi({$:r,listen:g,window:o,getViewer:()=>w,getState:()=>({selectedId:_,busy:N}),refresh:pe,announce:B,changeSize(a){q(!1);let u=y.get(_);te(u,w._models.get(_)),a(),te(u,w._models.get(_)),r("scene-arrangement").value="custom",pe()},duplicate(){let a=y.get(_),u=w.duplicate_model(_),x=w._models.get(u),z={...a,id:u,name:x.display_name,position:{...a.position},rotation:{...a.rotation}};te(z,x),z.originalPosition={...z.position},z.originalRotation={...z.rotation},y.set(u,z),A=Math.max(A,u+1),r("scene-arrangement").value="custom",Te(u),q(!0,"move",!0),B("Copy selected at the same position. Drag to move it.")}})),tt(),et(!1),q(!1);let _i={openFiles:rt,openURL:Tt,cancelLoading(){p(),nt()},clear(){p(),mi()},select(a){p(),Te(a)},remove(a){p(),Lt(a)},getState(){p();for(let a of y.values())te(a,w?._models.get(a.id));return{selectedId:_,busy:N,arrangement:r("scene-arrangement").value,memoryBudget:h.budget,models:[...y.values()].map(a=>({id:a.id,name:a.name,size:a.size,units:a.units,position:{...a.position},rotation:{...a.rotation},color:a.color,animation:w.get_model_animation_state(a.id)}))}},dispose(){m||(E?.dispose(),L?.dispose(),T?.dispose(),j?.dispose(),nt(),q(!1),k++,m=!0,l.abort(),K?.dispose(),w?.dispose(),y.clear(),e.id_prefix&&Me.forEach(a=>a.name="view-mode"),ii.delete(t))}};return ii.set(t,_i),_i}var Fo=globalThis.document?.currentScript;Ee.workerURL=new URL("viewstl.worker.js",Fo?.src||document.baseURI).href;globalThis.StlViewer=Ee;globalThis.mountViewstlApp=uo;})();
52
+ result=vec4(color,alpha);}`,zt=class{constructor(e,i,o,s){if(this.canvas=e,this.domElement=e,this.resources=new Map,this.sharedResources=new WeakMap,this.frames=0,this.lost=!1,this.gl=e.getContext("webgl2",{alpha:!0,antialias:!0,premultipliedAlpha:!1,preserveDrawingBuffer:!1}),!this.gl)throw new Error("WebGL2 is unavailable. Enable browser graphics acceleration or try another browser/device.");this.lostHandler=n=>{n.preventDefault(),this.lost=!0,this.resources.clear(),this.sharedResources=new WeakMap,this.gridResource=null,this.infiniteGrid=null,this.selectionResource=null,this.diagnosticResource=null,i()},this.restoredHandler=()=>{try{this.initialize(),this.lost=!1,o()}catch(n){s(n)}},e.addEventListener("webglcontextlost",this.lostHandler),e.addEventListener("webglcontextrestored",this.restoredHandler),this.initialize()}initialize(){let e=this.gl,i=[],o;try{for(let[s,n]of[[e.VERTEX_SHADER,Oo],[e.FRAGMENT_SHADER,Do]]){let r=e.createShader(s);if(i.push(r),e.shaderSource(r,n),e.compileShader(r),!e.getShaderParameter(r,e.COMPILE_STATUS))throw new Error(`Shader compilation failed: ${e.getShaderInfoLog(r)}`)}o=e.createProgram();for(let s of i)e.attachShader(o,s);if(e.linkProgram(o),!e.getProgramParameter(o,e.LINK_STATUS))throw new Error(`Shader link failed: ${e.getProgramInfoLog(o)}`);this.program=o,this.uniforms=Object.fromEntries(["mvp","modelMatrix","normalMatrix","tint","light","eye","opacity","unlit","section","appearance","useColors"].map(s=>[s,e.getUniformLocation(o,s)]))}catch(s){throw o&&e.deleteProgram(o),s}finally{for(let s of i)e.deleteShader(s)}}upload(e,i,o){let s=this.gl,n=s.createVertexArray(),r=[];if(!n)throw new Error("Graphics memory is unavailable for this model.");s.bindVertexArray(n);try{for(let[d,l]of[[0,e],[1,i],[2,o]])if(l){let c=s.createBuffer();if(!c)throw new Error("Graphics memory is unavailable for this model.");r.push(c),s.bindBuffer(s.ARRAY_BUFFER,c),s.bufferData(s.ARRAY_BUFFER,l,s.STATIC_DRAW);let m=s.getError();if(m!==s.NO_ERROR)throw new Error(m===s.OUT_OF_MEMORY?"Not enough graphics memory for this model. Try closing other tabs or using another device.":"The browser could not upload this model to the graphics device.");s.enableVertexAttribArray(d),s.vertexAttribPointer(d,3,s.FLOAT,!1,0,0)}return s.bindVertexArray(null),{vao:n,buffers:r,count:e.length/3}}catch(d){s.bindVertexArray(null);for(let l of r)s.deleteBuffer(l);throw s.deleteVertexArray(n),d}}free(e){if(e){for(let i of e.buffers)this.gl.deleteBuffer(i);this.gl.deleteVertexArray(e.vao)}}remove(e){this.diagnostic?.model===e&&this.setDiagnostic(null);let i=this.resources.get(e);if(i)for(let o of Object.values(i))--o.users===0&&(this.sharedResources.get(o.source)?.delete(o),this.free(o));this.resources.delete(e)}clear(){this.setDiagnostic(null),this.setSelection(null);for(let e of this.resources.keys())this.remove(e);this.free(this.gridResource),this.gridResource=null,this.infiniteGrid?.dispose(),this.infiniteGrid=null}get liveBuffers(){let e=(this.gridResource?.buffers.length||0)+(this.selectionResource?.buffers.length||0)+(this.diagnosticResource?.buffers.length||0),i=new Set;for(let o of this.resources.values())for(let s of Object.values(o))i.add(s);for(let o of i)e+=o.buffers.length;return e}setDiagnostic(e){this.free(this.diagnosticResource),this.diagnosticResource=null,this.diagnostic=e}drawDiagnostic(e){let i=this.gl,o=this.uniforms,s=this.diagnostic,n=J(s.model);this.diagnosticResource??=this.upload(s.positions),i.uniformMatrix4fv(o.mvp,!1,new Float32Array(He(e,n))),i.uniformMatrix4fv(o.modelMatrix,!1,new Float32Array(n)),i.uniform4fv(o.section,[0,0,0,0]),i.uniform1i(o.appearance,0),i.uniform1i(o.useColors,0),i.uniform1i(o.unlit,1),i.uniform3fv(o.tint,[.85,.16,.06]),i.uniform1f(o.opacity,1),i.bindVertexArray(this.diagnosticResource.vao),i.disable(i.DEPTH_TEST),i.drawArrays(i.LINES,0,this.diagnosticResource.count),i.enable(i.DEPTH_TEST)}setSelection(e){this.selection!==e&&(this.free(this.selectionResource),this.selectionResource=null,this.selection=e)}drawSelection(e,i){let o=this.gl,s=this.uniforms,n=J(this.selection);this.selectionResource??=this.upload(ao(this.selection.geometry.bounds)),o.uniformMatrix4fv(s.mvp,!1,new Float32Array(He(e,n))),o.uniformMatrix4fv(s.modelMatrix,!1,new Float32Array(n)),o.uniformMatrix3fv(s.normalMatrix,!1,new Float32Array([1,0,0,0,1,0,0,0,1])),o.uniform4fv(s.section,[0,0,0,0]),o.uniform1i(s.appearance,0),o.uniform1i(s.useColors,0),o.uniform1i(s.unlit,1);let r=i==="transparent"?[1,1,1]:Z(i);o.uniform3fv(s.tint,r[0]+r[1]+r[2]<1.5?[.42,.81,.96]:[.08,.43,.65]),o.bindVertexArray(this.selectionResource.vao),o.disable(o.DEPTH_TEST),o.uniform1f(s.opacity,.18),o.drawArrays(o.LINES,0,this.selectionResource.count),o.enable(o.DEPTH_TEST),o.uniform1f(s.opacity,.9),o.drawArrays(o.LINES,0,this.selectionResource.count)}resource(e,i){let o=this.resources.get(e);if(o||(o={},this.resources.set(e,o)),!o[i]){let s=e.geometry,n=i==="edges"||i==="wire",r=n?s[i]:s.positions,d=n?void 0:i==="smooth"?s.smoothNormals:s.normals,l=n?void 0:s.colors,c=this.sharedResources.get(r);c||this.sharedResources.set(r,c=new Set);let m=[...c].find(f=>f.normals===d&&f.colors===l);m||(m=Object.assign(this.upload(r,d,l),{source:r,normals:d,colors:l,users:0}),c.add(m)),m.users++,o[i]=m}return o[i]}setGrid(e){this.grid=e,this.free(this.gridResource),this.gridResource=null}resize(e,i,o=1){let s=this.gl,n=s.getParameter(s.MAX_RENDERBUFFER_SIZE);this.canvas.width=Math.min(n,Math.max(1,Math.round(e*o))),this.canvas.height=Math.min(n,Math.max(1,Math.round(i*o)))}draw(e,i,o,s=!0){if(this.lost)return;let n=this.gl,r=this.uniforms;n.viewport(0,0,this.canvas.width,this.canvas.height),n.clearColor(...o==="transparent"?[0,0,0,0]:[...Z(o),1]),n.depthMask(!0),n.clear(n.COLOR_BUFFER_BIT|n.DEPTH_BUFFER_BIT),n.enable(n.DEPTH_TEST),n.disable(n.CULL_FACE),n.useProgram(this.program),n.vertexAttrib3f(1,0,0,1),n.vertexAttrib3f(2,1,1,1),n.uniform3fv(r.light,Y(H(i.position,i.target))),n.uniform3fv(r.eye,i.position);let d=ht(i,this.canvas.width/this.canvas.height),l=e.filter(_=>_.geometry&&_.opacity>0&&_.color!=="transparent"),c=_=>{let p=Q(J(_),_.geometry.bounds.min.map((w,y)=>(w+_.geometry.bounds.max[y])/2)),h=H(p,i.position);return se(h,h)},m=l.filter(_=>_.opacity>=1&&_.display!=="xray"),f=l.filter(_=>_.opacity<1||_.display==="xray").sort((_,p)=>c(p)-c(_)),b=_=>{let p=J(_),h=ke(p),w=_.geometry;n.uniformMatrix4fv(r.mvp,!1,new Float32Array(He(d,p))),n.uniformMatrix4fv(r.modelMatrix,!1,new Float32Array(p)),n.uniform4fv(r.section,kt(w.bounds,_.section)),n.uniform1i(r.appearance,{mesh:1,xray:2,studio:3,orientation:4}[_.display]||0),n.uniformMatrix3fv(r.normalMatrix,!1,new Float32Array([h[0],h[4],h[8],h[1],h[5],h[9],h[2],h[6],h[10]])),n.uniform3fv(r.tint,_.color&&_.color!=="transparent"?Z(_.color):w.colors?[1,1,1]:Z("#909090")),n.uniform1f(r.opacity,_.opacity),n.uniform1i(r.useColors,+(!_.color&&!!w.colors));let y=_.display==="wireframe"&&w.wire,M=y?"wire":(_.smooth_shading||_.display==="smooth")&&w.smoothNormals?"smooth":"flat";n.uniform1i(r.unlit,+!!y);let P=_.view_edges||_.display==="edges";P&&(n.enable(n.POLYGON_OFFSET_FILL),n.polygonOffset(1,1));let C=this.resource(_,M);if(n.bindVertexArray(C.vao),_.display==="xray"?(n.enable(n.CULL_FACE),n.cullFace(n.FRONT),n.drawArrays(n.TRIANGLES,0,C.count),n.cullFace(n.BACK),n.drawArrays(n.TRIANGLES,0,C.count),n.disable(n.CULL_FACE)):n.drawArrays(y?n.LINES:n.TRIANGLES,0,C.count),n.disable(n.POLYGON_OFFSET_FILL),P&&w.edges){n.uniform1i(r.useColors,0),n.uniform3fv(r.tint,[.08,.09,.11]),n.uniform1i(r.unlit,1);let v=this.resource(_,"edges");n.bindVertexArray(v.vao),n.drawArrays(n.LINES,0,v.count)}};n.disable(n.BLEND);for(let _ of m)b(_);if(this.grid?.infinite)this.infiniteGrid??=new Mt(n),this.infiniteGrid.draw(d,i,this.grid,o),n.useProgram(this.program);else if(this.grid){if(!this.gridResource){let{size:_,divisions:p}=this.grid,h=[];for(let w=0;w<=p;w++){let y=-_/2+_*w/p;h.push(-_/2,y,0,_/2,y,0,y,-_/2,0,y,_/2,0)}this.gridResource=this.upload(new Float32Array(h))}n.uniformMatrix4fv(r.mvp,!1,new Float32Array(d)),n.uniform4fv(r.section,[0,0,0,0]),n.uniform1i(r.appearance,0),n.uniform1i(r.useColors,0),n.uniform3fv(r.tint,[.7,.73,.78]),n.uniform1f(r.opacity,1),n.uniform1i(r.unlit,1),n.bindVertexArray(this.gridResource.vao),n.drawArrays(n.LINES,0,this.gridResource.count)}n.enable(n.BLEND),n.blendFuncSeparate(n.SRC_ALPHA,n.ONE_MINUS_SRC_ALPHA,n.ONE,n.ONE_MINUS_SRC_ALPHA),n.depthMask(!1);for(let _ of f)b(_);s&&this.selection&&l.includes(this.selection)&&this.drawSelection(d,o),s&&this.diagnostic&&e.includes(this.diagnostic.model)&&this.drawDiagnostic(d),n.depthMask(!0),n.disable(n.BLEND),n.bindVertexArray(null),this.frames++}dispose(){this.canvas.removeEventListener("webglcontextlost",this.lostHandler),this.canvas.removeEventListener("webglcontextrestored",this.restoredHandler),this.clear(),this.gl.deleteProgram(this.program),this.gl.getExtension("WEBGL_lose_context")?.loseContext()}};var At=class{constructor(e,i,o,s,n=0){this.enabled=!0,this.noZoom=!1,this.type=n,this.camera=i,this.invalidate=o,this.pointers=new Map,this.cleanups=[],this.canvas=e;let r=(l,c,m)=>{e.addEventListener(l,c,m),this.cleanups.push(()=>e.removeEventListener(l,c,m))};r("pointerdown",l=>{this.enabled&&(l.preventDefault(),e.focus({preventScroll:!0}),e.setPointerCapture(l.pointerId),this.pointers.set(l.pointerId,{x:l.clientX,y:l.clientY,button:l.button}),s(l,l.pointerType==="touch"?20:l.button===2?3:1))}),r("pointermove",l=>{let c=this.pointers.get(l.pointerId);if(!c||!this.enabled)return;let m={x:l.clientX,y:l.clientY,button:c.button};if(this.pointers.size===2){let f=[...this.pointers.entries()].find(([p])=>p!==l.pointerId)[1],b=Math.hypot(c.x-f.x,c.y-f.y),_=Math.hypot(m.x-f.x,m.y-f.y);b>0&&_>0&&this.zoom(b/_),this.pan((m.x-c.x)/2,(m.y-c.y)/2)}else c.button===2||l.shiftKey||c.button===1?this.pan(m.x-c.x,m.y-c.y):this.orbit((m.x-c.x)/Math.max(1,e.clientHeight)*Math.PI,(m.y-c.y)/Math.max(1,e.clientHeight)*Math.PI);this.pointers.set(l.pointerId,m)});let d=l=>{this.pointers.delete(l.pointerId),e.hasPointerCapture(l.pointerId)&&e.releasePointerCapture(l.pointerId)};r("pointerup",d),r("pointercancel",d),r("lostpointercapture",l=>this.pointers.delete(l.pointerId)),r("wheel",l=>{if(!this.enabled||this.noZoom)return;l.preventDefault();let c=l.deltaY*(l.deltaMode===1?16:l.deltaMode===2?e.clientHeight:1);this.zoom(Math.exp(Math.max(-1,Math.min(1,c*.001))))},{passive:!1}),r("dblclick",l=>{this.enabled&&s(l,11)}),r("contextmenu",l=>l.preventDefault())}orbit(e,i){let o=this.camera,s=H(o.position,o.target),n=Y(o.up);s=ft(s,n,-e);let r=Y(le(n,s)),d=ft(s,r,-i);if(this.type===1)s=d,o.up=Y(ft(n,r,-i));else{let l=Y(d),c=l.reduce((m,f,b)=>m+f*n[b],0);Math.abs(c)<.9995&&(s=d)}o.position=ce(o.target,s),this.invalidate()}zoom(e){if(this.noZoom)return;let i=this.camera,o=H(i.position,i.target),s=Math.hypot(...o),n=Math.max(1e-6,Math.min(1e15,s*e));i.position=ce(i.target,ae(o,n/(s||1))),this.invalidate()}pan(e,i){let o=this.camera,s=H(o.position,o.target),n=Y(le(o.up,s)),r=Y(le(s,n)),d=2*Math.hypot(...s)*Math.tan(Math.PI/8)/Math.max(1,this.canvas.clientHeight),l=ce(ae(n,-e*d),ae(r,i*d));o.target=ce(o.target,l),o.position=ce(o.position,l),this.invalidate()}dispose(){for(let e of this.cleanups)e();this.pointers.clear()}};var St=class{constructor(e,{count:i=2,timeout:o=12e4,factory:s}={}){this.url=e,this.count=Math.max(1,Math.min(4,i)),this.timeout=o,this.factory=s,this.queue=[],this.active=new Set,this.next=0,this.disposed=!1}run(e,i,o=[]){if(this.disposed)return Promise.reject(new Error("Viewer disposed"));let s=++this.next,n,r=new Promise((d,l)=>{n={id:s,task:e,progress:i,transfer:o,resolve:d,reject:l},this.queue.push(n)});return r.cancel=()=>this.cancel(n),this.pump(),r}cancel(e){e.done||(e.done=!0,this.queue=this.queue.filter(i=>i!==e),clearTimeout(e.timer),e.worker?.terminate(),this.active.delete(e),e.reject(new DOMException("Loading cancelled","AbortError")),this.pump())}pump(){for(;!this.disposed&&this.active.size<this.count&&this.queue.length;){let e=this.queue.shift();this.active.add(e);let i=(o,s)=>{e.done||(e.done=!0,clearTimeout(e.timer),e.worker?.terminate(),this.active.delete(e),o?e.reject(o):e.resolve(s),this.pump())};try{e.worker=this.factory?this.factory():new Worker(this.url,{type:"module",name:"ViewSTL parser"}),e.worker.onmessage=({data:o})=>{if(o.id===e.id){if(o.progress){e.progress?.(o.progress);return}i(o.error?new Error(o.error):null,o.result)}},e.worker.onerror=o=>{o.preventDefault(),i(new Error(o.message||"Worker failed; check worker URL and Content Security Policy"))},e.worker.onmessageerror=()=>i(new Error("Invalid worker response")),e.timer=setTimeout(()=>i(new Error("File processing timed out")),this.timeout),e.worker.postMessage({id:e.id,task:e.task},e.transfer)}catch(o){i(o)}}}clear(){for(let e of[...this.queue,...this.active])this.cancel(e)}dispose(){this.disposed=!0,this.clear()}};function lo(t,e={}){let i=new AbortController,o=i.signal,s=this._generation,n=[],r=new Map,d=new Set,l=this._models.size>0,c,m=0,f,b=!1,_,p=()=>{i.abort(),c?.cancel?.();for(let[M,P]of r)this._models.get(M)===P&&this.remove_model(M)},h=()=>{if(o.aborted||s!==this._generation||this.killsign)throw new DOMException("Scene opening cancelled","AbortError")},w=M=>e.on_progress?.(M);e.signal?.addEventListener("abort",p,{once:!0}),e.signal?.aborted&&p(),o.addEventListener("abort",()=>c?.cancel?.(),{once:!0}),this._aborters.add(i);let y=(async()=>{await this.when_ready,h(),f=this.get_camera_state();let M=e.format||Me(typeof t=="string"?t:t.name);if(!["vsb","vsj"].includes(M))throw new Error("Choose VSB or VSJ for a scene");let P,C;if(typeof t=="string"){if(P=$t(t,document.baseURI),!this.options.url_import_endpoint)throw new Error("Configure url_import_endpoint for scene URL imports");if(C=new URL(this.options.url_import_endpoint,document.baseURI).href,new URL(C).origin!==location.origin)throw new Error("The URL relay must use the same origin as this page")}let v=this.limits.max_memory_bytes-this._occupiedMemory();X(this.limits,this._occupiedMemory()+67108864,"scene opening");let R={...this.limits,max_memory_bytes:v,max_file_bytes:Math.min(this.limits.max_file_bytes,Math.floor((v-67108864)/4))};m=Math.max(0,v-67108864),this._sceneBytes=(this._sceneBytes||0)+m,c=this._pool.run({kind:"read-scene",source:t,remote:P,relay:C,format:M,name:`scene.${M}`,limits:R},S=>{try{w({...S,phase:"reading-scene"})}catch(N){_=N,c.cancel()}});let k;try{k=await c}catch(S){throw _||S}c=null,h();let{scene:g,files:A,base:I}=k,E=vt(this.get_camera_bookmarks(),g.camera_bookmarks||[]);this._sceneBytes-=m,m=Object.values(A||{}).reduce((S,N)=>S+N.byteLength,0)+JSON.stringify(g).length*2,this._sceneBytes+=m;let L=e.files||[],T=[],D=g.models.map(S=>{let N={...S};if(A)N.local_file=new File([A[S.filename]],S.filename);else{let F=io(S.filename,L);if(F)N.local_file=F,d.add(F);else{let j=$t(S.filename,P?I:void 0);j?N.remote_url=j:T.push(S.filename)}}if(N.remote_url&&!this.options.url_import_endpoint)throw new Error("Scene URL references require a configured URL relay");return N});if(T.length)throw new Error("Choose the VSJ together with these model files: "+T.slice(0,8).join(", ")+(T.length>8?"\u2026":""));if(D.length+this._models.size>this.limits.max_archive_entries)throw new Error("Scene model count limit exceeded");for(let S=0;S<D.length;S++){h(),w({phase:"opening-model",loaded:S,total:D.length}),h();let N=D[S],F=this.max_model_id+1;this.add_model({...N,id:F,animation:null,animation_state:null});let j=this._models.get(F);if(!j)throw new Error(this.error||"Invalid scene model");if(n.push(F),r.set(F,j),j._sceneImportPending=!0,await this._pending.get(F),h(),this._models.get(F)!==j||!j.geometry)throw new Error(this.error||"A scene model could not be opened");let ve=g.center_models??this.center_models?j.geometry.bounds.min.map((U,W)=>(U+j.geometry.bounds.max[W])/2):[0,0,0],Fe=j.center.map((U,W)=>U-ve[W]),K=Q(J({...j,x:0,y:0,z:0,center:[0,0,0],scaleVector:j.scaleVector}),Fe);if(N.animation?j.center=[...N.animation_state?.center??ve]:["x","y","z"].forEach((U,W)=>j[U]+=K[W]),[...this._models.values()].reduce((U,W)=>U+(W.geometry?.triangles||0),0)>this.limits.max_triangles)throw new Error("Scene triangle limit exceeded")}w({phase:"complete",loaded:D.length,total:D.length}),h();for(let S=0;S<n.length;S++){let N=r.get(n[S]),F=D[S];F.animation&&this._startAnimation(N,F.animation,F.animation_state),N._sceneImportPending=!1}return g.bg_color!==void 0&&this.set_bg_color(g.bg_color),g.infinite_grid?this.set_infinite_grid(!0,g.infinite_grid.spacing,g.infinite_grid.height):this.set_grid(!!g.grid),g.auto_rotate!==void 0&&this.set_auto_rotate(g.auto_rotate),this._restoreCamera=g.camera_state||(l?f:null),this.camera_bookmarks=E,g.display_units&&(this.display_units=g.display_units),b=!0,{model_ids:n,scene:g,used_files:[...d]}})().catch(M=>{throw p(),M}).finally(()=>{e.signal?.removeEventListener("abort",p),this._aborters.delete(i),this._sceneBytes=(this._sceneBytes||0)-m,this._sceneLoads.delete(y),s===this._generation&&!this.killsign&&(!b&&f&&(this._restoreCamera=f),this._finishSession())});return this._sessionActive=!0,this._sceneLoads.add(y),y}var Qe=new WeakMap;function It(t,e){let i=Qe.get(e);return!!i&&i.viewer.deref()===t&&i.models.every(({model:o,geometry:s,signature:n})=>{let r=o.deref();return r&&t._models.get(r.id)===r&&r.geometry===s.deref()&&be(r)===n})}async function co(t={}){await this.when_ready;let e=Wi(t);if(this.killsign)throw new Error("Viewer disposed");let i=t.model_ids;if(i==="selected"&&(i=this.renderer?.selection?[this.renderer.selection.id]:[]),i??=[...this._models.keys()],!Array.isArray(i)||!i.length||new Set(i).size!==i.length||i.some(p=>!Number.isSafeInteger(p)))throw new Error("Choose one or more unique model IDs");if(i.length>this.limits.max_archive_entries)throw new Error("Print check model limit exceeded");let o=i.map(p=>{let h=this._model(p);if(!h.geometry||h._sceneImportPending)throw new Error("Wait for models to finish opening");return{model:h,geometry:h.geometry,signature:be(h)}}),s=JSON.stringify([i,e]);if(t.signal?.aborted)throw new DOMException("Print check cancelled","AbortError");if(this._printCache?.key===s&&It(this,this._printCache.report)){let p=structuredClone(this._printCache.report);return Qe.set(p,Qe.get(this._printCache.report)),p}if(this._printJobs?.size)throw new Error("A print check is already running");this._printJobs??=new Map;let n=new AbortController,r=()=>n.abort();t.signal?.addEventListener("abort",r,{once:!0}),this._aborters.add(n),this._printJobs.set(n,new Set(o.map(p=>p.model)));let d,l=0,c,m=()=>d?.cancel?.();n.signal.addEventListener("abort",m);let f=()=>{if(n.signal.aborted||this.killsign)throw new DOMException("Print check cancelled","AbortError");if(o.some(({model:p,geometry:h,signature:w})=>this._models.get(p.id)!==p||p.geometry!==h||be(p)!==w))throw new Error("Model changed. Run the print check again.")},b=p=>{f(),t.on_progress?.(p)},_=[];try{this._printCache=null;let p=o.length*256*1024;X(this.limits,this._occupiedMemory()+p,"print report"),l=p,this._printBytes=(this._printBytes||0)+l;for(let M=0;M<o.length;M++){f();let{model:P,geometry:C}=o[M],v=yt(C.triangles),R=this._occupiedMemory();X(this.limits,R+v,"print check"),this._printBytes+=v,l+=v;let k=new Float32Array(C.positions.length);for(let A=0;A<k.length;A+=262144)f(),k.set(C.positions.subarray(A,A+262144),A),A+262144<k.length&&await new Promise(I=>setTimeout(I,0));let g=e.apply_transforms?P:{...P,x:0,y:0,z:0,rotationx:0,rotationy:0,rotationz:0,center:[0,0,0],scaleVector:[1,1,1].map(()=>P.unitScale*(P.size_state?.unit_factor??1))};b({phase:"Starting",model_id:P.id,model_index:M,total_models:o.length}),d=this._pool.run({kind:"print-check",model:{id:P.id,name:P.orig_filename||P.filename||`Model ${P.id}`,positions:k,matrix:J(g),source_units:C.units||null},options:e,limits:{...this.limits,max_memory_bytes:this.limits.max_memory_bytes-R}},A=>{try{b({...A,model_id:P.id,model_index:M,total_models:o.length})}catch(I){c=I,n.abort()}},[k.buffer]);try{_.push(await d)}catch(A){throw c||A}finally{d=null,this._printBytes-=v,l-=v}}f();let h={version:1,model_ids:i.slice(),settings:e,models:_,summary:_.some(M=>M.summary==="issues_found")?"issues_found":_.some(M=>M.summary==="incomplete")?"incomplete":"no_issues_found",scope:"Each model checked separately; no cross-model union or collision analysis.",estimated:!!e.profile},w={viewer:new WeakRef(this),models:o.map(({model:M,geometry:P,signature:C})=>({model:new WeakRef(M),geometry:new WeakRef(P),signature:C}))};Qe.set(h,w);let y=structuredClone(h);return Qe.set(y,w),JSON.stringify(y).length<2*1024*1024&&this._occupiedMemory()+4*1024**2<=this.limits.max_memory_bytes&&(this._printCache={key:s,report:y}),b({phase:"Complete",total_models:o.length}),h}finally{d?.cancel?.(),this._printBytes=(this._printBytes||0)-l,t.signal?.removeEventListener("abort",r),this._aborters.delete(n),this._printJobs.delete(n)}}function mo(t,{issue:e,model_id:i=t.model_ids[0]}={}){if(!It(this,t))throw new Error("Print report is stale. Run the check again.");let o=t.models.find(l=>l.model_id===i),s=o?.checks.find(l=>l.code===e);if(!s)throw new Error("Unknown print check issue");let n=this._model(i),r=n.geometry.positions,d=[];if(s.edge_vertices?.length)d.push(...s.edge_vertices.slice(0,1536));else for(let l of s.triangle_ids.slice(0,128))if(!(!Number.isInteger(l)||l<0||l>=n.geometry.triangles))for(let c=0;c<3;c++)d.push(...r.subarray(l*9+c*3,l*9+c*3+3),...r.subarray(l*9+(c+1)%3*3,l*9+(c+1)%3*3+3));if(d.some(l=>!Number.isFinite(l)))throw new Error("Invalid print highlight");return this.renderer.setDiagnostic(d.length?{model:n,positions:new Float32Array(d),signature:be(n)}:null),this._invalidate(),d.length/6}function oi(t,e){return`${String(t||"scene").split(/[\\/]/).pop().split(/[?#]/)[0].replace(/[<>:"|*\x00-\x1f\x7f]/g,"_").replace(/\.(?:stl|obj|3mf|step|stp|iges|igs|zip|vsb|vsj)$/i,"").replace(/[. ]+$/g,"").slice(0,160)||"scene"}.${e}`}function uo(t={}){let e={stp:"step",igs:"iges"},i=String(t.format||"").toLowerCase(),o=e[i]||i;if(!["stl","obj","3mf","step","iges"].includes(o))throw new Error("Export format must be stl, obj, 3mf, step or iges");let s=t.units??"mm";if(!["mm","inch"].includes(s))throw new Error("Export units must be mm or inch");for(let d of["apply_transforms","colors"])if(t[d]!==void 0&&typeof t[d]!="boolean")throw new Error(`${d} must be a boolean`);if(t.on_progress!==void 0&&typeof t.on_progress!="function")throw new Error("on_progress must be a function");let n=t.colors!==!1&&["obj","3mf"].includes(o),r=o==="obj"&&n?"zip":o;return{format:o,units:s,colors:n,apply_transforms:t.apply_transforms!==!1,filename:oi(t.filename,r)}}function ho(t,e){let i=t.reduce((s,n)=>s+n.geometry.triangles,0);return 67108864+i*{stl:192,obj:2400,"3mf":3e3,step:12e3,iges:4e3}[e.format]+t.length*4096}async function fo(t,e,i=()=>{},o){let s,n=0;if(t instanceof ArrayBuffer){if(t.byteLength>e)throw new Error("File size limit exceeded");return i(t.byteLength,t.byteLength),t}if(t instanceof Blob){if(n=t.size,n>e)throw new Error("File size limit exceeded");if(o?.aborted)throw new DOMException("Loading cancelled","AbortError");i(0,n);let f=await t.arrayBuffer();if(o?.aborted)throw new DOMException("Loading cancelled","AbortError");return i(n,n),f}else{let f=new URL(String(t),globalThis.location?.href);if(!["http:","https:","blob:"].includes(f.protocol))throw new Error("Unsupported file URL protocol");let b=await fetch(f,{signal:o,credentials:"same-origin"});if(!b.ok)throw new Error(`HTTP ${b.status}: ${f.pathname}`);n=Number(b.headers.get("content-length"))||0,s=b.body}if(n>e)throw new Error("File size limit exceeded");if(!s)throw new Error("Empty response body");let r=s.getReader(),d=[],l=0;try{for(;;){if(o?.aborted)throw new DOMException("Loading cancelled","AbortError");let{done:f,value:b}=await r.read();if(f)break;if(l+=b.length,l>e)throw new Error("File size limit exceeded");d.push(b),i(l,Math.max(n,l))}}catch(f){throw await r.cancel().catch(()=>{}),f}finally{r.releaseLock()}let c=new Uint8Array(l),m=0;for(let f of d)c.set(f,m),m+=f.length;return i(l,l),c.buffer}function po(t,e){if(!t?.isMesh&&!t?.geometry)throw new Error("Expected a Three.js mesh");if(t.isSkinnedMesh||t.isInstancedMesh||t.children?.length||t.morphTargetInfluences?.some(Boolean))throw new Error("Only a static standalone Three.js mesh is supported");let i=t.material;if(Array.isArray(i)||i?.isShaderMaterial||i?.map)throw new Error("Multiple, textured or shader materials need an application adapter");let o=t.geometry,s,n=null;if(o?.attributes?.position){let r=o.attributes.position,d=o.index,l=d?.count??r.count;if(l%3||l/3>e.max_triangles)throw new Error("Invalid or oversized mesh");s=new Float32Array(l*3),o.attributes.color&&(n=new Float32Array(l*3));for(let c=0;c<l;c++){let m=d?d.getX(c):c;for(let[f,b]of["getX","getY","getZ"].entries())s[c*3+f]=r[b](m),n&&(n[c*3+f]=o.attributes.color[b](m))}}else if(o?.vertices&&o?.faces){if(o.faces.length>e.max_triangles)throw new Error("Triangle limit exceeded");s=new Float32Array(o.faces.length*9),i?.vertexColors&&(n=new Float32Array(s.length)),o.faces.forEach((r,d)=>{for(let[l,c]of[r.a,r.b,r.c].entries()){let m=o.vertices[c];if(!m)throw new Error("Invalid mesh index");s.set([m.x,m.y,m.z],d*9+l*3),n&&n.set([r.color.r,r.color.g,r.color.b],d*9+l*3)}})}else throw new Error("Unsupported Three.js geometry");return Et(s,n,e)}function _o(t,e){if(!e?.Mesh||!e?.BufferGeometry||!e?.BufferAttribute)throw new Error("get_model_mesh requires options.three or globalThis.THREE; use get_model_data for native geometry");let i=t.geometry,o=new e.BufferGeometry,s=i.positions.slice(),n=t.scaleVector,r=t.center;for(let m=0;m<s.length;m++)s[m]=(s[m]-r[m%3])*n[m%3];let d=(m,f)=>{let b=new e.BufferAttribute(f,3);o.setAttribute?o.setAttribute(m,b):o.addAttribute(m,b)};d("position",s),i.colors&&!t.color&&d("color",i.colors.slice()),o.computeVertexNormals();let l=new e.MeshLambertMaterial({color:t.color==="transparent"?"#909090":t.color||(i.colors?"#ffffff":"#909090"),vertexColors:i.colors&&!t.color?e.VertexColors??!0:!1,side:e.DoubleSide,transparent:t.opacity<1||t.color==="transparent",opacity:t.color==="transparent"?0:t.opacity,wireframe:t.display==="wireframe",flatShading:t.display!=="smooth"}),c=new e.Mesh(o,l);return c.position.set(t.x,t.y,t.z),c.rotation.set(t.rotationx,t.rotationy,t.rotationz),c}var ni=["x","y","z","rotationx","rotationy","rotationz","scalex","scaley","scalez"],jo=["id","filename","remote_url","remote_format","orig_filename","local_file","mesh","data","x","y","z","display","color","scale","scalex","scaley","scalez","rotationx","rotationy","rotationz","opacity","view_edges","smooth_shading","section","units","animation","animation_state","size_state","display_name"],$=(t,e)=>{if(typeof t!="number"||!Number.isFinite(t))throw new Error(`${e} must be a finite number`);return t},Te=(t,e)=>{if($(t,e),t<=0)throw new Error(`${e} must be positive`);return t},ri=(t,e)=>[$(t.x,`${e}.x`),$(t.y,`${e}.y`),$(t.z,`${e}.z`)],Ct=t=>({x:t[0],y:t[1],z:t[2]}),Rt=t=>String(t||"model.stl").split(/[\\/]/).pop().split(/[?#]/)[0];function $e(t,e){let i=document.createElement("a"),o=URL.createObjectURL(t);i.href=o,i.download=Rt(e),i.click(),setTimeout(()=>URL.revokeObjectURL(o),1e3)}function go(t){let e={};for(let i of jo)Object.hasOwn(t,i)&&(e[i]=t[i]);return e}var ze=class t{static version="2.0.0-rc.7";static workerURL=null;constructor(e,i={}){if(!e?.appendChild)throw new TypeError("StlViewer requires a DOM container");this.parent_element=e,this.options={...i},this.error=null,this.ready=!1,this.killsign=!1,this.models=[],this.models_ref=Object.create(null),this.models_count=0,this.max_model_id=-1,this.load_status=Object.create(null),this.load_session=0,this._models=new Map,this._pending=new Map,this._jobs=new Map,this._derived=new Set,this._memoryReservations=new Map,this._exportBytes=0,this._loadTail=Promise.resolve(),this._sceneLoads=new Set,this._aborters=new Set,this._generation=0,this._sessionActive=!1,this._frame=0,this._lastTime=0,this.camera_bookmarks=[],this.display_units="mm",this.grid=null,this._gridAuto=!1,this.camera={position:[0,0,100],target:[0,0,0],up:[0,1,0],near:.01,far:1e4},this.when_ready=new Promise((o,s)=>{this._readyResolve=o,this._readyReject=s}),this.when_ready.catch(()=>{});for(let o of["ready_callback","all_loaded_callback","model_loaded_callback","load_error_callback","loading_progress_callback","on_model_drop","animation_state_callback","animation_complete_callback"])this[o]=i[o]??null;this.onmousedown_callback=i.on_model_mousedown??i.on_model_mouseclick??null,queueMicrotask(()=>this._initialize())}_initialize(){if(!this.killsign)try{let e=this.options;if(this.limits=$i(e),this.bg_color=e.bg_color??e.bgcolor??"transparent",this.bg_color!=="transparent"&&Z(this.bg_color),e.worker_count!==void 0&&(!Number.isInteger(e.worker_count)||e.worker_count<1||e.worker_count>4))throw new Error("worker_count must be 1\u20134");if(e.worker_timeout!==void 0&&Te(e.worker_timeout,"worker_timeout"),e.pixel_ratio!==void 0&&Te(e.pixel_ratio,"pixel_ratio"),e.controls!==void 0&&e.controls!==0&&e.controls!==1)throw new Error("controls must be 0 or 1");this.center_models=e.center_models??!0,this.auto_resize=e.auto_resize??!0,this.auto_rotate=e.auto_rotate??!1,this.mouse_zoom=e.mouse_zoom??!0,this.send_no_model_click_event=e.send_no_model_click_event??!1,this.zoom=e.zoom??-1,this.canvas_width=e.width??e.canvas_width??"100%",this.canvas_height=e.height??e.canvas_height??"100%",this.canvas=document.createElement("canvas"),this.canvas.style.cssText="display:block;touch-action:none;outline-offset:3px;",this._setSizeStyle(),this.canvas.tabIndex=0,this.canvas.setAttribute("aria-label","3D model viewer. Drag to rotate, shift-drag to pan, scroll to zoom."),this.parent_element.appendChild(this.canvas),this.renderer=new zt(this.canvas,()=>{this._suspendAnimations(!0),this._message("Graphics interrupted. Waiting for the browser to restore rendering\u2026")},()=>{this._removeMessage(),this._suspendAnimations(this.canvas.ownerDocument.hidden),this._invalidate()},o=>this._error(o)),this.controls=new At(this.canvas,this.camera,()=>this._invalidate(),(o,s)=>this._pick(o,s),e.controls??0),this.controls.noZoom=!this.mouse_zoom;let i=e.worker_url??t.workerURL;if(e.worker_url===void 0&&typeof e.load_three_files=="string"&&(i=new URL("viewstl.worker.js",new URL(e.load_three_files||"./",document.baseURI)).href),!i&&!e.worker_factory)throw new Error("Specify worker_url when using the CommonJS build");this._pool=new St(i,{count:e.worker_count??2,timeout:e.worker_timeout??12e4,factory:e.worker_factory}),this._drop=o=>{o.preventDefault();let s=[...o.dataTransfer.files];for(let n of s)this._callback("on_model_drop",n.name),this.add_model({local_file:n})},this._drag=o=>o.preventDefault(),this.set_drag_and_drop(e.allow_drag_and_drop??!0),this.set_auto_resize(this.auto_resize),this.do_resize(),this.camera.position=[e.camerax??0,e.cameray??0,this.zoom>=0?Math.max(this.zoom,1e-6):e.cameraz??100],e.camera_state&&(this.set_camera_state(e.camera_state),this._restoreCamera=e.camera_state),e.grid&&this.set_grid(!0),this._key=o=>{if(!this.controls.enabled)return;let s={ArrowLeft:()=>this.controls.orbit(-.12,0),ArrowRight:()=>this.controls.orbit(.12,0),ArrowUp:()=>this.controls.orbit(0,-.12),ArrowDown:()=>this.controls.orbit(0,.12),"+":()=>this.controls.zoom(.9),"-":()=>this.controls.zoom(1.1),f:()=>this.set_auto_zoom()};s[o.key]&&(o.preventDefault(),s[o.key]())},this.canvas.addEventListener("keydown",this._key),this._visibility=()=>this._suspendAnimations(this.canvas.ownerDocument.hidden||this.renderer.lost),this.canvas.ownerDocument.addEventListener("visibilitychange",this._visibility),this._animationSuspended=this.canvas.ownerDocument.hidden,this.ready=!0,this._readyResolve(this),this._callback("ready_callback"),e.models&&this.add_models(e.models),this._invalidate()}catch(e){this.ready=!1,this._readyReject(e),this._error(e),this._message(e.message),this._pool?.dispose(),this.controls?.dispose(),this.renderer?.dispose(),this._resizeObserver?.disconnect(),this._visibility&&this.canvas.ownerDocument.removeEventListener("visibilitychange",this._visibility)}}_callback(e,...i){let o=this[e];if(typeof o=="function")try{o(...i)}catch(s){console.error(`ViewSTL ${e} callback failed`,s)}}_error(e){return this.error=e?.message??String(e),this._callback("load_error_callback",this.error),null}_message(e){this._removeMessage(),this._messageElement=document.createElement("p"),this._messageElement.setAttribute("role","status"),this._messageElement.textContent=e,this.parent_element.appendChild(this._messageElement)}_removeMessage(){this._messageElement?.remove(),this._messageElement=null}_setSizeStyle(){this.canvas.style.width=typeof this.canvas_width=="number"?`${this.canvas_width}px`:this.canvas_width,this.canvas.style.height=typeof this.canvas_height=="number"?`${this.canvas_height}px`:this.canvas_height}_guard(e){if(this.killsign)return null;try{return e()}catch(i){return this._error(i)}}_model(e){let i=this._models.get(Number(e));if(!i)throw new Error(`Model id not found: ${e}`);return i}_invalidate(){let e=this.renderer?.diagnostic;e&&be(e.model)!==e.signature&&this.renderer.setDiagnostic(null),!(this.killsign||!this.renderer||this.renderer.lost||this._frame||this._animationSuspended)&&(this._frame=requestAnimationFrame(i=>{this._frame=0,this._render(i)}))}_render(e){let i=this._lastTime?Math.min((e-this._lastTime)/1e3,.1):0;this._lastTime=e;let o=!1;for(let n of this._models.values())n.geometry&&!n._sceneImportPending&&n._animation&&!n._animation.paused&&(this._animate(n,e),o||=!!n._animation&&!n._animation.paused);this.auto_rotate&&this.controls.enabled&&this.controls.orbit(i*.3,0);let s=this.renderer.diagnostic;s&&be(s.model)!==s.signature&&this.renderer.setDiagnostic(null),this._clip();try{this.renderer.draw([...this._models.values()].filter(n=>!n._sceneImportPending),this.camera,this.bg_color)}catch(n){this.renderer.clear(),this._error(n);return}o||this.auto_rotate&&this.controls.enabled?this._invalidate():this._lastTime=0}_bounds(){let e=[1/0,1/0,1/0],i=[-1/0,-1/0,-1/0],o=0;for(let s of this._models.values())if(s.geometry&&!s._sceneImportPending){o++;let{bounds:n}=s.geometry,r=J(s);for(let d=0;d<8;d++){let l=Q(r,[0,1,2].map(c=>n[d&1<<c?"max":"min"][c]));for(let c=0;c<3;c++)e[c]=Math.min(e[c],l[c]),i[c]=Math.max(i[c],l[c])}}return o?{min:e,max:i,center:e.map((s,n)=>(s+i[n])/2),radius:Math.max(Math.hypot(...H(i,e))/2,1e-6)}:null}_clip(){let e=this._bounds(),i=Math.hypot(...H(this.camera.position,e?.center??this.camera.target)),o=e?.radius??10;this.camera.near=Math.max(1e-6,Math.min(o*.001,Math.max(i-o,1e-6)*.1)),this.camera.far=Math.max(this.camera.near*100,i+o*4,100)}_progress(e,i){!this._models.has(e)||this.killsign||(this.load_status[e]=i,this._callback("loading_progress_callback",this.load_status,this.load_session))}add_models(e){return this._guard(()=>{if(!Array.isArray(e))throw new Error("models must be an array");for(let i of e)this.add_model(i)})}add_model(e){return this._guard(()=>{if(!e||typeof e!="object")throw new Error("Invalid model");let i=go(e),o=i.filename??i.local_file?.name??"model.stl";if(/\.vsj(?:[?#]|$)/i.test(o))return this.load_vsj(i.local_file??o);if(/\.vsb(?:[?#]|$)/i.test(o))return this.load_vsb(i.local_file??o);let s=i.id===void 0||i.id===-1?this.max_model_id+1:i.id;if(!Number.isSafeInteger(s)||s<0||this._models.has(s))throw new Error(`Invalid or duplicate model id: ${s}`);let n={...i,id:s,filename:i.filename??i.local_file?.name??"",x:0,y:0,z:0,rotationx:0,rotationy:0,rotationz:0,scalex:1,scaley:1,scalez:1,opacity:1,units:"mm",display:"flat",view_edges:!1,color:null,unitScale:1,center:[0,0,0],geometry:null};for(let l of ni)n[l]=i[l]??(l.startsWith("scale")?i.scale??1:0);for(let l of ni)$(n[l],l),l.startsWith("scale")&&Te(n[l],l);if(i.size_state&&(n.size_state=Kt(i.size_state)),i.display_name!=null){if(typeof i.display_name!="string"||i.display_name.length>1024)throw new Error("Invalid model name");n.display_name=i.display_name}if(n.opacity=i.opacity??i.mesh?.material?.opacity??1,$(n.opacity,"opacity"),n.opacity<0||n.opacity>1)throw new Error("Opacity must be between 0 and 1");if(n.display=i.display??"flat",Object.assign(n,wt(n.display,i.smooth_shading??n.display==="smooth")),n.section=xt(i.section),n.units=i.units??"mm",!["mm","inch"].includes(n.units))throw new Error("Invalid units");if(n.color=i.color??(i.mesh?.material?.color?.getHexString?"#"+i.mesh.material.color.getHexString():null),n.color&&n.color!=="transparent"&&Z(n.color),n.view_edges=!!i.view_edges,n.animation=i.animation==null?null:Ye(i.animation),n.animation_state=i.animation_state==null?null:Je(i.animation_state),n.animation_state&&!n.animation)throw new Error("Playback state needs an animation");n.animation&&Xe(n.animation,n,n.animation_state),Object.defineProperty(n,"scaleVector",{get:()=>[n.scalex*n.unitScale,n.scaley*n.unitScale,n.scalez*n.unitScale]}),this.max_model_id=Math.max(s,this.max_model_id),this._models.set(s,n),this.models_ref[s]=this.models.length,this.models.push(n),this.models_count=this._models.size,this._sessionActive=!0,this.load_status[s]={loaded:0,total:0};let r=this._generation,d=this._loadModel(n,i,r).then(()=>{r!==this._generation||this._models.get(s)!==n||(this._pending.delete(s),this._finishSession(),this._callback("model_loaded_callback",s))}).catch(l=>{r===this._generation&&this._models.get(s)===n&&(this._pending.delete(s),this._deleteModel(n),l.name!=="AbortError"&&this._error(l),this._finishSession())}).finally(()=>{this._jobs.delete(n)});this._pending.set(s,d)})}_occupiedMemory(e){let i=(this._exportBytes||0)+(this._sceneBytes||0)+(this._printBytes||0)+(this._printCache?4194304:0);for(let o of this._models.values())if(o!==e){let s=this._memoryReservations?.get(o);i+=Math.max(Ke(o.geometry),[...s?.values()||[]].reduce((n,r)=>n+r.bytes,0))}return i}_reserveMemory(e,i,o="derive"){this._memoryReservations??=new Map;let s=this._memoryReservations.get(e);s||this._memoryReservations.set(e,s=new Map);let n={};return s.set(n,{bytes:i,kind:o}),()=>{s.delete(n),!s.size&&this._memoryReservations.get(e)===s&&this._memoryReservations.delete(e)}}async _loadModel(e,i,o){let s=()=>{};if(this.options.max_memory_bytes!==void 0){let n=this._loadTail;this._loadTail=new Promise(r=>{s=r}),await n}try{await this._readModel(e,i,o)}finally{s()}}async _readModel(e,i,o){if(await this.when_ready,this.killsign||o!==this._generation||this._models.get(e.id)!==e)return;let s=Math.max(1,this.limits.max_memory_bytes-this._occupiedMemory(e)),n={...this.limits,max_memory_bytes:s};X(n,67108864,"scene");let r=this.limits.max_memory_bytes<Number.MAX_SAFE_INTEGER?this._reserveMemory(e,s-67108864,"parse"):()=>{};try{let d=Zt(e);if(i.mesh)e.geometry=po(i.mesh,n);else if(i.data)e.geometry=Et(new Float32Array(i.data.positions),i.data.colors?new Float32Array(i.data.colors):null,n);else{let l=i.local_file??i.filename??i.remote_url;if(!l)throw new Error("A filename, local_file or mesh is required");let c;if(i.remote_url){let f=new URL(i.remote_url);if(!["https:","http:"].includes(f.protocol)||f.username||f.password)throw new Error("Use a public HTTP or HTTPS file URL without login credentials.");if(!this.options.url_import_endpoint)throw new Error("Configure url_import_endpoint to import remote URLs through a relay.");if(c=new URL(this.options.url_import_endpoint,document.baseURI).href,new URL(c).origin!==location.origin)throw new Error("The URL relay must use the same origin as this page.")}let m=this._pool.run({kind:"parse",remote:i.remote_url,format:i.remote_format,relay:c,source:typeof l=="string"?new URL(l,document.baseURI).href:l,name:e.display_name||e.filename,limits:n,features:d.smooth||d.edges||d.wire?d:null},f=>this._progress(e.id,f));this._jobs.set(e,m),e.geometry=await m,i.remote_url&&(e.filename=e.geometry.source_name,delete e.remote_url,delete e.remote_format)}if(this.killsign||o!==this._generation||this._models.get(e.id)!==e){e.geometry=null;return}this.center_models&&(e.center=e.geometry.bounds.min.map((l,c)=>(l+e.geometry.bounds.max[c])/2)),(i.mesh||i.data)&&(d.smooth||d.edges||d.wire)&&await this._derive(e,d),e.animation_state&&(e.center=[...e.animation_state.center]),e.animation&&!e._animation&&this._startAnimation(e,e.animation,e.animation_state),delete e.animation_state,delete e.mesh,delete e.data,this._invalidate()}finally{r()}}_finishSession(){this.killsign||this._pending.size||this._sceneLoads.size||!this._sessionActive||(this._sessionActive=!1,this._restoreCamera?(this.set_camera_state(this._restoreCamera),this._restoreCamera=null):this.zoom===-1&&this.set_auto_zoom(),this._gridAuto&&this.set_grid(!0),this.load_session++,this._callback("all_loaded_callback"),this._invalidate())}_deleteModel(e){this._stopAnimation(e,"removed");for(let i of e._measureJobs||[])i.abort();for(let[i,o]of this._printJobs||[])o.has(e)&&i.abort();this._printCache=null,this.renderer?.selection===e&&this.renderer.setSelection(null),this.renderer?.remove(e),this._jobs.get(e)?.cancel?.();for(let i of e._deriveJobs||[])i.cancel?.();this._models.delete(e.id),this._memoryReservations.delete(e),this.models[this.models_ref[e.id]]=null,delete this.models_ref[e.id],delete this.load_status[e.id],this.models_count=this._models.size,this._invalidate()}remove_model(e){return this._guard(()=>{let i=this._model(e);this._deleteModel(i),this._pending.delete(i.id),this._finishSession()})}clean(){if(!this.killsign){this._generation++,this._printCache=null,this.camera_bookmarks=[],this.display_units="mm",this._pool?.clear();for(let e of this._aborters)e.abort();this._aborters.clear();for(let e of this._models.values())this._stopAnimation(e,"clean");this._models.clear(),this._pending.clear(),this._jobs.clear(),this._derived.clear(),this._memoryReservations.clear(),this._sceneLoads.clear(),this.models=[],this.models_ref=Object.create(null),this.models_count=0,this.max_model_id=-1,this.load_status=Object.create(null),this._sessionActive=!1,this.renderer?.clear(),this._restoreCamera=null,this._invalidate()}}dispose(){if(!this.killsign){this.clean(),this.killsign=!0,this.ready=!1,this._readyReject(new Error("Viewer disposed")),cancelAnimationFrame(this._frame),this._frame=0,this._pool?.dispose(),this.controls?.dispose(),this._resizeObserver?.disconnect(),this._windowResize&&window.removeEventListener("resize",this._windowResize),this.renderer?.dispose(),this.canvas&&(this._visibility&&this.canvas.ownerDocument.removeEventListener("visibilitychange",this._visibility),this.canvas.removeEventListener("drop",this._drop),this.canvas.removeEventListener("dragover",this._drag),this.canvas.removeEventListener("keydown",this._key),this.canvas.remove()),this._removeMessage();for(let e of Object.keys(this))e.endsWith("_callback")&&(this[e]=null);this.options={}}}async when_idle(){for(await this.when_ready;this._pending.size||this._sceneLoads.size||this._derived.size;)await Promise.allSettled([...this._pending.values(),...this._sceneLoads,...this._derived]);return this}_derive(e,i){let o=this._occupiedMemory(e)+[...this._memoryReservations?.get(e)?.values()||[]].filter(m=>m.kind==="derive").reduce((m,f)=>m+f.bytes,0),s=Hi(e.geometry.triangles,{...i,smooth:i.smooth||!!e.geometry.smoothNormals,edges:i.edges||!!e.geometry.edges,wire:i.wire||!!e.geometry.wire});X(this.limits,o+s,"view mode");let n=this._reserveMemory(e,s-67108864),r=this._generation,d=e._deriveRevision=(e._deriveRevision||0)+1,l;try{let m=e.geometry.positions.slice();l=this._pool.run({kind:"derive",positions:m,features:i,limits:{...this.limits,max_memory_bytes:this.limits.max_memory_bytes-o}},null,[m.buffer])}catch(m){throw n(),m}(e._deriveJobs??=new Set).add(l);let c=l.then(m=>!this.killsign&&r===this._generation&&d===e._deriveRevision&&this._models.get(e.id)===e?(Object.assign(e.geometry,m),this.renderer.remove(e),this._invalidate(),!0):!1).catch(m=>{m.name!=="AbortError"&&r===this._generation&&this._error(m)}).finally(()=>{n(),e._deriveJobs.delete(l),this._derived.delete(c)});return this._derived.add(c),c}set_view(e,i){return this._guard(()=>{let o=this._model(e),s=o._requestedView||o,n=wt(i.display??s.display,i.smooth_shading??s.smooth_shading),r=Zt({...o,...n}),d=o.geometry,c=d&&(r.smooth&&!d.smoothNormals||r.wire&&!d.wire||r.edges&&(!d.edges||d.edgeAngle!==r.edgeAngle))?this._derive(o,r):null,m=(o._viewRevision||0)+1;o._viewRevision=m,o._requestedView=n;let f=b=>{this._models.get(e)!==o||o._viewRevision!==m||(b&&Object.assign(o,n),delete o._requestedView,this._invalidate())};if(!c)f(!0);else{let b=c.then(f).finally(()=>this._derived.delete(b));this._derived.add(b)}})}set_display(e,i){return this.set_view(e,{display:i,...i==="flat"||i==="smooth"?{smooth_shading:i==="smooth"}:{}})}set_smooth(e,i){return this._guard(()=>{let o=this._model(e),s=o._requestedView||o;return this.set_view(e,{display:s.display==="smooth"?"flat":s.display,smooth_shading:i})})}set_section(e,i){return this._guard(()=>{this._model(e).section=xt(i),this._invalidate()})}set_color(e,i){return this._guard(()=>{i!==null&&i!=="transparent"&&Z(i);let o=this._model(e);o.color=i,this._invalidate()})}set_opacity(e,i){return this._guard(()=>{if($(i,"opacity"),i<0||i>1)throw new Error("Opacity must be between 0 and 1");this._model(e).opacity=i,this._invalidate()})}set_position(e,i,o,s){return this._guard(()=>{let n=this._model(e);[i,o,s].forEach(r=>{r!==void 0&&$(r,"position")}),this._stopAnimation(n,"manual"),[i,o,s].forEach((r,d)=>{r!==void 0&&(n[["x","y","z"][d]]=$(r,"position"))}),this._invalidate()})}set_scale(e,i,o=i,s=i,n=!1){return this._guard(()=>{let r=this._model(e);if([i,o,s].forEach(d=>Te(d,"scale")),n){if(i/r.scalex!==o/r.scaley||i/r.scalex!==s/r.scalez)throw new Error("keep_prev_scale requires a uniform geometry factor");this._stopAnimation(r,"manual"),r.unitScale*=i/r.scalex}else this._stopAnimation(r,"manual"),[r.scalex,r.scaley,r.scalez]=[i,o,s];r._stats=null,this._invalidate()})}set_selection(e){return this._guard(()=>{this.renderer?.setSelection(e===null?null:this._model(e)),this._invalidate()})}set_rotation(e,i,o,s,n=!1){return this._guard(()=>{let r=this._model(e);[i,o,s].forEach(d=>{d!==void 0&&$(d,"rotation")}),this._stopAnimation(r,"manual"),[i,o,s].forEach((d,l)=>{let c=["rotationx","rotationy","rotationz"][l];d!==void 0&&(r[c]=$(d,"rotation")+(n?r[c]:0))}),this._invalidate()})}rotate(e,i,o,s){return this.set_rotation(e,i,o,s,!0)}set_edges(e,i){return this._guard(()=>{let o=this._model(e);o.view_edges=!!i,i&&o.geometry&&!o.geometry.edges&&this._derive(o,{edges:!0}),this._invalidate()})}set_grid(e,i,o=10){return this._guard(()=>{if(this._gridAuto=!!e&&i===void 0,!e)this.grid=null,this.renderer?.setGrid(null);else{let s=this._bounds();if(i??=s&&Math.max(...H(s.max,s.min))*1.2||10,Te(i,"grid size"),!Number.isInteger(o)||o<1||o>1e3)throw new Error("Grid divisions must be 1\u20131000");this.grid={size:i,divisions:o},this.renderer?.setGrid(this.grid)}this._invalidate()})}set_infinite_grid(e,i=1,o=0){return this._guard(()=>{Te(i,"grid spacing"),$(o,"grid height"),this._gridAuto=!1,this.grid=e?{infinite:!0,spacing:i,height:o}:null,this.renderer?.setGrid(this.grid),this._invalidate()})}set_model_units(e,i,o=!1){return this._guard(()=>{if(!["mm","inch"].includes(i))throw new Error("Units must be mm or inch");let s=this._model(e);this._stopAnimation(s,"manual"),o&&s.units!==i&&(s.unitScale*=i==="inch"?25.4:1/25.4),s.units=i,s._stats=null,this._invalidate()})}set_bg_color(e){return this._guard(()=>{e!=="transparent"&&Z(e),this.bg_color=e,this._invalidate()})}set_center_models(e){this.center_models=!!e}set_zoom(e=-1){return this._guard(()=>{if($(e,"zoom"),e===-1)this.zoom=-1,this.set_auto_zoom();else{if(e<0)throw new Error("Zoom must be non-negative or -1");this.zoom=e,this.camera.position[2]=Math.max(e,1e-6),this._invalidate()}})}set_auto_zoom(){let e=this._bounds();if(!e)return;this.zoom=-1;let i=(this.canvas?.clientWidth||1)/(this.canvas?.clientHeight||1),o=Math.min(Math.PI/8,Math.atan(Math.tan(Math.PI/8)*i)),s=Y(H(this.camera.position,this.camera.target));this.camera.target=e.center,this.camera.position=ce(e.center,ae(Math.hypot(...s)?s:[0,0,1],e.radius/Math.sin(o)*1.08)),this._invalidate()}set_auto_rotate(e){this.auto_rotate=!!e,this._invalidate()}set_mouse_zoom(e){this.mouse_zoom=!!e,this.controls&&(this.controls.noZoom=!e)}set_auto_resize(e){this.auto_resize=!!e,this._resizeObserver?.disconnect(),this._windowResize&&window.removeEventListener("resize",this._windowResize),!(!e||!this.canvas)&&(typeof ResizeObserver<"u"&&(this._resizeObserver=new ResizeObserver(()=>this.do_resize()),this._resizeObserver.observe(this.parent_element)),this._windowResize=()=>this.do_resize(),window.addEventListener("resize",this._windowResize))}do_resize(){if(!this.renderer||this.killsign)return;let e=this.canvas.getBoundingClientRect();this.renderer.resize(e.width||this.parent_element.clientWidth||300,e.height||this.parent_element.clientHeight||150,this.options.pixel_ratio??Math.min(globalThis.devicePixelRatio||1,2)),this._invalidate()}set_on_model_mousedown(e){this.onmousedown_callback=e}set_on_model_mouseclick(e){this.set_on_model_mousedown(e)}set_drag_and_drop(e){this.allow_drag_and_drop=!!e,this.canvas&&(this.canvas.removeEventListener("drop",this._drop),this.canvas.removeEventListener("dragover",this._drag),e&&(this.canvas.addEventListener("drop",this._drop),this.canvas.addEventListener("dragover",this._drag)))}get_camera_state(){return{position:Ct(this.camera.position),up:Ct(this.camera.up),target:Ct(this.camera.target)}}set_camera_state(e){return this._guard(()=>{let i=e.position?ri(e.position,"position"):this.camera.position,o=e.up?ri(e.up,"up"):this.camera.up,s=e.target?ri(e.target,"target"):this.camera.target;if(!Math.hypot(...o)||!Math.hypot(...H(i,s)))throw new Error("Degenerate camera state");this.camera.position=i,this.camera.up=Y(o),this.camera.target=s,this._invalidate()})}set_camera(e,i,o){return this.set_camera_state({position:{x:e??this.camera.position[0],y:i??this.camera.position[1],z:o??this.camera.position[2]}})}pick_model(e,i){if(!this.ready||this.killsign||!Number.isFinite(e)||!Number.isFinite(i))return null;let o=this.canvas.getBoundingClientRect();if(!o.width||!o.height||e<o.left||e>o.right||i<o.top||i>o.bottom)return null;let s=ke(ht(this.camera,o.width/o.height)),n=Q(s,[(e-o.left)/o.width*2-1,1-(i-o.top)/o.height*2,1]),r=Y(H(n,this.camera.position)),d=null,l=1/0;for(let c of this._models.values())if(c.geometry&&c.opacity>0&&c.color!=="transparent"){let m=ke(J(c)),f=eo(c.geometry,Q(m,this.camera.position),Q(m,r,0),kt(c.geometry.bounds,c.section));f<l&&(l=f,d=c.id)}return d===null?null:{id:d,distance:l}}_pick(e,i){if(!this.onmousedown_callback)return;let o=this.pick_model(e.clientX,e.clientY);(o||this.send_no_model_click_event)&&this._callback("onmousedown_callback",o?.id??null,e,o?.distance??0,i)}get_model_size(e){return Ee(this._model(e))}resize_model(e,i){return bt.call(this,e,i)}set_file_units(e,i){return Yi.call(this,e,i)}reset_model_size(e){return Ji.call(this,e)}duplicate_model(e){return Xi.call(this,e)}set_camera_view(e){return Ki.call(this,e)}set_display_units(e){this.display_units=Pe(e)}get_camera_bookmarks(){return structuredClone(this.camera_bookmarks||[])}set_camera_bookmarks(e){this.camera_bookmarks=Re(e)}measure_model(e,i){return Zi.call(this,e,i)}get_model_info(e,i={}){return this._guard(()=>{let o=this._model(e),s=o.geometry;if(!s)return null;let n=o.scaleVector,r=n.join(",");i.measurements!==!1&&(!o._stats||o._stats.key!==r)&&(o._stats={key:r,...to(s,n)});let d=o.units==="inch"?1/25.4:1;return{name:o.filename,orig_filename:o.orig_filename??null,position:{x:o.x,y:o.y,z:o.z},dims:Ct(s.bounds.min.map((l,c)=>(s.bounds.max[c]-l)*n[c])),rotation:{x:o.rotationx,y:o.rotationy,z:o.rotationz},display:o.display,smooth_shading:o.smooth_shading,section:o.section?{...o.section}:null,color:o.color??(s.colors?"#ffffff":"#909090"),scale:{x:o.scalex,y:o.scaley,z:o.scalez},volume:i.measurements===!1?null:o._stats.volume*d**3,area:i.measurements===!1?null:o._stats.area*d**2,triangles:s.triangles,bounds:{min:[...s.bounds.min],max:[...s.bounds.max]},has_colors:!!s.colors,source_units:s.units||null,units:o.units,opacity:o.opacity,file_bytes:s.file_bytes??null}})}get_model_data(e){return this._guard(()=>{let i=this._model(e);return i.geometry?{positions:i.geometry.positions.slice(),colors:i.geometry.colors?.slice()??null}:null})}get_model_mesh(e){return this._guard(()=>{let i=this._model(e);return i.geometry?_o(i,this.options.three??globalThis.THREE):null})}get_stl_bin(e){return this._guard(()=>{let i=this._model(e);return i.geometry?Qt(i.geometry,i.scaleVector,i.center):null})}check_printability(e={}){return co.call(this,e)}is_printability_current(e){return It(this,e)}show_printability(e,i){return mo.call(this,e,i)}clear_printability(){this.renderer?.setDiagnostic(null),this._invalidate()}async export_models(e={}){let i=uo(e),o=e.signal,s=()=>{throw new DOMException("Export cancelled","AbortError")};if(o?.aborted&&s(),await this.when_ready,o?.aborted&&s(),this.killsign)throw new Error("Viewer disposed");let n=e.model_ids;if(n==="selected"){let _=this.renderer?.selection;n=_?[_.id]:[]}else n===void 0&&(n=[...this._models.keys()]);if(!Array.isArray(n)||n.some(_=>!Number.isSafeInteger(_))||new Set(n).size!==n.length)throw new Error("model_ids must be an array of unique model IDs or 'selected'");if(!n.length)throw new Error("No models to export");let r=n.map(_=>{let p=this._model(_);if(!p.geometry)throw new Error(`Model ${_} has not finished loading`);return p});if(r.reduce((_,p)=>_+p.geometry.triangles,0)>this.limits.max_triangles)throw new Error("Export triangle limit exceeded");let l=ho(r,i),c=this._occupiedMemory();X(this.limits,c+l,"export"),this._exportBytes=(this._exportBytes||0)+l;let m,f,b;try{let _=r.map(h=>{let w=i.apply_transforms?h:{...h,center:[0,0,0],x:0,y:0,z:0,rotationx:0,rotationy:0,rotationz:0,scaleVector:[1,1,1].map(()=>h.unitScale*(h.size_state?.unit_factor??1))},y=J(w),M=i.units==="inch"?1/25.4:1;for(let P=0;P<4;P++)for(let C=0;C<3;C++)y[P*4+C]*=M;return{id:h.id,name:Rt(h.filename),matrix:y,positions:h.geometry.positions.slice(),colors:i.colors?h.geometry.colors?.slice():null,color:i.colors&&h.color&&h.color!=="transparent"?Z(h.color):null,opacity:h.color==="transparent"?0:h.opacity}}),p=_.flatMap(h=>[h.positions.buffer,...h.colors?[h.colors.buffer]:[]]);m=this._pool.run({kind:"export",models:_,options:i,limits:{...this.limits,max_memory_bytes:this.limits.max_memory_bytes-c}},h=>{try{e.on_progress?.(h)}catch(w){b=w,m.cancel()}},p),f=()=>m.cancel(),o?.addEventListener("abort",f,{once:!0}),o?.aborted&&f();try{return await m}catch(h){throw b||h}}finally{f&&o?.removeEventListener("abort",f),this._exportBytes-=l}}async download_models(e={}){let i=await this.export_models(e);if(e.signal?.aborted)throw new DOMException("Export cancelled","AbortError");return $e(i.blob,i.filename),i}download_model(e,i){let o=this.get_stl_bin(e);o&&$e(new Blob([o],{type:"model/stl"}),i??this._model(e).filename??"model.stl")}async export_scene(e={}){let i=String(e.format||"").toLowerCase();if(!["vsb","vsj"].includes(i))throw new Error("Scene format must be vsb or vsj");if(e.force_basename!==void 0&&typeof e.force_basename!="boolean")throw new Error("force_basename must be a boolean");if(e.on_progress!==void 0&&typeof e.on_progress!="function")throw new Error("on_progress must be a function");let o=e.signal,s=()=>{if(o?.aborted)throw new DOMException("Export cancelled","AbortError")};if(s(),await this.when_ready,s(),this.killsign)throw new Error("Viewer disposed");if(this._pending.size||this._sceneLoads.size)throw new Error("Wait for models to finish opening before saving the scene");let n=[...this._models.values()];if(!n.length)throw new Error("No models to export");if(n.some(p=>!p.geometry))throw new Error("A model has not finished loading");if(n.length+(i==="vsb"?1:0)>this.limits.max_archive_entries)throw new Error("Scene model count limit exceeded");let r=n.reduce((p,h)=>p+h.geometry.triangles,0);if(r>this.limits.max_triangles)throw new Error("Scene triangle limit exceeded");let d=this.get_vsj(!0,!!e.force_basename,i==="vsb"),l=JSON.stringify(d),c=new Blob([l]).size;if(c>this.limits.max_file_bytes)throw new Error("Scene manifest size limit exceeded");if(i==="vsb"&&c+n.length*84+r*50>this.limits.max_uncompressed_bytes)throw new Error("Scene archive limit exceeded");let m=67108864+l.length*8+(i==="vsb"?r*512:0);X(this.limits,this._occupiedMemory()+m,"scene export"),this._exportBytes+=m;let f,b,_;try{let p=i==="vsb"?n.map((w,y)=>({id:w.id,triangles:w.geometry.triangles,positions:w.geometry.positions.slice(),colors:w.geometry.colors?.slice()||null,scale:d.models[y].animation_state?[1,1,1]:w.scaleVector,center:d.models[y].animation_state?[0,0,0]:[...w.center]})):null;e.on_progress?.({loaded:0,total:n.length,phase:"exporting"}),s();let h;if(i==="vsj")h=new Blob([l],{type:"application/json"}),e.on_progress?.({loaded:n.length,total:n.length,phase:"complete"});else{f=this._pool.run({kind:"export-scene",scene:d,models:p,limits:this.limits},w=>{try{e.on_progress?.(w)}catch(y){_=y,f.cancel()}},p.flatMap(w=>[w.positions.buffer,...w.colors?[w.colors.buffer]:[]])),b=()=>f.cancel(),o?.addEventListener("abort",b,{once:!0}),o?.aborted&&b();try{h=await f}catch(w){throw _||w}}return s(),{blob:h,format:i,filename:oi(e.filename,i),model_ids:n.map(w=>w.id),triangles:r,representation:"scene"}}finally{b&&o?.removeEventListener("abort",b),this._exportBytes-=m}}async download_scene(e={}){let i=await this.export_scene(e);if(e.signal?.aborted||this.killsign)throw new DOMException("Export cancelled","AbortError");return $e(i.blob,i.filename),i}get_vsj(e=!1,i=!1,o=!1){let s={canvas_height:this.canvas_height,bg_color:this.bg_color,camera_state:this.get_camera_state(),camera_bookmarks:this.get_camera_bookmarks(),display_units:this.display_units||"mm",auto_rotate:this.auto_rotate,mouse_zoom:this.mouse_zoom,auto_resize:this.auto_resize,center_models:this.center_models,models:[]};this.grid&&(s.grid=!0,this.grid.infinite&&(s.infinite_grid={spacing:this.grid.spacing,height:this.grid.height}));for(let n of this._models.values())if(n.geometry){let r={id:o?-1:n.id,filename:o?`${n.id}.stl`:i?Rt(n.filename):n.filename,units:n.units,size_state:{...structuredClone(Le(n)),unit_factor:o&&!n._animation?1:n.unitScale*(Le(n).unit_factor??1)},...n.display_name?{display_name:n.display_name}:{},display:n.display,opacity:n.opacity,view_edges:n.view_edges,smooth_shading:n.smooth_shading,section:n.section?{...n.section}:null};o&&(r.orig_filename=Rt(n.orig_filename||n.filename));for(let l of ni)l.startsWith("scale")||(r[l]=n[l]);(!o||n._animation)&&(r.scalex=n.scalex*n.unitScale,r.scaley=n.scaley*n.unitScale,r.scalez=n.scalez*n.unitScale),n.color&&(r.color=n.color);let d=gt(n);if(d)Object.assign(r,d);else if(!o){let l=this.center_models?n.geometry.bounds.min.map((m,f)=>(m+n.geometry.bounds.max[f])/2):[0,0,0],c=Q(J(n),l);["x","y","z"].forEach((m,f)=>r[m]=c[f])}s.models.push(r)}return e?s:JSON.stringify(s)}download_vsj(e="1.vsj"){$e(new Blob([this.get_vsj()],{type:"application/json"}),e)}get_vsb(){return{vsj:this.get_vsj(!0,!0,!0),files:[...this._models.values()].filter(e=>e.geometry).map(e=>({id:e.id,bin:e._animation?Qt(e.geometry,[1,1,1],[0,0,0]):this.get_stl_bin(e.id)}))}}async get_vsb_blob(){await this.when_ready;let e=this.get_vsb(),i=this._pool.run({kind:"zip",scene:e,limits:this.limits},null,e.files.map(o=>o.bin));return new Blob([await i],{type:"application/octet-stream"})}download_vsb(e="1.vsb"){return this.get_vsb_blob().then(i=>$e(i,/\.vsb$/i.test(e)?e:`${e}.vsb`)).catch(i=>this._error(i))}import_scene(e,i={}){return lo.call(this,e,i)}_sceneLoad(e,i){let o=this._generation;this._sessionActive=!0;let s=(async()=>{if(await this.when_ready,o!==this._generation||this.killsign)return;let n,r,d=document.baseURI;if(typeof e=="string"&&(d=new URL(e,document.baseURI).href),i){if(r=await this._pool.run({kind:"unzip",source:typeof e=="string"?d:e,limits:this.limits}),!Object.hasOwn(r,"json_data.vsj"))throw new Error("VSB manifest json_data.vsj is missing");n=JSON.parse(new TextDecoder().decode(r["json_data.vsj"]))}else{let f=new AbortController;this._aborters.add(f);try{n=JSON.parse(new TextDecoder().decode(await fo(typeof e=="string"?d:e,this.limits.max_file_bytes,()=>{},f.signal)))}finally{this._aborters.delete(f)}}if(o!==this._generation||this.killsign)return;if(!n||!Array.isArray(n.models)||n.models.length>this.limits.max_archive_entries)throw new Error("Invalid or oversized scene manifest");n.bg_color!==void 0&&this.set_bg_color(n.bg_color),n.center_models!==void 0&&this.set_center_models(n.center_models),n.auto_rotate!==void 0&&this.set_auto_rotate(n.auto_rotate),n.mouse_zoom!==void 0&&this.set_mouse_zoom(n.mouse_zoom),n.auto_resize!==void 0&&this.set_auto_resize(n.auto_resize),n.canvas_height!==void 0&&(this.canvas_height=n.canvas_height,this._setSizeStyle(),this.do_resize()),n.infinite_grid?this.set_infinite_grid(!0,n.infinite_grid.spacing,n.infinite_grid.height):n.grid&&this.set_grid(!0),n.camera_state&&(this._restoreCamera=n.camera_state);let l=vt(this.get_camera_bookmarks(),n.camera_bookmarks||[]),c=Pe(n.display_units||this.display_units||"mm"),m=[];try{for(let f of n.models){if(!f||typeof f!="object")throw new Error("Invalid scene model");let b=go(f);if(delete b.mesh,delete b.data,delete b.local_file,r){if(typeof b.filename!="string"||!Object.hasOwn(r,b.filename))throw new Error("VSB model file is missing");b.local_file=new File([r[b.filename]],b.filename)}else b.filename&&(b.filename=new URL(b.filename,d).href);let _=b.id===void 0||b.id===-1?this.max_model_id+1:b.id;if(this._models.has(_))throw new Error(`Invalid or duplicate model id: ${_}`);this.add_model({...b,id:_,animation:null,animation_state:null});let p=this._models.get(_);if(!p)throw new Error(this.error||"Invalid scene model");p._sceneImportPending=!0,m.push({m:p,model:b,pending:this._pending.get(_)})}if(await Promise.all(m.map(f=>f.pending)),o!==this._generation||this.killsign)return;for(let{m:f,model:b}of m){if(this._models.get(f.id)!==f||!f.geometry)throw new Error("A scene model could not be opened");if(b.animation)Xe(b.animation,f,b.animation_state);else if(b.animation_state)throw new Error("Playback state needs an animation")}for(let{m:f,model:b}of m)b.animation&&this._startAnimation(f,b.animation,b.animation_state),f._sceneImportPending=!1;this.camera_bookmarks=l,this.display_units=c}catch(f){for(let{m:b}of m)this._models.get(b.id)===b&&this.remove_model(b.id);throw f}})().catch(n=>{o===this._generation&&n.name!=="AbortError"&&this._error(n)}).finally(()=>{this._sceneLoads.delete(s),this._finishSession()});this._sceneLoads.add(s)}load_vsj(e){return this._sceneLoad(e,!1)}load_vsb(e){return this._sceneLoad(e,!0)}animate_model(e,i){return this._guard(()=>{let o=this._model(e);if(!i){this._stopAnimation(o,"stopped"),this._invalidate();return}this._startAnimation(o,i),this._invalidate()})}_startAnimation(e,i,o){let s=Xe(i,e,o);e._animation&&this._stopAnimation(e,"replaced"),o&&(e.center=[...o.center]),e.animation=s.animation,e._animation=s,delete e.animation_state,e._animationResult=null,_t(s,e)?this._animationEvent(e,o?"restored":"started"):this._completeAnimation(e)}_animationEvent(e,i){let o=this._animationState(e);queueMicrotask(()=>{this._callback("animation_state_callback",e.id,o,i),i==="completed"&&this._callback("animation_complete_callback",e.id,o)})}_animationState(e){return e._animation?qi(e._animation,!!this._animationSuspended):{...e._animationResult??{status:"idle",elapsed_ms:0},suspended:!1,tracks:[]}}_stopAnimation(e,i){!e._animation&&!e.animation||(e._animationResult={status:"stopped",elapsed_ms:e._animation?.elapsed_ms??0},e._animation=null,e.animation=null,delete e.animation_state,this._animationEvent(e,i))}_completeAnimation(e){e._animationResult={status:"completed",elapsed_ms:e._animation.elapsed_ms},e._animation=null,e.animation=null,this._animationEvent(e,"completed")}pause_model_animation(e){return this._guard(()=>{let i=this._model(e);!i._animation||i._animation.paused||(i._animation.paused=!0,i._animation.last_time=null,this._animationEvent(i,"paused"),this._invalidate())})}resume_model_animation(e){return this._guard(()=>{let i=this._model(e);!i._animation||!i._animation.paused||(i._animation.paused=!1,i._animation.last_time=null,this._animationEvent(i,"resumed"),this._invalidate())})}get_model_animation_state(e){return this._guard(()=>this._animationState(this._model(e)))}_suspendAnimations(e){this._animationSuspended=!!e,this._lastTime=0;for(let i of this._models.values())i._animation&&(i._animation.last_time=null);e?(cancelAnimationFrame(this._frame),this._frame=0):this._invalidate()}_animate(e,i){if(!(this._animationSuspended||!e._animation))try{Gi(e._animation,e,i)||this._completeAnimation(e)}catch(o){this._stopAnimation(e,"error"),this._error(o)}}async get_image_blob(e="image/png"){await this.when_idle(),this._clip(),this.renderer.draw([...this._models.values()],this.camera,this.bg_color,!1);let i=new Promise((o,s)=>this.canvas.toBlob(n=>n?o(n):s(new Error("Screenshot failed")),e));return this._invalidate(),i}};var si=new WeakMap,Bo=["background-color","background-value","cancel-load","clear-scene","close-colors","close-info","close-model","close-scene","close-section","close-view","color-mode-note","colors-button","colors-panel","depth-controls","depth-model-button","dismiss-notice","drop-message","drop-overlay","empty-state","file-heading","file-input","filename","finish-move","fit-button","grid-button","image-button","info-button","info-dimensions","info-panel","info-size","info-triangles","live-status","loading-label","loading-state","memory-budget","model-color","model-color-value","model-controls","model-list","model-tool","move-controls","move-gesture-message","move-mode","move-mode-name","move-model-button","notice","notice-message","open-label","position-details","position-error","position-units","position-x","position-y","position-z","reset-position","reset-rotation","restore-color","rotate-controls","rotate-model-button","rotation-error","rotation-x","rotation-y","rotation-z","sample-button","scene-arrangement","scene-button","scene-count","scene-panel","section-axis","section-button","section-enabled","section-flip","section-panel","section-position","section-value","smooth-shading","unit-note","view-button","view-description","view-label","view-panel","view-status","viewer","workspace"];function yo(t,e={}){if(!t?.querySelectorAll)throw new TypeError("A Document or HTMLElement root is required");if(si.has(t))throw new Error("ViewSTL app is already mounted on this root");let i=t.ownerDocument||t,o=i.defaultView,s=o.URL,n=new Map([...t.querySelectorAll("[id]")].map(a=>[a.id,a])),r=a=>n.get((e.id_prefix||"")+a),d=Bo.filter(a=>!r(a));if(ei.some(a=>r(a))&&d.push(...ei.filter(a=>!r(a))),ti.some(a=>r(a))&&d.push(...ti.filter(a=>!r(a))),ii.some(a=>r(a))&&d.push(...ii.filter(a=>!r(a))),Vt.some(a=>r(a))&&d.push(...Vt.filter(a=>!r(a))),d.length)throw new Error("Missing ViewSTL controls: "+d.join(", "));let l=new o.AbortController,c=t===i?o:t,m=!1,f=null,b=null,_=()=>{if(m)throw new Error("ViewSTL app is disposed")},p=(a,u,x,z={})=>a.addEventListener(u,x,{...z,signal:l.signal}),h=zi(o.navigator.deviceMemory),w=["view","section","info","scene","colors"],y=new Map,M=[],P=["#64a5b2","#dd766b","#edb14c","#7ca984","#927fbc","#5a8ec7","#89949d"],C,v,R=0,k=0,g=null,A=0,I=null,E,L,T,D,S,N=!1,F=!1,j=!1,ve=0,Fe=1,K=!1,U=!1,W=null,ee="move",Ae,ai,we="transparent",li={flat:"Solid",edges:"Solid + edges",wireframe:"Wireframe",xray:"X-ray",mesh:"Mesh overlay",studio:"Studio",orientation:"Face orientation"},Se=[...t.querySelectorAll('[name="view-mode"]')],Pt=[...t.querySelectorAll("[data-viewstl-shortcut]")];e.id_prefix&&Se.forEach(a=>a.name=e.id_prefix+"view-mode");let Lt=e.sample_url,et=new Intl.NumberFormat(void 0,{maximumFractionDigits:2});function B(a){m||(r("live-status").textContent=a)}function me(a){m||(r("notice-message").textContent=a,r("notice").hidden=!1)}function Ie(){v?.set_selection(!F&&y.has(g)&&(U||K||!r("scene-panel").hidden)?g:null)}function ci(){for(let a of Pt){let u=a.dataset.viewstlShortcut;a.disabled=F||!y.size||u==="save"&&!E,u==="select"&&a.setAttribute("aria-pressed",String(U))}}function xe(a){a&&G(!1),U=!!a&&!F&&y.size>0,W=null,v&&(v.controls.enabled=!U,v.canvas.setAttribute("aria-label",U?"Select a model with a click. Escape returns to viewing.":"3D model viewer. Drag to rotate, shift-drag to pan, scroll to zoom.")),r("workspace").classList.toggle("selecting-model-mode",U),ci(),Ie()}function di(a){let u=v.pick_model(a.clientX,a.clientY);!u||!y.has(u.id)||(a.preventDefault(),Oe(u.id),ne(),r("scene-panel").hidden=!1,r("scene-button").setAttribute("aria-expanded","true"),r("position-details").open=!0,Ie(),B(y.get(u.id).name+" selected. Choose Move, Rotate or Depth."))}function mi(a){r(a+"-panel").hidden=!0,r(a+"-button").setAttribute("aria-expanded","false"),Ie()}function ne(){w.forEach(mi)}function tt(a){let u=r(a+"-panel").hidden;ne(),r(a+"-panel").hidden=!u,r(a+"-button").setAttribute("aria-expanded",String(u)),Ie(),u&&a==="info"&&it(),u&&(a==="scene"||a==="view")&&D?.sync()}function Ne(a){return a==null?"Sample model":a<1024**2?`${et.format(a/1024)} KiB`:a<1024**3?`${et.format(a/1024**2)} MiB`:`${et.format(a/1024**3)} GiB`}function Tt(){let a=y.get(g),u=/^#[a-f0-9]{6}$/i.test(a?.color)?a.color:"#ffffff";r("model-color").value=u,r("model-color-value").textContent=a?.color===null?"File colors":u.toUpperCase(),r("restore-color").textContent=a?.embedded?"Restore file colors":"Restore original color",t.querySelectorAll("[data-model-color]").forEach(x=>x.setAttribute("aria-pressed",String(x.dataset.modelColor===a?.color))),t.querySelectorAll("[data-background]").forEach(x=>x.setAttribute("aria-pressed",String(x.dataset.background===we))),r("background-color").value=we==="transparent"?"#fafbfb":we,r("background-value").textContent=we==="transparent"?"Default":we.toUpperCase()}function ui(){ie(y.get(g),v?._models.get(g));let a=g===null?null:v.get_model_info(g,{measurements:!1}),u=a?.display==="smooth"?"flat":a?.display||"flat";for(let O of Se)O.checked=O.value===u,O.disabled=F;r("view-label").textContent=D?"View":li[u],r("view-button").title="View \xB7 "+li[u],r("smooth-shading").checked=a?.smooth_shading||!1,r("smooth-shading").disabled=F||u==="wireframe",r("view-status").textContent=u==="wireframe"?"Smooth shading is available in surface views.":"Shading changes the appearance, not the geometry.";let x=u==="orientation"?"Blue: front faces \xB7 Red: back faces":"";r("view-description").textContent=x,r("view-description").hidden=!x,r("color-mode-note").hidden=u!=="orientation";let z=a?.section;r("section-enabled").checked=!!z,r("section-axis").value=z?.axis||"z",r("section-position").value=(z?.position??.5)*100,r("section-value").textContent=r("section-position").value+"%",r("section-flip").setAttribute("aria-pressed",String(z?.flip||!1)),r("section-button").setAttribute("aria-pressed",String(!!z)),t.querySelectorAll("[data-selected-name]").forEach(O=>O.textContent=y.get(g)?.name||""),Tt(),rt(),E?.sync(),L?.sync(),T?.sync(),D?.sync(),ci()}function it(){if(g===null)return;let a=v.get_model_info(g,{measurements:!1}),u=y.get(g),x=v.display_units==="inch"?25.4:1;r("info-triangles").textContent=a.triangles.toLocaleString(),r("info-dimensions").textContent=[a.dims.x,a.dims.y,a.dims.z].map(O=>et.format(O/x)).join(" \xD7 ")+(x===1?" mm":" in"),r("info-size").textContent=Ne(u.size);let z=v.get_model_size(g);r("unit-note").textContent=z.editable?"File coordinates interpreted as "+(z.file_units==="inch"?"inches.":"millimetres (assumed).")+" Change file units in Models \u2192 Size & units.":"Explicit file units were converted to millimetres on import.",D?.syncInfo()}function hi(){r("model-list").replaceChildren(...[...y.values()].map(a=>{let u=i.createElement("li"),x=i.createElement("button"),z=i.createElement("button"),O=i.createElement("button");return u.className="model-row",u.classList.toggle("selected",a.id===g),x.className="model-swatch",x.dataset.colorModel=a.id,x.style.backgroundColor=a.color||"#b7c5c9",x.setAttribute("aria-label","Color for "+a.name),x.title="Change color",z.className="model-pick",z.dataset.selectModel=a.id,z.textContent=a.name,z.title=a.name,z.setAttribute("aria-pressed",String(a.id===g)),O.className="icon-button",O.dataset.removeModel=a.id,O.textContent="\xD7",O.setAttribute("aria-label","Remove "+a.name),u.append(x,z,O),u})),r("scene-count").textContent=y.size,r("scene-arrangement").disabled=y.size===0}function _e(){let a=y.size>0;!a&&U&&xe(!1),r("workspace").classList.toggle("has-models",a),r("viewer").hidden=!a&&!F,r("empty-state").hidden=a||F,r("file-heading").hidden=!a,r("model-controls").hidden=!a,r("filename").textContent=y.get(g)?.name||"",r("filename").title=r("filename").textContent,r("open-label").textContent=a?"Add models":"Open files",r("drop-message").textContent=a?"Add to your scene.":"Drop it here.",hi(),ui(),it(),a||ne(),Ie()}function ot(a){a&&E?.close(),!m&&(a&&U&&xe(!1),a&&G(!1),F=a,r("loading-state").hidden=!a,r("workspace").setAttribute("aria-busy",String(a)),_e())}function Oe(a){E?.close(),y.has(a)&&(G(!1),k++,g=a,_e())}function bo(){return Ni([...y.values()],r("scene-arrangement").value)}function nt(){v?.set_infinite_grid(j,Fe,ve),r("grid-button").setAttribute("aria-pressed",String(j))}function Ft(){G(!1);for(let u of y.values())ie(u,v?._models.get(u.id));if(r("scene-arrangement").value==="custom")return;for(let u of y.values())re(u.id);if(r("scene-arrangement").value==="original")for(let u of y.values())u.rotation={...u.originalRotation||{x:0,y:0,z:0}};let a=bo();for(let u of a)y.get(u.id).position={x:u.x,y:u.y,z:u.z},Nt(y.get(u.id));(r("scene-arrangement").value!=="custom"||!y.size)&&(ve=Oi([...y.values()],a)),rt(),nt(),v?.set_auto_zoom()}function rt(a=!1){let u=y.get(g);for(let x of["x","y","z"]){let z=r("position-"+x);(!a||i.activeElement!==z)&&(z.value=Number((u?.position?.[x]||0).toPrecision(12))),z.disabled=!u,z.removeAttribute("aria-invalid")}r("position-error").hidden=!0,r("position-units").textContent=u?.animationPivot?"Position of the model center in the scene, in mm.":"Offset from file coordinates, in mm.",r("move-model-button").disabled=!u||F,r("reset-position").disabled=!u,pi(a);for(let x of["rotate-model-button","depth-model-button","depth-nearer","depth-farther"])r(x).disabled=!u||F}function De(a,u,x=!0){return!y.has(a)||!Object.values(u).every(z=>Number.isFinite(z)&&Math.abs(z)<=1e12)?!1:(y.get(a).position={...u},Nt(y.get(a)),r("scene-arrangement").value="custom",a===g&&x&&rt(),!0)}function Nt(a){let u=Ge(a),x=a.rotation;v.set_rotation(a.id,...["x","y","z"].map(z=>x[z]%360*Math.PI/180)),v.set_position(a.id,u.x,u.y,u.z)}function fi(){re(g);let a=y.get(g);return a?{...a,center:Li(a),radius:Ti(a)}:null}function pi(a=!1){let u=y.get(g);for(let x of["x","y","z"]){let z=r("rotation-"+x);(!a||i.activeElement!==z)&&(z.value=Number((u?.rotation?.[x]||0).toPrecision(10))),z.disabled=!u,z.removeAttribute("aria-invalid")}r("rotation-error").hidden=!0,r("reset-rotation").disabled=!u}function st(a,u,x=!0){return!y.has(a)||!Object.values(u).every(z=>Number.isFinite(z)&&Math.abs(z)<=36e4)?!1:(y.get(a).rotation={...u},Nt(y.get(a)),r("scene-arrangement").value="custom",x&&a===g&&pi(),!0)}let vo={move:"Move",rotate:"Rotate",depth:"Depth"},_i={move:"Drag to move the selected model",rotate:"Drag to rotate the selected model",depth:"Drag up for nearer, down for farther"};function wo(){v?.canvas&&(v.canvas.dataset.modelTool=ee),t.querySelectorAll("[data-transform-tab]").forEach(a=>a.setAttribute("aria-pressed",String(a.dataset.transformTab===ee)));for(let a of["move","rotate","depth"])r(a+"-controls").hidden=a!==ee,r(a+"-model-button").setAttribute("aria-pressed",String(K&&a===ee));r("model-tool").value=ee,r("move-gesture-message").textContent=_i[ee]+" \xB7 Scroll to adjust depth"}function G(a,u=ee,x=!1){a&&U&&xe(!1),Ae?.setEnabled(!1),ee=u,K=!!a&&g!==null&&!F,K&&!x&&re(g),Ae?.setEnabled(K),wo(),r("move-mode").hidden=!K,r("move-mode-name").textContent=y.get(g)?.name||"",r("workspace").classList.toggle("moving-model-mode",K),v?.canvas&&v.canvas.setAttribute("aria-label",K?_i[ee]+". Scroll changes only its depth. Escape exits.":U?"Select a model with a click. Escape returns to viewing.":"3D model viewer. Drag to rotate, shift-drag to pan, scroll to zoom."),K&&(ne(),v.canvas.focus({preventScroll:!0}),B(vo[ee]+" tool for "+y.get(g).name+". Done or Escape returns to viewing.")),Ie()}for(let a of["x","y","z"]){let u=r("rotation-"+a);p(u,"input",()=>{g===null||!u.value.trim()||(re(g),st(g,{...y.get(g).rotation,[a]:u.valueAsNumber},!1)&&(u.removeAttribute("aria-invalid"),r("rotation-error").hidden=!0))}),p(u,"change",()=>{g!==null&&(re(g),!u.value.trim()||!st(g,{...y.get(g).rotation,[a]:u.valueAsNumber})?(u.setAttribute("aria-invalid","true"),r("rotation-error").hidden=!1):B("Model rotation updated."))})}p(r("reset-rotation"),"click",()=>{G(!1),g!==null&&(re(g),st(g,{...y.get(g).originalRotation||{x:0,y:0,z:0}}),B("Selected model rotation reset."))});for(let a of["move","rotate","depth"])p(r(a+"-model-button"),"click",()=>G(!K||ee!==a,a));for(let[a,u]of[["depth-nearer",-.12],["depth-farther",.12]])p(r(a),"click",()=>{let x=fi();x&&(De(x.id,qe(x,v.get_camera_state(),u)),B(u<0?"Selected model moved nearer.":"Selected model moved farther."))});t.querySelectorAll("[data-transform-tab]").forEach(a=>p(a,"click",()=>G(!1,a.dataset.transformTab))),p(r("model-tool"),"change",()=>G(!0,r("model-tool").value));for(let a of["x","y","z"]){let u=r("position-"+a);p(u,"input",()=>{g===null||!u.value.trim()||(re(g),De(g,{...y.get(g).position,[a]:u.valueAsNumber},!1)&&(u.removeAttribute("aria-invalid"),r("position-error").hidden=!0))}),p(u,"change",()=>{g!==null&&(re(g),!u.value.trim()||!De(g,{...y.get(g).position,[a]:u.valueAsNumber})?(u.setAttribute("aria-invalid","true"),r("position-error").hidden=!1):B("Model position updated."))})}p(r("finish-move"),"click",()=>{G(!1),v?.canvas.focus({preventScroll:!0})}),p(r("reset-position"),"click",()=>{G(!1),g!==null&&(re(g),De(g,{...y.get(g).originalPosition||{x:0,y:0,z:0}}),B("Selected model restored to its original position."))}),p(o,"blur",()=>{K&&G(!1)});function at(){R++,M.length=0,S?.abort(),I!==null&&(v?.remove_model(I),I=null),ot(!1),B("Opening cancelled.")}function gi(){E?.close(),G(!1),at(),k++,v?.clean(),y.clear(),g=null,j=!1,ve=0,Fe=1,r("scene-arrangement").value="original",nt(),r("notice").hidden=!0,_e(),B("Scene cleared.")}function Ot(a){if(!y.has(a))return;E?.close();let u=y.get(a).name;G(!1),v.remove_model(a),y.delete(a),k++,g===a&&(g=[...y.keys()].at(-1)??null),Ft(),_e(),B(u+" removed.")}function re(a){y.has(a)&&(ie(y.get(a),v?._models.get(a)),v?.animate_model(a,null))}function yi(){m||g===null||(ie(y.get(g),v?._models.get(g)),r("info-panel").hidden||it(),!r("scene-panel").hidden&&r("position-details").open&&rt(!0))}function xo(a,u,x){m||(x==="restored"&&u.status==="running"&&o.matchMedia?.("(prefers-reduced-motion: reduce)").matches&&v.pause_model_animation(a),ie(y.get(a),v?._models.get(a)),["started","restored","resumed"].includes(x)&&(r("scene-arrangement").value="custom"),a===g&&yi(),T?.sync(),L?.sync(),e.animation_state_callback?.(a,u,x))}async function bi(){return C||(C=Promise.resolve().then(async()=>{if(m)throw new Error("ViewSTL app is disposed");if(v=new ze(r("viewer"),{...h.limits,worker_count:1,worker_timeout:e.worker_timeout??6e5,worker_url:e.worker_url,worker_factory:e.worker_factory,url_import_endpoint:e.url_import_endpoint,center_models:!1,bg_color:we,allow_drag_and_drop:!1,animation_state_callback:xo,animation_complete_callback:(...a)=>{m||e.animation_complete_callback?.(...a)},camera_state:{position:{x:90,y:-130,z:90},target:{x:0,y:0,z:0},up:{x:0,y:0,z:1}},loading_progress_callback:a=>{if(m||!F||S)return;let u=a[I];r("loading-label").textContent=u?.phase==="loading-cad"?"Loading the CAD reader\u2026":u?.phase==="parsing-cad"?"Preparing CAD surfaces\u2026":u?.loaded&&!u.total?`Downloading your file\u2026 ${Ne(u.loaded)}`:u?.total&&u.loaded<u.total?`Reading your file\u2026 ${Math.min(99,Math.floor(100*u.loaded/u.total))}%`:"Preparing your model\u2026"},model_loaded_callback:a=>{b=a},load_error_callback:a=>{me(/limit exceeded|safety budget/i.test(a)?`This scene or view mode exceeds the estimated memory budget for this device (${Ne(h.budget)}). Remove a model, use Solid view without smoothing, or try a device with more memory.`:`Couldn\u2019t display this model. ${a}`)}}),await v.when_ready,m)throw new Error("ViewSTL app is disposed");Ae=ji(v.canvas,{getCamera:()=>v.get_camera_state(),getModel:fi,getTool:()=>ee,onRotate:(a,u)=>st(a,u),onMove:(a,u)=>De(a,u),onStart:()=>{ai=r("scene-arrangement").value},onEnd:(a,u)=>{u&&(r("scene-arrangement").value=ai),B(u?"Move cancelled.":"Model updated.")}}),p(v.canvas,"dblclick",a=>{F||U||a.button!==0||di(a)}),p(v.canvas,"pointerdown",a=>{!U||F||a.button!==0||!a.isPrimary||(W={id:a.pointerId,x:a.clientX,y:a.clientY,moved:!1},v.canvas.focus({preventScroll:!0}),v.canvas.setPointerCapture(a.pointerId),a.preventDefault())}),p(v.canvas,"pointermove",a=>{W?.id===a.pointerId&&Math.hypot(a.clientX-W.x,a.clientY-W.y)>6&&(W.moved=!0)}),p(v.canvas,"pointerup",a=>{let u=W;W=null,U&&!F&&u?.id===a.pointerId&&!u.moved&&di(a)});for(let a of["pointercancel","lostpointercapture"])p(v.canvas,a,()=>{W=null});return v}).catch(a=>{throw Ae?.dispose(),Ae=null,v?.dispose(),v=null,C=null,a})),C}function lt(a){_();let u=[];for(let z of a){if(!/\.(stl|obj|3mf|step|stp|iges|igs|vsb|vsj)$/i.test(z.name)){me("Choose STL, OBJ, 3MF, STEP/STP, IGES/IGS, VSB or VSJ files.");continue}if(z.size===0){me("This file is empty. Choose a file containing a 3D model.");continue}u.push(z)}let x=u.filter(z=>Me(z.name));if(x.length){let z={files:u.filter(O=>!Me(O.name)),used:new Set,failed:!1};for(let O of x)M.push({name:O.name,sceneFile:O,batch:z});M.push({remaining:z})}else M.push(...u);return M.length&&!N&&(f=vi()),f||Promise.resolve()}function Dt(a,u=""){if(_(),!e.url_import_endpoint)throw new Error("URL imports are not configured.");let x=new s(a.trim());if(!["https:","http:"].includes(x.protocol)||x.username||x.password)throw new Error("Use a public HTTP or HTTPS file URL without login credentials.");if(u&&!/^(stl|obj|3mf|step|stp|iges|igs|vsb|vsj)$/.test(u))throw new Error("Choose a supported 3D format.");x.hash="";let z=decodeURIComponent(x.pathname.split("/").at(-1)||"Remote model").slice(0,200);return M.push({name:z,remote:x.href,format:u,size:0,scene:["vsb","vsj"].includes(u)?u:Me(z)}),N||(f=vi()),f||Promise.resolve()}r("url-form")&&r("url-dialog")&&p(r("url-form"),"submit",a=>{a.preventDefault();try{let u=Dt(r("url-input").value,r("url-format").value);r("url-input").value="",r("url-error").hidden=!0,r("url-dialog").close(),u.catch(x=>me(x.message))}catch(u){r("url-error").textContent=u.message,r("url-error").hidden=!1}});async function vi(){if(!N){N=!0;try{for(;M.length;){let a=M.shift(),u=R;if(a.remaining){a.remaining.failed||M.unshift(...a.remaining.files.filter(x=>!a.remaining.used.has(x)));continue}ot(!0),r("notice").hidden=!0,r("loading-label").textContent="Opening "+a.name+"\u2026",B("Opening "+a.name);try{if(a.sceneFile||a.scene){await ko(a,u);continue}let x=await Ai(a);if(u!==R)continue;let z=[...y.values()].reduce((q,ye)=>q+ye.estimated,0);if(x+z>h.budget||a.size>h.limits.max_file_bytes)throw Error(`Adding this file would exceed the estimated ${Ne(h.budget)} scene memory budget. Remove a model or try a device with more memory.`);let O=await bi();if(u!==R)continue;O.do_resize(),A=Math.max(A,O.max_model_id+1);let oe=A++;if(I=oe,b=null,O.add_model({id:oe,display:"flat",...a.remote?{remote_url:a.remote,remote_format:a.format}:a.url?{filename:a.url}:{local_file:a}}),await O.when_idle(),u!==R)continue;I=null;let ue=b===oe?O.get_model_info(oe,{measurements:!1}):null;if(!ue){B(a.name+" could not be opened.");continue}a.remote&&(a.name=ue.name,a.size=ue.file_bytes,delete a.remote);let ge=ue.has_colors,V=ge?null:P[y.size%P.length];V&&O.set_color(oe,V),y.set(oe,{id:oe,name:a.name,size:a.size,units:ue.source_units||(/\.3mf$/i.test(a.name)?"mm":null),bounds:ue.bounds,position:{x:0,y:0,z:0},rotation:{x:0,y:0,z:0},embedded:ge,originalColor:V,color:V,estimated:ue.triangles*224,sourceFile:a instanceof o.File?a:null}),g=oe,k++,Ft(),_e(),B(a.name+" is ready."),O.canvas.focus({preventScroll:!0})}catch(x){a.batch&&(a.batch.failed=!0),u===R&&(I!==null&&(v?.remove_model(I),I=null),me(/WebGL/i.test(x.message)?"3D viewing needs WebGL 2. Try enabling hardware acceleration in your browser, or use another device.":x.message))}}}finally{N=!1,ot(!1)}}}async function ko(a,u){let x=await bi();if(u!==R)return;let z=new o.AbortController;S=z;try{let O=a.batch?.files||[],oe=[...new Set([...y.values()].map(V=>V.sourceFile).filter(Boolean))],ue=[...O,...a.sceneFile?oe.filter(V=>!O.some(q=>q.name===V.name)&&oe.filter(q=>q.name===V.name).length===1):[]],ge=await x.import_scene(a.sceneFile||a.remote,{format:a.scene||Me(a.name),signal:z.signal,files:ue,on_progress(V){u!==R||m||(r("loading-label").textContent=V.phase==="opening-model"?`Opening scene model ${V.loaded+1} of ${V.total}\u2026`:V.phase==="complete"?"Restoring scene\u2026":V.total?`Reading scene\u2026 ${Math.min(99,Math.floor(V.loaded/V.total*100))}%`:"Reading scene\u2026")}});if(u!==R)return;for(let V of ge.used_files)a.batch?.used.add(V);for(let V of ge.model_ids){let q=x._models.get(V),ye=q.geometry,Eo=Object.fromEntries(["min","max"].map(Ce=>[Ce,ye.bounds[Ce].map((zo,ki)=>(zo-q.center[ki])*q.scaleVector[ki])])),he={id:V,name:String(q.display_name||q.orig_filename||q.filename).split(/[\\/]/).pop().split(/[?#]/)[0],size:ye.file_bytes??q.local_file?.size??null,units:ye.units||q.units,bounds:Eo,position:{x:0,y:0,z:0},rotation:{x:q.rotationx*180/Math.PI,y:q.rotationy*180/Math.PI,z:q.rotationz*180/Math.PI},embedded:!!ye.colors,color:q.color||(ye.colors?null:"#909090"),estimated:ye.triangles*224,sourceFile:ge.used_files.includes(q.local_file)?q.local_file:null},Mo=Ge(he);for(let Ce of["x","y","z"])he.position[Ce]=q[Ce]-Mo[Ce];he.originalPosition={...he.position},he.originalRotation={...he.rotation},he.originalColor=he.color,y.set(V,he)}A=Math.max(A,x.max_model_id+1),g=ge.model_ids.at(-1),k++,r("scene-arrangement").value="custom",j=!!x.grid,ve=x.grid?.height||0,Fe=x.grid?.spacing||1,r("grid-button").setAttribute("aria-pressed",String(j)),Bt(x.bg_color),_e(),B(a.name+" opened. "+ge.model_ids.length+" models added."),x.canvas.focus({preventScroll:!0})}finally{S===z&&(S=null)}}t.querySelectorAll("[data-open-file]").forEach(a=>p(a,"click",()=>r("file-input").click()));for(let a of Pt)p(a,"click",()=>{if(a.disabled||F||!y.size)return;let u=a.dataset.viewstlShortcut;u==="save"?r("save-button")?.click():u==="select"?(xe(!U),ne(),B(U?"Selection mode. Click a model; Escape returns to viewing.":"Viewing mode. Drag to rotate the scene.")):["front","back","left","right","top","bottom","isometric"].includes(u)&&(G(!1),xe(!1),v.set_camera_view(u),D?.sync(),B(a.title||u+" view"))});p(o,"resize",()=>{U&&!Pt.some(a=>a.dataset.viewstlShortcut==="select"&&a.getClientRects().length)&&xe(!1)}),p(r("file-input"),"change",()=>{let a=[...r("file-input").files];r("file-input").value="",lt(a)}),r("sample-button").hidden=!Lt,p(r("sample-button"),"click",()=>{Lt&&lt([{name:e.sample_name||"Sample.stl",url:Lt}])}),p(r("close-model"),"click",()=>Ot(g)),p(r("cancel-load"),"click",at),p(r("clear-scene"),"click",gi),p(r("dismiss-notice"),"click",()=>{r("notice").hidden=!0}),p(r("fit-button"),"click",()=>v?.set_auto_zoom()),p(r("scene-arrangement"),"change",Ft),p(r("model-list"),"click",a=>{let u=a.target.closest("button");u&&(u.dataset.removeModel!==void 0?Ot(Number(u.dataset.removeModel)):u.dataset.selectModel!==void 0?Oe(Number(u.dataset.selectModel)):u.dataset.colorModel!==void 0&&(Oe(Number(u.dataset.colorModel)),tt("colors")))});async function wi(){if(g===null||F)return;let a=++k,u=Se.find(x=>x.checked).value;Se.forEach(x=>{x.disabled=!0}),r("smooth-shading").disabled=!0,r("view-status").textContent="Preparing view\u2026",r("notice").hidden=!0;try{v.set_view(g,{display:u,smooth_shading:r("smooth-shading").checked}),await v.when_idle()}finally{a===k&&(ui(),B(r("view-label").textContent+" view ready."))}}Se.forEach(a=>p(a,"change",wi)),p(r("smooth-shading"),"change",wi);for(let a of w)p(r(a+"-button"),"click",()=>{a==="info"&&it(),tt(a),a==="section"&&!r("section-panel").hidden&&!r("section-enabled").checked&&(r("section-enabled").checked=!0,je())}),p(r("close-"+a),"click",()=>{mi(a),a==="colors"&&tt("view"),r(a+"-button").focus()});function je(){if(g===null)return;let a=r("section-enabled").checked;v.set_section(g,a?{axis:r("section-axis").value,position:Number(r("section-position").value)/100,flip:r("section-flip").getAttribute("aria-pressed")==="true"}:null),r("section-value").textContent=r("section-position").value+"%",r("section-button").setAttribute("aria-pressed",String(a))}p(r("section-enabled"),"change",je),p(r("section-axis"),"change",je),p(r("section-position"),"input",je),p(r("section-flip"),"click",()=>{r("section-flip").setAttribute("aria-pressed",String(r("section-flip").getAttribute("aria-pressed")!=="true")),je()}),p(r("grid-button"),"click",()=>{j=!j,nt()});function jt(a){g!==null&&(v.set_color(g,a),y.get(g).color=a,Tt(),hi())}p(r("model-color"),"input",()=>jt(r("model-color").value)),p(r("restore-color"),"click",()=>jt(y.get(g)?.originalColor)),t.querySelectorAll("[data-model-color]").forEach(a=>p(a,"click",()=>jt(a.dataset.modelColor)));function Bt(a){we=a;let u=a==="transparent"?[255,255,255]:[1,3,5].map(x=>parseInt(a.slice(x,x+2),16));r("workspace").classList.toggle("dark-background",u[0]*.2126+u[1]*.7152+u[2]*.0722<115),v?.set_bg_color(a),Tt()}p(r("background-color"),"input",()=>Bt(r("background-color").value)),t.querySelectorAll("[data-background]").forEach(a=>p(a,"click",()=>Bt(a.dataset.background))),p(r("image-button"),"click",async()=>{if(g===null)return;let a=y.size>1?"viewstl-scene.png":y.get(g).name.replace(/\.[^.]+$/,"")+".png";try{let u=await v.get_image_blob("image/png");if(m)return;let x=s.createObjectURL(u),z=i.createElement("a");z.href=x,z.download=a,z.click(),setTimeout(()=>s.revokeObjectURL(x),1e3),B("Image ready to download.")}catch{me("The image could not be saved. Please try again.")}});let ct=0,Ut=a=>{let u=Jt(a.dataTransfer);return u==="files"?u:!e.url_import_endpoint||a.target?.isContentEditable||a.target?.closest?.("input, textarea")?null:u},dt=()=>{ct=0,r("drop-overlay").hidden=!0};p(c,"dragenter",a=>{Ut(a)&&(a.preventDefault(),ct++,r("drop-overlay").hidden=!1)}),p(c,"dragover",a=>{Ut(a)&&(a.preventDefault(),a.dataTransfer.dropEffect="copy")}),p(c,"dragleave",a=>{ct>0&&--ct===0&&dt()}),p(c,"drop",a=>{let u=Ut(a);if(dt(),!!u){a.preventDefault();try{if(u==="files")lt([...a.dataTransfer.files]).catch(x=>me(x.message));else for(let x of Bi(a.dataTransfer))Dt(x).catch(z=>me(z.message))}catch(x){me(x.message)}}}),p(c,"dragend",dt),p(o,"blur",dt),t.querySelectorAll("[data-dialog]").forEach(a=>p(a,"click",()=>r(a.dataset.dialog).showModal())),t.querySelectorAll("dialog").forEach(a=>p(a,"click",u=>{if(u.target===a){let x=a.getBoundingClientRect();(u.clientX<x.left||u.clientX>x.right||u.clientY<x.top||u.clientY>x.bottom)&&(a===r("save-dialog")?E.close():a.close())}})),p(t,"keydown",a=>{if(a.key!=="Escape"||r("save-dialog")?.open)return;if(U){xe(!1),ne(),B("Viewing mode. Drag to rotate the scene.");return}if(K){G(!1),B("Move tool closed.");return}let u=w.find(x=>!r(x+"-panel").hidden);u&&(ne(),u==="colors"&&tt("view"),r(u+"-button").focus())}),p(t,"pointerdown",a=>{a.target.closest(".view-panel,.info-panel,.toolbar,.scene-heading-button,.move-mode")||ne()}),r("memory-budget").textContent=`Scene memory budget: ${Ne(h.budget)}. Half of ${h.reported?"the memory estimate reported by your browser":"a conservative 2 GiB estimate because this browser does not report device memory"} is kept in reserve. This is an estimate, not a guarantee of available memory.`,r("scene-arrangement").value="original",r("notice").hidden=!0,r("drop-overlay").hidden=!0,r("save-button")&&(E=oo({$:r,listen:p,window:o,getState:()=>({busy:F,selectedId:g,models:[...y.values()]}),getViewer:()=>v,onOpen:()=>{G(!1),ne()},announce:B})),r("print-button")&&(L=no({$:r,listen:p,window:o,getState:()=>({busy:F,selectedId:g,models:[...y.values()]}),getViewer:()=>v,onOpen:()=>{G(!1),ne()},announce:B})),r("animation-details")&&(T=so({$:r,listen:p,window:o,getState:()=>({busy:F,selectedId:g,models:[...y.values()]}),getViewer:()=>v,beforePlay(a){G(!1),re(a),ro(y.get(a),v._models.get(a)),r("scene-arrangement").value="custom"},refreshPose:yi,announce:B})),r("size-details")&&(D=Mi({$:r,listen:p,window:o,getViewer:()=>v,getState:()=>({selectedId:g,busy:F}),refresh:_e,announce:B,changeSize(a){G(!1);let u=y.get(g);ie(u,v._models.get(g)),a(),ie(u,v._models.get(g)),r("scene-arrangement").value="custom",_e()},duplicate(){let a=y.get(g),u=v.duplicate_model(g),x=v._models.get(u),z={...a,id:u,name:x.display_name,position:{...a.position},rotation:{...a.rotation}};ie(z,x),z.originalPosition={...z.position},z.originalRotation={...z.rotation},y.set(u,z),A=Math.max(A,u+1),r("scene-arrangement").value="custom",Oe(u),G(!0,"move",!0),B("Copy selected at the same position. Drag to move it.")}})),nt(),ot(!1),G(!1);let xi={openFiles:lt,openURL:Dt,cancelLoading(){_(),at()},clear(){_(),gi()},select(a){_(),Oe(a)},remove(a){_(),Ot(a)},getState(){_();for(let a of y.values())ie(a,v?._models.get(a.id));return{selectedId:g,busy:F,arrangement:r("scene-arrangement").value,memoryBudget:h.budget,models:[...y.values()].map(a=>({id:a.id,name:a.name,size:a.size,units:a.units,position:{...a.position},rotation:{...a.rotation},color:a.color,animation:v.get_model_animation_state(a.id)}))}},dispose(){m||(E?.dispose(),L?.dispose(),T?.dispose(),D?.dispose(),at(),G(!1),k++,m=!0,l.abort(),Ae?.dispose(),v?.dispose(),y.clear(),e.id_prefix&&Se.forEach(a=>a.name="view-mode"),si.delete(t))}};return si.set(t,xi),xi}var Uo=globalThis.document?.currentScript;ze.workerURL=new URL("viewstl.worker.js",Uo?.src||document.baseURI).href;globalThis.StlViewer=ze;globalThis.mountViewstlApp=yo;})();