shotops-mcp 0.9.9 → 0.11.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +105 -256
- package/dist/local.js +14417 -15617
- package/harness-dist/assets/index-DvXlO6pq.js +1 -0
- package/harness-dist/index.html +1 -1
- package/package.json +1 -1
- package/widget-dist/bundle.js +4 -4
- package/widget-dist/operation.js +282 -0
- package/widget-dist/panels.js +2 -2
- package/harness-dist/assets/index-B8oQTxzE.js +0 -1
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{S as Un,G as $n,A as Gn,D as Ie,M as Vn,R as qn,a as Xn,C as Kn,b as Yn,c as Jn}from"./three-addons-zF8BveTt.js";import{aa as Zn,P as Ke,b as Qn,V as G,a4 as eo,l as qt,C as R,ab as to,J as ct,$ as ie,M as no,a2 as oo,B as ro,a3 as ao,a7 as io,ac as dt,ad as so,ae as lo}from"./three-webgl-BAyyruEx.js";(function(){const t=document.createElement("link").relList;if(t&&t.supports&&t.supports("modulepreload"))return;for(const r of document.querySelectorAll('link[rel="modulepreload"]'))o(r);new MutationObserver(r=>{for(const a of r)if(a.type==="childList")for(const i of a.addedNodes)i.tagName==="LINK"&&i.rel==="modulepreload"&&o(i)}).observe(document,{childList:!0,subtree:!0});function n(r){const a={};return r.integrity&&(a.integrity=r.integrity),r.referrerPolicy&&(a.referrerPolicy=r.referrerPolicy),r.crossOrigin==="use-credentials"?a.credentials="include":r.crossOrigin==="anonymous"?a.credentials="omit":a.credentials="same-origin",a}function o(r){if(r.ep)return;r.ep=!0;const a=n(r);fetch(r.href,a)}})();const q={lineHeight:1.2,bandInset:.06,bandCenter:.5,padX:.07},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},padX:{min:0,max:.5},reserveLines:{min:1,max:8}},ue=[{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"}],ut=ue.map(e=>e.id);[ut[0],...ut.slice(1)];const J=600;function Ye(e){return ue.find(t=>t.id===e)??ue[0]}const Xt=[{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",boxAlign:"center",padX:.07}},{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",boxAlign:"center",padX:.07}},{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",boxAlign:"center",padX:.07}},{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",boxAlign:"left",padX:.07}},{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",boxAlign:"right",padX:.07}},{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",boxAlign:"center",padX:.07}},{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",boxAlign:"left",padX:.07}}],Je=Xt,ft=Je.map(e=>e.id);[ft[0],...ft.slice(1)];Array.from(new Set(Xt.flatMap(e=>Object.keys(e.caption))));const Kt=[{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"}}],ht=Kt.map(e=>e.id);[ht[0],...ht.slice(1)];const M={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},Ne={angle:{valueKind:"angle",required:!0,defaultSource:"default-look",defaultValue:M.angle,persistence:"always"},cameraPos:{valueKind:"camera-position",required:!0,defaultSource:"default-look",defaultValue:M.cameraPos,persistence:"always"},roll:{valueKind:"numeric-string",required:!0,defaultSource:"default-look",defaultValue:M.roll,persistence:"always"},deviceSize:{valueKind:"numeric-string",required:!0,defaultSource:"default-look",defaultValue:M.deviceSize,persistence:"always"},hOffset:{valueKind:"numeric-string",required:!0,defaultSource:"default-look",defaultValue:M.hOffset,persistence:"always"},vOffset:{valueKind:"numeric-string",required:!0,defaultSource:"default-look",defaultValue:M.vOffset,persistence:"always"},material:{valueKind:"material",required:!0,defaultSource:"default-look",defaultValue:M.material,persistence:"always"},colorway:{valueKind:"colorway",required:!0,defaultSource:"default-look",defaultValue:M.colorway,persistence:"always"},customColor:{valueKind:"string",required:!0,defaultSource:"default-look",defaultValue:M.customColor,persistence:"always"},finish:{valueKind:"numeric-string",required:!0,defaultSource:"default-look",defaultValue:M.finish,persistence:"always"},clearcoat:{valueKind:"numeric-string",required:!0,defaultSource:"default-look",defaultValue:M.clearcoat,persistence:"always"},clayTone:{valueKind:"clay-tone",required:!0,defaultSource:"default-look",defaultValue:M.clayTone,persistence:"always"},clayCustom:{valueKind:"string",required:!0,defaultSource:"default-look",defaultValue:M.clayCustom,persistence:"always"},flatScreen:{valueKind:"boolean",required:!0,defaultSource:"default-look",defaultValue:M.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:M.glare,persistence:"always"},lighting:{valueKind:"boolean",required:!0,defaultSource:"default-look",defaultValue:M.lighting,persistence:"always"},reflections:{valueKind:"boolean",required:!0,defaultSource:"default-look",defaultValue:M.reflections,persistence:"always"}},Yt={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}},Jt=.82;function Zt(e){return e/100*Jt}function co(e){return Math.round(e/Jt*100)/100}const Z={x:.5,y:.06},Ze={fontId:"inter",sizePt:32,color:"FFFFFF",align:"center",anchor:Z,maxWidth:.86},pt=[{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 ne(e){return pt.find(t=>t.id===e)??pt[0]}const be=932,ze="iphone-17-pro",uo="pixel-10-pro",Qe=[{id:"iphone-6-9",label:"iPhone 17 Pro",panelPresetId:"r69",ascDeviceSet:"APP_IPHONE_67",modelId:ze,screenFamily:"iphone"},{id:"iphone-6-5",label:"iPhone 17",panelPresetId:"r65",ascDeviceSet:"APP_IPHONE_65",modelId:ze,screenFamily:"iphone"},{id:"pixel-10-pro",label:"Pixel 10 Pro",panelPresetId:"pixel69",ascDeviceSet:"ANDROID_PHONE",modelId:uo,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 fo(e){return Qe.find(t=>t.panelPresetId===e)?.modelId??ze}const Qt="iphone-6-9";function et(e){return Qe.find(t=>t.id===e)}function ho(){return Qe.filter(e=>!e.comingSoon)}function en(e,t){if(Array.isArray(e)){const n=new Set,o=[];for(const r of e){const a=et(r);a&&!a.comingSoon&&!n.has(r)&&(n.add(r),o.push(r))}if(o.length>0)return o}if(t){const n=ho().find(o=>o.panelPresetId===t);if(n)return[n.id]}return[Qt]}function po(e,t){return e.find(o=>et(o)?.panelPresetId===t)??e[0]}function mo(e){const t=e??{},n=Array.isArray(t.outputs)?t.outputs.filter(a=>typeof a=="string"):void 0,o=en(n,typeof t.panelPresetId=="string"?t.panelPresetId:void 0),r=ne(typeof t.panelPresetId=="string"?t.panelPresetId:"").id;return{outputs:o,panelPresetId:r,activeDeviceId:po(o,r)}}const tt=et(Qt)?.screenFamily??"iphone";function tn(e){const t={...e},n=t,o=Object.keys(Ne);for(const r of o){const a=Ne[r];a.persistence==="omit-default"&&(n[r]===void 0||n[r]===a.defaultValue)&&delete n[r]}return t}function go(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 o=typeof t=="number"?t:Number.parseFloat(String(t??""));Number.isFinite(o)&&(n.deviceSize=String(co(o)))}return n}function nn(e){return tn({...M,...go(e)})}function on(e){return tn(nn(e))}function L(e,t){const{min:n,max:o}=Yt[e],r=typeof t=="number"?t:Number.parseFloat(t??""),a=Number.isFinite(r)?r:Number.parseFloat(String(Ne[e].defaultValue));return Math.max(n,Math.min(o,a))}const yo=90,rn=180,bo="#1b1b2e",vo="#0a0a14";function wo(e){return e==="horizontal"?yo:rn}function xo(e){const t=(e%180+180)%180;return t>=45&&t<135?"horizontal":"vertical"}function an(e,t,n){return{stops:[{color:e,at:0},{color:t,at:1}],angle:wo(n)}}const sn=e=>e*Math.PI/180;function Io(e){const t=sn(e);return{dx:Math.sin(t),dy:-Math.cos(t)}}function So(e,t,n){const o=sn(n);return Math.abs(e*Math.sin(o))+Math.abs(t*Math.cos(o))}function Ao(e,t,n){const{dx:o,dy:r}=Io(n),a=So(e,t,n)/2,i=e/2,s=t/2;return{x0:i-a*o,y0:s-a*r,x1:i+a*o,y1:s+a*r}}function fe(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:xo(e.angle)}}function ve(e,t){if(!Array.isArray(e)||e.length===0)return null;const n=[];for(const r of e){if(!r||typeof r!="object")return null;const a=r;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 o=typeof t=="number"&&Number.isFinite(t)?Po(t):rn;return{stops:n,angle:o}}function he(e){return ve(e.gradientStops,e.gradientAngle)??an(e.gradientFrom,e.gradientTo,e.gradientDir)}function Po(e){return(e%360+360)%360}function ko(e){return ve(e.stops,e.angle)??an(e.from,e.to,e.dir)}function ln(e){if(!e||typeof e!="object"||Array.isArray(e))return{};const t={};for(const[n,o]of Object.entries(e)){if(!o||typeof o!="object")continue;const r=o;if(r.kind==="solid"&&typeof r.color=="string")t[n]={kind:"solid",color:r.color};else if(r.kind==="gradient"&&typeof r.from=="string"&&typeof r.to=="string"&&(r.dir==="horizontal"||r.dir==="vertical")){const a=ve(r.stops,r.angle);t[n]=a?{kind:"gradient",stops:a.stops,angle:a.angle,from:r.from,to:r.to,dir:r.dir}:{kind:"gradient",from:r.from,to:r.to,dir:r.dir}}}return t}const mt=e=>Math.round(e*1e6)/1e6;function oe(e){return e.widthMode==="fill"?1-2*(e.padX??q.padX):e.maxWidth}function cn(e){const t=oe(e);if(e.boxAlign===void 0&&e.bandCenter!==void 0)return e.bandCenter-t/2;const n=e.padX??q.padX;return e.boxAlign==="left"?n:e.boxAlign==="right"?1-n-t:q.bandCenter-t/2}function Co(e,t){return Math.abs(e-q.bandCenter)<1e-9?null:e<.5?{boxAlign:"left",padX:mt(e-t/2)}:{boxAlign:"right",padX:mt(1-e-t/2)}}function Be(e,t){const n={...e,...t},o=t;return o.bandCenter!==void 0&&o.boxAlign===void 0&&delete n.boxAlign,o.boxAlign!==void 0&&o.bandCenter===void 0&&delete n.bandCenter,n}function D(e){return!e||e.x===Z.x&&e.y===Z.y}const Oo=["sizePt","maxWidth","lineHeight","reserveLines"];function To(e,t){return t?Oo.filter(n=>e[n]!==t[n]):[]}function Mo(e){const{text:t,anchor:n,...o}=e;return D(n)?{...o}:{...o,anchor:n}}const Eo=.55,N="en-US";function Lo(e,t){return`${e}:${t}`}function Fo(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 dn(e,t,n,o){if(!e||typeof e!="object"||Array.isArray(e))return{};const r={};for(const[a,i]of Object.entries(e)){if(a===n||!t.includes(a)||!Array.isArray(i))continue;const s=Array.from(new Set(i.filter(c=>typeof c=="string"))).filter(c=>{const l=Fo(c);return!!l&&!!o[n]?.[l.panelId]?.[l.index]&&!!o[a]?.[l.panelId]?.[l.index]});s.length>0&&(r[a]=s)}return r}function un(e){if(!e||typeof e!="object"||Array.isArray(e))return{};const t={};for(const[n,o]of Object.entries(e))!o||typeof o!="object"||Array.isArray(o)||(t[n]=X(o));return t}function Ro(e){if(!e||typeof e!="object")return;const t=e,n=typeof t.x=="number"?t.x:Z.x,o=typeof t.y=="number"?t.y:Z.y;return D({x:n,y:o})?void 0:{x:n,y:o}}function X(e){const t=e&&typeof e=="object"?e:{},n=Ro(t.anchor),o={...Ze,...t};n?o.anchor=n:delete o.anchor,typeof o.reserveLines!="number"||!Number.isFinite(o.reserveLines)||o.reserveLines<de.reserveLines.min?delete o.reserveLines:o.reserveLines=Math.floor(o.reserveLines),o.band!=="bottom"&&delete o.band;for(const r of["bandInset","lineHeight","bandCenter","padX"]){const{min:a,max:i}=de[r],s=o[r];(typeof s!="number"||!Number.isFinite(s)||s<a||s>i)&&delete o[r]}return o.boxAlign!=="left"&&o.boxAlign!=="center"&&o.boxAlign!=="right"&&delete o.boxAlign,o.widthMode!=="fill"&&delete o.widthMode,No(o),o}function No(e){const t=e.bandCenter;if(t===void 0)return;const n=Co(t,e.maxWidth);if(e.boxAlign!==void 0||n===null){delete e.bandCenter;return}e.widthMode!=="fill"&&n.padX>=de.padX.min&&n.padX<=de.padX.max&&(e.boxAlign=n.boxAlign,e.padX=n.padX,delete e.bandCenter)}function zo(e){const t=e&&typeof e=="object"?e:{};return{...X(t),text:typeof t.text=="string"?t.text:""}}function nt(e){if(!e||typeof e!="object"||Array.isArray(e))return{};const t={};for(const[n,o]of Object.entries(e))Array.isArray(o)?o.length>0&&(t[n]=o.map(X)):o&&typeof o=="object"&&(t[n]=[X(o)]);return t}function Bo(e,t){const n=[{...X(t),text:e.headline}];return typeof e.subtitle=="string"&&e.subtitle.trim()&&n.push({...X({...t,sizePt:t.sizePt*Eo}),text:e.subtitle}),n}function we(e,t,n=N){if(!e||typeof e!="object"||Array.isArray(e))return{};const o=un(t),r=l=>o[l]??Ze,a=l=>{if(!l||typeof l!="object"||Array.isArray(l))return{};const f={};for(const[u,d]of Object.entries(l))Array.isArray(d)?d.length>0&&(f[u]=d.map(zo)):d&&typeof d=="object"&&typeof d.headline=="string"&&(f[u]=Bo(d,r(u)));return f},i=Object.entries(e);if(i.some(([,l])=>!!l&&typeof l=="object"&&typeof l.headline=="string"))return{[n]:a(e)};const c={};for(const[l,f]of i)c[l]=a(f);return c}function Q(e,t,n=N){return e[t??n]??e[n]??{}}function fn(e,t=N){const n={},o=Object.keys(e),r=o.includes(t)?[t,...o.filter(a=>a!==t)]:o;for(const a of r){const i=e[a];if(i)for(const[s,c]of Object.entries(i))n[s]===void 0&&Array.isArray(c)&&c.length>0&&(n[s]=c.map(Mo))}return n}function _e(e,t=N,n=tt){const o={};return e.family!==void 0&&e.family!==n&&(o.family=e.family),e.locale!==void 0&&e.locale!==t&&(o.locale=e.locale),o}function gt(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 je(e){const t=[];return e.family!==void 0&&t.push("family"),e.locale!==void 0&&t.push("locale"),t}const _o={order:["family","locale"],reach:"strict"},jo={order:["locale","family"],reach:"lattice"};function Do(e){const t=[];for(let n=0;n<1<<e.length;n++){const o=[];for(let r=0;r<e.length;r++)n&1<<r&&o.push(e[r]);t.push(o)}return t.sort((n,o)=>{if(n.length!==o.length)return o.length-n.length;for(let r=0;r<n.length;r++){const a=e.indexOf(n[r])-e.indexOf(o[r]);if(a!==0)return a}return 0})}function Wo(e,t){const n=je(e),o=t.order.filter(a=>n.includes(a));return(t.reach==="strict"?Array.from({length:o.length+1},(a,i)=>o.slice(0,o.length-i)):Do(o)).map(a=>{const i={};return a.includes("family")&&(i.family=e.family),a.includes("locale")&&(i.locale=e.locale),i})}function hn(e,t,n,o,r=N){const a=_e(n,r);for(const i of Wo(a,o)){const s=e(t,i);if(s!==void 0){const c=je(i);return{value:s,resolvedAt:i,inherited:je(a).filter(l=>!c.includes(l))}}}return{value:void 0,resolvedAt:null,inherited:[]}}const pn=e=>{let t="";for(let n=0;n<e.length;n++)t+=e[n].toString(16).padStart(2,"0");return t};async function Ho(e){const t=globalThis.crypto?.subtle;return t?pn(new Uint8Array(await t.digest("SHA-256",e))):$o(e)}const Uo=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]),_=(e,t)=>e>>>t|e<<32-t;function $o(e){const t=e.length,n=new Uint8Array(t+72>>6<<6);n.set(e),n[t]=128;const o=t*8,r=new DataView(n.buffer);r.setUint32(n.length-8,Math.floor(o/4294967296)),r.setUint32(n.length-4,o>>>0);const a=new Uint32Array([1779033703,3144134277,1013904242,2773480762,1359893119,2600822924,528734635,1541459225]),i=new Uint32Array(64);for(let s=0;s<n.length;s+=64){for(let g=0;g<16;g++)i[g]=r.getUint32(s+g*4);for(let g=16;g<64;g++){const p=i[g-15],b=i[g-2],v=_(p,7)^_(p,18)^p>>>3,w=_(b,17)^_(b,19)^b>>>10;i[g]=i[g-16]+v+i[g-7]+w>>>0}let[c,l,f,u,d,h,y,m]=[a[0],a[1],a[2],a[3],a[4],a[5],a[6],a[7]];for(let g=0;g<64;g++){const p=_(d,6)^_(d,11)^_(d,25),b=d&h^~d&y,v=m+p+b+Uo[g]+i[g]>>>0,w=_(c,2)^_(c,13)^_(c,22),x=c&l^c&f^l&f,A=w+x>>>0;m=y,y=h,h=d,d=u+v>>>0,u=f,f=l,l=c,c=v+A>>>0}a[0]=a[0]+c>>>0,a[1]=a[1]+l>>>0,a[2]=a[2]+f>>>0,a[3]=a[3]+u>>>0,a[4]=a[4]+d>>>0,a[5]=a[5]+h>>>0,a[6]=a[6]+y>>>0,a[7]=a[7]+m>>>0}return pn(Go(a))}function Go(e){const t=new Uint8Array(e.length*4),n=new DataView(t.buffer);for(let o=0;o<e.length;o++)n.setUint32(o*4,e[o]);return t}function De(e,t,n=N){const o=r=>{const a=new Set,i=[];for(const s of r)typeof s=="string"&&s&&!a.has(s)&&(a.add(s),i.push(s));return i};if(Array.isArray(t)){const r=o(t);if(r.length>0)return r.includes(n)?r:[...r,n]}return o([n,...Object.keys(e)])}function ot(e,t=N){return typeof e=="string"&&e.length>0?e:t}const K={"it-IT":"it"};function yt(e,t){if(!(Object.keys(e).some(r=>r in K)||(t?.some(r=>r in K)??!1)))return{captionText:e,locales:t};const o={};for(const[r,a]of Object.entries(e))r in K||(o[r]=a);for(const[r,a]of Object.entries(e)){const i=K[r];i&&(o[i]={...a,...o[i]??{}})}return{captionText:o,locales:t?.map(r=>K[r]??r)}}function Vo(e){const t=e??{},n=ot(t.baseLocale),o=Array.isArray(t.locales)?t.locales.filter(s=>typeof s=="string"&&s.length>0):void 0,{captionText:r,locales:a}=yt(we(t.captionText,t.captionStyles,n),o),i=yt({[n]:{}},[n]).locales?.[0]??n;return{captionText:r,locales:De(r,a,i),baseLocale:i}}function qo(e,t,n,o,r){return(a,i)=>{const s=i.locale??r,c=i.family!==void 0?t?.[i.family]?.[s]?.[n]?.[o]:e[s]?.[n]?.[o]?.text;return typeof c=="string"&&c.length>0?c:void 0}}function Xo(e,t,n,o,r=N){const a=Q(e,o,r);if(n===tt||!t?.[n])return a;const i={family:n,locale:o},s={};for(const[c,l]of Object.entries(a))s[c]=l.map((f,u)=>{const d=qo(e,t,c,u,r),{value:h}=hn(d,Lo(c,u),i,jo,r);return h===void 0||h===f.text?f:{...f,text:h}});return s}function mn(e){if(!e||typeof e!="object"||Array.isArray(e))return{};const t={};for(const[n,o]of Object.entries(e)){if(n===tt||!o||typeof o!="object"||Array.isArray(o))continue;const r={};for(const[a,i]of Object.entries(o)){if(!i||typeof i!="object"||Array.isArray(i))continue;const s={};for(const[c,l]of Object.entries(i))Array.isArray(l)&&l.every(f=>typeof f=="string")&&(s[c]=l);Object.keys(s).length>0&&(r[a]=s)}Object.keys(r).length>0&&(t[n]=r)}return t}function Ko(e,t,n){if(!t||!n)return e;let o=!1;const r=e.map((a,i)=>{const s=t[i];if(!s)return a;const c=To(s,n[i]);if(c.length===0)return a;const l={...a},f=l;for(const u of c){const d=s[u];d===void 0?delete f[u]:f[u]=d}return o=!0,l});return o?r:e}function Yo(e,t,n,o){if(t.length===0)return e;const r={...e},a=e[n];let i=!1;for(const s of t)for(const c of Object.keys(r)){const l=o(r[c][s],s,c);l!==void 0&&(r[c]={...r[c],[s]:c===n?l:Ko(l,e[c][s],a?.[s])},i=!0)}return i?r:e}function $(e){const t=e?.z;return{...typeof t=="number"&&Number.isSafeInteger(t)&&t!==0?{z:t}:{},...e?.hidden===!0?{hidden:!0}:{}}}function V(e,t){return t.flatMap(n=>e.filter(o=>o.panelId===n.id))}function Jo(e,t){const n=V(e,t).filter(r=>r.hidden!==!0),o=r=>$(r).z??0;return n.some(r=>o(r)!==0)?n.map((r,a)=>({shot:r,index:a,z:o(r)})).sort((r,a)=>r.z-a.z||r.index-a.index).map(r=>r.shot):n}let bt=0,vt=0;function Zo(e,t){const n=(o,r)=>o.reduce((a,i)=>{const s=i.startsWith(r)?Number.parseInt(i.slice(r.length),10):NaN;return Number.isFinite(s)&&s>a?s:a},0);bt=Math.max(bt,n(e,"shot-")),vt=Math.max(vt,n(t,"panel-"))}const Qo=.49,er=e=>Math.round(e*100)/100,pe=(e,t,n)=>Math.max(t,Math.min(n,e));function wt(e,t){return{x:e*t.width,y:0,width:t.width,height:t.height}}function tr(e,t,n){if(n<=0||t<=0||e.width<=0)return[];if(e.x+e.width<=0||e.x>=t*n)return[];const o=pe(Math.floor(e.x/t),0,n-1),r=pe(Math.ceil((e.x+e.width)/t)-1,0,n-1),a=[];for(let i=o;i<=r;i++)a.push(i);return a}function gn(e,t,n,o){const r=n*e.heightFrac,a=o&&o.height>0?o.width*(r/o.height):r*Qo,s=e.panelIndex*t+t/2-a/2+e.hOffsetFrac*(t/2),c=(n-r)/2+e.vOffsetFrac*(n/2);return{x:s,y:c,width:a,height:r}}function nr(e,t,n){return gn({panelIndex:e.panelIndex,hOffsetFrac:L("hOffset",e.hOffset)/100,vOffsetFrac:L("vOffset",e.vOffset)/100,heightFrac:Zt(L("deviceSize",e.deviceSize))},t.width,t.height,n!==void 0&&n>0?{width:n,height:1}:void 0)}function or(e,t,n){const{min:o,max:r}=Yt.hOffset;if(!Number.isFinite(t)||t>=o&&t<=r||n<=0)return{panelIndex:e,hOffset:t};const a=e+.5+t/200,i=pe(Math.floor(a),0,n-1);return{panelIndex:i,hOffset:pe(er(t+(e-i)*200),o,r)}}function rr(e,t){const n=new Map(t.map((a,i)=>[a.id,i]));let o=!1;const r=e.map(a=>{const i=n.get(a.panelId);if(i===void 0)return a;const s=Number.parseFloat(a.look.hOffset),c=or(i,s,t.length);return c.panelIndex===i&&c.hOffset===s?a:(o=!0,{...a,panelId:t[c.panelIndex].id,look:{...a.look,hOffset:String(c.hOffset)}})});return o?V(r,t):e}function ar(e,t,n){return e.map(o=>{const r=gn({panelIndex:o.panelIndex,hOffsetFrac:o.hOffset,vOffsetFrac:o.vOffset,heightFrac:o.heightFrac},t,n,{width:o.width,height:o.height});return{shotId:o.shotId,bytes:o.bytes,x:Math.round(r.x),y:Math.round(r.y),width:Math.round(r.width),height:Math.round(r.height),panelIndex:o.panelIndex,...o.clipToFrame===!0?{clipToFrame:!0}:{},...o.layers?{layers:o.layers}:{}}})}function ir(e,t){const n=t.panelBackgrounds??{},o=he(t),r=o.stops[0]?.color??t.gradientFrom;if(!e.some(c=>n[c.id]))return t.bgMode==="gradient"?{kind:"gradient",gradient:o}:{kind:"perPanel",colors:e.map(c=>t.panelColors[c.id]??r)};const i=c=>t.bgMode==="gradient"?{kind:"gradient",gradient:o}:{kind:"solid",color:t.panelColors[c]??r};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:ko(l)}:i(c.id)})}}const sr=9/19.5;function lr(e){return e.deviceFrame!==!1}function cr(e,t,n,o){const r=e>0&&t>0,a=r?t:Math.max(1,o),i=r?e:a*sr,s=Math.min(1,Math.max(1,o)/a),c=Math.max(1,Math.round(i*s)),l=Math.max(1,Math.round(a*s)),f=Math.min(c*L("screenCornerRadius",n.screenCornerRadius)/100,Math.min(c,l)/2),u=L("roll",n.roll)*Math.PI/180,d=Math.abs(Math.cos(u)),h=Math.abs(Math.sin(u)),y=Math.max(1,Math.ceil(c*d+l*h-1e-6)),m=Math.max(1,Math.ceil(c*h+l*d-1e-6));return{width:y,height:m,cardWidth:c,cardHeight:l,radius:f,rotation:u}}function yn(e,t,n=N){const o=he(e);return{panelPresetId:e.panelPresetId,bgMode:e.bgMode,gradientStops:o.stops,gradientAngle:o.angle,...fe(o),panelColors:e.panelColors,shadow:e.shadow,floorReflection:e.floorReflection??!1,panelBackgrounds:e.panelBackgrounds??{},captionStyles:{...nt(e.captionStyles),...fn(t,n)}}}function dr(e){const t=ur(e),n=t.lines===void 0?"":` Reserves ${t.lines} headline lines (~${t.characters} characters).`;return`${e.blurb}${n}${t.column?" Restyles the headline into a narrower column.":" Leaves the headline full-width and centred."} Character: [${e.character}]. Bleeds: [${e.bleedEdge}].`}function ur(e){const t=e.caption.reserveLines,n=e.caption.maxWidth??.86,o=n<.86||(e.caption.align??"center")!=="center";return typeof t!="number"?{column:o}:{lines:t,characters:Math.round(t*18*n/.86),column:o}}function fr(e){return Je.find(t=>t.id===e)}const hr=e=>({...e,...e.anchor?{anchor:{...e.anchor}}:{}}),Se=(e,t)=>JSON.stringify(e)===JSON.stringify(t),j=e=>typeof e=="object"&&e!==null&&!Array.isArray(e);function xt(e){if(!j(e))return null;const[t]=nt({layer:[e]}).layer,{text:n,...o}=t;return Object.fromEntries(Object.entries(o).sort(([r],[a])=>r<a?-1:r>a?1:0))}function pr(e,t){if(!j(e)||!j(e.frameTemplates))return null;const n=e.frameTemplates[t];if(!j(n)||typeof n.templateId!="string"||!fr(n.templateId))return null;const o=n.templateId,r=Array.isArray(n.shots)?n.shots.filter(j):[],a=Array.isArray(e.shots)?e.shots.filter(f=>j(f)&&f.panelId===t):[];let i=a.length!==r.length||r.some((f,u)=>{const d=a[u];return d?.id!==f.id||!Se(d?.look,f.look)});const s=j(e.captionSlotIds)?e.captionSlotIds:{},c=Array.isArray(s[t])?s[t]:[],l=Array.isArray(n.captionSlotIds)?n.captionSlotIds:[];if(!i&&!Se(c,l)&&(i=!0),!i){const f=j(e.captionText)?e.captionText:{},u=j(n.captions)?n.captions:{},d=typeof n.baseLocale=="string"?n.baseLocale:"",h=new Set([...Object.keys(f),...Object.keys(u)]);for(const y of Array.from(h)){const m=j(f[y])?f[y]:{},g=Array.isArray(m[t])?m[t]:[],p=Array.isArray(u[y])?u[y]:Array.isArray(u[d])?u[d]:[];if(g.length!==l.length||p.length!==l.length){i=!0;break}if(p.some((b,v)=>!Se(xt(g[v]),xt(b)))){i=!0;break}}}return{templateId:o,modified:i,resettable:!0}}function mr(e,t){return Math.max(0,...Object.values(e).map(n=>n[t]?.length??0))}function bn(e,t,n){const o=e&&typeof e=="object"&&!Array.isArray(e)?e:{},r=new Set,a={};let i=1;const s=()=>{for(;r.has(`caption-${i}`);)i+=1;const c=`caption-${i}`;return r.add(c),i+=1,c};for(const c of n){const l=mr(t,c);if(l===0)continue;const f=Array.isArray(o[c])?o[c]:[];a[c]=Array.from({length:l},(u,d)=>{const h=f[d];return typeof h=="string"&&h.length>0&&!r.has(h)?(r.add(h),h):s()})}return a}function gr(e,t,n){const o={};for(const[r,a]of Object.entries(e.captionText)){const i=a[t];i?.length&&(o[r]=i.map(hr))}return{templateId:n,baseLocale:e.baseLocale,shots:e.shots.filter(r=>r.panelId===t).map(r=>({id:r.id,frameNodeId:r.frameNodeId,frameName:r.frameName,look:{...r.look},...r.inputAnchor?{inputAnchor:r.inputAnchor}:{},...r.outputAnchor?{outputAnchor:r.outputAnchor}:{}})),captionSlotIds:[...e.captionSlotIds[t]??[]],captions:o}}function yr(e,t){return pr(e,t)}const vn=2;function br(e){if(!e||typeof e!="object"||Array.isArray(e))return!1;const t=e;return t.schema===vn&&Array.isArray(t.shots)&&Array.isArray(t.panels)&&t.panels.length>0}function vr(e){let t;try{t=JSON.parse(e)}catch{return null}if(!br(t))return null;const n=t,o=new Set(n.panels.map(h=>h.id)),r=n.shots.filter(h=>o.has(h.panelId)).map(h=>({id:h.id,panelId:h.panelId,frameNodeId:h.frameNodeId,frameName:h.frameName,bytes:null,look:nn(h.look),thumb:null,thumbStale:!0,inputAnchor:h.inputAnchor,outputAnchor:h.outputAnchor,...$(h)})),a=n.panels.map(h=>({id:h.id}));Zo(r.map(h=>h.id),a.map(h=>h.id));const i=n.selectedShotId&&r.some(h=>h.id===n.selectedShotId)?n.selectedShotId:r[0]?.id??null,{captionText:s,locales:c,baseLocale:l}=Vo(n),f=mo(n),u=bn(n.captionSlotIds,s,a.map(h=>h.id)),d=ve(n.gradientStops,n.gradientAngle);return{shots:rr(V(r,a),a),panels:a,selectedShotId:i,panelPresetId:f.panelPresetId,bgMode:n.bgMode==="perPanel"?"perPanel":"gradient",...d?{gradientStops:d.stops,gradientAngle:d.angle,...fe(d)}:{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:ln(n.panelBackgrounds),captionText:s,locales:c,baseLocale:l,staleCaptionTranslations:dn(n.staleCaptionTranslations,c,l,s),outputs:f.outputs,localeScreens:{},outputCaptions:mn(n.outputCaptions),captionSlotIds:u,frameTemplates:n.frameTemplates&&typeof n.frameTemplates=="object"&&!Array.isArray(n.frameTemplates)?n.frameTemplates:{}}}function wn(e){const n=V(e.shots,e.panels).map(a=>({id:a.id,panelId:a.panelId,frameNodeId:a.frameNodeId,frameName:a.frameName,look:on(a.look),inputAnchor:a.inputAnchor,outputAnchor:a.outputAnchor,...$(a)})),o=ot(e.baseLocale),r=we(e.captionText,e.captionStyles,o);return{schema:vn,shots:n,panels:e.panels,selectedShotId:e.selectedShotId,captionText:r,locales:De(r,e.locales,o),baseLocale:o,staleCaptionTranslations:dn(e.staleCaptionTranslations,De(r,e.locales,o),o,r),outputs:en(e.outputs,e.panelPresetId),outputCaptions:mn(e.outputCaptions),...(()=>{const a=bn(e.captionSlotIds,r,e.panels.map(i=>i.id));return Object.keys(a).length>0?{captionSlotIds:a}:{}})(),...e.frameTemplates&&Object.keys(e.frameTemplates).length>0?{frameTemplates:e.frameTemplates}:{},...yn(e,r,o)}}const wr=1;function xr(e){const t=V(e.shots,e.panels),n=we(e.captionText,e.captionStyles),o=ot(e.baseLocale);return{schema:wr,shots:t.map(r=>({panelId:r.panelId,look:on(r.look),...$(r)})),...yn(e,n,o)}}Kt.map(e=>({id:e.id,label:e.label,description:e.blurb}));Je.map(e=>({id:e.id,label:e.label,description:dr(e),character:e.character}));const Ir=[{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","setShotLayering"],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.","A device’s paint order and hiding it are not writable; the user sets them in Studio or through edit_project."],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",Ar=[{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."}],Pr=Ir.map(e=>e.id);[...Pr,...Ar.map(e=>e.id)];const kr=7,It={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 xn(e){const t=It[e]??It.front,n=Math.hypot(t.x,t.y,t.z),o=kr/n;return{x:t.x*o,y:t.y*o,z:t.z*o}}function Cr(e){return Math.atan2(e.x,-e.z)*180/Math.PI}const In=[{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"}];In.map(e=>e.code);Object.fromEntries(In.map(e=>[e.code,e]));({...Ze});function Or(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(L("finish",t.finish)),e.setClearcoat(L("clearcoat",t.clearcoat)))}function Tr(e,t,n){e.screen.setGlare(!n&&t?e.device.environmentMap():null)}async function Mr(e,t,n,o){const{stage:r,device:a,screen:i}=e,s=t.material==="clay";if(t.cameraPos?r.setCameraPosition(t.cameraPos):r.setAngle(t.angle),a.setRoll(L("roll",t.roll)),Or(a,t),i.restoreScreen(),r.setStudioLighting(t.lighting),a.setReflections(t.reflections),i.setFlatScreen(t.flatScreen),n){try{await i.applyWallpaper(n)}catch{}if(!o())return}Tr(e,t.glare,s)}const Er=""+new URL("iphone-optimized-BdcJzlHi.glb",import.meta.url).href,Lr="data:model/gltf-binary;base64,Z2xURgIAAADUAAAAwAAAAEpTT057ImFzc2V0Ijp7InZlcnNpb24iOiIyLjAiLCJnZW5lcmF0b3IiOiJTaG90T3BzIHBsYWNlaG9sZGVyIOKAlCB0aGUgUGl4ZWwgbW9kZWwgaXMgZGVsaWJlcmF0ZWx5IG5vdCBidW5kbGVkIGluIHRoZSBucG0gcGFja2FnZSJ9LCJzY2VuZXMiOlt7Im5hbWUiOiJwaXhlbC1ub3QtYnVuZGxlZCIsIm5vZGVzIjpbXX1dLCJzY2VuZSI6MH0gICA=",Fr=[{id:"grey",label:"Grey",color:11579568},{id:"white",label:"White",color:15263458},{id:"charcoal",label:"Charcoal",color:3815996}],Rr=[{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}],Nr=[{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}],me={id:"iphone-17-pro",glb:Er,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:Rr},St={id:"pixel-10-pro",glb:Lr,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:Nr},zr={[me.id]:me,[St.id]:St};function rt(e){return e&&zr[e]||me}function We(e){const t=xn(e);return new G(t.x,t.y,t.z)}const Br=1.4;function _r(e,t){return(t?new G(t.x,t.y,t.z):We(e)).multiplyScalar(Br)}const at=35;function jr(e){e.traverse(t=>{const n=t;n.geometry?.dispose();const o=n.material;Array.isArray(o)?o.forEach(At):o&&At(o)}),e.clear()}function At(e){for(const t of Object.values(e))t&&typeof t=="object"&&t.isTexture&&t.dispose();e.dispose()}function Sn(e,t){const n=document.createElement("canvas"),o=new Zn({canvas:n,antialias:!0,preserveDrawingBuffer:!0,alpha:!0});o.setSize(e,t,!1),o.shadowMap.enabled=!0;const r=new Un;r.background=null;const{ambient:a,directionals:i}=Dr(r),s=new Ke(at,e/t,.01,100);s.position.copy(We("front")),s.lookAt(0,0,0);function c(h){s.position.copy(We(h)),s.lookAt(0,0,0)}function l(h){s.position.set(h.x,h.y,h.z),s.lookAt(0,0,0)}function f(h){i.forEach(y=>y.visible=h),a.intensity=h?.75:1.6}let u=!1;function d(){u||(u=!0,r.environment?.dispose(),r.environment=null,jr(r),o.dispose(),o.forceContextLoss())}return{scene:r,camera:s,renderer:o,dispose:d,setAngle:c,setCameraPosition:l,getCameraPosition:()=>({x:s.position.x,y:s.position.y,z:s.position.z}),onUserPose:()=>{},previewOrbit:()=>{},commitOrbit:()=>{},setOrbitEnabled:()=>{},setBackground:()=>{},setStudioLighting:f,resize:()=>{},invalidate:()=>{}}}function Dr(e){const t=new Gn(16777215,.75);e.add(t);const n=new Ie(16777215,2.2);n.position.set(3,5,5);const o=new Ie(12571903,.7);o.position.set(-4,1,2);const r=new Ie(16777215,1);r.position.set(0,3,-5);const a=[n,o,r];return a.forEach(i=>e.add(i)),{ambient:t,directionals:a}}function An(e,t){const n=rt(t);return new Promise((o,r)=>{new $n().load(n.glb,a=>{const i=a.scene;if(n.pruneNamePrefixes.length){const d=[];i.traverse(h=>{n.pruneNamePrefixes.some(y=>h.name.startsWith(y))&&d.push(h)}),d.forEach(h=>h.removeFromParent())}i.rotation.set(n.baseEuler.x,n.baseEuler.y,n.baseEuler.z),i.updateMatrixWorld(!0);const s=new Qn().setFromObject(i),c=s.getSize(new G),l=s.getCenter(new G),f=n.fitSize/Math.max(c.x,c.y,c.z);i.scale.multiplyScalar(f),i.position.copy(l.multiplyScalar(-f));const u=new eo;u.add(i),e.scene.add(u),e.setAngle("front"),o(u)},void 0,r)})}function Wr(e){return An(e)}const Pt=1900,kt=2800,Hr=8192,Ur=2;async function $r(e,t,n,o={}){const r=e.renderer,a=r.getPixelRatio(),i=r.getSize(new qt);r.setDrawingBufferSize(t,n,1);let s;o.cameraPosition?(s=new Ke(at,t/n,.01,100),s.position.copy(o.cameraPosition),s.lookAt(0,0,0)):(s=e.camera.clone(),s.aspect=t/n,s.updateProjectionMatrix());try{const c=e.scene.background;e.scene.background=null;try{r.render(e.scene,s)}finally{e.scene.background=c}const l=document.createElement("canvas");let f=null;try{l.width=t,l.height=n,l.getContext("2d")?.drawImage(r.domElement,0,0);const u=Pn(l),d=u.canvas;f=d;const h=d.width,y=d.height;return{bytes:await new Promise((g,p)=>{d.toBlob(b=>{if(!b){p(new Error("toBlob returned null"));return}b.arrayBuffer().then(v=>g(new Uint8Array(v)),p)},"image/png")}),width:h,height:y,frame:{width:t,height:n,cropX:u.x,cropY:u.y}}}finally{f&&f!==l&&(f.width=0,f.height=0),l.width=0,l.height=0}}finally{r.setDrawingBufferSize(i.x,i.y,a),e.invalidate()}}function Pn(e,t=Ur){const n=e.getContext("2d",{willReadFrequently:!0});if(!n)return{canvas:e,x:0,y:0};const{width:o,height:r}=e,a=n.getImageData(0,0,o,r).data;let i=o,s=r,c=-1,l=-1;for(let h=0;h<r;h++)for(let y=0;y<o;y++)a[(h*o+y)*4+3]!==0&&(y<i&&(i=y),y>c&&(c=y),h<s&&(s=h),h>l&&(l=h));if(c<i||l<s)return{canvas:e,x:0,y:0};i=Math.max(0,i-t),s=Math.max(0,s-t),c=Math.min(o-1,c+t),l=Math.min(r-1,l+t);const f=c-i+1,u=l-s+1,d=document.createElement("canvas");return d.width=f,d.height=u,d.getContext("2d")?.drawImage(e,i,s,f,u,0,0,f,u),{canvas:d,x:i,y:s}}function Gr(e){const t=URL.createObjectURL(new Blob([e],{type:"image/png"}));return new Promise((n,o)=>{const r=new Image;r.onload=()=>{URL.revokeObjectURL(t),n(r)},r.onerror=()=>{URL.revokeObjectURL(t),o(new Error("Screenshot could not be decoded for the flat card"))},r.src=t})}function Vr(e,t,n,o){if(e.beginPath(),o<=0){e.rect(0,0,t,n);return}e.moveTo(o,0),e.arcTo(t,0,t,n,o),e.arcTo(t,n,0,n,o),e.arcTo(0,n,0,0,o),e.arcTo(0,0,t,0,o),e.closePath()}function qr(e,t,n,o){const r=t?"naturalWidth"in t?t.naturalWidth:t.width:0,a=t?"naturalHeight"in t?t.naturalHeight:t.height:0,i=cr(r,a,n,o),{width:s,height:c,cardWidth:l,cardHeight:f,radius:u,rotation:d}=i;e.width=s,e.height=c;const h=e.getContext("2d");if(!h)throw new Error("2D context unavailable for the flat card");return h.translate(s/2,c/2),h.rotate(d),h.translate(-l/2,-f/2),Vr(h,l,f,u),h.clip(),t?(h.imageSmoothingQuality="high",h.drawImage(t,0,0,l,f)):(h.fillStyle="#000",h.fillRect(0,0,l,f)),i}async function Xr(e,t,n){return(await kn(e,t,n)).out}async function kn(e,t,n){const o=e?await Gr(e):null,r=document.createElement("canvas");try{const a=qr(r,o,t,n),{width:i,height:s}=a;return{out:{bytes:await new Promise((l,f)=>{r.toBlob(u=>{if(!u){f(new Error("toBlob returned null"));return}u.arrayBuffer().then(d=>l(new Uint8Array(d)),f)},"image/png")}),width:i,height:s,frame:{width:i,height:s,cropX:0,cropY:0}},geometry:a}}finally{r.width=0,r.height=0}}const Ct=24*1024*1024,He=new WeakMap;async function Kr(e){const t=await Ho(e.bytes);return Ue({look:e.look,screenshot:t,width:e.width,height:e.height,physicalBody:e.physicalBody,screenLayers:e.screenLayers})}function Yr(e,t){const n=He.get(e);if(!n)return;const o=n.entries.get(t);if(o)return n.entries.delete(t),n.entries.set(t,o),o}function Jr(e,t,n){const o=n.bytes.byteLength;if(o>Ct)return;let r=He.get(e);r||(r={entries:new Map,bytes:0},He.set(e,r));const a=r.entries.get(t);a&&(r.bytes-=a.bytes.byteLength),r.entries.delete(t),r.entries.set(t,n),r.bytes+=o;const i=Array.from(r.entries.keys());for(let s=0;s<i.length&&r.bytes>Ct;s++){const c=r.entries.get(i[s]);c&&(r.bytes-=c.bytes.byteLength,r.entries.delete(i[s]))}}function Ue(e){if(e===null||typeof e!="object")return JSON.stringify(e)??"null";if(Array.isArray(e))return`[${e.map(Ue).join(",")}]`;const t=e;return`{${Object.keys(t).filter(o=>t[o]!==void 0).sort().map(o=>`${JSON.stringify(o)}:${Ue(t[o])}`).join(",")}}`}function Zr(e,t,n,o,r){return{x:(e.x+1)/2*t-o,y:(1-e.y)/2*n-r}}function Qr(e){const{width:t,height:n,cardWidth:o,cardHeight:r,rotation:a}=e,i=Math.cos(a),s=Math.sin(a),c=(u,d)=>({x:t/2+u*i-d*s,y:n/2+u*s+d*i}),l=o/2,f=r/2;return{tl:c(-l,-f),tr:c(l,-f),br:c(l,f),bl:c(-l,f)}}function Ae(e){return new Promise((t,n)=>{e.toBlob(o=>{if(!o){n(new Error("toBlob returned null"));return}o.arrayBuffer().then(r=>t(new Uint8Array(r)),n)},"image/png")})}function Ot(e,t,n,o,r){const a=document.createElement("canvas");return a.width=o,a.height=r,a.getContext("2d")?.drawImage(e,t,n,o,r,0,0,o,r),a}function ea(e,t){const n=Math.hypot(e.tr.x-e.tl.x,e.tr.y-e.tl.y),o=Math.hypot(e.bl.x-e.tl.x,e.bl.y-e.tl.y);return n>0?Math.min(n,o)*t/n:0}async function ta(e,t,n,o,r,a={}){const i=e.renderer,s=i.getPixelRatio(),c=i.getSize(new qt);i.setDrawingBufferSize(n,o,1);let l;a.cameraPosition?(l=new Ke(at,n/o,.01,100),l.position.copy(a.cameraPosition),l.lookAt(0,0,0)):(l=e.camera.clone(),l.aspect=n/o,l.updateProjectionMatrix()),l.updateMatrixWorld();const f=[],u=()=>{const d=document.createElement("canvas");return d.width=n,d.height=o,f.push(d),d};try{const d=u(),h=u(),y=u(),m=e.scene.background;e.scene.background=null;try{i.render(e.scene,l),d.getContext("2d")?.drawImage(i.domElement,0,0);try{t.setLayerPass("device"),i.render(e.scene,l),h.getContext("2d")?.drawImage(i.domElement,0,0),t.setLayerPass("screen"),i.render(e.scene,l),y.getContext("2d")?.drawImage(i.domElement,0,0)}finally{t.restoreLayerPass()}}finally{e.scene.background=m}const g=Pn(d);g.canvas!==d&&f.push(g.canvas);const p=g.canvas.width,b=g.canvas.height,v=Ot(h,g.x,g.y,p,b),w=Ot(y,g.x,g.y,p,b);f.push(v,w),e.scene.updateMatrixWorld();const x=t.screenCornersWorld(),A=T=>{const O=T.clone().project(l);return Zr(O,n,o,g.x,g.y)},S={x:0,y:0},I=x?{tl:A(x.tl),tr:A(x.tr),br:A(x.br),bl:A(x.bl)}:{tl:S,tr:S,br:S,bl:S},[C,P,k]=[await Ae(g.canvas),await Ae(v),await Ae(w)];return{bytes:C,width:p,height:b,frame:{width:n,height:o,cropX:g.x,cropY:g.y},layers:{width:p,height:b,device:P,screen:{bytes:k,quad:I,cornerRadiusFrac:ea(I,t.cornerRatio),sourceNodeId:r}}}}finally{f.forEach(d=>{d.width=0,d.height=0}),i.setDrawingBufferSize(c.x,c.y,s),e.invalidate()}}async function na(e,t,n,o){const{out:r,geometry:a}=await kn(e,t,n);return oa(r,a,o)}function oa(e,t,n){const o=Qr(t);return{...e,layers:{width:e.width,height:e.height,device:null,screen:{bytes:e.bytes,quad:o,cornerRadiusFrac:t.cardWidth>0?t.radius/t.cardWidth:0,sourceNodeId:n}}}}function ra(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 aa(e,t){return e.usesPhysicalFinish()?!0:t.material!=="clay"&&L("clearcoat",t.clearcoat)>0}async function ia(e,t,n,o,r,a){const i=V(n,o),s=Jo(n,o).filter(y=>y.bytes);if(s.length===0)return null;const c=ne(r.panelPresetId),l=new Map(o.map((y,m)=>[y.id,m])),f=r.renderScale!=null&&Number.isFinite(r.renderScale)&&r.renderScale>0?r.renderScale:1,u=Math.min(f,Hr/Math.max(Pt,kt)),d=Math.max(1,Math.round(Pt*u)),h=Math.max(1,Math.round(kt*u));{const y=[];for(let b=0;b<s.length;b++){const v=s[b];a(`Rendering ${b+1}/${s.length}${r.locale?` (${r.locale})`:""}…`);let w,x;const A=v.frameNodeId||null,S=r.screenLayers||!v.bytes?null:await Kr({look:v.look,bytes:v.bytes,width:d,height:h,physicalBody:aa(t.device,v.look),screenLayers:!1}),I=S?Yr(e,S):void 0;if(I)w=I;else if(lr(v.look)){await Mr(t,v.look,v.bytes,()=>!0);const C=_r(v.look.angle,v.look.cameraPos);if(r.screenLayers){const P=await ta(e,t.screen,d,h,A,{cameraPosition:C});w=P,x=P.layers}else w=await $r(e,d,h,{cameraPosition:C})}else if(r.screenLayers){const C=await na(v.bytes,v.look,h,A);w=C,x=C.layers}else w=await Xr(v.bytes,v.look,h);S&&!I&&Jr(e,S,w),y.push({shotId:v.id,bytes:w.bytes,width:w.width,height:w.height,heightFrac:Zt(L("deviceSize",v.look.deviceSize)),hOffset:L("hOffset",v.look.hOffset)/100,vOffset:L("vOffset",v.look.vOffset)/100,panelIndex:l.get(v.panelId)??0,...v.look.clipToFrame===!0?{clipToFrame:!0}:{},...x?{layers:x}:{}})}const m=ar(y,c.width,c.height),g=ir(o,r);a("Saving project…");const p=wn(ra(i,o,r));return{panelWidth:c.width,panelHeight:c.height,count:o.length,background:g,phones:m,shadow:r.shadow,floorReflection:r.floorReflection??!1,project:JSON.stringify(p)}}}function ge(e){return/^[0-9a-fA-F]{3,8}$/.test(e)?`#${e}`:e}function $e(e,t,n,o){const{x0:r,y0:a,x1:i,y1:s}=Ao(n,o,t.angle),c=e.createLinearGradient(r,a,i,s);for(const l of t.stops)c.addColorStop(Math.min(1,Math.max(0,l.at)),ge(l.color));return c}function se(e,t,n,o,r,a,i){const s=document.createElement("canvas");s.width=n,s.height=o;try{const c=s.getContext("2d");if(!c)return;c.fillStyle=$e(c,t,n,o),c.fillRect(r,0,a,o),e.drawImage(s,r,0,a,o,i,0,a,o)}finally{s.width=0,s.height=0}}function Tt(e){return URL.createObjectURL(new Blob([e],{type:"image/png"}))}function Mt(e){return new Promise((t,n)=>{const o=new Image;o.onload=()=>t(o),o.onerror=n,o.src=e})}const sa=128,la=32;function ca(e){const t=e.naturalWidth,n=e.naturalHeight;if(!(t>0&&n>0))return{rows:[]};const o=Math.min(sa,n),r=Math.max(1,Math.min(t,Math.round(o*t/n)*2)),a=document.createElement("canvas");a.width=r,a.height=o;try{const i=a.getContext("2d",{willReadFrequently:!0});if(!i)return{rows:[]};i.drawImage(e,0,0,r,o);const s=i.getImageData(0,0,r,o).data,c=[];for(let l=0;l<o;l++){let f=-1,u=-1;for(let d=0;d<r;d++)s[(l*r+d)*4+3]<la||(f<0&&(f=d),u=d);c.push(f<0?null:[f/r,(u+1)/r])}return{rows:c}}finally{a.width=0,a.height=0}}const da=16*1024*1024;function Et(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 Cn(){let e=0;const t=Array.from(U.values());for(const r of t)e+=Et(r);const n=Array.from(U.keys());let o=0;for(;e>da&&o<n.length-1;){const r=U.get(n[o]);r&&(e-=Et(r),r.reflection&&(r.reflection.canvas.width=0,r.reflection.canvas.height=0),U.delete(n[o])),o++}}const U=new Map,Pe=new Map;async function ua(e,t){if(!t){const a=Tt(e);try{return{img:await Mt(a)}}finally{URL.revokeObjectURL(a)}}const n=U.get(e);if(n)return U.delete(e),U.set(e,n),n;const o=Pe.get(e);if(o)return o;const r=(async()=>{const a=Tt(e);try{return{img:await Mt(a)}}finally{URL.revokeObjectURL(a)}})();Pe.set(e,r);try{const a=await r;return U.set(e,a),Cn(),a}finally{Pe.delete(e)}}async function fa(e,t,n){const o={},r=t.panelWidth*t.count,a=t.panelHeight,i=n?.backgroundViewport,s=i?t.panelWidth*i.panelCount:r,c=i?t.panelWidth*i.panelIndex:0,l=n?.panelViewport,f=l===void 0?0:l*t.panelWidth,u=l===void 0?r:t.panelWidth;e.width=u,e.height=a;const d=e.getContext("2d");if(!d)return{silhouettes:o};n?.transparentBg?d.clearRect(0,0,r,a):t.background.kind==="gradient"?l!==void 0?se(d,t.background.gradient,r,a,f,u,0):i?se(d,t.background.gradient,s,a,c,r,0):(d.fillStyle=$e(d,t.background.gradient,r,a),d.fillRect(0,0,r,a)):t.background.kind==="perPanel"?t.background.colors.forEach((g,p)=>{d.fillStyle=ge(g),d.fillRect(p*t.panelWidth-f,0,t.panelWidth,a)}):t.background.fills.forEach((g,p)=>{const b=p*t.panelWidth-f;l!==void 0&&p!==l||(g.kind==="solid"?(d.fillStyle=ge(g.color),d.fillRect(b,0,t.panelWidth,a)):l!==void 0?se(d,g.gradient,r,a,f,u,0):i?se(d,g.gradient,s,a,c+b,t.panelWidth,b):(d.fillStyle=$e(d,g.gradient,r,a),d.fillRect(b,0,t.panelWidth,a)))}),d.save(),d.translate(-f,0);const h=n?.phoneRange?Math.max(0,n.phoneRange.start):0,y=n?.phoneRange?Math.min(t.phones.length,n.phoneRange.end):t.phones.length,m=n?.reuseDecodedPhones===!0;for(let g=h;g<y;g++){const p=t.phones[g],b=n?.clip==="panel"||n?.clip===void 0&&p.clipToFrame===!0;if(n?.skipShotId&&p.shotId===n.skipShotId)continue;const v=await ua(p.bytes,m),w=v.img,x=v.silhouette??ca(w);m&&(v.silhouette=x),o[p.shotId]=x,ha(d,v,p,t,b,m)}return d.restore(),{silhouettes:o}}function ha(e,t,n,o,r=n.clipToFrame===!0,a=!1,i=1){const s=t.img;r&&(e.save(),e.beginPath(),e.rect(n.panelIndex*o.panelWidth,0,o.panelWidth,o.panelHeight),e.clip()),o.floorReflection&&pa(e,t,n,a),e.save(),o.shadow&&(e.shadowColor="rgba(0,0,0,0.35)",e.shadowBlur=o.panelWidth*.03*i,e.shadowOffsetY=o.panelHeight*.012*i),e.drawImage(s,n.x,n.y,n.width,n.height),e.restore(),r&&e.restore()}function pa(e,t,n,o){const r=Math.round(n.height*.45);if(r<=0||n.width<=0)return;const a=o?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,r);return}const i=t.img,s=document.createElement("canvas");s.width=Math.max(1,n.width),s.height=Math.max(1,r);const c=s.getContext("2d");if(!c)return;c.save(),c.translate(0,r),c.scale(1,-1),c.drawImage(i,0,r-n.height,n.width,n.height),c.restore();const l=c.createLinearGradient(0,0,0,r);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,r),e.drawImage(s,n.x,n.y+n.height,n.width,r),o&&(t.reflection={width:n.width,height:n.height,canvas:s},Cn())}const On=q.lineHeight,ma=q.bandInset;function ga(e,t,n){if(!e)return[t];const o=t.split(/\s+/).filter(Boolean),r=[];let a="";for(const i of o){const s=a?`${a} ${i}`:i;a&&e.measureText(s).width>n?(r.push(a),a=i):a=s}return a&&r.push(a),r}function ya(e,t){if(!e)return 0;let n=0;for(const o of t)n=Math.max(n,e.measureText(o).width);return n}function Lt(e,t,n){return e==="center"?t+n/2:e==="right"?t+n:t}function Tn(e,t,n,o){const r=t.map((y,m)=>{const g=y.text.trim();if(!g)return null;const p=y.sizePt*(o/be),b=Ye(y.fontId).family;e&&(e.font=`${J} ${p}px "${b}"`);const w=(D(y.anchor)?oe(y):y.maxWidth)*n,x=ga(e,g,w),A=p*(y.lineHeight??On),S=x.length*A,I=Math.max(S,(y.reserveLines??x.length)*A);return{layer:y,index:m,lines:x,px:p,lineH:A,width:ya(e,x),blockH:S,reservedH:I,boxWidth:w}}),a=r.filter(y=>y!==null&&D(y.layer.anchor)),i=a.filter(y=>y.layer.band==="bottom"),s=a.filter(y=>y.layer.band!=="bottom"),c=y=>y[0]?.layer.bandInset??ma,l=(1-c(i))*o-i.reduce((y,m)=>y+m.reservedH,0);let f=c(s)*o,u=l,d=0;const h=[];for(const y of r){if(!y)continue;if(!D(y.layer.anchor)){const w=y.layer.anchor.x*n,x=y.layer.anchor.y*o;h.push({layer:y.layer,index:y.index,x:Lt(y.layer.align,w,y.boxWidth),yTop:x,lines:y.lines,px:y.px,lineH:y.lineH,width:y.width,boxLeft:w,boxWidth:y.boxWidth,boxTop:x,boxHeight:y.blockH});continue}const m=y.layer.band==="bottom",g=m?u:f,p=g+(y.reservedH-y.blockH)/2,b=cn(y.layer)*n,v=Lt(y.layer.align,b,y.boxWidth);h.push({layer:y.layer,index:y.index,x:v,yTop:p,lines:y.lines,px:y.px,lineH:y.lineH,width:y.width,boxLeft:b,boxWidth:y.boxWidth,boxTop:g,boxHeight:y.reservedH}),m?u+=y.reservedH:f+=y.reservedH,d=Math.max(d,p+y.blockH)}return{placed:h,bandBottom:d}}function ba(e,t,n,o){e.save(),e.textBaseline="top";const{placed:r}=Tn(e,t,n,o);for(const a of r){e.fillStyle=ge(a.layer.color),e.textAlign=a.layer.align,e.font=`${J} ${a.px}px "${Ye(a.layer.fontId).family}"`;let i=a.yTop;for(const s of a.lines)e.fillText(s,a.x,i),i+=a.lineH}e.restore()}function va(e,t){return e.sizePt*(t/be)*(e.lineHeight??On)}function wa(e,t,n,o){const r=Tn(e,t,n,o).placed;e?.save(),e&&(e.textBaseline="top");const a=r.map(i=>{const s=i.layer.align==="center"?i.x-i.width/2:i.layer.align==="right"?i.x-i.width:i.x,c=i.lines.length*i.lineH;let l=i.yTop,f=i.yTop+c;if(e){e.font=`${J} ${i.px}px "${Ye(i.layer.fontId).family}"`;const u=e.measureText(i.lines[0]).actualBoundingBoxAscent,d=e.measureText(i.lines[i.lines.length-1]).actualBoundingBoxDescent;Number.isFinite(u)&&Number.isFinite(d)&&(l=i.yTop-u,f=i.yTop+(i.lines.length-1)*i.lineH+d)}return{index:i.index,anchorX:i.boxLeft/n,top:i.yTop/o,boxLeft:i.boxLeft/n,boxTop:i.boxTop/o,boxWidth:i.boxWidth/n,boxHeight:i.boxHeight/o,left:s/n,width:i.width/n,height:c/o,inkTop:l/o,inkHeight:(f-l)/o}});return e?.restore(),a}function xa(e,t,n,o,r){t.forEach((a,i)=>{const s=r[a];!s||s.length===0||(e.save(),e.translate(i*n,0),ba(e,s,n,o),e.restore())})}const Ia=""+new URL("Inter-SemiBold-B9yU462S.woff2",import.meta.url).href,Sa=""+new URL("Manrope-SemiBold-44nuYf5T.woff2",import.meta.url).href,Aa=""+new URL("Poppins-SemiBold-DJVo7c07.woff2",import.meta.url).href,Pa=""+new URL("Fraunces-SemiBold-BtraKtER.woff2",import.meta.url).href,ka=""+new URL("SpaceGrotesk-SemiBold-CyO2J5Y0.woff2",import.meta.url).href,Ca={inter:Ia,manrope:Sa,poppins:Aa,fraunces:Pa,"space-grotesk":ka},Oa=ue.map(e=>({...e,url:Ca[e.id]}));let le=null;function Ta(){return le||(le=(async()=>{const e=new Set;document.fonts.forEach(t=>e.add(`${t.family}/${t.weight}`)),await Promise.all(Oa.filter(t=>!e.has(`${t.family}/${String(J)}`)).map(async t=>{const n=new FontFace(t.family,`url(${t.url})`,{weight:String(J)});await n.load(),document.fonts.add(n)})),await document.fonts.ready})().catch(e=>{throw le=null,e})),le}const Ma=22/be,Ea=1.1,Ft=4,La=.063,Fa=.167,Y=Math.round(Ma*be),Ra=.02,Na=50;function xe(e,t){const n=W(e,t.box);if(!n||!t.silhouette||t.silhouette.rows.length===0)return n;const{frame:o}=t,r=t.silhouette.rows,a=o.height/r.length;let i=1/0,s=1/0,c=-1/0,l=-1/0;const f=Math.max(0,Math.floor((n.y-o.y)/a)),u=Math.min(r.length-1,Math.ceil((n.y+n.height-o.y)/a)-1);for(let d=f;d<=u;d++){const h=r[d];if(!h)continue;const y=W(n,{x:o.x+h[0]*o.width,y:o.y+d*a,width:(h[1]-h[0])*o.width,height:a});y&&(i=Math.min(i,y.x),s=Math.min(s,y.y),c=Math.max(c,y.x+y.width),l=Math.max(l,y.y+y.height))}return c>i&&l>s?{x:i,y:s,width:c-i,height:l-s}:null}function W(e,t){const n=Math.max(e.x,t.x),o=Math.max(e.y,t.y),r=Math.min(e.x+e.width,t.x+t.width),a=Math.min(e.y+e.height,t.y+t.height);return r<=n||a<=o?null:{x:n,y:o,width:r-n,height:a-o}}function ye(e,t){return W(e,t)}function Rt(e,t){const n=Math.abs(e-t)%360;return n>180?360-n:n}function Nt(e){return Cr(e.cameraPos??xn(e.angle))}function re(e,t,n,o,r,a,i){if(t.length===0)return[];const s=[];for(const c of wa(e,t,r,a)){const l=t[c.index];if(!l)continue;const f=ye({x:(o+c.left)*r,y:c.top*a,width:c.width*r,height:c.height*a},i);f&&s.push({ref:{panelId:n,panelIndex:o,layerIndex:c.index,band:D(l.anchor)},box:f,lineHeightPx:va(l,a)})}return s}function Mn(e,t,n,o){return n.height<=Ge(e,t,o)}function Ge(e,t,n){const o=e.y+e.height/2<=t.y+t.height/2;return n*(o?Fa:La)}function Ve(e,t,n){return n.height<=Ge(e.box,t.box,e.lineHeightPx)+Ge(t.box,e.box,t.lineHeightPx)}function En(e){const{ctx:t,panelIds:n,panelWidth:o,panelHeight:r}=e,a={x:0,y:0,width:o*n.length,height:r};t?.save();try{return Ba(e,a)}finally{t?.restore()}}function za(e){const{ctx:t,panelIds:n,panelWidth:o,panelHeight:r,captionLayers:a}=e,i={x:0,y:0,width:o*n.length,height:r};t?.save();try{return n.flatMap((s,c)=>re(t,a[s]??[],s,c,o,r,i)).map(({ref:s,box:c})=>({ref:s,box:c}))}finally{t?.restore()}}function Ba(e,t){const{ctx:n,panelIds:o,panelWidth:r,panelHeight:a,captionLayers:i}=e,s=o.flatMap((m,g)=>re(n,i[m]??[],m,g,r,a,t)),c=[];for(const m of e.phones){const p=e.clip==="panel"||e.clip===void 0&&m.clipToFrame===!0?{x:m.panelIndex*r,y:0,width:r,height:a}:t,b={x:m.x,y:m.y,width:m.width,height:m.height},v=ye(b,p);v&&c.push({shotId:m.shotId,box:v,frame:b,silhouette:e.silhouettes?.[m.shotId],layoutHeight:m.height})}const l=[];for(let m=0;m<s.length;m++)for(let g=m+1;g<s.length;g++){const p=W(s[m].box,s[g].box);p&&l.push({a:s[m].ref,b:s[g].ref,overlap:p,depthFrac:a>0?p.height/a:0,inkUncertain:Ve(s[m],s[g],p)})}const f=[];for(const m of s)for(const g of c){const p=xe(m.box,g);p&&f.push({caption:m.ref,shotId:g.shotId,overlap:p,depthFrac:a>0?p.height/a:0,inkUncertain:Mn(m.box,g.box,p,m.lineHeightPx)})}const u=[];for(let m=0;m<c.length;m++)for(let g=m+1;g<c.length;g++){const p=c[m],b=c[g],v=W(p.box,b.box);if(!v)continue;const w=[],x=Math.max(p.layoutHeight,b.layoutHeight),A=Math.min(p.layoutHeight,b.layoutHeight);A>0&&x/A>=Ea&&w.push("scale");const S=e.looks?.[p.shotId],I=e.looks?.[b.shotId],C=!!S&&!!I;S&&I&&(Rt(Nt(S),Nt(I))>=Ft&&w.push("angle"),Rt(L("roll",S.roll),L("roll",I.roll))>=Ft&&w.push("roll"));const P=Math.min(p.box.width*p.box.height,b.box.width*b.box.height);u.push({shotIdA:p.shotId,shotIdB:b.shotId,overlap:v,coverage:P>0?v.width*v.height/P:0,deliberate:w.length>0,signals:w,anglesKnown:C})}const d=new Set;for(const m of l)m.a.band&&d.add(m.a.panelId),m.b.band&&d.add(m.b.panelId);for(const m of f)m.caption.band&&d.add(m.caption.panelId);const h=[],y=[];return o.forEach((m,g)=>{if(!d.has(m))return;const p=ja(e,m,g,t,s,c);p!==null&&y.push({panelId:m,maxWidth:p});const b=Da(e,m,g,t,s,c);b&&h.push(b)}),{captionsMeasurable:n!=null,captionOverlaps:l,captionDeviceOverlaps:f,deviceOverlaps:u,suggestions:h,widthSuggestions:y,hasWarning:l.length>0||f.length>0||u.some(m=>!m.deliberate)}}function _a(e){const{ctx:t,panelIds:n,panelWidth:o,panelHeight:r}=e,a={x:0,y:0,width:o*n.length,height:r},i=[];for(const l of e.phones){const u=e.clip==="panel"||e.clip===void 0&&l.clipToFrame===!0?{x:l.panelIndex*o,y:0,width:o,height:r}:a,d={x:l.x,y:l.y,width:l.width,height:l.height},h=ye(d,u);h&&i.push({shotId:l.shotId,box:h,frame:d,silhouette:e.silhouettes?.[l.shotId],layoutHeight:l.height})}const s=(l,f,u)=>{const d=n.indexOf(l);if(d<0||!t)return[];t.save();try{return re(t,f,l,d,o,r,u?a:{x:-1e9,y:-1e9,width:2e9,height:2e9})}finally{t.restore()}},c=new Map(n.map(l=>[l,s(l,e.captionLayers[l]??[],!0)]));return{measurable:t!=null,commit(l,f){c.set(l,s(l,f,!0))},probe(l,f){const u=s(l,f,!1),d=u.flatMap(m=>{const g=ye(m.box,a);return g?[{...m,box:g}]:[]}),h=n.flatMap(m=>m===l?[]:c.get(m)??[]),y=[];for(const m of d){for(const g of i){const p=xe(m.box,g);p&&y.push({layerIndex:m.ref.layerIndex,band:m.ref.band,against:"device",samePanelBand:!1,depthFrac:r>0?p.height/r:0,inkUncertain:Mn(m.box,g.box,p,m.lineHeightPx)})}for(const g of h){const p=W(m.box,g.box);p&&y.push({layerIndex:m.ref.layerIndex,band:m.ref.band,against:"caption",samePanelBand:!1,depthFrac:r>0?p.height/r:0,inkUncertain:Ve(m,g,p)})}}for(let m=0;m<d.length;m++)for(let g=m+1;g<d.length;g++){const p=W(d[m].box,d[g].box);if(!p)continue;const b=r>0?p.height/r:0,v=Ve(d[m],d[g],p);for(const[w,x]of[[d[m],d[g]],[d[g],d[m]]])y.push({layerIndex:w.ref.layerIndex,band:w.ref.band,against:"caption",samePanelBand:x.ref.band,depthFrac:b,inkUncertain:v})}return{hits:y,boxes:u.map(m=>({layerIndex:m.ref.layerIndex,band:m.ref.band,box:m.box}))}}}}function ja(e,t,n,o,r,a){const i=e.captionLayers[t]??[];if(!i.length||i.some(f=>!D(f.anchor)))return null;const s=r.filter(f=>f.ref.panelId!==t).map(f=>f.box),c=f=>a.some(u=>xe(f,u))||s.some(u=>W(f,u)),l=Math.min(...i.map(f=>f.maxWidth));for(let f=Math.ceil(l*100)-1;f>=10;f--){const u=f/100,d=re(e.ctx,i.map(h=>({...h,maxWidth:u})),t,n,e.panelWidth,e.panelHeight,o);if(d.length&&d.every((h,y)=>!c(h.box)&&!d.slice(y+1).some(m=>W(h.box,m.box))))return u}return null}function Da(e,t,n,o,r,a){const i=e.captionLayers[t]??[],s=i.flatMap((u,d)=>D(u.anchor)&&u.text.trim()?[d]:[]);if(s.length===0||!(Math.min(...s.map(u=>i[u].sizePt))>Y))return null;const l=r.filter(u=>!(u.ref.panelId===t&&u.ref.band)).map(u=>u.box),f=u=>a.some(d=>xe(u,d))||l.some(d=>W(u,d));for(let u=1;u<=Na;u++){const d=Math.round((1-u*Ra)*100)/100,h=new Map(s.map(p=>[p,i[p].sizePt*d]));if(Math.min(...Array.from(h.values()))<Y)return null;const y=i.map((p,b)=>{const v=h.get(b);return v===void 0?p:{...p,sizePt:v}});if(re(e.ctx,y,t,n,e.panelWidth,e.panelHeight,o).filter(p=>p.ref.band).every(p=>!f(p.box)))return{panelId:t,scale:d,layers:s.map(p=>({layerIndex:p,fromSizePt:i[p].sizePt,toSizePt:h.get(p)}))}}return null}me.colorways;class Ln{frame=[];back=[];accent=[];allBody=[];model;scene;renderer;profile;envTexture=null;constructor(t,n,o,r){this.model=t,this.scene=n,this.renderer=o,this.profile=rt(r);const{frame:a,back:i,accent:s}=this.profile.body;t.traverse(c=>{const l=c;if(!l.isMesh)return;(Array.isArray(l.material)?l.material:[l.material]).forEach(u=>{const d=u;!d||!d.name||(a.includes(d.name)?this.push(this.frame,d):i.includes(d.name)?this.push(this.back,d):s.includes(d.name)&&this.push(this.accent,d),this.push(this.allBody,d))})})}push(t,n){t.includes(n)||t.push(n)}get finishMaterials(){return[...this.frame,...this.back]}paint(t,n){const o=n instanceof R?n:new R(n);t.forEach(r=>{r.color=o.clone(),r.needsUpdate=!0})}setColorway(t){if(t==="custom")return;const n=this.profile.colorways.find(o=>o.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 R(t),o=n.clone().lerp(new R(16777215),.2),r=n.clone().multiplyScalar(.6);this.paint(this.frame,n),this.paint(this.back,o),this.paint(this.accent,r)}setFinish(t){const n=Number.isFinite(t)?Math.max(0,Math.min(1,t)):0;this.finishMaterials.forEach(o=>{o.userData.baseRoughness===void 0&&(o.userData.baseRoughness=o.roughness);const r=o.userData.baseRoughness;o.roughness=r*(1-n),o.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(o=>{const r=o;r.clearcoat=n,r.clearcoatRoughness=.1,r.needsUpdate=!0})}upgradeFinishToPhysical(){this.clearcoatUpgraded=!0;const t=new Map;for(const o of Array.from(new Set(this.finishMaterials))){const r=new Vn;r.color.copy(o.color),r.metalness=o.metalness,r.roughness=o.roughness,r.map=o.map,r.normalMap=o.normalMap,r.normalScale.copy(o.normalScale),r.roughnessMap=o.roughnessMap,r.metalnessMap=o.metalnessMap,r.aoMap=o.aoMap,r.aoMapIntensity=o.aoMapIntensity,r.emissive.copy(o.emissive),r.emissiveMap=o.emissiveMap,r.emissiveIntensity=o.emissiveIntensity,r.envMapIntensity=o.envMapIntensity,r.transparent=o.transparent,r.opacity=o.opacity,r.alphaTest=o.alphaTest,r.side=o.side,r.flatShading=o.flatShading,r.vertexColors=o.vertexColors,r.name=o.name,r.userData={...o.userData},r.clearcoat=0,t.set(o,r)}this.model.traverse(o=>{const r=o;if(r.isMesh)if(Array.isArray(r.material))r.material=r.material.map(a=>t.get(a)??a);else{const a=t.get(r.material);a&&(r.material=a)}});const n=o=>o.map(r=>t.get(r)??r);this.frame=n(this.frame),this.back=n(this.back),this.allBody=n(this.allBody)}environmentMap(){if(!this.envTexture){const t=new to(this.renderer);this.envTexture=t.fromScene(new qn,.04).texture,t.dispose()}return this.envTexture}setClay(t){const n=Fr.find(r=>r.id===t),o=n?new R(n.color):new R(t);this.allBody.forEach(r=>{r.userData.clayStashedMap===void 0&&(r.userData.clayStashedMap=r.map),r.color=o.clone(),r.metalness=0,r.roughness=.85,r.map=null,r.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 zt=1.35;class Fn{materials=[];glassOverlays=[];screenMesh=null;flatPlane=null;texture=null;appliedBytes=null;flatScreenOn=!1;profile;model;passRestore=[];constructor(t,n){this.profile=rt(n),this.model=t;const o=this.profile.screen.material;t.traverse(r=>{const a=r;if(!a.isMesh)return;(Array.isArray(a.material)?a.material:[a.material]).forEach(s=>{const c=s;c&&c.name===o&&!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 o=n.max.x-n.min.x,r=n.max.y-n.min.y,a=n.max.z-n.min.z,i=(n.max.x+n.min.x)/2,s=(n.max.y+n.min.y)/2,c=(n.max.z+n.min.z)/2,l=r<=o&&r<=a?"y":a<=o&&a<=r?"z":"x",f=this.texture.clone();f.needsUpdate=!0,f.colorSpace=ct,f.flipY=!1,f.center.set(.5,.5),f.wrapS=ie,f.wrapT=ie;const{coverFill:u,coverCornerRatio:d,coverRepeat:h}=this.profile.screen;f.repeat.set(h.x,h.y);const y=l==="x"?a:o,m=l==="z"||l==="x"?r:a,g=Math.min(y,m)*u*d,p=Wa(y*u,m*u,g),b=new no(p,new Xn({map:f,emissive:new R(16777215),emissiveMap:f,emissiveIntensity:zt,color:new R(0),toneMapped:!1,side:oo,depthTest:!0,depthWrite:!0,polygonOffset:!0,polygonOffsetFactor:-4,polygonOffsetUnits:-4}));l==="y"?(b.rotation.x=-Math.PI/2,b.position.set(i,n.max.y,c)):l==="x"?(b.rotation.y=Math.PI/2,b.position.set(n.max.x,s,c)):b.position.set(i,s,n.max.z),b.renderOrder=999,this.screenMesh.add(b),this.flatPlane=b}setLayerPass(t){this.restoreLayerPass();const n=a=>{const i=a.visible;a.visible=!1,this.passRestore.push(()=>{a.visible=i})};if(t==="screen"){this.model.traverse(a=>{const i=a;if(!i.isMesh||i===this.flatPlane)return;(Array.isArray(i.material)?i.material:[i.material]).forEach(c=>{c&&!this.materials.includes(c)&&n(c)})});return}this.glassOverlays.forEach(n);const o=a=>new ao({blending:lo,blendEquation:so,blendSrc:dt,blendDst:dt,depthTest:!0,depthWrite:!0,side:a?.side??io,polygonOffset:a?.polygonOffset??!1,polygonOffsetFactor:a?.polygonOffsetFactor??0,polygonOffsetUnits:a?.polygonOffsetUnits??0}),r=(a,i)=>{const s=a.material;if(!(Array.isArray(s)?s:[s]).some(i))return;const c=[],l=f=>{if(!i(f))return f;const u=o(f);return c.push(u),u};a.material=Array.isArray(s)?s.map(l):l(s),this.passRestore.push(()=>{a.material=s,c.forEach(f=>f.dispose())})};this.model.traverse(a=>{const i=a;i.isMesh&&(i===this.flatPlane?r(i,()=>!0):r(i,s=>this.materials.includes(s)))})}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 o=n.boundingBox,r=n.attributes.position,a=n.attributes.uv;if(!o||!r||!a)return null;const i=o.getSize(new G),s=o.getCenter(new G),c=i.y<=i.x&&i.y<=i.z?"y":i.z<=i.x&&i.z<=i.y?"z":"x",[l,f]=c==="y"?["x","z"]:c==="z"?["x","y"]:["z","y"],u=this.profile.screen.coverFill,{repeat:d}=this.profile.screen,h={};for(const b of[-1,1])for(const v of[-1,1]){const w=new G;w[c]=o.max[c],w[l]=s[l]+b*i[l]*u/2,w[f]=s[f]+v*i[f]*u/2;let x=-1,A=1/0;for(let P=0;P<r.count;P++){const k=Math.hypot(r.getComponent(P,"xyz".indexOf(l))-w[l],r.getComponent(P,"xyz".indexOf(f))-w[f]);k<A&&(A=k,x=P)}if(x<0)return null;const S=.5+(a.getX(x)-.5)*d.x,I=.5+(a.getY(x)-.5)*d.y;if(S===.5||I===.5)return null;const C=`${I<.5?"t":"b"}${S<.5?"l":"r"}`;if(h[C])return null;h[C]=w}const{tl:y,tr:m,br:g,bl:p}=h;return!y||!m||!g||!p?null:(t.updateWorldMatrix(!0,!1),{tl:y.applyMatrix4(t.matrixWorld),tr:m.applyMatrix4(t.matrixWorld),br:g.applyMatrix4(t.matrixWorld),bl:p.applyMatrix4(t.matrixWorld)})}get cornerRatio(){return this.profile.screen.coverCornerRatio}restoreScreen(){this.prepareScreen()}prepareScreen(){this.materials.forEach(t=>{t.color=new R(0),t.emissive=new R(16777215),t.emissiveIntensity=1,t.roughness=1,t.metalness=0,t.needsUpdate=!0})}dimGlassOverlay(t){t.traverse(n=>{const o=n;if(!o.isMesh)return;(Array.isArray(o.material)?o.material:[o.material]).forEach(a=>{const i=a;i&&i.name!==this.profile.screen.material&&i.transparent&&i.opacity>.2&&this.glassOverlays.push(i)})})}applyWallpaper(t){if(this.appliedBytes===t&&this.texture)return this.lightScreen(this.texture),Promise.resolve();const n=new Blob([t],{type:"image/png"}),o=URL.createObjectURL(n),r=this.texture;return new Promise((a,i)=>{const s=new Image;s.onload=()=>{try{const c=document.createElement("canvas");c.width=s.naturalWidth,c.height=s.naturalHeight;const l=c.getContext("2d");if(!l)throw new Error("2D context unavailable for wallpaper blit");l.drawImage(s,0,0);const f=new Kn(c);f.colorSpace=ct,f.flipY=!1,f.center.set(.5,.5),f.wrapS=ie,f.wrapT=ie,f.repeat.set(this.profile.screen.repeat.x,this.profile.screen.repeat.y),f.needsUpdate=!0,this.texture=f,this.appliedBytes=t,this.lightScreen(f),this.flatScreenOn&&this.setFlatScreen(!0),r?.dispose(),URL.revokeObjectURL(o),a()}catch(c){URL.revokeObjectURL(o),i(c)}},s.onerror=()=>{URL.revokeObjectURL(o),i(new Error("wallpaper image failed to decode"))},s.src=o})}lightScreen(t){this.materials.forEach(n=>{n.map=t,n.emissiveMap=t,n.emissive=new R(16777215),n.emissiveIntensity=zt,n.color=new R(0),n.needsUpdate=!0})}}function Wa(e,t,n){const o=e/2,r=t/2,a=Math.min(n,o,r),i=new Yn;i.moveTo(-o+a,-r),i.lineTo(o-a,-r),i.quadraticCurveTo(o,-r,o,-r+a),i.lineTo(o,r-a),i.quadraticCurveTo(o,r,o-a,r),i.lineTo(-o+a,r),i.quadraticCurveTo(-o,r,-o,r-a),i.lineTo(-o,-r+a),i.quadraticCurveTo(-o,-r,-o+a,-r);const s=new Jn(i,16),c=s.attributes.position,l=new Float32Array(c.count*2);for(let f=0;f<c.count;f++)l[f*2]=(c.getX(f)+o)/e,l[f*2+1]=(c.getY(f)+r)/t;return s.setAttribute("uv",new ro(l,2)),s}function ee(e){return`build-shot-${e+1}`}function it(e){const t=[...e.panelIds??[]];for(const n of e.shots)t.includes(n.panelId)||t.push(n.panelId);return t}function Ha(e,t){return{...e,panelIds:t.map(n=>n.id)}}const Ua=1900,$a=2800;function Ga(e){return new Promise((t,n)=>{e.toBlob(o=>{if(!o)return n(new Error("canvas toBlob returned null"));o.arrayBuffer().then(r=>t(new Uint8Array(r)),n)},"image/png")})}async function Rn(e,t,n,o={}){await Ta();const r=it(e);if(o.panelViewport!==void 0&&(!Number.isInteger(o.panelViewport)||o.panelViewport<0||o.panelViewport>=r.length))throw new Error("buildStrip: panel viewport is outside the strip");const a=r.map(d=>({id:d})),i=e.shots.map((d,h)=>({id:ee(h),panelId:d.panelId,frameNodeId:"",frameName:`screen-${h+1}`,bytes:t.screens[h]??null,look:d.look,thumb:null,thumbStale:!1,...$(d)})),c={panelPresetId:ne(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:o.renderScale,locale:n},l=o.onProgress??(()=>{});let f=o.refs,u=null;if(!f){const d=fo(e.panelPresetId);u=Sn(Ua,$a);const h=await An(u,d);f={stage:u,device:new Ln(h,u.scene,u.renderer,d),screen:new Fn(h,d)}}try{const d=await ia(f.stage,f,i,a,c,l);if(!d)throw new Error("buildStrip: nothing renderable (no shots)");const h=document.createElement("canvas");try{const y={...o.panelViewport!==void 0?{panelViewport:o.panelViewport}:{},...o.clip?{clip:o.clip}:{},...o.backgroundViewport?{backgroundViewport:o.backgroundViewport}:{}},m=await fa(h,d,Object.keys(y).length>0?y:void 0),g=d.panelWidth,p=d.panelHeight,b=h.getContext("2d");if(!b)throw new Error("buildStrip: 2D context unavailable");b.save(),o.panelViewport!==void 0&&b.translate(-o.panelViewport*g,0),xa(b,r,g,p,t.captionText??{}),b.restore();const v=En({phones:d.phones,panelIds:r,captionLayers:t.captionText??{},panelWidth:g,panelHeight:p,ctx:b,looks:Object.fromEntries(i.map(P=>[P.id,P.look])),clip:o.clip,silhouettes:m.silhouettes}),w=o.renderScale&&o.renderScale>0&&o.renderScale<1?o.renderScale:1,x=[],A=o.panelViewport??0,S=o.panelViewport===void 0?d.count:A+1;for(let P=A;P<S;P++){const k=document.createElement("canvas");k.width=Math.max(1,Math.round(g*w)),k.height=Math.max(1,Math.round(p*w));const T=k.width,O=k.height;try{const E=k.getContext("2d",{alpha:!1});if(!E)throw new Error("buildStrip: 2D context unavailable");E.fillStyle="#000",E.fillRect(0,0,T,O),E.drawImage(h,o.panelViewport===void 0?P*g:0,0,g,p,0,0,T,O),x.push({index:P,bytes:await Ga(k),width:T,height:O})}finally{k.width=0,k.height=0}}const I=d.phones.map(({shotId:P,panelIndex:k,x:T,y:O,width:E,height:z})=>({shotId:P,panelIndex:k,x:T,y:O,width:E,height:z})),C={panelIds:[...r],panelWidth:g,panelHeight:p,phones:d.phones.map(({shotId:P,panelIndex:k,x:T,y:O,width:E,height:z,clipToFrame:H})=>({shotId:P,panelIndex:k,x:T,y:O,width:E,height:z,...H===!0?{clipToFrame:!0}:{}})),silhouettes:m.silhouettes,...o.clip?{clip:o.clip}:{}};return{panels:x,layout:v,phones:I,geometry:C}}finally{h.width=0,h.height=0}}finally{u&&u.dispose()}}function Va(e){if(!e||e.length===0)return null;const t=Array.from(new Set(e.flatMap(o=>o.frames))).sort((o,r)=>o-r).map(o=>`Frame ${o+1}`),n=t.length===0?"":t.length===1?` in ${t[0]}`:` in ${t.slice(0,-1).join(", ")} and ${t[t.length-1]}`;return e.length===1?`${e[0].kind==="caption-device"?"A caption still overlaps a device":e[0].kind==="caption-caption"?"Two captions still overlap":"Two devices still collide"}${n}.`:`${e.length} layout overlaps still remain${n}.`}const qe=.005,qa=.02,Xa=12;function ke(e){return Math.max(1,Math.round(e*100))}function Ce(e){return`${e.kind}:${e.frames.join(",")}:${e.anchored}`}function Ka(e,t){const n=new Map(e.suggestions.map(i=>[i.panelId,i.scale])),o=new Map((e.widthSuggestions??[]).map(i=>[i.panelId,i.maxWidth])),r=[];for(const i of e.captionOverlaps){if(i.inkUncertain||i.depthFrac<qe)continue;const[s,c]=i.a.band===i.b.band?[i.a,i.b]:i.a.band?[i.a,i.b]:[i.b,i.a],l=Oe([t.frameOfPanel(s.panelId),t.frameOfPanel(c.panelId)]);l.length!==0&&r.push({kind:"caption-caption",frames:l,depthPct:ke(i.depthFrac),anchored:!i.a.band||!i.b.band,...Bt(n,s.band?s.panelId:null),..._t(o,s.band?s.panelId:null)})}for(const i of e.captionDeviceOverlaps){if(i.inkUncertain||i.depthFrac<qe)continue;const s=Oe([t.frameOfPanel(i.caption.panelId),t.frameOfShot(i.shotId)]);s.length!==0&&r.push({kind:"caption-device",frames:s,depthPct:ke(i.depthFrac),anchored:!i.caption.band,...Bt(n,i.caption.band?i.caption.panelId:null),..._t(o,i.caption.band?i.caption.panelId:null)})}for(const i of e.deviceOverlaps){if(i.deliberate||i.coverage<qa)continue;const s=Oe([t.frameOfShot(i.shotIdA),t.frameOfShot(i.shotIdB)]);s.length!==0&&r.push({kind:"device-device",frames:s,depthPct:ke(i.coverage),anchored:!1})}const a=new Map;for(const i of r){const s=a.get(Ce(i));s?i.depthPct>s.depthPct?a.set(Ce(i),{...i,clearAtScale:i.clearAtScale??s.clearAtScale,clearAtMaxWidth:i.clearAtMaxWidth??s.clearAtMaxWidth}):s.clearAtScale==null&&i.clearAtScale!=null&&(s.clearAtScale=i.clearAtScale):a.set(Ce(i),i),s&&s.clearAtMaxWidth==null&&i.clearAtMaxWidth!=null&&(s.clearAtMaxWidth=i.clearAtMaxWidth)}return Array.from(a.values()).sort((i,s)=>s.depthPct-i.depthPct).slice(0,Xa).sort((i,s)=>i.frames[0]-s.frames[0]||i.kind.localeCompare(s.kind))}function Oe(e){const[t,...n]=e;return t<0?[]:[t,...n.filter(o=>o>=0&&o!==t)]}function Bt(e,t){const n=t==null?void 0:e.get(t);return n==null?{}:{clearAtScale:Math.round(n*100)/100}}function _t(e,t){const n=t==null?void 0:e.get(t);return n==null?{}:{clearAtMaxWidth:n}}function Ya(e,t){if(t.length===0)return e;const n=e.captionStyles;if(!n)return e;const o={};for(const[r,a]of Object.entries(n))o[r]=a.map(i=>({...i}));for(const r of t){const a=o[r.panelId];if(a)for(const i of r.layers){const s=a[i.layerIndex];s&&(s.sizePt=i.toSizePt)}}return{...e,captionStyles:o}}function Te(e){return e.frames.map(t=>`frame ${t+1}`).join(" + ")}function Ja(e,t,n){if(!e.captionsMeasurable)return null;const o=Ka(e,t);if(o.length===0)return null;const r=o.filter(l=>l.kind==="device-device"),a=o.filter(l=>l.kind!=="device-device"&&l.clearAtScale==null);if(r.length>0||a.length>0||!n){const l=[];r.length>0&&l.push(`${r.map(Te).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 f of a)l.push(f.anchored?`${Te(f)}: 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.`:`${Te(f)}: 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:o,note:`No corrected look is offered. ${l.join(" ")}`}}const i=new Set(o.filter(l=>l.kind!=="device-device").map(l=>l.frames[0])),s=e.suggestions.filter(l=>i.has(t.frameOfPanel(l.panelId))),c=s.flatMap(l=>{const f=t.frameOfPanel(l.panelId)+1;return l.layers.map(u=>`frame ${f} layer ${u.layerIndex+1}: sizePt ${u.fromSizePt} → ${u.toSizePt}`)}).join("; ");return{findings:o,correctedLook:Ya(n,s),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 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 Za(e){return String(Math.max(-100,Math.min(100,e*35)))}const Qa=["roll","deviceSize","hOffset","vOffset","finish","clearcoat"];function jt(e){if(!e||typeof e!="object")return{};const t={...e};for(const n of Qa)typeof t[n]=="number"&&(t[n]=String(t[n]));return t}function ei(e){const{subtitle:t,sizePt:n,maxWidth:o,...r}=e;return{...r,...n!==void 0?{sizePt:Number(n)}:{},...o!==void 0?{maxWidth:Number(o)}:{}}}function Dt(e){const t={};for(const[n,o]of Object.entries(e))o!==void 0&&(t[n]=o);return t}function Me(e,t,n){const o={};return e&&t.forEach((r,a)=>{const i=n[a];i!==void 0&&e[r]!==void 0&&(o[i]=e[r])}),o}function ti(e){const t=Array.isArray(e.sourcePanelIds)&&e.sourcePanelIds.length===e.slotSizes.length?e.sourcePanelIds:null,n=t?e.slotSizes.map(I=>Number.isInteger(I)&&I>0?I:0):e.slotSizes.filter(I=>Number.isInteger(I)&&I>0),o=n.map((I,C)=>`panel-${C+1}`);let r={};const a=e.look&&typeof e.look=="object"?e.look:null,i=e.style??null,s=a&&Array.isArray(a.shots)?a.shots:[],c=s.length>0,l=i?jt(i.shotLook):null,f=[];let u=0;n.forEach((I,C)=>{for(let P=0;P<I;P++){const k=c?jt(s[u]?.look??s[0]?.look??{}):l??{},T=k.hOffset!==void 0&&k.hOffset!==null?String(k.hOffset):Za(P),{z:O}=c?$(s[u]):{};f.push({panelId:o[C],look:{...M,...k,hOffset:T},...O!==void 0?{z:O}:{}}),u++}});let d={},h={},y={},m="gradient",g=bo,p=vo,b="vertical",v,w,x=!0,A=!1;if(a){m=a.bgMode==="perPanel"?"perPanel":"gradient";const I=he({gradientStops:Array.isArray(a.gradientStops)?a.gradientStops:void 0,gradientAngle:typeof a.gradientAngle=="number"?a.gradientAngle:void 0,gradientFrom:typeof a.gradientFrom=="string"?a.gradientFrom:g,gradientTo:typeof a.gradientTo=="string"?a.gradientTo:p,gradientDir:a.gradientDir==="horizontal"?"horizontal":b});v=I.stops,w=I.angle,{gradientFrom:g,gradientTo:p,gradientDir:b}=fe(I),a.shadow===!1&&(x=!1),a.floorReflection===!0&&(A=!0);const C=t?[...t]:[];if(!t)for(const P of s){const k=typeof P?.panelId=="string"?P.panelId:null;k&&!C.includes(k)&&C.push(k)}d=Me(a.panelColors,C,o),h=Me(nt(a.captionStyles),C,o),y=Me(ln(a.panelBackgrounds),C,o)}else if(i){const I=i.background??{};m=I.mode==="perPanel"?"perPanel":"gradient";const C=he({gradientStops:I.stops,gradientAngle:I.angle,gradientFrom:g,gradientTo:p,gradientDir:b});v=C.stops,w=C.angle,{gradientFrom:g,gradientTo:p,gradientDir:b}=fe(C),I.shadow===!1&&(x=!1),I.floorReflection===!0&&(A=!0),Array.isArray(I.panelColors)&&I.panelColors.forEach((P,k)=>{typeof P=="string"&&P&&o[k]!==void 0&&(d[o[k]]=P)})}if(i&&Array.isArray(i.captions)){const I=h,C=(O,E)=>({...I[O]?.[E]??{}}),P={},k={};i.captions.forEach((O,E)=>{const z=o[E];if(!(z===void 0||O===null||O===void 0)){if(Array.isArray(O)){const H=O.filter(B=>!!B&&typeof B=="object"&&typeof B.text=="string"&&B.text.trim()!=="").map((B,ae)=>Be(C(z,ae),Dt(ei(B))));H.length>0&&(k[z]=H)}else if(typeof O=="object"){const{text:H,subtitle:B,sizePt:ae,maxWidth:lt,...Hn}=O;P[z]=Be(C(z,0),Dt({...Hn,...ae!==void 0?{sizePt:Number(ae)}:{},...lt!==void 0?{maxWidth:Number(lt)}:{}})),typeof H=="string"&&H.trim()&&(k[z]={headline:H,...typeof B=="string"&&B?{subtitle:B}:{}})}}});const T=we({[N]:k},un(P));h=fn(T),r=Q(T)}return{look:{panelPresetId:e.panelPresetId??(typeof a?.panelPresetId=="string"?a.panelPresetId:void 0)??"r69",bgMode:m,gradientStops:v,gradientAngle:w,gradientFrom:g,gradientTo:p,gradientDir:b,panelColors:d,shadow:x,floorReflection:A,panelBackgrounds:y,captionStyles:h,shots:f,...t?{panelIds:o}:{}},panelIds:o,captionText:r}}function ni(e){const t=e?.trim();return t?/\.(png|jpe?g|webp)$/i.test(t)?t:`${t}.png`:null}function oi(e,t){const n=new Map;return e.map((o,r)=>{const a=ni(t?.[r]);if(!a)return`screen-${r+1}.png`;const i=n.get(a)??0;if(n.set(a,i+1),i===0)return a;const s=a.lastIndexOf(".");return`${a.slice(0,s)}-${i+1}${a.slice(s)}`})}function ri(e){const{look:t,panelIds:n,captionText:o,locale:r,shotNames:a,outputs:i,locales:s,baseLocale:c}=e,l=n.map(d=>({id:d})),f=oi(t.shots,a),u=t.shots.map((d,h)=>({id:`shot-${h+1}`,panelId:d.panelId,frameNodeId:f[h],frameName:f[h],bytes:null,look:d.look,thumb:null,thumbStale:!0}));return wn({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:i,...s?{locales:s}:{},...c?{baseLocale:c}:{},captionText:o&&Object.keys(o).length>0?{[r||N]:o}:{}})}const ai=1900,ii=2800,Wt=new Map;async function si(e){e("booting headless stage + loading model (once)…");const t=Sn(ai,ii),n=await Wr(t);return{stage:t,device:new Ln(n,t.scene,t.renderer),screen:new Fn(n)}}function Nn(e,t,n={}){let o=Wt.get(e);o||(o={refs:si(n.onProgress??(()=>{})),tail:Promise.resolve()},Wt.set(e,o));const{refs:r}=o,a=o.tail.then(async()=>t(await r));return o.tail=a.catch(()=>{}),a}function zn(e,t){return t===e.baseLocale||!e.locales||e.locales.includes(t)}function Ht(e,t){const n={...e,...t.set};for(const o of t.unset??[])delete n[o];return n}function Ee(e,t){if(t.edits.length===0)return e;const n=Object.keys(e.captionText).filter(u=>!zn(e,u)),o=n.length===0?e.captionText:Object.fromEntries(Object.entries(e.captionText).filter(([u])=>!n.includes(u))),r=t.edits.filter(u=>u.locale===void 0||u.locale===e.baseLocale),a=new Map;for(const u of r)a.set(u.panelId,[...a.get(u.panelId)??[],u]);let i=Yo(o,Array.from(a.keys()),e.baseLocale,(u,d)=>{const h=a.get(d);if(!(!u?.length||!h))return u.map((y,m)=>h.filter(g=>g.layerIndex===m).reduce(Ht,y))});for(const u of t.edits){if(u.locale===void 0||u.locale===e.baseLocale||n.includes(u.locale))continue;const d=i[u.locale]?.[u.panelId];d?.[u.layerIndex]&&(i={...i,[u.locale]:{...i[u.locale],[u.panelId]:d.map((h,y)=>y===u.layerIndex?Ht(h,u):h)}})}if(i===o)return e;n.length>0&&(i={...i,...Object.fromEntries(n.map(u=>[u,e.captionText[u]]))});const s={...e,captionText:i};if(!e.frameTemplates||!e.shots)return s;const c={...e.frameTemplates},l=new Set(t.edits.map(u=>u.panelId));let f=!1;for(const u of Array.from(l)){const d=e.frameTemplates[u];if(!d)continue;const h=yr({...e,shots:e.shots,captionSlotIds:e.captionSlotIds??{},frameTemplates:e.frameTemplates},u);!h||h.modified||(c[u]=gr({shots:e.shots,captionText:i,captionSlotIds:e.captionSlotIds??{},baseLocale:e.baseLocale},u,d.templateId),f=!0)}return f?{...s,frameTemplates:c}:s}const li=.4,Ut=.02,ci=.02,$t=[.04,.02],ce=.5,te=e=>Math.round(e*100)/100;function di(e){const t=new Map,n=o=>{const r=`${e.font}\0${e.textBaseline}\0${o}`;let a=t.get(r);return a||(a=e.measureText(o),t.set(r,a)),a};return new Proxy(e,{get(o,r){if(r==="measureText")return n;const a=Reflect.get(o,r,o);return typeof a=="function"?a.bind(o):a},set(o,r,a){return Reflect.set(o,r,a,o)}})}const Xe=e=>!e.inkUncertain&&e.depthFrac>=qe;function Bn(e){if(e.boxAlign)return e.boxAlign;if(e.bandCenter===void 0)return"center";const t=cn(e),n=oe(e),o=t+n/2;return Math.abs(o-.5)<.01?"center":o<.5?"left":"right"}function ui(e,t,n){return e.map((o,r)=>{if(!t.has(r))return o;let a={...o};const i=oe(o);return n.width<i-1e-9&&(delete a.widthMode,a.maxWidth=te(n.width)),n.align&&n.align!==Bn(o)&&(a=Be(a,{boxAlign:n.align})),n.flip&&(a.band==="bottom"?delete a.band:a.band="bottom"),n.inset!==null&&(a.bandInset=n.inset),a})}function fi(e,t,n){return e.hits.some(o=>t.has(o.layerIndex)&&Xe(o))?!1:e.boxes.every(({layerIndex:o,box:r})=>!t.has(o)||r.y>=-ce&&r.y+r.height<=n.height+ce&&r.x>=n.left-ce&&r.x+r.width<=n.right+ce)}function Gt(e,t,n){const o=n?[e]:[];for(let r=te(e-Ut);r>=t-1e-9;r=te(r-Ut))o.push(r);return o}function hi(e,t,n){const o=Array.from(t),r=o.map(h=>oe(e[h])),a=Math.max(...r),i=Math.min(li,Math.min(...r)),s=Gt(a,i,!1).map(h=>({width:h,align:null,flip:!1,inset:null}));if(n)return s;const c=Bn(e[o[0]]),l=[c,...["left","right","center"].filter(h=>h!==c)],f=e[o[0]].bandInset??.06,u=$t.filter(h=>h<f-1e-9),d=(h,y,m)=>{for(const g of Gt(a,i,!0))s.push({width:g,align:h,flip:y,inset:m})};return l.slice(1).forEach(h=>d(h,!1,null)),u.forEach(h=>l.forEach(y=>d(y,!1,h))),[null,...$t].forEach(h=>l.forEach(y=>d(y,!0,h))),s}function pi(e,t,n,o,r){const a={},i=[];return t.maxWidth!==e.maxWidth&&(a.maxWidth=t.maxWidth),t.boxAlign!==e.boxAlign&&t.boxAlign&&(a.boxAlign=t.boxAlign),t.bandInset!==e.bandInset&&t.bandInset!==void 0&&(a.bandInset=t.bandInset),t.band!==e.band&&(t.band?a.band=t.band:i.push("band")),e.widthMode!==void 0&&t.widthMode===void 0&&i.push("widthMode"),e.bandCenter!==void 0&&t.bandCenter===void 0&&i.push("bandCenter"),Object.keys(a).length===0&&i.length===0?null:{...r?{locale:r}:{},panelId:n,layerIndex:o,set:a,...i.length>0?{unset:i}:{}}}function mi(e,t){const n=m=>({state:e,resolution:{edits:[]},measured:m,remaining:[],remainingSentence:null});if(!t.ctx||t.panelIds.length===0)return n(!1);const o=di(t.ctx),r=m=>e.panels?e.panels.findIndex(g=>g.id===m):t.panelIds.indexOf(m),a=m=>{const g=t.panelIds.indexOf(m);return{left:g*t.panelWidth,right:(g+1)*t.panelWidth,height:t.panelHeight}},i=m=>_a({phones:t.phones,panelIds:t.panelIds,captionLayers:m,panelWidth:t.panelWidth,panelHeight:t.panelHeight,ctx:o,...t.clip?{clip:t.clip}:{},...t.silhouettes?{silhouettes:t.silhouettes}:{}}),s=(m,g)=>new Set(m.flatMap((p,b)=>D(p.anchor)&&p.text.trim()&&!(g&&p.widthMode==="fill")?[b]:[])),c=(m,g,p,b)=>{const v=i(g),w=[];for(const x of t.panelIds){const A=g[x];if(!A?.length||!b(x))continue;const S=s(A,p);if(S.size===0)continue;const I=a(x);if(v.probe(x,A).hits.some(P=>S.has(P.layerIndex)&&Xe(P)))for(const P of hi(A,S,p)){const k=ui(A,S,P);if(fi(v.probe(x,k),S,I)){v.commit(x,k),k.forEach((T,O)=>{const E=pi(A[O],T,x,O,p?m:void 0);E&&w.push(E)});break}}}return w},l=e.baseLocale,f=(m,g)=>t.family?Xo(m.captionText,m.outputCaptions,t.family,g,l):Q(m.captionText,g,l),u=m=>Object.keys(m.captionText).filter(g=>zn(m,g)),d=m=>{const g=new Map,p=u(m);for(const b of p.length>0?p:[l]){const v=f(m,b),w=i(v);for(const x of t.panelIds){const A=v[x];if(!A?.length)continue;const S=s(A,!1),I=r(x);if(!(I<0))for(const C of w.probe(x,A).hits){if(!S.has(C.layerIndex)||!Xe(C))continue;const P=C.against==="device"?"caption-device":"caption-caption",k=Math.max(1,Math.round(C.depthFrac*100)),T=`${P}:${I}`,O=g.get(T);(!O||O.depthPct<k)&&g.set(T,{kind:P,frames:[I],depthPct:k,anchored:!1})}}}return Array.from(g.values()).sort((b,v)=>b.frames[0]-v.frames[0]||b.kind.localeCompare(v.kind))},h=m=>{const g=c(l,f(m,l),!1,()=>!0);let p=Ee(m,{edits:g});const b=[];for(const v of u(p)){if(v===l)continue;const w=p.captionText[v]??{};b.push(...c(v,f(p,v),!0,x=>w[x]!==void 0))}return b.length>0&&(p=Ee(p,{edits:b})),{state:p,edits:[...g,...b],remaining:d(p)}};let y=h(e);if(y.remaining.length>0){const m=e.captionText[l]??{},g=Object.keys(m).flatMap(p=>m[p].flatMap((b,v)=>D(b.anchor)&&b.text.trim()&&b.sizePt>Y?[{panelId:p,layerIndex:v,sizePt:b.sizePt}]:[]));for(let p=1;g.length>0;p++){const b=te(1-p*ci),v=g.map(({panelId:x,layerIndex:A,sizePt:S})=>({panelId:x,layerIndex:A,set:{sizePt:Math.max(Y,te(S*b))}})),w=h(Ee(e,{edits:v}));if(w.remaining.length===0){y={...w,edits:[...v,...w.edits]};break}if(g.every(({sizePt:x})=>x*b<=Y))break}}return{state:y.state,resolution:{edits:y.edits},measured:!0,remaining:y.remaining,remainingSentence:Va(y.remaining)}}function gi(e,t){const n=Math.max(e.x,t.x),o=Math.max(e.y,t.y),r=Math.min(e.x+e.width,t.x+t.width),a=Math.min(e.y+e.height,t.y+t.height);return r<=n||a<=o?null:{x:n,y:o,width:r-n,height:a-o}}const Le=e=>Math.max(0,e.width)*Math.max(0,e.height);function Fe(e,t,n,o,r){const a=Le(o),i=Math.min(Le(n[0]),Le(n[1]));return{kind:e,subjects:t,objectBounds:n,intersectionBounds:o,overlapPx:a,overlapPct:i>0?Math.round(a/i*1e4)/100:0,...r}}const Re=e=>({kind:"caption",panelId:e.panelId,panelIndex:e.panelIndex,layerIndex:e.layerIndex});function yi(e){const{geometry:t}=e,{panelIds:n,panelWidth:o,panelHeight:r}=t,a={width:o,height:r},i=n.length,s=o*i,c={x:0,y:0,width:s,height:r},l=new Map,f=t.phones.map(p=>{const b=t.clip==="panel"||t.clip===void 0&&p.clipToFrame===!0,v={x:p.x,y:p.y,width:p.width,height:p.height},w=gi(v,b?wt(p.panelIndex,a):c);return l.set(p.shotId,w),{shotId:p.shotId,rect:v,panelIndex:p.panelIndex,panelIndices:w?tr(w,o,i):[],z:$(e.layering?.[p.shotId]).z??0,hidden:!1,clipToFrame:p.clipToFrame===!0}});for(const p of e.hiddenDevices??[])f.push({shotId:p.shotId,rect:nr(p.placement,a,p.cropAspect),panelIndex:p.placement.panelIndex,panelIndices:[],z:$(p).z??0,hidden:!0,clipToFrame:!1});const u=e.ctx??null,d=e.captionLayers??{},h=En({phones:t.phones,panelIds:n,captionLayers:d,panelWidth:o,panelHeight:r,ctx:u,looks:e.looks,clip:t.clip,silhouettes:t.silhouettes}),y=new Map(za({ctx:u,panelIds:n,captionLayers:d,panelWidth:o,panelHeight:r}).map(({ref:p,box:b})=>[`${p.panelId}\0${p.layerIndex}`,b])),m=p=>y.get(`${p.panelId}\0${p.layerIndex}`),g=[];for(const p of h.deviceOverlaps){const b=l.get(p.shotIdA),v=l.get(p.shotIdB);!b||!v||g.push(Fe("device-device",[{kind:"device",shotId:p.shotIdA},{kind:"device",shotId:p.shotIdB}],[b,v],p.overlap,{deliberate:p.deliberate}))}for(const p of h.captionDeviceOverlaps){const b=m(p.caption),v=l.get(p.shotId);!b||!v||g.push(Fe("caption-device",[Re(p.caption),{kind:"device",shotId:p.shotId}],[b,v],p.overlap,{inkUncertain:p.inkUncertain}))}for(const p of h.captionOverlaps){const b=m(p.a),v=m(p.b);!b||!v||g.push(Fe("caption-caption",[Re(p.a),Re(p.b)],[b,v],p.overlap,{inkUncertain:p.inkUncertain}))}return{panelWidth:o,panelHeight:r,stripWidth:s,panels:n.map((p,b)=>({panelId:p,index:b,bounds:wt(b,a)})),devices:f,overlaps:g,captionsMeasured:u!=null}}function F(e){console.log("[render]",e)}function _n(e){const t=atob(e),n=new Uint8Array(t.length);for(let o=0;o<t.length;o++)n[o]=t.charCodeAt(o);return n}function st(e){let t="";for(let n=0;n<e.length;n++)t+=String.fromCharCode(e[n]);return btoa(t)}function bi(e){return new Promise((t,n)=>{e.toBlob(async o=>{if(!o)return n(new Error("toBlob null"));t(st(new Uint8Array(await o.arrayBuffer())))},"image/png")})}function jn(e,t){const n=it(t),o=new Map(t.shots.map((a,i)=>[ee(i),n.indexOf(a.panelId)])),r=Ja(e.layout,{frameOfPanel:a=>n.indexOf(a),frameOfShot:a=>o.get(a)??-1},t);if(r)return{layout:{findings:r.findings,...r.correctedLook?{correctedLook:r.correctedLook}:{}},layoutNote:r.note}}async function Dn(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,i)=>a+i.width,0),n.height=t[0]?.height??1;const o=n.getContext("2d");let r=0;for(const a of t)o.drawImage(a,r,0),r+=a.width,a.close();return{base64:await bi(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(v=>Array.isArray(v)?v:[v]),{look:o,panelIds:r,captionText:a}=ti({slotSizes:n.map(v=>v.length),...Array.isArray(t.panelIds)?{sourcePanelIds:t.panelIds}:{},panelPresetId:t.panelPresetId,look:t.look??void 0,style:t.style??void 0}),i=n.flat().map(_n),s=Array.isArray(t.captionLayers)&&r[0]?{[r[0]]:t.captionLayers}:a,c=t.preview?.25:1;F(`buildStrip (${n.length} panel${n.length===1?"":"s"}${t.locale?`, ${t.locale}`:""})…`);let l=0;const f=await Nn("visible",v=>(l=performance.now(),Rn(o,{screens:i,captionText:s},t.locale,{refs:v,renderScale:c,onProgress:w=>F(" "+w),...t.clip?{clip:t.clip}:{},...Number.isInteger(t.panelViewport)?{panelViewport:t.panelViewport}:{},...t.backgroundViewport?{backgroundViewport:t.backgroundViewport}:{}})),{onProgress:F});F("encoding panels + stitching the strip preview…");const u=f.panels.map(v=>st(v.bytes)),d=await Dn(f.panels),h=ne(o.panelPresetId),y=Math.round(performance.now()-l),m=jn(f,o),g=f.layout.captionsMeasurable,p=Array.isArray(t.screenshotNames)?t.screenshotNames.flat():void 0,b=t.buildRecord?ri({look:o,panelIds:r,captionText:a,locale:t.locale,shotNames:p,outputs:t.outputs}):void 0;return F(`done: ${f.panels.length} panels, strip ${d.width}x${d.height}, ${y}ms`),{ok:!0,ms:y,count:f.panels.length,panelPresetId:h.id,panelWidth:h.width,panelHeight:h.height,stripWidth:d.width,stripHeight:d.height,panels:u,stripBase64:d.base64,preview:c<1,...b?{projectRecord:b}:{},...m??{},layoutMeasured:g,...t.layerBoxes?{layerBoxes:f.phones.map(({shotId:v,...w})=>({shot:o.shots.findIndex((x,A)=>ee(A)===v),...w}))}:{}}}catch(n){const o=n&&n.stack?n.stack:String(n);return F("ERROR: "+o),{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=vr(JSON.stringify(t.projectFile));if(!n)throw new Error("renderProject: the saved project could not be restored (wrong schema or malformed record)");const o=t.locale||n.baseLocale||n.locales?.[0]||"en-US",r=V(n.shots,n.panels),a=_e(t.variant||{},n.baseLocale),i=new Map((t.screenManifest||[]).map(S=>[`${S.shotId} ${gt(_e(S.variant||{},n.baseLocale))}`,S])),s=(S,I)=>i.get(`${S} ${gt(I)}`),c=r.map(S=>hn(s,S.id,a,_o,n.baseLocale)),l=r.map((S,I)=>({frameName:S.frameName,matched:c[I].value!==void 0,requestedVariant:a,resolvedAt:c[I].resolvedAt,inherited:c[I].inherited,...c[I].value?.source?{source:c[I].value.source}:{}})),f=c.map(({value:S})=>S?.bytes?_n(S.bytes):null),u=Q(n.captionText,o,n.baseLocale),d=Ha(xr({...n,selectedShotId:null,panelPresetId:t.panelPresetId??n.panelPresetId,captionText:{[o]:u}}),n.panels),h=t.preview?.25:1;F(`renderProject (${r.length} shot${r.length===1?"":"s"}, ${o})…`);let y=0;const m=await Nn("visible",S=>(y=performance.now(),Rn(d,{screens:f,captionText:u},o,{refs:S,renderScale:h,onProgress:I=>F(" "+I)})),{onProgress:F});F("encoding panels + stitching the strip preview…");const g=m.panels.map(S=>st(S.bytes)),p=await Dn(m.panels),b=ne(d.panelPresetId),v=Math.round(performance.now()-y),w=jn(m,d),x=m.layout.captionsMeasurable,A=t.settleCaptions?vi(n,m.geometry,a.family):null;return F(`done: ${m.panels.length} panels, strip ${p.width}x${p.height}, ${v}ms`),{ok:!0,ms:v,count:m.panels.length,panelPresetId:b.id,panelWidth:b.width,panelHeight:b.height,stripWidth:p.width,stripHeight:p.height,panels:g,stripBase64:p.base64,preview:h<1,shots:l,locale:o,...w??{},layoutMeasured:x,...t.layoutGeometry?{layoutGeometry:m.geometry}:{},...A?A.wire:{},...t.stripGeometry?{stripGeometry:wi(m,d,r,A?.state?Q(A.state.captionText,o,A.state.baseLocale):u)}:{}}}catch(n){const o=n&&n.stack?n.stack:String(n);return F("ERROR: "+o),{ok:!1,error:String(n&&n.message?n.message:n)}}};let Vt=null;function Wn(){return Vt??=document.createElement("canvas").getContext("2d"),Vt}function vi(e,t,n){if(!t)return{wire:{captionResolution:{edits:[]},captionsMeasured:!1,captionRemaining:null},state:null};const o=mi(e,{...t,...n?{family:n}:{},ctx:Wn()});return{wire:{captionResolution:o.resolution,captionsMeasured:o.measured,captionRemaining:o.remainingSentence},state:o.state}}function wi(e,t,n,o){const r=it(t),a=new Map(n.map((u,d)=>[ee(d),u.id])),i={},s={},c=[];t.shots.forEach((u,d)=>{const h=ee(d);s[h]=u.look,typeof u.z=="number"&&(i[h]={z:u.z}),u.hidden===!0&&c.push({shotId:h,placement:{panelIndex:Math.max(0,r.indexOf(u.panelId)),hOffset:Number.parseFloat(u.look.hOffset)||0,vOffset:Number.parseFloat(u.look.vOffset)||0,deviceSize:Number.parseFloat(u.look.deviceSize)||100},...typeof u.z=="number"?{z:u.z}:{}})});const l=yi({geometry:e.geometry,layering:i,hiddenDevices:c,captionLayers:o,ctx:Wn(),looks:s}),f=u=>a.get(u)??u;return{...l,devices:l.devices.map(u=>({...u,shotId:f(u.shotId)})),overlaps:l.overlaps.map(u=>({...u,subjects:u.subjects.map(d=>d.kind==="device"?{...d,shotId:f(d.shotId)}:d)}))}}window.__RENDER_READY=!0;F("harness ready ✓");
|
package/harness-dist/index.html
CHANGED
|
@@ -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-
|
|
6
|
+
<script type="module" crossorigin src="./assets/index-DvXlO6pq.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.
|
|
3
|
+
"version": "0.11.0",
|
|
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.",
|
package/widget-dist/bundle.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
"use strict";(()=>{var
|
|
1
|
+
"use strict";(()=>{var _="shotops/widgetPayload";var $=`
|
|
2
2
|
:root {
|
|
3
3
|
color-scheme: light dark;
|
|
4
4
|
--sf-ink: #15151a;
|
|
@@ -124,8 +124,8 @@ button, a { font: inherit; }
|
|
|
124
124
|
@media (prefers-reduced-motion: reduce) {
|
|
125
125
|
.sf-download, .sf-open { transition: none; }
|
|
126
126
|
}
|
|
127
|
-
`;function r(n,e,o){let t=document.createElement(n);return e&&(t.className=e),o!==void 0&&(t.textContent=o),t}function
|
|
128
|
-
`)}function
|
|
127
|
+
`;function r(n,e,o){let t=document.createElement(n);return e&&(t.className=e),o!==void 0&&(t.textContent=o),t}function m(n,e,o){let t=r("div","sf-stat");t.append(r("div","sf-k",e),r("div","sf-v",o)),n.append(t)}var Q="2026-01-26",J="shotops-widget",X=4e3;function M(){return typeof window.openai<"u"}function z(){return window.parent!==window}var ee=1,A=new Map;window.addEventListener("message",n=>{if(n.source!==window.parent)return;let e=n.data;if(!e||e.jsonrpc!=="2.0"||e.method||typeof e.id!="number")return;let o=A.get(e.id);o&&(A.delete(e.id),e.error?o.reject(new Error(e.error?.message??"MCP Apps request failed")):o.resolve(e.result))},{passive:!0});function j(n,e){let o=ee++;return new Promise((t,i)=>{A.set(o,{resolve:t,reject:i}),window.parent.postMessage({jsonrpc:"2.0",id:o,method:n,params:e},"*")})}function D(n,e){window.parent.postMessage({jsonrpc:"2.0",method:n,params:e},"*")}var E=null;function P(){if(M()||!z())return Promise.resolve();if(!E){let n=j("ui/initialize",{capabilities:{},clientInfo:{name:J,version:"1.0.0"},protocolVersion:Q,appCapabilities:{availableDisplayModes:["inline"]}});E=new Promise(e=>{let o=setTimeout(e,X);n.then(()=>{clearTimeout(o),e()},()=>{clearTimeout(o),e()})}).then(()=>{D("ui/notifications/initialized",{}),ne()})}return E}var N="";function H(){let n=Math.ceil(document.documentElement.clientWidth||0),e=Math.ceil(document.body?.getBoundingClientRect().height??0),o=`${n}x${e}`;o!==N&&(N=o,D("ui/notifications/size-changed",{width:n,height:e}))}function ne(){if(typeof ResizeObserver>"u"||!document.body)return;let n=0;new ResizeObserver(()=>{n||(n=requestAnimationFrame(()=>{n=0,H()}))}).observe(document.body)}function te(){return!!window.openai?.openExternal||!M()&&z()}function O(){if(window.openai?.notifyIntrinsicHeight){window.openai.notifyIntrinsicHeight();return}M()||!z()||P().then(H)}async function F(n){if(window.openai?.openExternal){await window.openai.openExternal({href:n});return}if(!M()&&z())try{await P(),await j("ui/open-link",{url:n});return}catch{}window.open(n,"_blank","noopener,noreferrer")}function U(n,e,o,t){let i=e;try{let p=new URL(e);/\/storage\/v1\/object\/sign\//.test(p.pathname)&&(p.searchParams.set("download",o),i=p.toString())}catch{}let s=r("a",t,n);return s.href=i,s.download=o,s.rel="noopener noreferrer",/^https?:/i.test(e)?(s.target="_blank",s.addEventListener("click",p=>{te()&&(p.preventDefault(),F(i))}),s):(!M()&&z()&&(s.style.display="none"),s)}function L(n,e,o){let t=r("button",o,n);return t.type="button",t.addEventListener("click",()=>{F(e)}),t}function d(n){return n&&typeof n=="object"&&!Array.isArray(n)?n:null}function oe(n){if(!Array.isArray(n.content))return null;let e=[];for(let o of n.content){let t=d(o);if(!t)continue;if(t.type==="image"&&typeof t.data=="string"&&t.mimeType==="image/png"){e.push(t.data);continue}if(t.type==="resource_link"&&typeof t.uri=="string"&&t.mimeType==="image/png"){e.push({url:t.uri});continue}let i=d(t.resource);t.type==="resource"&&i&&typeof i.uri=="string"&&i.mimeType==="image/png"&&e.push({url:i.uri})}if(e.length>0)return{ok:!0,count:e.length,output:typeof e[0]=="string"?"inline":"urls",panels:e};if(n.isError===!0){let o=n.content.map(t=>d(t)).find(t=>t?.type==="text"&&typeof t.text=="string")?.text;return{ok:!1,...typeof o=="string"?{note:o}:{}}}return null}function W(n,e=0){let o=d(n);if(!o||e>6)return null;let t=d(o[_]);if(t)return t;let i=d(o._meta),s=d(i?.[_]);if(s)return s;for(let p of["mcp_tool_result","call_tool_result","tool_result","result"]){let c=W(o[p],e+1);if(c)return c}return null}function C(n,e=!0,o=0){let t=d(n);if(!t||o>6)return e?n:null;for(let s of["structuredContent","structured_content"]){let p=d(t[s]);if(p)return p}for(let s of["mcp_tool_result","call_tool_result","tool_result","result"]){if(t[s]===void 0)continue;let p=C(t[s],!1,o+1);if(p)return p}let i=oe(t);return i||(e?n:null)}function q(n,e=0){let o=d(n);if(!o||e>6)return null;let t=typeof o.status=="string"?o.status.toLowerCase():"";if(["failed","failure","error","cancelled","canceled"].includes(t))return"failure";if(["complete","completed","success","succeeded"].includes(t))return"success";for(let i of["mcp_tool_result","call_tool_result","tool_result","result"]){let s=q(o[i],e+1);if(s)return s}return null}function re(n){let e=d(n.detail);return d(e?.globals)}function ie(n){return W(n)??C(n,!1)}function se(n){if(!n||typeof n!="object")return n;let e=n;return e.structuredContent&&typeof e.structuredContent=="object"?e.structuredContent:C(n)}function Y(n){P();let e=document.createElement("style");e.textContent=n.css;let o=r("div","sf-root");o.id=n.rootId,o.append(r("div","sf-empty",n.loading)),document.body.append(e,o);let t=!1,i=l=>{let a=se(l);!a||typeof a!="object"||n.accept&&!n.accept(a)||(t=!0,n.render(o,a))},s=l=>i(ie(l));window.addEventListener("message",l=>{if(l.source!==window.parent)return;let a=l.data;!a||a.jsonrpc!=="2.0"||a.method!=="ui/notifications/tool-result"||(i(a.params?.structuredContent),t||s(a.params))},{passive:!0}),window.addEventListener("openai:set_globals",l=>{let a=re(l);a&&(i(a.toolOutput),t||s(a.toolResponseMetadata))},{passive:!0});let p=100,c=500,x=2e3,w=5*6e4,b=2e3,u=0,g=null,h=!1,v=()=>{if(typeof window>"u"||(i(window.openai?.toolOutput),t||s(window.openai?.toolResponseMetadata),t))return;let l=q(window.openai?.toolResponseMetadata);if(l&&g===null&&(g=u),l&&!h&&(l==="failure"||u-(g??u)>=b)&&(h=!0,o.replaceChildren(r("div","sf-empty",n.terminal??n.empty))),u>=w){h||o.replaceChildren(r("div","sf-empty",n.terminal??n.empty));return}let a=u<x?p:c;u+=a,setTimeout(v,a)};v()}function ae(n){return n<1024?`${n} B`:n<1024*1024?`${Math.round(n/1024)} KB`:`${(n/(1024*1024)).toFixed(1)} MB`}function S(n){if(typeof n.zipBase64=="string"&&n.zipBase64.length>0){let e=n.zipBase64.endsWith("==")?2:n.zipBase64.endsWith("=")?1:0;return{href:`data:application/zip;base64,${n.zipBase64}`,size:ae(Math.max(0,n.zipBase64.length*3/4-e))}}return typeof n.zipUrl=="string"&&n.zipUrl.length>0?{href:n.zipUrl,size:null}:null}function G(n){if(!n)return"Anyone with the link can download it. Links last 14 days.";let e=new Date(n);if(Number.isNaN(e.getTime()))return"Anyone with the link can download it. Links last 14 days.";let o=e.toLocaleDateString(void 0,{day:"numeric",month:"short",year:"numeric"}),t=Math.ceil((e.getTime()-Date.now())/864e5);return t<=0?`This link has expired (${o}). Emit the bundle again for a fresh one.`:`Anyone with the link can download it. Expires ${o} \u2014 ${t} day${t===1?"":"s"} from now.`}function K(n){let e=n.length>0?n:["en-US"],o=["fastlane/"],t=e.slice(0,3);return t.forEach(i=>{o.push(` screenshots/${i}/ the PNGs, named in strip order`)}),e.length>t.length&&o.push(` screenshots/\u2026 +${e.length-t.length} more locale folder(s)`),o.push(" Deliverfile pre-filled, ready to run"),o.push("README.md how to upload with your own key"),o.join(`
|
|
128
|
+
`)}function T(n){if(!n.operationId||!n.status)return null;let e=n.progress,o=typeof e?.panelsTotal=="number"&&e.panelsTotal>0,t=Math.max(0,Number((o?e?.panelsCompleted:e?.completed)??0)),i=Math.max(t,Number((o?e?.panelsTotal:e?.total)??0)),s={accepted:["Production accepted","ShotOps is preparing the durable render.","Accepted",!1],queued:["Production queued","The render is safely queued and can outlive this conversation.","Queued",!1],running:["Production rendering","ShotOps is rendering and checkpointing the final assets.","Running",!1],cancel_requested:["Cancellation requested","Work already in flight will stop at the next safe checkpoint.","Cancelling",!1],failed:["Production could not finish","The operation stopped without returning a partial asset set.","Failed",!0],cancelled:["Production cancelled","Unfinished work stopped and the remaining reservation was released.","Cancelled",!0],succeeded:["Production finished","The durable operation succeeded; request its result for fresh download links.","Succeeded",!0]},[p,c,x,w]=s[n.status];return{title:p,detail:c,badge:x,terminal:w,completed:t,total:i}}var V=`${$}
|
|
129
129
|
.sf-body { padding: 15px 16px 4px; }
|
|
130
130
|
.sf-zip {
|
|
131
131
|
display: flex;
|
|
@@ -218,4 +218,4 @@ button, a { font: inherit; }
|
|
|
218
218
|
@media (prefers-reduced-motion: reduce) {
|
|
219
219
|
.sf-get { transition: none; }
|
|
220
220
|
}
|
|
221
|
-
`,
|
|
221
|
+
`,pe="You upload this yourself. ShotOps never holds your Apple credentials, never creates an App Store version, and never submits anything for review.";function le(n,e){return U("Download .zip",n.href,e,"sf-get")}function Z(n,e){n.replaceChildren();let o=T(e);if(o&&!S(e)){let f=r("section","sf-shell"),y=r("header","sf-head"),I=r("div");I.append(r("p","sf-eyebrow","ShotOps / durable production"),r("h2","sf-title",o.title),r("p","sf-sub",o.detail));let B=r("span","sf-badge");B.append(r("span","sf-dot"),document.createTextNode(o.badge)),y.append(I,B),f.append(y);let k=r("footer","sf-meta");m(k,"Progress",o.total>0?`${o.completed}/${o.total}`:"Waiting"),typeof e.progress?.attempt=="number"&&m(k,"Attempt",String(e.progress.attempt)),typeof e.contract?.cost?.reserved=="number"&&m(k,"Reserved",String(e.contract.cost.reserved)),typeof e.contract?.cost?.released=="number"&&m(k,"Released",String(e.contract.cost.released)),f.append(k,r("p","sf-note",`Operation ${e.operationId}. Reconnect with production_operation.`)),n.append(f),O();return}let t=Array.isArray(e.locales)&&e.locales.length>0?e.locales:e.locale?[e.locale]:[],i=typeof e.panelCount=="number"?e.panelCount:0,s=typeof e.totalPanelCount=="number"?e.totalPanelCount:i*Math.max(1,t.length),p=r("section","sf-shell"),c=r("header","sf-head"),x=r("div");x.append(r("p","sf-eyebrow","ShotOps"),r("h2","sf-title","Your screenshot bundle is ready"),r("p","sf-sub",t.length>1?`${s} screenshots across ${t.length} locales, laid out the way fastlane deliver expects.`:"Laid out the way fastlane deliver expects \u2014 download it and upload with your own key."));let w=r("span","sf-badge");w.append(r("span","sf-dot"),document.createTextNode(e.output==="urls"?"Download link":"Inline zip")),c.append(x,w),p.append(c);let b=r("div","sf-body"),u=S(e),g=r("div","sf-zip");g.append(r("div","sf-zip-icon","ZIP"));let h=r("div","sf-zip-text");h.append(r("div","sf-zip-name",e.filename??"fastlane-bundle.zip"));let v=u?.size?` \xB7 ${u.size}`:"";h.append(r("div","sf-zip-sub",s>0?`${s} screenshot${s===1?"":"s"}${v}`:`Bundle${v}`)),g.append(h),u&&g.append(le(u,e.filename??"fastlane-bundle.zip")),b.append(g);let l=r("div","sf-inside");if(l.append(r("p","sf-inside-k","What's inside")),l.append(r("pre","sf-tree",K(t))),b.append(l),e.shareLink?.url){let f=r("div","sf-share"),y=r("div","sf-share-text");y.append(document.createTextNode("Share link")),y.append(r("div","sf-share-sub",G(e.shareLink.expiresAt))),f.append(y,L("Open \u2197",e.shareLink.url,"sf-open")),b.append(f)}p.append(b);let a=r("footer","sf-meta");if(e.bundleId&&m(a,"Bundle ID",e.bundleId),t.length>0&&m(a,t.length===1?"Locale":"Locales",t.join(", ")),Array.isArray(e.outputs)&&e.outputs.length>0&&m(a,"Devices",e.outputs.join(", ")),i>0&&t.length>1&&m(a,"Per locale",String(i)),e.openUrl){let f=r("div","sf-actions");f.append(L("Open in ShotOps \u2197",e.openUrl,"sf-open")),a.append(f)}a.childElementCount>0&&p.append(a);let R=[e.note,e.projectNote].filter(Boolean).join(" ");R&&p.append(r("p","sf-note",R)),p.append(r("p","sf-custody",pe)),n.append(p),O()}Y({css:V,rootId:"shotops-bundle",loading:"Preparing your screenshot bundle\u2026",empty:"No ShotOps bundle result is available.",terminal:"The bundle finished, but ChatGPT did not deliver its result. Refresh ShotOps and try again.",accept:n=>!!(T(n)||S(n)),render:Z});})();
|