shotops-mcp 0.8.0 → 0.9.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.
@@ -0,0 +1 @@
1
+ import{S as Kt,G as qt,A as Yt,D as ae,M as Xt,R as Jt,a as Zt,C as Qt,b as en,c as tn}from"./three-addons-CvX38LO6.js";import{aa as Qe,P as et,b as nn,V as q,a4 as rn,C as k,ab as on,J as Oe,$ as V,M as an,a2 as sn,B as ln}from"./three-webgl-DCw804Ic.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 cn=""+new URL("iphone-optimized-BdcJzlHi.glb",import.meta.url).href,dn="data:model/gltf-binary;base64,Z2xURgIAAADUAAAAwAAAAEpTT057ImFzc2V0Ijp7InZlcnNpb24iOiIyLjAiLCJnZW5lcmF0b3IiOiJTaG90T3BzIHBsYWNlaG9sZGVyIOKAlCB0aGUgUGl4ZWwgbW9kZWwgaXMgZGVsaWJlcmF0ZWx5IG5vdCBidW5kbGVkIGluIHRoZSBucG0gcGFja2FnZSJ9LCJzY2VuZXMiOlt7Im5hbWUiOiJwaXhlbC1ub3QtYnVuZGxlZCIsIm5vZGVzIjpbXX1dLCJzY2VuZSI6MH0gICA=",un=[{id:"grey",label:"Grey",color:11579568},{id:"white",label:"White",color:15263458},{id:"charcoal",label:"Charcoal",color:3815996}],fn=[{id:"silver",label:"Silver",frame:16119285,back:16514043,accent:13816532},{id:"blue",label:"Deep Blue",frame:3290954,back:4409953,accent:2172211},{id:"orange",label:"Cosmic Orange",frame:16219693,back:16487504,accent:12738072}],hn=[{id:"silver",label:"Moonstone",frame:9345186,back:8621205,accent:7041658},{id:"blue",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}],Y={id:"iphone-17-pro",glb:cn,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:fn},Te={id:"pixel-10-pro",glb:dn,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:hn},pn={[Y.id]:Y,[Te.id]:Te};function we(e){return e&&pn[e]||Y}const mn=7,ke={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 tt(e){const t=ke[e]??ke.front,n=Math.hypot(t.x,t.y,t.z),o=mn/n;return{x:t.x*o,y:t.y*o,z:t.z*o}}function gn(e){return Math.atan2(e.x,-e.z)*180/Math.PI}function he(e){const t=tt(e);return new q(t.x,t.y,t.z)}const yn=1.4;function bn(e,t){return(t?new q(t.x,t.y,t.z):he(e)).multiplyScalar(yn)}const nt=35;function Sn(e){e.traverse(t=>{const n=t;n.geometry?.dispose();const o=n.material;Array.isArray(o)?o.forEach(Ce):o&&Ce(o)}),e.clear()}function Ce(e){for(const t of Object.values(e))t&&typeof t=="object"&&t.isTexture&&t.dispose();e.dispose()}function rt(e,t){const n=document.createElement("canvas"),o=new Qe({canvas:n,antialias:!0,preserveDrawingBuffer:!0,alpha:!0});o.setSize(e,t,!1),o.shadowMap.enabled=!0;const r=new Kt;r.background=null;const{ambient:a,directionals:i}=wn(r),l=new et(nt,e/t,.01,100);l.position.copy(he("front")),l.lookAt(0,0,0);function s(f){l.position.copy(he(f)),l.lookAt(0,0,0)}function d(f){l.position.set(f.x,f.y,f.z),l.lookAt(0,0,0)}function u(f){i.forEach(c=>c.visible=f),a.intensity=f?.75:1.6}let p=!1;function h(){p||(p=!0,r.environment?.dispose(),r.environment=null,Sn(r),o.dispose(),o.forceContextLoss())}return{scene:r,camera:l,renderer:o,dispose:h,setAngle:s,setCameraPosition:d,getCameraPosition:()=>({x:l.position.x,y:l.position.y,z:l.position.z}),onUserPose:()=>{},previewOrbit:()=>{},commitOrbit:()=>{},setOrbitEnabled:()=>{},setBackground:()=>{},setStudioLighting:u,resize:()=>{}}}function wn(e){const t=new Yt(16777215,.75);e.add(t);const n=new ae(16777215,2.2);n.position.set(3,5,5);const o=new ae(12571903,.7);o.position.set(-4,1,2);const r=new ae(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 ot(e,t){const n=we(t);return new Promise((o,r)=>{new qt().load(n.glb,a=>{const i=a.scene;if(n.pruneNamePrefixes.length){const h=[];i.traverse(f=>{n.pruneNamePrefixes.some(c=>f.name.startsWith(c))&&h.push(f)}),h.forEach(f=>f.removeFromParent())}i.rotation.set(n.baseEuler.x,n.baseEuler.y,n.baseEuler.z),i.updateMatrixWorld(!0);const l=new nn().setFromObject(i),s=l.getSize(new q),d=l.getCenter(new q),u=n.fitSize/Math.max(s.x,s.y,s.z);i.scale.multiplyScalar(u),i.position.copy(d.multiplyScalar(-u));const p=new rn;p.add(i),e.scene.add(p),e.setAngle("front"),o(p)},void 0,r)})}function vn(e){return ot(e)}Y.colorways;class at{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=we(r);const{frame:a,back:i,accent:l}=this.profile.body;t.traverse(s=>{const d=s;if(!d.isMesh)return;(Array.isArray(d.material)?d.material:[d.material]).forEach(p=>{const h=p;!h||!h.name||(a.includes(h.name)?this.push(this.frame,h):i.includes(h.name)?this.push(this.back,h):l.includes(h.name)&&this.push(this.accent,h),this.push(this.allBody,h))})})}push(t,n){t.includes(n)||t.push(n)}get finishMaterials(){return[...this.frame,...this.back]}paint(t,n){const o=n instanceof k?n:new k(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 k(t),o=n.clone().lerp(new k(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;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 Xt;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 on(this.renderer);this.envTexture=t.fromScene(new Jt,.04).texture,t.dispose()}return this.envTexture}setClay(t){const n=un.find(r=>r.id===t),o=n?new k(n.color):new k(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 Ee=1.35;class it{materials=[];glassOverlays=[];screenMesh=null;flatPlane=null;texture=null;flatScreenOn=!1;profile;constructor(t,n){this.profile=we(n);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(l=>{const s=l;s&&s.name===o&&!this.materials.includes(s)&&(this.materials.push(s),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 y=this.flatPlane.material;y.map?.dispose(),y.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,l=(n.max.y+n.min.y)/2,s=(n.max.z+n.min.z)/2,d=r<=o&&r<=a?"y":a<=o&&a<=r?"z":"x",u=this.texture.clone();u.needsUpdate=!0,u.colorSpace=Oe,u.flipY=!1,u.center.set(.5,.5),u.wrapS=V,u.wrapT=V;const{coverFill:p,coverCornerRatio:h,coverRepeat:f}=this.profile.screen;u.repeat.set(f.x,f.y);const c=d==="x"?a:o,g=d==="z"||d==="x"?r:a,m=Math.min(c,g)*p*h,b=In(c*p,g*p,m),S=new an(b,new Zt({map:u,emissive:new k(16777215),emissiveMap:u,emissiveIntensity:Ee,color:new k(0),toneMapped:!1,side:sn,depthTest:!0,depthWrite:!0,polygonOffset:!0,polygonOffsetFactor:-4,polygonOffsetUnits:-4}));d==="y"?(S.rotation.x=-Math.PI/2,S.position.set(i,n.max.y,s)):d==="x"?(S.rotation.y=Math.PI/2,S.position.set(n.max.x,l,s)):S.position.set(i,l,n.max.z),S.renderOrder=999,this.screenMesh.add(S),this.flatPlane=S}restoreScreen(){this.prepareScreen()}prepareScreen(){this.materials.forEach(t=>{t.color=new k(0),t.emissive=new k(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){const n=new Blob([t],{type:"image/png"}),o=URL.createObjectURL(n),r=this.texture;return new Promise((a,i)=>{const l=new Image;l.onload=()=>{try{const s=document.createElement("canvas");s.width=l.naturalWidth,s.height=l.naturalHeight;const d=s.getContext("2d");if(!d)throw new Error("2D context unavailable for wallpaper blit");d.drawImage(l,0,0);const u=new Qt(s);u.colorSpace=Oe,u.flipY=!1,u.center.set(.5,.5),u.wrapS=V,u.wrapT=V,u.repeat.set(this.profile.screen.repeat.x,this.profile.screen.repeat.y),u.needsUpdate=!0,this.texture=u,this.materials.forEach(p=>{p.map=u,p.emissiveMap=u,p.emissive=new k(16777215),p.emissiveIntensity=Ee,p.color=new k(0),p.needsUpdate=!0}),this.flatScreenOn&&this.setFlatScreen(!0),r?.dispose(),URL.revokeObjectURL(o),a()}catch(s){URL.revokeObjectURL(o),i(s)}},l.onerror=()=>{URL.revokeObjectURL(o),i(new Error("wallpaper image failed to decode"))},l.src=o})}}function In(e,t,n){const o=e/2,r=t/2,a=Math.min(n,o,r),i=new en;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 l=new tn(i,16),s=l.attributes.position,d=new Float32Array(s.count*2);for(let u=0;u<s.count;u++)d[u*2]=(s.getX(u)+o)/e,d[u*2+1]=(s.getY(u)+r)/t;return l.setAttribute("uv",new ln(d,2)),l}const Me={sizePt:{min:20,max:120},maxWidth:{min:.1,max:1},lineHeight:{min:.5,max:3},bandInset:{min:0,max:.5},bandCenter:{min:0,max:1},reserveLines:{min:1,max:8}},X=[{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"}],Le=X.map(e=>e.id);[Le[0],...Le.slice(1)];const J=600;function st(e){return X.find(t=>t.id===e)??X[0]}const lt=[{id:"standard",label:"Standard",blurb:"Headline on top, whole device below it, nothing cropped. The safe default.",character:"safe",shotLook:{phoneHeight:"82",hOffset:"0",vOffset:"18",angle:"front",cameraPos:null,roll:"0"},caption:{sizePt:32,maxWidth:.86,reserveLines:2}},{id:"bleed",label:"Bleed",blurb:"Room for a longer headline, device running off the bottom edge. What the market looks like.",character:"conventional",shotLook:{phoneHeight:"82",hOffset:"0",vOffset:"38",angle:"front",cameraPos:null,roll:"0"},caption:{sizePt:32,maxWidth:.86,reserveLines:4}},{id:"top-bleed",label:"Top bleed",blurb:"Device running off the TOP edge, headline underneath it. Inverts the usual reading order.",character:"expressive",shotLook:{phoneHeight:"82",hOffset:"0",vOffset:"-38",angle:"front",cameraPos:null,roll:"0"},caption:{sizePt:32,maxWidth:.86,reserveLines:4,band:"bottom"}}],ct=lt,Fe=ct.map(e=>e.id);[Fe[0],...Fe.slice(1)];Array.from(new Set(lt.flatMap(e=>Object.keys(e.caption))));const dt=[{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"}}],Re=dt.map(e=>e.id);[Re[0],...Re.slice(1)];const x={angle:"front",cameraPos:null,roll:"0",phoneHeight:"82",hOffset:"0",vOffset:"18",material:"real",colorway:"silver",customColor:"F5F5F5",finish:"0",clearcoat:"0",clayTone:"grey",clayCustom:"B0B0B0",flatScreen:!1,glare:!1,lighting:!0,reflections:!1},_e={angle:{valueKind:"angle",required:!0,defaultSource:"default-look",defaultValue:x.angle,persistence:"always"},cameraPos:{valueKind:"camera-position",required:!0,defaultSource:"default-look",defaultValue:x.cameraPos,persistence:"always"},roll:{valueKind:"numeric-string",required:!0,defaultSource:"default-look",defaultValue:x.roll,persistence:"always"},phoneHeight:{valueKind:"numeric-string",required:!0,defaultSource:"default-look",defaultValue:x.phoneHeight,persistence:"always"},hOffset:{valueKind:"numeric-string",required:!0,defaultSource:"default-look",defaultValue:x.hOffset,persistence:"always"},vOffset:{valueKind:"numeric-string",required:!0,defaultSource:"default-look",defaultValue:x.vOffset,persistence:"always"},material:{valueKind:"material",required:!0,defaultSource:"default-look",defaultValue:x.material,persistence:"always"},colorway:{valueKind:"colorway",required:!0,defaultSource:"default-look",defaultValue:x.colorway,persistence:"always"},customColor:{valueKind:"string",required:!0,defaultSource:"default-look",defaultValue:x.customColor,persistence:"always"},finish:{valueKind:"numeric-string",required:!0,defaultSource:"default-look",defaultValue:x.finish,persistence:"always"},clearcoat:{valueKind:"numeric-string",required:!0,defaultSource:"default-look",defaultValue:x.clearcoat,persistence:"always"},clayTone:{valueKind:"clay-tone",required:!0,defaultSource:"default-look",defaultValue:x.clayTone,persistence:"always"},clayCustom:{valueKind:"string",required:!0,defaultSource:"default-look",defaultValue:x.clayCustom,persistence:"always"},flatScreen:{valueKind:"boolean",required:!0,defaultSource:"default-look",defaultValue:x.flatScreen,persistence:"always"},clipToFrame:{valueKind:"boolean",required:!1,defaultSource:"explicit",defaultValue:!1,persistence:"omit-default"},glare:{valueKind:"boolean",required:!0,defaultSource:"default-look",defaultValue:x.glare,persistence:"always"},lighting:{valueKind:"boolean",required:!0,defaultSource:"default-look",defaultValue:x.lighting,persistence:"always"},reflections:{valueKind:"boolean",required:!0,defaultSource:"default-look",defaultValue:x.reflections,persistence:"always"}},xn={roll:{min:-45,max:45},phoneHeight:{min:20,max:200},hOffset:{min:-100,max:100},vOffset:{min:-200,max:200},finish:{min:0,max:1},clearcoat:{min:0,max:1}},H={x:.5,y:.06},ve={fontId:"inter",sizePt:32,color:"FFFFFF",align:"center",anchor:H,maxWidth:.86},Ne=[{id:"r69",label:"6.9″ iPhone · 1290×2796",width:1290,height:2796},{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 · 1290×2796",width:1290,height:2796},{id:"ipad13",label:"13″ iPad · 2064×2752",width:2064,height:2752},{id:"ipad129",label:"12.9″ iPad · 2048×2732",width:2048,height:2732}];function G(e){return Ne.find(t=>t.id===e)??Ne[0]}const te=932,pe="iphone-17-pro",Pn="pixel-10-pro",Ie=[{id:"iphone-6-9",label:"iPhone 17 Pro",panelPresetId:"r69",ascDeviceSet:"APP_IPHONE_67",modelId:pe,screenFamily:"iphone"},{id:"iphone-6-5",label:"iPhone 17",panelPresetId:"r65",ascDeviceSet:"APP_IPHONE_65",modelId:pe,screenFamily:"iphone"},{id:"pixel-10-pro",label:"Pixel 10 Pro",panelPresetId:"pixel69",ascDeviceSet:"ANDROID_PHONE",modelId:Pn,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 An(e){return Ie.find(t=>t.panelPresetId===e)?.modelId??pe}const ut="iphone-6-9";function ft(e){return Ie.find(t=>t.id===e)}function On(){return Ie.filter(e=>!e.comingSoon)}function ht(e,t){if(Array.isArray(e)){const n=new Set,o=[];for(const r of e){const a=ft(r);a&&!a.comingSoon&&!n.has(r)&&(n.add(r),o.push(r))}if(o.length>0)return o}if(t){const n=On().find(o=>o.panelPresetId===t);if(n)return[n.id]}return[ut]}const pt=ft(ut)?.screenFamily??"iphone";function mt(e){const t={...e},n=t,o=Object.keys(_e);for(const r of o){const a=_e[r];a.persistence==="omit-default"&&(n[r]===void 0||n[r]===a.defaultValue)&&delete n[r]}return t}function gt(e){return mt({...x,...e})}function yt(e){return mt(gt(e))}function R(e,t){const{min:n,max:o}=xn[e],r=typeof t=="number"?t:Number.parseFloat(t??""),a=Number.isFinite(r)?r:Number.parseFloat(x[e]);return Math.max(n,Math.min(o,a))}const Tn=90,bt=180,kn="#1b1b2e",Cn="#0a0a14";function En(e){return e==="horizontal"?Tn:bt}function Mn(e){const t=(e%180+180)%180;return t>=45&&t<135?"horizontal":"vertical"}function St(e,t,n){return{stops:[{color:e,at:0},{color:t,at:1}],angle:En(n)}}const wt=e=>e*Math.PI/180;function Ln(e){const t=wt(e);return{dx:Math.sin(t),dy:-Math.cos(t)}}function Fn(e,t,n){const o=wt(n);return Math.abs(e*Math.sin(o))+Math.abs(t*Math.cos(o))}function Rn(e,t,n){const{dx:o,dy:r}=Ln(n),a=Fn(e,t,n)/2,i=e/2,l=t/2;return{x0:i-a*o,y0:l-a*r,x1:i+a*o,y1:l+a*r}}function Z(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:Mn(e.angle)}}function ne(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)?_n(t):bt;return{stops:n,angle:o}}function Q(e){return ne(e.gradientStops,e.gradientAngle)??St(e.gradientFrom,e.gradientTo,e.gradientDir)}function _n(e){return(e%360+360)%360}function Nn(e){return ne(e.stops,e.angle)??St(e.from,e.to,e.dir)}function vt(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=ne(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}function B(e){return!e||e.x===H.x&&e.y===H.y}function Bn(e){const{text:t,anchor:n,...o}=e;return B(n)?{...o}:{...o,anchor:n}}const Dn=.55,M="en-US";function zn(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 It(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 l=Array.from(new Set(i.filter(s=>typeof s=="string"))).filter(s=>{const d=zn(s);return!!d&&!!o[n]?.[d.panelId]?.[d.index]&&!!o[a]?.[d.panelId]?.[d.index]});l.length>0&&(r[a]=l)}return r}function xt(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]=D(o));return t}function jn(e){if(!e||typeof e!="object")return;const t=e,n=typeof t.x=="number"?t.x:H.x,o=typeof t.y=="number"?t.y:H.y;return B({x:n,y:o})?void 0:{x:n,y:o}}function D(e){const t=e&&typeof e=="object"?e:{},n=jn(t.anchor),o={...ve,...t};n?o.anchor=n:delete o.anchor,typeof o.reserveLines!="number"||!Number.isFinite(o.reserveLines)||o.reserveLines<Me.reserveLines.min?delete o.reserveLines:o.reserveLines=Math.floor(o.reserveLines),o.band!=="bottom"&&delete o.band;for(const r of["bandInset","lineHeight","bandCenter"]){const{min:a,max:i}=Me[r],l=o[r];(typeof l!="number"||!Number.isFinite(l)||l<a||l>i)&&delete o[r]}return o}function Hn(e){const t=e&&typeof e=="object"?e:{};return{...D(t),text:typeof t.text=="string"?t.text:""}}function Pt(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(D)):o&&typeof o=="object"&&(t[n]=[D(o)]);return t}function Gn(e,t){const n=[{...D(t),text:e.headline}];return typeof e.subtitle=="string"&&e.subtitle.trim()&&n.push({...D({...t,sizePt:t.sizePt*Dn}),text:e.subtitle}),n}function re(e,t,n=M){if(!e||typeof e!="object"||Array.isArray(e))return{};const o=xt(t),r=d=>o[d]??ve,a=d=>{if(!d||typeof d!="object"||Array.isArray(d))return{};const u={};for(const[p,h]of Object.entries(d))Array.isArray(h)?h.length>0&&(u[p]=h.map(Hn)):h&&typeof h=="object"&&typeof h.headline=="string"&&(u[p]=Gn(h,r(p)));return u},i=Object.entries(e);if(i.some(([,d])=>!!d&&typeof d=="object"&&typeof d.headline=="string"))return{[n]:a(e)};const s={};for(const[d,u]of i)s[d]=a(u);return s}function At(e,t,n=M){return e[t??n]??e[n]??{}}function Ot(e,t=M){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[l,s]of Object.entries(i))n[l]===void 0&&Array.isArray(s)&&s.length>0&&(n[l]=s.map(Bn))}return n}function me(e,t=M,n=pt){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 Be(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 ge(e){const t=[];return e.family!==void 0&&t.push("family"),e.locale!==void 0&&t.push("locale"),t}const Un={order:["family","locale"],reach:"strict"};function $n(e,t){const n=ge(e),o=t.order.filter(a=>n.includes(a));return Array.from({length:o.length+1},(a,i)=>o.slice(0,o.length-i)).map(a=>{const i={};return a.includes("family")&&(i.family=e.family),a.includes("locale")&&(i.locale=e.locale),i})}function Wn(e,t,n,o,r=M){const a=me(n,r);for(const i of $n(a,o)){const l=e(t,i);if(l!==void 0){const s=ge(i);return{value:l,resolvedAt:i,inherited:ge(a).filter(d=>!s.includes(d))}}}return{value:void 0,resolvedAt:null,inherited:[]}}function ye(e,t,n=M){const o=r=>{const a=new Set,i=[];for(const l of r)typeof l=="string"&&l&&!a.has(l)&&(a.add(l),i.push(l));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 xe(e,t=M){return typeof e=="string"&&e.length>0?e:t}const z={"it-IT":"it"};function De(e,t){if(!(Object.keys(e).some(r=>r in z)||(t?.some(r=>r in z)??!1)))return{captionText:e,locales:t};const o={};for(const[r,a]of Object.entries(e))r in z||(o[r]=a);for(const[r,a]of Object.entries(e)){const i=z[r];i&&(o[i]={...a,...o[i]??{}})}return{captionText:o,locales:t?.map(r=>z[r]??r)}}function Tt(e){if(!e||typeof e!="object"||Array.isArray(e))return{};const t={};for(const[n,o]of Object.entries(e)){if(n===pt||!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 l={};for(const[s,d]of Object.entries(i))Array.isArray(d)&&d.every(u=>typeof u=="string")&&(l[s]=d);Object.keys(l).length>0&&(r[a]=l)}Object.keys(r).length>0&&(t[n]=r)}return t}function U(e,t){return t.flatMap(n=>e.filter(o=>o.panelId===n.id))}let ze=0,je=0;function Vn(e,t){const n=(o,r)=>o.reduce((a,i)=>{const l=i.startsWith(r)?Number.parseInt(i.slice(r.length),10):NaN;return Number.isFinite(l)&&l>a?l:a},0);ze=Math.max(ze,n(e,"shot-")),je=Math.max(je,n(t,"panel-"))}const Kn=.49;function qn(e,t,n){return e.map(o=>{const r=n*o.heightFrac,a=o.height>0?o.width*(r/o.height):r*Kn,l=o.panelIndex*t+t/2-a/2+o.hOffset*(t/2),d=(n-r)/2+o.vOffset*(n/2);return{shotId:o.shotId,bytes:o.bytes,x:Math.round(l),y:Math.round(d),width:Math.round(a),height:Math.round(r),panelIndex:o.panelIndex,...o.clipToFrame===!0?{clipToFrame:!0}:{}}})}function Yn(e,t){const n=t.panelBackgrounds??{},o=Q(t),r=o.stops[0]?.color??t.gradientFrom;if(!e.some(s=>n[s.id]))return t.bgMode==="gradient"?{kind:"gradient",gradient:o}:{kind:"perPanel",colors:e.map(s=>t.panelColors[s.id]??r)};const i=s=>t.bgMode==="gradient"?{kind:"gradient",gradient:o}:{kind:"solid",color:t.panelColors[s]??r};return{kind:"perPanelFills",fills:e.map(s=>{const d=n[s.id];return d?d.kind==="solid"?{kind:"solid",color:d.color}:{kind:"gradient",gradient:Nn(d)}:i(s.id)})}}function kt(e,t,n=M){const o=Q(e);return{panelPresetId:e.panelPresetId,bgMode:e.bgMode,gradientStops:o.stops,gradientAngle:o.angle,...Z(o),panelColors:e.panelColors,shadow:e.shadow,floorReflection:e.floorReflection??!1,panelBackgrounds:e.panelBackgrounds??{},captionStyles:{...Pt(e.captionStyles),...Ot(t,n)}}}function Xn(e){const t=e.caption.reserveLines,n=typeof t=="number"?` Reserves ${t} headline lines (~${t*18} characters).`:"";return`${e.blurb}${n} Character: [${e.character}].`}function Jn(e,t){return Math.max(0,...Object.values(e).map(n=>n[t]?.length??0))}function Ct(e,t,n){const o=e&&typeof e=="object"&&!Array.isArray(e)?e:{},r=new Set,a={};let i=1;const l=()=>{for(;r.has(`caption-${i}`);)i+=1;const s=`caption-${i}`;return r.add(s),i+=1,s};for(const s of n){const d=Jn(t,s);if(d===0)continue;const u=Array.isArray(o[s])?o[s]:[];a[s]=Array.from({length:d},(p,h)=>{const f=u[h];return typeof f=="string"&&f.length>0&&!r.has(f)?(r.add(f),f):l()})}return a}const Et=2;function Zn(e){if(!e||typeof e!="object"||Array.isArray(e))return!1;const t=e;return t.schema===Et&&Array.isArray(t.shots)&&Array.isArray(t.panels)&&t.panels.length>0}function Qn(e){let t;try{t=JSON.parse(e)}catch{return null}if(!Zn(t))return null;const n=t,o=new Set(n.panels.map(c=>c.id)),r=n.shots.filter(c=>o.has(c.panelId)).map(c=>({id:c.id,panelId:c.panelId,frameNodeId:c.frameNodeId,frameName:c.frameName,bytes:null,look:gt(c.look),thumb:null,thumbStale:!0,inputAnchor:c.inputAnchor,outputAnchor:c.outputAnchor})),a=n.panels.map(c=>({id:c.id}));Vn(r.map(c=>c.id),a.map(c=>c.id));const i=n.selectedShotId&&r.some(c=>c.id===n.selectedShotId)?n.selectedShotId:r[0]?.id??null,l=xe(n.baseLocale),{captionText:s,locales:d}=De(re(n.captionText,n.captionStyles,l),n.locales),u=De({[l]:{}},[l]).locales?.[0]??l,p=ye(s,d,u),h=Ct(n.captionSlotIds,s,a.map(c=>c.id)),f=ne(n.gradientStops,n.gradientAngle);return{shots:U(r,a),panels:a,selectedShotId:i,panelPresetId:G(n.panelPresetId).id,bgMode:n.bgMode==="perPanel"?"perPanel":"gradient",...f?{gradientStops:f.stops,gradientAngle:f.angle,...Z(f)}:{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:vt(n.panelBackgrounds),captionText:s,locales:p,baseLocale:u,staleCaptionTranslations:It(n.staleCaptionTranslations,p,u,s),outputs:ht(n.outputs,n.panelPresetId),localeScreens:{},outputCaptions:Tt(n.outputCaptions),captionSlotIds:h,frameTemplates:n.frameTemplates&&typeof n.frameTemplates=="object"&&!Array.isArray(n.frameTemplates)?n.frameTemplates:{}}}function Mt(e){const n=U(e.shots,e.panels).map(a=>({id:a.id,panelId:a.panelId,frameNodeId:a.frameNodeId,frameName:a.frameName,look:yt(a.look),inputAnchor:a.inputAnchor,outputAnchor:a.outputAnchor})),o=xe(e.baseLocale),r=re(e.captionText,e.captionStyles,o);return{schema:Et,shots:n,panels:e.panels,selectedShotId:e.selectedShotId,captionText:r,locales:ye(r,e.locales,o),baseLocale:o,staleCaptionTranslations:It(e.staleCaptionTranslations,ye(r,e.locales,o),o,r),outputs:ht(e.outputs,e.panelPresetId),outputCaptions:Tt(e.outputCaptions),...(()=>{const a=Ct(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}:{},...kt(e,r,o)}}const er=1;function tr(e){const t=U(e.shots,e.panels),n=re(e.captionText,e.captionStyles),o=xe(e.baseLocale);return{schema:er,shots:t.map(r=>({panelId:r.panelId,look:yt(r.look)})),...kt(e,n,o)}}dt.map(e=>({id:e.id,label:e.label,description:e.blurb}));ct.map(e=>({id:e.id,label:e.label,description:Xn(e),character:e.character}));const Lt=[{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"}];Lt.map(e=>e.code);Object.fromEntries(Lt.map(e=>[e.code,e]));({...ve});function nr(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(R("finish",t.finish)),e.setClearcoat(R("clearcoat",t.clearcoat)))}function rr(e,t,n){e.screen.setGlare(!n&&t?e.device.environmentMap():null)}async function or(e,t,n,o){const{stage:r,device:a,screen:i}=e,l=t.material==="clay";if(t.cameraPos?r.setCameraPosition(t.cameraPos):r.setAngle(t.angle),a.setRoll(R("roll",t.roll)),nr(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}rr(e,t.glare,l)}function Ft(){const e=new Qe({antialias:!0,preserveDrawingBuffer:!0,alpha:!0});return e.setPixelRatio(1),e.shadowMap.enabled=!0,e}async function ar(e,t,n,o={}){const r=!o.renderer,a=o.renderer??Ft();a.setSize(t,n,!1);let i;o.cameraPosition?(i=new et(nt,t/n,.01,100),i.position.copy(o.cameraPosition),i.lookAt(0,0,0)):(i=e.camera.clone(),i.aspect=t/n,i.updateProjectionMatrix());try{const l=e.scene.background;e.scene.background=null;try{a.render(e.scene,i)}finally{e.scene.background=l}const s=document.createElement("canvas");let d=null;try{s.width=t,s.height=n,s.getContext("2d")?.drawImage(a.domElement,0,0);const u=ir(s);d=u;const p=u.width,h=u.height;return{bytes:await new Promise((c,g)=>{u.toBlob(m=>{if(!m){g(new Error("toBlob returned null"));return}m.arrayBuffer().then(b=>c(new Uint8Array(b)),g)},"image/png")}),width:p,height:h}}finally{d&&d!==s&&(d.width=0,d.height=0),s.width=0,s.height=0}}finally{r&&a.dispose()}}function ir(e,t=2){const n=e.getContext("2d",{willReadFrequently:!0});if(!n)return e;const{width:o,height:r}=e,a=n.getImageData(0,0,o,r).data;let i=o,l=r,s=-1,d=-1;for(let f=0;f<r;f++)for(let c=0;c<o;c++)a[(f*o+c)*4+3]!==0&&(c<i&&(i=c),c>s&&(s=c),f<l&&(l=f),f>d&&(d=f));if(s<i||d<l)return e;i=Math.max(0,i-t),l=Math.max(0,l-t),s=Math.min(o-1,s+t),d=Math.min(r-1,d+t);const u=s-i+1,p=d-l+1,h=document.createElement("canvas");return h.width=u,h.height=p,h.getContext("2d")?.drawImage(e,i,l,u,p,0,0,u,p),h}const sr=1900,lr=2800;function cr(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}}async function dr(e,t,n,o,r,a){const i=U(n,o),l=i.filter(c=>c.bytes);if(l.length===0)return null;const s=G(r.panelPresetId),d=new Map(o.map((c,g)=>[c.id,g])),u=r.renderScale!=null&&r.renderScale>0&&r.renderScale<=1?r.renderScale:1,p=Math.max(1,Math.round(sr*u)),h=Math.max(1,Math.round(lr*u)),f=Ft();try{const c=[];for(let S=0;S<l.length;S++){const y=l[S];a(`Rendering ${S+1}/${l.length}${r.locale?` (${r.locale})`:""}…`),await or(t,y.look,y.bytes,()=>!0);const P=await ar(e,p,h,{renderer:f,cameraPosition:bn(y.look.angle,y.look.cameraPos)});c.push({shotId:y.id,bytes:P.bytes,width:P.width,height:P.height,heightFrac:R("phoneHeight",y.look.phoneHeight)/100,hOffset:R("hOffset",y.look.hOffset)/100,vOffset:R("vOffset",y.look.vOffset)/100,panelIndex:d.get(y.panelId)??0,...y.look.clipToFrame===!0?{clipToFrame:!0}:{}})}const g=qn(c,s.width,s.height),m=Yn(o,r);a("Saving project…");const b=Mt(cr(i,o,r));return{panelWidth:s.width,panelHeight:s.height,count:o.length,background:m,phones:g,shadow:r.shadow,floorReflection:r.floorReflection??!1,project:JSON.stringify(b)}}finally{f.dispose(),f.forceContextLoss()}}function ee(e){return/^[0-9a-fA-F]{3,8}$/.test(e)?`#${e}`:e}function be(e,t,n,o){const{x0:r,y0:a,x1:i,y1:l}=Rn(n,o,t.angle),s=e.createLinearGradient(r,a,i,l);for(const d of t.stops)s.addColorStop(Math.min(1,Math.max(0,d.at)),ee(d.color));return s}function He(e,t,n,o,r,a,i){const l=document.createElement("canvas");l.width=n,l.height=o;try{const s=l.getContext("2d");if(!s)return;s.fillStyle=be(s,t,n,o),s.fillRect(r,0,a,o),e.drawImage(l,r,0,a,o,i,0,a,o)}finally{l.width=0,l.height=0}}function Ge(e){return URL.createObjectURL(new Blob([e],{type:"image/png"}))}function Ue(e){return new Promise((t,n)=>{const o=new Image;o.onload=()=>t(o),o.onerror=n,o.src=e})}const ur=16*1024*1024;function $e(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 Rt(){let e=0;const t=Array.from(F.values());for(const r of t)e+=$e(r);const n=Array.from(F.keys());let o=0;for(;e>ur&&o<n.length-1;){const r=F.get(n[o]);r&&(e-=$e(r),r.reflection&&(r.reflection.canvas.width=0,r.reflection.canvas.height=0),F.delete(n[o])),o++}}const F=new Map,ie=new Map;async function fr(e,t){if(!t){const a=Ge(e);try{return{img:await Ue(a)}}finally{URL.revokeObjectURL(a)}}const n=F.get(e);if(n)return F.delete(e),F.set(e,n),n;const o=ie.get(e);if(o)return o;const r=(async()=>{const a=Ge(e);try{return{img:await Ue(a)}}finally{URL.revokeObjectURL(a)}})();ie.set(e,r);try{const a=await r;return F.set(e,a),Rt(),a}finally{ie.delete(e)}}async function hr(e,t,n){const o=t.panelWidth*t.count,r=t.panelHeight,a=n?.backgroundViewport,i=a?t.panelWidth*a.panelCount:o,l=a?t.panelWidth*a.panelIndex:0;e.width=o,e.height=r;const s=e.getContext("2d");if(!s)return;n?.transparentBg?s.clearRect(0,0,o,r):t.background.kind==="gradient"?a?He(s,t.background.gradient,i,r,l,o,0):(s.fillStyle=be(s,t.background.gradient,o,r),s.fillRect(0,0,o,r)):t.background.kind==="perPanel"?t.background.colors.forEach((h,f)=>{s.fillStyle=ee(h),s.fillRect(f*t.panelWidth,0,t.panelWidth,r)}):t.background.fills.forEach((h,f)=>{const c=f*t.panelWidth;h.kind==="solid"?(s.fillStyle=ee(h.color),s.fillRect(c,0,t.panelWidth,r)):a?He(s,h.gradient,i,r,l+c,t.panelWidth,c):(s.fillStyle=be(s,h.gradient,o,r),s.fillRect(c,0,t.panelWidth,r))});const d=n?.phoneRange?Math.max(0,n.phoneRange.start):0,u=n?.phoneRange?Math.min(t.phones.length,n.phoneRange.end):t.phones.length,p=n?.reuseDecodedPhones===!0;for(let h=d;h<u;h++){const f=t.phones[h],c=n?.clip==="panel"||n?.clip===void 0&&f.clipToFrame===!0;if(n?.skipShotId&&f.shotId===n.skipShotId)continue;const g=await fr(f.bytes,p),m=g.img;c&&(s.save(),s.beginPath(),s.rect(f.panelIndex*t.panelWidth,0,t.panelWidth,r),s.clip()),t.floorReflection&&pr(s,g,f,p),s.save(),t.shadow&&(s.shadowColor="rgba(0,0,0,0.35)",s.shadowBlur=t.panelWidth*.03,s.shadowOffsetY=t.panelHeight*.012),s.drawImage(m,f.x,f.y,f.width,f.height),s.restore(),c&&s.restore()}}function pr(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,l=document.createElement("canvas");l.width=Math.max(1,n.width),l.height=Math.max(1,r);const s=l.getContext("2d");if(!s)return;s.save(),s.translate(0,r),s.scale(1,-1),s.drawImage(i,0,r-n.height,n.width,n.height),s.restore();const d=s.createLinearGradient(0,0,0,r);d.addColorStop(0,"rgba(0,0,0,0.34)"),d.addColorStop(1,"rgba(0,0,0,0)"),s.globalCompositeOperation="destination-in",s.fillStyle=d,s.fillRect(0,0,n.width,r),e.drawImage(l,n.x,n.y+n.height,n.width,r),o&&(t.reflection={width:n.width,height:n.height,canvas:l},Rt())}const _t=1.2,mr=.06,gr=.5;function yr(e,t,n){if(!e)return[t];const o=t.split(/\s+/).filter(Boolean),r=[];let a="";for(const i of o){const l=a?`${a} ${i}`:i;a&&e.measureText(l).width>n?(r.push(a),a=i):a=l}return a&&r.push(a),r}function br(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 Nt(e,t,n,o){const r=t.map((c,g)=>{const m=c.text.trim();if(!m)return null;const b=c.sizePt*(o/te),S=st(c.fontId).family;e&&(e.font=`${J} ${b}px "${S}"`);const y=yr(e,m,c.maxWidth*n),P=b*(c.lineHeight??_t),A=y.length*P,v=Math.max(A,(c.reserveLines??y.length)*P);return{layer:c,index:g,lines:y,px:b,lineH:P,width:br(e,y),blockH:A,reservedH:v}}),a=r.filter(c=>c!==null&&B(c.layer.anchor)),i=a.filter(c=>c.layer.band==="bottom"),l=a.filter(c=>c.layer.band!=="bottom"),s=c=>c[0]?.layer.bandInset??mr,d=(1-s(i))*o-i.reduce((c,g)=>c+g.reservedH,0);let u=s(l)*o,p=d,h=0;const f=[];for(const c of r){if(!c)continue;if(!B(c.layer.anchor)){f.push({layer:c.layer,index:c.index,x:c.layer.anchor.x*n,yTop:c.layer.anchor.y*o,lines:c.lines,px:c.px,lineH:c.lineH,width:c.width});continue}const g=c.layer.band==="bottom",b=(g?p:u)+(c.reservedH-c.blockH)/2,S=(c.layer.bandCenter??gr)*n;f.push({layer:c.layer,index:c.index,x:S,yTop:b,lines:c.lines,px:c.px,lineH:c.lineH,width:c.width}),g?p+=c.reservedH:u+=c.reservedH,h=Math.max(h,b+c.blockH)}return{placed:f,bandBottom:h}}function Sr(e,t,n,o){e.save(),e.textBaseline="top";const{placed:r}=Nt(e,t,n,o);for(const a of r){e.fillStyle=ee(a.layer.color),e.textAlign=a.layer.align,e.font=`${J} ${a.px}px "${st(a.layer.fontId).family}"`;let i=a.yTop;for(const l of a.lines)e.fillText(l,a.x,i),i+=a.lineH}e.restore()}function wr(e,t){return e.sizePt*(t/te)*(e.lineHeight??_t)}function vr(e,t,n,o){return Nt(e,t,n,o).placed.map(r=>{const a=r.layer.align==="center"?r.x-r.width/2:r.layer.align==="right"?r.x-r.width:r.x;return{index:r.index,anchorX:r.x/n,top:r.yTop/o,left:a/n,width:r.width/n,height:r.lines.length*r.lineH/o}})}function Ir(e,t,n,o,r){t.forEach((a,i)=>{const l=r[a];!l||l.length===0||(e.save(),e.translate(i*n,0),Sr(e,l,n,o),e.restore())})}const xr=""+new URL("Inter-SemiBold-B9yU462S.woff2",import.meta.url).href,Pr=""+new URL("Manrope-SemiBold-44nuYf5T.woff2",import.meta.url).href,Ar=""+new URL("Poppins-SemiBold-DJVo7c07.woff2",import.meta.url).href,Or=""+new URL("Fraunces-SemiBold-BtraKtER.woff2",import.meta.url).href,Tr=""+new URL("SpaceGrotesk-SemiBold-CyO2J5Y0.woff2",import.meta.url).href,kr={inter:xr,manrope:Pr,poppins:Ar,fraunces:Or,"space-grotesk":Tr},Cr=X.map(e=>({...e,url:kr[e.id]}));let K=null;function Er(){return K||(K=(async()=>{const e=new Set;document.fonts.forEach(t=>e.add(`${t.family}/${t.weight}`)),await Promise.all(Cr.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 K=null,e})),K}const Mr=22/te,Lr=1.1,We=4,Fr=.063,Rr=.167,Ve=Math.round(Mr*te),_r=.02,Nr=50;function j(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 Bt(e,t){return j(e,t)}function Ke(e,t){const n=Math.abs(e-t)%360;return n>180?360-n:n}function qe(e){return gn(e.cameraPos??tt(e.angle))}function Dt(e,t,n,o,r,a,i){if(t.length===0)return[];const l=[];for(const s of vr(e,t,r,a)){const d=t[s.index];if(!d)continue;const u=Bt({x:(o+s.left)*r,y:s.top*a,width:s.width*r,height:s.height*a},i);u&&l.push({ref:{panelId:n,panelIndex:o,layerIndex:s.index,band:B(d.anchor)},box:u,lineHeightPx:wr(d,a)})}return l}function Br(e,t,n,o){return n.height<=Se(e,t,o)}function Se(e,t,n){const o=e.y+e.height/2<=t.y+t.height/2;return n*(o?Rr:Fr)}function Dr(e,t,n){return n.height<=Se(e.box,t.box,e.lineHeightPx)+Se(t.box,e.box,t.lineHeightPx)}function zr(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 jr(e,a)}finally{t?.restore()}}function jr(e,t){const{ctx:n,panelIds:o,panelWidth:r,panelHeight:a,captionLayers:i}=e,l=o.flatMap((c,g)=>Dt(n,i[c]??[],c,g,r,a,t)),s=[];for(const c of e.phones){const m=e.clip==="panel"||e.clip===void 0&&c.clipToFrame===!0?{x:c.panelIndex*r,y:0,width:r,height:a}:t,b=Bt({x:c.x,y:c.y,width:c.width,height:c.height},m);b&&s.push({shotId:c.shotId,box:b,layoutHeight:c.height})}const d=[];for(let c=0;c<l.length;c++)for(let g=c+1;g<l.length;g++){const m=j(l[c].box,l[g].box);m&&d.push({a:l[c].ref,b:l[g].ref,overlap:m,depthFrac:a>0?m.height/a:0,inkUncertain:Dr(l[c],l[g],m)})}const u=[];for(const c of l)for(const g of s){const m=j(c.box,g.box);m&&u.push({caption:c.ref,shotId:g.shotId,overlap:m,depthFrac:a>0?m.height/a:0,inkUncertain:Br(c.box,g.box,m,c.lineHeightPx)})}const p=[];for(let c=0;c<s.length;c++)for(let g=c+1;g<s.length;g++){const m=s[c],b=s[g],S=j(m.box,b.box);if(!S)continue;const y=[],P=Math.max(m.layoutHeight,b.layoutHeight),A=Math.min(m.layoutHeight,b.layoutHeight);A>0&&P/A>=Lr&&y.push("scale");const v=e.looks?.[m.shotId],w=e.looks?.[b.shotId],I=!!v&&!!w;v&&w&&(Ke(qe(v),qe(w))>=We&&y.push("angle"),Ke(R("roll",v.roll),R("roll",w.roll))>=We&&y.push("roll"));const O=Math.min(m.box.width*m.box.height,b.box.width*b.box.height);p.push({shotIdA:m.shotId,shotIdB:b.shotId,overlap:S,coverage:O>0?S.width*S.height/O:0,deliberate:y.length>0,signals:y,anglesKnown:I})}const h=new Set;for(const c of d)c.a.band&&h.add(c.a.panelId),c.b.band&&h.add(c.b.panelId);for(const c of u)c.caption.band&&h.add(c.caption.panelId);const f=[];return o.forEach((c,g)=>{if(!h.has(c))return;const m=Hr(e,c,g,t,l,s);m&&f.push(m)}),{captionsMeasurable:n!=null,captionOverlaps:d,captionDeviceOverlaps:u,deviceOverlaps:p,suggestions:f,hasWarning:d.length>0||u.length>0||p.some(c=>!c.deliberate)}}function Hr(e,t,n,o,r,a){const i=e.captionLayers[t]??[],l=i.flatMap((u,p)=>B(u.anchor)&&u.text.trim()?[p]:[]);if(l.length===0||!(Math.min(...l.map(u=>i[u].sizePt))>Ve))return null;const d=[...a.map(u=>u.box),...r.filter(u=>!(u.ref.panelId===t&&u.ref.band)).map(u=>u.box)];for(let u=1;u<=Nr;u++){const p=1-u*_r,h=new Map(l.map(m=>[m,Math.floor(i[m].sizePt*p)]));if(Math.min(...h.values())<Ve)return null;const f=i.map((m,b)=>{const S=h.get(b);return S===void 0?m:{...m,sizePt:S}});if(Dt(e.ctx,f,t,n,e.panelWidth,e.panelHeight,o).filter(m=>m.ref.band).every(m=>!d.some(b=>j(m.box,b))))return{panelId:t,scale:p,layers:l.map(m=>({layerIndex:m,fromSizePt:i[m].sizePt,toSizePt:h.get(m)}))}}return null}function zt(e){return`build-shot-${e+1}`}function jt(e){const t=[];for(const n of e.shots)t.includes(n.panelId)||t.push(n.panelId);return t}const Gr=1900,Ur=2800;function $r(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 Ht(e,t,n,o={}){await Er();const r=jt(e),a=r.map(h=>({id:h})),i=e.shots.map((h,f)=>({id:zt(f),panelId:h.panelId,frameNodeId:"",frameName:`screen-${f+1}`,bytes:t.screens[f]??null,look:h.look,thumb:null,thumbStale:!1})),s={panelPresetId:G(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},d=o.onProgress??(()=>{});let u=o.refs,p=null;if(!u){const h=An(e.panelPresetId);p=rt(Gr,Ur);const f=await ot(p,h);u={stage:p,device:new at(f,p.scene,p.renderer,h),screen:new it(f,h)}}try{const h=await dr(u.stage,u,i,a,s,d);if(!h)throw new Error("buildStrip: nothing renderable (no shots)");const f=document.createElement("canvas");try{const c={...o.clip?{clip:o.clip}:{},...o.backgroundViewport?{backgroundViewport:o.backgroundViewport}:{}};await hr(f,h,Object.keys(c).length>0?c:void 0);const g=h.panelWidth,m=h.panelHeight,b=f.getContext("2d");if(!b)throw new Error("buildStrip: 2D context unavailable");Ir(b,r,g,m,t.captionText??{});const S=zr({phones:h.phones,panelIds:r,captionLayers:t.captionText??{},panelWidth:g,panelHeight:m,ctx:b,looks:Object.fromEntries(i.map(A=>[A.id,A.look])),clip:o.clip}),y=o.renderScale&&o.renderScale>0&&o.renderScale<1?o.renderScale:1,P=[];for(let A=0;A<h.count;A++){const v=document.createElement("canvas");v.width=Math.max(1,Math.round(g*y)),v.height=Math.max(1,Math.round(m*y));const w=v.width,I=v.height;try{const O=v.getContext("2d");if(!O)throw new Error("buildStrip: 2D context unavailable");O.drawImage(f,A*g,0,g,m,0,0,w,I),P.push({index:A,bytes:await $r(v),width:w,height:I})}finally{v.width=0,v.height=0}}return{panels:P,layout:S}}finally{f.width=0,f.height=0}}finally{p&&p.dispose()}}const Ye=.005,Wr=.02,Vr=12;function se(e){return Math.max(1,Math.round(e*100))}function le(e){return`${e.kind}:${e.frames.join(",")}:${e.anchored}`}function Kr(e,t){const n=new Map(e.suggestions.map(a=>[a.panelId,a.scale])),o=[];for(const a of e.captionOverlaps){if(a.inkUncertain||a.depthFrac<Ye)continue;const[i,l]=a.a.band===a.b.band?[a.a,a.b]:a.a.band?[a.a,a.b]:[a.b,a.a],s=ce([t.frameOfPanel(i.panelId),t.frameOfPanel(l.panelId)]);s.length!==0&&o.push({kind:"caption-caption",frames:s,depthPct:se(a.depthFrac),anchored:!a.a.band||!a.b.band,...Xe(n,i.band?i.panelId:null)})}for(const a of e.captionDeviceOverlaps){if(a.inkUncertain||a.depthFrac<Ye)continue;const i=ce([t.frameOfPanel(a.caption.panelId),t.frameOfShot(a.shotId)]);i.length!==0&&o.push({kind:"caption-device",frames:i,depthPct:se(a.depthFrac),anchored:!a.caption.band,...Xe(n,a.caption.band?a.caption.panelId:null)})}for(const a of e.deviceOverlaps){if(a.deliberate||a.coverage<Wr)continue;const i=ce([t.frameOfShot(a.shotIdA),t.frameOfShot(a.shotIdB)]);i.length!==0&&o.push({kind:"device-device",frames:i,depthPct:se(a.coverage),anchored:!1})}const r=new Map;for(const a of o){const i=r.get(le(a));i?a.depthPct>i.depthPct?r.set(le(a),{...a,clearAtScale:a.clearAtScale??i.clearAtScale}):i.clearAtScale==null&&a.clearAtScale!=null&&(i.clearAtScale=a.clearAtScale):r.set(le(a),a)}return[...r.values()].sort((a,i)=>i.depthPct-a.depthPct).slice(0,Vr).sort((a,i)=>a.frames[0]-i.frames[0]||a.kind.localeCompare(i.kind))}function ce(e){const[t,...n]=e;return t<0?[]:[t,...n.filter(o=>o>=0&&o!==t)]}function Xe(e,t){const n=t==null?void 0:e.get(t);return n==null?{}:{clearAtScale:Math.round(n*100)/100}}function qr(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 l=a[i.layerIndex];l&&(l.sizePt=i.toSizePt)}}return{...e,captionStyles:o}}function de(e){return e.frames.map(t=>`frame ${t+1}`).join(" + ")}function Yr(e,t,n){if(!e.captionsMeasurable)return null;const o=Kr(e,t);if(o.length===0)return null;const r=o.filter(d=>d.kind==="device-device"),a=o.filter(d=>d.kind!=="device-device"&&d.clearAtScale==null);if(r.length>0||a.length>0||!n){const d=[];r.length>0&&d.push(`${r.map(de).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 u of a)d.push(u.anchored?`${de(u)}: 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.`:`${de(u)}: 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 d.length===0&&d.push("The rendered look was not available here, so no corrected look could be built."),{findings:o,note:`No corrected look is offered. ${d.join(" ")}`}}const i=new Set(o.filter(d=>d.kind!=="device-device").map(d=>d.frames[0])),l=e.suggestions.filter(d=>i.has(t.frameOfPanel(d.panelId))),s=l.flatMap(d=>{const u=t.frameOfPanel(d.panelId)+1;return d.layers.map(p=>`frame ${u} layer ${p.layerIndex+1}: sizePt ${p.fromSizePt} → ${p.toSizePt}`)}).join("; ");return{findings:o,correctedLook:qr(n,l),note:`\`layout.correctedLook\` is this same look with every caption shrunk to the largest size that was verified to clear the overlap (${s}). Nothing here is applied for you — re-render with it, or show the user the finding and let them decide. On render_strip pass it back as \`look\` together with the SAME \`style.captions\` you just sent: the words come from \`style.captions\` and every style field you leave out of them now comes from this look. The one thing that still beats it is a field you set EXPLICITLY on a caption entry, so if your \`style.captions\` pin \`sizePt\` at the original numbers, drop them or set them to the sizes above.`}}function Xr(e){return String(Math.max(-100,Math.min(100,e*35)))}const Jr=["roll","phoneHeight","hOffset","vOffset","finish","clearcoat"];function Je(e){if(!e||typeof e!="object")return{};const t={...e};for(const n of Jr)typeof t[n]=="number"&&(t[n]=String(t[n]));return t}function Zr(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 Ze(e){const t={};for(const[n,o]of Object.entries(e))o!==void 0&&(t[n]=o);return t}function ue(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 Qr(e){const t=e.slotSizes.filter(w=>Number.isInteger(w)&&w>0),n=t.map((w,I)=>`panel-${I+1}`);let o={};const r=e.look&&typeof e.look=="object"?e.look:null,a=e.style??null,i=r&&Array.isArray(r.shots)?r.shots:[],l=i.length>0,s=a?Je(a.shotLook):null,d=[];let u=0;t.forEach((w,I)=>{for(let O=0;O<w;O++){const T=l?Je(i[u]?.look??i[0]?.look??{}):s??{},$=T.hOffset!==void 0&&T.hOffset!==null?String(T.hOffset):Xr(O);d.push({panelId:n[I],look:{...x,...T,hOffset:$}}),u++}});let p={},h={},f={},c="gradient",g=kn,m=Cn,b="vertical",S,y,P=!0,A=!1;if(r){c=r.bgMode==="perPanel"?"perPanel":"gradient";const w=Q({gradientStops:Array.isArray(r.gradientStops)?r.gradientStops:void 0,gradientAngle:typeof r.gradientAngle=="number"?r.gradientAngle:void 0,gradientFrom:typeof r.gradientFrom=="string"?r.gradientFrom:g,gradientTo:typeof r.gradientTo=="string"?r.gradientTo:m,gradientDir:r.gradientDir==="horizontal"?"horizontal":b});S=w.stops,y=w.angle,{gradientFrom:g,gradientTo:m,gradientDir:b}=Z(w),r.shadow===!1&&(P=!1),r.floorReflection===!0&&(A=!0);const I=[];for(const O of i){const T=typeof O?.panelId=="string"?O.panelId:null;T&&!I.includes(T)&&I.push(T)}p=ue(r.panelColors,I,n),h=ue(Pt(r.captionStyles),I,n),f=ue(vt(r.panelBackgrounds),I,n)}else if(a){const w=a.background??{};c=w.mode==="perPanel"?"perPanel":"gradient";const I=Q({gradientStops:w.stops,gradientAngle:w.angle,gradientFrom:g,gradientTo:m,gradientDir:b});S=I.stops,y=I.angle,{gradientFrom:g,gradientTo:m,gradientDir:b}=Z(I),w.shadow===!1&&(P=!1),w.floorReflection===!0&&(A=!0),Array.isArray(w.panelColors)&&w.panelColors.forEach((O,T)=>{typeof O=="string"&&O&&n[T]!==void 0&&(p[n[T]]=O)})}if(a&&Array.isArray(a.captions)){const w=h,I=(L,oe)=>({...w[L]?.[oe]??{}}),O={},T={};a.captions.forEach((L,oe)=>{const _=n[oe];if(!(_===void 0||L===null||L===void 0)){if(Array.isArray(L)){const N=L.filter(E=>!!E&&typeof E=="object"&&typeof E.text=="string"&&E.text.trim()!=="").map((E,W)=>({...I(_,W),...Ze(Zr(E))}));N.length>0&&(T[_]=N)}else if(typeof L=="object"){const{text:N,subtitle:E,sizePt:W,maxWidth:Ae,...Vt}=L;O[_]={...I(_,0),...Ze({...Vt,...W!==void 0?{sizePt:Number(W)}:{},...Ae!==void 0?{maxWidth:Number(Ae)}:{}})},typeof N=="string"&&N.trim()&&(T[_]={headline:N,...typeof E=="string"&&E?{subtitle:E}:{}})}}});const $=re({[M]:T},xt(O));h=Ot($),o=At($)}return{look:{panelPresetId:e.panelPresetId??(typeof r?.panelPresetId=="string"?r.panelPresetId:void 0)??"r69",bgMode:c,gradientStops:S,gradientAngle:y,gradientFrom:g,gradientTo:m,gradientDir:b,panelColors:p,shadow:P,floorReflection:A,panelBackgrounds:f,captionStyles:h,shots:d},panelIds:n,captionText:o}}function eo(e){const t=e?.trim();return t?/\.(png|jpe?g|webp)$/i.test(t)?t:`${t}.png`:null}function to(e,t){const n=new Map;return e.map((o,r)=>{const a=eo(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 l=a.lastIndexOf(".");return`${a.slice(0,l)}-${i+1}${a.slice(l)}`})}function no(e){const{look:t,panelIds:n,captionText:o,locale:r,shotNames:a,outputs:i}=e,l=n.map(u=>({id:u})),s=to(t.shots,a),d=t.shots.map((u,p)=>({id:`shot-${p+1}`,panelId:u.panelId,frameNodeId:s[p],frameName:s[p],bytes:null,look:u.look,thumb:null,thumbStale:!0}));return Mt({shots:d,panels:l,selectedShotId:d[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,captionText:o&&Object.keys(o).length>0?{[r||M]:o}:{}})}function C(e){console.log("[render]",e)}const ro=1900,oo=2800;let fe=null;async function Gt(){return fe||(fe=(async()=>{C("booting headless stage + loading model (once)…");const e=rt(ro,oo),t=await vn(e);return{stage:e,device:new at(t,e.scene,e.renderer),screen:new it(t)}})()),fe}function Ut(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 Pe(e){let t="";for(let n=0;n<e.length;n++)t+=String.fromCharCode(e[n]);return btoa(t)}function ao(e){return new Promise((t,n)=>{e.toBlob(async o=>{if(!o)return n(new Error("toBlob null"));t(Pe(new Uint8Array(await o.arrayBuffer())))},"image/png")})}function $t(e,t){const n=jt(t),o=new Map(t.shots.map((a,i)=>[zt(i),n.indexOf(a.panelId)])),r=Yr(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 Wt(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 ao(n),width:n.width,height:n.height}}window.renderStrip=async function(t){try{if(!t||!Array.isArray(t.screenshots)||t.screenshots.length===0)throw new Error("renderStrip: input.screenshots must be a non-empty nested array of slots");const n=await Gt(),o=t.screenshots.map(y=>Array.isArray(y)?y:[y]),{look:r,panelIds:a,captionText:i}=Qr({slotSizes:o.map(y=>y.length),panelPresetId:t.panelPresetId,look:t.look??void 0,style:t.style??void 0}),l=o.flat().map(Ut),s=Array.isArray(t.captionLayers)&&a[0]?{[a[0]]:t.captionLayers}:i,d=t.preview?.25:1;C(`buildStrip (${o.length} panel${o.length===1?"":"s"}${t.locale?`, ${t.locale}`:""})…`);const u=performance.now(),p=await Ht(r,{screens:l,captionText:s},t.locale,{refs:n,renderScale:d,onProgress:y=>C(" "+y),...t.clip?{clip:t.clip}:{},...t.backgroundViewport?{backgroundViewport:t.backgroundViewport}:{}});C("encoding panels + stitching the strip preview…");const h=p.panels.map(y=>Pe(y.bytes)),f=await Wt(p.panels),c=G(r.panelPresetId),g=Math.round(performance.now()-u),m=$t(p,r),b=Array.isArray(t.screenshotNames)?t.screenshotNames.flat():void 0,S=t.buildRecord?no({look:r,panelIds:a,captionText:i,locale:t.locale,shotNames:b,outputs:t.outputs}):void 0;return C(`done: ${p.panels.length} panels, strip ${f.width}x${f.height}, ${g}ms`),{ok:!0,ms:g,count:p.panels.length,panelPresetId:c.id,panelWidth:c.width,panelHeight:c.height,stripWidth:f.width,stripHeight:f.height,panels:h,stripBase64:f.base64,preview:d<1,...S?{projectRecord:S}:{},...m??{}}}catch(n){const o=n&&n.stack?n.stack:String(n);return C("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=Qn(JSON.stringify(t.projectFile));if(!n)throw new Error("renderProject: the saved project could not be restored (wrong schema or malformed record)");const o=await Gt(),r=t.locale||n.baseLocale||n.locales?.[0]||"en-US",a=U(n.shots,n.panels),i=me(t.variant||{},n.baseLocale),l=new Map((t.screenManifest||[]).map(v=>[`${v.shotId} ${Be(me(v.variant||{},n.baseLocale))}`,v])),s=(v,w)=>l.get(`${v} ${Be(w)}`),d=a.map(v=>Wn(s,v.id,i,Un,n.baseLocale)),u=a.map((v,w)=>({frameName:v.frameName,matched:d[w].value!==void 0,requestedVariant:i,resolvedAt:d[w].resolvedAt,inherited:d[w].inherited,...d[w].value?.source?{source:d[w].value.source}:{}})),p=d.map(({value:v})=>v?.bytes?Ut(v.bytes):null),h=At(n.captionText,r,n.baseLocale),f=tr({...n,selectedShotId:null,panelPresetId:t.panelPresetId??n.panelPresetId,captionText:{[r]:h}}),c=t.preview?.25:1;C(`renderProject (${a.length} shot${a.length===1?"":"s"}, ${r})…`);const g=performance.now(),m=await Ht(f,{screens:p,captionText:h},r,{refs:o,renderScale:c,onProgress:v=>C(" "+v)});C("encoding panels + stitching the strip preview…");const b=m.panels.map(v=>Pe(v.bytes)),S=await Wt(m.panels),y=G(f.panelPresetId),P=Math.round(performance.now()-g),A=$t(m,f);return C(`done: ${m.panels.length} panels, strip ${S.width}x${S.height}, ${P}ms`),{ok:!0,ms:P,count:m.panels.length,panelPresetId:y.id,panelWidth:y.width,panelHeight:y.height,stripWidth:S.width,stripHeight:S.height,panels:b,stripBase64:S.base64,preview:c<1,shots:u,locale:r,...A??{}}}catch(n){const o=n&&n.stack?n.stack:String(n);return C("ERROR: "+o),{ok:!1,error:String(n&&n.message?n.message:n)}}};window.__RENDER_READY=!0;C("harness ready ✓");
@@ -3,7 +3,7 @@
3
3
  <head>
4
4
  <meta charset="utf-8" />
5
5
  <title>shotops-mcp headless render harness</title>
6
- <script type="module" crossorigin src="./assets/index-BfJOyBU7.js"></script>
6
+ <script type="module" crossorigin src="./assets/index-Wb7M1qGz.js"></script>
7
7
  <link rel="modulepreload" crossorigin href="./assets/three-webgl-DCw804Ic.js">
8
8
  <link rel="modulepreload" crossorigin href="./assets/three-addons-CvX38LO6.js">
9
9
  </head>
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "shotops-mcp",
3
- "version": "0.8.0",
3
+ "version": "0.9.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.",
@@ -1,4 +1,4 @@
1
- "use strict";(()=>{var T=`
1
+ "use strict";(()=>{var z="shotops/widgetPayload";var P=`
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 t(n,e,o){let r=document.createElement(n);return e&&(r.className=e),o!==void 0&&(r.textContent=o),r}function f(n,e,o){let r=t("div","sf-stat");r.append(t("div","sf-k",e),t("div","sf-v",o)),n.append(r)}async function E(n){if(window.openai?.openExternal){await window.openai.openExternal({href:n});return}window.open(n,"_blank","noopener,noreferrer")}function L(n,e,o,r){let a=e;try{let i=new URL(e);/\/storage\/v1\/object\/sign\//.test(i.pathname)&&(i.searchParams.set("download",o),a=i.toString())}catch{}let s=t("a",r,n);return s.href=a,s.download=o,s.rel="noopener noreferrer",/^https?:/i.test(e)&&(s.target="_blank",s.addEventListener("click",i=>{window.openai?.openExternal&&(i.preventDefault(),E(a))})),s}function y(n,e,o){let r=t("button",o,n);return r.type="button",r.addEventListener("click",()=>{E(e)}),r}function P(n){let e=document.createElement("style");e.textContent=n.css;let o=t("div","sf-root");o.id=n.rootId,o.append(t("div","sf-empty",n.loading)),document.body.append(e,o);let r=!1,a=p=>{!p||typeof p!="object"||(r=!0,n.render(o,p))};window.addEventListener("message",p=>{if(p.source!==window.parent)return;let d=p.data;!d||d.jsonrpc!=="2.0"||d.method!=="ui/notifications/tool-result"||a(d.params?.structuredContent)},{passive:!0});let s=100,i=500,g=2e3,b=5*6e4,m=0,c=()=>{if(a(window.openai?.toolOutput),r)return;if(m>=b){o.replaceChildren(t("div","sf-empty",n.empty));return}let p=m<g?s:i;m+=p,setTimeout(c,p)};c()}function $(n){return n<1024?`${n} B`:n<1024*1024?`${Math.round(n/1024)} KB`:`${(n/(1024*1024)).toFixed(1)} MB`}function k(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:$(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 A(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"}),r=Math.ceil((e.getTime()-Date.now())/864e5);return r<=0?`This link has expired (${o}). Emit the bundle again for a fresh one.`:`Anyone with the link can download it. Expires ${o} \u2014 ${r} day${r===1?"":"s"} from now.`}function B(n){let e=n.length>0?n:["en-US"],o=["fastlane/"],r=e.slice(0,3);return r.forEach(a=>{o.push(` screenshots/${a}/ the PNGs, named in strip order`)}),e.length>r.length&&o.push(` screenshots/\u2026 +${e.length-r.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 I(n){if(!n.operationId||!n.status)return null;let e=Math.max(0,Number(n.progress?.completed??0)),o=Math.max(e,Number(n.progress?.total??0)),r={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]},[a,s,i,g]=r[n.status];return{title:a,detail:s,badge:i,terminal:g,completed:e,total:o}}var _=`${T}
127
+ `;function r(e,n,o){let t=document.createElement(e);return n&&(t.className=n),o!==void 0&&(t.textContent=o),t}function g(e,n,o){let t=r("div","sf-stat");t.append(r("div","sf-k",n),r("div","sf-v",o)),e.append(t)}async function L(e){if(window.openai?.openExternal){await window.openai.openExternal({href:e});return}window.open(e,"_blank","noopener,noreferrer")}function R(e,n,o,t){let i=n;try{let p=new URL(n);/\/storage\/v1\/object\/sign\//.test(p.pathname)&&(p.searchParams.set("download",o),i=p.toString())}catch{}let s=r("a",t,e);return s.href=i,s.download=o,s.rel="noopener noreferrer",/^https?:/i.test(n)&&(s.target="_blank",s.addEventListener("click",p=>{window.openai?.openExternal&&(p.preventDefault(),L(i))})),s}function M(e,n,o){let t=r("button",o,e);return t.type="button",t.addEventListener("click",()=>{L(n)}),t}function d(e){return e&&typeof e=="object"&&!Array.isArray(e)?e:null}function D(e){if(!Array.isArray(e.content))return null;let n=[];for(let o of e.content){let t=d(o);if(!t)continue;if(t.type==="image"&&typeof t.data=="string"&&t.mimeType==="image/png"){n.push(t.data);continue}if(t.type==="resource_link"&&typeof t.uri=="string"&&t.mimeType==="image/png"){n.push({url:t.uri});continue}let i=d(t.resource);t.type==="resource"&&i&&typeof i.uri=="string"&&i.mimeType==="image/png"&&n.push({url:i.uri})}if(n.length>0)return{ok:!0,count:n.length,output:typeof n[0]=="string"?"inline":"urls",panels:n};if(e.isError===!0){let o=e.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 C(e,n=0){let o=d(e);if(!o||n>6)return null;let t=d(o[z]);if(t)return t;let i=d(o._meta),s=d(i?.[z]);if(s)return s;for(let p of["mcp_tool_result","call_tool_result","tool_result","result"]){let c=C(o[p],n+1);if(c)return c}return null}function _(e,n=!0,o=0){let t=d(e);if(!t||o>6)return n?e: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=_(t[s],!1,o+1);if(p)return p}let i=D(t);return i||(n?e:null)}function B(e,n=0){let o=d(e);if(!o||n>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=B(o[i],n+1);if(s)return s}return null}function j(e){let n=d(e.detail);return d(n?.globals)}function F(e){return C(e)??_(e,!1)}function U(e){if(!e||typeof e!="object")return e;let n=e;return n.structuredContent&&typeof n.structuredContent=="object"?n.structuredContent:_(e)}function I(e){let n=document.createElement("style");n.textContent=e.css;let o=r("div","sf-root");o.id=e.rootId,o.append(r("div","sf-empty",e.loading)),document.body.append(n,o);let t=!1,i=l=>{let a=U(l);!a||typeof a!="object"||e.accept&&!e.accept(a)||(t=!0,e.render(o,a))},s=l=>i(F(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=j(l);a&&(i(a.toolOutput),t||s(a.toolResponseMetadata))},{passive:!0});let p=100,c=500,v=2e3,k=5*6e4,x=2e3,u=0,m=null,h=!1,w=()=>{if(i(window.openai?.toolOutput),t||s(window.openai?.toolResponseMetadata),t)return;let l=B(window.openai?.toolResponseMetadata);if(l&&m===null&&(m=u),l&&!h&&(l==="failure"||u-(m??u)>=x)&&(h=!0,o.replaceChildren(r("div","sf-empty",e.terminal??e.empty))),u>=k){h||o.replaceChildren(r("div","sf-empty",e.terminal??e.empty));return}let a=u<v?p:c;u+=a,setTimeout(w,a)};w()}function W(e){return e<1024?`${e} B`:e<1024*1024?`${Math.round(e/1024)} KB`:`${(e/(1024*1024)).toFixed(1)} MB`}function S(e){if(typeof e.zipBase64=="string"&&e.zipBase64.length>0){let n=e.zipBase64.endsWith("==")?2:e.zipBase64.endsWith("=")?1:0;return{href:`data:application/zip;base64,${e.zipBase64}`,size:W(Math.max(0,e.zipBase64.length*3/4-n))}}return typeof e.zipUrl=="string"&&e.zipUrl.length>0?{href:e.zipUrl,size:null}:null}function $(e){if(!e)return"Anyone with the link can download it. Links last 14 days.";let n=new Date(e);if(Number.isNaN(n.getTime()))return"Anyone with the link can download it. Links last 14 days.";let o=n.toLocaleDateString(void 0,{day:"numeric",month:"short",year:"numeric"}),t=Math.ceil((n.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 N(e){let n=e.length>0?e:["en-US"],o=["fastlane/"],t=n.slice(0,3);return t.forEach(i=>{o.push(` screenshots/${i}/ the PNGs, named in strip order`)}),n.length>t.length&&o.push(` screenshots/\u2026 +${n.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(e){if(!e.operationId||!e.status)return null;let n=Math.max(0,Number(e.progress?.completed??0)),o=Math.max(n,Number(e.progress?.total??0)),t={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]},[i,s,p,c]=t[e.status];return{title:i,detail:s,badge:p,terminal:c,completed:n,total:o}}var H=`${P}
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
- `,C="You upload this yourself. ShotOps never holds your Apple credentials, never creates an App Store version, and never submits anything for review.";function N(n,e){return L("Download .zip",n.href,e,"sf-get")}function R(n,e){n.replaceChildren();let o=I(e);if(o&&!k(e)){let l=t("section","sf-shell"),h=t("header","sf-head"),M=t("div");M.append(t("p","sf-eyebrow","ShotOps / durable production"),t("h2","sf-title",o.title),t("p","sf-sub",o.detail));let O=t("span","sf-badge");O.append(t("span","sf-dot"),document.createTextNode(o.badge)),h.append(M,O),l.append(h);let x=t("footer","sf-meta");f(x,"Progress",o.total>0?`${o.completed}/${o.total}`:"Waiting"),typeof e.progress?.attempt=="number"&&f(x,"Attempt",String(e.progress.attempt)),typeof e.contract?.cost?.reserved=="number"&&f(x,"Reserved",String(e.contract.cost.reserved)),typeof e.contract?.cost?.released=="number"&&f(x,"Released",String(e.contract.cost.released)),l.append(x,t("p","sf-note",`Operation ${e.operationId}. Reconnect with production_operation.`)),n.append(l),window.openai?.notifyIntrinsicHeight?.();return}let r=Array.isArray(e.locales)&&e.locales.length>0?e.locales:e.locale?[e.locale]:[],a=typeof e.panelCount=="number"?e.panelCount:0,s=typeof e.totalPanelCount=="number"?e.totalPanelCount:a*Math.max(1,r.length),i=t("section","sf-shell"),g=t("header","sf-head"),b=t("div");b.append(t("p","sf-eyebrow","ShotOps / fastlane"),t("h2","sf-title","Your fastlane bundle is ready"),t("p","sf-sub",r.length>1?`${s} screenshots across ${r.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 m=t("span","sf-badge");m.append(t("span","sf-dot"),document.createTextNode(e.output==="urls"?"Download link":"Inline zip")),g.append(b,m),i.append(g);let c=t("div","sf-body"),p=k(e),d=t("div","sf-zip");d.append(t("div","sf-zip-icon","ZIP"));let w=t("div","sf-zip-text");w.append(t("div","sf-zip-name",e.filename??"fastlane-bundle.zip"));let z=p?.size?` \xB7 ${p.size}`:"";w.append(t("div","sf-zip-sub",s>0?`${s} screenshot${s===1?"":"s"}${z}`:`Bundle${z}`)),d.append(w),p&&d.append(N(p,e.filename??"fastlane-bundle.zip")),c.append(d);let v=t("div","sf-inside");if(v.append(t("p","sf-inside-k","What's inside")),v.append(t("pre","sf-tree",B(r))),c.append(v),e.shareLink?.url){let l=t("div","sf-share"),h=t("div","sf-share-text");h.append(document.createTextNode("Share link")),h.append(t("div","sf-share-sub",A(e.shareLink.expiresAt))),l.append(h,y("Open \u2197",e.shareLink.url,"sf-open")),c.append(l)}i.append(c);let u=t("footer","sf-meta");if(e.bundleId&&f(u,"Bundle ID",e.bundleId),r.length>0&&f(u,r.length===1?"Locale":"Locales",r.join(", ")),Array.isArray(e.outputs)&&e.outputs.length>0&&f(u,"Devices",e.outputs.join(", ")),a>0&&r.length>1&&f(u,"Per locale",String(a)),e.openUrl){let l=t("div","sf-actions");l.append(y("Open in ShotOps \u2197",e.openUrl,"sf-open")),u.append(l)}u.childElementCount>0&&i.append(u);let S=[e.note,e.projectNote].filter(Boolean).join(" ");S&&i.append(t("p","sf-note",S)),i.append(t("p","sf-custody",C)),n.append(i),window.openai?.notifyIntrinsicHeight?.()}P({css:_,rootId:"shotops-bundle",loading:"Preparing your fastlane bundle\u2026",empty:"No ShotOps bundle result is available.",render:R});})();
221
+ `,Y="You upload this yourself. ShotOps never holds your Apple credentials, never creates an App Store version, and never submits anything for review.";function q(e,n){return R("Download .zip",e.href,n,"sf-get")}function G(e,n){e.replaceChildren();let o=T(n);if(o&&!S(n)){let f=r("section","sf-shell"),b=r("header","sf-head"),O=r("div");O.append(r("p","sf-eyebrow","ShotOps / durable production"),r("h2","sf-title",o.title),r("p","sf-sub",o.detail));let A=r("span","sf-badge");A.append(r("span","sf-dot"),document.createTextNode(o.badge)),b.append(O,A),f.append(b);let y=r("footer","sf-meta");g(y,"Progress",o.total>0?`${o.completed}/${o.total}`:"Waiting"),typeof n.progress?.attempt=="number"&&g(y,"Attempt",String(n.progress.attempt)),typeof n.contract?.cost?.reserved=="number"&&g(y,"Reserved",String(n.contract.cost.reserved)),typeof n.contract?.cost?.released=="number"&&g(y,"Released",String(n.contract.cost.released)),f.append(y,r("p","sf-note",`Operation ${n.operationId}. Reconnect with production_operation.`)),e.append(f),window.openai?.notifyIntrinsicHeight?.();return}let t=Array.isArray(n.locales)&&n.locales.length>0?n.locales:n.locale?[n.locale]:[],i=typeof n.panelCount=="number"?n.panelCount:0,s=typeof n.totalPanelCount=="number"?n.totalPanelCount:i*Math.max(1,t.length),p=r("section","sf-shell"),c=r("header","sf-head"),v=r("div");v.append(r("p","sf-eyebrow","ShotOps / fastlane"),r("h2","sf-title","Your fastlane 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 k=r("span","sf-badge");k.append(r("span","sf-dot"),document.createTextNode(n.output==="urls"?"Download link":"Inline zip")),c.append(v,k),p.append(c);let x=r("div","sf-body"),u=S(n),m=r("div","sf-zip");m.append(r("div","sf-zip-icon","ZIP"));let h=r("div","sf-zip-text");h.append(r("div","sf-zip-name",n.filename??"fastlane-bundle.zip"));let w=u?.size?` \xB7 ${u.size}`:"";h.append(r("div","sf-zip-sub",s>0?`${s} screenshot${s===1?"":"s"}${w}`:`Bundle${w}`)),m.append(h),u&&m.append(q(u,n.filename??"fastlane-bundle.zip")),x.append(m);let l=r("div","sf-inside");if(l.append(r("p","sf-inside-k","What's inside")),l.append(r("pre","sf-tree",N(t))),x.append(l),n.shareLink?.url){let f=r("div","sf-share"),b=r("div","sf-share-text");b.append(document.createTextNode("Share link")),b.append(r("div","sf-share-sub",$(n.shareLink.expiresAt))),f.append(b,M("Open \u2197",n.shareLink.url,"sf-open")),x.append(f)}p.append(x);let a=r("footer","sf-meta");if(n.bundleId&&g(a,"Bundle ID",n.bundleId),t.length>0&&g(a,t.length===1?"Locale":"Locales",t.join(", ")),Array.isArray(n.outputs)&&n.outputs.length>0&&g(a,"Devices",n.outputs.join(", ")),i>0&&t.length>1&&g(a,"Per locale",String(i)),n.openUrl){let f=r("div","sf-actions");f.append(M("Open in ShotOps \u2197",n.openUrl,"sf-open")),a.append(f)}a.childElementCount>0&&p.append(a);let E=[n.note,n.projectNote].filter(Boolean).join(" ");E&&p.append(r("p","sf-note",E)),p.append(r("p","sf-custody",Y)),e.append(p),window.openai?.notifyIntrinsicHeight?.()}I({css:H,rootId:"shotops-bundle",loading:"Preparing your fastlane 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:e=>!!(T(e)||S(e)),render:G});})();
@@ -1,4 +1,4 @@
1
- "use strict";(()=>{var y=`
1
+ "use strict";(()=>{var k="shotops/widgetPayload";var _=`
2
2
  :root {
3
3
  color-scheme: light dark;
4
4
  --sf-ink: #15151a;
@@ -124,7 +124,7 @@ button, a { font: inherit; }
124
124
  @media (prefers-reduced-motion: reduce) {
125
125
  .sf-download, .sf-open { transition: none; }
126
126
  }
127
- `;function n(t,e,o){let r=document.createElement(t);return e&&(r.className=e),o!==void 0&&(r.textContent=o),r}function c(t,e,o){let r=n("div","sf-stat");r.append(n("div","sf-k",e),n("div","sf-v",o)),t.append(r)}async function S(t){if(window.openai?.openExternal){await window.openai.openExternal({href:t});return}window.open(t,"_blank","noopener,noreferrer")}function k(t,e,o,r){let p=e;try{let a=new URL(e);/\/storage\/v1\/object\/sign\//.test(a.pathname)&&(a.searchParams.set("download",o),p=a.toString())}catch{}let i=n("a",r,t);return i.href=p,i.download=o,i.rel="noopener noreferrer",/^https?:/i.test(e)&&(i.target="_blank",i.addEventListener("click",a=>{window.openai?.openExternal&&(a.preventDefault(),S(p))})),i}function O(t,e,o){let r=n("button",o,t);return r.type="button",r.addEventListener("click",()=>{S(e)}),r}function M(t){let e=document.createElement("style");e.textContent=t.css;let o=n("div","sf-root");o.id=t.rootId,o.append(n("div","sf-empty",t.loading)),document.body.append(e,o);let r=!1,p=s=>{!s||typeof s!="object"||(r=!0,t.render(o,s))};window.addEventListener("message",s=>{if(s.source!==window.parent)return;let l=s.data;!l||l.jsonrpc!=="2.0"||l.method!=="ui/notifications/tool-result"||p(l.params?.structuredContent)},{passive:!0});let i=100,a=500,m=2e3,w=5*6e4,d=0,h=()=>{if(p(window.openai?.toolOutput),r)return;if(d>=w){o.replaceChildren(n("div","sf-empty",t.empty));return}let s=d<m?i:a;d+=s,setTimeout(h,s)};h()}function P(t){if(!t.operationId||!t.status)return null;let e=Math.max(0,Number(t.progress?.completed??0)),o=Math.max(e,Number(t.progress?.total??0)),r={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,i,a,m]=r[t.status];return{title:p,detail:i,badge:a,terminal:m,completed:e,total:o}}var E=`${y}
127
+ `;function o(t,e,r){let n=document.createElement(t);return e&&(n.className=e),r!==void 0&&(n.textContent=r),n}function h(t,e,r){let n=o("div","sf-stat");n.append(o("div","sf-k",e),o("div","sf-v",r)),t.append(n)}async function M(t){if(window.openai?.openExternal){await window.openai.openExternal({href:t});return}window.open(t,"_blank","noopener,noreferrer")}function O(t,e,r,n){let i=e;try{let p=new URL(e);/\/storage\/v1\/object\/sign\//.test(p.pathname)&&(p.searchParams.set("download",r),i=p.toString())}catch{}let s=o("a",n,t);return s.href=i,s.download=r,s.rel="noopener noreferrer",/^https?:/i.test(e)&&(s.target="_blank",s.addEventListener("click",p=>{window.openai?.openExternal&&(p.preventDefault(),M(i))})),s}function P(t,e,r){let n=o("button",r,t);return n.type="button",n.addEventListener("click",()=>{M(e)}),n}function u(t){return t&&typeof t=="object"&&!Array.isArray(t)?t:null}function C(t){if(!Array.isArray(t.content))return null;let e=[];for(let r of t.content){let n=u(r);if(!n)continue;if(n.type==="image"&&typeof n.data=="string"&&n.mimeType==="image/png"){e.push(n.data);continue}if(n.type==="resource_link"&&typeof n.uri=="string"&&n.mimeType==="image/png"){e.push({url:n.uri});continue}let i=u(n.resource);n.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(t.isError===!0){let r=t.content.map(n=>u(n)).find(n=>n?.type==="text"&&typeof n.text=="string")?.text;return{ok:!1,...typeof r=="string"?{note:r}:{}}}return null}function E(t,e=0){let r=u(t);if(!r||e>6)return null;let n=u(r[k]);if(n)return n;let i=u(r._meta),s=u(i?.[k]);if(s)return s;for(let p of["mcp_tool_result","call_tool_result","tool_result","result"]){let g=E(r[p],e+1);if(g)return g}return null}function S(t,e=!0,r=0){let n=u(t);if(!n||r>6)return e?t:null;for(let s of["structuredContent","structured_content"]){let p=u(n[s]);if(p)return p}for(let s of["mcp_tool_result","call_tool_result","tool_result","result"]){if(n[s]===void 0)continue;let p=S(n[s],!1,r+1);if(p)return p}let i=C(n);return i||(e?t:null)}function T(t,e=0){let r=u(t);if(!r||e>6)return null;let n=typeof r.status=="string"?r.status.toLowerCase():"";if(["failed","failure","error","cancelled","canceled"].includes(n))return"failure";if(["complete","completed","success","succeeded"].includes(n))return"success";for(let i of["mcp_tool_result","call_tool_result","tool_result","result"]){let s=T(r[i],e+1);if(s)return s}return null}function I(t){let e=u(t.detail);return u(e?.globals)}function H(t){return E(t)??S(t,!1)}function W(t){if(!t||typeof t!="object")return t;let e=t;return e.structuredContent&&typeof e.structuredContent=="object"?e.structuredContent:S(t)}function A(t){let e=document.createElement("style");e.textContent=t.css;let r=o("div","sf-root");r.id=t.rootId,r.append(o("div","sf-empty",t.loading)),document.body.append(e,r);let n=!1,i=l=>{let a=W(l);!a||typeof a!="object"||t.accept&&!t.accept(a)||(n=!0,t.render(r,a))},s=l=>i(H(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),n||s(a.params))},{passive:!0}),window.addEventListener("openai:set_globals",l=>{let a=I(l);a&&(i(a.toolOutput),n||s(a.toolResponseMetadata))},{passive:!0});let p=100,g=500,w=2e3,m=5*6e4,y=2e3,d=0,x=null,c=!1,f=()=>{if(i(window.openai?.toolOutput),n||s(window.openai?.toolResponseMetadata),n)return;let l=T(window.openai?.toolResponseMetadata);if(l&&x===null&&(x=d),l&&!c&&(l==="failure"||d-(x??d)>=y)&&(c=!0,r.replaceChildren(o("div","sf-empty",t.terminal??t.empty))),d>=m){c||r.replaceChildren(o("div","sf-empty",t.terminal??t.empty));return}let a=d<w?p:g;d+=a,setTimeout(f,a)};f()}function R(t){if(!t.operationId||!t.status)return null;let e=Math.max(0,Number(t.progress?.completed??0)),r=Math.max(e,Number(t.progress?.total??0)),n={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]},[i,s,p,g]=n[t.status];return{title:i,detail:s,badge:p,terminal:g,completed:e,total:r}}var j=`${_}
128
128
  .sf-rail {
129
129
  display: grid;
130
130
  grid-auto-flow: column;
@@ -185,4 +185,4 @@ button, a { font: inherit; }
185
185
  @media (max-width: 440px) {
186
186
  .sf-rail { padding-inline: 14px; grid-auto-columns: min(64vw, 190px); }
187
187
  }
188
- `;function T(t){if(typeof t=="string"){let e=t.startsWith("data:")?t:`data:image/png;base64,${t}`;return{src:e,href:e}}return typeof t?.url=="string"&&t.url.length>0?{src:t.url,href:t.url}:null}function L(t,e){return k("Download PNG",t,`shotops-panel-${String(e+1).padStart(2,"0")}.png`,"sf-download")}function A(t,e){t.replaceChildren();let o=P(e);if(o&&(!Array.isArray(e.panels)||e.panels.length===0)){let s=n("section","sf-shell"),l=n("header","sf-head"),f=n("div");f.append(n("p","sf-eyebrow","ShotOps / durable production"),n("h2","sf-title",o.title),n("p","sf-sub",o.detail));let g=n("span","sf-badge");g.append(n("span","sf-dot"),document.createTextNode(o.badge)),l.append(f,g),s.append(l);let u=n("footer","sf-meta");c(u,"Progress",o.total>0?`${o.completed}/${o.total}`:"Waiting"),typeof e.progress?.attempt=="number"&&c(u,"Attempt",String(e.progress.attempt)),typeof e.contract?.cost?.reserved=="number"&&c(u,"Reserved",String(e.contract.cost.reserved)),typeof e.contract?.cost?.released=="number"&&c(u,"Released",String(e.contract.cost.released)),s.append(u,n("p","sf-note",`Operation ${e.operationId}. Reconnect with production_operation.`)),t.append(s),window.openai?.notifyIntrinsicHeight?.();return}let r=n("section","sf-shell"),p=n("header","sf-head"),i=n("div"),a=Array.isArray(e.panels)?e.panels:[],m=typeof e.count=="number"?e.count:a.length;i.append(n("p","sf-eyebrow","ShotOps / App Store"),n("h2","sf-title",m===1?"Your panel is ready":`Your ${m}-panel strip is ready`),n("p","sf-sub","Swipe through the final panels, then open or download each PNG."));let w=n("span","sf-badge");if(w.append(n("span","sf-dot"),document.createTextNode(e.output==="urls"?"Full-size links":"Inline result")),p.append(i,w),r.append(p),a.length>0){let s=n("div","sf-rail");e.panelWidth&&e.panelHeight&&s.style.setProperty("--sf-ratio",`${e.panelWidth} / ${e.panelHeight}`),a.forEach((l,f)=>{let g=T(l),u=n("article","sf-panel"),x=n("div","sf-frame");if(x.append(n("span","sf-index",String(f+1).padStart(2,"0"))),g){let b=n("img");b.src=g.src,b.alt=`Rendered App Store panel ${f+1} of ${a.length}`,b.loading=f===0?"eager":"lazy",b.addEventListener("error",()=>x.classList.add("is-error")),x.append(b)}else x.classList.add("is-error");x.append(n("div","sf-expired","Preview unavailable. Ask ShotOps to render this panel again."));let v=n("div","sf-panel-foot");v.append(n("span","sf-panel-name",`Panel ${String(f+1).padStart(2,"0")}`)),g&&v.append(L(g.href,f)),u.append(x,v),s.append(u)}),r.append(s)}else r.append(n("div","sf-empty","The render completed, but no panel previews were returned."));let d=n("footer","sf-meta");if(e.panelWidth&&e.panelHeight&&c(d,"Canvas",`${e.panelWidth}\xD7${e.panelHeight}`),e.panelPresetId&&c(d,"Preset",e.panelPresetId),e.locale&&c(d,"Locale",e.locale),typeof e.renderMs=="number"&&c(d,"Render",`${(e.renderMs/1e3).toFixed(1)}s`),e.openUrl){let s=n("div","sf-actions");s.append(O("Open in ShotOps \u2197",e.openUrl,"sf-open")),d.append(s)}d.childElementCount>0&&r.append(d);let h=[e.note,e.projectNote].filter(Boolean).join(" ");h&&r.append(n("p","sf-note",h)),t.append(r),window.openai?.notifyIntrinsicHeight?.()}M({css:E,rootId:"shotops-result",loading:"Loading ShotOps panels\u2026",empty:"No ShotOps render result is available.",render:A});})();
188
+ `;function L(t){if(typeof t=="string"){let e=t.startsWith("data:")?t:`data:image/png;base64,${t}`;return{src:e,href:e}}return typeof t?.url=="string"&&t.url.length>0?{src:t.url,href:t.url}:null}function N(t,e){return O("Download PNG",t,`shotops-panel-${String(e+1).padStart(2,"0")}.png`,"sf-download")}function $(t,e){t.replaceChildren();let r=R(e);if(r&&(!Array.isArray(e.panels)||e.panels.length===0)){let d=o("section","sf-shell"),x=o("header","sf-head"),c=o("div");c.append(o("p","sf-eyebrow","ShotOps / durable production"),o("h2","sf-title",r.title),o("p","sf-sub",r.detail));let f=o("span","sf-badge");f.append(o("span","sf-dot"),document.createTextNode(r.badge)),x.append(c,f),d.append(x);let l=o("footer","sf-meta");h(l,"Progress",r.total>0?`${r.completed}/${r.total}`:"Waiting"),typeof e.progress?.attempt=="number"&&h(l,"Attempt",String(e.progress.attempt)),typeof e.contract?.cost?.reserved=="number"&&h(l,"Reserved",String(e.contract.cost.reserved)),typeof e.contract?.cost?.released=="number"&&h(l,"Released",String(e.contract.cost.released)),d.append(l,o("p","sf-note",`Operation ${e.operationId}. Reconnect with production_operation.`)),t.append(d),window.openai?.notifyIntrinsicHeight?.();return}let n=o("section","sf-shell"),i=o("header","sf-head"),s=o("div"),p=Array.isArray(e.panels)?e.panels:[],g=typeof e.count=="number"?e.count:p.length;s.append(o("p","sf-eyebrow","ShotOps / App Store"),o("h2","sf-title",g===1?"Your panel is ready":`Your ${g}-panel strip is ready`),o("p","sf-sub","Swipe through the final panels, then open or download each PNG."));let w=o("span","sf-badge");if(w.append(o("span","sf-dot"),document.createTextNode(e.output==="urls"?"Full-size links":"Inline result")),i.append(s,w),n.append(i),p.length>0){let d=o("div","sf-rail");e.panelWidth&&e.panelHeight&&d.style.setProperty("--sf-ratio",`${e.panelWidth} / ${e.panelHeight}`),p.forEach((x,c)=>{let f=L(x),l=o("article","sf-panel"),a=o("div","sf-frame");if(a.append(o("span","sf-index",String(c+1).padStart(2,"0"))),f){let b=o("img");b.src=f.src,b.alt=`Rendered App Store panel ${c+1} of ${p.length}`,b.loading=c===0?"eager":"lazy",b.addEventListener("error",()=>a.classList.add("is-error")),a.append(b)}else a.classList.add("is-error");a.append(o("div","sf-expired","Preview unavailable. Ask ShotOps to render this panel again."));let v=o("div","sf-panel-foot");v.append(o("span","sf-panel-name",`Panel ${String(c+1).padStart(2,"0")}`)),f&&v.append(N(f.href,c)),l.append(a,v),d.append(l)}),n.append(d)}else n.append(o("div","sf-empty","The render completed, but no panel previews were returned."));let m=o("footer","sf-meta");if(e.panelWidth&&e.panelHeight&&h(m,"Canvas",`${e.panelWidth}\xD7${e.panelHeight}`),e.panelPresetId&&h(m,"Preset",e.panelPresetId),e.locale&&h(m,"Locale",e.locale),typeof e.renderMs=="number"&&h(m,"Render",`${(e.renderMs/1e3).toFixed(1)}s`),e.openUrl){let d=o("div","sf-actions");d.append(P("Open in ShotOps \u2197",e.openUrl,"sf-open")),m.append(d)}m.childElementCount>0&&n.append(m);let y=[e.note,e.projectNote].filter(Boolean).join(" ");y&&n.append(o("p","sf-note",y)),t.append(n),window.openai?.notifyIntrinsicHeight?.()}function F(t){if(typeof t.operationId=="string"&&typeof t.status=="string"||t.ok===!1)return!0;if(t.ok!==!0)return!1;let e=Array.isArray(t.panels)?t.panels:[];return(typeof t.count=="number"?t.count:e.length)===0||e.length>0&&e.every(n=>L(n)!==null)}A({css:j,rootId:"shotops-result",loading:"Loading ShotOps panels\u2026",empty:"No ShotOps render result is available.",terminal:"The render finished, but ChatGPT did not deliver its panel data. Refresh ShotOps and try again.",accept:F,render:$});})();
@@ -1 +0,0 @@
1
- import{S as Wt,G as Vt,A as Kt,D as ae,M as qt,R as Yt,a as Xt,C as Jt,b as Zt,c as Qt}from"./three-addons-CvX38LO6.js";import{aa as Ze,P as Qe,b as en,V as q,a4 as tn,C as E,ab as nn,J as Ae,$ as V,M as rn,a2 as on,B as an}from"./three-webgl-DCw804Ic.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 sn=""+new URL("iphone-optimized-BdcJzlHi.glb",import.meta.url).href,ln="data:model/gltf-binary;base64,Z2xURgIAAADUAAAAwAAAAEpTT057ImFzc2V0Ijp7InZlcnNpb24iOiIyLjAiLCJnZW5lcmF0b3IiOiJTaG90T3BzIHBsYWNlaG9sZGVyIOKAlCB0aGUgUGl4ZWwgbW9kZWwgaXMgZGVsaWJlcmF0ZWx5IG5vdCBidW5kbGVkIGluIHRoZSBucG0gcGFja2FnZSJ9LCJzY2VuZXMiOlt7Im5hbWUiOiJwaXhlbC1ub3QtYnVuZGxlZCIsIm5vZGVzIjpbXX1dLCJzY2VuZSI6MH0gICA=",cn=[{id:"grey",label:"Grey",color:11579568},{id:"white",label:"White",color:15263458},{id:"charcoal",label:"Charcoal",color:3815996}],dn=[{id:"silver",label:"Silver",frame:16119285,back:16514043,accent:13816532},{id:"blue",label:"Deep Blue",frame:3290954,back:4409953,accent:2172211},{id:"orange",label:"Cosmic Orange",frame:16219693,back:16487504,accent:12738072}],un=[{id:"silver",label:"Moonstone",frame:9345186,back:8621205,accent:7041658},{id:"blue",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}],Y={id:"iphone-17-pro",glb:sn,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:dn},Oe={id:"pixel-10-pro",glb:ln,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:un},fn={[Y.id]:Y,[Oe.id]:Oe};function Se(e){return e&&fn[e]||Y}const hn=7,Te={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 et(e){const t=Te[e]??Te.front,n=Math.hypot(t.x,t.y,t.z),o=hn/n;return{x:t.x*o,y:t.y*o,z:t.z*o}}function pn(e){return Math.atan2(e.x,-e.z)*180/Math.PI}function he(e){const t=et(e);return new q(t.x,t.y,t.z)}const mn=1.4;function gn(e,t){return(t?new q(t.x,t.y,t.z):he(e)).multiplyScalar(mn)}const tt=35;function yn(e){e.traverse(t=>{const n=t;n.geometry?.dispose();const o=n.material;Array.isArray(o)?o.forEach(Ee):o&&Ee(o)}),e.clear()}function Ee(e){for(const t of Object.values(e))t&&typeof t=="object"&&t.isTexture&&t.dispose();e.dispose()}function nt(e,t){const n=document.createElement("canvas"),o=new Ze({canvas:n,antialias:!0,preserveDrawingBuffer:!0,alpha:!0});o.setSize(e,t,!1),o.shadowMap.enabled=!0;const r=new Wt;r.background=null;const{ambient:a,directionals:i}=bn(r),s=new Qe(tt,e/t,.01,100);s.position.copy(he("front")),s.lookAt(0,0,0);function c(h){s.position.copy(he(h)),s.lookAt(0,0,0)}function l(h){s.position.set(h.x,h.y,h.z),s.lookAt(0,0,0)}function d(h){i.forEach(u=>u.visible=h),a.intensity=h?.75:1.6}let p=!1;function f(){p||(p=!0,r.environment?.dispose(),r.environment=null,yn(r),o.dispose(),o.forceContextLoss())}return{scene:r,camera:s,renderer:o,dispose:f,setAngle:c,setCameraPosition:l,getCameraPosition:()=>({x:s.position.x,y:s.position.y,z:s.position.z}),onUserPose:()=>{},previewOrbit:()=>{},commitOrbit:()=>{},setOrbitEnabled:()=>{},setBackground:()=>{},setStudioLighting:d,resize:()=>{}}}function bn(e){const t=new Kt(16777215,.75);e.add(t);const n=new ae(16777215,2.2);n.position.set(3,5,5);const o=new ae(12571903,.7);o.position.set(-4,1,2);const r=new ae(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 rt(e,t){const n=Se(t);return new Promise((o,r)=>{new Vt().load(n.glb,a=>{const i=a.scene;if(n.pruneNamePrefixes.length){const f=[];i.traverse(h=>{n.pruneNamePrefixes.some(u=>h.name.startsWith(u))&&f.push(h)}),f.forEach(h=>h.removeFromParent())}i.rotation.set(n.baseEuler.x,n.baseEuler.y,n.baseEuler.z),i.updateMatrixWorld(!0);const s=new en().setFromObject(i),c=s.getSize(new q),l=s.getCenter(new q),d=n.fitSize/Math.max(c.x,c.y,c.z);i.scale.multiplyScalar(d),i.position.copy(l.multiplyScalar(-d));const p=new tn;p.add(i),e.scene.add(p),e.setAngle("front"),o(p)},void 0,r)})}function Sn(e){return rt(e)}Y.colorways;class ot{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=Se(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(p=>{const f=p;!f||!f.name||(a.includes(f.name)?this.push(this.frame,f):i.includes(f.name)?this.push(this.back,f):s.includes(f.name)&&this.push(this.accent,f),this.push(this.allBody,f))})})}push(t,n){t.includes(n)||t.push(n)}get finishMaterials(){return[...this.frame,...this.back]}paint(t,n){const o=n instanceof E?n:new E(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 E(t),o=n.clone().lerp(new E(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;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 qt;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 nn(this.renderer);this.envTexture=t.fromScene(new Yt,.04).texture,t.dispose()}return this.envTexture}setClay(t){const n=cn.find(r=>r.id===t),o=n?new E(n.color):new E(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 ke=1.35;class at{materials=[];glassOverlays=[];screenMesh=null;flatPlane=null;texture=null;flatScreenOn=!1;profile;constructor(t,n){this.profile=Se(n);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 S=this.flatPlane.material;S.map?.dispose(),S.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",d=this.texture.clone();d.needsUpdate=!0,d.colorSpace=Ae,d.flipY=!1,d.center.set(.5,.5),d.wrapS=V,d.wrapT=V;const{coverFill:p,coverCornerRatio:f,coverRepeat:h}=this.profile.screen;d.repeat.set(h.x,h.y);const u=l==="x"?a:o,g=l==="z"||l==="x"?r:a,m=Math.min(u,g)*p*f,b=vn(u*p,g*p,m),y=new rn(b,new Xt({map:d,emissive:new E(16777215),emissiveMap:d,emissiveIntensity:ke,color:new E(0),toneMapped:!1,side:on,depthTest:!0,depthWrite:!0,polygonOffset:!0,polygonOffsetFactor:-4,polygonOffsetUnits:-4}));l==="y"?(y.rotation.x=-Math.PI/2,y.position.set(i,n.max.y,c)):l==="x"?(y.rotation.y=Math.PI/2,y.position.set(n.max.x,s,c)):y.position.set(i,s,n.max.z),y.renderOrder=999,this.screenMesh.add(y),this.flatPlane=y}restoreScreen(){this.prepareScreen()}prepareScreen(){this.materials.forEach(t=>{t.color=new E(0),t.emissive=new E(16777215),t.emissiveIntensity=1,t.roughness=1,t.metalness=0,t.needsUpdate=!0})}dimGlassOverlay(t){t.traverse(n=>{const 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){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 d=new Jt(c);d.colorSpace=Ae,d.flipY=!1,d.center.set(.5,.5),d.wrapS=V,d.wrapT=V,d.repeat.set(this.profile.screen.repeat.x,this.profile.screen.repeat.y),d.needsUpdate=!0,this.texture=d,this.materials.forEach(p=>{p.map=d,p.emissiveMap=d,p.emissive=new E(16777215),p.emissiveIntensity=ke,p.color=new E(0),p.needsUpdate=!0}),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})}}function vn(e,t,n){const o=e/2,r=t/2,a=Math.min(n,o,r),i=new Zt;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 Qt(i,16),c=s.attributes.position,l=new Float32Array(c.count*2);for(let d=0;d<c.count;d++)l[d*2]=(c.getX(d)+o)/e,l[d*2+1]=(c.getY(d)+r)/t;return s.setAttribute("uv",new an(l,2)),s}const Ce={sizePt:{min:20,max:120},maxWidth:{min:.1,max:1},lineHeight:{min:.5,max:3},bandInset:{min:0,max:.5},bandCenter:{min:0,max:1},reserveLines:{min:1,max:8}},X=[{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"}],Me=X.map(e=>e.id);[Me[0],...Me.slice(1)];const J=600;function it(e){return X.find(t=>t.id===e)??X[0]}const st=[{id:"standard",label:"Standard",blurb:"Headline on top, whole device below it, nothing cropped. The safe default.",character:"safe",shotLook:{phoneHeight:"82",hOffset:"0",vOffset:"18"},caption:{sizePt:32,maxWidth:.86,reserveLines:2}},{id:"bleed",label:"Bleed",blurb:"Room for a longer headline, device running off the bottom edge. What the market looks like.",character:"conventional",shotLook:{phoneHeight:"82",hOffset:"0",vOffset:"38"},caption:{sizePt:32,maxWidth:.86,reserveLines:4}},{id:"top-bleed",label:"Top bleed",blurb:"Device running off the TOP edge, headline underneath it. Inverts the usual reading order.",character:"expressive",shotLook:{phoneHeight:"82",hOffset:"0",vOffset:"-38"},caption:{sizePt:32,maxWidth:.86,reserveLines:4,band:"bottom"}}],lt=st,Le=lt.map(e=>e.id);[Le[0],...Le.slice(1)];Array.from(new Set(st.flatMap(e=>Object.keys(e.caption))));const ct=[{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"}}],Fe=ct.map(e=>e.id);[Fe[0],...Fe.slice(1)];const A={angle:"front",cameraPos:null,roll:"0",phoneHeight:"82",hOffset:"0",vOffset:"18",material:"real",colorway:"silver",customColor:"F5F5F5",finish:"0",clearcoat:"0",clayTone:"grey",clayCustom:"B0B0B0",flatScreen:!1,glare:!1,lighting:!0,reflections:!1},Re={angle:{valueKind:"angle",required:!0,defaultSource:"default-look",defaultValue:A.angle,persistence:"always"},cameraPos:{valueKind:"camera-position",required:!0,defaultSource:"default-look",defaultValue:A.cameraPos,persistence:"always"},roll:{valueKind:"numeric-string",required:!0,defaultSource:"default-look",defaultValue:A.roll,persistence:"always"},phoneHeight:{valueKind:"numeric-string",required:!0,defaultSource:"default-look",defaultValue:A.phoneHeight,persistence:"always"},hOffset:{valueKind:"numeric-string",required:!0,defaultSource:"default-look",defaultValue:A.hOffset,persistence:"always"},vOffset:{valueKind:"numeric-string",required:!0,defaultSource:"default-look",defaultValue:A.vOffset,persistence:"always"},material:{valueKind:"material",required:!0,defaultSource:"default-look",defaultValue:A.material,persistence:"always"},colorway:{valueKind:"colorway",required:!0,defaultSource:"default-look",defaultValue:A.colorway,persistence:"always"},customColor:{valueKind:"string",required:!0,defaultSource:"default-look",defaultValue:A.customColor,persistence:"always"},finish:{valueKind:"numeric-string",required:!0,defaultSource:"default-look",defaultValue:A.finish,persistence:"always"},clearcoat:{valueKind:"numeric-string",required:!0,defaultSource:"default-look",defaultValue:A.clearcoat,persistence:"always"},clayTone:{valueKind:"clay-tone",required:!0,defaultSource:"default-look",defaultValue:A.clayTone,persistence:"always"},clayCustom:{valueKind:"string",required:!0,defaultSource:"default-look",defaultValue:A.clayCustom,persistence:"always"},flatScreen:{valueKind:"boolean",required:!0,defaultSource:"default-look",defaultValue:A.flatScreen,persistence:"always"},clipToFrame:{valueKind:"boolean",required:!1,defaultSource:"explicit",defaultValue:!1,persistence:"omit-default"},glare:{valueKind:"boolean",required:!0,defaultSource:"default-look",defaultValue:A.glare,persistence:"always"},lighting:{valueKind:"boolean",required:!0,defaultSource:"default-look",defaultValue:A.lighting,persistence:"always"},reflections:{valueKind:"boolean",required:!0,defaultSource:"default-look",defaultValue:A.reflections,persistence:"always"}},wn={roll:{min:-45,max:45},phoneHeight:{min:20,max:200},hOffset:{min:-100,max:100},vOffset:{min:-200,max:200},finish:{min:0,max:1},clearcoat:{min:0,max:1}},H={x:.5,y:.06},ve={fontId:"inter",sizePt:32,color:"FFFFFF",align:"center",anchor:H,maxWidth:.86},_e=[{id:"r69",label:"6.9″ iPhone · 1290×2796",width:1290,height:2796},{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 · 1290×2796",width:1290,height:2796},{id:"ipad13",label:"13″ iPad · 2064×2752",width:2064,height:2752},{id:"ipad129",label:"12.9″ iPad · 2048×2732",width:2048,height:2732}];function G(e){return _e.find(t=>t.id===e)??_e[0]}const te=932,pe="iphone-17-pro",In="pixel-10-pro",we=[{id:"iphone-6-9",label:"iPhone 17 Pro",panelPresetId:"r69",ascDeviceSet:"APP_IPHONE_67",modelId:pe,screenFamily:"iphone"},{id:"iphone-6-5",label:"iPhone 17",panelPresetId:"r65",ascDeviceSet:"APP_IPHONE_65",modelId:pe,screenFamily:"iphone"},{id:"pixel-10-pro",label:"Pixel 10 Pro",panelPresetId:"pixel69",ascDeviceSet:"ANDROID_PHONE",modelId:In,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 Pn(e){return we.find(t=>t.panelPresetId===e)?.modelId??pe}const dt="iphone-6-9";function ut(e){return we.find(t=>t.id===e)}function xn(){return we.filter(e=>!e.comingSoon)}function ft(e,t){if(Array.isArray(e)){const n=new Set,o=[];for(const r of e){const a=ut(r);a&&!a.comingSoon&&!n.has(r)&&(n.add(r),o.push(r))}if(o.length>0)return o}if(t){const n=xn().find(o=>o.panelPresetId===t);if(n)return[n.id]}return[dt]}const ht=ut(dt)?.screenFamily??"iphone";function pt(e){const t={...e},n=t,o=Object.keys(Re);for(const r of o){const a=Re[r];a.persistence==="omit-default"&&(n[r]===void 0||n[r]===a.defaultValue)&&delete n[r]}return t}function mt(e){return pt({...A,...e})}function gt(e){return pt(mt(e))}function R(e,t){const{min:n,max:o}=wn[e],r=typeof t=="number"?t:Number.parseFloat(t??""),a=Number.isFinite(r)?r:Number.parseFloat(A[e]);return Math.max(n,Math.min(o,a))}const An=90,yt=180,On="#1b1b2e",Tn="#0a0a14";function En(e){return e==="horizontal"?An:yt}function kn(e){const t=(e%180+180)%180;return t>=45&&t<135?"horizontal":"vertical"}function bt(e,t,n){return{stops:[{color:e,at:0},{color:t,at:1}],angle:En(n)}}const St=e=>e*Math.PI/180;function Cn(e){const t=St(e);return{dx:Math.sin(t),dy:-Math.cos(t)}}function Mn(e,t,n){const o=St(n);return Math.abs(e*Math.sin(o))+Math.abs(t*Math.cos(o))}function Ln(e,t,n){const{dx:o,dy:r}=Cn(n),a=Mn(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 Z(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:kn(e.angle)}}function ne(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)?Fn(t):yt;return{stops:n,angle:o}}function Q(e){return ne(e.gradientStops,e.gradientAngle)??bt(e.gradientFrom,e.gradientTo,e.gradientDir)}function Fn(e){return(e%360+360)%360}function Rn(e){return ne(e.stops,e.angle)??bt(e.from,e.to,e.dir)}function vt(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=ne(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}function B(e){return!e||e.x===H.x&&e.y===H.y}function _n(e){const{text:t,anchor:n,...o}=e;return B(n)?{...o}:{...o,anchor:n}}const Nn=.55,M="en-US";function Bn(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 wt(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=Bn(c);return!!l&&!!o[n]?.[l.panelId]?.[l.index]&&!!o[a]?.[l.panelId]?.[l.index]});s.length>0&&(r[a]=s)}return r}function It(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]=D(o));return t}function Dn(e){if(!e||typeof e!="object")return;const t=e,n=typeof t.x=="number"?t.x:H.x,o=typeof t.y=="number"?t.y:H.y;return B({x:n,y:o})?void 0:{x:n,y:o}}function D(e){const t=e&&typeof e=="object"?e:{},n=Dn(t.anchor),o={...ve,...t};n?o.anchor=n:delete o.anchor,typeof o.reserveLines!="number"||!Number.isFinite(o.reserveLines)||o.reserveLines<Ce.reserveLines.min?delete o.reserveLines:o.reserveLines=Math.floor(o.reserveLines),o.band!=="bottom"&&delete o.band;for(const r of["bandInset","lineHeight","bandCenter"]){const{min:a,max:i}=Ce[r],s=o[r];(typeof s!="number"||!Number.isFinite(s)||s<a||s>i)&&delete o[r]}return o}function zn(e){const t=e&&typeof e=="object"?e:{};return{...D(t),text:typeof t.text=="string"?t.text:""}}function Pt(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(D)):o&&typeof o=="object"&&(t[n]=[D(o)]);return t}function jn(e,t){const n=[{...D(t),text:e.headline}];return typeof e.subtitle=="string"&&e.subtitle.trim()&&n.push({...D({...t,sizePt:t.sizePt*Nn}),text:e.subtitle}),n}function re(e,t,n=M){if(!e||typeof e!="object"||Array.isArray(e))return{};const o=It(t),r=l=>o[l]??ve,a=l=>{if(!l||typeof l!="object"||Array.isArray(l))return{};const d={};for(const[p,f]of Object.entries(l))Array.isArray(f)?f.length>0&&(d[p]=f.map(zn)):f&&typeof f=="object"&&typeof f.headline=="string"&&(d[p]=jn(f,r(p)));return d},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,d]of i)c[l]=a(d);return c}function xt(e,t,n=M){return e[t??n]??e[n]??{}}function At(e,t=M){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(_n))}return n}function me(e,t=M,n=ht){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 Ne(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 ge(e){const t=[];return e.family!==void 0&&t.push("family"),e.locale!==void 0&&t.push("locale"),t}const Hn={order:["family","locale"],reach:"strict"};function Gn(e,t){const n=ge(e),o=t.order.filter(a=>n.includes(a));return Array.from({length:o.length+1},(a,i)=>o.slice(0,o.length-i)).map(a=>{const i={};return a.includes("family")&&(i.family=e.family),a.includes("locale")&&(i.locale=e.locale),i})}function Un(e,t,n,o,r=M){const a=me(n,r);for(const i of Gn(a,o)){const s=e(t,i);if(s!==void 0){const c=ge(i);return{value:s,resolvedAt:i,inherited:ge(a).filter(l=>!c.includes(l))}}}return{value:void 0,resolvedAt:null,inherited:[]}}function ye(e,t,n=M){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 Ie(e,t=M){return typeof e=="string"&&e.length>0?e:t}const z={"it-IT":"it"};function Be(e,t){if(!(Object.keys(e).some(r=>r in z)||(t?.some(r=>r in z)??!1)))return{captionText:e,locales:t};const o={};for(const[r,a]of Object.entries(e))r in z||(o[r]=a);for(const[r,a]of Object.entries(e)){const i=z[r];i&&(o[i]={...a,...o[i]??{}})}return{captionText:o,locales:t?.map(r=>z[r]??r)}}function Ot(e){if(!e||typeof e!="object"||Array.isArray(e))return{};const t={};for(const[n,o]of Object.entries(e)){if(n===ht||!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(d=>typeof d=="string")&&(s[c]=l);Object.keys(s).length>0&&(r[a]=s)}Object.keys(r).length>0&&(t[n]=r)}return t}function U(e,t){return t.flatMap(n=>e.filter(o=>o.panelId===n.id))}let De=0,ze=0;function $n(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);De=Math.max(De,n(e,"shot-")),ze=Math.max(ze,n(t,"panel-"))}const Wn=.49;function Vn(e,t,n){return e.map(o=>{const r=n*o.heightFrac,a=o.height>0?o.width*(r/o.height):r*Wn,s=o.panelIndex*t+t/2-a/2+o.hOffset*(t/2),l=(n-r)/2+o.vOffset*(n/2);return{shotId:o.shotId,bytes:o.bytes,x:Math.round(s),y:Math.round(l),width:Math.round(a),height:Math.round(r),panelIndex:o.panelIndex,...o.clipToFrame===!0?{clipToFrame:!0}:{}}})}function Kn(e,t){const n=t.panelBackgrounds??{},o=Q(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:Rn(l)}:i(c.id)})}}function Tt(e,t,n=M){const o=Q(e);return{panelPresetId:e.panelPresetId,bgMode:e.bgMode,gradientStops:o.stops,gradientAngle:o.angle,...Z(o),panelColors:e.panelColors,shadow:e.shadow,floorReflection:e.floorReflection??!1,panelBackgrounds:e.panelBackgrounds??{},captionStyles:{...Pt(e.captionStyles),...At(t,n)}}}const Et=2;function qn(e){if(!e||typeof e!="object"||Array.isArray(e))return!1;const t=e;return t.schema===Et&&Array.isArray(t.shots)&&Array.isArray(t.panels)&&t.panels.length>0}function Yn(e){let t;try{t=JSON.parse(e)}catch{return null}if(!qn(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:mt(h.look),thumb:null,thumbStale:!0,inputAnchor:h.inputAnchor,outputAnchor:h.outputAnchor})),a=n.panels.map(h=>({id:h.id}));$n(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,s=Ie(n.baseLocale),{captionText:c,locales:l}=Be(re(n.captionText,n.captionStyles,s),n.locales),d=Be({[s]:{}},[s]).locales?.[0]??s,p=ye(c,l,d),f=ne(n.gradientStops,n.gradientAngle);return{shots:U(r,a),panels:a,selectedShotId:i,panelPresetId:G(n.panelPresetId).id,bgMode:n.bgMode==="perPanel"?"perPanel":"gradient",...f?{gradientStops:f.stops,gradientAngle:f.angle,...Z(f)}:{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:vt(n.panelBackgrounds),captionText:c,locales:p,baseLocale:d,staleCaptionTranslations:wt(n.staleCaptionTranslations,p,d,c),outputs:ft(n.outputs,n.panelPresetId),localeScreens:{},outputCaptions:Ot(n.outputCaptions)}}function kt(e){const n=U(e.shots,e.panels).map(a=>({id:a.id,panelId:a.panelId,frameNodeId:a.frameNodeId,frameName:a.frameName,look:gt(a.look),inputAnchor:a.inputAnchor,outputAnchor:a.outputAnchor})),o=Ie(e.baseLocale),r=re(e.captionText,e.captionStyles,o);return{schema:Et,shots:n,panels:e.panels,selectedShotId:e.selectedShotId,captionText:r,locales:ye(r,e.locales,o),baseLocale:o,staleCaptionTranslations:wt(e.staleCaptionTranslations,ye(r,e.locales,o),o,r),outputs:ft(e.outputs,e.panelPresetId),outputCaptions:Ot(e.outputCaptions),...Tt(e,r,o)}}const Xn=1;function Jn(e){const t=U(e.shots,e.panels),n=re(e.captionText,e.captionStyles),o=Ie(e.baseLocale);return{schema:Xn,shots:t.map(r=>({panelId:r.panelId,look:gt(r.look)})),...Tt(e,n,o)}}function Zn(e){const t=e.caption.reserveLines,n=typeof t=="number"?` Reserves ${t} headline lines (~${t*18} characters).`:"";return`${e.blurb}${n} Character: [${e.character}].`}ct.map(e=>({id:e.id,label:e.label,description:e.blurb}));lt.map(e=>({id:e.id,label:e.label,description:Zn(e),character:e.character}));const Ct=[{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"}];Ct.map(e=>e.code);Object.fromEntries(Ct.map(e=>[e.code,e]));({...ve});function Qn(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(R("finish",t.finish)),e.setClearcoat(R("clearcoat",t.clearcoat)))}function er(e,t,n){e.screen.setGlare(!n&&t?e.device.environmentMap():null)}async function tr(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(R("roll",t.roll)),Qn(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}er(e,t.glare,s)}function Mt(){const e=new Ze({antialias:!0,preserveDrawingBuffer:!0,alpha:!0});return e.setPixelRatio(1),e.shadowMap.enabled=!0,e}async function nr(e,t,n,o={}){const r=!o.renderer,a=o.renderer??Mt();a.setSize(t,n,!1);let i;o.cameraPosition?(i=new Qe(tt,t/n,.01,100),i.position.copy(o.cameraPosition),i.lookAt(0,0,0)):(i=e.camera.clone(),i.aspect=t/n,i.updateProjectionMatrix());try{const s=e.scene.background;e.scene.background=null;try{a.render(e.scene,i)}finally{e.scene.background=s}const c=document.createElement("canvas");let l=null;try{c.width=t,c.height=n,c.getContext("2d")?.drawImage(a.domElement,0,0);const d=rr(c);l=d;const p=d.width,f=d.height;return{bytes:await new Promise((u,g)=>{d.toBlob(m=>{if(!m){g(new Error("toBlob returned null"));return}m.arrayBuffer().then(b=>u(new Uint8Array(b)),g)},"image/png")}),width:p,height:f}}finally{l&&l!==c&&(l.width=0,l.height=0),c.width=0,c.height=0}}finally{r&&a.dispose()}}function rr(e,t=2){const n=e.getContext("2d",{willReadFrequently:!0});if(!n)return e;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 u=0;u<o;u++)a[(h*o+u)*4+3]!==0&&(u<i&&(i=u),u>c&&(c=u),h<s&&(s=h),h>l&&(l=h));if(c<i||l<s)return e;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 d=c-i+1,p=l-s+1,f=document.createElement("canvas");return f.width=d,f.height=p,f.getContext("2d")?.drawImage(e,i,s,d,p,0,0,d,p),f}const or=1900,ar=2800;function ir(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}}async function sr(e,t,n,o,r,a){const i=U(n,o),s=i.filter(u=>u.bytes);if(s.length===0)return null;const c=G(r.panelPresetId),l=new Map(o.map((u,g)=>[u.id,g])),d=r.renderScale!=null&&r.renderScale>0&&r.renderScale<=1?r.renderScale:1,p=Math.max(1,Math.round(or*d)),f=Math.max(1,Math.round(ar*d)),h=Mt();try{const u=[];for(let y=0;y<s.length;y++){const S=s[y];a(`Rendering ${y+1}/${s.length}${r.locale?` (${r.locale})`:""}…`),await tr(t,S.look,S.bytes,()=>!0);const I=await nr(e,p,f,{renderer:h,cameraPosition:gn(S.look.angle,S.look.cameraPos)});u.push({shotId:S.id,bytes:I.bytes,width:I.width,height:I.height,heightFrac:R("phoneHeight",S.look.phoneHeight)/100,hOffset:R("hOffset",S.look.hOffset)/100,vOffset:R("vOffset",S.look.vOffset)/100,panelIndex:l.get(S.panelId)??0,...S.look.clipToFrame===!0?{clipToFrame:!0}:{}})}const g=Vn(u,c.width,c.height),m=Kn(o,r);a("Saving project…");const b=kt(ir(i,o,r));return{panelWidth:c.width,panelHeight:c.height,count:o.length,background:m,phones:g,shadow:r.shadow,floorReflection:r.floorReflection??!1,project:JSON.stringify(b)}}finally{h.dispose(),h.forceContextLoss()}}function ee(e){return/^[0-9a-fA-F]{3,8}$/.test(e)?`#${e}`:e}function je(e,t,n,o){const{x0:r,y0:a,x1:i,y1:s}=Ln(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)),ee(l.color));return c}function He(e){return URL.createObjectURL(new Blob([e],{type:"image/png"}))}function Ge(e){return new Promise((t,n)=>{const o=new Image;o.onload=()=>t(o),o.onerror=n,o.src=e})}const lr=16*1024*1024;function Ue(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 Lt(){let e=0;const t=Array.from(F.values());for(const r of t)e+=Ue(r);const n=Array.from(F.keys());let o=0;for(;e>lr&&o<n.length-1;){const r=F.get(n[o]);r&&(e-=Ue(r),r.reflection&&(r.reflection.canvas.width=0,r.reflection.canvas.height=0),F.delete(n[o])),o++}}const F=new Map,ie=new Map;async function cr(e,t){if(!t){const a=He(e);try{return{img:await Ge(a)}}finally{URL.revokeObjectURL(a)}}const n=F.get(e);if(n)return F.delete(e),F.set(e,n),n;const o=ie.get(e);if(o)return o;const r=(async()=>{const a=He(e);try{return{img:await Ge(a)}}finally{URL.revokeObjectURL(a)}})();ie.set(e,r);try{const a=await r;return F.set(e,a),Lt(),a}finally{ie.delete(e)}}async function dr(e,t,n){const o=t.panelWidth*t.count,r=t.panelHeight;e.width=o,e.height=r;const a=e.getContext("2d");if(!a)return;n?.transparentBg?a.clearRect(0,0,o,r):t.background.kind==="gradient"?(a.fillStyle=je(a,t.background.gradient,o,r),a.fillRect(0,0,o,r)):t.background.kind==="perPanel"?t.background.colors.forEach((l,d)=>{a.fillStyle=ee(l),a.fillRect(d*t.panelWidth,0,t.panelWidth,r)}):t.background.fills.forEach((l,d)=>{const p=d*t.panelWidth;a.fillStyle=l.kind==="solid"?ee(l.color):je(a,l.gradient,o,r),a.fillRect(p,0,t.panelWidth,r)});const i=n?.phoneRange?Math.max(0,n.phoneRange.start):0,s=n?.phoneRange?Math.min(t.phones.length,n.phoneRange.end):t.phones.length,c=n?.reuseDecodedPhones===!0;for(let l=i;l<s;l++){const d=t.phones[l],p=n?.clip==="panel"||n?.clip===void 0&&d.clipToFrame===!0;if(n?.skipShotId&&d.shotId===n.skipShotId)continue;const f=await cr(d.bytes,c),h=f.img;p&&(a.save(),a.beginPath(),a.rect(d.panelIndex*t.panelWidth,0,t.panelWidth,r),a.clip()),t.floorReflection&&ur(a,f,d,c),a.save(),t.shadow&&(a.shadowColor="rgba(0,0,0,0.35)",a.shadowBlur=t.panelWidth*.03,a.shadowOffsetY=t.panelHeight*.012),a.drawImage(h,d.x,d.y,d.width,d.height),a.restore(),p&&a.restore()}}function ur(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},Lt())}const Ft=1.2,fr=.06,hr=.5;function pr(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 mr(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 Rt(e,t,n,o){const r=t.map((u,g)=>{const m=u.text.trim();if(!m)return null;const b=u.sizePt*(o/te),y=it(u.fontId).family;e&&(e.font=`${J} ${b}px "${y}"`);const S=pr(e,m,u.maxWidth*n),I=b*(u.lineHeight??Ft),x=S.length*I,w=Math.max(x,(u.reserveLines??S.length)*I);return{layer:u,index:g,lines:S,px:b,lineH:I,width:mr(e,S),blockH:x,reservedH:w}}),a=r.filter(u=>u!==null&&B(u.layer.anchor)),i=a.filter(u=>u.layer.band==="bottom"),s=a.filter(u=>u.layer.band!=="bottom"),c=u=>u[0]?.layer.bandInset??fr,l=(1-c(i))*o-i.reduce((u,g)=>u+g.reservedH,0);let d=c(s)*o,p=l,f=0;const h=[];for(const u of r){if(!u)continue;if(!B(u.layer.anchor)){h.push({layer:u.layer,index:u.index,x:u.layer.anchor.x*n,yTop:u.layer.anchor.y*o,lines:u.lines,px:u.px,lineH:u.lineH,width:u.width});continue}const g=u.layer.band==="bottom",b=(g?p:d)+(u.reservedH-u.blockH)/2,y=(u.layer.bandCenter??hr)*n;h.push({layer:u.layer,index:u.index,x:y,yTop:b,lines:u.lines,px:u.px,lineH:u.lineH,width:u.width}),g?p+=u.reservedH:d+=u.reservedH,f=Math.max(f,b+u.blockH)}return{placed:h,bandBottom:f}}function gr(e,t,n,o){e.save(),e.textBaseline="top";const{placed:r}=Rt(e,t,n,o);for(const a of r){e.fillStyle=ee(a.layer.color),e.textAlign=a.layer.align,e.font=`${J} ${a.px}px "${it(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 yr(e,t){return e.sizePt*(t/te)*(e.lineHeight??Ft)}function br(e,t,n,o){return Rt(e,t,n,o).placed.map(r=>{const a=r.layer.align==="center"?r.x-r.width/2:r.layer.align==="right"?r.x-r.width:r.x;return{index:r.index,anchorX:r.x/n,top:r.yTop/o,left:a/n,width:r.width/n,height:r.lines.length*r.lineH/o}})}function Sr(e,t,n,o,r){t.forEach((a,i)=>{const s=r[a];!s||s.length===0||(e.save(),e.translate(i*n,0),gr(e,s,n,o),e.restore())})}const vr=""+new URL("Inter-SemiBold-B9yU462S.woff2",import.meta.url).href,wr=""+new URL("Manrope-SemiBold-44nuYf5T.woff2",import.meta.url).href,Ir=""+new URL("Poppins-SemiBold-DJVo7c07.woff2",import.meta.url).href,Pr=""+new URL("Fraunces-SemiBold-BtraKtER.woff2",import.meta.url).href,xr=""+new URL("SpaceGrotesk-SemiBold-CyO2J5Y0.woff2",import.meta.url).href,Ar={inter:vr,manrope:wr,poppins:Ir,fraunces:Pr,"space-grotesk":xr},Or=X.map(e=>({...e,url:Ar[e.id]}));let K=null;function Tr(){return K||(K=(async()=>{const e=new Set;document.fonts.forEach(t=>e.add(`${t.family}/${t.weight}`)),await Promise.all(Or.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 K=null,e})),K}const Er=22/te,kr=1.1,$e=4,Cr=.063,Mr=.167,We=Math.round(Er*te),Lr=.02,Fr=50;function j(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 _t(e,t){return j(e,t)}function Ve(e,t){const n=Math.abs(e-t)%360;return n>180?360-n:n}function Ke(e){return pn(e.cameraPos??et(e.angle))}function Nt(e,t,n,o,r,a,i){if(t.length===0)return[];const s=[];for(const c of br(e,t,r,a)){const l=t[c.index];if(!l)continue;const d=_t({x:(o+c.left)*r,y:c.top*a,width:c.width*r,height:c.height*a},i);d&&s.push({ref:{panelId:n,panelIndex:o,layerIndex:c.index,band:B(l.anchor)},box:d,lineHeightPx:yr(l,a)})}return s}function Rr(e,t,n,o){return n.height<=be(e,t,o)}function be(e,t,n){const o=e.y+e.height/2<=t.y+t.height/2;return n*(o?Mr:Cr)}function _r(e,t,n){return n.height<=be(e.box,t.box,e.lineHeightPx)+be(t.box,e.box,t.lineHeightPx)}function Nr(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 Br(e,a)}finally{t?.restore()}}function Br(e,t){const{ctx:n,panelIds:o,panelWidth:r,panelHeight:a,captionLayers:i}=e,s=o.flatMap((u,g)=>Nt(n,i[u]??[],u,g,r,a,t)),c=[];for(const u of e.phones){const m=e.clip==="panel"||e.clip===void 0&&u.clipToFrame===!0?{x:u.panelIndex*r,y:0,width:r,height:a}:t,b=_t({x:u.x,y:u.y,width:u.width,height:u.height},m);b&&c.push({shotId:u.shotId,box:b,layoutHeight:u.height})}const l=[];for(let u=0;u<s.length;u++)for(let g=u+1;g<s.length;g++){const m=j(s[u].box,s[g].box);m&&l.push({a:s[u].ref,b:s[g].ref,overlap:m,depthFrac:a>0?m.height/a:0,inkUncertain:_r(s[u],s[g],m)})}const d=[];for(const u of s)for(const g of c){const m=j(u.box,g.box);m&&d.push({caption:u.ref,shotId:g.shotId,overlap:m,depthFrac:a>0?m.height/a:0,inkUncertain:Rr(u.box,g.box,m,u.lineHeightPx)})}const p=[];for(let u=0;u<c.length;u++)for(let g=u+1;g<c.length;g++){const m=c[u],b=c[g],y=j(m.box,b.box);if(!y)continue;const S=[],I=Math.max(m.layoutHeight,b.layoutHeight),x=Math.min(m.layoutHeight,b.layoutHeight);x>0&&I/x>=kr&&S.push("scale");const w=e.looks?.[m.shotId],v=e.looks?.[b.shotId],P=!!w&&!!v;w&&v&&(Ve(Ke(w),Ke(v))>=$e&&S.push("angle"),Ve(R("roll",w.roll),R("roll",v.roll))>=$e&&S.push("roll"));const O=Math.min(m.box.width*m.box.height,b.box.width*b.box.height);p.push({shotIdA:m.shotId,shotIdB:b.shotId,overlap:y,coverage:O>0?y.width*y.height/O:0,deliberate:S.length>0,signals:S,anglesKnown:P})}const f=new Set;for(const u of l)u.a.band&&f.add(u.a.panelId),u.b.band&&f.add(u.b.panelId);for(const u of d)u.caption.band&&f.add(u.caption.panelId);const h=[];return o.forEach((u,g)=>{if(!f.has(u))return;const m=Dr(e,u,g,t,s,c);m&&h.push(m)}),{captionsMeasurable:n!=null,captionOverlaps:l,captionDeviceOverlaps:d,deviceOverlaps:p,suggestions:h,hasWarning:l.length>0||d.length>0||p.some(u=>!u.deliberate)}}function Dr(e,t,n,o,r,a){const i=e.captionLayers[t]??[],s=i.flatMap((d,p)=>B(d.anchor)&&d.text.trim()?[p]:[]);if(s.length===0||!(Math.min(...s.map(d=>i[d].sizePt))>We))return null;const l=[...a.map(d=>d.box),...r.filter(d=>!(d.ref.panelId===t&&d.ref.band)).map(d=>d.box)];for(let d=1;d<=Fr;d++){const p=1-d*Lr,f=new Map(s.map(m=>[m,Math.floor(i[m].sizePt*p)]));if(Math.min(...f.values())<We)return null;const h=i.map((m,b)=>{const y=f.get(b);return y===void 0?m:{...m,sizePt:y}});if(Nt(e.ctx,h,t,n,e.panelWidth,e.panelHeight,o).filter(m=>m.ref.band).every(m=>!l.some(b=>j(m.box,b))))return{panelId:t,scale:p,layers:s.map(m=>({layerIndex:m,fromSizePt:i[m].sizePt,toSizePt:f.get(m)}))}}return null}function Bt(e){return`build-shot-${e+1}`}function Dt(e){const t=[];for(const n of e.shots)t.includes(n.panelId)||t.push(n.panelId);return t}const zr=1900,jr=2800;function Hr(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 zt(e,t,n,o={}){await Tr();const r=Dt(e),a=r.map(f=>({id:f})),i=e.shots.map((f,h)=>({id:Bt(h),panelId:f.panelId,frameNodeId:"",frameName:`screen-${h+1}`,bytes:t.screens[h]??null,look:f.look,thumb:null,thumbStale:!1})),c={panelPresetId:G(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 d=o.refs,p=null;if(!d){const f=Pn(e.panelPresetId);p=nt(zr,jr);const h=await rt(p,f);d={stage:p,device:new ot(h,p.scene,p.renderer,f),screen:new at(h,f)}}try{const f=await sr(d.stage,d,i,a,c,l);if(!f)throw new Error("buildStrip: nothing renderable (no shots)");const h=document.createElement("canvas");try{await dr(h,f,o.clip?{clip:o.clip}:void 0);const u=f.panelWidth,g=f.panelHeight,m=h.getContext("2d");if(!m)throw new Error("buildStrip: 2D context unavailable");Sr(m,r,u,g,t.captionText??{});const b=Nr({phones:f.phones,panelIds:r,captionLayers:t.captionText??{},panelWidth:u,panelHeight:g,ctx:m,looks:Object.fromEntries(i.map(I=>[I.id,I.look])),clip:o.clip}),y=o.renderScale&&o.renderScale>0&&o.renderScale<1?o.renderScale:1,S=[];for(let I=0;I<f.count;I++){const x=document.createElement("canvas");x.width=Math.max(1,Math.round(u*y)),x.height=Math.max(1,Math.round(g*y));const w=x.width,v=x.height;try{const P=x.getContext("2d");if(!P)throw new Error("buildStrip: 2D context unavailable");P.drawImage(h,I*u,0,u,g,0,0,w,v),S.push({index:I,bytes:await Hr(x),width:w,height:v})}finally{x.width=0,x.height=0}}return{panels:S,layout:b}}finally{h.width=0,h.height=0}}finally{p&&p.dispose()}}const qe=.005,Gr=.02,Ur=12;function se(e){return Math.max(1,Math.round(e*100))}function le(e){return`${e.kind}:${e.frames.join(",")}:${e.anchored}`}function $r(e,t){const n=new Map(e.suggestions.map(a=>[a.panelId,a.scale])),o=[];for(const a of e.captionOverlaps){if(a.inkUncertain||a.depthFrac<qe)continue;const[i,s]=a.a.band===a.b.band?[a.a,a.b]:a.a.band?[a.a,a.b]:[a.b,a.a],c=ce([t.frameOfPanel(i.panelId),t.frameOfPanel(s.panelId)]);c.length!==0&&o.push({kind:"caption-caption",frames:c,depthPct:se(a.depthFrac),anchored:!a.a.band||!a.b.band,...Ye(n,i.band?i.panelId:null)})}for(const a of e.captionDeviceOverlaps){if(a.inkUncertain||a.depthFrac<qe)continue;const i=ce([t.frameOfPanel(a.caption.panelId),t.frameOfShot(a.shotId)]);i.length!==0&&o.push({kind:"caption-device",frames:i,depthPct:se(a.depthFrac),anchored:!a.caption.band,...Ye(n,a.caption.band?a.caption.panelId:null)})}for(const a of e.deviceOverlaps){if(a.deliberate||a.coverage<Gr)continue;const i=ce([t.frameOfShot(a.shotIdA),t.frameOfShot(a.shotIdB)]);i.length!==0&&o.push({kind:"device-device",frames:i,depthPct:se(a.coverage),anchored:!1})}const r=new Map;for(const a of o){const i=r.get(le(a));i?a.depthPct>i.depthPct?r.set(le(a),{...a,clearAtScale:a.clearAtScale??i.clearAtScale}):i.clearAtScale==null&&a.clearAtScale!=null&&(i.clearAtScale=a.clearAtScale):r.set(le(a),a)}return[...r.values()].sort((a,i)=>i.depthPct-a.depthPct).slice(0,Ur).sort((a,i)=>a.frames[0]-i.frames[0]||a.kind.localeCompare(i.kind))}function ce(e){const[t,...n]=e;return t<0?[]:[t,...n.filter(o=>o>=0&&o!==t)]}function Ye(e,t){const n=t==null?void 0:e.get(t);return n==null?{}:{clearAtScale:Math.round(n*100)/100}}function Wr(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 de(e){return e.frames.map(t=>`frame ${t+1}`).join(" + ")}function Vr(e,t,n){if(!e.captionsMeasurable)return null;const o=$r(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(de).join(", ")}: two devices overlap without reading as composed. There is no deterministic repair — give the pair a real difference in scale, camera angle or roll (that is what makes an overlap read as deliberate), or leave it if it already is.`);for(const d of a)l.push(d.anchored?`${de(d)}: the caption is anchored by hand, so it is reported and never rewritten — move it, or drop its \`anchor\` to let the band place it.`:`${de(d)}: no caption size above the legibility floor clears it — shorten the headline, or pick a layout with a bigger text region (\`style.layout: "bleed"\`).`);return l.length===0&&l.push("The rendered look was not available here, so no corrected look could be built."),{findings: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 d=t.frameOfPanel(l.panelId)+1;return l.layers.map(p=>`frame ${d} layer ${p.layerIndex+1}: sizePt ${p.fromSizePt} → ${p.toSizePt}`)}).join("; ");return{findings:o,correctedLook:Wr(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_strip pass it back as \`look\` together with the SAME \`style.captions\` you just sent: the words come from \`style.captions\` and every style field you leave out of them now comes from this look. The one thing that still beats it is a field you set EXPLICITLY on a caption entry, so if your \`style.captions\` pin \`sizePt\` at the original numbers, drop them or set them to the sizes above.`}}function Kr(e){return String(Math.max(-100,Math.min(100,e*35)))}const qr=["roll","phoneHeight","hOffset","vOffset","finish","clearcoat"];function Xe(e){if(!e||typeof e!="object")return{};const t={...e};for(const n of qr)typeof t[n]=="number"&&(t[n]=String(t[n]));return t}function Yr(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 Je(e){const t={};for(const[n,o]of Object.entries(e))o!==void 0&&(t[n]=o);return t}function ue(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 Xr(e){const t=e.slotSizes.filter(v=>Number.isInteger(v)&&v>0),n=t.map((v,P)=>`panel-${P+1}`);let o={};const r=e.look&&typeof e.look=="object"?e.look:null,a=e.style??null,i=r&&Array.isArray(r.shots)?r.shots:[],s=i.length>0,c=a?Xe(a.shotLook):null,l=[];let d=0;t.forEach((v,P)=>{for(let O=0;O<v;O++){const T=s?Xe(i[d]?.look??i[0]?.look??{}):c??{},$=T.hOffset!==void 0&&T.hOffset!==null?String(T.hOffset):Kr(O);l.push({panelId:n[P],look:{...A,...T,hOffset:$}}),d++}});let p={},f={},h={},u="gradient",g=On,m=Tn,b="vertical",y,S,I=!0,x=!1;if(r){u=r.bgMode==="perPanel"?"perPanel":"gradient";const v=Q({gradientStops:Array.isArray(r.gradientStops)?r.gradientStops:void 0,gradientAngle:typeof r.gradientAngle=="number"?r.gradientAngle:void 0,gradientFrom:typeof r.gradientFrom=="string"?r.gradientFrom:g,gradientTo:typeof r.gradientTo=="string"?r.gradientTo:m,gradientDir:r.gradientDir==="horizontal"?"horizontal":b});y=v.stops,S=v.angle,{gradientFrom:g,gradientTo:m,gradientDir:b}=Z(v),r.shadow===!1&&(I=!1),r.floorReflection===!0&&(x=!0);const P=[];for(const O of i){const T=typeof O?.panelId=="string"?O.panelId:null;T&&!P.includes(T)&&P.push(T)}p=ue(r.panelColors,P,n),f=ue(Pt(r.captionStyles),P,n),h=ue(vt(r.panelBackgrounds),P,n)}else if(a){const v=a.background??{};u=v.mode==="perPanel"?"perPanel":"gradient";const P=Q({gradientStops:v.stops,gradientAngle:v.angle,gradientFrom:g,gradientTo:m,gradientDir:b});y=P.stops,S=P.angle,{gradientFrom:g,gradientTo:m,gradientDir:b}=Z(P),v.shadow===!1&&(I=!1),v.floorReflection===!0&&(x=!0),Array.isArray(v.panelColors)&&v.panelColors.forEach((O,T)=>{typeof O=="string"&&O&&n[T]!==void 0&&(p[n[T]]=O)})}if(a&&Array.isArray(a.captions)){const v=f,P=(L,oe)=>({...v[L]?.[oe]??{}}),O={},T={};a.captions.forEach((L,oe)=>{const _=n[oe];if(!(_===void 0||L===null||L===void 0)){if(Array.isArray(L)){const N=L.filter(C=>!!C&&typeof C=="object"&&typeof C.text=="string"&&C.text.trim()!=="").map((C,W)=>({...P(_,W),...Je(Yr(C))}));N.length>0&&(T[_]=N)}else if(typeof L=="object"){const{text:N,subtitle:C,sizePt:W,maxWidth:xe,...$t}=L;O[_]={...P(_,0),...Je({...$t,...W!==void 0?{sizePt:Number(W)}:{},...xe!==void 0?{maxWidth:Number(xe)}:{}})},typeof N=="string"&&N.trim()&&(T[_]={headline:N,...typeof C=="string"&&C?{subtitle:C}:{}})}}});const $=re({[M]:T},It(O));f=At($),o=xt($)}return{look:{panelPresetId:e.panelPresetId??(typeof r?.panelPresetId=="string"?r.panelPresetId:void 0)??"r69",bgMode:u,gradientStops:y,gradientAngle:S,gradientFrom:g,gradientTo:m,gradientDir:b,panelColors:p,shadow:I,floorReflection:x,panelBackgrounds:h,captionStyles:f,shots:l},panelIds:n,captionText:o}}function Jr(e){const t=e?.trim();return t?/\.(png|jpe?g|webp)$/i.test(t)?t:`${t}.png`:null}function Zr(e,t){const n=new Map;return e.map((o,r)=>{const a=Jr(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 Qr(e){const{look:t,panelIds:n,captionText:o,locale:r,shotNames:a,outputs:i}=e,s=n.map(d=>({id:d})),c=Zr(t.shots,a),l=t.shots.map((d,p)=>({id:`shot-${p+1}`,panelId:d.panelId,frameNodeId:c[p],frameName:c[p],bytes:null,look:d.look,thumb:null,thumbStale:!0}));return kt({shots:l,panels:s,selectedShotId:l[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,captionText:o&&Object.keys(o).length>0?{[r||M]:o}:{}})}function k(e){console.log("[render]",e)}const eo=1900,to=2800;let fe=null;async function jt(){return fe||(fe=(async()=>{k("booting headless stage + loading model (once)…");const e=nt(eo,to),t=await Sn(e);return{stage:e,device:new ot(t,e.scene,e.renderer),screen:new at(t)}})()),fe}function Ht(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 Pe(e){let t="";for(let n=0;n<e.length;n++)t+=String.fromCharCode(e[n]);return btoa(t)}function no(e){return new Promise((t,n)=>{e.toBlob(async o=>{if(!o)return n(new Error("toBlob null"));t(Pe(new Uint8Array(await o.arrayBuffer())))},"image/png")})}function Gt(e,t){const n=Dt(t),o=new Map(t.shots.map((a,i)=>[Bt(i),n.indexOf(a.panelId)])),r=Vr(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 Ut(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 no(n),width:n.width,height:n.height}}window.renderStrip=async function(t){try{if(!t||!Array.isArray(t.screenshots)||t.screenshots.length===0)throw new Error("renderStrip: input.screenshots must be a non-empty nested array of slots");const n=await jt(),o=t.screenshots.map(y=>Array.isArray(y)?y:[y]),{look:r,panelIds:a,captionText:i}=Xr({slotSizes:o.map(y=>y.length),panelPresetId:t.panelPresetId,look:t.look??void 0,style:t.style??void 0}),s=o.flat().map(Ht),c=t.preview?.25:1;k(`buildStrip (${o.length} panel${o.length===1?"":"s"}${t.locale?`, ${t.locale}`:""})…`);const l=performance.now(),d=await zt(r,{screens:s,captionText:i},t.locale,{refs:n,renderScale:c,onProgress:y=>k(" "+y),...t.clip?{clip:t.clip}:{}});k("encoding panels + stitching the strip preview…");const p=d.panels.map(y=>Pe(y.bytes)),f=await Ut(d.panels),h=G(r.panelPresetId),u=Math.round(performance.now()-l),g=Gt(d,r),m=Array.isArray(t.screenshotNames)?t.screenshotNames.flat():void 0,b=t.buildRecord?Qr({look:r,panelIds:a,captionText:i,locale:t.locale,shotNames:m,outputs:t.outputs}):void 0;return k(`done: ${d.panels.length} panels, strip ${f.width}x${f.height}, ${u}ms`),{ok:!0,ms:u,count:d.panels.length,panelPresetId:h.id,panelWidth:h.width,panelHeight:h.height,stripWidth:f.width,stripHeight:f.height,panels:p,stripBase64:f.base64,preview:c<1,...b?{projectRecord:b}:{},...g??{}}}catch(n){const o=n&&n.stack?n.stack:String(n);return k("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=Yn(JSON.stringify(t.projectFile));if(!n)throw new Error("renderProject: the saved project could not be restored (wrong schema or malformed record)");const o=await jt(),r=t.locale||n.baseLocale||n.locales?.[0]||"en-US",a=U(n.shots,n.panels),i=me(t.variant||{},n.baseLocale),s=new Map((t.screenManifest||[]).map(w=>[`${w.shotId} ${Ne(me(w.variant||{},n.baseLocale))}`,w])),c=(w,v)=>s.get(`${w} ${Ne(v)}`),l=a.map(w=>Un(c,w.id,i,Hn,n.baseLocale)),d=a.map((w,v)=>({frameName:w.frameName,matched:l[v].value!==void 0,requestedVariant:i,resolvedAt:l[v].resolvedAt,inherited:l[v].inherited,...l[v].value?.source?{source:l[v].value.source}:{}})),p=l.map(({value:w})=>w?.bytes?Ht(w.bytes):null),f=xt(n.captionText,r,n.baseLocale),h=Jn({...n,selectedShotId:null,panelPresetId:t.panelPresetId??n.panelPresetId,captionText:{[r]:f}}),u=t.preview?.25:1;k(`renderProject (${a.length} shot${a.length===1?"":"s"}, ${r})…`);const g=performance.now(),m=await zt(h,{screens:p,captionText:f},r,{refs:o,renderScale:u,onProgress:w=>k(" "+w)});k("encoding panels + stitching the strip preview…");const b=m.panels.map(w=>Pe(w.bytes)),y=await Ut(m.panels),S=G(h.panelPresetId),I=Math.round(performance.now()-g),x=Gt(m,h);return k(`done: ${m.panels.length} panels, strip ${y.width}x${y.height}, ${I}ms`),{ok:!0,ms:I,count:m.panels.length,panelPresetId:S.id,panelWidth:S.width,panelHeight:S.height,stripWidth:y.width,stripHeight:y.height,panels:b,stripBase64:y.base64,preview:u<1,shots:d,locale:r,...x??{}}}catch(n){const o=n&&n.stack?n.stack:String(n);return k("ERROR: "+o),{ok:!1,error:String(n&&n.message?n.message:n)}}};window.__RENDER_READY=!0;k("harness ready ✓");