shotops-mcp 0.9.8 → 0.9.9

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.
@@ -0,0 +1 @@
1
+ import{S as ln,G as cn,A as dn,D as ie,M as un,R as pn,a as fn,C as hn,b as mn,c as gn}from"./three-addons-zF8BveTt.js";import{aa as yn,P as Pe,b as bn,V as z,a4 as vn,l as gt,C as L,ab as wn,J as ze,$ as X,M as Sn,a2 as In,B as xn,a3 as An,a7 as Pn,ac as je,ad as Cn,ae as kn}from"./three-webgl-BAyyruEx.js";(function(){const t=document.createElement("link").relList;if(t&&t.supports&&t.supports("modulepreload"))return;for(const o of document.querySelectorAll('link[rel="modulepreload"]'))r(o);new MutationObserver(o=>{for(const a of o)if(a.type==="childList")for(const s of a.addedNodes)s.tagName==="LINK"&&s.rel==="modulepreload"&&r(s)}).observe(document,{childList:!0,subtree:!0});function n(o){const a={};return o.integrity&&(a.integrity=o.integrity),o.referrerPolicy&&(a.referrerPolicy=o.referrerPolicy),o.crossOrigin==="use-credentials"?a.credentials="include":o.crossOrigin==="anonymous"?a.credentials="omit":a.credentials="same-origin",a}function r(o){if(o.ep)return;o.ep=!0;const a=n(o);fetch(o.href,a)}})();const Ce={lineHeight:1.2,bandInset:.06,bandCenter:.5},De={sizePt:{min:20,max:120},maxWidth:{min:.1,max:1},lineHeight:{min:.5,max:3},bandInset:{min:0,max:.5},bandCenter:{min:0,max:1},reserveLines:{min:1,max:8}},Q=[{id:"inter",family:"Inter",label:"Inter"},{id:"manrope",family:"Manrope",label:"Manrope"},{id:"poppins",family:"Poppins",label:"Poppins"},{id:"fraunces",family:"Fraunces",label:"Fraunces"},{id:"space-grotesk",family:"Space Grotesk",label:"Space Grotesk"}],Ue=Q.map(e=>e.id);[Ue[0],...Ue.slice(1)];const $=600;function ke(e){return Q.find(t=>t.id===e)??Q[0]}const yt=[{id:"standard",label:"Standard",blurb:"Headline on top, whole device below it, nothing cropped. The safe default.",character:"safe",bleedEdge:"none",shotLook:{deviceSize:"100",hOffset:"0",vOffset:"18",angle:"front",cameraPos:null,roll:"0"},caption:{sizePt:32,maxWidth:.86,reserveLines:2,align:"center",bandCenter:.5}},{id:"bleed",label:"Bleed",blurb:"Room for a longer headline, device running off the bottom edge. What the market looks like.",character:"conventional",bleedEdge:"bottom",shotLook:{deviceSize:"100",hOffset:"0",vOffset:"38",angle:"front",cameraPos:null,roll:"0"},caption:{sizePt:32,maxWidth:.86,reserveLines:4,align:"center",bandCenter:.5}},{id:"top-bleed",label:"Top bleed",blurb:"Device running off the TOP edge, headline underneath it. Inverts the usual reading order.",character:"expressive",bleedEdge:"top",shotLook:{deviceSize:"100",hOffset:"0",vOffset:"-38",angle:"front",cameraPos:null,roll:"0"},caption:{sizePt:32,maxWidth:.86,reserveLines:4,band:"bottom",align:"center",bandCenter:.5}},{id:"lean-right",label:"Lean right",blurb:"Device pushed off the RIGHT edge, headline in a column down the left. Reads as one continuous swipe.",character:"expressive",bleedEdge:"right",shotLook:{deviceSize:"100",hOffset:"46",vOffset:"18",angle:"front",cameraPos:null,roll:"0"},caption:{sizePt:32,maxWidth:.61,reserveLines:2,align:"left",bandCenter:.375}},{id:"lean-left",label:"Lean left",blurb:"Device pushed off the LEFT edge, headline in a column down the right. The mirror of Lean right.",character:"expressive",bleedEdge:"left",shotLook:{deviceSize:"100",hOffset:"-46",vOffset:"18",angle:"front",cameraPos:null,roll:"0"},caption:{sizePt:32,maxWidth:.61,reserveLines:2,align:"right",bandCenter:.625}},{id:"swipe",label:"Swipe",blurb:"A third of the device carried into the next panel, headline full width above it. Only honest applied to every frame.",character:"expressive",bleedEdge:"right",shotLook:{deviceSize:"100",hOffset:"78",vOffset:"18",angle:"front",cameraPos:null,roll:"0"},caption:{sizePt:32,maxWidth:.86,reserveLines:2,align:"center",bandCenter:.5}},{id:"corner-bleed",label:"Corner bleed",blurb:"Off the bottom AND the right at once, headline in a column down the left. The most opinionated panel here.",character:"expressive",bleedEdge:"bottom-right",shotLook:{deviceSize:"100",hOffset:"46",vOffset:"38",angle:"front",cameraPos:null,roll:"0"},caption:{sizePt:32,maxWidth:.61,reserveLines:4,align:"left",bandCenter:.375}}],bt=yt,We=bt.map(e=>e.id);[We[0],...We.slice(1)];Array.from(new Set(yt.flatMap(e=>Object.keys(e.caption))));const vt=[{id:"noir",label:"Noir",blurb:"Near-black, high contrast, glossy silver device. The default premium look.",background:{gradientFrom:"#1C1C22",gradientTo:"#08080B",gradientDir:"vertical",shadow:!0,floorReflection:!1},shotLook:{material:"real",colorway:"silver",finish:"0",clearcoat:"1",reflections:!0,lighting:!0,angle:"front"},caption:{fontId:"inter",color:"FFFFFF"}},{id:"daylight",label:"Daylight",blurb:"Warm off-white, soft matte white device, dark text. Calm and editorial.",background:{gradientFrom:"#F4F1EA",gradientTo:"#DFD8CA",gradientDir:"vertical",shadow:!0,floorReflection:!1},shotLook:{material:"clay",clayTone:"white",finish:"0",clearcoat:"0",reflections:!1,lighting:!0,angle:"front"},caption:{fontId:"manrope",color:"1A1A1F"}},{id:"pop",label:"Pop",blurb:"Saturated indigo-to-violet, orange device. Loud, consumer, scroll-stopping.",background:{gradientFrom:"#5B6CF0",gradientTo:"#9B4DF0",gradientDir:"vertical",shadow:!0,floorReflection:!1},shotLook:{material:"real",colorway:"orange",finish:"0",clearcoat:"0.4",reflections:!0,lighting:!0,angle:"front"},caption:{fontId:"poppins",color:"FFFFFF"}},{id:"clay",label:"Clay",blurb:"Warm terracotta, matte charcoal device, tilted. Reads like a product photo.",background:{gradientFrom:"#E9BBAC",gradientTo:"#C88C7C",gradientDir:"vertical",shadow:!0,floorReflection:!1},shotLook:{material:"clay",clayTone:"charcoal",finish:"0",clearcoat:"0",reflections:!1,lighting:!0,angle:"left",roll:"-6"},caption:{fontId:"fraunces",color:"2A2320"}},{id:"studio",label:"Studio",blurb:"Mid slate with a floor reflection, blue device. Technical and precise.",background:{gradientFrom:"#5A6678",gradientTo:"#2B3340",gradientDir:"vertical",shadow:!0,floorReflection:!0},shotLook:{material:"real",colorway:"blue",finish:"0",clearcoat:"0",reflections:!0,lighting:!0,angle:"front"},caption:{fontId:"space-grotesk",color:"FFFFFF"}}],He=vt.map(e=>e.id);[He[0],...He.slice(1)];const k={angle:"front",cameraPos:null,roll:"0",deviceSize:"100",hOffset:"0",vOffset:"18",material:"real",colorway:"blue",customColor:"32374A",finish:"0",clearcoat:"0",clayTone:"grey",clayCustom:"B0B0B0",flatScreen:!1,glare:!1,lighting:!0,reflections:!1},me={angle:{valueKind:"angle",required:!0,defaultSource:"default-look",defaultValue:k.angle,persistence:"always"},cameraPos:{valueKind:"camera-position",required:!0,defaultSource:"default-look",defaultValue:k.cameraPos,persistence:"always"},roll:{valueKind:"numeric-string",required:!0,defaultSource:"default-look",defaultValue:k.roll,persistence:"always"},deviceSize:{valueKind:"numeric-string",required:!0,defaultSource:"default-look",defaultValue:k.deviceSize,persistence:"always"},hOffset:{valueKind:"numeric-string",required:!0,defaultSource:"default-look",defaultValue:k.hOffset,persistence:"always"},vOffset:{valueKind:"numeric-string",required:!0,defaultSource:"default-look",defaultValue:k.vOffset,persistence:"always"},material:{valueKind:"material",required:!0,defaultSource:"default-look",defaultValue:k.material,persistence:"always"},colorway:{valueKind:"colorway",required:!0,defaultSource:"default-look",defaultValue:k.colorway,persistence:"always"},customColor:{valueKind:"string",required:!0,defaultSource:"default-look",defaultValue:k.customColor,persistence:"always"},finish:{valueKind:"numeric-string",required:!0,defaultSource:"default-look",defaultValue:k.finish,persistence:"always"},clearcoat:{valueKind:"numeric-string",required:!0,defaultSource:"default-look",defaultValue:k.clearcoat,persistence:"always"},clayTone:{valueKind:"clay-tone",required:!0,defaultSource:"default-look",defaultValue:k.clayTone,persistence:"always"},clayCustom:{valueKind:"string",required:!0,defaultSource:"default-look",defaultValue:k.clayCustom,persistence:"always"},flatScreen:{valueKind:"boolean",required:!0,defaultSource:"default-look",defaultValue:k.flatScreen,persistence:"always"},clipToFrame:{valueKind:"boolean",required:!1,defaultSource:"explicit",defaultValue:!1,persistence:"omit-default"},deviceFrame:{valueKind:"boolean",required:!1,defaultSource:"explicit",defaultValue:!0,persistence:"omit-default"},screenCornerRadius:{valueKind:"numeric-string",required:!1,defaultSource:"explicit",defaultValue:"12",persistence:"omit-default"},glare:{valueKind:"boolean",required:!0,defaultSource:"default-look",defaultValue:k.glare,persistence:"always"},lighting:{valueKind:"boolean",required:!0,defaultSource:"default-look",defaultValue:k.lighting,persistence:"always"},reflections:{valueKind:"boolean",required:!0,defaultSource:"default-look",defaultValue:k.reflections,persistence:"always"}},On={roll:{min:-45,max:45},deviceSize:{min:25,max:240},hOffset:{min:-100,max:100},vOffset:{min:-200,max:200},finish:{min:0,max:1},clearcoat:{min:0,max:1},screenCornerRadius:{min:0,max:50}},wt=.82;function Tn(e){return e/100*wt}function En(e){return Math.round(e/wt*100)/100}const V={x:.5,y:.06},Oe={fontId:"inter",sizePt:32,color:"FFFFFF",align:"center",anchor:V,maxWidth:.86},Ge=[{id:"r69",label:"6.9″ iPhone · 1320×2868",width:1320,height:2868},{id:"r65",label:"6.5″ iPhone · 1242×2688",width:1242,height:2688},{id:"r55",label:"5.5″ iPhone · 1242×2208",width:1242,height:2208},{id:"pixel69",label:"Pixel 10 Pro · 1320×2868",width:1320,height:2868},{id:"ipad13",label:"13″ iPad · 2064×2752",width:2064,height:2752},{id:"ipad129",label:"12.9″ iPad · 2048×2732",width:2048,height:2732}];function q(e){return Ge.find(t=>t.id===e)??Ge[0]}const oe=932,ge="iphone-17-pro",Ln="pixel-10-pro",Te=[{id:"iphone-6-9",label:"iPhone 17 Pro",panelPresetId:"r69",ascDeviceSet:"APP_IPHONE_67",modelId:ge,screenFamily:"iphone"},{id:"iphone-6-5",label:"iPhone 17",panelPresetId:"r65",ascDeviceSet:"APP_IPHONE_65",modelId:ge,screenFamily:"iphone"},{id:"pixel-10-pro",label:"Pixel 10 Pro",panelPresetId:"pixel69",ascDeviceSet:"ANDROID_PHONE",modelId:Ln,screenFamily:"android"},{id:"ipad-13",label:"iPad 13″",panelPresetId:"ipad13",ascDeviceSet:"APP_IPAD_PRO_129",modelId:"ipad-pro",screenFamily:"ipad",comingSoon:!0},{id:"ipad-12-9",label:"iPad 12.9″",panelPresetId:"ipad129",ascDeviceSet:"APP_IPAD_PRO_3GEN_129",modelId:"ipad-pro",screenFamily:"ipad",comingSoon:!0}];function Mn(e){return Te.find(t=>t.panelPresetId===e)?.modelId??ge}const St="iphone-6-9";function Ee(e){return Te.find(t=>t.id===e)}function Rn(){return Te.filter(e=>!e.comingSoon)}function It(e,t){if(Array.isArray(e)){const n=new Set,r=[];for(const o of e){const a=Ee(o);a&&!a.comingSoon&&!n.has(o)&&(n.add(o),r.push(o))}if(r.length>0)return r}if(t){const n=Rn().find(r=>r.panelPresetId===t);if(n)return[n.id]}return[St]}function Fn(e,t){return e.find(r=>Ee(r)?.panelPresetId===t)??e[0]}function Nn(e){const t=e??{},n=Array.isArray(t.outputs)?t.outputs.filter(a=>typeof a=="string"):void 0,r=It(n,typeof t.panelPresetId=="string"?t.panelPresetId:void 0),o=q(typeof t.panelPresetId=="string"?t.panelPresetId:"").id;return{outputs:r,panelPresetId:o,activeDeviceId:Fn(r,o)}}const xt=Ee(St)?.screenFamily??"iphone";function At(e){const t={...e},n=t,r=Object.keys(me);for(const o of r){const a=me[o];a.persistence==="omit-default"&&(n[o]===void 0||n[o]===a.defaultValue)&&delete n[o]}return t}function _n(e){if(!e||typeof e!="object"||Array.isArray(e)||!("phoneHeight"in e))return e;const{phoneHeight:t,...n}=e;if(n.deviceSize===void 0){const r=typeof t=="number"?t:Number.parseFloat(String(t??""));Number.isFinite(r)&&(n.deviceSize=String(En(r)))}return n}function Pt(e){return At({...k,..._n(e)})}function Ct(e){return At(Pt(e))}function M(e,t){const{min:n,max:r}=On[e],o=typeof t=="number"?t:Number.parseFloat(t??""),a=Number.isFinite(o)?o:Number.parseFloat(String(me[e].defaultValue));return Math.max(n,Math.min(r,a))}const Bn=90,kt=180,zn="#1b1b2e",jn="#0a0a14";function Dn(e){return e==="horizontal"?Bn:kt}function Un(e){const t=(e%180+180)%180;return t>=45&&t<135?"horizontal":"vertical"}function Ot(e,t,n){return{stops:[{color:e,at:0},{color:t,at:1}],angle:Dn(n)}}const Tt=e=>e*Math.PI/180;function Wn(e){const t=Tt(e);return{dx:Math.sin(t),dy:-Math.cos(t)}}function Hn(e,t,n){const r=Tt(n);return Math.abs(e*Math.sin(r))+Math.abs(t*Math.cos(r))}function Gn(e,t,n){const{dx:r,dy:o}=Wn(n),a=Hn(e,t,n)/2,s=e/2,i=t/2;return{x0:s-a*r,y0:i-a*o,x1:s+a*r,y1:i+a*o}}function ee(e){const t=e.stops[0],n=e.stops[e.stops.length-1];return{gradientFrom:t?.color??"#000000",gradientTo:n?.color??t?.color??"#000000",gradientDir:Un(e.angle)}}function ae(e,t){if(!Array.isArray(e)||e.length===0)return null;const n=[];for(const o of e){if(!o||typeof o!="object")return null;const a=o;if(typeof a.color!="string"||typeof a.at!="number"||!Number.isFinite(a.at))return null;n.push({color:a.color,at:Math.min(1,Math.max(0,a.at))})}const r=typeof t=="number"&&Number.isFinite(t)?$n(t):kt;return{stops:n,angle:r}}function te(e){return ae(e.gradientStops,e.gradientAngle)??Ot(e.gradientFrom,e.gradientTo,e.gradientDir)}function $n(e){return(e%360+360)%360}function Vn(e){return ae(e.stops,e.angle)??Ot(e.from,e.to,e.dir)}function Et(e){if(!e||typeof e!="object"||Array.isArray(e))return{};const t={};for(const[n,r]of Object.entries(e)){if(!r||typeof r!="object")continue;const o=r;if(o.kind==="solid"&&typeof o.color=="string")t[n]={kind:"solid",color:o.color};else if(o.kind==="gradient"&&typeof o.from=="string"&&typeof o.to=="string"&&(o.dir==="horizontal"||o.dir==="vertical")){const a=ae(o.stops,o.angle);t[n]=a?{kind:"gradient",stops:a.stops,angle:a.angle,from:o.from,to:o.to,dir:o.dir}:{kind:"gradient",from:o.from,to:o.to,dir:o.dir}}}return t}function D(e){return!e||e.x===V.x&&e.y===V.y}function qn(e){const{text:t,anchor:n,...r}=e;return D(n)?{...r}:{...r,anchor:n}}const Kn=.55,N="en-US";function Yn(e){const t=e.lastIndexOf(":");if(t<=0)return null;const n=Number(e.slice(t+1));return!Number.isSafeInteger(n)||n<0?null:{panelId:e.slice(0,t),index:n}}function Lt(e,t,n,r){if(!e||typeof e!="object"||Array.isArray(e))return{};const o={};for(const[a,s]of Object.entries(e)){if(a===n||!t.includes(a)||!Array.isArray(s))continue;const i=Array.from(new Set(s.filter(c=>typeof c=="string"))).filter(c=>{const l=Yn(c);return!!l&&!!r[n]?.[l.panelId]?.[l.index]&&!!r[a]?.[l.panelId]?.[l.index]});i.length>0&&(o[a]=i)}return o}function Mt(e){if(!e||typeof e!="object"||Array.isArray(e))return{};const t={};for(const[n,r]of Object.entries(e))!r||typeof r!="object"||Array.isArray(r)||(t[n]=H(r));return t}function Xn(e){if(!e||typeof e!="object")return;const t=e,n=typeof t.x=="number"?t.x:V.x,r=typeof t.y=="number"?t.y:V.y;return D({x:n,y:r})?void 0:{x:n,y:r}}function H(e){const t=e&&typeof e=="object"?e:{},n=Xn(t.anchor),r={...Oe,...t};n?r.anchor=n:delete r.anchor,typeof r.reserveLines!="number"||!Number.isFinite(r.reserveLines)||r.reserveLines<De.reserveLines.min?delete r.reserveLines:r.reserveLines=Math.floor(r.reserveLines),r.band!=="bottom"&&delete r.band;for(const o of["bandInset","lineHeight","bandCenter"]){const{min:a,max:s}=De[o],i=r[o];(typeof i!="number"||!Number.isFinite(i)||i<a||i>s)&&delete r[o]}return r}function Jn(e){const t=e&&typeof e=="object"?e:{};return{...H(t),text:typeof t.text=="string"?t.text:""}}function Rt(e){if(!e||typeof e!="object"||Array.isArray(e))return{};const t={};for(const[n,r]of Object.entries(e))Array.isArray(r)?r.length>0&&(t[n]=r.map(H)):r&&typeof r=="object"&&(t[n]=[H(r)]);return t}function Zn(e,t){const n=[{...H(t),text:e.headline}];return typeof e.subtitle=="string"&&e.subtitle.trim()&&n.push({...H({...t,sizePt:t.sizePt*Kn}),text:e.subtitle}),n}function se(e,t,n=N){if(!e||typeof e!="object"||Array.isArray(e))return{};const r=Mt(t),o=l=>r[l]??Oe,a=l=>{if(!l||typeof l!="object"||Array.isArray(l))return{};const d={};for(const[p,u]of Object.entries(l))Array.isArray(u)?u.length>0&&(d[p]=u.map(Jn)):u&&typeof u=="object"&&typeof u.headline=="string"&&(d[p]=Zn(u,o(p)));return d},s=Object.entries(e);if(s.some(([,l])=>!!l&&typeof l=="object"&&typeof l.headline=="string"))return{[n]:a(e)};const c={};for(const[l,d]of s)c[l]=a(d);return c}function Ft(e,t,n=N){return e[t??n]??e[n]??{}}function Nt(e,t=N){const n={},r=Object.keys(e),o=r.includes(t)?[t,...r.filter(a=>a!==t)]:r;for(const a of o){const s=e[a];if(s)for(const[i,c]of Object.entries(s))n[i]===void 0&&Array.isArray(c)&&c.length>0&&(n[i]=c.map(qn))}return n}function ye(e,t=N,n=xt){const r={};return e.family!==void 0&&e.family!==n&&(r.family=e.family),e.locale!==void 0&&e.locale!==t&&(r.locale=e.locale),r}function $e(e){const t=[];return e.family!==void 0&&t.push(`family=${e.family}`),e.locale!==void 0&&t.push(`locale=${e.locale}`),t.join("&")}function be(e){const t=[];return e.family!==void 0&&t.push("family"),e.locale!==void 0&&t.push("locale"),t}const Qn={order:["family","locale"],reach:"strict"};function er(e,t){const n=be(e),r=t.order.filter(a=>n.includes(a));return Array.from({length:r.length+1},(a,s)=>r.slice(0,r.length-s)).map(a=>{const s={};return a.includes("family")&&(s.family=e.family),a.includes("locale")&&(s.locale=e.locale),s})}function tr(e,t,n,r,o=N){const a=ye(n,o);for(const s of er(a,r)){const i=e(t,s);if(i!==void 0){const c=be(s);return{value:i,resolvedAt:s,inherited:be(a).filter(l=>!c.includes(l))}}}return{value:void 0,resolvedAt:null,inherited:[]}}const _t=e=>{let t="";for(let n=0;n<e.length;n++)t+=e[n].toString(16).padStart(2,"0");return t};async function nr(e){const t=globalThis.crypto?.subtle;return t?_t(new Uint8Array(await t.digest("SHA-256",e))):or(e)}const rr=new Uint32Array([1116352408,1899447441,3049323471,3921009573,961987163,1508970993,2453635748,2870763221,3624381080,310598401,607225278,1426881987,1925078388,2162078206,2614888103,3248222580,3835390401,4022224774,264347078,604807628,770255983,1249150122,1555081692,1996064986,2554220882,2821834349,2952996808,3210313671,3336571891,3584528711,113926993,338241895,666307205,773529912,1294757372,1396182291,1695183700,1986661051,2177026350,2456956037,2730485921,2820302411,3259730800,3345764771,3516065817,3600352804,4094571909,275423344,430227734,506948616,659060556,883997877,958139571,1322822218,1537002063,1747873779,1955562222,2024104815,2227730452,2361852424,2428436474,2756734187,3204031479,3329325298]),F=(e,t)=>e>>>t|e<<32-t;function or(e){const t=e.length,n=new Uint8Array(t+72>>6<<6);n.set(e),n[t]=128;const r=t*8,o=new DataView(n.buffer);o.setUint32(n.length-8,Math.floor(r/4294967296)),o.setUint32(n.length-4,r>>>0);const a=new Uint32Array([1779033703,3144134277,1013904242,2773480762,1359893119,2600822924,528734635,1541459225]),s=new Uint32Array(64);for(let i=0;i<n.length;i+=64){for(let h=0;h<16;h++)s[h]=o.getUint32(i+h*4);for(let h=16;h<64;h++){const y=s[h-15],v=s[h-2],b=F(y,7)^F(y,18)^y>>>3,S=F(v,17)^F(v,19)^v>>>10;s[h]=s[h-16]+b+s[h-7]+S>>>0}let[c,l,d,p,u,f,g,m]=[a[0],a[1],a[2],a[3],a[4],a[5],a[6],a[7]];for(let h=0;h<64;h++){const y=F(u,6)^F(u,11)^F(u,25),v=u&f^~u&g,b=m+y+v+rr[h]+s[h]>>>0,S=F(c,2)^F(c,13)^F(c,22),C=c&l^c&d^l&d,x=S+C>>>0;m=g,g=f,f=u,u=p+b>>>0,p=d,d=l,l=c,c=b+x>>>0}a[0]=a[0]+c>>>0,a[1]=a[1]+l>>>0,a[2]=a[2]+d>>>0,a[3]=a[3]+p>>>0,a[4]=a[4]+u>>>0,a[5]=a[5]+f>>>0,a[6]=a[6]+g>>>0,a[7]=a[7]+m>>>0}return _t(ar(a))}function ar(e){const t=new Uint8Array(e.length*4),n=new DataView(t.buffer);for(let r=0;r<e.length;r++)n.setUint32(r*4,e[r]);return t}function ve(e,t,n=N){const r=o=>{const a=new Set,s=[];for(const i of o)typeof i=="string"&&i&&!a.has(i)&&(a.add(i),s.push(i));return s};if(Array.isArray(t)){const o=r(t);if(o.length>0)return o.includes(n)?o:[...o,n]}return r([n,...Object.keys(e)])}function Le(e,t=N){return typeof e=="string"&&e.length>0?e:t}const G={"it-IT":"it"};function Ve(e,t){if(!(Object.keys(e).some(o=>o in G)||(t?.some(o=>o in G)??!1)))return{captionText:e,locales:t};const r={};for(const[o,a]of Object.entries(e))o in G||(r[o]=a);for(const[o,a]of Object.entries(e)){const s=G[o];s&&(r[s]={...a,...r[s]??{}})}return{captionText:r,locales:t?.map(o=>G[o]??o)}}function sr(e){const t=e??{},n=Le(t.baseLocale),r=Array.isArray(t.locales)?t.locales.filter(i=>typeof i=="string"&&i.length>0):void 0,{captionText:o,locales:a}=Ve(se(t.captionText,t.captionStyles,n),r),s=Ve({[n]:{}},[n]).locales?.[0]??n;return{captionText:o,locales:ve(o,a,s),baseLocale:s}}function Bt(e){if(!e||typeof e!="object"||Array.isArray(e))return{};const t={};for(const[n,r]of Object.entries(e)){if(n===xt||!r||typeof r!="object"||Array.isArray(r))continue;const o={};for(const[a,s]of Object.entries(r)){if(!s||typeof s!="object"||Array.isArray(s))continue;const i={};for(const[c,l]of Object.entries(s))Array.isArray(l)&&l.every(d=>typeof d=="string")&&(i[c]=l);Object.keys(i).length>0&&(o[a]=i)}Object.keys(o).length>0&&(t[n]=o)}return t}function K(e,t){return t.flatMap(n=>e.filter(r=>r.panelId===n.id))}let qe=0,Ke=0;function ir(e,t){const n=(r,o)=>r.reduce((a,s)=>{const i=s.startsWith(o)?Number.parseInt(s.slice(o.length),10):NaN;return Number.isFinite(i)&&i>a?i:a},0);qe=Math.max(qe,n(e,"shot-")),Ke=Math.max(Ke,n(t,"panel-"))}const lr=.49;function cr(e,t,n){return e.map(r=>{const o=n*r.heightFrac,a=r.height>0?r.width*(o/r.height):o*lr,i=r.panelIndex*t+t/2-a/2+r.hOffset*(t/2),l=(n-o)/2+r.vOffset*(n/2);return{shotId:r.shotId,bytes:r.bytes,x:Math.round(i),y:Math.round(l),width:Math.round(a),height:Math.round(o),panelIndex:r.panelIndex,...r.clipToFrame===!0?{clipToFrame:!0}:{},...r.layers?{layers:r.layers}:{}}})}function dr(e,t){const n=t.panelBackgrounds??{},r=te(t),o=r.stops[0]?.color??t.gradientFrom;if(!e.some(c=>n[c.id]))return t.bgMode==="gradient"?{kind:"gradient",gradient:r}:{kind:"perPanel",colors:e.map(c=>t.panelColors[c.id]??o)};const s=c=>t.bgMode==="gradient"?{kind:"gradient",gradient:r}:{kind:"solid",color:t.panelColors[c]??o};return{kind:"perPanelFills",fills:e.map(c=>{const l=n[c.id];return l?l.kind==="solid"?{kind:"solid",color:l.color}:{kind:"gradient",gradient:Vn(l)}:s(c.id)})}}const ur=9/19.5;function pr(e){return e.deviceFrame!==!1}function fr(e,t,n,r){const o=e>0&&t>0,a=o?t:Math.max(1,r),s=o?e:a*ur,i=Math.min(1,Math.max(1,r)/a),c=Math.max(1,Math.round(s*i)),l=Math.max(1,Math.round(a*i)),d=Math.min(c*M("screenCornerRadius",n.screenCornerRadius)/100,Math.min(c,l)/2),p=M("roll",n.roll)*Math.PI/180,u=Math.abs(Math.cos(p)),f=Math.abs(Math.sin(p)),g=Math.max(1,Math.ceil(c*u+l*f-1e-6)),m=Math.max(1,Math.ceil(c*f+l*u-1e-6));return{width:g,height:m,cardWidth:c,cardHeight:l,radius:d,rotation:p}}function zt(e,t,n=N){const r=te(e);return{panelPresetId:e.panelPresetId,bgMode:e.bgMode,gradientStops:r.stops,gradientAngle:r.angle,...ee(r),panelColors:e.panelColors,shadow:e.shadow,floorReflection:e.floorReflection??!1,panelBackgrounds:e.panelBackgrounds??{},captionStyles:{...Rt(e.captionStyles),...Nt(t,n)}}}function hr(e){const t=e.caption.reserveLines,n=typeof t=="number"?` Reserves ${t} headline lines (~${Math.round(t*18*(e.caption.maxWidth??.86)/.86)} characters).`:"",r=(e.caption.maxWidth??.86)<.86||(e.caption.align??"center")!=="center"?" Restyles the headline into a narrower column.":" Leaves the headline full-width and centred.";return`${e.blurb}${n}${r} Character: [${e.character}]. Bleeds: [${e.bleedEdge}].`}function mr(e,t){return Math.max(0,...Object.values(e).map(n=>n[t]?.length??0))}function jt(e,t,n){const r=e&&typeof e=="object"&&!Array.isArray(e)?e:{},o=new Set,a={};let s=1;const i=()=>{for(;o.has(`caption-${s}`);)s+=1;const c=`caption-${s}`;return o.add(c),s+=1,c};for(const c of n){const l=mr(t,c);if(l===0)continue;const d=Array.isArray(r[c])?r[c]:[];a[c]=Array.from({length:l},(p,u)=>{const f=d[u];return typeof f=="string"&&f.length>0&&!o.has(f)?(o.add(f),f):i()})}return a}const Dt=2;function gr(e){if(!e||typeof e!="object"||Array.isArray(e))return!1;const t=e;return t.schema===Dt&&Array.isArray(t.shots)&&Array.isArray(t.panels)&&t.panels.length>0}function yr(e){let t;try{t=JSON.parse(e)}catch{return null}if(!gr(t))return null;const n=t,r=new Set(n.panels.map(f=>f.id)),o=n.shots.filter(f=>r.has(f.panelId)).map(f=>({id:f.id,panelId:f.panelId,frameNodeId:f.frameNodeId,frameName:f.frameName,bytes:null,look:Pt(f.look),thumb:null,thumbStale:!0,inputAnchor:f.inputAnchor,outputAnchor:f.outputAnchor})),a=n.panels.map(f=>({id:f.id}));ir(o.map(f=>f.id),a.map(f=>f.id));const s=n.selectedShotId&&o.some(f=>f.id===n.selectedShotId)?n.selectedShotId:o[0]?.id??null,{captionText:i,locales:c,baseLocale:l}=sr(n),d=Nn(n),p=jt(n.captionSlotIds,i,a.map(f=>f.id)),u=ae(n.gradientStops,n.gradientAngle);return{shots:K(o,a),panels:a,selectedShotId:s,panelPresetId:d.panelPresetId,bgMode:n.bgMode==="perPanel"?"perPanel":"gradient",...u?{gradientStops:u.stops,gradientAngle:u.angle,...ee(u)}:{gradientFrom:n.gradientFrom??"5B6CF0",gradientTo:n.gradientTo??"9B4DF0",gradientDir:n.gradientDir==="vertical"?"vertical":"horizontal"},panelColors:n.panelColors??{},shadow:n.shadow!==!1,floorReflection:n.floorReflection===!0,panelBackgrounds:Et(n.panelBackgrounds),captionText:i,locales:c,baseLocale:l,staleCaptionTranslations:Lt(n.staleCaptionTranslations,c,l,i),outputs:d.outputs,localeScreens:{},outputCaptions:Bt(n.outputCaptions),captionSlotIds:p,frameTemplates:n.frameTemplates&&typeof n.frameTemplates=="object"&&!Array.isArray(n.frameTemplates)?n.frameTemplates:{}}}function Ut(e){const n=K(e.shots,e.panels).map(a=>({id:a.id,panelId:a.panelId,frameNodeId:a.frameNodeId,frameName:a.frameName,look:Ct(a.look),inputAnchor:a.inputAnchor,outputAnchor:a.outputAnchor})),r=Le(e.baseLocale),o=se(e.captionText,e.captionStyles,r);return{schema:Dt,shots:n,panels:e.panels,selectedShotId:e.selectedShotId,captionText:o,locales:ve(o,e.locales,r),baseLocale:r,staleCaptionTranslations:Lt(e.staleCaptionTranslations,ve(o,e.locales,r),r,o),outputs:It(e.outputs,e.panelPresetId),outputCaptions:Bt(e.outputCaptions),...(()=>{const a=jt(e.captionSlotIds,o,e.panels.map(s=>s.id));return Object.keys(a).length>0?{captionSlotIds:a}:{}})(),...e.frameTemplates&&Object.keys(e.frameTemplates).length>0?{frameTemplates:e.frameTemplates}:{},...zt(e,o,r)}}const br=1;function vr(e){const t=K(e.shots,e.panels),n=se(e.captionText,e.captionStyles),r=Le(e.baseLocale);return{schema:br,shots:t.map(o=>({panelId:o.panelId,look:Ct(o.look)})),...zt(e,n,r)}}vt.map(e=>({id:e.id,label:e.label,description:e.blurb}));bt.map(e=>({id:e.id,label:e.label,description:hr(e),character:e.character}));const wr=[{id:"frame.add",domain:"frame",status:"supported",summary:"Add a blank frame after an existing one.",studioCommands:["addPanel"],wire:"structuralOperations: frame.add",targets:["project"],requiredInputs:["afterFrameId (optional)","frameRef (optional, patch-local alias)"],limits:["Declare frameRef to address the new frame in later ordered operations of the same patch. Without frameRef, wait until the next cycle reports its id."],evaluationCases:["structure-add-closing-frame"]},{id:"frame.remove",domain:"frame",status:"supported",summary:"Remove a frame, with the devices and captions it holds.",studioCommands:["removePanel"],wire:"structuralOperations: frame.remove",targets:["frame"],requiredInputs:["frameId"],limits:["The last remaining frame cannot be removed."],evaluationCases:["structure-remove-empty-frame","structure-remove-populated-frame"]},{id:"frame.reorder",domain:"frame",status:"supported",summary:"Change the order frames tell the story in.",studioCommands:["movePanel","reorderPanels"],wire:"structuralOperations: frame.move, or the complete screenOrder permutation",targets:["project","frame"],requiredInputs:["frameId and its new position"],evaluationCases:["project-reorder-strongest"]},{id:"frame.split",domain:"frame",status:"supported",summary:"Split a multi-device frame by moving some of its devices into a new frame beside it.",studioCommands:[],wire:"structuralOperations: frame.split",targets:["frame","device"],requiredInputs:["frameId","a non-empty proper subset of its deviceIds"],evaluationCases:["structure-split-two-device-frame"]},{id:"frame.combine",domain:"frame",status:"supported",summary:"Merge one frame into another, keeping every device and caption, and drop the emptied frame.",studioCommands:[],wire:"structuralOperations: frame.combine",targets:["frame"],requiredInputs:["frameId (the survivor)","fromFrameId (the frame merged into it)"],evaluationCases:["structure-combine-last-two-frames"]},{id:"device.look",domain:"device",status:"supported",summary:"Restyle a device: camera angle, tilt, size, position, body colour, finish and lighting.",studioCommands:["patchShotLook"],wire:"patch.devices (by deviceId) or the complete patch.shots array",targets:["device"],requiredInputs:["deviceId","the look fields to change"],limits:["The raw camera 3-vector is not writable; the Agent moves the sanctioned orbit axis instead."],evaluationCases:["device-frame-two-clockwise","device-frame-one-gold","device-alternating-clay","device-frame-three-smaller-right","multi-device-spread-frame-two"]},{id:"device.move-to-frame",domain:"device",status:"supported",summary:"Move a device into an existing frame, at a chosen position among that frame’s devices.",studioCommands:["moveShotToFrame","moveShotToPanel","reorderShots"],wire:"structuralOperations: device.move",targets:["device","frame"],requiredInputs:["deviceId","toFrameId","toIndex (optional)"],evaluationCases:["structure-combine-last-two-frames"]},{id:"device.reorder",domain:"device",status:"supported",summary:"Reorder devices inside their own frame.",studioCommands:["moveShot"],wire:"structuralOperations: device.reorder",targets:["device"],requiredInputs:["deviceId","toIndex"],evaluationCases:["structure-reorder-devices-in-frame"]},{id:"device.remove",domain:"device",status:"supported",summary:"Remove one device while its frame stays.",studioCommands:["removeShot"],wire:"structuralOperations: device.remove",targets:["device"],requiredInputs:["deviceId"],limits:["The project’s last remaining device cannot be removed."],evaluationCases:["structure-remove-second-device"]},{id:"device.add",domain:"device",status:"supported",summary:"Add a device to a frame from a screenshot supplied with this instruction.",studioCommands:["addShot"],wire:"structuralOperations: device.add, naming an assetId from AVAILABLE SCREENSHOTS",targets:["frame"],requiredInputs:["toFrameId","assetId","toIndex (optional)"],withoutAssetReason:"Adding a device needs a screenshot sent with the instruction. This one carried none.",limits:["Only a screenshot listed in AVAILABLE SCREENSHOTS; the Agent never invents or generates pixels.","A device created this cycle can only be addressed in the next one, after Studio reports its id.","It lands on the default device look, exactly as dropping a screenshot into Studio does."],evaluationCases:["asset-add-supplied-screenshot"]},{id:"device.replace-pixels",domain:"asset",status:"supported",summary:"Replace the screenshot shown on an existing device, keeping the device untouched.",studioCommands:["reskinShots","ordinalReskin"],wire:"structuralOperations: device.replace, naming an assetId from AVAILABLE SCREENSHOTS",targets:["device"],requiredInputs:["deviceId","assetId"],withoutAssetReason:"Changing what a device shows needs the new screenshot sent with the instruction. This one carried none.",limits:["Only a screenshot listed in AVAILABLE SCREENSHOTS; the Agent never invents or generates pixels.","The device keeps its look, placement, captions, translated screens and Output membership — only the pixels change."],evaluationCases:["asset-replace-device-screenshot"]},{id:"caption.text",domain:"caption",status:"supported",summary:"Rewrite the headline words on frames.",studioCommands:["patchCaptionLayer"],wire:"the complete patch.captions array",targets:["project","frame","caption"],requiredInputs:["the complete caption list, one entry per frame"],limits:["Only each frame’s first caption layer, in the base language.","Hand-placed caption anchors and per-language fit overrides stay manual."],evaluationCases:["copy-all-six-words","copy-frame-two-exact","selection-caption-shorter"]},{id:"caption.style",domain:"caption",status:"supported",summary:"Restyle captions: font, size, colour, alignment, width and band placement.",studioCommands:["patchAllCaptionStyles"],wire:"patch.captionStyle (strip-wide) or patch.frames[i].captionStyle (one frame)",targets:["project","frame"],requiredInputs:["the style fields to change"],evaluationCases:["style-all-captions-smaller","style-selected-caption-white-left"]},{id:"caption.add",domain:"caption",status:"supported",summary:"Add a caption layer to a frame, with its words and styling.",studioCommands:["addCaptionLayer"],wire:"structuralOperations: caption.add",targets:["frame"],requiredInputs:["frameId","the caption text"],evaluationCases:["structure-subtitle-each-frame"]},{id:"caption.remove",domain:"caption",status:"supported",summary:"Remove one caption layer from a frame.",studioCommands:["removeCaptionLayer"],wire:"structuralOperations: caption.remove",targets:["caption"],requiredInputs:["frameId","the caption position"],evaluationCases:["structure-remove-subtitle"]},{id:"caption.reorder",domain:"caption",status:"supported",summary:"Reorder the caption layers stacked on one frame.",studioCommands:["reorderCaptionLayer"],wire:"structuralOperations: caption.move within one frame",targets:["caption"],requiredInputs:["frameId","the caption position","its new position"],evaluationCases:["structure-reorder-captions"]},{id:"caption.move-to-frame",domain:"caption",status:"supported",summary:"Move a caption layer to another frame.",studioCommands:["moveCaptionLayer","moveCaptionLayerToFrame"],wire:"structuralOperations: caption.move across frames",targets:["caption","frame"],requiredInputs:["frameId","the caption position","toFrameId"],evaluationCases:["structure-move-caption-to-frame"]},{id:"caption.translate",domain:"caption",status:"intentionally_excluded",summary:"Write caption words in a non-base language.",studioCommands:["applyCaptionTranslations","clearCaptionTranslation"],wire:null,targets:["project"],requiredInputs:[],reason:"Agent refinement cannot translate captions. Open Translate in Studio to create German or other language versions while retaining the base words.",evaluationCases:["unsupported-translate-captions"]},{id:"caption.output-override",domain:"caption",status:"intentionally_excluded",summary:"Give an output family its own caption wording.",studioCommands:["patchOutputCaption","clearOutputCaption"],wire:null,targets:["caption"],requiredInputs:[],reason:"Agent refinement edits shared captions. Studio has manual output-family caption wording; both iPhone sizes share one family and cannot have separate words.",evaluationCases:["unsupported-per-output-caption"]},{id:"strip.background",domain:"look",status:"supported",summary:"Change the strip backdrop: gradient stops, angle, shadow and floor reflection.",studioCommands:["patchConfig"],wire:"patch.background",targets:["project"],requiredInputs:["the backdrop fields to change"],limits:["The canvas size a Look is authored against stays a Studio control.","Per-frame solid colours are set through the frame backdrop, not the strip config."],evaluationCases:["background-strip-navy-gradient"]},{id:"frame.background",domain:"look",status:"supported",summary:"Give one frame its own backdrop.",studioCommands:["setPanelBackground"],wire:"patch.frames[i].background",targets:["frame"],requiredInputs:["the frame","the backdrop fields"],evaluationCases:["background-frame-one-amber","background-frame-three-flat-teal","inspection-correct-frame-two-background"]},{id:"frame.background-reset",domain:"look",status:"intentionally_excluded",summary:"Drop one or all frame backdrops so they inherit the strip again.",studioCommands:["clearPanelBackground","clearAllPanelBackgrounds"],wire:null,targets:["frame"],requiredInputs:[],reason:"Agent refinement cannot reset backdrop inheritance. Use the frame background reset control in Studio to return it to the strip default.",evaluationCases:["unsupported-frame-background-reset"]},{id:"strip.background-broadcast",domain:"look",status:"intentionally_excluded",summary:"Copy one frame’s backdrop onto every frame, or promote it to the strip default.",studioCommands:["applyBackgroundToAllPanels","setStripDefaultBackground"],wire:null,targets:["project"],requiredInputs:[],reason:"No Studio surface offers these transfers today; the Agent writes the strip backdrop directly.",evaluationCases:["unsupported-background-broadcast"]},{id:"frame.color",domain:"look",status:"intentionally_excluded",summary:"Set the legacy per-panel colour that sits under a frame’s backdrop.",studioCommands:["setPanelColor"],wire:null,targets:["frame"],requiredInputs:[],reason:"No Studio surface dispatches it. A flat colour is a one-stop frame backdrop (`frame.background`), so a request for one is carried out there, never refused.",evaluationCases:["background-frame-three-flat-teal"]},{id:"look.design-preset",domain:"look",status:"supported",summary:"Apply a named design preset to the whole strip.",studioCommands:[],wire:"patch.designPreset",targets:["project"],requiredInputs:["a catalog preset id"],evaluationCases:["styling-apply-design-preset"]},{id:"look.layout-template",domain:"look",status:"supported",summary:"Apply a layout template, or explicitly reset one frame to its saved template baseline.",studioCommands:["applyLayoutTemplate","resetFrameTemplate"],wire:"patch.layout, or structuralOperations: frame.template-reset",targets:["project","frame"],requiredInputs:["a catalog layout id, or the frameId named in an explicit reset/revert request"],limits:["Never reset implicitly while handling a general styling request; reset may remove added screens or captions."],evaluationCases:["layout-use-bleed"]},{id:"look.apply-saved",domain:"look",status:"intentionally_excluded",summary:"Restore the project’s saved Look, or one of its earlier versions.",studioCommands:["applyLook"],wire:null,targets:["project"],requiredInputs:[],reason:"Agent refinement cannot restore a saved Look. Restore the saved version through Look version history in Studio.",evaluationCases:["unsupported-restore-saved-look"]},{id:"output.membership",domain:"output",status:"supported",summary:"Add or remove the store output sizes this project renders for.",studioCommands:["addOutput","removeOutput","setActiveOutput"],wire:"patch.outputs",targets:["project"],requiredInputs:["the complete output list"],limits:["Which output is previewed on screen stays a Studio cursor."],evaluationCases:["project-add-android-output"]},{id:"locale.membership",domain:"locale",status:"supported",summary:"Add or remove the languages this project is captioned in.",studioCommands:["addLocale","removeLocale"],wire:"patch.locales",targets:["project"],requiredInputs:["the complete language list"],limits:["The base language cannot be removed, and which language is being authored stays a Studio cursor."],evaluationCases:["project-add-german-locale","geometry-clear-while-adding-a-language"]},{id:"strip.add-screens",domain:"asset",status:"supported",summary:"Add new screenshots to the project, each in its own frame.",studioCommands:["addShots"],wire:"structuralOperations: frame.add with a frameRef, then device.add into it, once per screenshot from AVAILABLE SCREENSHOTS",targets:["project"],requiredInputs:["one or more authorized screenshot references"],withoutAssetReason:"New frames need new pixels. Send the screenshots with the instruction and the Agent will place them.",limits:["Only screenshots listed in AVAILABLE SCREENSHOTS; the Agent never invents or generates pixels.","Each new frame starts without a caption and its device on the default look, exactly as adding screenshots in Studio does."],evaluationCases:["asset-add-screens-supplied","asset-add-screens-needs-pixels"]},{id:"strip.replace-screens",domain:"asset",status:"supported",summary:"Replace every screenshot in the project, keeping the styling.",studioCommands:["loadScreens"],wire:"structuralOperations: device.replace on every device in strip order, each naming its own assetId from AVAILABLE SCREENSHOTS",targets:["project"],requiredInputs:["a complete authorized screenshot set"],withoutAssetReason:"Replacing the whole strip needs the whole new set of pixels. This instruction carried none.",limits:["Only screenshots listed in AVAILABLE SCREENSHOTS; the Agent never invents or generates pixels.","Every device keeps its look, placement, captions, translated screens and Output membership — only the pixels change.","When the supplied screenshots do not match the devices one to one, the Agent asks which goes where instead of swapping some of them."],evaluationCases:["asset-replace-all-screens-supplied","asset-replace-all-screens-needs-pixels","asset-replace-all-screens-count-mismatch"]},{id:"locale.load-screens",domain:"asset",status:"requires_asset",summary:"Supply localized screenshots for one language.",studioCommands:["loadLocaleScreens"],wire:null,targets:["project"],requiredInputs:["the language","authorized screenshots named for the frames they belong to"],reason:"A localized screen is different pixels, not a different caption.",evaluationCases:["asset-locale-screens-needs-pixels"]},{id:"output.load-screens",domain:"asset",status:"requires_asset",summary:"Supply screenshots captured at another output size.",studioCommands:["loadOutputScreens"],wire:null,targets:["project"],requiredInputs:["the output family","authorized screenshots named for the frames they belong to"],reason:"A second output size needs its own captures; the Agent cannot resample one from another.",evaluationCases:["asset-output-screens-needs-pixels"]}],Sr="unknown",Ir=[{id:"image.generate",summary:"Generate or paint new imagery rather than arranging supplied screenshots."},{id:"animation.create",summary:"Animate a screen, produce a video, or export motion instead of stills."},{id:"device.unsupported-model",summary:"Use a device model ShotOps does not offer."}],xr=wr.map(e=>e.id);[...xr,...Ir.map(e=>e.id)];const Ar=7,Ye={front:{x:0,y:0,z:-1},left:{x:-2.6,y:.6,z:-5.2},right:{x:2.6,y:.6,z:-5.2}};function Wt(e){const t=Ye[e]??Ye.front,n=Math.hypot(t.x,t.y,t.z),r=Ar/n;return{x:t.x*r,y:t.y*r,z:t.z*r}}function Pr(e){return Math.atan2(e.x,-e.z)*180/Math.PI}const Ht=[{code:"ar-SA",name:"Arabic",script:"rtl",dir:"rtl"},{code:"bn-BD",name:"Bengali",script:"indic",dir:"ltr"},{code:"ca",name:"Catalan",script:"latin",dir:"ltr"},{code:"cs",name:"Czech",script:"latin",dir:"ltr"},{code:"da",name:"Danish",script:"latin",dir:"ltr"},{code:"de-DE",name:"German",script:"latin",dir:"ltr"},{code:"el",name:"Greek",script:"greek",dir:"ltr"},{code:"en-AU",name:"English (Australia)",script:"latin",dir:"ltr"},{code:"en-CA",name:"English (Canada)",script:"latin",dir:"ltr"},{code:"en-GB",name:"English (U.K.)",script:"latin",dir:"ltr"},{code:"en-US",name:"English (U.S.)",script:"latin",dir:"ltr"},{code:"es-ES",name:"Spanish (Spain)",script:"latin",dir:"ltr"},{code:"es-MX",name:"Spanish (Mexico)",script:"latin",dir:"ltr"},{code:"fi",name:"Finnish",script:"latin",dir:"ltr"},{code:"fr-CA",name:"French (Canada)",script:"latin",dir:"ltr"},{code:"fr-FR",name:"French",script:"latin",dir:"ltr"},{code:"gu-IN",name:"Gujarati",script:"indic",dir:"ltr"},{code:"he",name:"Hebrew",script:"rtl",dir:"rtl"},{code:"hi",name:"Hindi",script:"indic",dir:"ltr"},{code:"hr",name:"Croatian",script:"latin",dir:"ltr"},{code:"hu",name:"Hungarian",script:"latin",dir:"ltr"},{code:"id",name:"Indonesian",script:"latin",dir:"ltr"},{code:"it",name:"Italian",script:"latin",dir:"ltr"},{code:"ja",name:"Japanese",script:"cjk",dir:"ltr"},{code:"kn-IN",name:"Kannada",script:"indic",dir:"ltr"},{code:"ko",name:"Korean",script:"cjk",dir:"ltr"},{code:"ml-IN",name:"Malayalam",script:"indic",dir:"ltr"},{code:"mr-IN",name:"Marathi",script:"indic",dir:"ltr"},{code:"ms",name:"Malay",script:"latin",dir:"ltr"},{code:"nl-NL",name:"Dutch",script:"latin",dir:"ltr"},{code:"no",name:"Norwegian",script:"latin",dir:"ltr"},{code:"or-IN",name:"Odia",script:"indic",dir:"ltr"},{code:"pa-IN",name:"Punjabi",script:"indic",dir:"ltr"},{code:"pl",name:"Polish",script:"latin",dir:"ltr"},{code:"pt-BR",name:"Portuguese (Brazil)",script:"latin",dir:"ltr"},{code:"pt-PT",name:"Portuguese (Portugal)",script:"latin",dir:"ltr"},{code:"ro",name:"Romanian",script:"latin",dir:"ltr"},{code:"ru",name:"Russian",script:"cyrillic",dir:"ltr"},{code:"sk",name:"Slovak",script:"latin",dir:"ltr"},{code:"sl-SI",name:"Slovenian",script:"latin",dir:"ltr"},{code:"sv",name:"Swedish",script:"latin",dir:"ltr"},{code:"ta-IN",name:"Tamil",script:"indic",dir:"ltr"},{code:"te-IN",name:"Telugu",script:"indic",dir:"ltr"},{code:"th",name:"Thai",script:"thai",dir:"ltr"},{code:"tr",name:"Turkish",script:"latin",dir:"ltr"},{code:"uk",name:"Ukrainian",script:"cyrillic",dir:"ltr"},{code:"ur-PK",name:"Urdu",script:"rtl",dir:"rtl"},{code:"vi",name:"Vietnamese",script:"latin",dir:"ltr"},{code:"zh-Hans",name:"Chinese (Simplified)",script:"cjk",dir:"ltr"},{code:"zh-Hant",name:"Chinese (Traditional)",script:"cjk",dir:"ltr"}];Ht.map(e=>e.code);Object.fromEntries(Ht.map(e=>[e.code,e]));({...Oe});function Cr(e,t){t.material==="clay"?(e.setClay(t.clayTone==="custom"?`#${t.clayCustom}`:t.clayTone),e.setClearcoat(0)):(e.clayOff(),t.colorway==="custom"?e.setCustomColor(`#${t.customColor}`):e.setColorway(t.colorway),e.setFinish(M("finish",t.finish)),e.setClearcoat(M("clearcoat",t.clearcoat)))}function kr(e,t,n){e.screen.setGlare(!n&&t?e.device.environmentMap():null)}async function Or(e,t,n,r){const{stage:o,device:a,screen:s}=e,i=t.material==="clay";if(t.cameraPos?o.setCameraPosition(t.cameraPos):o.setAngle(t.angle),a.setRoll(M("roll",t.roll)),Cr(a,t),s.restoreScreen(),o.setStudioLighting(t.lighting),a.setReflections(t.reflections),s.setFlatScreen(t.flatScreen),n){try{await s.applyWallpaper(n)}catch{}if(!r())return}kr(e,t.glare,i)}const Tr=""+new URL("iphone-optimized-BdcJzlHi.glb",import.meta.url).href,Er="data:model/gltf-binary;base64,Z2xURgIAAADUAAAAwAAAAEpTT057ImFzc2V0Ijp7InZlcnNpb24iOiIyLjAiLCJnZW5lcmF0b3IiOiJTaG90T3BzIHBsYWNlaG9sZGVyIOKAlCB0aGUgUGl4ZWwgbW9kZWwgaXMgZGVsaWJlcmF0ZWx5IG5vdCBidW5kbGVkIGluIHRoZSBucG0gcGFja2FnZSJ9LCJzY2VuZXMiOlt7Im5hbWUiOiJwaXhlbC1ub3QtYnVuZGxlZCIsIm5vZGVzIjpbXX1dLCJzY2VuZSI6MH0gICA=",Lr=[{id:"grey",label:"Grey",color:11579568},{id:"white",label:"White",color:15263458},{id:"charcoal",label:"Charcoal",color:3815996}],Mr=[{id:"blue",label:"Deep Blue",frame:3290954,back:4409953,accent:2172211},{id:"silver",label:"Silver",frame:16119285,back:16514043,accent:13816532},{id:"orange",label:"Cosmic Orange",frame:16219693,back:16487504,accent:12738072},{id:"ice",label:"Glacier",frame:15266559,back:15463679,accent:11450047},{id:"red",label:"Burgundy",frame:5052449,back:6435900,accent:3805721},{id:"black",label:"Black",frame:3947580,back:5460819,accent:2960685}],Rr=[{id:"silver",label:"Moonstone",frame:9345186,back:8621205,accent:7041658},{id:"black",label:"Obsidian",frame:2763308,back:2565928,accent:2105377},{id:"orange",label:"Porcelain",frame:15920872,back:14670805,accent:11973550},{id:"green",label:"Jade",frame:9412240,back:8688005,accent:7042924}],ne={id:"iphone-17-pro",glb:Tr,fitSize:3.6,baseEuler:{x:0,y:0,z:0},pruneNamePrefixes:[],screen:{material:"OLED",repeat:{x:-1,y:1},coverFill:1.001,coverCornerRatio:.18,coverRepeat:{x:-1,y:-1}},body:{frame:["Anodized aluminum"],back:["Frosted glass"],accent:["Plastic antena","PaletteMaterial001"]},colorways:Mr},Xe={id:"pixel-10-pro",glb:Er,fitSize:3.6,baseEuler:{x:0,y:Math.PI,z:0},pruneNamePrefixes:["Google Pixel 10 Pro Moonstone.1"],screen:{material:"GP10p_display",repeat:{x:1,y:1},coverFill:1.001,coverCornerRatio:.14,coverRepeat:{x:1,y:-1}},body:{frame:["GP10p_mid","GP10p_camera"],back:["GP10p_back","GP10p_plastic"],accent:["GP10p_logo"]},colorways:Rr},Fr={[ne.id]:ne,[Xe.id]:Xe};function Me(e){return e&&Fr[e]||ne}function we(e){const t=Wt(e);return new z(t.x,t.y,t.z)}const Nr=1.4;function _r(e,t){return(t?new z(t.x,t.y,t.z):we(e)).multiplyScalar(Nr)}const Re=35;function Br(e){e.traverse(t=>{const n=t;n.geometry?.dispose();const r=n.material;Array.isArray(r)?r.forEach(Je):r&&Je(r)}),e.clear()}function Je(e){for(const t of Object.values(e))t&&typeof t=="object"&&t.isTexture&&t.dispose();e.dispose()}function Gt(e,t){const n=document.createElement("canvas"),r=new yn({canvas:n,antialias:!0,preserveDrawingBuffer:!0,alpha:!0});r.setSize(e,t,!1),r.shadowMap.enabled=!0;const o=new ln;o.background=null;const{ambient:a,directionals:s}=zr(o),i=new Pe(Re,e/t,.01,100);i.position.copy(we("front")),i.lookAt(0,0,0);function c(f){i.position.copy(we(f)),i.lookAt(0,0,0)}function l(f){i.position.set(f.x,f.y,f.z),i.lookAt(0,0,0)}function d(f){s.forEach(g=>g.visible=f),a.intensity=f?.75:1.6}let p=!1;function u(){p||(p=!0,o.environment?.dispose(),o.environment=null,Br(o),r.dispose(),r.forceContextLoss())}return{scene:o,camera:i,renderer:r,dispose:u,setAngle:c,setCameraPosition:l,getCameraPosition:()=>({x:i.position.x,y:i.position.y,z:i.position.z}),onUserPose:()=>{},previewOrbit:()=>{},commitOrbit:()=>{},setOrbitEnabled:()=>{},setBackground:()=>{},setStudioLighting:d,resize:()=>{},invalidate:()=>{}}}function zr(e){const t=new dn(16777215,.75);e.add(t);const n=new ie(16777215,2.2);n.position.set(3,5,5);const r=new ie(12571903,.7);r.position.set(-4,1,2);const o=new ie(16777215,1);o.position.set(0,3,-5);const a=[n,r,o];return a.forEach(s=>e.add(s)),{ambient:t,directionals:a}}function $t(e,t){const n=Me(t);return new Promise((r,o)=>{new cn().load(n.glb,a=>{const s=a.scene;if(n.pruneNamePrefixes.length){const u=[];s.traverse(f=>{n.pruneNamePrefixes.some(g=>f.name.startsWith(g))&&u.push(f)}),u.forEach(f=>f.removeFromParent())}s.rotation.set(n.baseEuler.x,n.baseEuler.y,n.baseEuler.z),s.updateMatrixWorld(!0);const i=new bn().setFromObject(s),c=i.getSize(new z),l=i.getCenter(new z),d=n.fitSize/Math.max(c.x,c.y,c.z);s.scale.multiplyScalar(d),s.position.copy(l.multiplyScalar(-d));const p=new vn;p.add(s),e.scene.add(p),e.setAngle("front"),r(p)},void 0,o)})}function jr(e){return $t(e)}const Ze=1900,Qe=2800,Dr=8192,Ur=2;async function Wr(e,t,n,r={}){const o=e.renderer,a=o.getPixelRatio(),s=o.getSize(new gt);o.setDrawingBufferSize(t,n,1);let i;r.cameraPosition?(i=new Pe(Re,t/n,.01,100),i.position.copy(r.cameraPosition),i.lookAt(0,0,0)):(i=e.camera.clone(),i.aspect=t/n,i.updateProjectionMatrix());try{const c=e.scene.background;e.scene.background=null;try{o.render(e.scene,i)}finally{e.scene.background=c}const l=document.createElement("canvas");let d=null;try{l.width=t,l.height=n,l.getContext("2d")?.drawImage(o.domElement,0,0);const p=Vt(l),u=p.canvas;d=u;const f=u.width,g=u.height;return{bytes:await new Promise((h,y)=>{u.toBlob(v=>{if(!v){y(new Error("toBlob returned null"));return}v.arrayBuffer().then(b=>h(new Uint8Array(b)),y)},"image/png")}),width:f,height:g,frame:{width:t,height:n,cropX:p.x,cropY:p.y}}}finally{d&&d!==l&&(d.width=0,d.height=0),l.width=0,l.height=0}}finally{o.setDrawingBufferSize(s.x,s.y,a),e.invalidate()}}function Vt(e,t=Ur){const n=e.getContext("2d",{willReadFrequently:!0});if(!n)return{canvas:e,x:0,y:0};const{width:r,height:o}=e,a=n.getImageData(0,0,r,o).data;let s=r,i=o,c=-1,l=-1;for(let f=0;f<o;f++)for(let g=0;g<r;g++)a[(f*r+g)*4+3]!==0&&(g<s&&(s=g),g>c&&(c=g),f<i&&(i=f),f>l&&(l=f));if(c<s||l<i)return{canvas:e,x:0,y:0};s=Math.max(0,s-t),i=Math.max(0,i-t),c=Math.min(r-1,c+t),l=Math.min(o-1,l+t);const d=c-s+1,p=l-i+1,u=document.createElement("canvas");return u.width=d,u.height=p,u.getContext("2d")?.drawImage(e,s,i,d,p,0,0,d,p),{canvas:u,x:s,y:i}}function Hr(e){const t=URL.createObjectURL(new Blob([e],{type:"image/png"}));return new Promise((n,r)=>{const o=new Image;o.onload=()=>{URL.revokeObjectURL(t),n(o)},o.onerror=()=>{URL.revokeObjectURL(t),r(new Error("Screenshot could not be decoded for the flat card"))},o.src=t})}function Gr(e,t,n,r){if(e.beginPath(),r<=0){e.rect(0,0,t,n);return}e.moveTo(r,0),e.arcTo(t,0,t,n,r),e.arcTo(t,n,0,n,r),e.arcTo(0,n,0,0,r),e.arcTo(0,0,t,0,r),e.closePath()}function $r(e,t,n,r){const o=t?"naturalWidth"in t?t.naturalWidth:t.width:0,a=t?"naturalHeight"in t?t.naturalHeight:t.height:0,s=fr(o,a,n,r),{width:i,height:c,cardWidth:l,cardHeight:d,radius:p,rotation:u}=s;e.width=i,e.height=c;const f=e.getContext("2d");if(!f)throw new Error("2D context unavailable for the flat card");return f.translate(i/2,c/2),f.rotate(u),f.translate(-l/2,-d/2),Gr(f,l,d,p),f.clip(),t?(f.imageSmoothingQuality="high",f.drawImage(t,0,0,l,d)):(f.fillStyle="#000",f.fillRect(0,0,l,d)),s}async function Vr(e,t,n){return(await qt(e,t,n)).out}async function qt(e,t,n){const r=e?await Hr(e):null,o=document.createElement("canvas");try{const a=$r(o,r,t,n),{width:s,height:i}=a;return{out:{bytes:await new Promise((l,d)=>{o.toBlob(p=>{if(!p){d(new Error("toBlob returned null"));return}p.arrayBuffer().then(u=>l(new Uint8Array(u)),d)},"image/png")}),width:s,height:i,frame:{width:s,height:i,cropX:0,cropY:0}},geometry:a}}finally{o.width=0,o.height=0}}const et=24*1024*1024,Se=new WeakMap;async function qr(e){const t=await nr(e.bytes);return Ie({look:e.look,screenshot:t,width:e.width,height:e.height,physicalBody:e.physicalBody,screenLayers:e.screenLayers})}function Kr(e,t){const n=Se.get(e);if(!n)return;const r=n.entries.get(t);if(r)return n.entries.delete(t),n.entries.set(t,r),r}function Yr(e,t,n){const r=n.bytes.byteLength;if(r>et)return;let o=Se.get(e);o||(o={entries:new Map,bytes:0},Se.set(e,o));const a=o.entries.get(t);a&&(o.bytes-=a.bytes.byteLength),o.entries.delete(t),o.entries.set(t,n),o.bytes+=r;const s=Array.from(o.entries.keys());for(let i=0;i<s.length&&o.bytes>et;i++){const c=o.entries.get(s[i]);c&&(o.bytes-=c.bytes.byteLength,o.entries.delete(s[i]))}}function Ie(e){if(e===null||typeof e!="object")return JSON.stringify(e)??"null";if(Array.isArray(e))return`[${e.map(Ie).join(",")}]`;const t=e;return`{${Object.keys(t).filter(r=>t[r]!==void 0).sort().map(r=>`${JSON.stringify(r)}:${Ie(t[r])}`).join(",")}}`}function Xr(e,t,n,r,o){return{x:(e.x+1)/2*t-r,y:(1-e.y)/2*n-o}}function Jr(e){const{width:t,height:n,cardWidth:r,cardHeight:o,rotation:a}=e,s=Math.cos(a),i=Math.sin(a),c=(p,u)=>({x:t/2+p*s-u*i,y:n/2+p*i+u*s}),l=r/2,d=o/2;return{tl:c(-l,-d),tr:c(l,-d),br:c(l,d),bl:c(-l,d)}}function le(e){return new Promise((t,n)=>{e.toBlob(r=>{if(!r){n(new Error("toBlob returned null"));return}r.arrayBuffer().then(o=>t(new Uint8Array(o)),n)},"image/png")})}function tt(e,t,n,r,o){const a=document.createElement("canvas");return a.width=r,a.height=o,a.getContext("2d")?.drawImage(e,t,n,r,o,0,0,r,o),a}function Zr(e,t){const n=Math.hypot(e.tr.x-e.tl.x,e.tr.y-e.tl.y),r=Math.hypot(e.bl.x-e.tl.x,e.bl.y-e.tl.y);return n>0?Math.min(n,r)*t/n:0}async function Qr(e,t,n,r,o,a={}){const s=e.renderer,i=s.getPixelRatio(),c=s.getSize(new gt);s.setDrawingBufferSize(n,r,1);let l;a.cameraPosition?(l=new Pe(Re,n/r,.01,100),l.position.copy(a.cameraPosition),l.lookAt(0,0,0)):(l=e.camera.clone(),l.aspect=n/r,l.updateProjectionMatrix()),l.updateMatrixWorld();const d=[],p=()=>{const u=document.createElement("canvas");return u.width=n,u.height=r,d.push(u),u};try{const u=p(),f=p(),g=p(),m=e.scene.background;e.scene.background=null;try{s.render(e.scene,l),u.getContext("2d")?.drawImage(s.domElement,0,0);try{t.setLayerPass("device"),s.render(e.scene,l),f.getContext("2d")?.drawImage(s.domElement,0,0),t.setLayerPass("screen"),s.render(e.scene,l),g.getContext("2d")?.drawImage(s.domElement,0,0)}finally{t.restoreLayerPass()}}finally{e.scene.background=m}const h=Vt(u);h.canvas!==u&&d.push(h.canvas);const y=h.canvas.width,v=h.canvas.height,b=tt(f,h.x,h.y,y,v),S=tt(g,h.x,h.y,y,v);d.push(b,S),e.scene.updateMatrixWorld();const C=t.screenCornersWorld(),x=T=>{const B=T.clone().project(l);return Xr(B,n,r,h.x,h.y)},w={x:0,y:0},I=C?{tl:x(C.tl),tr:x(C.tr),br:x(C.br),bl:x(C.bl)}:{tl:w,tr:w,br:w,bl:w},[A,P,O]=[await le(h.canvas),await le(b),await le(S)];return{bytes:A,width:y,height:v,frame:{width:n,height:r,cropX:h.x,cropY:h.y},layers:{width:y,height:v,device:P,screen:{bytes:O,quad:I,cornerRadiusFrac:Zr(I,t.cornerRatio),sourceNodeId:o}}}}finally{d.forEach(u=>{u.width=0,u.height=0}),s.setDrawingBufferSize(c.x,c.y,i),e.invalidate()}}async function eo(e,t,n,r){const{out:o,geometry:a}=await qt(e,t,n);return to(o,a,r)}function to(e,t,n){const r=Jr(t);return{...e,layers:{width:e.width,height:e.height,device:null,screen:{bytes:e.bytes,quad:r,cornerRadiusFrac:t.cardWidth>0?t.radius/t.cardWidth:0,sourceNodeId:n}}}}function no(e,t,n){return{shots:e,panels:t,selectedShotId:n.selectedShotId,panelPresetId:n.panelPresetId,bgMode:n.bgMode,gradientStops:n.gradientStops,gradientAngle:n.gradientAngle,gradientFrom:n.gradientFrom,gradientTo:n.gradientTo,gradientDir:n.gradientDir,panelColors:n.panelColors,shadow:n.shadow,floorReflection:n.floorReflection,panelBackgrounds:n.panelBackgrounds,captionStyles:n.captionStyles,captionText:n.captionText,locales:n.locales,baseLocale:n.baseLocale,outputs:n.outputs}}function ro(e,t){return e.usesPhysicalFinish()?!0:t.material!=="clay"&&M("clearcoat",t.clearcoat)>0}async function oo(e,t,n,r,o,a){const s=K(n,r),i=s.filter(g=>g.bytes);if(i.length===0)return null;const c=q(o.panelPresetId),l=new Map(r.map((g,m)=>[g.id,m])),d=o.renderScale!=null&&Number.isFinite(o.renderScale)&&o.renderScale>0?o.renderScale:1,p=Math.min(d,Dr/Math.max(Ze,Qe)),u=Math.max(1,Math.round(Ze*p)),f=Math.max(1,Math.round(Qe*p));{const g=[];for(let v=0;v<i.length;v++){const b=i[v];a(`Rendering ${v+1}/${i.length}${o.locale?` (${o.locale})`:""}…`);let S,C;const x=b.frameNodeId||null,w=o.screenLayers||!b.bytes?null:await qr({look:b.look,bytes:b.bytes,width:u,height:f,physicalBody:ro(t.device,b.look),screenLayers:!1}),I=w?Kr(e,w):void 0;if(I)S=I;else if(pr(b.look)){await Or(t,b.look,b.bytes,()=>!0);const A=_r(b.look.angle,b.look.cameraPos);if(o.screenLayers){const P=await Qr(e,t.screen,u,f,x,{cameraPosition:A});S=P,C=P.layers}else S=await Wr(e,u,f,{cameraPosition:A})}else if(o.screenLayers){const A=await eo(b.bytes,b.look,f,x);S=A,C=A.layers}else S=await Vr(b.bytes,b.look,f);w&&!I&&Yr(e,w,S),g.push({shotId:b.id,bytes:S.bytes,width:S.width,height:S.height,heightFrac:Tn(M("deviceSize",b.look.deviceSize)),hOffset:M("hOffset",b.look.hOffset)/100,vOffset:M("vOffset",b.look.vOffset)/100,panelIndex:l.get(b.panelId)??0,...b.look.clipToFrame===!0?{clipToFrame:!0}:{},...C?{layers:C}:{}})}const m=cr(g,c.width,c.height),h=dr(r,o);a("Saving project…");const y=Ut(no(s,r,o));return{panelWidth:c.width,panelHeight:c.height,count:r.length,background:h,phones:m,shadow:o.shadow,floorReflection:o.floorReflection??!1,project:JSON.stringify(y)}}}function re(e){return/^[0-9a-fA-F]{3,8}$/.test(e)?`#${e}`:e}function xe(e,t,n,r){const{x0:o,y0:a,x1:s,y1:i}=Gn(n,r,t.angle),c=e.createLinearGradient(o,a,s,i);for(const l of t.stops)c.addColorStop(Math.min(1,Math.max(0,l.at)),re(l.color));return c}function J(e,t,n,r,o,a,s){const i=document.createElement("canvas");i.width=n,i.height=r;try{const c=i.getContext("2d");if(!c)return;c.fillStyle=xe(c,t,n,r),c.fillRect(o,0,a,r),e.drawImage(i,o,0,a,r,s,0,a,r)}finally{i.width=0,i.height=0}}function nt(e){return URL.createObjectURL(new Blob([e],{type:"image/png"}))}function rt(e){return new Promise((t,n)=>{const r=new Image;r.onload=()=>t(r),r.onerror=n,r.src=e})}const ao=16*1024*1024;function ot(e){const t=(e.img.naturalWidth||0)*(e.img.naturalHeight||0),n=e.reflection?e.reflection.canvas.width*e.reflection.canvas.height:0;return t+n}function Kt(){let e=0;const t=Array.from(_.values());for(const o of t)e+=ot(o);const n=Array.from(_.keys());let r=0;for(;e>ao&&r<n.length-1;){const o=_.get(n[r]);o&&(e-=ot(o),o.reflection&&(o.reflection.canvas.width=0,o.reflection.canvas.height=0),_.delete(n[r])),r++}}const _=new Map,ce=new Map;async function so(e,t){if(!t){const a=nt(e);try{return{img:await rt(a)}}finally{URL.revokeObjectURL(a)}}const n=_.get(e);if(n)return _.delete(e),_.set(e,n),n;const r=ce.get(e);if(r)return r;const o=(async()=>{const a=nt(e);try{return{img:await rt(a)}}finally{URL.revokeObjectURL(a)}})();ce.set(e,o);try{const a=await o;return _.set(e,a),Kt(),a}finally{ce.delete(e)}}async function io(e,t,n){const r=t.panelWidth*t.count,o=t.panelHeight,a=n?.backgroundViewport,s=a?t.panelWidth*a.panelCount:r,i=a?t.panelWidth*a.panelIndex:0,c=n?.panelViewport,l=c===void 0?0:c*t.panelWidth,d=c===void 0?r:t.panelWidth;e.width=d,e.height=o;const p=e.getContext("2d");if(!p)return;n?.transparentBg?p.clearRect(0,0,r,o):t.background.kind==="gradient"?c!==void 0?J(p,t.background.gradient,r,o,l,d,0):a?J(p,t.background.gradient,s,o,i,r,0):(p.fillStyle=xe(p,t.background.gradient,r,o),p.fillRect(0,0,r,o)):t.background.kind==="perPanel"?t.background.colors.forEach((m,h)=>{p.fillStyle=re(m),p.fillRect(h*t.panelWidth-l,0,t.panelWidth,o)}):t.background.fills.forEach((m,h)=>{const y=h*t.panelWidth-l;c!==void 0&&h!==c||(m.kind==="solid"?(p.fillStyle=re(m.color),p.fillRect(y,0,t.panelWidth,o)):c!==void 0?J(p,m.gradient,r,o,l,d,0):a?J(p,m.gradient,s,o,i+y,t.panelWidth,y):(p.fillStyle=xe(p,m.gradient,r,o),p.fillRect(y,0,t.panelWidth,o)))}),p.save(),p.translate(-l,0);const u=n?.phoneRange?Math.max(0,n.phoneRange.start):0,f=n?.phoneRange?Math.min(t.phones.length,n.phoneRange.end):t.phones.length,g=n?.reuseDecodedPhones===!0;for(let m=u;m<f;m++){const h=t.phones[m],y=n?.clip==="panel"||n?.clip===void 0&&h.clipToFrame===!0;if(n?.skipShotId&&h.shotId===n.skipShotId)continue;const v=await so(h.bytes,g),b=v.img;y&&(p.save(),p.beginPath(),p.rect(h.panelIndex*t.panelWidth,0,t.panelWidth,o),p.clip()),t.floorReflection&&lo(p,v,h,g),p.save(),t.shadow&&(p.shadowColor="rgba(0,0,0,0.35)",p.shadowBlur=t.panelWidth*.03,p.shadowOffsetY=t.panelHeight*.012),p.drawImage(b,h.x,h.y,h.width,h.height),p.restore(),y&&p.restore()}p.restore()}function lo(e,t,n,r){const o=Math.round(n.height*.45);if(o<=0||n.width<=0)return;const a=r?t.reflection:void 0;if(a&&a.width===n.width&&a.height===n.height){e.drawImage(a.canvas,n.x,n.y+n.height,n.width,o);return}const s=t.img,i=document.createElement("canvas");i.width=Math.max(1,n.width),i.height=Math.max(1,o);const c=i.getContext("2d");if(!c)return;c.save(),c.translate(0,o),c.scale(1,-1),c.drawImage(s,0,o-n.height,n.width,n.height),c.restore();const l=c.createLinearGradient(0,0,0,o);l.addColorStop(0,"rgba(0,0,0,0.34)"),l.addColorStop(1,"rgba(0,0,0,0)"),c.globalCompositeOperation="destination-in",c.fillStyle=l,c.fillRect(0,0,n.width,o),e.drawImage(i,n.x,n.y+n.height,n.width,o),r&&(t.reflection={width:n.width,height:n.height,canvas:i},Kt())}const Yt=Ce.lineHeight,co=Ce.bandInset,uo=Ce.bandCenter;function po(e,t,n){if(!e)return[t];const r=t.split(/\s+/).filter(Boolean),o=[];let a="";for(const s of r){const i=a?`${a} ${s}`:s;a&&e.measureText(i).width>n?(o.push(a),a=s):a=i}return a&&o.push(a),o}function fo(e,t){if(!e)return 0;let n=0;for(const r of t)n=Math.max(n,e.measureText(r).width);return n}function Xt(e,t,n,r){const o=t.map((g,m)=>{const h=g.text.trim();if(!h)return null;const y=g.sizePt*(r/oe),v=ke(g.fontId).family;e&&(e.font=`${$} ${y}px "${v}"`);const b=po(e,h,g.maxWidth*n),S=y*(g.lineHeight??Yt),C=b.length*S,x=Math.max(C,(g.reserveLines??b.length)*S);return{layer:g,index:m,lines:b,px:y,lineH:S,width:fo(e,b),blockH:C,reservedH:x}}),a=o.filter(g=>g!==null&&D(g.layer.anchor)),s=a.filter(g=>g.layer.band==="bottom"),i=a.filter(g=>g.layer.band!=="bottom"),c=g=>g[0]?.layer.bandInset??co,l=(1-c(s))*r-s.reduce((g,m)=>g+m.reservedH,0);let d=c(i)*r,p=l,u=0;const f=[];for(const g of o){if(!g)continue;if(!D(g.layer.anchor)){f.push({layer:g.layer,index:g.index,x:g.layer.anchor.x*n,yTop:g.layer.anchor.y*r,lines:g.lines,px:g.px,lineH:g.lineH,width:g.width});continue}const m=g.layer.band==="bottom",y=(m?p:d)+(g.reservedH-g.blockH)/2,v=(g.layer.bandCenter??uo)*n;f.push({layer:g.layer,index:g.index,x:v,yTop:y,lines:g.lines,px:g.px,lineH:g.lineH,width:g.width}),m?p+=g.reservedH:d+=g.reservedH,u=Math.max(u,y+g.blockH)}return{placed:f,bandBottom:u}}function ho(e,t,n,r){e.save(),e.textBaseline="top";const{placed:o}=Xt(e,t,n,r);for(const a of o){e.fillStyle=re(a.layer.color),e.textAlign=a.layer.align,e.font=`${$} ${a.px}px "${ke(a.layer.fontId).family}"`;let s=a.yTop;for(const i of a.lines)e.fillText(i,a.x,s),s+=a.lineH}e.restore()}function mo(e,t){return e.sizePt*(t/oe)*(e.lineHeight??Yt)}function go(e,t,n,r){const o=Xt(e,t,n,r).placed;e?.save(),e&&(e.textBaseline="top");const a=o.map(s=>{const i=s.layer.align==="center"?s.x-s.width/2:s.layer.align==="right"?s.x-s.width:s.x,c=s.lines.length*s.lineH;let l=s.yTop,d=s.yTop+c;if(e){e.font=`${$} ${s.px}px "${ke(s.layer.fontId).family}"`;const p=e.measureText(s.lines[0]).actualBoundingBoxAscent,u=e.measureText(s.lines[s.lines.length-1]).actualBoundingBoxDescent;Number.isFinite(p)&&Number.isFinite(u)&&(l=s.yTop-p,d=s.yTop+(s.lines.length-1)*s.lineH+u)}return{index:s.index,anchorX:s.x/n,top:s.yTop/r,left:i/n,width:s.width/n,height:c/r,inkTop:l/r,inkHeight:(d-l)/r}});return e?.restore(),a}function yo(e,t,n,r,o){t.forEach((a,s)=>{const i=o[a];!i||i.length===0||(e.save(),e.translate(s*n,0),ho(e,i,n,r),e.restore())})}const bo=""+new URL("Inter-SemiBold-B9yU462S.woff2",import.meta.url).href,vo=""+new URL("Manrope-SemiBold-44nuYf5T.woff2",import.meta.url).href,wo=""+new URL("Poppins-SemiBold-DJVo7c07.woff2",import.meta.url).href,So=""+new URL("Fraunces-SemiBold-BtraKtER.woff2",import.meta.url).href,Io=""+new URL("SpaceGrotesk-SemiBold-CyO2J5Y0.woff2",import.meta.url).href,xo={inter:bo,manrope:vo,poppins:wo,fraunces:So,"space-grotesk":Io},Ao=Q.map(e=>({...e,url:xo[e.id]}));let Z=null;function Po(){return Z||(Z=(async()=>{const e=new Set;document.fonts.forEach(t=>e.add(`${t.family}/${t.weight}`)),await Promise.all(Ao.filter(t=>!e.has(`${t.family}/${String($)}`)).map(async t=>{const n=new FontFace(t.family,`url(${t.url})`,{weight:String($)});await n.load(),document.fonts.add(n)})),await document.fonts.ready})().catch(e=>{throw Z=null,e})),Z}const Co=22/oe,ko=1.1,at=4,Oo=.063,To=.167,st=Math.round(Co*oe),Eo=.02,Lo=50;function j(e,t){const n=Math.max(e.x,t.x),r=Math.max(e.y,t.y),o=Math.min(e.x+e.width,t.x+t.width),a=Math.min(e.y+e.height,t.y+t.height);return o<=n||a<=r?null:{x:n,y:r,width:o-n,height:a-r}}function Jt(e,t){return j(e,t)}function it(e,t){const n=Math.abs(e-t)%360;return n>180?360-n:n}function lt(e){return Pr(e.cameraPos??Wt(e.angle))}function Fe(e,t,n,r,o,a,s){if(t.length===0)return[];const i=[];for(const c of go(e,t,o,a)){const l=t[c.index];if(!l)continue;const d=Jt({x:(r+c.left)*o,y:c.top*a,width:c.width*o,height:c.height*a},s);d&&i.push({ref:{panelId:n,panelIndex:r,layerIndex:c.index,band:D(l.anchor)},box:d,lineHeightPx:mo(l,a)})}return i}function Mo(e,t,n,r){return n.height<=Ae(e,t,r)}function Ae(e,t,n){const r=e.y+e.height/2<=t.y+t.height/2;return n*(r?To:Oo)}function Ro(e,t,n){return n.height<=Ae(e.box,t.box,e.lineHeightPx)+Ae(t.box,e.box,t.lineHeightPx)}function Fo(e){const{ctx:t,panelIds:n,panelWidth:r,panelHeight:o}=e,a={x:0,y:0,width:r*n.length,height:o};t?.save();try{return No(e,a)}finally{t?.restore()}}function No(e,t){const{ctx:n,panelIds:r,panelWidth:o,panelHeight:a,captionLayers:s}=e,i=r.flatMap((m,h)=>Fe(n,s[m]??[],m,h,o,a,t)),c=[];for(const m of e.phones){const y=e.clip==="panel"||e.clip===void 0&&m.clipToFrame===!0?{x:m.panelIndex*o,y:0,width:o,height:a}:t,v=Jt({x:m.x,y:m.y,width:m.width,height:m.height},y);v&&c.push({shotId:m.shotId,box:v,layoutHeight:m.height})}const l=[];for(let m=0;m<i.length;m++)for(let h=m+1;h<i.length;h++){const y=j(i[m].box,i[h].box);y&&l.push({a:i[m].ref,b:i[h].ref,overlap:y,depthFrac:a>0?y.height/a:0,inkUncertain:Ro(i[m],i[h],y)})}const d=[];for(const m of i)for(const h of c){const y=j(m.box,h.box);y&&d.push({caption:m.ref,shotId:h.shotId,overlap:y,depthFrac:a>0?y.height/a:0,inkUncertain:Mo(m.box,h.box,y,m.lineHeightPx)})}const p=[];for(let m=0;m<c.length;m++)for(let h=m+1;h<c.length;h++){const y=c[m],v=c[h],b=j(y.box,v.box);if(!b)continue;const S=[],C=Math.max(y.layoutHeight,v.layoutHeight),x=Math.min(y.layoutHeight,v.layoutHeight);x>0&&C/x>=ko&&S.push("scale");const w=e.looks?.[y.shotId],I=e.looks?.[v.shotId],A=!!w&&!!I;w&&I&&(it(lt(w),lt(I))>=at&&S.push("angle"),it(M("roll",w.roll),M("roll",I.roll))>=at&&S.push("roll"));const P=Math.min(y.box.width*y.box.height,v.box.width*v.box.height);p.push({shotIdA:y.shotId,shotIdB:v.shotId,overlap:b,coverage:P>0?b.width*b.height/P:0,deliberate:S.length>0,signals:S,anglesKnown:A})}const u=new Set;for(const m of l)m.a.band&&u.add(m.a.panelId),m.b.band&&u.add(m.b.panelId);for(const m of d)m.caption.band&&u.add(m.caption.panelId);const f=[],g=[];return r.forEach((m,h)=>{if(!u.has(m))return;const y=_o(e,m,h,t,i,c);y!==null&&g.push({panelId:m,maxWidth:y});const v=Bo(e,m,h,t,i,c);v&&f.push(v)}),{captionsMeasurable:n!=null,captionOverlaps:l,captionDeviceOverlaps:d,deviceOverlaps:p,suggestions:f,widthSuggestions:g,hasWarning:l.length>0||d.length>0||p.some(m=>!m.deliberate)}}function _o(e,t,n,r,o,a){const s=e.captionLayers[t]??[];if(!s.length||s.some(l=>!D(l.anchor)))return null;const i=[...a.map(l=>l.box),...o.filter(l=>l.ref.panelId!==t).map(l=>l.box)],c=Math.min(...s.map(l=>l.maxWidth));for(let l=Math.ceil(c*100)-1;l>=10;l--){const d=l/100,p=Fe(e.ctx,s.map(u=>({...u,maxWidth:d})),t,n,e.panelWidth,e.panelHeight,r);if(p.length&&p.every((u,f)=>!i.some(g=>j(u.box,g))&&!p.slice(f+1).some(g=>j(u.box,g.box))))return d}return null}function Bo(e,t,n,r,o,a){const s=e.captionLayers[t]??[],i=s.flatMap((d,p)=>D(d.anchor)&&d.text.trim()?[p]:[]);if(i.length===0||!(Math.min(...i.map(d=>s[d].sizePt))>st))return null;const l=[...a.map(d=>d.box),...o.filter(d=>!(d.ref.panelId===t&&d.ref.band)).map(d=>d.box)];for(let d=1;d<=Lo;d++){const p=Math.round((1-d*Eo)*100)/100,u=new Map(i.map(h=>[h,s[h].sizePt*p]));if(Math.min(...u.values())<st)return null;const f=s.map((h,y)=>{const v=u.get(y);return v===void 0?h:{...h,sizePt:v}});if(Fe(e.ctx,f,t,n,e.panelWidth,e.panelHeight,r).filter(h=>h.ref.band).every(h=>!l.some(y=>j(h.box,y))))return{panelId:t,scale:p,layers:i.map(h=>({layerIndex:h,fromSizePt:s[h].sizePt,toSizePt:u.get(h)}))}}return null}ne.colorways;class Zt{frame=[];back=[];accent=[];allBody=[];model;scene;renderer;profile;envTexture=null;constructor(t,n,r,o){this.model=t,this.scene=n,this.renderer=r,this.profile=Me(o);const{frame:a,back:s,accent:i}=this.profile.body;t.traverse(c=>{const l=c;if(!l.isMesh)return;(Array.isArray(l.material)?l.material:[l.material]).forEach(p=>{const u=p;!u||!u.name||(a.includes(u.name)?this.push(this.frame,u):s.includes(u.name)?this.push(this.back,u):i.includes(u.name)&&this.push(this.accent,u),this.push(this.allBody,u))})})}push(t,n){t.includes(n)||t.push(n)}get finishMaterials(){return[...this.frame,...this.back]}paint(t,n){const r=n instanceof L?n:new L(n);t.forEach(o=>{o.color=r.clone(),o.needsUpdate=!0})}setColorway(t){if(t==="custom")return;const n=this.profile.colorways.find(r=>r.id===t)??this.profile.colorways[0];n&&(this.paint(this.frame,n.frame),this.paint(this.back,n.back),this.paint(this.accent,n.accent))}setCustomColor(t){const n=new L(t),r=n.clone().lerp(new L(16777215),.2),o=n.clone().multiplyScalar(.6);this.paint(this.frame,n),this.paint(this.back,r),this.paint(this.accent,o)}setFinish(t){const n=Number.isFinite(t)?Math.max(0,Math.min(1,t)):0;this.finishMaterials.forEach(r=>{r.userData.baseRoughness===void 0&&(r.userData.baseRoughness=r.roughness);const o=r.userData.baseRoughness;r.roughness=o*(1-n),r.needsUpdate=!0})}clearcoatUpgraded=!1;usesPhysicalFinish(){return this.clearcoatUpgraded}setClearcoat(t){const n=Math.max(0,Math.min(1,t));n>0&&!this.clearcoatUpgraded&&this.upgradeFinishToPhysical(),this.clearcoatUpgraded&&this.finishMaterials.forEach(r=>{const o=r;o.clearcoat=n,o.clearcoatRoughness=.1,o.needsUpdate=!0})}upgradeFinishToPhysical(){this.clearcoatUpgraded=!0;const t=new Map;for(const r of Array.from(new Set(this.finishMaterials))){const o=new un;o.color.copy(r.color),o.metalness=r.metalness,o.roughness=r.roughness,o.map=r.map,o.normalMap=r.normalMap,o.normalScale.copy(r.normalScale),o.roughnessMap=r.roughnessMap,o.metalnessMap=r.metalnessMap,o.aoMap=r.aoMap,o.aoMapIntensity=r.aoMapIntensity,o.emissive.copy(r.emissive),o.emissiveMap=r.emissiveMap,o.emissiveIntensity=r.emissiveIntensity,o.envMapIntensity=r.envMapIntensity,o.transparent=r.transparent,o.opacity=r.opacity,o.alphaTest=r.alphaTest,o.side=r.side,o.flatShading=r.flatShading,o.vertexColors=r.vertexColors,o.name=r.name,o.userData={...r.userData},o.clearcoat=0,t.set(r,o)}this.model.traverse(r=>{const o=r;if(o.isMesh)if(Array.isArray(o.material))o.material=o.material.map(a=>t.get(a)??a);else{const a=t.get(o.material);a&&(o.material=a)}});const n=r=>r.map(o=>t.get(o)??o);this.frame=n(this.frame),this.back=n(this.back),this.allBody=n(this.allBody)}environmentMap(){if(!this.envTexture){const t=new wn(this.renderer);this.envTexture=t.fromScene(new pn,.04).texture,t.dispose()}return this.envTexture}setClay(t){const n=Lr.find(o=>o.id===t),r=n?new L(n.color):new L(t);this.allBody.forEach(o=>{o.userData.clayStashedMap===void 0&&(o.userData.clayStashedMap=o.map),o.color=r.clone(),o.metalness=0,o.roughness=.85,o.map=null,o.needsUpdate=!0})}clayOff(){this.allBody.forEach(t=>{t.userData.clayStashedMap!==void 0&&(t.map=t.userData.clayStashedMap,t.userData.clayStashedMap=void 0,t.needsUpdate=!0)})}setReflections(t){this.scene.environment=t?this.environmentMap():null}setRoll(t){this.model.rotation.z=t*Math.PI/180}}const ct=1.35;class Qt{materials=[];glassOverlays=[];screenMesh=null;flatPlane=null;texture=null;appliedBytes=null;flatScreenOn=!1;profile;model;passRestore=[];constructor(t,n){this.profile=Me(n),this.model=t;const r=this.profile.screen.material;t.traverse(o=>{const a=o;if(!a.isMesh)return;(Array.isArray(a.material)?a.material:[a.material]).forEach(i=>{const c=i;c&&c.name===r&&!this.materials.includes(c)&&(this.materials.push(c),this.screenMesh=a)})}),this.dimGlassOverlay(t),this.prepareScreen(),this.setGlare(null)}get found(){return this.materials.length>0}setGlare(t){this.materials.forEach(n=>{n.envMap=t,n.envMapIntensity=t?.6:0,n.metalness=t?.5:0,n.roughness=t?.15:1,n.needsUpdate=!0}),this.glassOverlays.forEach(n=>{n.opacity=t?.08:0,n.needsUpdate=!0})}setFlatScreen(t){if(this.flatScreenOn=t,!this.screenMesh)return;if(this.flatPlane){this.screenMesh.remove(this.flatPlane);const b=this.flatPlane.material;b.map?.dispose(),b.dispose(),this.flatPlane.geometry.dispose(),this.flatPlane=null}if(!t||!this.texture)return;this.screenMesh.geometry.computeBoundingBox();const n=this.screenMesh.geometry.boundingBox;if(!n)return;const r=n.max.x-n.min.x,o=n.max.y-n.min.y,a=n.max.z-n.min.z,s=(n.max.x+n.min.x)/2,i=(n.max.y+n.min.y)/2,c=(n.max.z+n.min.z)/2,l=o<=r&&o<=a?"y":a<=r&&a<=o?"z":"x",d=this.texture.clone();d.needsUpdate=!0,d.colorSpace=ze,d.flipY=!1,d.center.set(.5,.5),d.wrapS=X,d.wrapT=X;const{coverFill:p,coverCornerRatio:u,coverRepeat:f}=this.profile.screen;d.repeat.set(f.x,f.y);const g=l==="x"?a:r,m=l==="z"||l==="x"?o:a,h=Math.min(g,m)*p*u,y=zo(g*p,m*p,h),v=new Sn(y,new fn({map:d,emissive:new L(16777215),emissiveMap:d,emissiveIntensity:ct,color:new L(0),toneMapped:!1,side:In,depthTest:!0,depthWrite:!0,polygonOffset:!0,polygonOffsetFactor:-4,polygonOffsetUnits:-4}));l==="y"?(v.rotation.x=-Math.PI/2,v.position.set(s,n.max.y,c)):l==="x"?(v.rotation.y=Math.PI/2,v.position.set(n.max.x,i,c)):v.position.set(s,i,n.max.z),v.renderOrder=999,this.screenMesh.add(v),this.flatPlane=v}setLayerPass(t){this.restoreLayerPass();const n=a=>{const s=a.visible;a.visible=!1,this.passRestore.push(()=>{a.visible=s})};if(t==="screen"){this.model.traverse(a=>{const s=a;if(!s.isMesh||s===this.flatPlane)return;(Array.isArray(s.material)?s.material:[s.material]).forEach(c=>{c&&!this.materials.includes(c)&&n(c)})});return}this.glassOverlays.forEach(n);const r=a=>new An({blending:kn,blendEquation:Cn,blendSrc:je,blendDst:je,depthTest:!0,depthWrite:!0,side:a?.side??Pn,polygonOffset:a?.polygonOffset??!1,polygonOffsetFactor:a?.polygonOffsetFactor??0,polygonOffsetUnits:a?.polygonOffsetUnits??0}),o=(a,s)=>{const i=a.material;if(!(Array.isArray(i)?i:[i]).some(s))return;const c=[],l=d=>{if(!s(d))return d;const p=r(d);return c.push(p),p};a.material=Array.isArray(i)?i.map(l):l(i),this.passRestore.push(()=>{a.material=i,c.forEach(d=>d.dispose())})};this.model.traverse(a=>{const s=a;s.isMesh&&(s===this.flatPlane?o(s,()=>!0):o(s,i=>this.materials.includes(i)))})}restoreLayerPass(){const t=this.passRestore.reverse();this.passRestore=[],t.forEach(n=>n())}screenCornersWorld(){const t=this.screenMesh;if(!t)return null;const n=t.geometry;n.computeBoundingBox();const r=n.boundingBox,o=n.attributes.position,a=n.attributes.uv;if(!r||!o||!a)return null;const s=r.getSize(new z),i=r.getCenter(new z),c=s.y<=s.x&&s.y<=s.z?"y":s.z<=s.x&&s.z<=s.y?"z":"x",[l,d]=c==="y"?["x","z"]:c==="z"?["x","y"]:["z","y"],p=this.profile.screen.coverFill,{repeat:u}=this.profile.screen,f={};for(const v of[-1,1])for(const b of[-1,1]){const S=new z;S[c]=r.max[c],S[l]=i[l]+v*s[l]*p/2,S[d]=i[d]+b*s[d]*p/2;let C=-1,x=1/0;for(let P=0;P<o.count;P++){const O=Math.hypot(o.getComponent(P,"xyz".indexOf(l))-S[l],o.getComponent(P,"xyz".indexOf(d))-S[d]);O<x&&(x=O,C=P)}if(C<0)return null;const w=.5+(a.getX(C)-.5)*u.x,I=.5+(a.getY(C)-.5)*u.y;if(w===.5||I===.5)return null;const A=`${I<.5?"t":"b"}${w<.5?"l":"r"}`;if(f[A])return null;f[A]=S}const{tl:g,tr:m,br:h,bl:y}=f;return!g||!m||!h||!y?null:(t.updateWorldMatrix(!0,!1),{tl:g.applyMatrix4(t.matrixWorld),tr:m.applyMatrix4(t.matrixWorld),br:h.applyMatrix4(t.matrixWorld),bl:y.applyMatrix4(t.matrixWorld)})}get cornerRatio(){return this.profile.screen.coverCornerRatio}restoreScreen(){this.prepareScreen()}prepareScreen(){this.materials.forEach(t=>{t.color=new L(0),t.emissive=new L(16777215),t.emissiveIntensity=1,t.roughness=1,t.metalness=0,t.needsUpdate=!0})}dimGlassOverlay(t){t.traverse(n=>{const r=n;if(!r.isMesh)return;(Array.isArray(r.material)?r.material:[r.material]).forEach(a=>{const s=a;s&&s.name!==this.profile.screen.material&&s.transparent&&s.opacity>.2&&this.glassOverlays.push(s)})})}applyWallpaper(t){if(this.appliedBytes===t&&this.texture)return this.lightScreen(this.texture),Promise.resolve();const n=new Blob([t],{type:"image/png"}),r=URL.createObjectURL(n),o=this.texture;return new Promise((a,s)=>{const i=new Image;i.onload=()=>{try{const c=document.createElement("canvas");c.width=i.naturalWidth,c.height=i.naturalHeight;const l=c.getContext("2d");if(!l)throw new Error("2D context unavailable for wallpaper blit");l.drawImage(i,0,0);const d=new hn(c);d.colorSpace=ze,d.flipY=!1,d.center.set(.5,.5),d.wrapS=X,d.wrapT=X,d.repeat.set(this.profile.screen.repeat.x,this.profile.screen.repeat.y),d.needsUpdate=!0,this.texture=d,this.appliedBytes=t,this.lightScreen(d),this.flatScreenOn&&this.setFlatScreen(!0),o?.dispose(),URL.revokeObjectURL(r),a()}catch(c){URL.revokeObjectURL(r),s(c)}},i.onerror=()=>{URL.revokeObjectURL(r),s(new Error("wallpaper image failed to decode"))},i.src=r})}lightScreen(t){this.materials.forEach(n=>{n.map=t,n.emissiveMap=t,n.emissive=new L(16777215),n.emissiveIntensity=ct,n.color=new L(0),n.needsUpdate=!0})}}function zo(e,t,n){const r=e/2,o=t/2,a=Math.min(n,r,o),s=new mn;s.moveTo(-r+a,-o),s.lineTo(r-a,-o),s.quadraticCurveTo(r,-o,r,-o+a),s.lineTo(r,o-a),s.quadraticCurveTo(r,o,r-a,o),s.lineTo(-r+a,o),s.quadraticCurveTo(-r,o,-r,o-a),s.lineTo(-r,-o+a),s.quadraticCurveTo(-r,-o,-r+a,-o);const i=new gn(s,16),c=i.attributes.position,l=new Float32Array(c.count*2);for(let d=0;d<c.count;d++)l[d*2]=(c.getX(d)+r)/e,l[d*2+1]=(c.getY(d)+o)/t;return i.setAttribute("uv",new xn(l,2)),i}function Ne(e){return`build-shot-${e+1}`}function en(e){const t=[];for(const n of e.shots)t.includes(n.panelId)||t.push(n.panelId);return t}const jo=1900,Do=2800;function Uo(e){return new Promise((t,n)=>{e.toBlob(r=>{if(!r)return n(new Error("canvas toBlob returned null"));r.arrayBuffer().then(o=>t(new Uint8Array(o)),n)},"image/png")})}async function tn(e,t,n,r={}){await Po();const o=en(e);if(r.panelViewport!==void 0&&(!Number.isInteger(r.panelViewport)||r.panelViewport<0||r.panelViewport>=o.length))throw new Error("buildStrip: panel viewport is outside the strip");const a=o.map(u=>({id:u})),s=e.shots.map((u,f)=>({id:Ne(f),panelId:u.panelId,frameNodeId:"",frameName:`screen-${f+1}`,bytes:t.screens[f]??null,look:u.look,thumb:null,thumbStale:!1})),c={panelPresetId:q(e.panelPresetId).id,bgMode:e.bgMode,gradientStops:e.gradientStops,gradientAngle:e.gradientAngle,gradientFrom:e.gradientFrom,gradientTo:e.gradientTo,gradientDir:e.gradientDir,panelColors:e.panelColors,shadow:e.shadow,floorReflection:e.floorReflection,panelBackgrounds:e.panelBackgrounds,selectedShotId:null,renderScale:r.renderScale,locale:n},l=r.onProgress??(()=>{});let d=r.refs,p=null;if(!d){const u=Mn(e.panelPresetId);p=Gt(jo,Do);const f=await $t(p,u);d={stage:p,device:new Zt(f,p.scene,p.renderer,u),screen:new Qt(f,u)}}try{const u=await oo(d.stage,d,s,a,c,l);if(!u)throw new Error("buildStrip: nothing renderable (no shots)");const f=document.createElement("canvas");try{const g={...r.panelViewport!==void 0?{panelViewport:r.panelViewport}:{},...r.clip?{clip:r.clip}:{},...r.backgroundViewport?{backgroundViewport:r.backgroundViewport}:{}};await io(f,u,Object.keys(g).length>0?g:void 0);const m=u.panelWidth,h=u.panelHeight,y=f.getContext("2d");if(!y)throw new Error("buildStrip: 2D context unavailable");y.save(),r.panelViewport!==void 0&&y.translate(-r.panelViewport*m,0),yo(y,o,m,h,t.captionText??{}),y.restore();const v=Fo({phones:u.phones,panelIds:o,captionLayers:t.captionText??{},panelWidth:m,panelHeight:h,ctx:y,looks:Object.fromEntries(s.map(I=>[I.id,I.look])),clip:r.clip}),b=r.renderScale&&r.renderScale>0&&r.renderScale<1?r.renderScale:1,S=[],C=r.panelViewport??0,x=r.panelViewport===void 0?u.count:C+1;for(let I=C;I<x;I++){const A=document.createElement("canvas");A.width=Math.max(1,Math.round(m*b)),A.height=Math.max(1,Math.round(h*b));const P=A.width,O=A.height;try{const T=A.getContext("2d");if(!T)throw new Error("buildStrip: 2D context unavailable");T.drawImage(f,r.panelViewport===void 0?I*m:0,0,m,h,0,0,P,O),S.push({index:I,bytes:await Uo(A),width:P,height:O})}finally{A.width=0,A.height=0}}const w=u.phones.map(({shotId:I,panelIndex:A,x:P,y:O,width:T,height:B})=>({shotId:I,panelIndex:A,x:P,y:O,width:T,height:B}));return{panels:S,layout:v,phones:w}}finally{f.width=0,f.height=0}}finally{p&&p.dispose()}}const dt=.005,Wo=.02,Ho=12;function de(e){return Math.max(1,Math.round(e*100))}function ue(e){return`${e.kind}:${e.frames.join(",")}:${e.anchored}`}function Go(e,t){const n=new Map(e.suggestions.map(s=>[s.panelId,s.scale])),r=new Map((e.widthSuggestions??[]).map(s=>[s.panelId,s.maxWidth])),o=[];for(const s of e.captionOverlaps){if(s.inkUncertain||s.depthFrac<dt)continue;const[i,c]=s.a.band===s.b.band?[s.a,s.b]:s.a.band?[s.a,s.b]:[s.b,s.a],l=pe([t.frameOfPanel(i.panelId),t.frameOfPanel(c.panelId)]);l.length!==0&&o.push({kind:"caption-caption",frames:l,depthPct:de(s.depthFrac),anchored:!s.a.band||!s.b.band,...ut(n,i.band?i.panelId:null),...pt(r,i.band?i.panelId:null)})}for(const s of e.captionDeviceOverlaps){if(s.inkUncertain||s.depthFrac<dt)continue;const i=pe([t.frameOfPanel(s.caption.panelId),t.frameOfShot(s.shotId)]);i.length!==0&&o.push({kind:"caption-device",frames:i,depthPct:de(s.depthFrac),anchored:!s.caption.band,...ut(n,s.caption.band?s.caption.panelId:null),...pt(r,s.caption.band?s.caption.panelId:null)})}for(const s of e.deviceOverlaps){if(s.deliberate||s.coverage<Wo)continue;const i=pe([t.frameOfShot(s.shotIdA),t.frameOfShot(s.shotIdB)]);i.length!==0&&o.push({kind:"device-device",frames:i,depthPct:de(s.coverage),anchored:!1})}const a=new Map;for(const s of o){const i=a.get(ue(s));i?s.depthPct>i.depthPct?a.set(ue(s),{...s,clearAtScale:s.clearAtScale??i.clearAtScale,clearAtMaxWidth:s.clearAtMaxWidth??i.clearAtMaxWidth}):i.clearAtScale==null&&s.clearAtScale!=null&&(i.clearAtScale=s.clearAtScale):a.set(ue(s),s),i&&i.clearAtMaxWidth==null&&s.clearAtMaxWidth!=null&&(i.clearAtMaxWidth=s.clearAtMaxWidth)}return[...a.values()].sort((s,i)=>i.depthPct-s.depthPct).slice(0,Ho).sort((s,i)=>s.frames[0]-i.frames[0]||s.kind.localeCompare(i.kind))}function pe(e){const[t,...n]=e;return t<0?[]:[t,...n.filter(r=>r>=0&&r!==t)]}function ut(e,t){const n=t==null?void 0:e.get(t);return n==null?{}:{clearAtScale:Math.round(n*100)/100}}function pt(e,t){const n=t==null?void 0:e.get(t);return n==null?{}:{clearAtMaxWidth:n}}function $o(e,t){if(t.length===0)return e;const n=e.captionStyles;if(!n)return e;const r={};for(const[o,a]of Object.entries(n))r[o]=a.map(s=>({...s}));for(const o of t){const a=r[o.panelId];if(a)for(const s of o.layers){const i=a[s.layerIndex];i&&(i.sizePt=s.toSizePt)}}return{...e,captionStyles:r}}function fe(e){return e.frames.map(t=>`frame ${t+1}`).join(" + ")}function Vo(e,t,n){if(!e.captionsMeasurable)return null;const r=Go(e,t);if(r.length===0)return null;const o=r.filter(l=>l.kind==="device-device"),a=r.filter(l=>l.kind!=="device-device"&&l.clearAtScale==null);if(o.length>0||a.length>0||!n){const l=[];o.length>0&&l.push(`${o.map(fe).join(", ")}: two devices overlap without reading as composed. There is no deterministic repair — give the pair a real difference in scale, camera angle or roll (that is what makes an overlap read as deliberate), or leave it if it already is.`);for(const d of a)l.push(d.anchored?`${fe(d)}: the caption is anchored by hand, so it is reported and never rewritten — move it, or drop its \`anchor\` to let the band place it.`:`${fe(d)}: no caption size above the legibility floor clears it — shorten the headline, or pick a layout with a bigger text region (\`style.layout: "bleed"\`).`);return l.length===0&&l.push("The rendered look was not available here, so no corrected look could be built."),{findings:r,note:`No corrected look is offered. ${l.join(" ")}`}}const s=new Set(r.filter(l=>l.kind!=="device-device").map(l=>l.frames[0])),i=e.suggestions.filter(l=>s.has(t.frameOfPanel(l.panelId))),c=i.flatMap(l=>{const d=t.frameOfPanel(l.panelId)+1;return l.layers.map(p=>`frame ${d} layer ${p.layerIndex+1}: sizePt ${p.fromSizePt} → ${p.toSizePt}`)}).join("; ");return{findings:r,correctedLook:$o(n,i),note:`\`layout.correctedLook\` is this same look with every caption shrunk to the largest size that was verified to clear the overlap (${c}). Nothing here is applied for you — re-render with it, or show the user the finding and let them decide. On render_strip pass it back as \`look\` together with the SAME \`style.captions\` you just sent: the words come from \`style.captions\` and every style field you leave out of them now comes from this look. The one thing that still beats it is a field you set EXPLICITLY on a caption entry, so if your \`style.captions\` pin \`sizePt\` at the original numbers, drop them or set them to the sizes above.`}}function qo(e){return String(Math.max(-100,Math.min(100,e*35)))}const Ko=["roll","deviceSize","hOffset","vOffset","finish","clearcoat"];function ft(e){if(!e||typeof e!="object")return{};const t={...e};for(const n of Ko)typeof t[n]=="number"&&(t[n]=String(t[n]));return t}function Yo(e){const{subtitle:t,sizePt:n,maxWidth:r,...o}=e;return{...o,...n!==void 0?{sizePt:Number(n)}:{},...r!==void 0?{maxWidth:Number(r)}:{}}}function ht(e){const t={};for(const[n,r]of Object.entries(e))r!==void 0&&(t[n]=r);return t}function he(e,t,n){const r={};return e&&t.forEach((o,a)=>{const s=n[a];s!==void 0&&e[o]!==void 0&&(r[s]=e[o])}),r}function Xo(e){const t=e.slotSizes.filter(w=>Number.isInteger(w)&&w>0),n=t.map((w,I)=>`panel-${I+1}`);let r={};const o=e.look&&typeof e.look=="object"?e.look:null,a=e.style??null,s=o&&Array.isArray(o.shots)?o.shots:[],i=s.length>0,c=a?ft(a.shotLook):null,l=[];let d=0;t.forEach((w,I)=>{for(let A=0;A<w;A++){const P=i?ft(s[d]?.look??s[0]?.look??{}):c??{},O=P.hOffset!==void 0&&P.hOffset!==null?String(P.hOffset):qo(A);l.push({panelId:n[I],look:{...k,...P,hOffset:O}}),d++}});let p={},u={},f={},g="gradient",m=zn,h=jn,y="vertical",v,b,S=!0,C=!1;if(o){g=o.bgMode==="perPanel"?"perPanel":"gradient";const w=te({gradientStops:Array.isArray(o.gradientStops)?o.gradientStops:void 0,gradientAngle:typeof o.gradientAngle=="number"?o.gradientAngle:void 0,gradientFrom:typeof o.gradientFrom=="string"?o.gradientFrom:m,gradientTo:typeof o.gradientTo=="string"?o.gradientTo:h,gradientDir:o.gradientDir==="horizontal"?"horizontal":y});v=w.stops,b=w.angle,{gradientFrom:m,gradientTo:h,gradientDir:y}=ee(w),o.shadow===!1&&(S=!1),o.floorReflection===!0&&(C=!0);const I=[];for(const A of s){const P=typeof A?.panelId=="string"?A.panelId:null;P&&!I.includes(P)&&I.push(P)}p=he(o.panelColors,I,n),u=he(Rt(o.captionStyles),I,n),f=he(Et(o.panelBackgrounds),I,n)}else if(a){const w=a.background??{};g=w.mode==="perPanel"?"perPanel":"gradient";const I=te({gradientStops:w.stops,gradientAngle:w.angle,gradientFrom:m,gradientTo:h,gradientDir:y});v=I.stops,b=I.angle,{gradientFrom:m,gradientTo:h,gradientDir:y}=ee(I),w.shadow===!1&&(S=!1),w.floorReflection===!0&&(C=!0),Array.isArray(w.panelColors)&&w.panelColors.forEach((A,P)=>{typeof A=="string"&&A&&n[P]!==void 0&&(p[n[P]]=A)})}if(a&&Array.isArray(a.captions)){const w=u,I=(T,B)=>({...w[T]?.[B]??{}}),A={},P={};a.captions.forEach((T,B)=>{const U=n[B];if(!(U===void 0||T===null||T===void 0)){if(Array.isArray(T)){const W=T.filter(R=>!!R&&typeof R=="object"&&typeof R.text=="string"&&R.text.trim()!=="").map((R,Y)=>({...I(U,Y),...ht(Yo(R))}));W.length>0&&(P[U]=W)}else if(typeof T=="object"){const{text:W,subtitle:R,sizePt:Y,maxWidth:Be,...sn}=T;A[U]={...I(U,0),...ht({...sn,...Y!==void 0?{sizePt:Number(Y)}:{},...Be!==void 0?{maxWidth:Number(Be)}:{}})},typeof W=="string"&&W.trim()&&(P[U]={headline:W,...typeof R=="string"&&R?{subtitle:R}:{}})}}});const O=se({[N]:P},Mt(A));u=Nt(O),r=Ft(O)}return{look:{panelPresetId:e.panelPresetId??(typeof o?.panelPresetId=="string"?o.panelPresetId:void 0)??"r69",bgMode:g,gradientStops:v,gradientAngle:b,gradientFrom:m,gradientTo:h,gradientDir:y,panelColors:p,shadow:S,floorReflection:C,panelBackgrounds:f,captionStyles:u,shots:l},panelIds:n,captionText:r}}function Jo(e){const t=e?.trim();return t?/\.(png|jpe?g|webp)$/i.test(t)?t:`${t}.png`:null}function Zo(e,t){const n=new Map;return e.map((r,o)=>{const a=Jo(t?.[o]);if(!a)return`screen-${o+1}.png`;const s=n.get(a)??0;if(n.set(a,s+1),s===0)return a;const i=a.lastIndexOf(".");return`${a.slice(0,i)}-${s+1}${a.slice(i)}`})}function Qo(e){const{look:t,panelIds:n,captionText:r,locale:o,shotNames:a,outputs:s,locales:i,baseLocale:c}=e,l=n.map(u=>({id:u})),d=Zo(t.shots,a),p=t.shots.map((u,f)=>({id:`shot-${f+1}`,panelId:u.panelId,frameNodeId:d[f],frameName:d[f],bytes:null,look:u.look,thumb:null,thumbStale:!0}));return Ut({shots:p,panels:l,selectedShotId:p[0]?.id??null,panelPresetId:t.panelPresetId,bgMode:t.bgMode,gradientStops:t.gradientStops,gradientAngle:t.gradientAngle,gradientFrom:t.gradientFrom,gradientTo:t.gradientTo,gradientDir:t.gradientDir,panelColors:t.panelColors,shadow:t.shadow,floorReflection:t.floorReflection,panelBackgrounds:t.panelBackgrounds,captionStyles:t.captionStyles,outputs:s,...i?{locales:i}:{},...c?{baseLocale:c}:{},captionText:r&&Object.keys(r).length>0?{[o||N]:r}:{}})}const ea=1900,ta=2800,mt=new Map;async function na(e){e("booting headless stage + loading model (once)…");const t=Gt(ea,ta),n=await jr(t);return{stage:t,device:new Zt(n,t.scene,t.renderer),screen:new Qt(n)}}function nn(e,t,n={}){let r=mt.get(e);r||(r={refs:na(n.onProgress??(()=>{})),tail:Promise.resolve()},mt.set(e,r));const{refs:o}=r,a=r.tail.then(async()=>t(await o));return r.tail=a.catch(()=>{}),a}function E(e){console.log("[render]",e)}function rn(e){const t=atob(e),n=new Uint8Array(t.length);for(let r=0;r<t.length;r++)n[r]=t.charCodeAt(r);return n}function _e(e){let t="";for(let n=0;n<e.length;n++)t+=String.fromCharCode(e[n]);return btoa(t)}function ra(e){return new Promise((t,n)=>{e.toBlob(async r=>{if(!r)return n(new Error("toBlob null"));t(_e(new Uint8Array(await r.arrayBuffer())))},"image/png")})}function on(e,t){const n=en(t),r=new Map(t.shots.map((a,s)=>[Ne(s),n.indexOf(a.panelId)])),o=Vo(e.layout,{frameOfPanel:a=>n.indexOf(a),frameOfShot:a=>r.get(a)??-1},t);if(o)return{layout:{findings:o.findings,...o.correctedLook?{correctedLook:o.correctedLook}:{}},layoutNote:o.note}}async function an(e){const t=await Promise.all(e.map(a=>createImageBitmap(new Blob([new Uint8Array(a.bytes)],{type:"image/png"})))),n=document.createElement("canvas");n.width=t.reduce((a,s)=>a+s.width,0),n.height=t[0]?.height??1;const r=n.getContext("2d");let o=0;for(const a of t)r.drawImage(a,o,0),o+=a.width,a.close();return{base64:await ra(n),width:n.width,height:n.height}}window.renderStrip=async function(t){try{if(!t||!Array.isArray(t.screenshots)||t.screenshots.length===0)throw new Error("renderStrip: input.screenshots must be a non-empty nested array of slots");const n=t.screenshots.map(b=>Array.isArray(b)?b:[b]),{look:r,panelIds:o,captionText:a}=Xo({slotSizes:n.map(b=>b.length),panelPresetId:t.panelPresetId,look:t.look??void 0,style:t.style??void 0}),s=n.flat().map(rn),i=Array.isArray(t.captionLayers)&&o[0]?{[o[0]]:t.captionLayers}:a,c=t.preview?.25:1;E(`buildStrip (${n.length} panel${n.length===1?"":"s"}${t.locale?`, ${t.locale}`:""})…`);let l=0;const d=await nn("visible",b=>(l=performance.now(),tn(r,{screens:s,captionText:i},t.locale,{refs:b,renderScale:c,onProgress:S=>E(" "+S),...t.clip?{clip:t.clip}:{},...Number.isInteger(t.panelViewport)?{panelViewport:t.panelViewport}:{},...t.backgroundViewport?{backgroundViewport:t.backgroundViewport}:{}})),{onProgress:E});E("encoding panels + stitching the strip preview…");const p=d.panels.map(b=>_e(b.bytes)),u=await an(d.panels),f=q(r.panelPresetId),g=Math.round(performance.now()-l),m=on(d,r),h=d.layout.captionsMeasurable,y=Array.isArray(t.screenshotNames)?t.screenshotNames.flat():void 0,v=t.buildRecord?Qo({look:r,panelIds:o,captionText:a,locale:t.locale,shotNames:y,outputs:t.outputs}):void 0;return E(`done: ${d.panels.length} panels, strip ${u.width}x${u.height}, ${g}ms`),{ok:!0,ms:g,count:d.panels.length,panelPresetId:f.id,panelWidth:f.width,panelHeight:f.height,stripWidth:u.width,stripHeight:u.height,panels:p,stripBase64:u.base64,preview:c<1,...v?{projectRecord:v}:{},...m??{},layoutMeasured:h,...t.layerBoxes?{layerBoxes:d.phones.map(({shotId:b,...S})=>({shot:r.shots.findIndex((C,x)=>Ne(x)===b),...S}))}:{}}}catch(n){const r=n&&n.stack?n.stack:String(n);return E("ERROR: "+r),{ok:!1,error:String(n&&n.message?n.message:n)}}};window.renderProject=async function(t){try{if(!t||t.projectFile==null||typeof t.projectFile!="object")throw new Error("renderProject: input.projectFile (the saved ProjectFile) is required");const n=yr(JSON.stringify(t.projectFile));if(!n)throw new Error("renderProject: the saved project could not be restored (wrong schema or malformed record)");const r=t.locale||n.baseLocale||n.locales?.[0]||"en-US",o=K(n.shots,n.panels),a=ye(t.variant||{},n.baseLocale),s=new Map((t.screenManifest||[]).map(x=>[`${x.shotId} ${$e(ye(x.variant||{},n.baseLocale))}`,x])),i=(x,w)=>s.get(`${x} ${$e(w)}`),c=o.map(x=>tr(i,x.id,a,Qn,n.baseLocale)),l=o.map((x,w)=>({frameName:x.frameName,matched:c[w].value!==void 0,requestedVariant:a,resolvedAt:c[w].resolvedAt,inherited:c[w].inherited,...c[w].value?.source?{source:c[w].value.source}:{}})),d=c.map(({value:x})=>x?.bytes?rn(x.bytes):null),p=Ft(n.captionText,r,n.baseLocale),u=vr({...n,selectedShotId:null,panelPresetId:t.panelPresetId??n.panelPresetId,captionText:{[r]:p}}),f=t.preview?.25:1;E(`renderProject (${o.length} shot${o.length===1?"":"s"}, ${r})…`);let g=0;const m=await nn("visible",x=>(g=performance.now(),tn(u,{screens:d,captionText:p},r,{refs:x,renderScale:f,onProgress:w=>E(" "+w)})),{onProgress:E});E("encoding panels + stitching the strip preview…");const h=m.panels.map(x=>_e(x.bytes)),y=await an(m.panels),v=q(u.panelPresetId),b=Math.round(performance.now()-g),S=on(m,u),C=m.layout.captionsMeasurable;return E(`done: ${m.panels.length} panels, strip ${y.width}x${y.height}, ${b}ms`),{ok:!0,ms:b,count:m.panels.length,panelPresetId:v.id,panelWidth:v.width,panelHeight:v.height,stripWidth:y.width,stripHeight:y.height,panels:h,stripBase64:y.base64,preview:f<1,shots:l,locale:r,...S??{},layoutMeasured:C}}catch(n){const r=n&&n.stack?n.stack:String(n);return E("ERROR: "+r),{ok:!1,error:String(n&&n.message?n.message:n)}}};window.__RENDER_READY=!0;E("harness ready ✓");
@@ -3,7 +3,7 @@
3
3
  <head>
4
4
  <meta charset="utf-8" />
5
5
  <title>shotops-mcp headless render harness</title>
6
- <script type="module" crossorigin src="./assets/index-D7fH-FSG.js"></script>
6
+ <script type="module" crossorigin src="./assets/index-B8oQTxzE.js"></script>
7
7
  <link rel="modulepreload" crossorigin href="./assets/three-webgl-BAyyruEx.js">
8
8
  <link rel="modulepreload" crossorigin href="./assets/three-addons-zF8BveTt.js">
9
9
  </head>
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "shotops-mcp",
3
- "version": "0.9.8",
3
+ "version": "0.9.9",
4
4
  "private": false,
5
5
  "type": "module",
6
6
  "description": "The bundle-emitting MCP server over the @engine/@sync spine. Exposes ShotOps tools to ChatGPT, Claude Code, Cursor, and CI over Streamable HTTP with OAuth or personal API tokens. Hosted and MCP tool paths never accept, store, or forward a store-signing credential; the explicit local release CLI validates the user's existing key directly with Apple and records only its path. Renders via headless Playwright Chromium, the engine's native non-browser habitat (same path as mockup-mcp). Also ships as a free LOCAL stdio server (`npx shotops-mcp`) — same render, on your own machine, no account needed.",
@@ -1 +0,0 @@
1
- import{S as sn,G as ln,A as cn,D as ie,M as dn,R as un,a as pn,C as fn,b as hn,c as mn}from"./three-addons-zF8BveTt.js";import{aa as gn,P as Ce,b as yn,V as z,a4 as bn,C as E,ab as vn,J as ze,$ as X,M as wn,a2 as Sn,B as In,a3 as xn,a7 as An,ac as je,ad as Pn,ae as Cn,l as mt}from"./three-webgl-BAyyruEx.js";(function(){const t=document.createElement("link").relList;if(t&&t.supports&&t.supports("modulepreload"))return;for(const o of document.querySelectorAll('link[rel="modulepreload"]'))r(o);new MutationObserver(o=>{for(const a of o)if(a.type==="childList")for(const s of a.addedNodes)s.tagName==="LINK"&&s.rel==="modulepreload"&&r(s)}).observe(document,{childList:!0,subtree:!0});function n(o){const a={};return o.integrity&&(a.integrity=o.integrity),o.referrerPolicy&&(a.referrerPolicy=o.referrerPolicy),o.crossOrigin==="use-credentials"?a.credentials="include":o.crossOrigin==="anonymous"?a.credentials="omit":a.credentials="same-origin",a}function r(o){if(o.ep)return;o.ep=!0;const a=n(o);fetch(o.href,a)}})();const kn=""+new URL("iphone-optimized-BdcJzlHi.glb",import.meta.url).href,On="data:model/gltf-binary;base64,Z2xURgIAAADUAAAAwAAAAEpTT057ImFzc2V0Ijp7InZlcnNpb24iOiIyLjAiLCJnZW5lcmF0b3IiOiJTaG90T3BzIHBsYWNlaG9sZGVyIOKAlCB0aGUgUGl4ZWwgbW9kZWwgaXMgZGVsaWJlcmF0ZWx5IG5vdCBidW5kbGVkIGluIHRoZSBucG0gcGFja2FnZSJ9LCJzY2VuZXMiOlt7Im5hbWUiOiJwaXhlbC1ub3QtYnVuZGxlZCIsIm5vZGVzIjpbXX1dLCJzY2VuZSI6MH0gICA=",Tn=[{id:"grey",label:"Grey",color:11579568},{id:"white",label:"White",color:15263458},{id:"charcoal",label:"Charcoal",color:3815996}],En=[{id:"blue",label:"Deep Blue",frame:3290954,back:4409953,accent:2172211},{id:"silver",label:"Silver",frame:16119285,back:16514043,accent:13816532},{id:"orange",label:"Cosmic Orange",frame:16219693,back:16487504,accent:12738072},{id:"ice",label:"Glacier",frame:15266559,back:15463679,accent:11450047},{id:"red",label:"Burgundy",frame:5052449,back:6435900,accent:3805721},{id:"black",label:"Black",frame:3947580,back:5460819,accent:2960685}],Ln=[{id:"silver",label:"Moonstone",frame:9345186,back:8621205,accent:7041658},{id:"black",label:"Obsidian",frame:2763308,back:2565928,accent:2105377},{id:"orange",label:"Porcelain",frame:15920872,back:14670805,accent:11973550},{id:"green",label:"Jade",frame:9412240,back:8688005,accent:7042924}],Q={id:"iphone-17-pro",glb:kn,fitSize:3.6,baseEuler:{x:0,y:0,z:0},pruneNamePrefixes:[],screen:{material:"OLED",repeat:{x:-1,y:1},coverFill:1.001,coverCornerRatio:.18,coverRepeat:{x:-1,y:-1}},body:{frame:["Anodized aluminum"],back:["Frosted glass"],accent:["Plastic antena","PaletteMaterial001"]},colorways:En},De={id:"pixel-10-pro",glb:On,fitSize:3.6,baseEuler:{x:0,y:Math.PI,z:0},pruneNamePrefixes:["Google Pixel 10 Pro Moonstone.1"],screen:{material:"GP10p_display",repeat:{x:1,y:1},coverFill:1.001,coverCornerRatio:.14,coverRepeat:{x:1,y:-1}},body:{frame:["GP10p_mid","GP10p_camera"],back:["GP10p_back","GP10p_plastic"],accent:["GP10p_logo"]},colorways:Ln},Mn={[Q.id]:Q,[De.id]:De};function ke(e){return e&&Mn[e]||Q}const Rn=7,Ue={front:{x:0,y:0,z:-1},left:{x:-2.6,y:.6,z:-5.2},right:{x:2.6,y:.6,z:-5.2}};function gt(e){const t=Ue[e]??Ue.front,n=Math.hypot(t.x,t.y,t.z),r=Rn/n;return{x:t.x*r,y:t.y*r,z:t.z*r}}function Fn(e){return Math.atan2(e.x,-e.z)*180/Math.PI}function ge(e){const t=gt(e);return new z(t.x,t.y,t.z)}const Nn=1.4;function Bn(e,t){return(t?new z(t.x,t.y,t.z):ge(e)).multiplyScalar(Nn)}const Oe=35;function _n(e){e.traverse(t=>{const n=t;n.geometry?.dispose();const r=n.material;Array.isArray(r)?r.forEach(We):r&&We(r)}),e.clear()}function We(e){for(const t of Object.values(e))t&&typeof t=="object"&&t.isTexture&&t.dispose();e.dispose()}function yt(e,t){const n=document.createElement("canvas"),r=new gn({canvas:n,antialias:!0,preserveDrawingBuffer:!0,alpha:!0});r.setSize(e,t,!1),r.shadowMap.enabled=!0;const o=new sn;o.background=null;const{ambient:a,directionals:s}=zn(o),i=new Ce(Oe,e/t,.01,100);i.position.copy(ge("front")),i.lookAt(0,0,0);function c(f){i.position.copy(ge(f)),i.lookAt(0,0,0)}function l(f){i.position.set(f.x,f.y,f.z),i.lookAt(0,0,0)}function d(f){s.forEach(m=>m.visible=f),a.intensity=f?.75:1.6}let u=!1;function p(){u||(u=!0,o.environment?.dispose(),o.environment=null,_n(o),r.dispose(),r.forceContextLoss())}return{scene:o,camera:i,renderer:r,dispose:p,setAngle:c,setCameraPosition:l,getCameraPosition:()=>({x:i.position.x,y:i.position.y,z:i.position.z}),onUserPose:()=>{},previewOrbit:()=>{},commitOrbit:()=>{},setOrbitEnabled:()=>{},setBackground:()=>{},setStudioLighting:d,resize:()=>{},invalidate:()=>{}}}function zn(e){const t=new cn(16777215,.75);e.add(t);const n=new ie(16777215,2.2);n.position.set(3,5,5);const r=new ie(12571903,.7);r.position.set(-4,1,2);const o=new ie(16777215,1);o.position.set(0,3,-5);const a=[n,r,o];return a.forEach(s=>e.add(s)),{ambient:t,directionals:a}}function bt(e,t){const n=ke(t);return new Promise((r,o)=>{new ln().load(n.glb,a=>{const s=a.scene;if(n.pruneNamePrefixes.length){const p=[];s.traverse(f=>{n.pruneNamePrefixes.some(m=>f.name.startsWith(m))&&p.push(f)}),p.forEach(f=>f.removeFromParent())}s.rotation.set(n.baseEuler.x,n.baseEuler.y,n.baseEuler.z),s.updateMatrixWorld(!0);const i=new yn().setFromObject(s),c=i.getSize(new z),l=i.getCenter(new z),d=n.fitSize/Math.max(c.x,c.y,c.z);s.scale.multiplyScalar(d),s.position.copy(l.multiplyScalar(-d));const u=new bn;u.add(s),e.scene.add(u),e.setAngle("front"),r(u)},void 0,o)})}function jn(e){return bt(e)}Q.colorways;class vt{frame=[];back=[];accent=[];allBody=[];model;scene;renderer;profile;envTexture=null;constructor(t,n,r,o){this.model=t,this.scene=n,this.renderer=r,this.profile=ke(o);const{frame:a,back:s,accent:i}=this.profile.body;t.traverse(c=>{const l=c;if(!l.isMesh)return;(Array.isArray(l.material)?l.material:[l.material]).forEach(u=>{const p=u;!p||!p.name||(a.includes(p.name)?this.push(this.frame,p):s.includes(p.name)?this.push(this.back,p):i.includes(p.name)&&this.push(this.accent,p),this.push(this.allBody,p))})})}push(t,n){t.includes(n)||t.push(n)}get finishMaterials(){return[...this.frame,...this.back]}paint(t,n){const r=n instanceof E?n:new E(n);t.forEach(o=>{o.color=r.clone(),o.needsUpdate=!0})}setColorway(t){if(t==="custom")return;const n=this.profile.colorways.find(r=>r.id===t)??this.profile.colorways[0];n&&(this.paint(this.frame,n.frame),this.paint(this.back,n.back),this.paint(this.accent,n.accent))}setCustomColor(t){const n=new E(t),r=n.clone().lerp(new E(16777215),.2),o=n.clone().multiplyScalar(.6);this.paint(this.frame,n),this.paint(this.back,r),this.paint(this.accent,o)}setFinish(t){const n=Number.isFinite(t)?Math.max(0,Math.min(1,t)):0;this.finishMaterials.forEach(r=>{r.userData.baseRoughness===void 0&&(r.userData.baseRoughness=r.roughness);const o=r.userData.baseRoughness;r.roughness=o*(1-n),r.needsUpdate=!0})}clearcoatUpgraded=!1;usesPhysicalFinish(){return this.clearcoatUpgraded}setClearcoat(t){const n=Math.max(0,Math.min(1,t));n>0&&!this.clearcoatUpgraded&&this.upgradeFinishToPhysical(),this.clearcoatUpgraded&&this.finishMaterials.forEach(r=>{const o=r;o.clearcoat=n,o.clearcoatRoughness=.1,o.needsUpdate=!0})}upgradeFinishToPhysical(){this.clearcoatUpgraded=!0;const t=new Map;for(const r of Array.from(new Set(this.finishMaterials))){const o=new dn;o.color.copy(r.color),o.metalness=r.metalness,o.roughness=r.roughness,o.map=r.map,o.normalMap=r.normalMap,o.normalScale.copy(r.normalScale),o.roughnessMap=r.roughnessMap,o.metalnessMap=r.metalnessMap,o.aoMap=r.aoMap,o.aoMapIntensity=r.aoMapIntensity,o.emissive.copy(r.emissive),o.emissiveMap=r.emissiveMap,o.emissiveIntensity=r.emissiveIntensity,o.envMapIntensity=r.envMapIntensity,o.transparent=r.transparent,o.opacity=r.opacity,o.alphaTest=r.alphaTest,o.side=r.side,o.flatShading=r.flatShading,o.vertexColors=r.vertexColors,o.name=r.name,o.userData={...r.userData},o.clearcoat=0,t.set(r,o)}this.model.traverse(r=>{const o=r;if(o.isMesh)if(Array.isArray(o.material))o.material=o.material.map(a=>t.get(a)??a);else{const a=t.get(o.material);a&&(o.material=a)}});const n=r=>r.map(o=>t.get(o)??o);this.frame=n(this.frame),this.back=n(this.back),this.allBody=n(this.allBody)}environmentMap(){if(!this.envTexture){const t=new vn(this.renderer);this.envTexture=t.fromScene(new un,.04).texture,t.dispose()}return this.envTexture}setClay(t){const n=Tn.find(o=>o.id===t),r=n?new E(n.color):new E(t);this.allBody.forEach(o=>{o.userData.clayStashedMap===void 0&&(o.userData.clayStashedMap=o.map),o.color=r.clone(),o.metalness=0,o.roughness=.85,o.map=null,o.needsUpdate=!0})}clayOff(){this.allBody.forEach(t=>{t.userData.clayStashedMap!==void 0&&(t.map=t.userData.clayStashedMap,t.userData.clayStashedMap=void 0,t.needsUpdate=!0)})}setReflections(t){this.scene.environment=t?this.environmentMap():null}setRoll(t){this.model.rotation.z=t*Math.PI/180}}const He=1.35;class wt{materials=[];glassOverlays=[];screenMesh=null;flatPlane=null;texture=null;appliedBytes=null;flatScreenOn=!1;profile;model;passRestore=[];constructor(t,n){this.profile=ke(n),this.model=t;const r=this.profile.screen.material;t.traverse(o=>{const a=o;if(!a.isMesh)return;(Array.isArray(a.material)?a.material:[a.material]).forEach(i=>{const c=i;c&&c.name===r&&!this.materials.includes(c)&&(this.materials.push(c),this.screenMesh=a)})}),this.dimGlassOverlay(t),this.prepareScreen(),this.setGlare(null)}get found(){return this.materials.length>0}setGlare(t){this.materials.forEach(n=>{n.envMap=t,n.envMapIntensity=t?.6:0,n.metalness=t?.5:0,n.roughness=t?.15:1,n.needsUpdate=!0}),this.glassOverlays.forEach(n=>{n.opacity=t?.08:0,n.needsUpdate=!0})}setFlatScreen(t){if(this.flatScreenOn=t,!this.screenMesh)return;if(this.flatPlane){this.screenMesh.remove(this.flatPlane);const v=this.flatPlane.material;v.map?.dispose(),v.dispose(),this.flatPlane.geometry.dispose(),this.flatPlane=null}if(!t||!this.texture)return;this.screenMesh.geometry.computeBoundingBox();const n=this.screenMesh.geometry.boundingBox;if(!n)return;const r=n.max.x-n.min.x,o=n.max.y-n.min.y,a=n.max.z-n.min.z,s=(n.max.x+n.min.x)/2,i=(n.max.y+n.min.y)/2,c=(n.max.z+n.min.z)/2,l=o<=r&&o<=a?"y":a<=r&&a<=o?"z":"x",d=this.texture.clone();d.needsUpdate=!0,d.colorSpace=ze,d.flipY=!1,d.center.set(.5,.5),d.wrapS=X,d.wrapT=X;const{coverFill:u,coverCornerRatio:p,coverRepeat:f}=this.profile.screen;d.repeat.set(f.x,f.y);const m=l==="x"?a:r,g=l==="z"||l==="x"?o:a,h=Math.min(m,g)*u*p,y=Dn(m*u,g*u,h),b=new wn(y,new pn({map:d,emissive:new E(16777215),emissiveMap:d,emissiveIntensity:He,color:new E(0),toneMapped:!1,side:Sn,depthTest:!0,depthWrite:!0,polygonOffset:!0,polygonOffsetFactor:-4,polygonOffsetUnits:-4}));l==="y"?(b.rotation.x=-Math.PI/2,b.position.set(s,n.max.y,c)):l==="x"?(b.rotation.y=Math.PI/2,b.position.set(n.max.x,i,c)):b.position.set(s,i,n.max.z),b.renderOrder=999,this.screenMesh.add(b),this.flatPlane=b}setLayerPass(t){this.restoreLayerPass();const n=a=>{const s=a.visible;a.visible=!1,this.passRestore.push(()=>{a.visible=s})};if(t==="screen"){this.model.traverse(a=>{const s=a;if(!s.isMesh||s===this.flatPlane)return;(Array.isArray(s.material)?s.material:[s.material]).forEach(c=>{c&&!this.materials.includes(c)&&n(c)})});return}this.glassOverlays.forEach(n);const r=a=>new xn({blending:Cn,blendEquation:Pn,blendSrc:je,blendDst:je,depthTest:!0,depthWrite:!0,side:a?.side??An,polygonOffset:a?.polygonOffset??!1,polygonOffsetFactor:a?.polygonOffsetFactor??0,polygonOffsetUnits:a?.polygonOffsetUnits??0}),o=(a,s)=>{const i=a.material;if(!(Array.isArray(i)?i:[i]).some(s))return;const c=[],l=d=>{if(!s(d))return d;const u=r(d);return c.push(u),u};a.material=Array.isArray(i)?i.map(l):l(i),this.passRestore.push(()=>{a.material=i,c.forEach(d=>d.dispose())})};this.model.traverse(a=>{const s=a;s.isMesh&&(s===this.flatPlane?o(s,()=>!0):o(s,i=>this.materials.includes(i)))})}restoreLayerPass(){const t=this.passRestore.reverse();this.passRestore=[],t.forEach(n=>n())}screenCornersWorld(){const t=this.screenMesh;if(!t)return null;const n=t.geometry;n.computeBoundingBox();const r=n.boundingBox,o=n.attributes.position,a=n.attributes.uv;if(!r||!o||!a)return null;const s=r.getSize(new z),i=r.getCenter(new z),c=s.y<=s.x&&s.y<=s.z?"y":s.z<=s.x&&s.z<=s.y?"z":"x",[l,d]=c==="y"?["x","z"]:c==="z"?["x","y"]:["z","y"],u=this.profile.screen.coverFill,{repeat:p}=this.profile.screen,f={};for(const b of[-1,1])for(const v of[-1,1]){const S=new z;S[c]=r.max[c],S[l]=i[l]+b*s[l]*u/2,S[d]=i[d]+v*s[d]*u/2;let P=-1,C=1/0;for(let A=0;A<o.count;A++){const O=Math.hypot(o.getComponent(A,"xyz".indexOf(l))-S[l],o.getComponent(A,"xyz".indexOf(d))-S[d]);O<C&&(C=O,P=A)}if(P<0)return null;const w=.5+(a.getX(P)-.5)*p.x,I=.5+(a.getY(P)-.5)*p.y;if(w===.5||I===.5)return null;const x=`${I<.5?"t":"b"}${w<.5?"l":"r"}`;if(f[x])return null;f[x]=S}const{tl:m,tr:g,br:h,bl:y}=f;return!m||!g||!h||!y?null:(t.updateWorldMatrix(!0,!1),{tl:m.applyMatrix4(t.matrixWorld),tr:g.applyMatrix4(t.matrixWorld),br:h.applyMatrix4(t.matrixWorld),bl:y.applyMatrix4(t.matrixWorld)})}get cornerRatio(){return this.profile.screen.coverCornerRatio}restoreScreen(){this.prepareScreen()}prepareScreen(){this.materials.forEach(t=>{t.color=new E(0),t.emissive=new E(16777215),t.emissiveIntensity=1,t.roughness=1,t.metalness=0,t.needsUpdate=!0})}dimGlassOverlay(t){t.traverse(n=>{const r=n;if(!r.isMesh)return;(Array.isArray(r.material)?r.material:[r.material]).forEach(a=>{const s=a;s&&s.name!==this.profile.screen.material&&s.transparent&&s.opacity>.2&&this.glassOverlays.push(s)})})}applyWallpaper(t){if(this.appliedBytes===t&&this.texture)return this.lightScreen(this.texture),Promise.resolve();const n=new Blob([t],{type:"image/png"}),r=URL.createObjectURL(n),o=this.texture;return new Promise((a,s)=>{const i=new Image;i.onload=()=>{try{const c=document.createElement("canvas");c.width=i.naturalWidth,c.height=i.naturalHeight;const l=c.getContext("2d");if(!l)throw new Error("2D context unavailable for wallpaper blit");l.drawImage(i,0,0);const d=new fn(c);d.colorSpace=ze,d.flipY=!1,d.center.set(.5,.5),d.wrapS=X,d.wrapT=X,d.repeat.set(this.profile.screen.repeat.x,this.profile.screen.repeat.y),d.needsUpdate=!0,this.texture=d,this.appliedBytes=t,this.lightScreen(d),this.flatScreenOn&&this.setFlatScreen(!0),o?.dispose(),URL.revokeObjectURL(r),a()}catch(c){URL.revokeObjectURL(r),s(c)}},i.onerror=()=>{URL.revokeObjectURL(r),s(new Error("wallpaper image failed to decode"))},i.src=r})}lightScreen(t){this.materials.forEach(n=>{n.map=t,n.emissiveMap=t,n.emissive=new E(16777215),n.emissiveIntensity=He,n.color=new E(0),n.needsUpdate=!0})}}function Dn(e,t,n){const r=e/2,o=t/2,a=Math.min(n,r,o),s=new hn;s.moveTo(-r+a,-o),s.lineTo(r-a,-o),s.quadraticCurveTo(r,-o,r,-o+a),s.lineTo(r,o-a),s.quadraticCurveTo(r,o,r-a,o),s.lineTo(-r+a,o),s.quadraticCurveTo(-r,o,-r,o-a),s.lineTo(-r,-o+a),s.quadraticCurveTo(-r,-o,-r+a,-o);const i=new mn(s,16),c=i.attributes.position,l=new Float32Array(c.count*2);for(let d=0;d<c.count;d++)l[d*2]=(c.getX(d)+r)/e,l[d*2+1]=(c.getY(d)+o)/t;return i.setAttribute("uv",new In(l,2)),i}const Ge={sizePt:{min:20,max:120},maxWidth:{min:.1,max:1},lineHeight:{min:.5,max:3},bandInset:{min:0,max:.5},bandCenter:{min:0,max:1},reserveLines:{min:1,max:8}},ee=[{id:"inter",family:"Inter",label:"Inter"},{id:"manrope",family:"Manrope",label:"Manrope"},{id:"poppins",family:"Poppins",label:"Poppins"},{id:"fraunces",family:"Fraunces",label:"Fraunces"},{id:"space-grotesk",family:"Space Grotesk",label:"Space Grotesk"}],$e=ee.map(e=>e.id);[$e[0],...$e.slice(1)];const $=600;function Te(e){return ee.find(t=>t.id===e)??ee[0]}const St=[{id:"standard",label:"Standard",blurb:"Headline on top, whole device below it, nothing cropped. The safe default.",character:"safe",bleedEdge:"none",shotLook:{deviceSize:"100",hOffset:"0",vOffset:"18",angle:"front",cameraPos:null,roll:"0"},caption:{sizePt:32,maxWidth:.86,reserveLines:2,align:"center",bandCenter:.5}},{id:"bleed",label:"Bleed",blurb:"Room for a longer headline, device running off the bottom edge. What the market looks like.",character:"conventional",bleedEdge:"bottom",shotLook:{deviceSize:"100",hOffset:"0",vOffset:"38",angle:"front",cameraPos:null,roll:"0"},caption:{sizePt:32,maxWidth:.86,reserveLines:4,align:"center",bandCenter:.5}},{id:"top-bleed",label:"Top bleed",blurb:"Device running off the TOP edge, headline underneath it. Inverts the usual reading order.",character:"expressive",bleedEdge:"top",shotLook:{deviceSize:"100",hOffset:"0",vOffset:"-38",angle:"front",cameraPos:null,roll:"0"},caption:{sizePt:32,maxWidth:.86,reserveLines:4,band:"bottom",align:"center",bandCenter:.5}},{id:"lean-right",label:"Lean right",blurb:"Device pushed off the RIGHT edge, headline in a column down the left. Reads as one continuous swipe.",character:"expressive",bleedEdge:"right",shotLook:{deviceSize:"100",hOffset:"46",vOffset:"18",angle:"front",cameraPos:null,roll:"0"},caption:{sizePt:32,maxWidth:.61,reserveLines:2,align:"left",bandCenter:.375}},{id:"lean-left",label:"Lean left",blurb:"Device pushed off the LEFT edge, headline in a column down the right. The mirror of Lean right.",character:"expressive",bleedEdge:"left",shotLook:{deviceSize:"100",hOffset:"-46",vOffset:"18",angle:"front",cameraPos:null,roll:"0"},caption:{sizePt:32,maxWidth:.61,reserveLines:2,align:"right",bandCenter:.625}},{id:"swipe",label:"Swipe",blurb:"A third of the device carried into the next panel, headline full width above it. Only honest applied to every frame.",character:"expressive",bleedEdge:"right",shotLook:{deviceSize:"100",hOffset:"78",vOffset:"18",angle:"front",cameraPos:null,roll:"0"},caption:{sizePt:32,maxWidth:.86,reserveLines:2,align:"center",bandCenter:.5}},{id:"corner-bleed",label:"Corner bleed",blurb:"Off the bottom AND the right at once, headline in a column down the left. The most opinionated panel here.",character:"expressive",bleedEdge:"bottom-right",shotLook:{deviceSize:"100",hOffset:"46",vOffset:"38",angle:"front",cameraPos:null,roll:"0"},caption:{sizePt:32,maxWidth:.61,reserveLines:4,align:"left",bandCenter:.375}}],It=St,Ve=It.map(e=>e.id);[Ve[0],...Ve.slice(1)];Array.from(new Set(St.flatMap(e=>Object.keys(e.caption))));const xt=[{id:"noir",label:"Noir",blurb:"Near-black, high contrast, glossy silver device. The default premium look.",background:{gradientFrom:"#1C1C22",gradientTo:"#08080B",gradientDir:"vertical",shadow:!0,floorReflection:!1},shotLook:{material:"real",colorway:"silver",finish:"0",clearcoat:"1",reflections:!0,lighting:!0,angle:"front"},caption:{fontId:"inter",color:"FFFFFF"}},{id:"daylight",label:"Daylight",blurb:"Warm off-white, soft matte white device, dark text. Calm and editorial.",background:{gradientFrom:"#F4F1EA",gradientTo:"#DFD8CA",gradientDir:"vertical",shadow:!0,floorReflection:!1},shotLook:{material:"clay",clayTone:"white",finish:"0",clearcoat:"0",reflections:!1,lighting:!0,angle:"front"},caption:{fontId:"manrope",color:"1A1A1F"}},{id:"pop",label:"Pop",blurb:"Saturated indigo-to-violet, orange device. Loud, consumer, scroll-stopping.",background:{gradientFrom:"#5B6CF0",gradientTo:"#9B4DF0",gradientDir:"vertical",shadow:!0,floorReflection:!1},shotLook:{material:"real",colorway:"orange",finish:"0",clearcoat:"0.4",reflections:!0,lighting:!0,angle:"front"},caption:{fontId:"poppins",color:"FFFFFF"}},{id:"clay",label:"Clay",blurb:"Warm terracotta, matte charcoal device, tilted. Reads like a product photo.",background:{gradientFrom:"#E9BBAC",gradientTo:"#C88C7C",gradientDir:"vertical",shadow:!0,floorReflection:!1},shotLook:{material:"clay",clayTone:"charcoal",finish:"0",clearcoat:"0",reflections:!1,lighting:!0,angle:"left",roll:"-6"},caption:{fontId:"fraunces",color:"2A2320"}},{id:"studio",label:"Studio",blurb:"Mid slate with a floor reflection, blue device. Technical and precise.",background:{gradientFrom:"#5A6678",gradientTo:"#2B3340",gradientDir:"vertical",shadow:!0,floorReflection:!0},shotLook:{material:"real",colorway:"blue",finish:"0",clearcoat:"0",reflections:!0,lighting:!0,angle:"front"},caption:{fontId:"space-grotesk",color:"FFFFFF"}}],qe=xt.map(e=>e.id);[qe[0],...qe.slice(1)];const k={angle:"front",cameraPos:null,roll:"0",deviceSize:"100",hOffset:"0",vOffset:"18",material:"real",colorway:"blue",customColor:"32374A",finish:"0",clearcoat:"0",clayTone:"grey",clayCustom:"B0B0B0",flatScreen:!1,glare:!1,lighting:!0,reflections:!1},ye={angle:{valueKind:"angle",required:!0,defaultSource:"default-look",defaultValue:k.angle,persistence:"always"},cameraPos:{valueKind:"camera-position",required:!0,defaultSource:"default-look",defaultValue:k.cameraPos,persistence:"always"},roll:{valueKind:"numeric-string",required:!0,defaultSource:"default-look",defaultValue:k.roll,persistence:"always"},deviceSize:{valueKind:"numeric-string",required:!0,defaultSource:"default-look",defaultValue:k.deviceSize,persistence:"always"},hOffset:{valueKind:"numeric-string",required:!0,defaultSource:"default-look",defaultValue:k.hOffset,persistence:"always"},vOffset:{valueKind:"numeric-string",required:!0,defaultSource:"default-look",defaultValue:k.vOffset,persistence:"always"},material:{valueKind:"material",required:!0,defaultSource:"default-look",defaultValue:k.material,persistence:"always"},colorway:{valueKind:"colorway",required:!0,defaultSource:"default-look",defaultValue:k.colorway,persistence:"always"},customColor:{valueKind:"string",required:!0,defaultSource:"default-look",defaultValue:k.customColor,persistence:"always"},finish:{valueKind:"numeric-string",required:!0,defaultSource:"default-look",defaultValue:k.finish,persistence:"always"},clearcoat:{valueKind:"numeric-string",required:!0,defaultSource:"default-look",defaultValue:k.clearcoat,persistence:"always"},clayTone:{valueKind:"clay-tone",required:!0,defaultSource:"default-look",defaultValue:k.clayTone,persistence:"always"},clayCustom:{valueKind:"string",required:!0,defaultSource:"default-look",defaultValue:k.clayCustom,persistence:"always"},flatScreen:{valueKind:"boolean",required:!0,defaultSource:"default-look",defaultValue:k.flatScreen,persistence:"always"},clipToFrame:{valueKind:"boolean",required:!1,defaultSource:"explicit",defaultValue:!1,persistence:"omit-default"},deviceFrame:{valueKind:"boolean",required:!1,defaultSource:"explicit",defaultValue:!0,persistence:"omit-default"},screenCornerRadius:{valueKind:"numeric-string",required:!1,defaultSource:"explicit",defaultValue:"12",persistence:"omit-default"},glare:{valueKind:"boolean",required:!0,defaultSource:"default-look",defaultValue:k.glare,persistence:"always"},lighting:{valueKind:"boolean",required:!0,defaultSource:"default-look",defaultValue:k.lighting,persistence:"always"},reflections:{valueKind:"boolean",required:!0,defaultSource:"default-look",defaultValue:k.reflections,persistence:"always"}},Un={roll:{min:-45,max:45},deviceSize:{min:25,max:240},hOffset:{min:-100,max:100},vOffset:{min:-200,max:200},finish:{min:0,max:1},clearcoat:{min:0,max:1},screenCornerRadius:{min:0,max:50}},At=.82;function Wn(e){return e/100*At}function Hn(e){return Math.round(e/At*100)/100}const V={x:.5,y:.06},Ee={fontId:"inter",sizePt:32,color:"FFFFFF",align:"center",anchor:V,maxWidth:.86},Ke=[{id:"r69",label:"6.9″ iPhone · 1320×2868",width:1320,height:2868},{id:"r65",label:"6.5″ iPhone · 1242×2688",width:1242,height:2688},{id:"r55",label:"5.5″ iPhone · 1242×2208",width:1242,height:2208},{id:"pixel69",label:"Pixel 10 Pro · 1320×2868",width:1320,height:2868},{id:"ipad13",label:"13″ iPad · 2064×2752",width:2064,height:2752},{id:"ipad129",label:"12.9″ iPad · 2048×2732",width:2048,height:2732}];function q(e){return Ke.find(t=>t.id===e)??Ke[0]}const oe=932,be="iphone-17-pro",Gn="pixel-10-pro",Le=[{id:"iphone-6-9",label:"iPhone 17 Pro",panelPresetId:"r69",ascDeviceSet:"APP_IPHONE_67",modelId:be,screenFamily:"iphone"},{id:"iphone-6-5",label:"iPhone 17",panelPresetId:"r65",ascDeviceSet:"APP_IPHONE_65",modelId:be,screenFamily:"iphone"},{id:"pixel-10-pro",label:"Pixel 10 Pro",panelPresetId:"pixel69",ascDeviceSet:"ANDROID_PHONE",modelId:Gn,screenFamily:"android"},{id:"ipad-13",label:"iPad 13″",panelPresetId:"ipad13",ascDeviceSet:"APP_IPAD_PRO_129",modelId:"ipad-pro",screenFamily:"ipad",comingSoon:!0},{id:"ipad-12-9",label:"iPad 12.9″",panelPresetId:"ipad129",ascDeviceSet:"APP_IPAD_PRO_3GEN_129",modelId:"ipad-pro",screenFamily:"ipad",comingSoon:!0}];function $n(e){return Le.find(t=>t.panelPresetId===e)?.modelId??be}const Pt="iphone-6-9";function Me(e){return Le.find(t=>t.id===e)}function Vn(){return Le.filter(e=>!e.comingSoon)}function Ct(e,t){if(Array.isArray(e)){const n=new Set,r=[];for(const o of e){const a=Me(o);a&&!a.comingSoon&&!n.has(o)&&(n.add(o),r.push(o))}if(r.length>0)return r}if(t){const n=Vn().find(r=>r.panelPresetId===t);if(n)return[n.id]}return[Pt]}function qn(e,t){return e.find(r=>Me(r)?.panelPresetId===t)??e[0]}function Kn(e){const t=e??{},n=Array.isArray(t.outputs)?t.outputs.filter(a=>typeof a=="string"):void 0,r=Ct(n,typeof t.panelPresetId=="string"?t.panelPresetId:void 0),o=q(typeof t.panelPresetId=="string"?t.panelPresetId:"").id;return{outputs:r,panelPresetId:o,activeDeviceId:qn(r,o)}}const kt=Me(Pt)?.screenFamily??"iphone";function Ot(e){const t={...e},n=t,r=Object.keys(ye);for(const o of r){const a=ye[o];a.persistence==="omit-default"&&(n[o]===void 0||n[o]===a.defaultValue)&&delete n[o]}return t}function Yn(e){if(!e||typeof e!="object"||Array.isArray(e)||!("phoneHeight"in e))return e;const{phoneHeight:t,...n}=e;if(n.deviceSize===void 0){const r=typeof t=="number"?t:Number.parseFloat(String(t??""));Number.isFinite(r)&&(n.deviceSize=String(Hn(r)))}return n}function Tt(e){return Ot({...k,...Yn(e)})}function Et(e){return Ot(Tt(e))}function M(e,t){const{min:n,max:r}=Un[e],o=typeof t=="number"?t:Number.parseFloat(t??""),a=Number.isFinite(o)?o:Number.parseFloat(String(ye[e].defaultValue));return Math.max(n,Math.min(r,a))}const Xn=90,Lt=180,Jn="#1b1b2e",Zn="#0a0a14";function Qn(e){return e==="horizontal"?Xn:Lt}function er(e){const t=(e%180+180)%180;return t>=45&&t<135?"horizontal":"vertical"}function Mt(e,t,n){return{stops:[{color:e,at:0},{color:t,at:1}],angle:Qn(n)}}const Rt=e=>e*Math.PI/180;function tr(e){const t=Rt(e);return{dx:Math.sin(t),dy:-Math.cos(t)}}function nr(e,t,n){const r=Rt(n);return Math.abs(e*Math.sin(r))+Math.abs(t*Math.cos(r))}function rr(e,t,n){const{dx:r,dy:o}=tr(n),a=nr(e,t,n)/2,s=e/2,i=t/2;return{x0:s-a*r,y0:i-a*o,x1:s+a*r,y1:i+a*o}}function te(e){const t=e.stops[0],n=e.stops[e.stops.length-1];return{gradientFrom:t?.color??"#000000",gradientTo:n?.color??t?.color??"#000000",gradientDir:er(e.angle)}}function ae(e,t){if(!Array.isArray(e)||e.length===0)return null;const n=[];for(const o of e){if(!o||typeof o!="object")return null;const a=o;if(typeof a.color!="string"||typeof a.at!="number"||!Number.isFinite(a.at))return null;n.push({color:a.color,at:Math.min(1,Math.max(0,a.at))})}const r=typeof t=="number"&&Number.isFinite(t)?or(t):Lt;return{stops:n,angle:r}}function ne(e){return ae(e.gradientStops,e.gradientAngle)??Mt(e.gradientFrom,e.gradientTo,e.gradientDir)}function or(e){return(e%360+360)%360}function ar(e){return ae(e.stops,e.angle)??Mt(e.from,e.to,e.dir)}function Ft(e){if(!e||typeof e!="object"||Array.isArray(e))return{};const t={};for(const[n,r]of Object.entries(e)){if(!r||typeof r!="object")continue;const o=r;if(o.kind==="solid"&&typeof o.color=="string")t[n]={kind:"solid",color:o.color};else if(o.kind==="gradient"&&typeof o.from=="string"&&typeof o.to=="string"&&(o.dir==="horizontal"||o.dir==="vertical")){const a=ae(o.stops,o.angle);t[n]=a?{kind:"gradient",stops:a.stops,angle:a.angle,from:o.from,to:o.to,dir:o.dir}:{kind:"gradient",from:o.from,to:o.to,dir:o.dir}}}return t}function D(e){return!e||e.x===V.x&&e.y===V.y}function sr(e){const{text:t,anchor:n,...r}=e;return D(n)?{...r}:{...r,anchor:n}}const ir=.55,N="en-US";function lr(e){const t=e.lastIndexOf(":");if(t<=0)return null;const n=Number(e.slice(t+1));return!Number.isSafeInteger(n)||n<0?null:{panelId:e.slice(0,t),index:n}}function Nt(e,t,n,r){if(!e||typeof e!="object"||Array.isArray(e))return{};const o={};for(const[a,s]of Object.entries(e)){if(a===n||!t.includes(a)||!Array.isArray(s))continue;const i=Array.from(new Set(s.filter(c=>typeof c=="string"))).filter(c=>{const l=lr(c);return!!l&&!!r[n]?.[l.panelId]?.[l.index]&&!!r[a]?.[l.panelId]?.[l.index]});i.length>0&&(o[a]=i)}return o}function Bt(e){if(!e||typeof e!="object"||Array.isArray(e))return{};const t={};for(const[n,r]of Object.entries(e))!r||typeof r!="object"||Array.isArray(r)||(t[n]=H(r));return t}function cr(e){if(!e||typeof e!="object")return;const t=e,n=typeof t.x=="number"?t.x:V.x,r=typeof t.y=="number"?t.y:V.y;return D({x:n,y:r})?void 0:{x:n,y:r}}function H(e){const t=e&&typeof e=="object"?e:{},n=cr(t.anchor),r={...Ee,...t};n?r.anchor=n:delete r.anchor,typeof r.reserveLines!="number"||!Number.isFinite(r.reserveLines)||r.reserveLines<Ge.reserveLines.min?delete r.reserveLines:r.reserveLines=Math.floor(r.reserveLines),r.band!=="bottom"&&delete r.band;for(const o of["bandInset","lineHeight","bandCenter"]){const{min:a,max:s}=Ge[o],i=r[o];(typeof i!="number"||!Number.isFinite(i)||i<a||i>s)&&delete r[o]}return r}function dr(e){const t=e&&typeof e=="object"?e:{};return{...H(t),text:typeof t.text=="string"?t.text:""}}function _t(e){if(!e||typeof e!="object"||Array.isArray(e))return{};const t={};for(const[n,r]of Object.entries(e))Array.isArray(r)?r.length>0&&(t[n]=r.map(H)):r&&typeof r=="object"&&(t[n]=[H(r)]);return t}function ur(e,t){const n=[{...H(t),text:e.headline}];return typeof e.subtitle=="string"&&e.subtitle.trim()&&n.push({...H({...t,sizePt:t.sizePt*ir}),text:e.subtitle}),n}function se(e,t,n=N){if(!e||typeof e!="object"||Array.isArray(e))return{};const r=Bt(t),o=l=>r[l]??Ee,a=l=>{if(!l||typeof l!="object"||Array.isArray(l))return{};const d={};for(const[u,p]of Object.entries(l))Array.isArray(p)?p.length>0&&(d[u]=p.map(dr)):p&&typeof p=="object"&&typeof p.headline=="string"&&(d[u]=ur(p,o(u)));return d},s=Object.entries(e);if(s.some(([,l])=>!!l&&typeof l=="object"&&typeof l.headline=="string"))return{[n]:a(e)};const c={};for(const[l,d]of s)c[l]=a(d);return c}function zt(e,t,n=N){return e[t??n]??e[n]??{}}function jt(e,t=N){const n={},r=Object.keys(e),o=r.includes(t)?[t,...r.filter(a=>a!==t)]:r;for(const a of o){const s=e[a];if(s)for(const[i,c]of Object.entries(s))n[i]===void 0&&Array.isArray(c)&&c.length>0&&(n[i]=c.map(sr))}return n}function ve(e,t=N,n=kt){const r={};return e.family!==void 0&&e.family!==n&&(r.family=e.family),e.locale!==void 0&&e.locale!==t&&(r.locale=e.locale),r}function Ye(e){const t=[];return e.family!==void 0&&t.push(`family=${e.family}`),e.locale!==void 0&&t.push(`locale=${e.locale}`),t.join("&")}function we(e){const t=[];return e.family!==void 0&&t.push("family"),e.locale!==void 0&&t.push("locale"),t}const pr={order:["family","locale"],reach:"strict"};function fr(e,t){const n=we(e),r=t.order.filter(a=>n.includes(a));return Array.from({length:r.length+1},(a,s)=>r.slice(0,r.length-s)).map(a=>{const s={};return a.includes("family")&&(s.family=e.family),a.includes("locale")&&(s.locale=e.locale),s})}function hr(e,t,n,r,o=N){const a=ve(n,o);for(const s of fr(a,r)){const i=e(t,s);if(i!==void 0){const c=we(s);return{value:i,resolvedAt:s,inherited:we(a).filter(l=>!c.includes(l))}}}return{value:void 0,resolvedAt:null,inherited:[]}}const Dt=e=>{let t="";for(let n=0;n<e.length;n++)t+=e[n].toString(16).padStart(2,"0");return t};async function mr(e){const t=globalThis.crypto?.subtle;return t?Dt(new Uint8Array(await t.digest("SHA-256",e))):yr(e)}const gr=new Uint32Array([1116352408,1899447441,3049323471,3921009573,961987163,1508970993,2453635748,2870763221,3624381080,310598401,607225278,1426881987,1925078388,2162078206,2614888103,3248222580,3835390401,4022224774,264347078,604807628,770255983,1249150122,1555081692,1996064986,2554220882,2821834349,2952996808,3210313671,3336571891,3584528711,113926993,338241895,666307205,773529912,1294757372,1396182291,1695183700,1986661051,2177026350,2456956037,2730485921,2820302411,3259730800,3345764771,3516065817,3600352804,4094571909,275423344,430227734,506948616,659060556,883997877,958139571,1322822218,1537002063,1747873779,1955562222,2024104815,2227730452,2361852424,2428436474,2756734187,3204031479,3329325298]),F=(e,t)=>e>>>t|e<<32-t;function yr(e){const t=e.length,n=new Uint8Array(t+72>>6<<6);n.set(e),n[t]=128;const r=t*8,o=new DataView(n.buffer);o.setUint32(n.length-8,Math.floor(r/4294967296)),o.setUint32(n.length-4,r>>>0);const a=new Uint32Array([1779033703,3144134277,1013904242,2773480762,1359893119,2600822924,528734635,1541459225]),s=new Uint32Array(64);for(let i=0;i<n.length;i+=64){for(let h=0;h<16;h++)s[h]=o.getUint32(i+h*4);for(let h=16;h<64;h++){const y=s[h-15],b=s[h-2],v=F(y,7)^F(y,18)^y>>>3,S=F(b,17)^F(b,19)^b>>>10;s[h]=s[h-16]+v+s[h-7]+S>>>0}let[c,l,d,u,p,f,m,g]=[a[0],a[1],a[2],a[3],a[4],a[5],a[6],a[7]];for(let h=0;h<64;h++){const y=F(p,6)^F(p,11)^F(p,25),b=p&f^~p&m,v=g+y+b+gr[h]+s[h]>>>0,S=F(c,2)^F(c,13)^F(c,22),P=c&l^c&d^l&d,C=S+P>>>0;g=m,m=f,f=p,p=u+v>>>0,u=d,d=l,l=c,c=v+C>>>0}a[0]=a[0]+c>>>0,a[1]=a[1]+l>>>0,a[2]=a[2]+d>>>0,a[3]=a[3]+u>>>0,a[4]=a[4]+p>>>0,a[5]=a[5]+f>>>0,a[6]=a[6]+m>>>0,a[7]=a[7]+g>>>0}return Dt(br(a))}function br(e){const t=new Uint8Array(e.length*4),n=new DataView(t.buffer);for(let r=0;r<e.length;r++)n.setUint32(r*4,e[r]);return t}function Se(e,t,n=N){const r=o=>{const a=new Set,s=[];for(const i of o)typeof i=="string"&&i&&!a.has(i)&&(a.add(i),s.push(i));return s};if(Array.isArray(t)){const o=r(t);if(o.length>0)return o.includes(n)?o:[...o,n]}return r([n,...Object.keys(e)])}function Re(e,t=N){return typeof e=="string"&&e.length>0?e:t}const G={"it-IT":"it"};function Xe(e,t){if(!(Object.keys(e).some(o=>o in G)||(t?.some(o=>o in G)??!1)))return{captionText:e,locales:t};const r={};for(const[o,a]of Object.entries(e))o in G||(r[o]=a);for(const[o,a]of Object.entries(e)){const s=G[o];s&&(r[s]={...a,...r[s]??{}})}return{captionText:r,locales:t?.map(o=>G[o]??o)}}function vr(e){const t=e??{},n=Re(t.baseLocale),r=Array.isArray(t.locales)?t.locales.filter(i=>typeof i=="string"&&i.length>0):void 0,{captionText:o,locales:a}=Xe(se(t.captionText,t.captionStyles,n),r),s=Xe({[n]:{}},[n]).locales?.[0]??n;return{captionText:o,locales:Se(o,a,s),baseLocale:s}}function Ut(e){if(!e||typeof e!="object"||Array.isArray(e))return{};const t={};for(const[n,r]of Object.entries(e)){if(n===kt||!r||typeof r!="object"||Array.isArray(r))continue;const o={};for(const[a,s]of Object.entries(r)){if(!s||typeof s!="object"||Array.isArray(s))continue;const i={};for(const[c,l]of Object.entries(s))Array.isArray(l)&&l.every(d=>typeof d=="string")&&(i[c]=l);Object.keys(i).length>0&&(o[a]=i)}Object.keys(o).length>0&&(t[n]=o)}return t}function K(e,t){return t.flatMap(n=>e.filter(r=>r.panelId===n.id))}let Je=0,Ze=0;function wr(e,t){const n=(r,o)=>r.reduce((a,s)=>{const i=s.startsWith(o)?Number.parseInt(s.slice(o.length),10):NaN;return Number.isFinite(i)&&i>a?i:a},0);Je=Math.max(Je,n(e,"shot-")),Ze=Math.max(Ze,n(t,"panel-"))}const Sr=.49;function Ir(e,t,n){return e.map(r=>{const o=n*r.heightFrac,a=r.height>0?r.width*(o/r.height):o*Sr,i=r.panelIndex*t+t/2-a/2+r.hOffset*(t/2),l=(n-o)/2+r.vOffset*(n/2);return{shotId:r.shotId,bytes:r.bytes,x:Math.round(i),y:Math.round(l),width:Math.round(a),height:Math.round(o),panelIndex:r.panelIndex,...r.clipToFrame===!0?{clipToFrame:!0}:{},...r.layers?{layers:r.layers}:{}}})}function xr(e,t){const n=t.panelBackgrounds??{},r=ne(t),o=r.stops[0]?.color??t.gradientFrom;if(!e.some(c=>n[c.id]))return t.bgMode==="gradient"?{kind:"gradient",gradient:r}:{kind:"perPanel",colors:e.map(c=>t.panelColors[c.id]??o)};const s=c=>t.bgMode==="gradient"?{kind:"gradient",gradient:r}:{kind:"solid",color:t.panelColors[c]??o};return{kind:"perPanelFills",fills:e.map(c=>{const l=n[c.id];return l?l.kind==="solid"?{kind:"solid",color:l.color}:{kind:"gradient",gradient:ar(l)}:s(c.id)})}}const Ar=9/19.5;function Pr(e){return e.deviceFrame!==!1}function Cr(e,t,n,r){const o=e>0&&t>0,a=o?t:Math.max(1,r),s=o?e:a*Ar,i=Math.min(1,Math.max(1,r)/a),c=Math.max(1,Math.round(s*i)),l=Math.max(1,Math.round(a*i)),d=Math.min(c*M("screenCornerRadius",n.screenCornerRadius)/100,Math.min(c,l)/2),u=M("roll",n.roll)*Math.PI/180,p=Math.abs(Math.cos(u)),f=Math.abs(Math.sin(u)),m=Math.max(1,Math.ceil(c*p+l*f-1e-6)),g=Math.max(1,Math.ceil(c*f+l*p-1e-6));return{width:m,height:g,cardWidth:c,cardHeight:l,radius:d,rotation:u}}function Wt(e,t,n=N){const r=ne(e);return{panelPresetId:e.panelPresetId,bgMode:e.bgMode,gradientStops:r.stops,gradientAngle:r.angle,...te(r),panelColors:e.panelColors,shadow:e.shadow,floorReflection:e.floorReflection??!1,panelBackgrounds:e.panelBackgrounds??{},captionStyles:{..._t(e.captionStyles),...jt(t,n)}}}function kr(e){const t=e.caption.reserveLines,n=typeof t=="number"?` Reserves ${t} headline lines (~${Math.round(t*18*(e.caption.maxWidth??.86)/.86)} characters).`:"",r=(e.caption.maxWidth??.86)<.86||(e.caption.align??"center")!=="center"?" Restyles the headline into a narrower column.":" Leaves the headline full-width and centred.";return`${e.blurb}${n}${r} Character: [${e.character}]. Bleeds: [${e.bleedEdge}].`}function Or(e,t){return Math.max(0,...Object.values(e).map(n=>n[t]?.length??0))}function Ht(e,t,n){const r=e&&typeof e=="object"&&!Array.isArray(e)?e:{},o=new Set,a={};let s=1;const i=()=>{for(;o.has(`caption-${s}`);)s+=1;const c=`caption-${s}`;return o.add(c),s+=1,c};for(const c of n){const l=Or(t,c);if(l===0)continue;const d=Array.isArray(r[c])?r[c]:[];a[c]=Array.from({length:l},(u,p)=>{const f=d[p];return typeof f=="string"&&f.length>0&&!o.has(f)?(o.add(f),f):i()})}return a}const Gt=2;function Tr(e){if(!e||typeof e!="object"||Array.isArray(e))return!1;const t=e;return t.schema===Gt&&Array.isArray(t.shots)&&Array.isArray(t.panels)&&t.panels.length>0}function Er(e){let t;try{t=JSON.parse(e)}catch{return null}if(!Tr(t))return null;const n=t,r=new Set(n.panels.map(f=>f.id)),o=n.shots.filter(f=>r.has(f.panelId)).map(f=>({id:f.id,panelId:f.panelId,frameNodeId:f.frameNodeId,frameName:f.frameName,bytes:null,look:Tt(f.look),thumb:null,thumbStale:!0,inputAnchor:f.inputAnchor,outputAnchor:f.outputAnchor})),a=n.panels.map(f=>({id:f.id}));wr(o.map(f=>f.id),a.map(f=>f.id));const s=n.selectedShotId&&o.some(f=>f.id===n.selectedShotId)?n.selectedShotId:o[0]?.id??null,{captionText:i,locales:c,baseLocale:l}=vr(n),d=Kn(n),u=Ht(n.captionSlotIds,i,a.map(f=>f.id)),p=ae(n.gradientStops,n.gradientAngle);return{shots:K(o,a),panels:a,selectedShotId:s,panelPresetId:d.panelPresetId,bgMode:n.bgMode==="perPanel"?"perPanel":"gradient",...p?{gradientStops:p.stops,gradientAngle:p.angle,...te(p)}:{gradientFrom:n.gradientFrom??"5B6CF0",gradientTo:n.gradientTo??"9B4DF0",gradientDir:n.gradientDir==="vertical"?"vertical":"horizontal"},panelColors:n.panelColors??{},shadow:n.shadow!==!1,floorReflection:n.floorReflection===!0,panelBackgrounds:Ft(n.panelBackgrounds),captionText:i,locales:c,baseLocale:l,staleCaptionTranslations:Nt(n.staleCaptionTranslations,c,l,i),outputs:d.outputs,localeScreens:{},outputCaptions:Ut(n.outputCaptions),captionSlotIds:u,frameTemplates:n.frameTemplates&&typeof n.frameTemplates=="object"&&!Array.isArray(n.frameTemplates)?n.frameTemplates:{}}}function $t(e){const n=K(e.shots,e.panels).map(a=>({id:a.id,panelId:a.panelId,frameNodeId:a.frameNodeId,frameName:a.frameName,look:Et(a.look),inputAnchor:a.inputAnchor,outputAnchor:a.outputAnchor})),r=Re(e.baseLocale),o=se(e.captionText,e.captionStyles,r);return{schema:Gt,shots:n,panels:e.panels,selectedShotId:e.selectedShotId,captionText:o,locales:Se(o,e.locales,r),baseLocale:r,staleCaptionTranslations:Nt(e.staleCaptionTranslations,Se(o,e.locales,r),r,o),outputs:Ct(e.outputs,e.panelPresetId),outputCaptions:Ut(e.outputCaptions),...(()=>{const a=Ht(e.captionSlotIds,o,e.panels.map(s=>s.id));return Object.keys(a).length>0?{captionSlotIds:a}:{}})(),...e.frameTemplates&&Object.keys(e.frameTemplates).length>0?{frameTemplates:e.frameTemplates}:{},...Wt(e,o,r)}}const Lr=1;function Mr(e){const t=K(e.shots,e.panels),n=se(e.captionText,e.captionStyles),r=Re(e.baseLocale);return{schema:Lr,shots:t.map(o=>({panelId:o.panelId,look:Et(o.look)})),...Wt(e,n,r)}}xt.map(e=>({id:e.id,label:e.label,description:e.blurb}));It.map(e=>({id:e.id,label:e.label,description:kr(e),character:e.character}));const Rr=[{id:"frame.add",domain:"frame",status:"supported",summary:"Add a blank frame after an existing one.",studioCommands:["addPanel"],wire:"structuralOperations: frame.add",targets:["project"],requiredInputs:["afterFrameId (optional)","frameRef (optional, patch-local alias)"],limits:["Declare frameRef to address the new frame in later ordered operations of the same patch. Without frameRef, wait until the next cycle reports its id."],evaluationCases:["structure-add-closing-frame"]},{id:"frame.remove",domain:"frame",status:"supported",summary:"Remove a frame, with the devices and captions it holds.",studioCommands:["removePanel"],wire:"structuralOperations: frame.remove",targets:["frame"],requiredInputs:["frameId"],limits:["The last remaining frame cannot be removed."],evaluationCases:["structure-remove-empty-frame","structure-remove-populated-frame"]},{id:"frame.reorder",domain:"frame",status:"supported",summary:"Change the order frames tell the story in.",studioCommands:["movePanel","reorderPanels"],wire:"structuralOperations: frame.move, or the complete screenOrder permutation",targets:["project","frame"],requiredInputs:["frameId and its new position"],evaluationCases:["project-reorder-strongest"]},{id:"frame.split",domain:"frame",status:"supported",summary:"Split a multi-device frame by moving some of its devices into a new frame beside it.",studioCommands:[],wire:"structuralOperations: frame.split",targets:["frame","device"],requiredInputs:["frameId","a non-empty proper subset of its deviceIds"],evaluationCases:["structure-split-two-device-frame"]},{id:"frame.combine",domain:"frame",status:"supported",summary:"Merge one frame into another, keeping every device and caption, and drop the emptied frame.",studioCommands:[],wire:"structuralOperations: frame.combine",targets:["frame"],requiredInputs:["frameId (the survivor)","fromFrameId (the frame merged into it)"],evaluationCases:["structure-combine-last-two-frames"]},{id:"device.look",domain:"device",status:"supported",summary:"Restyle a device: camera angle, tilt, size, position, body colour, finish and lighting.",studioCommands:["patchShotLook"],wire:"patch.devices (by deviceId) or the complete patch.shots array",targets:["device"],requiredInputs:["deviceId","the look fields to change"],limits:["The raw camera 3-vector is not writable; the Agent moves the sanctioned orbit axis instead."],evaluationCases:["device-frame-two-clockwise","device-frame-one-gold","device-alternating-clay","device-frame-three-smaller-right","multi-device-spread-frame-two"]},{id:"device.move-to-frame",domain:"device",status:"supported",summary:"Move a device into an existing frame, at a chosen position among that frame’s devices.",studioCommands:["moveShotToFrame","moveShotToPanel","reorderShots"],wire:"structuralOperations: device.move",targets:["device","frame"],requiredInputs:["deviceId","toFrameId","toIndex (optional)"],evaluationCases:["structure-combine-last-two-frames"]},{id:"device.reorder",domain:"device",status:"supported",summary:"Reorder devices inside their own frame.",studioCommands:["moveShot"],wire:"structuralOperations: device.reorder",targets:["device"],requiredInputs:["deviceId","toIndex"],evaluationCases:["structure-reorder-devices-in-frame"]},{id:"device.remove",domain:"device",status:"supported",summary:"Remove one device while its frame stays.",studioCommands:["removeShot"],wire:"structuralOperations: device.remove",targets:["device"],requiredInputs:["deviceId"],limits:["The project’s last remaining device cannot be removed."],evaluationCases:["structure-remove-second-device"]},{id:"device.add",domain:"device",status:"supported",summary:"Add a device to a frame from a screenshot supplied with this instruction.",studioCommands:["addShot"],wire:"structuralOperations: device.add, naming an assetId from AVAILABLE SCREENSHOTS",targets:["frame"],requiredInputs:["toFrameId","assetId","toIndex (optional)"],withoutAssetReason:"Adding a device needs a screenshot sent with the instruction. This one carried none.",limits:["Only a screenshot listed in AVAILABLE SCREENSHOTS; the Agent never invents or generates pixels.","A device created this cycle can only be addressed in the next one, after Studio reports its id.","It lands on the default device look, exactly as dropping a screenshot into Studio does."],evaluationCases:["asset-add-supplied-screenshot"]},{id:"device.replace-pixels",domain:"asset",status:"supported",summary:"Replace the screenshot shown on an existing device, keeping the device untouched.",studioCommands:["reskinShots","ordinalReskin"],wire:"structuralOperations: device.replace, naming an assetId from AVAILABLE SCREENSHOTS",targets:["device"],requiredInputs:["deviceId","assetId"],withoutAssetReason:"Changing what a device shows needs the new screenshot sent with the instruction. This one carried none.",limits:["Only a screenshot listed in AVAILABLE SCREENSHOTS; the Agent never invents or generates pixels.","The device keeps its look, placement, captions, translated screens and Output membership — only the pixels change."],evaluationCases:["asset-replace-device-screenshot"]},{id:"caption.text",domain:"caption",status:"supported",summary:"Rewrite the headline words on frames.",studioCommands:["patchCaptionLayer"],wire:"the complete patch.captions array",targets:["project","frame","caption"],requiredInputs:["the complete caption list, one entry per frame"],limits:["Only each frame’s first caption layer, in the base language.","Hand-placed caption anchors and per-language fit overrides stay manual."],evaluationCases:["copy-all-six-words","copy-frame-two-exact","selection-caption-shorter"]},{id:"caption.style",domain:"caption",status:"supported",summary:"Restyle captions: font, size, colour, alignment, width and band placement.",studioCommands:["patchAllCaptionStyles"],wire:"patch.captionStyle (strip-wide) or patch.frames[i].captionStyle (one frame)",targets:["project","frame"],requiredInputs:["the style fields to change"],evaluationCases:["style-all-captions-smaller","style-selected-caption-white-left"]},{id:"caption.add",domain:"caption",status:"supported",summary:"Add a caption layer to a frame, with its words and styling.",studioCommands:["addCaptionLayer"],wire:"structuralOperations: caption.add",targets:["frame"],requiredInputs:["frameId","the caption text"],evaluationCases:["structure-subtitle-each-frame"]},{id:"caption.remove",domain:"caption",status:"supported",summary:"Remove one caption layer from a frame.",studioCommands:["removeCaptionLayer"],wire:"structuralOperations: caption.remove",targets:["caption"],requiredInputs:["frameId","the caption position"],evaluationCases:["structure-remove-subtitle"]},{id:"caption.reorder",domain:"caption",status:"supported",summary:"Reorder the caption layers stacked on one frame.",studioCommands:["reorderCaptionLayer"],wire:"structuralOperations: caption.move within one frame",targets:["caption"],requiredInputs:["frameId","the caption position","its new position"],evaluationCases:["structure-reorder-captions"]},{id:"caption.move-to-frame",domain:"caption",status:"supported",summary:"Move a caption layer to another frame.",studioCommands:["moveCaptionLayer","moveCaptionLayerToFrame"],wire:"structuralOperations: caption.move across frames",targets:["caption","frame"],requiredInputs:["frameId","the caption position","toFrameId"],evaluationCases:["structure-move-caption-to-frame"]},{id:"caption.translate",domain:"caption",status:"intentionally_excluded",summary:"Write caption words in a non-base language.",studioCommands:["applyCaptionTranslations","clearCaptionTranslation"],wire:null,targets:["project"],requiredInputs:[],reason:"Agent refinement cannot translate captions. Open Translate in Studio to create German or other language versions while retaining the base words.",evaluationCases:["unsupported-translate-captions"]},{id:"caption.output-override",domain:"caption",status:"intentionally_excluded",summary:"Give an output family its own caption wording.",studioCommands:["patchOutputCaption","clearOutputCaption"],wire:null,targets:["caption"],requiredInputs:[],reason:"Agent refinement edits shared captions. Studio has manual output-family caption wording; both iPhone sizes share one family and cannot have separate words.",evaluationCases:["unsupported-per-output-caption"]},{id:"strip.background",domain:"look",status:"supported",summary:"Change the strip backdrop: gradient stops, angle, shadow and floor reflection.",studioCommands:["patchConfig"],wire:"patch.background",targets:["project"],requiredInputs:["the backdrop fields to change"],limits:["The canvas size a Look is authored against stays a Studio control.","Per-frame solid colours are set through the frame backdrop, not the strip config."],evaluationCases:["background-strip-navy-gradient"]},{id:"frame.background",domain:"look",status:"supported",summary:"Give one frame its own backdrop.",studioCommands:["setPanelBackground"],wire:"patch.frames[i].background",targets:["frame"],requiredInputs:["the frame","the backdrop fields"],evaluationCases:["background-frame-one-amber","background-frame-three-flat-teal","inspection-correct-frame-two-background"]},{id:"frame.background-reset",domain:"look",status:"intentionally_excluded",summary:"Drop one or all frame backdrops so they inherit the strip again.",studioCommands:["clearPanelBackground","clearAllPanelBackgrounds"],wire:null,targets:["frame"],requiredInputs:[],reason:"Agent refinement cannot reset backdrop inheritance. Use the frame background reset control in Studio to return it to the strip default.",evaluationCases:["unsupported-frame-background-reset"]},{id:"strip.background-broadcast",domain:"look",status:"intentionally_excluded",summary:"Copy one frame’s backdrop onto every frame, or promote it to the strip default.",studioCommands:["applyBackgroundToAllPanels","setStripDefaultBackground"],wire:null,targets:["project"],requiredInputs:[],reason:"No Studio surface offers these transfers today; the Agent writes the strip backdrop directly.",evaluationCases:["unsupported-background-broadcast"]},{id:"frame.color",domain:"look",status:"intentionally_excluded",summary:"Set the legacy per-panel colour that sits under a frame’s backdrop.",studioCommands:["setPanelColor"],wire:null,targets:["frame"],requiredInputs:[],reason:"No Studio surface dispatches it. A flat colour is a one-stop frame backdrop (`frame.background`), so a request for one is carried out there, never refused.",evaluationCases:["background-frame-three-flat-teal"]},{id:"look.design-preset",domain:"look",status:"supported",summary:"Apply a named design preset to the whole strip.",studioCommands:[],wire:"patch.designPreset",targets:["project"],requiredInputs:["a catalog preset id"],evaluationCases:["styling-apply-design-preset"]},{id:"look.layout-template",domain:"look",status:"supported",summary:"Apply a layout template, or explicitly reset one frame to its saved template baseline.",studioCommands:["applyLayoutTemplate","resetFrameTemplate"],wire:"patch.layout, or structuralOperations: frame.template-reset",targets:["project","frame"],requiredInputs:["a catalog layout id, or the frameId named in an explicit reset/revert request"],limits:["Never reset implicitly while handling a general styling request; reset may remove added screens or captions."],evaluationCases:["layout-use-bleed"]},{id:"look.apply-saved",domain:"look",status:"intentionally_excluded",summary:"Restore the project’s saved Look, or one of its earlier versions.",studioCommands:["applyLook"],wire:null,targets:["project"],requiredInputs:[],reason:"Agent refinement cannot restore a saved Look. Restore the saved version through Look version history in Studio.",evaluationCases:["unsupported-restore-saved-look"]},{id:"output.membership",domain:"output",status:"supported",summary:"Add or remove the store output sizes this project renders for.",studioCommands:["addOutput","removeOutput","setActiveOutput"],wire:"patch.outputs",targets:["project"],requiredInputs:["the complete output list"],limits:["Which output is previewed on screen stays a Studio cursor."],evaluationCases:["project-add-android-output"]},{id:"locale.membership",domain:"locale",status:"supported",summary:"Add or remove the languages this project is captioned in.",studioCommands:["addLocale","removeLocale"],wire:"patch.locales",targets:["project"],requiredInputs:["the complete language list"],limits:["The base language cannot be removed, and which language is being authored stays a Studio cursor."],evaluationCases:["project-add-german-locale","geometry-clear-while-adding-a-language"]},{id:"strip.add-screens",domain:"asset",status:"supported",summary:"Add new screenshots to the project, each in its own frame.",studioCommands:["addShots"],wire:"structuralOperations: frame.add with a frameRef, then device.add into it, once per screenshot from AVAILABLE SCREENSHOTS",targets:["project"],requiredInputs:["one or more authorized screenshot references"],withoutAssetReason:"New frames need new pixels. Send the screenshots with the instruction and the Agent will place them.",limits:["Only screenshots listed in AVAILABLE SCREENSHOTS; the Agent never invents or generates pixels.","Each new frame starts without a caption and its device on the default look, exactly as adding screenshots in Studio does."],evaluationCases:["asset-add-screens-supplied","asset-add-screens-needs-pixels"]},{id:"strip.replace-screens",domain:"asset",status:"supported",summary:"Replace every screenshot in the project, keeping the styling.",studioCommands:["loadScreens"],wire:"structuralOperations: device.replace on every device in strip order, each naming its own assetId from AVAILABLE SCREENSHOTS",targets:["project"],requiredInputs:["a complete authorized screenshot set"],withoutAssetReason:"Replacing the whole strip needs the whole new set of pixels. This instruction carried none.",limits:["Only screenshots listed in AVAILABLE SCREENSHOTS; the Agent never invents or generates pixels.","Every device keeps its look, placement, captions, translated screens and Output membership — only the pixels change.","When the supplied screenshots do not match the devices one to one, the Agent asks which goes where instead of swapping some of them."],evaluationCases:["asset-replace-all-screens-supplied","asset-replace-all-screens-needs-pixels","asset-replace-all-screens-count-mismatch"]},{id:"locale.load-screens",domain:"asset",status:"requires_asset",summary:"Supply localized screenshots for one language.",studioCommands:["loadLocaleScreens"],wire:null,targets:["project"],requiredInputs:["the language","authorized screenshots named for the frames they belong to"],reason:"A localized screen is different pixels, not a different caption.",evaluationCases:["asset-locale-screens-needs-pixels"]},{id:"output.load-screens",domain:"asset",status:"requires_asset",summary:"Supply screenshots captured at another output size.",studioCommands:["loadOutputScreens"],wire:null,targets:["project"],requiredInputs:["the output family","authorized screenshots named for the frames they belong to"],reason:"A second output size needs its own captures; the Agent cannot resample one from another.",evaluationCases:["asset-output-screens-needs-pixels"]}],Fr="unknown",Nr=[{id:"image.generate",summary:"Generate or paint new imagery rather than arranging supplied screenshots."},{id:"animation.create",summary:"Animate a screen, produce a video, or export motion instead of stills."},{id:"device.unsupported-model",summary:"Use a device model ShotOps does not offer."}],Br=Rr.map(e=>e.id);[...Br,...Nr.map(e=>e.id)];const Vt=[{code:"ar-SA",name:"Arabic",script:"rtl",dir:"rtl"},{code:"bn-BD",name:"Bengali",script:"indic",dir:"ltr"},{code:"ca",name:"Catalan",script:"latin",dir:"ltr"},{code:"cs",name:"Czech",script:"latin",dir:"ltr"},{code:"da",name:"Danish",script:"latin",dir:"ltr"},{code:"de-DE",name:"German",script:"latin",dir:"ltr"},{code:"el",name:"Greek",script:"greek",dir:"ltr"},{code:"en-AU",name:"English (Australia)",script:"latin",dir:"ltr"},{code:"en-CA",name:"English (Canada)",script:"latin",dir:"ltr"},{code:"en-GB",name:"English (U.K.)",script:"latin",dir:"ltr"},{code:"en-US",name:"English (U.S.)",script:"latin",dir:"ltr"},{code:"es-ES",name:"Spanish (Spain)",script:"latin",dir:"ltr"},{code:"es-MX",name:"Spanish (Mexico)",script:"latin",dir:"ltr"},{code:"fi",name:"Finnish",script:"latin",dir:"ltr"},{code:"fr-CA",name:"French (Canada)",script:"latin",dir:"ltr"},{code:"fr-FR",name:"French",script:"latin",dir:"ltr"},{code:"gu-IN",name:"Gujarati",script:"indic",dir:"ltr"},{code:"he",name:"Hebrew",script:"rtl",dir:"rtl"},{code:"hi",name:"Hindi",script:"indic",dir:"ltr"},{code:"hr",name:"Croatian",script:"latin",dir:"ltr"},{code:"hu",name:"Hungarian",script:"latin",dir:"ltr"},{code:"id",name:"Indonesian",script:"latin",dir:"ltr"},{code:"it",name:"Italian",script:"latin",dir:"ltr"},{code:"ja",name:"Japanese",script:"cjk",dir:"ltr"},{code:"kn-IN",name:"Kannada",script:"indic",dir:"ltr"},{code:"ko",name:"Korean",script:"cjk",dir:"ltr"},{code:"ml-IN",name:"Malayalam",script:"indic",dir:"ltr"},{code:"mr-IN",name:"Marathi",script:"indic",dir:"ltr"},{code:"ms",name:"Malay",script:"latin",dir:"ltr"},{code:"nl-NL",name:"Dutch",script:"latin",dir:"ltr"},{code:"no",name:"Norwegian",script:"latin",dir:"ltr"},{code:"or-IN",name:"Odia",script:"indic",dir:"ltr"},{code:"pa-IN",name:"Punjabi",script:"indic",dir:"ltr"},{code:"pl",name:"Polish",script:"latin",dir:"ltr"},{code:"pt-BR",name:"Portuguese (Brazil)",script:"latin",dir:"ltr"},{code:"pt-PT",name:"Portuguese (Portugal)",script:"latin",dir:"ltr"},{code:"ro",name:"Romanian",script:"latin",dir:"ltr"},{code:"ru",name:"Russian",script:"cyrillic",dir:"ltr"},{code:"sk",name:"Slovak",script:"latin",dir:"ltr"},{code:"sl-SI",name:"Slovenian",script:"latin",dir:"ltr"},{code:"sv",name:"Swedish",script:"latin",dir:"ltr"},{code:"ta-IN",name:"Tamil",script:"indic",dir:"ltr"},{code:"te-IN",name:"Telugu",script:"indic",dir:"ltr"},{code:"th",name:"Thai",script:"thai",dir:"ltr"},{code:"tr",name:"Turkish",script:"latin",dir:"ltr"},{code:"uk",name:"Ukrainian",script:"cyrillic",dir:"ltr"},{code:"ur-PK",name:"Urdu",script:"rtl",dir:"rtl"},{code:"vi",name:"Vietnamese",script:"latin",dir:"ltr"},{code:"zh-Hans",name:"Chinese (Simplified)",script:"cjk",dir:"ltr"},{code:"zh-Hant",name:"Chinese (Traditional)",script:"cjk",dir:"ltr"}];Vt.map(e=>e.code);Object.fromEntries(Vt.map(e=>[e.code,e]));({...Ee});function _r(e,t){t.material==="clay"?(e.setClay(t.clayTone==="custom"?`#${t.clayCustom}`:t.clayTone),e.setClearcoat(0)):(e.clayOff(),t.colorway==="custom"?e.setCustomColor(`#${t.customColor}`):e.setColorway(t.colorway),e.setFinish(M("finish",t.finish)),e.setClearcoat(M("clearcoat",t.clearcoat)))}function zr(e,t,n){e.screen.setGlare(!n&&t?e.device.environmentMap():null)}async function jr(e,t,n,r){const{stage:o,device:a,screen:s}=e,i=t.material==="clay";if(t.cameraPos?o.setCameraPosition(t.cameraPos):o.setAngle(t.angle),a.setRoll(M("roll",t.roll)),_r(a,t),s.restoreScreen(),o.setStudioLighting(t.lighting),a.setReflections(t.reflections),s.setFlatScreen(t.flatScreen),n){try{await s.applyWallpaper(n)}catch{}if(!r())return}zr(e,t.glare,i)}const Qe=1900,et=2800,Dr=8192,Ur=2;async function Wr(e,t,n,r={}){const o=e.renderer,a=o.getPixelRatio(),s=o.getSize(new mt);o.setDrawingBufferSize(t,n,1);let i;r.cameraPosition?(i=new Ce(Oe,t/n,.01,100),i.position.copy(r.cameraPosition),i.lookAt(0,0,0)):(i=e.camera.clone(),i.aspect=t/n,i.updateProjectionMatrix());try{const c=e.scene.background;e.scene.background=null;try{o.render(e.scene,i)}finally{e.scene.background=c}const l=document.createElement("canvas");let d=null;try{l.width=t,l.height=n,l.getContext("2d")?.drawImage(o.domElement,0,0);const u=qt(l),p=u.canvas;d=p;const f=p.width,m=p.height;return{bytes:await new Promise((h,y)=>{p.toBlob(b=>{if(!b){y(new Error("toBlob returned null"));return}b.arrayBuffer().then(v=>h(new Uint8Array(v)),y)},"image/png")}),width:f,height:m,frame:{width:t,height:n,cropX:u.x,cropY:u.y}}}finally{d&&d!==l&&(d.width=0,d.height=0),l.width=0,l.height=0}}finally{o.setDrawingBufferSize(s.x,s.y,a),e.invalidate()}}function qt(e,t=Ur){const n=e.getContext("2d",{willReadFrequently:!0});if(!n)return{canvas:e,x:0,y:0};const{width:r,height:o}=e,a=n.getImageData(0,0,r,o).data;let s=r,i=o,c=-1,l=-1;for(let f=0;f<o;f++)for(let m=0;m<r;m++)a[(f*r+m)*4+3]!==0&&(m<s&&(s=m),m>c&&(c=m),f<i&&(i=f),f>l&&(l=f));if(c<s||l<i)return{canvas:e,x:0,y:0};s=Math.max(0,s-t),i=Math.max(0,i-t),c=Math.min(r-1,c+t),l=Math.min(o-1,l+t);const d=c-s+1,u=l-i+1,p=document.createElement("canvas");return p.width=d,p.height=u,p.getContext("2d")?.drawImage(e,s,i,d,u,0,0,d,u),{canvas:p,x:s,y:i}}function Hr(e){const t=URL.createObjectURL(new Blob([e],{type:"image/png"}));return new Promise((n,r)=>{const o=new Image;o.onload=()=>{URL.revokeObjectURL(t),n(o)},o.onerror=()=>{URL.revokeObjectURL(t),r(new Error("Screenshot could not be decoded for the flat card"))},o.src=t})}function Gr(e,t,n,r){if(e.beginPath(),r<=0){e.rect(0,0,t,n);return}e.moveTo(r,0),e.arcTo(t,0,t,n,r),e.arcTo(t,n,0,n,r),e.arcTo(0,n,0,0,r),e.arcTo(0,0,t,0,r),e.closePath()}function $r(e,t,n,r){const o=t?"naturalWidth"in t?t.naturalWidth:t.width:0,a=t?"naturalHeight"in t?t.naturalHeight:t.height:0,s=Cr(o,a,n,r),{width:i,height:c,cardWidth:l,cardHeight:d,radius:u,rotation:p}=s;e.width=i,e.height=c;const f=e.getContext("2d");if(!f)throw new Error("2D context unavailable for the flat card");return f.translate(i/2,c/2),f.rotate(p),f.translate(-l/2,-d/2),Gr(f,l,d,u),f.clip(),t?(f.imageSmoothingQuality="high",f.drawImage(t,0,0,l,d)):(f.fillStyle="#000",f.fillRect(0,0,l,d)),s}async function Vr(e,t,n){return(await Kt(e,t,n)).out}async function Kt(e,t,n){const r=e?await Hr(e):null,o=document.createElement("canvas");try{const a=$r(o,r,t,n),{width:s,height:i}=a;return{out:{bytes:await new Promise((l,d)=>{o.toBlob(u=>{if(!u){d(new Error("toBlob returned null"));return}u.arrayBuffer().then(p=>l(new Uint8Array(p)),d)},"image/png")}),width:s,height:i,frame:{width:s,height:i,cropX:0,cropY:0}},geometry:a}}finally{o.width=0,o.height=0}}const tt=24*1024*1024,Ie=new WeakMap;async function qr(e){const t=await mr(e.bytes);return xe({look:e.look,screenshot:t,width:e.width,height:e.height,physicalBody:e.physicalBody,screenLayers:e.screenLayers})}function Kr(e,t){const n=Ie.get(e);if(!n)return;const r=n.entries.get(t);if(r)return n.entries.delete(t),n.entries.set(t,r),r}function Yr(e,t,n){const r=n.bytes.byteLength;if(r>tt)return;let o=Ie.get(e);o||(o={entries:new Map,bytes:0},Ie.set(e,o));const a=o.entries.get(t);a&&(o.bytes-=a.bytes.byteLength),o.entries.delete(t),o.entries.set(t,n),o.bytes+=r;const s=Array.from(o.entries.keys());for(let i=0;i<s.length&&o.bytes>tt;i++){const c=o.entries.get(s[i]);c&&(o.bytes-=c.bytes.byteLength,o.entries.delete(s[i]))}}function xe(e){if(e===null||typeof e!="object")return JSON.stringify(e)??"null";if(Array.isArray(e))return`[${e.map(xe).join(",")}]`;const t=e;return`{${Object.keys(t).filter(r=>t[r]!==void 0).sort().map(r=>`${JSON.stringify(r)}:${xe(t[r])}`).join(",")}}`}function Xr(e,t,n,r,o){return{x:(e.x+1)/2*t-r,y:(1-e.y)/2*n-o}}function Jr(e){const{width:t,height:n,cardWidth:r,cardHeight:o,rotation:a}=e,s=Math.cos(a),i=Math.sin(a),c=(u,p)=>({x:t/2+u*s-p*i,y:n/2+u*i+p*s}),l=r/2,d=o/2;return{tl:c(-l,-d),tr:c(l,-d),br:c(l,d),bl:c(-l,d)}}function le(e){return new Promise((t,n)=>{e.toBlob(r=>{if(!r){n(new Error("toBlob returned null"));return}r.arrayBuffer().then(o=>t(new Uint8Array(o)),n)},"image/png")})}function nt(e,t,n,r,o){const a=document.createElement("canvas");return a.width=r,a.height=o,a.getContext("2d")?.drawImage(e,t,n,r,o,0,0,r,o),a}function Zr(e,t){const n=Math.hypot(e.tr.x-e.tl.x,e.tr.y-e.tl.y),r=Math.hypot(e.bl.x-e.tl.x,e.bl.y-e.tl.y);return n>0?Math.min(n,r)*t/n:0}async function Qr(e,t,n,r,o,a={}){const s=e.renderer,i=s.getPixelRatio(),c=s.getSize(new mt);s.setDrawingBufferSize(n,r,1);let l;a.cameraPosition?(l=new Ce(Oe,n/r,.01,100),l.position.copy(a.cameraPosition),l.lookAt(0,0,0)):(l=e.camera.clone(),l.aspect=n/r,l.updateProjectionMatrix()),l.updateMatrixWorld();const d=[],u=()=>{const p=document.createElement("canvas");return p.width=n,p.height=r,d.push(p),p};try{const p=u(),f=u(),m=u(),g=e.scene.background;e.scene.background=null;try{s.render(e.scene,l),p.getContext("2d")?.drawImage(s.domElement,0,0);try{t.setLayerPass("device"),s.render(e.scene,l),f.getContext("2d")?.drawImage(s.domElement,0,0),t.setLayerPass("screen"),s.render(e.scene,l),m.getContext("2d")?.drawImage(s.domElement,0,0)}finally{t.restoreLayerPass()}}finally{e.scene.background=g}const h=qt(p);h.canvas!==p&&d.push(h.canvas);const y=h.canvas.width,b=h.canvas.height,v=nt(f,h.x,h.y,y,b),S=nt(m,h.x,h.y,y,b);d.push(v,S),e.scene.updateMatrixWorld();const P=t.screenCornersWorld(),C=T=>{const _=T.clone().project(l);return Xr(_,n,r,h.x,h.y)},w={x:0,y:0},I=P?{tl:C(P.tl),tr:C(P.tr),br:C(P.br),bl:C(P.bl)}:{tl:w,tr:w,br:w,bl:w},[x,A,O]=[await le(h.canvas),await le(v),await le(S)];return{bytes:x,width:y,height:b,frame:{width:n,height:r,cropX:h.x,cropY:h.y},layers:{width:y,height:b,device:A,screen:{bytes:O,quad:I,cornerRadiusFrac:Zr(I,t.cornerRatio),sourceNodeId:o}}}}finally{d.forEach(p=>{p.width=0,p.height=0}),s.setDrawingBufferSize(c.x,c.y,i),e.invalidate()}}async function eo(e,t,n,r){const{out:o,geometry:a}=await Kt(e,t,n);return to(o,a,r)}function to(e,t,n){const r=Jr(t);return{...e,layers:{width:e.width,height:e.height,device:null,screen:{bytes:e.bytes,quad:r,cornerRadiusFrac:t.cardWidth>0?t.radius/t.cardWidth:0,sourceNodeId:n}}}}function no(e,t,n){return{shots:e,panels:t,selectedShotId:n.selectedShotId,panelPresetId:n.panelPresetId,bgMode:n.bgMode,gradientStops:n.gradientStops,gradientAngle:n.gradientAngle,gradientFrom:n.gradientFrom,gradientTo:n.gradientTo,gradientDir:n.gradientDir,panelColors:n.panelColors,shadow:n.shadow,floorReflection:n.floorReflection,panelBackgrounds:n.panelBackgrounds,captionStyles:n.captionStyles,captionText:n.captionText,locales:n.locales,baseLocale:n.baseLocale,outputs:n.outputs}}function ro(e,t){return e.usesPhysicalFinish()?!0:t.material!=="clay"&&M("clearcoat",t.clearcoat)>0}async function oo(e,t,n,r,o,a){const s=K(n,r),i=s.filter(m=>m.bytes);if(i.length===0)return null;const c=q(o.panelPresetId),l=new Map(r.map((m,g)=>[m.id,g])),d=o.renderScale!=null&&Number.isFinite(o.renderScale)&&o.renderScale>0?o.renderScale:1,u=Math.min(d,Dr/Math.max(Qe,et)),p=Math.max(1,Math.round(Qe*u)),f=Math.max(1,Math.round(et*u));{const m=[];for(let b=0;b<i.length;b++){const v=i[b];a(`Rendering ${b+1}/${i.length}${o.locale?` (${o.locale})`:""}…`);let S,P;const C=v.frameNodeId||null,w=o.screenLayers||!v.bytes?null:await qr({look:v.look,bytes:v.bytes,width:p,height:f,physicalBody:ro(t.device,v.look),screenLayers:!1}),I=w?Kr(e,w):void 0;if(I)S=I;else if(Pr(v.look)){await jr(t,v.look,v.bytes,()=>!0);const x=Bn(v.look.angle,v.look.cameraPos);if(o.screenLayers){const A=await Qr(e,t.screen,p,f,C,{cameraPosition:x});S=A,P=A.layers}else S=await Wr(e,p,f,{cameraPosition:x})}else if(o.screenLayers){const x=await eo(v.bytes,v.look,f,C);S=x,P=x.layers}else S=await Vr(v.bytes,v.look,f);w&&!I&&Yr(e,w,S),m.push({shotId:v.id,bytes:S.bytes,width:S.width,height:S.height,heightFrac:Wn(M("deviceSize",v.look.deviceSize)),hOffset:M("hOffset",v.look.hOffset)/100,vOffset:M("vOffset",v.look.vOffset)/100,panelIndex:l.get(v.panelId)??0,...v.look.clipToFrame===!0?{clipToFrame:!0}:{},...P?{layers:P}:{}})}const g=Ir(m,c.width,c.height),h=xr(r,o);a("Saving project…");const y=$t(no(s,r,o));return{panelWidth:c.width,panelHeight:c.height,count:r.length,background:h,phones:g,shadow:o.shadow,floorReflection:o.floorReflection??!1,project:JSON.stringify(y)}}}function re(e){return/^[0-9a-fA-F]{3,8}$/.test(e)?`#${e}`:e}function Ae(e,t,n,r){const{x0:o,y0:a,x1:s,y1:i}=rr(n,r,t.angle),c=e.createLinearGradient(o,a,s,i);for(const l of t.stops)c.addColorStop(Math.min(1,Math.max(0,l.at)),re(l.color));return c}function J(e,t,n,r,o,a,s){const i=document.createElement("canvas");i.width=n,i.height=r;try{const c=i.getContext("2d");if(!c)return;c.fillStyle=Ae(c,t,n,r),c.fillRect(o,0,a,r),e.drawImage(i,o,0,a,r,s,0,a,r)}finally{i.width=0,i.height=0}}function rt(e){return URL.createObjectURL(new Blob([e],{type:"image/png"}))}function ot(e){return new Promise((t,n)=>{const r=new Image;r.onload=()=>t(r),r.onerror=n,r.src=e})}const ao=16*1024*1024;function at(e){const t=(e.img.naturalWidth||0)*(e.img.naturalHeight||0),n=e.reflection?e.reflection.canvas.width*e.reflection.canvas.height:0;return t+n}function Yt(){let e=0;const t=Array.from(B.values());for(const o of t)e+=at(o);const n=Array.from(B.keys());let r=0;for(;e>ao&&r<n.length-1;){const o=B.get(n[r]);o&&(e-=at(o),o.reflection&&(o.reflection.canvas.width=0,o.reflection.canvas.height=0),B.delete(n[r])),r++}}const B=new Map,ce=new Map;async function so(e,t){if(!t){const a=rt(e);try{return{img:await ot(a)}}finally{URL.revokeObjectURL(a)}}const n=B.get(e);if(n)return B.delete(e),B.set(e,n),n;const r=ce.get(e);if(r)return r;const o=(async()=>{const a=rt(e);try{return{img:await ot(a)}}finally{URL.revokeObjectURL(a)}})();ce.set(e,o);try{const a=await o;return B.set(e,a),Yt(),a}finally{ce.delete(e)}}async function io(e,t,n){const r=t.panelWidth*t.count,o=t.panelHeight,a=n?.backgroundViewport,s=a?t.panelWidth*a.panelCount:r,i=a?t.panelWidth*a.panelIndex:0,c=n?.panelViewport,l=c===void 0?0:c*t.panelWidth,d=c===void 0?r:t.panelWidth;e.width=d,e.height=o;const u=e.getContext("2d");if(!u)return;n?.transparentBg?u.clearRect(0,0,r,o):t.background.kind==="gradient"?c!==void 0?J(u,t.background.gradient,r,o,l,d,0):a?J(u,t.background.gradient,s,o,i,r,0):(u.fillStyle=Ae(u,t.background.gradient,r,o),u.fillRect(0,0,r,o)):t.background.kind==="perPanel"?t.background.colors.forEach((g,h)=>{u.fillStyle=re(g),u.fillRect(h*t.panelWidth-l,0,t.panelWidth,o)}):t.background.fills.forEach((g,h)=>{const y=h*t.panelWidth-l;c!==void 0&&h!==c||(g.kind==="solid"?(u.fillStyle=re(g.color),u.fillRect(y,0,t.panelWidth,o)):c!==void 0?J(u,g.gradient,r,o,l,d,0):a?J(u,g.gradient,s,o,i+y,t.panelWidth,y):(u.fillStyle=Ae(u,g.gradient,r,o),u.fillRect(y,0,t.panelWidth,o)))}),u.save(),u.translate(-l,0);const p=n?.phoneRange?Math.max(0,n.phoneRange.start):0,f=n?.phoneRange?Math.min(t.phones.length,n.phoneRange.end):t.phones.length,m=n?.reuseDecodedPhones===!0;for(let g=p;g<f;g++){const h=t.phones[g],y=n?.clip==="panel"||n?.clip===void 0&&h.clipToFrame===!0;if(n?.skipShotId&&h.shotId===n.skipShotId)continue;const b=await so(h.bytes,m),v=b.img;y&&(u.save(),u.beginPath(),u.rect(h.panelIndex*t.panelWidth,0,t.panelWidth,o),u.clip()),t.floorReflection&&lo(u,b,h,m),u.save(),t.shadow&&(u.shadowColor="rgba(0,0,0,0.35)",u.shadowBlur=t.panelWidth*.03,u.shadowOffsetY=t.panelHeight*.012),u.drawImage(v,h.x,h.y,h.width,h.height),u.restore(),y&&u.restore()}u.restore()}function lo(e,t,n,r){const o=Math.round(n.height*.45);if(o<=0||n.width<=0)return;const a=r?t.reflection:void 0;if(a&&a.width===n.width&&a.height===n.height){e.drawImage(a.canvas,n.x,n.y+n.height,n.width,o);return}const s=t.img,i=document.createElement("canvas");i.width=Math.max(1,n.width),i.height=Math.max(1,o);const c=i.getContext("2d");if(!c)return;c.save(),c.translate(0,o),c.scale(1,-1),c.drawImage(s,0,o-n.height,n.width,n.height),c.restore();const l=c.createLinearGradient(0,0,0,o);l.addColorStop(0,"rgba(0,0,0,0.34)"),l.addColorStop(1,"rgba(0,0,0,0)"),c.globalCompositeOperation="destination-in",c.fillStyle=l,c.fillRect(0,0,n.width,o),e.drawImage(i,n.x,n.y+n.height,n.width,o),r&&(t.reflection={width:n.width,height:n.height,canvas:i},Yt())}const Xt=1.2,co=.06,uo=.5;function po(e,t,n){if(!e)return[t];const r=t.split(/\s+/).filter(Boolean),o=[];let a="";for(const s of r){const i=a?`${a} ${s}`:s;a&&e.measureText(i).width>n?(o.push(a),a=s):a=i}return a&&o.push(a),o}function fo(e,t){if(!e)return 0;let n=0;for(const r of t)n=Math.max(n,e.measureText(r).width);return n}function Jt(e,t,n,r){const o=t.map((m,g)=>{const h=m.text.trim();if(!h)return null;const y=m.sizePt*(r/oe),b=Te(m.fontId).family;e&&(e.font=`${$} ${y}px "${b}"`);const v=po(e,h,m.maxWidth*n),S=y*(m.lineHeight??Xt),P=v.length*S,C=Math.max(P,(m.reserveLines??v.length)*S);return{layer:m,index:g,lines:v,px:y,lineH:S,width:fo(e,v),blockH:P,reservedH:C}}),a=o.filter(m=>m!==null&&D(m.layer.anchor)),s=a.filter(m=>m.layer.band==="bottom"),i=a.filter(m=>m.layer.band!=="bottom"),c=m=>m[0]?.layer.bandInset??co,l=(1-c(s))*r-s.reduce((m,g)=>m+g.reservedH,0);let d=c(i)*r,u=l,p=0;const f=[];for(const m of o){if(!m)continue;if(!D(m.layer.anchor)){f.push({layer:m.layer,index:m.index,x:m.layer.anchor.x*n,yTop:m.layer.anchor.y*r,lines:m.lines,px:m.px,lineH:m.lineH,width:m.width});continue}const g=m.layer.band==="bottom",y=(g?u:d)+(m.reservedH-m.blockH)/2,b=(m.layer.bandCenter??uo)*n;f.push({layer:m.layer,index:m.index,x:b,yTop:y,lines:m.lines,px:m.px,lineH:m.lineH,width:m.width}),g?u+=m.reservedH:d+=m.reservedH,p=Math.max(p,y+m.blockH)}return{placed:f,bandBottom:p}}function ho(e,t,n,r){e.save(),e.textBaseline="top";const{placed:o}=Jt(e,t,n,r);for(const a of o){e.fillStyle=re(a.layer.color),e.textAlign=a.layer.align,e.font=`${$} ${a.px}px "${Te(a.layer.fontId).family}"`;let s=a.yTop;for(const i of a.lines)e.fillText(i,a.x,s),s+=a.lineH}e.restore()}function mo(e,t){return e.sizePt*(t/oe)*(e.lineHeight??Xt)}function go(e,t,n,r){const o=Jt(e,t,n,r).placed;e?.save(),e&&(e.textBaseline="top");const a=o.map(s=>{const i=s.layer.align==="center"?s.x-s.width/2:s.layer.align==="right"?s.x-s.width:s.x,c=s.lines.length*s.lineH;let l=s.yTop,d=s.yTop+c;if(e){e.font=`${$} ${s.px}px "${Te(s.layer.fontId).family}"`;const u=e.measureText(s.lines[0]).actualBoundingBoxAscent,p=e.measureText(s.lines[s.lines.length-1]).actualBoundingBoxDescent;Number.isFinite(u)&&Number.isFinite(p)&&(l=s.yTop-u,d=s.yTop+(s.lines.length-1)*s.lineH+p)}return{index:s.index,anchorX:s.x/n,top:s.yTop/r,left:i/n,width:s.width/n,height:c/r,inkTop:l/r,inkHeight:(d-l)/r}});return e?.restore(),a}function yo(e,t,n,r,o){t.forEach((a,s)=>{const i=o[a];!i||i.length===0||(e.save(),e.translate(s*n,0),ho(e,i,n,r),e.restore())})}const bo=""+new URL("Inter-SemiBold-B9yU462S.woff2",import.meta.url).href,vo=""+new URL("Manrope-SemiBold-44nuYf5T.woff2",import.meta.url).href,wo=""+new URL("Poppins-SemiBold-DJVo7c07.woff2",import.meta.url).href,So=""+new URL("Fraunces-SemiBold-BtraKtER.woff2",import.meta.url).href,Io=""+new URL("SpaceGrotesk-SemiBold-CyO2J5Y0.woff2",import.meta.url).href,xo={inter:bo,manrope:vo,poppins:wo,fraunces:So,"space-grotesk":Io},Ao=ee.map(e=>({...e,url:xo[e.id]}));let Z=null;function Po(){return Z||(Z=(async()=>{const e=new Set;document.fonts.forEach(t=>e.add(`${t.family}/${t.weight}`)),await Promise.all(Ao.filter(t=>!e.has(`${t.family}/${String($)}`)).map(async t=>{const n=new FontFace(t.family,`url(${t.url})`,{weight:String($)});await n.load(),document.fonts.add(n)})),await document.fonts.ready})().catch(e=>{throw Z=null,e})),Z}const Co=22/oe,ko=1.1,st=4,Oo=.063,To=.167,it=Math.round(Co*oe),Eo=.02,Lo=50;function j(e,t){const n=Math.max(e.x,t.x),r=Math.max(e.y,t.y),o=Math.min(e.x+e.width,t.x+t.width),a=Math.min(e.y+e.height,t.y+t.height);return o<=n||a<=r?null:{x:n,y:r,width:o-n,height:a-r}}function Zt(e,t){return j(e,t)}function lt(e,t){const n=Math.abs(e-t)%360;return n>180?360-n:n}function ct(e){return Fn(e.cameraPos??gt(e.angle))}function Fe(e,t,n,r,o,a,s){if(t.length===0)return[];const i=[];for(const c of go(e,t,o,a)){const l=t[c.index];if(!l)continue;const d=Zt({x:(r+c.left)*o,y:c.top*a,width:c.width*o,height:c.height*a},s);d&&i.push({ref:{panelId:n,panelIndex:r,layerIndex:c.index,band:D(l.anchor)},box:d,lineHeightPx:mo(l,a)})}return i}function Mo(e,t,n,r){return n.height<=Pe(e,t,r)}function Pe(e,t,n){const r=e.y+e.height/2<=t.y+t.height/2;return n*(r?To:Oo)}function Ro(e,t,n){return n.height<=Pe(e.box,t.box,e.lineHeightPx)+Pe(t.box,e.box,t.lineHeightPx)}function Fo(e){const{ctx:t,panelIds:n,panelWidth:r,panelHeight:o}=e,a={x:0,y:0,width:r*n.length,height:o};t?.save();try{return No(e,a)}finally{t?.restore()}}function No(e,t){const{ctx:n,panelIds:r,panelWidth:o,panelHeight:a,captionLayers:s}=e,i=r.flatMap((g,h)=>Fe(n,s[g]??[],g,h,o,a,t)),c=[];for(const g of e.phones){const y=e.clip==="panel"||e.clip===void 0&&g.clipToFrame===!0?{x:g.panelIndex*o,y:0,width:o,height:a}:t,b=Zt({x:g.x,y:g.y,width:g.width,height:g.height},y);b&&c.push({shotId:g.shotId,box:b,layoutHeight:g.height})}const l=[];for(let g=0;g<i.length;g++)for(let h=g+1;h<i.length;h++){const y=j(i[g].box,i[h].box);y&&l.push({a:i[g].ref,b:i[h].ref,overlap:y,depthFrac:a>0?y.height/a:0,inkUncertain:Ro(i[g],i[h],y)})}const d=[];for(const g of i)for(const h of c){const y=j(g.box,h.box);y&&d.push({caption:g.ref,shotId:h.shotId,overlap:y,depthFrac:a>0?y.height/a:0,inkUncertain:Mo(g.box,h.box,y,g.lineHeightPx)})}const u=[];for(let g=0;g<c.length;g++)for(let h=g+1;h<c.length;h++){const y=c[g],b=c[h],v=j(y.box,b.box);if(!v)continue;const S=[],P=Math.max(y.layoutHeight,b.layoutHeight),C=Math.min(y.layoutHeight,b.layoutHeight);C>0&&P/C>=ko&&S.push("scale");const w=e.looks?.[y.shotId],I=e.looks?.[b.shotId],x=!!w&&!!I;w&&I&&(lt(ct(w),ct(I))>=st&&S.push("angle"),lt(M("roll",w.roll),M("roll",I.roll))>=st&&S.push("roll"));const A=Math.min(y.box.width*y.box.height,b.box.width*b.box.height);u.push({shotIdA:y.shotId,shotIdB:b.shotId,overlap:v,coverage:A>0?v.width*v.height/A:0,deliberate:S.length>0,signals:S,anglesKnown:x})}const p=new Set;for(const g of l)g.a.band&&p.add(g.a.panelId),g.b.band&&p.add(g.b.panelId);for(const g of d)g.caption.band&&p.add(g.caption.panelId);const f=[],m=[];return r.forEach((g,h)=>{if(!p.has(g))return;const y=Bo(e,g,h,t,i,c);y!==null&&m.push({panelId:g,maxWidth:y});const b=_o(e,g,h,t,i,c);b&&f.push(b)}),{captionsMeasurable:n!=null,captionOverlaps:l,captionDeviceOverlaps:d,deviceOverlaps:u,suggestions:f,widthSuggestions:m,hasWarning:l.length>0||d.length>0||u.some(g=>!g.deliberate)}}function Bo(e,t,n,r,o,a){const s=e.captionLayers[t]??[];if(!s.length||s.some(l=>!D(l.anchor)))return null;const i=[...a.map(l=>l.box),...o.filter(l=>l.ref.panelId!==t).map(l=>l.box)],c=Math.min(...s.map(l=>l.maxWidth));for(let l=Math.ceil(c*100)-1;l>=10;l--){const d=l/100,u=Fe(e.ctx,s.map(p=>({...p,maxWidth:d})),t,n,e.panelWidth,e.panelHeight,r);if(u.length&&u.every((p,f)=>!i.some(m=>j(p.box,m))&&!u.slice(f+1).some(m=>j(p.box,m.box))))return d}return null}function _o(e,t,n,r,o,a){const s=e.captionLayers[t]??[],i=s.flatMap((d,u)=>D(d.anchor)&&d.text.trim()?[u]:[]);if(i.length===0||!(Math.min(...i.map(d=>s[d].sizePt))>it))return null;const l=[...a.map(d=>d.box),...o.filter(d=>!(d.ref.panelId===t&&d.ref.band)).map(d=>d.box)];for(let d=1;d<=Lo;d++){const u=Math.round((1-d*Eo)*100)/100,p=new Map(i.map(h=>[h,s[h].sizePt*u]));if(Math.min(...p.values())<it)return null;const f=s.map((h,y)=>{const b=p.get(y);return b===void 0?h:{...h,sizePt:b}});if(Fe(e.ctx,f,t,n,e.panelWidth,e.panelHeight,r).filter(h=>h.ref.band).every(h=>!l.some(y=>j(h.box,y))))return{panelId:t,scale:u,layers:i.map(h=>({layerIndex:h,fromSizePt:s[h].sizePt,toSizePt:p.get(h)}))}}return null}function Ne(e){return`build-shot-${e+1}`}function Qt(e){const t=[];for(const n of e.shots)t.includes(n.panelId)||t.push(n.panelId);return t}const zo=1900,jo=2800;function Do(e){return new Promise((t,n)=>{e.toBlob(r=>{if(!r)return n(new Error("canvas toBlob returned null"));r.arrayBuffer().then(o=>t(new Uint8Array(o)),n)},"image/png")})}async function en(e,t,n,r={}){await Po();const o=Qt(e);if(r.panelViewport!==void 0&&(!Number.isInteger(r.panelViewport)||r.panelViewport<0||r.panelViewport>=o.length))throw new Error("buildStrip: panel viewport is outside the strip");const a=o.map(p=>({id:p})),s=e.shots.map((p,f)=>({id:Ne(f),panelId:p.panelId,frameNodeId:"",frameName:`screen-${f+1}`,bytes:t.screens[f]??null,look:p.look,thumb:null,thumbStale:!1})),c={panelPresetId:q(e.panelPresetId).id,bgMode:e.bgMode,gradientStops:e.gradientStops,gradientAngle:e.gradientAngle,gradientFrom:e.gradientFrom,gradientTo:e.gradientTo,gradientDir:e.gradientDir,panelColors:e.panelColors,shadow:e.shadow,floorReflection:e.floorReflection,panelBackgrounds:e.panelBackgrounds,selectedShotId:null,renderScale:r.renderScale,locale:n},l=r.onProgress??(()=>{});let d=r.refs,u=null;if(!d){const p=$n(e.panelPresetId);u=yt(zo,jo);const f=await bt(u,p);d={stage:u,device:new vt(f,u.scene,u.renderer,p),screen:new wt(f,p)}}try{const p=await oo(d.stage,d,s,a,c,l);if(!p)throw new Error("buildStrip: nothing renderable (no shots)");const f=document.createElement("canvas");try{const m={...r.panelViewport!==void 0?{panelViewport:r.panelViewport}:{},...r.clip?{clip:r.clip}:{},...r.backgroundViewport?{backgroundViewport:r.backgroundViewport}:{}};await io(f,p,Object.keys(m).length>0?m:void 0);const g=p.panelWidth,h=p.panelHeight,y=f.getContext("2d");if(!y)throw new Error("buildStrip: 2D context unavailable");y.save(),r.panelViewport!==void 0&&y.translate(-r.panelViewport*g,0),yo(y,o,g,h,t.captionText??{}),y.restore();const b=Fo({phones:p.phones,panelIds:o,captionLayers:t.captionText??{},panelWidth:g,panelHeight:h,ctx:y,looks:Object.fromEntries(s.map(I=>[I.id,I.look])),clip:r.clip}),v=r.renderScale&&r.renderScale>0&&r.renderScale<1?r.renderScale:1,S=[],P=r.panelViewport??0,C=r.panelViewport===void 0?p.count:P+1;for(let I=P;I<C;I++){const x=document.createElement("canvas");x.width=Math.max(1,Math.round(g*v)),x.height=Math.max(1,Math.round(h*v));const A=x.width,O=x.height;try{const T=x.getContext("2d");if(!T)throw new Error("buildStrip: 2D context unavailable");T.drawImage(f,r.panelViewport===void 0?I*g:0,0,g,h,0,0,A,O),S.push({index:I,bytes:await Do(x),width:A,height:O})}finally{x.width=0,x.height=0}}const w=p.phones.map(({shotId:I,panelIndex:x,x:A,y:O,width:T,height:_})=>({shotId:I,panelIndex:x,x:A,y:O,width:T,height:_}));return{panels:S,layout:b,phones:w}}finally{f.width=0,f.height=0}}finally{u&&u.dispose()}}const dt=.005,Uo=.02,Wo=12;function de(e){return Math.max(1,Math.round(e*100))}function ue(e){return`${e.kind}:${e.frames.join(",")}:${e.anchored}`}function Ho(e,t){const n=new Map(e.suggestions.map(s=>[s.panelId,s.scale])),r=new Map((e.widthSuggestions??[]).map(s=>[s.panelId,s.maxWidth])),o=[];for(const s of e.captionOverlaps){if(s.inkUncertain||s.depthFrac<dt)continue;const[i,c]=s.a.band===s.b.band?[s.a,s.b]:s.a.band?[s.a,s.b]:[s.b,s.a],l=pe([t.frameOfPanel(i.panelId),t.frameOfPanel(c.panelId)]);l.length!==0&&o.push({kind:"caption-caption",frames:l,depthPct:de(s.depthFrac),anchored:!s.a.band||!s.b.band,...ut(n,i.band?i.panelId:null),...pt(r,i.band?i.panelId:null)})}for(const s of e.captionDeviceOverlaps){if(s.inkUncertain||s.depthFrac<dt)continue;const i=pe([t.frameOfPanel(s.caption.panelId),t.frameOfShot(s.shotId)]);i.length!==0&&o.push({kind:"caption-device",frames:i,depthPct:de(s.depthFrac),anchored:!s.caption.band,...ut(n,s.caption.band?s.caption.panelId:null),...pt(r,s.caption.band?s.caption.panelId:null)})}for(const s of e.deviceOverlaps){if(s.deliberate||s.coverage<Uo)continue;const i=pe([t.frameOfShot(s.shotIdA),t.frameOfShot(s.shotIdB)]);i.length!==0&&o.push({kind:"device-device",frames:i,depthPct:de(s.coverage),anchored:!1})}const a=new Map;for(const s of o){const i=a.get(ue(s));i?s.depthPct>i.depthPct?a.set(ue(s),{...s,clearAtScale:s.clearAtScale??i.clearAtScale,clearAtMaxWidth:s.clearAtMaxWidth??i.clearAtMaxWidth}):i.clearAtScale==null&&s.clearAtScale!=null&&(i.clearAtScale=s.clearAtScale):a.set(ue(s),s),i&&i.clearAtMaxWidth==null&&s.clearAtMaxWidth!=null&&(i.clearAtMaxWidth=s.clearAtMaxWidth)}return[...a.values()].sort((s,i)=>i.depthPct-s.depthPct).slice(0,Wo).sort((s,i)=>s.frames[0]-i.frames[0]||s.kind.localeCompare(i.kind))}function pe(e){const[t,...n]=e;return t<0?[]:[t,...n.filter(r=>r>=0&&r!==t)]}function ut(e,t){const n=t==null?void 0:e.get(t);return n==null?{}:{clearAtScale:Math.round(n*100)/100}}function pt(e,t){const n=t==null?void 0:e.get(t);return n==null?{}:{clearAtMaxWidth:n}}function Go(e,t){if(t.length===0)return e;const n=e.captionStyles;if(!n)return e;const r={};for(const[o,a]of Object.entries(n))r[o]=a.map(s=>({...s}));for(const o of t){const a=r[o.panelId];if(a)for(const s of o.layers){const i=a[s.layerIndex];i&&(i.sizePt=s.toSizePt)}}return{...e,captionStyles:r}}function fe(e){return e.frames.map(t=>`frame ${t+1}`).join(" + ")}function $o(e,t,n){if(!e.captionsMeasurable)return null;const r=Ho(e,t);if(r.length===0)return null;const o=r.filter(l=>l.kind==="device-device"),a=r.filter(l=>l.kind!=="device-device"&&l.clearAtScale==null);if(o.length>0||a.length>0||!n){const l=[];o.length>0&&l.push(`${o.map(fe).join(", ")}: two devices overlap without reading as composed. There is no deterministic repair — give the pair a real difference in scale, camera angle or roll (that is what makes an overlap read as deliberate), or leave it if it already is.`);for(const d of a)l.push(d.anchored?`${fe(d)}: the caption is anchored by hand, so it is reported and never rewritten — move it, or drop its \`anchor\` to let the band place it.`:`${fe(d)}: no caption size above the legibility floor clears it — shorten the headline, or pick a layout with a bigger text region (\`style.layout: "bleed"\`).`);return l.length===0&&l.push("The rendered look was not available here, so no corrected look could be built."),{findings:r,note:`No corrected look is offered. ${l.join(" ")}`}}const s=new Set(r.filter(l=>l.kind!=="device-device").map(l=>l.frames[0])),i=e.suggestions.filter(l=>s.has(t.frameOfPanel(l.panelId))),c=i.flatMap(l=>{const d=t.frameOfPanel(l.panelId)+1;return l.layers.map(u=>`frame ${d} layer ${u.layerIndex+1}: sizePt ${u.fromSizePt} → ${u.toSizePt}`)}).join("; ");return{findings:r,correctedLook:Go(n,i),note:`\`layout.correctedLook\` is this same look with every caption shrunk to the largest size that was verified to clear the overlap (${c}). Nothing here is applied for you — re-render with it, or show the user the finding and let them decide. On render_strip pass it back as \`look\` together with the SAME \`style.captions\` you just sent: the words come from \`style.captions\` and every style field you leave out of them now comes from this look. The one thing that still beats it is a field you set EXPLICITLY on a caption entry, so if your \`style.captions\` pin \`sizePt\` at the original numbers, drop them or set them to the sizes above.`}}function Vo(e){return String(Math.max(-100,Math.min(100,e*35)))}const qo=["roll","deviceSize","hOffset","vOffset","finish","clearcoat"];function ft(e){if(!e||typeof e!="object")return{};const t={...e};for(const n of qo)typeof t[n]=="number"&&(t[n]=String(t[n]));return t}function Ko(e){const{subtitle:t,sizePt:n,maxWidth:r,...o}=e;return{...o,...n!==void 0?{sizePt:Number(n)}:{},...r!==void 0?{maxWidth:Number(r)}:{}}}function ht(e){const t={};for(const[n,r]of Object.entries(e))r!==void 0&&(t[n]=r);return t}function he(e,t,n){const r={};return e&&t.forEach((o,a)=>{const s=n[a];s!==void 0&&e[o]!==void 0&&(r[s]=e[o])}),r}function Yo(e){const t=e.slotSizes.filter(w=>Number.isInteger(w)&&w>0),n=t.map((w,I)=>`panel-${I+1}`);let r={};const o=e.look&&typeof e.look=="object"?e.look:null,a=e.style??null,s=o&&Array.isArray(o.shots)?o.shots:[],i=s.length>0,c=a?ft(a.shotLook):null,l=[];let d=0;t.forEach((w,I)=>{for(let x=0;x<w;x++){const A=i?ft(s[d]?.look??s[0]?.look??{}):c??{},O=A.hOffset!==void 0&&A.hOffset!==null?String(A.hOffset):Vo(x);l.push({panelId:n[I],look:{...k,...A,hOffset:O}}),d++}});let u={},p={},f={},m="gradient",g=Jn,h=Zn,y="vertical",b,v,S=!0,P=!1;if(o){m=o.bgMode==="perPanel"?"perPanel":"gradient";const w=ne({gradientStops:Array.isArray(o.gradientStops)?o.gradientStops:void 0,gradientAngle:typeof o.gradientAngle=="number"?o.gradientAngle:void 0,gradientFrom:typeof o.gradientFrom=="string"?o.gradientFrom:g,gradientTo:typeof o.gradientTo=="string"?o.gradientTo:h,gradientDir:o.gradientDir==="horizontal"?"horizontal":y});b=w.stops,v=w.angle,{gradientFrom:g,gradientTo:h,gradientDir:y}=te(w),o.shadow===!1&&(S=!1),o.floorReflection===!0&&(P=!0);const I=[];for(const x of s){const A=typeof x?.panelId=="string"?x.panelId:null;A&&!I.includes(A)&&I.push(A)}u=he(o.panelColors,I,n),p=he(_t(o.captionStyles),I,n),f=he(Ft(o.panelBackgrounds),I,n)}else if(a){const w=a.background??{};m=w.mode==="perPanel"?"perPanel":"gradient";const I=ne({gradientStops:w.stops,gradientAngle:w.angle,gradientFrom:g,gradientTo:h,gradientDir:y});b=I.stops,v=I.angle,{gradientFrom:g,gradientTo:h,gradientDir:y}=te(I),w.shadow===!1&&(S=!1),w.floorReflection===!0&&(P=!0),Array.isArray(w.panelColors)&&w.panelColors.forEach((x,A)=>{typeof x=="string"&&x&&n[A]!==void 0&&(u[n[A]]=x)})}if(a&&Array.isArray(a.captions)){const w=p,I=(T,_)=>({...w[T]?.[_]??{}}),x={},A={};a.captions.forEach((T,_)=>{const U=n[_];if(!(U===void 0||T===null||T===void 0)){if(Array.isArray(T)){const W=T.filter(R=>!!R&&typeof R=="object"&&typeof R.text=="string"&&R.text.trim()!=="").map((R,Y)=>({...I(U,Y),...ht(Ko(R))}));W.length>0&&(A[U]=W)}else if(typeof T=="object"){const{text:W,subtitle:R,sizePt:Y,maxWidth:_e,...an}=T;x[U]={...I(U,0),...ht({...an,...Y!==void 0?{sizePt:Number(Y)}:{},..._e!==void 0?{maxWidth:Number(_e)}:{}})},typeof W=="string"&&W.trim()&&(A[U]={headline:W,...typeof R=="string"&&R?{subtitle:R}:{}})}}});const O=se({[N]:A},Bt(x));p=jt(O),r=zt(O)}return{look:{panelPresetId:e.panelPresetId??(typeof o?.panelPresetId=="string"?o.panelPresetId:void 0)??"r69",bgMode:m,gradientStops:b,gradientAngle:v,gradientFrom:g,gradientTo:h,gradientDir:y,panelColors:u,shadow:S,floorReflection:P,panelBackgrounds:f,captionStyles:p,shots:l},panelIds:n,captionText:r}}function Xo(e){const t=e?.trim();return t?/\.(png|jpe?g|webp)$/i.test(t)?t:`${t}.png`:null}function Jo(e,t){const n=new Map;return e.map((r,o)=>{const a=Xo(t?.[o]);if(!a)return`screen-${o+1}.png`;const s=n.get(a)??0;if(n.set(a,s+1),s===0)return a;const i=a.lastIndexOf(".");return`${a.slice(0,i)}-${s+1}${a.slice(i)}`})}function Zo(e){const{look:t,panelIds:n,captionText:r,locale:o,shotNames:a,outputs:s,locales:i,baseLocale:c}=e,l=n.map(p=>({id:p})),d=Jo(t.shots,a),u=t.shots.map((p,f)=>({id:`shot-${f+1}`,panelId:p.panelId,frameNodeId:d[f],frameName:d[f],bytes:null,look:p.look,thumb:null,thumbStale:!0}));return $t({shots:u,panels:l,selectedShotId:u[0]?.id??null,panelPresetId:t.panelPresetId,bgMode:t.bgMode,gradientStops:t.gradientStops,gradientAngle:t.gradientAngle,gradientFrom:t.gradientFrom,gradientTo:t.gradientTo,gradientDir:t.gradientDir,panelColors:t.panelColors,shadow:t.shadow,floorReflection:t.floorReflection,panelBackgrounds:t.panelBackgrounds,captionStyles:t.captionStyles,outputs:s,...i?{locales:i}:{},...c?{baseLocale:c}:{},captionText:r&&Object.keys(r).length>0?{[o||N]:r}:{}})}function L(e){console.log("[render]",e)}const Qo=1900,ea=2800;let me=null;async function tn(){return me||(me=(async()=>{L("booting headless stage + loading model (once)…");const e=yt(Qo,ea),t=await jn(e);return{stage:e,device:new vt(t,e.scene,e.renderer),screen:new wt(t)}})()),me}function nn(e){const t=atob(e),n=new Uint8Array(t.length);for(let r=0;r<t.length;r++)n[r]=t.charCodeAt(r);return n}function Be(e){let t="";for(let n=0;n<e.length;n++)t+=String.fromCharCode(e[n]);return btoa(t)}function ta(e){return new Promise((t,n)=>{e.toBlob(async r=>{if(!r)return n(new Error("toBlob null"));t(Be(new Uint8Array(await r.arrayBuffer())))},"image/png")})}function rn(e,t){const n=Qt(t),r=new Map(t.shots.map((a,s)=>[Ne(s),n.indexOf(a.panelId)])),o=$o(e.layout,{frameOfPanel:a=>n.indexOf(a),frameOfShot:a=>r.get(a)??-1},t);if(o)return{layout:{findings:o.findings,...o.correctedLook?{correctedLook:o.correctedLook}:{}},layoutNote:o.note}}async function on(e){const t=await Promise.all(e.map(a=>createImageBitmap(new Blob([new Uint8Array(a.bytes)],{type:"image/png"})))),n=document.createElement("canvas");n.width=t.reduce((a,s)=>a+s.width,0),n.height=t[0]?.height??1;const r=n.getContext("2d");let o=0;for(const a of t)r.drawImage(a,o,0),o+=a.width,a.close();return{base64:await ta(n),width:n.width,height:n.height}}window.renderStrip=async function(t){try{if(!t||!Array.isArray(t.screenshots)||t.screenshots.length===0)throw new Error("renderStrip: input.screenshots must be a non-empty nested array of slots");const n=await tn(),r=t.screenshots.map(S=>Array.isArray(S)?S:[S]),{look:o,panelIds:a,captionText:s}=Yo({slotSizes:r.map(S=>S.length),panelPresetId:t.panelPresetId,look:t.look??void 0,style:t.style??void 0}),i=r.flat().map(nn),c=Array.isArray(t.captionLayers)&&a[0]?{[a[0]]:t.captionLayers}:s,l=t.preview?.25:1;L(`buildStrip (${r.length} panel${r.length===1?"":"s"}${t.locale?`, ${t.locale}`:""})…`);const d=performance.now(),u=await en(o,{screens:i,captionText:c},t.locale,{refs:n,renderScale:l,onProgress:S=>L(" "+S),...t.clip?{clip:t.clip}:{},...Number.isInteger(t.panelViewport)?{panelViewport:t.panelViewport}:{},...t.backgroundViewport?{backgroundViewport:t.backgroundViewport}:{}});L("encoding panels + stitching the strip preview…");const p=u.panels.map(S=>Be(S.bytes)),f=await on(u.panels),m=q(o.panelPresetId),g=Math.round(performance.now()-d),h=rn(u,o),y=u.layout.captionsMeasurable,b=Array.isArray(t.screenshotNames)?t.screenshotNames.flat():void 0,v=t.buildRecord?Zo({look:o,panelIds:a,captionText:s,locale:t.locale,shotNames:b,outputs:t.outputs}):void 0;return L(`done: ${u.panels.length} panels, strip ${f.width}x${f.height}, ${g}ms`),{ok:!0,ms:g,count:u.panels.length,panelPresetId:m.id,panelWidth:m.width,panelHeight:m.height,stripWidth:f.width,stripHeight:f.height,panels:p,stripBase64:f.base64,preview:l<1,...v?{projectRecord:v}:{},...h??{},layoutMeasured:y,...t.layerBoxes?{layerBoxes:u.phones.map(({shotId:S,...P})=>({shot:o.shots.findIndex((C,w)=>Ne(w)===S),...P}))}:{}}}catch(n){const r=n&&n.stack?n.stack:String(n);return L("ERROR: "+r),{ok:!1,error:String(n&&n.message?n.message:n)}}};window.renderProject=async function(t){try{if(!t||t.projectFile==null||typeof t.projectFile!="object")throw new Error("renderProject: input.projectFile (the saved ProjectFile) is required");const n=Er(JSON.stringify(t.projectFile));if(!n)throw new Error("renderProject: the saved project could not be restored (wrong schema or malformed record)");const r=await tn(),o=t.locale||n.baseLocale||n.locales?.[0]||"en-US",a=K(n.shots,n.panels),s=ve(t.variant||{},n.baseLocale),i=new Map((t.screenManifest||[]).map(w=>[`${w.shotId} ${Ye(ve(w.variant||{},n.baseLocale))}`,w])),c=(w,I)=>i.get(`${w} ${Ye(I)}`),l=a.map(w=>hr(c,w.id,s,pr,n.baseLocale)),d=a.map((w,I)=>({frameName:w.frameName,matched:l[I].value!==void 0,requestedVariant:s,resolvedAt:l[I].resolvedAt,inherited:l[I].inherited,...l[I].value?.source?{source:l[I].value.source}:{}})),u=l.map(({value:w})=>w?.bytes?nn(w.bytes):null),p=zt(n.captionText,o,n.baseLocale),f=Mr({...n,selectedShotId:null,panelPresetId:t.panelPresetId??n.panelPresetId,captionText:{[o]:p}}),m=t.preview?.25:1;L(`renderProject (${a.length} shot${a.length===1?"":"s"}, ${o})…`);const g=performance.now(),h=await en(f,{screens:u,captionText:p},o,{refs:r,renderScale:m,onProgress:w=>L(" "+w)});L("encoding panels + stitching the strip preview…");const y=h.panels.map(w=>Be(w.bytes)),b=await on(h.panels),v=q(f.panelPresetId),S=Math.round(performance.now()-g),P=rn(h,f),C=h.layout.captionsMeasurable;return L(`done: ${h.panels.length} panels, strip ${b.width}x${b.height}, ${S}ms`),{ok:!0,ms:S,count:h.panels.length,panelPresetId:v.id,panelWidth:v.width,panelHeight:v.height,stripWidth:b.width,stripHeight:b.height,panels:y,stripBase64:b.base64,preview:m<1,shots:d,locale:o,...P??{},layoutMeasured:C}}catch(n){const r=n&&n.stack?n.stack:String(n);return L("ERROR: "+r),{ok:!1,error:String(n&&n.message?n.message:n)}}};window.__RENDER_READY=!0;L("harness ready ✓");