shotops-mcp 0.9.0 → 0.9.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +22 -23
- package/dist/local.js +317 -127
- package/harness-dist/assets/index-DdK1IK1N.js +1 -0
- package/harness-dist/index.html +1 -1
- package/package.json +1 -1
- package/harness-dist/assets/index-Wb7M1qGz.js +0 -1
|
@@ -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;appliedBytes=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){if(this.appliedBytes===t&&this.texture)return this.lightScreen(this.texture),Promise.resolve();const n=new Blob([t],{type:"image/png"}),o=URL.createObjectURL(n),r=this.texture;return new Promise((a,i)=>{const 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.appliedBytes=t,this.lightScreen(u),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})}lightScreen(t){this.materials.forEach(n=>{n.map=t,n.emissiveMap=t,n.emissive=new k(16777215),n.emissiveIntensity=Ee,n.color=new k(0),n.needsUpdate=!0})}}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 ✓");
|
package/harness-dist/index.html
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
<head>
|
|
4
4
|
<meta charset="utf-8" />
|
|
5
5
|
<title>shotops-mcp headless render harness</title>
|
|
6
|
-
<script type="module" crossorigin src="./assets/index-
|
|
6
|
+
<script type="module" crossorigin src="./assets/index-DdK1IK1N.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.9.
|
|
3
|
+
"version": "0.9.2",
|
|
4
4
|
"private": false,
|
|
5
5
|
"type": "module",
|
|
6
6
|
"description": "The bundle-emitting MCP server over the @engine/@sync spine. Exposes ShotOps tools to ChatGPT, Claude Code, Cursor, and CI over Streamable HTTP with OAuth or personal API tokens. Hosted and MCP tool paths never accept, store, or forward a store-signing credential; the explicit local release CLI validates the user's existing key directly with Apple and records only its path. Renders via headless Playwright Chromium, the engine's native non-browser habitat (same path as mockup-mcp). Also ships as a free LOCAL stdio server (`npx shotops-mcp`) — same render, on your own machine, no account needed.",
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
import{S as 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 ✓");
|