@gui-chat-plugin/sequence 0.4.0 → 0.4.1

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/CHANGELOG.md CHANGED
@@ -1,5 +1,15 @@
1
1
  # Changelog
2
2
 
3
+ ## 0.4.1
4
+
5
+ - **Slides are explained, not announced.** Asked only to "explain" the slide on the screen, OpenAI's
6
+ voice models often said a line about the slide ("Let's start with the big picture, then we'll
7
+ move on", "This first slide is about quantum theory") and went on to the next. After each slide,
8
+ the model is now told to teach its subject in at least two sentences, beginning with the content
9
+ itself, never with the slide or its plan; a guide step says what to do, directly. In MulmoGlass
10
+ (mock images), OpenAI began 9 of 10 slide explanations with their content, against 3 of 7
11
+ before; Gemini and Grok already did, and still do.
12
+
3
13
  ## 0.4.0
4
14
 
5
15
  - **HTML slides animate with MulmoCast's `data-animation` attributes**, not CSS: `animate`
@@ -0,0 +1,145 @@
1
+ let e=require("gui-chat-protocol");var t=1280,n=720,r=6e4,i=`https://cdn.jsdelivr.net/npm/@tailwindcss/browser@4.3.3/dist/index.global.js`,a=`sha384-2ql948lIdLcGEE0/qxNiudyTjgauA3RDJERu5xW75kFCvSl5a9odyQYCb6tEjnmB`,o=[`animate`,`counter`,`typewriter`],s=8,c=`
2
+ (() => {
3
+ const EASE = {
4
+ linear: (t) => t,
5
+ easeIn: (t) => t * t,
6
+ easeOut: (t) => 1 - (1 - t) * (1 - t),
7
+ easeInOut: (t) => (t < 0.5 ? 2 * t * t : 1 - Math.pow(-2 * t + 2, 2) / 2),
8
+ };
9
+ const AUTO_END = 8;
10
+ const TRANSFORMS = [
11
+ ["data-translate-x", "translateX", "px"],
12
+ ["data-translate-y", "translateY", "px"],
13
+ ["data-scale", "scale", ""],
14
+ ["data-rotate", "rotate", "deg"],
15
+ ["data-rotate-x", "rotateX", "deg"],
16
+ ["data-rotate-y", "rotateY", "deg"],
17
+ ["data-rotate-z", "rotateZ", "deg"],
18
+ ];
19
+ const STYLES = [
20
+ ["data-opacity", "opacity", ""],
21
+ ["data-width", "width", "px"],
22
+ ["data-height", "height", "px"],
23
+ ];
24
+ const number = (value, fallback) => {
25
+ const n = Number(value);
26
+ return value !== null && value.trim() !== "" && Number.isFinite(n) ? n : fallback;
27
+ };
28
+ const range = (value, unit) => {
29
+ if (value === null) return null;
30
+ const parts = value.split(",").map((part) => part.trim());
31
+ const from = Number(parts[0]);
32
+ const to = Number(parts[1]);
33
+ if (!Number.isFinite(from) || !Number.isFinite(to)) return null;
34
+ return { from, to, unit: parts[2] || unit };
35
+ };
36
+ const ranges = (el, table) =>
37
+ table
38
+ .map(([attr, name, unit]) => [name, range(el.getAttribute(attr), unit)])
39
+ .filter(([, r]) => r);
40
+ let entries = [];
41
+ const collect = () => {
42
+ entries = [...document.querySelectorAll("[data-animation]")].map((el) => {
43
+ const kind = el.getAttribute("data-animation");
44
+ const end = el.getAttribute("data-end");
45
+ const entry = {
46
+ el,
47
+ kind,
48
+ start: number(el.getAttribute("data-start"), 0),
49
+ end: end === null || end.trim() === "auto" ? null : number(end, null),
50
+ ease: EASE[el.getAttribute("data-easing")] || EASE.linear,
51
+ };
52
+ if (kind === "animate") {
53
+ entry.transforms = ranges(el, TRANSFORMS);
54
+ entry.styles = ranges(el, STYLES);
55
+ } else if (kind === "counter") {
56
+ entry.from = number(el.getAttribute("data-from"), 0);
57
+ entry.to = number(el.getAttribute("data-to"), 0);
58
+ entry.decimals = Math.max(0, Math.round(number(el.getAttribute("data-decimals"), 0)));
59
+ entry.prefix = el.getAttribute("data-prefix") || "";
60
+ entry.suffix = el.getAttribute("data-suffix") || "";
61
+ } else if (kind === "typewriter") {
62
+ entry.text = el.getAttribute("data-text") ?? el.textContent;
63
+ } else {
64
+ return null;
65
+ }
66
+ return entry;
67
+ }).filter(Boolean);
68
+ };
69
+ const seek = (t) => {
70
+ for (const e of entries) {
71
+ const end = e.end ?? AUTO_END;
72
+ const span = end - e.start;
73
+ const p = span > 0 ? Math.min(1, Math.max(0, (t - e.start) / span)) : t >= e.start ? 1 : 0;
74
+ const k = e.ease(p);
75
+ const at = (r) => r.from + (r.to - r.from) * k;
76
+ if (e.kind === "animate") {
77
+ if (e.transforms.length) {
78
+ e.el.style.transform = e.transforms.map(([name, r]) => name + "(" + at(r) + r.unit + ")").join(" ");
79
+ }
80
+ for (const [name, r] of e.styles) e.el.style[name] = at(r) + r.unit;
81
+ } else if (e.kind === "counter") {
82
+ e.el.textContent = e.prefix + (e.from + (e.to - e.from) * k).toFixed(e.decimals) + e.suffix;
83
+ } else {
84
+ e.el.textContent = e.text.slice(0, Math.floor(e.text.length * k));
85
+ }
86
+ }
87
+ };
88
+ window.__slideSeek = seek;
89
+ const play = () => {
90
+ const last = Math.max(0, ...entries.map((e) => e.end ?? AUTO_END));
91
+ const begun = performance.now();
92
+ const tick = (now) => {
93
+ const t = (now - begun) / 1000;
94
+ seek(t);
95
+ if (t <= last) requestAnimationFrame(tick);
96
+ };
97
+ requestAnimationFrame(tick);
98
+ };
99
+ // Collected once the body is parsed: at DOMContentLoaded, or earlier when
100
+ // the fallback shows the slide while a slow Tailwind still holds
101
+ // DOMContentLoaded back (the body is parsed by then: readyState is
102
+ // "interactive" before deferred scripts run). Played once both are done.
103
+ let collected = false;
104
+ let shown = false;
105
+ const init = () => {
106
+ if (collected || document.readyState === "loading") return;
107
+ collected = true;
108
+ collect();
109
+ seek(0);
110
+ if (shown) play();
111
+ };
112
+ const show = () => {
113
+ if (shown) return;
114
+ init();
115
+ shown = true;
116
+ document.documentElement.classList.add("ready");
117
+ if (collected) play();
118
+ };
119
+ const ready = () => requestAnimationFrame(() => requestAnimationFrame(show));
120
+ const check = () =>
121
+ document.querySelector("style:not([type]):not(#slide-base)") ? ready() : setTimeout(check, 30);
122
+ addEventListener("DOMContentLoaded", () => {
123
+ init();
124
+ check();
125
+ });
126
+ setTimeout(show, 1000);
127
+ addEventListener("click", (event) => {
128
+ if (event.target instanceof Element && event.target.closest("a, area")) event.preventDefault();
129
+ }, true);
130
+ })();`,l=[`default-src 'none'`,`script-src 'sha256-0zsqCvkCfq5Z1iJCn46NiAtSAyIr/JDkyNs/Fae1J+Y=' ${i}`,`style-src 'unsafe-inline' https://fonts.googleapis.com`,`font-src https://fonts.gstatic.com data:`,`img-src data: blob:`,`media-src data: blob:`,`connect-src 'none'`,`form-action 'none'`,`base-uri 'none'`].join(`; `),u=e=>e.replace(/<(?=(meta|base|link)\b)/gi,`&lt;`).replace(/shadowroot/gi,`data-no-shadow-root`),d=`*, *::before, *::after { animation-play-state: paused !important; animation-duration: 0s !important; animation-delay: 0s !important; animation-iteration-count: 1 !important; animation-fill-mode: both !important; transition: none !important; }`,f=`
131
+ html, body { margin: 0; width: ${t}px; height: 720px; overflow: hidden; }
132
+ html:not(.ready) body { visibility: hidden; }
133
+ ${d}`;function p(e){return`<!doctype html>
134
+ <html lang="en">
135
+ <head>
136
+ <meta charset="utf-8">
137
+ <meta http-equiv="Content-Security-Policy" content="${l}">
138
+ <style id="slide-base">${f}</style>
139
+ <script>${c}<\/script>
140
+ <script defer src="${i}" integrity="${a}" crossorigin="anonymous"><\/script>
141
+ </head>
142
+ <body class="bg-white text-slate-900 font-sans antialiased">
143
+ ${u(e)}
144
+ </body>
145
+ </html>`}var m=`presentSlide`,h=`defineStoryboard`,g=`presentPanel`,ee=4,te=12,ne=3,_=/^[0-9a-f]{12}$/,v=e=>typeof e==`object`&&!!e&&!Array.isArray(e),y=e=>typeof e==`string`?e.trim():``,b=(e,t)=>e.toLowerCase()===t.toLowerCase(),x=e=>typeof e==`number`&&Number.isInteger(e),S=`presentSlide needs slide and totalSlides (whole numbers, slide from 1 to totalSlides), and either an imagePrompt or html`,re=`presentSlide's html is too long: keep a slide under ${r} characters`;function C(e){let{slide:t,totalSlides:n,title:r,imagePrompt:i}=e,a=y(e.html);return!x(t)||!x(n)||t<1||n<t||!a&&!y(i)?S:a.length>6e4?re:{slide:t,totalSlides:n,title:typeof r==`string`?r:``,imagePrompt:a?``:String(i),...a&&{html:a},mode:e.mode===`steps`?`steps`:`presentation`}}var w=`teach its subject in at least two sentences, as a presenter speaking to the audience. Begin with the content itself, never with the slide or your plan: no "This slide is about…", "The first slide shows…", "Let's unpack this one", "Next, I'll…". A line about the slide is not an explanation.`,T=({slide:e,totalSlides:t,title:n,mode:r})=>{let i=n?` ("${n}")`:``;if(r===`steps`){let n=`Step ${e} of ${t}${i}`;return e<t?`${n} is now on the screen. Say what to do in this step, directly ("Crack two eggs into a bowl…", not "This step is about eggs"), then stop and wait while the user does it. When they say they're ready (next, done, go on), call presentSlide for step ${e+1} with mode "steps". If they ask to go back or to see a step again, call presentSlide for that step.`:`${n}, the last one, is now on the screen. Say what to do, directly, then wrap up the guide once the user is done.`}let a=`Slide ${e} of ${t}${i}`;return e<t?`${a} is now on the screen. Explain it: ${w} Then, in this same reply and without waiting for the user, call presentSlide for slide ${e+1}. If the user has asked you to stop, or asked something else, since the slideshow began, answer them instead of going on.`:`${a}, the last one, is now on the screen. Explain it: ${w} Then wrap up the slideshow.`},ie=[`For an HTML slide, instead of imagePrompt: the slide's content, the inside of <body> only (no <html>, <head> or <body> tags), for a ${t}x720 px canvas, which it should fill (start with a <div class="w-full h-full ...">). Style it with Tailwind CSS v4 classes, which are loaded for you: a clear layout, a large title (text-6xl or so), few words in large type, a color scheme, and inline SVG or emoji for icons and diagrams. There is no network: no <img> from URLs, no links to follow.`,`Animate it so it builds up as you explain it, with MulmoCast's data-animation attributes (the same ones make it move in a movie of the slideshow): data-animation="animate" with data-opacity="0,1", data-translate-x, data-translate-y (px), data-scale, data-rotate (deg), data-width or data-height ("0,80,%"), each "from,to"; data-animation="counter" with data-from, data-to, data-decimals, data-prefix, data-suffix; data-animation="typewriter" (its text, or data-text). Give every one data-start and data-end in seconds, and optionally data-easing (linear, easeIn, easeOut, easeInOut); stagger the parts with later data-start values so they appear one after another over a few seconds (for example 0, 0.6, 1.2). Set the first frame inline too (style="opacity:0" on an element that fades in).`,`CSS animations, transitions and scripts don't play: animate only with data-animation. A <style> for layout is allowed (and Google Fonts by @import).`].join(` `),E=`When the user asks for a slideshow (or to explain something with slides), plan four to six slides, then show them one at a time with presentSlide: slide 1 first, and each next slide only after you have explained the one on the screen. Explain the subject, not the slides: say what the slide teaches, not that a slide is about it. Go on to the last slide without asking whether to continue. A slide is a generated picture (imagePrompt) or a designed slide in HTML (html): use a picture for a scene, an object or a place, and HTML for words, numbers, lists, comparisons, timelines and diagrams, which a picture model draws badly; a slideshow can mix them. When the user asks for HTML slides (slides in HTML, an HTML presentation), this is the tool: make them HTML slides with presentSlide, one call per slide, not one HTML page. When the user wants to be shown how to do something they will do along with you (cooking, folding, fixing, an exercise), make it a step-by-step guide instead: mode "steps", one slide per step, and after each step wait for the user to say they are ready. Use generateImage for a single picture, not for slides.`,D={type:`function`,name:m,prompt:E,description:`Show one slide of a slideshow, full screen: a picture generated from imagePrompt, or a slide written in HTML (html). Call it once per slide, in order, starting with slide 1. With mode "steps" it is a step-by-step guide: one slide per step, and the next step waits for the user.`,parameters:{type:`object`,properties:{slide:{type:`integer`,description:`This slide's number, starting at 1.`},totalSlides:{type:`integer`,description:`How many slides the slideshow has. Keep it the same for every slide.`},title:{type:`string`,description:`The slide's title.`},imagePrompt:{type:`string`,description:`For a picture slide: the picture, a clear illustration of its point, with the title as its only large text. Be concrete. For a step, show the action: hands, tools and the object. Leave it out for an HTML slide.`},html:{type:`string`,description:ie},mode:{type:`string`,enum:[`presentation`,`steps`],description:`"presentation" (the default) goes on by itself; "steps" is a how-to the user does along with you, and waits for them after each step. Keep it the same for every slide.`}},required:[`slide`,`totalSlides`,`title`]}};function O(e){let{totalPanels:t}=e;if(!x(t)||t<1||t>12)return`totalPanels must be a whole number from 1 to 12`;let n=[];for(let t of Array.isArray(e.characters)?e.characters:[]){let e=v(t)?y(t.name):``,r=v(t)?y(t.description):``;if(!e||!r)return`every character needs a name and a description`;if(n.some(t=>b(t.name,e)))return`two characters are named ${e}`;n.push({name:e,description:r})}return n.length<1||n.length>4?`a storyboard has 1 to 4 characters`:{title:y(e.title),style:y(e.style),totalPanels:t,characters:n,interactive:e.interactive===!0}}var k=({title:e,id:t})=>`The cast of "${e}" is now on the screen. Introduce the characters briefly, then, in this same reply and without waiting for the user, call presentPanel for panel 1 with storyboardId "${t}". If the user has asked you to stop, or asked something else, answer them instead of going on.`,A=`presentPanel needs a storyboardId, a panel number (from 1) and an imagePrompt`;function j(e){let{panel:t}=e,n=y(e.storyboardId),r=y(e.imagePrompt);if(!n||!r||!x(t)||t<1)return null;let i=e=>(Array.isArray(e)?e:[]).map(y).filter(Boolean);return{storyboardId:n,panel:t,characters:i(e.characters),imagePrompt:r,caption:y(e.caption),choices:i(e.choices).slice(0,3)}}function M(e,t,n){let{id:r,totalPanels:i}=e;return n.length?`Panel ${t} of ${i} is now on the screen, with the user's choices: ${n.map((e,t)=>`${t+1}. ${e}`).join(` `)} Tell this part of the story, then read the choices out and ask the user which one they pick, and wait for their answer. Then call presentPanel for panel ${t+1} with storyboardId "${r}", going on the way they chose.`:t<i?`Panel ${t} of ${i} is now on the screen. Tell this part of the story, then, in this same reply and without waiting for the user, call presentPanel for panel ${t+1} with storyboardId "${r}". If the user has asked you to stop, or asked something else, since the story began, answer them instead of going on.`:`Panel ${t} of ${i}, the last one, is now on the screen. Tell this part of the story, then bring it to an end.`}var N=`When the user asks for a story, a picture book, a comic or a storyboard, tell it in pictures: first call defineStoryboard with the art style and the characters who appear more than once (it draws a reference sheet for each, so they look the same in every panel), then show the panels one at a time with presentPanel, naming the characters in each, and tell each part of the story when its panel appears. Go on to the last panel without asking whether to continue, unless the story is interactive. When the user wants to decide what happens (an adventure, a story for a child who wants to choose), set interactive, and give two or three choices on two or three of the panels: the story waits there for the user's pick and goes on their way; it still ends at the last panel whichever way it goes. Use presentSlide to explain a topic, not to tell a story.`,P={type:`function`,name:h,prompt:N,description:`Start a story told in pictures: set its art style and draw a reference sheet for each recurring character, shown as the cast. Then call presentPanel for each panel, in order.`,parameters:{type:`object`,properties:{title:{type:`string`,description:`The story's title.`},style:{type:`string`,description:`The art style of every picture, in one sentence (for example: soft watercolor, children's picture book).`},totalPanels:{type:`integer`,description:`How many panels the story has, at most 12; four to eight is usual.`},interactive:{type:`boolean`,description:`The user chooses what happens: panels can offer choices, and the story waits for the pick.`},characters:{type:`array`,description:`The characters who appear in more than one panel, 1 to 4.`,items:{type:`object`,properties:{name:{type:`string`,description:`A short name, used in presentPanel.`},description:{type:`string`,description:`How they look: age, build, face, hair, clothes and colors. Be concrete: it is drawn once and reused in every panel.`}},required:[`name`,`description`]}}},required:[`title`,`style`,`totalPanels`,`characters`]}},F={type:`function`,name:g,description:`Show one panel of a storyboard made with defineStoryboard: a picture of the scene with its characters drawn as in their reference sheets, and a caption. Call it once per panel, in order, starting with panel 1.`,parameters:{type:`object`,properties:{storyboardId:{type:`string`,description:`The storyboardId defineStoryboard returned.`},panel:{type:`integer`,description:`This panel's number, starting at 1.`},characters:{type:`array`,items:{type:`string`},description:`The names (as in defineStoryboard) of the characters in this panel.`},imagePrompt:{type:`string`,description:`What the panel shows: the setting, what happens, expressions and the camera angle. Refer to characters by name; don't describe their looks again.`},caption:{type:`string`,description:`One short line shown under the picture.`},choices:{type:`array`,items:{type:`string`},description:`Only in an interactive story, and not on the last panel: two or three short options for what happens next. The story waits for the user's pick.`}},required:[`storyboardId`,`panel`,`characters`,`imagePrompt`]}},I=e=>typeof e==`object`&&!!e&&!Array.isArray(e),ae=e=>I(e)&&typeof e.message==`string`;function L(e){let t=I(e?.data)?e.data:{};return{...typeof t.imageData==`string`&&{imageData:t.imageData},...typeof t.imagePath==`string`&&{imagePath:t.imagePath}}}function R(e){let t=I(e?.data)?e.data:{};return typeof t.html==`string`?t.html:``}var oe=e=>!!L(e).imageData||!!R(e);function se(e,t){let n=L(e),r=L(t);if(n.imagePath&&r.imagePath)return n.imagePath===r.imagePath;if(n.imageData)return n.imageData===r.imageData;let i=R(e);return!!i&&i===R(t)}var ce=(e,t)=>e.userSpokeAt===void 0||e.userSpokeAt>t,z=()=>crypto.randomUUID().replace(/-/g,``).slice(0,12),le=`artifacts/`;async function B(e,t){let n=e.files?.artifacts;if(!e.app?.editImages||!n)return[];let r=[];for(let e of t)if(e.startsWith(le))try{await n.exists(e.slice(10))&&r.push(e)}catch{}return r}async function V(e,t,n=[]){let r=e.app,i=r?.editImages,a=r?.generateImage;try{let e;if(n.length&&i)e=await i(t,[...n]);else if(a)e=await a(t);else return{message:`image generation isn't available`};return ae(e)?e:{message:`image generation returned an unrecognized result`}}catch(e){return{message:`image generation failed: ${e instanceof Error?e.message:String(e)}`}}}var ue=50;function H(e){let t=new Map;return n=>{let r=n.conversationId??``,i=t.get(r);if(i===void 0?i=e():t.delete(r),t.set(r,i),t.size>ue){let e=t.keys().next().value;e!==void 0&&t.delete(e)}return i}}var U=`slideshows`,W=`storyboards`,G={},K=new WeakMap,q=new WeakMap;function J(e){let t=K.get(e);return t||K.set(e,t=new Map),t}function de(t,n){let r=q.get(t);r||q.set(t,r=new Map);let i=r.get(n);return i||r.set(n,i=(0,e.createSerialLock)()),i}var Y=(e,t)=>`${e}/${t}.json`;async function X(e,t){let n=J(e??G),r=n.get(t);if(r)return r;if(!e)return null;try{let r=JSON.parse(await e.read(t));return n.set(t,r),r}catch{return null}}async function Z(e,t,n){return _.test(n)?X(e,Y(t,n)):null}async function Q(e,t,n,r){let i=Y(t,n),a=e??G;return de(a,i)(async()=>{let t=r(await X(e,i));if(J(a).set(i,t),!e)return!1;try{return await e.write(i,JSON.stringify(t,null,2)),!0}catch(e){return console.warn(`[sequence] could not save`,i,e),!1}})}var $=e=>`the ${e} could not be saved, so it lasts only until the app or server restarts`,fe=6e4;function pe(){let e=new Map;return{claim:t=>{let n=Date.now();for(let[t,r]of e)n-r.at>fe&&e.delete(t);let r=e.get(t);if(r)return{earlier:r.shown};let i=()=>void 0,a=new Promise(e=>i=e);return e.set(t,{at:n,shown:a}),{settle:n=>{!n&&e.get(t)?.shown===a&&e.delete(t),i(n)}}}}}function me({slide:e,totalSlides:t,mode:n}){return n===`steps`?{step:e,total:t,kind:`guide`,label:`Step ${e} of ${t}`,onShown:`explain it`,nextCall:`call presentSlide for step ${e+1} of ${t} with mode "steps"`,waitsForUser:!0}:{step:e,total:t,kind:`slideshow`,label:`Slide ${e} of ${t}`,onShown:`explain it`,nextCall:`call presentSlide for slide ${e+1} of ${t}`}}var he=(e,{slide:t,totalSlides:n,title:r,imagePrompt:i,html:a})=>JSON.stringify([e,t,n,r,i,a]),ge=H(()=>({latest:{presentation:null,steps:null},lastShown:null,repeats:pe()}));function _e(e,t){let n=e.latest[t.mode],r=n?.totalSlides===t.totalSlides&&(t.slide!==1||n.firstTitle===t.title);if(n&&r)return n;let i={id:z(),mode:t.mode,totalSlides:t.totalSlides,firstTitle:t.slide===1?t.title:``,slides:new Map,current:0,shownAt:-1/0};return e.latest[t.mode]=i,i}function ve(e,t,n,r){t.current=n.slide,t.shownAt=Date.now(),e.lastShown=t;let i=n.mode===`steps`?`step`:`slide`,{uuid:a,...o}=r;return{...o,message:`${i} ${n.slide} of ${n.totalSlides} is on the screen again, as it was`,instructions:T(n),instructionsRequired:!0,sequence:me(n)}}function ye(e,t){if(e.mode!==`steps`)return e.title?`A presentation slide titled "${e.title}". ${e.imagePrompt}`:e.imagePrompt;let n=e.title?`, "${e.title}"`:``;return[`An instructional illustration of step ${e.slide} of ${e.totalSlides}${n}. ${e.imagePrompt}`,t?`The reference image is the previous step: keep the same objects, hands, tools and setting, and show what this step changes.`:``,`Show the action clearly, with little or no text.`].filter(Boolean).join(` `)}async function be(e,t,n){if(n.html)return{html:n.html,prompt:``};let r=t.slides.get(n.slide-1),i=n.mode===`steps`?L(r).imagePath:void 0,a=i?await B(e,[i]):[],o=ye(n,a.length>0),s=await V(e,o,a),{imageData:c,imagePath:l}=L(s);return c?{imageData:c,...l&&{imagePath:l},prompt:o}:{failed:{...s,sequence:null}}}async function xe(e,t,n){let r=await be(e,t,n);if(`failed`in r)return r.failed;let{imageData:i,imagePath:a,html:o,prompt:s}=r,c=t.id,l=await Q(e.files?.artifacts,U,c,e=>{let t=e??{id:c,title:``,mode:n.mode,totalSlides:n.totalSlides,slides:{}};return n.slide===1&&(t.title=n.title),t.slides[String(n.slide)]={title:n.title,imagePrompt:n.imagePrompt,...a&&{imagePath:a},...o&&{html:o}},t}),u={...i&&{imageData:i},...a&&{imagePath:a},...o&&{html:o},prompt:s,slideshowId:c,slide:n.slide,totalSlides:n.totalSlides,title:n.title,mode:n.mode},d=n.mode===`steps`?`step`:`slide`;return{data:u,title:n.title||`Slide ${n.slide}`,message:[`${d} ${n.slide} of ${n.totalSlides} of slideshow "${c}" is on the screen`,a?`saved to ${a}`:``,l?``:$(`slideshow`)].filter(Boolean).join(`; `),instructions:T(n),instructionsRequired:!0,sequence:me(n)}}async function Se(e,t){let n=C(t);if(typeof n==`string`)return{message:n,sequence:null};let r=ge(e),i=_e(r,n),a=n.mode===`steps`;if(a&&n.slide>i.current&&i.current>0&&!ce(e,i.shownAt)){console.info(`[sequence] holding step ${n.slide} for the user`);let e=i.shownAt===1/0?`is still being drawn`:`is still on the screen`;return{message:`step ${n.slide} was not shown: the user hasn't said they're ready yet, and step ${i.current} ${e}. Wait for them before calling presentSlide for step ${n.slide}.`,cancelled:!0}}let o=a?i.slides.get(n.slide):void 0;if(o)return se(e.currentResult,o)?{message:`step ${n.slide} of ${n.totalSlides} is already on the screen`,cancelled:!0}:ve(r,i,n,o);let s=r.repeats.claim(he(i.id,n));if(`earlier`in s){if(!await s.earlier)return Se(e,t);let a=i.slides.get(n.slide);return a&&r.lastShown!==i?ve(r,i,n,a):{message:`slide ${n.slide} of ${n.totalSlides} is already on the screen`,cancelled:!0}}let{settle:c}=s,l={current:i.current,shownAt:i.shownAt};i.current=n.slide,i.shownAt=1/0;let u=!1;try{let t=await xe(e,i,n);return u=oe(t),u&&(i.slides.set(n.slide,t),i.current=n.slide,i.shownAt=Date.now(),r.lastShown=i),t}finally{c(u),!u&&i.current===n.slide&&(i.current=l.current,i.shownAt=l.shownAt)}}var Ce=({id:e,title:t,totalPanels:n})=>({step:0,total:n,kind:`story`,label:`The cast of "${t}"`,onShown:`introduce the characters`,nextCall:`call presentPanel for panel 1 of ${n} with storyboardId "${e}"`}),we=({id:e,totalPanels:t},n,r)=>({step:n,total:t,kind:`story`,label:`Panel ${n} of ${t}`,onShown:`tell that part of the story`,nextCall:`call presentPanel for panel ${n+1} of ${t} with storyboardId "${e}"`,...r.length>0&&{waitsForUser:!0}}),Te=(e,t)=>e?`${e}. ${t}`:t,Ee=(e,{name:t,description:n})=>Te(e,`Character reference sheet of ${t}: ${n}. Full body, front, side and back views, on a plain white background. No text or labels.`);async function De(e,t){let n=O(t);if(typeof n==`string`)return{message:n,sequence:null};let r=await Promise.all(n.characters.map(t=>V(e,Ee(n.style,t)))),i=r.map(L),a=r.find((e,t)=>!i[t]?.imageData);if(i.every(({imageData:e})=>!e)&&a)return{...a,message:`the character sheets couldn't be made: ${a.message}`,sequence:null};let o={id:z(),...n,characters:n.characters.map((e,t)=>{let n=i[t]?.imagePath;return{...e,...n&&{imagePath:n}}}),panels:{}},s=await Q(e.files?.artifacts,W,o.id,()=>o),c=o.characters.filter(e=>e.imagePath).map(e=>`${e.name}: ${e.imagePath}`),l=n.characters.map(({name:e},t)=>i[t]?.imageData?null:`${e} (${r[t]?.message??``})`).filter(e=>!!e),u=i.find(e=>e.imageData)?.imageData;return{data:{storyboardId:o.id,title:o.title,totalPanels:o.totalPanels,...u&&{imageData:u},characters:o.characters.map(({name:e,imagePath:t},n)=>{let r=i[n]?.imageData;return{name:e,...r&&{imageData:r},...t&&{imagePath:t}}})},title:o.title,message:[`storyboard "${o.id}" is ready with ${o.totalPanels} panels; the cast is on the screen`,c.length?`character sheets saved to ${c.join(`, `)}`:``,l.length?`no sheet for ${l.join(`; `)}: they will be drawn from their description`:``,s?``:$(`storyboard`)].filter(Boolean).join(`; `),instructions:k(o),instructionsRequired:!0,sequence:Ce(o)}}function Oe(e,t,n){let r=[Te(e.style,`Panel ${t.panel} of ${e.totalPanels} of the illustrated story "${e.title}". ${t.imagePrompt}`)],i=0,a=n.map(({character:e,hasSheet:t})=>t?`${e.name} is the character in reference image ${++i}`:`${e.name}: ${e.description}`);return a.length&&r.push(`${a.join(`. `)}.`),i&&r.push(`Draw each character exactly as in their reference image: the same face, hair, clothes and colors. Use the reference images only for how the characters look, not for their pose or the background.`),r.push(`No captions, speech bubbles or other text in the picture.`),r.join(` `)}async function ke(e,t,n){let r=[],i=[];for(let a of n.characters){let n=t.characters.find(e=>b(e.name,a));if(!n)r.push(a);else if(!i.some(e=>e.character===n)){let[t]=n.imagePath?await B(e,[n.imagePath]):[];i.push({character:n,sheet:t??null})}}let a=i.map(({sheet:e})=>e).filter(e=>!!e),o=Oe(t,n,i.map(({character:e,sheet:t})=>({character:e,hasSheet:!!t}))),s=await V(e,o,a),{imageData:c,imagePath:l}=L(s);if(!c)return{...s,sequence:null};let u=n.panel<t.totalPanels&&n.choices.length>=2?n.choices:[],d=await Q(e.files?.artifacts,W,t.id,e=>{let r=e??t;return u.length&&(r.interactive=!0),r.panels[String(n.panel)]={caption:n.caption,characters:i.map(({character:e})=>e.name),imagePrompt:n.imagePrompt,...l&&{imagePath:l},...u.length&&{choices:u}},r});return{data:{imageData:c,...l&&{imagePath:l},prompt:o,storyboardId:t.id,panel:n.panel,totalPanels:t.totalPanels,caption:n.caption,...u.length&&{choices:u}},title:n.caption||`Panel ${n.panel}`,message:[`panel ${n.panel} of ${t.totalPanels} is on the screen`,l?`saved to ${l}`:``,r.length?`not in the cast, so drawn from the prompt alone: ${r.join(`, `)}`:``,d?``:$(`storyboard`)].filter(Boolean).join(`; `),instructions:M(t,n.panel,u),instructionsRequired:!0,sequence:we(t,n.panel,u)}}var Ae=H(()=>({repeats:pe(),awaitingChoice:new Map}));async function je(e,t){let n=j(t);if(!n)return{message:A,sequence:null};let{storyboardId:r,panel:i}=n,{repeats:a,awaitingChoice:o}=Ae(e),s=o.get(r);if(s&&i>s.panel&&!ce(e,s.shownAt))return console.info(`[sequence] holding panel ${i} for the user`),{message:s.shownAt===1/0?`panel ${i} was not shown: panel ${s.panel} is still being drawn. Wait for it before going on.`:`panel ${i} was not shown: the user hasn't picked a choice yet, and panel ${s.panel} is still on the screen. Wait for their answer.`,cancelled:!0};let c=a.claim(JSON.stringify(n));if(`earlier`in c)return await c.earlier?{message:`panel ${i} is already on the screen`,cancelled:!0}:je(e,t);let{settle:l}=c,u={panel:i,shownAt:1/0},d=o.get(r);o.set(r,u);let f=()=>o.get(r)===u,p=!1;try{let t=await Z(e.files?.artifacts,W,r);if(!t)return{message:`there is no storyboard "${r}"; call defineStoryboard first`,sequence:null};if(i>t.totalPanels)return{message:`storyboard "${t.id}" has ${t.totalPanels} panels`,sequence:null};let a=await ke(e,t,n);p=!!L(a).imageData;let s=a.data;return p&&f()&&(s?.choices?.length?o.set(r,{panel:i,shownAt:Date.now()}):o.delete(r)),a}finally{l(p),!p&&f()&&(d?o.set(r,d):o.delete(r))}}var Me={toolDefinition:D,generatingMessage:`Making the slide...`,isEnabled:()=>!0,execute:(e,t)=>Se(e,t)},Ne={toolDefinition:P,generatingMessage:`Drawing the characters...`,isEnabled:()=>!0,execute:(e,t)=>De(e,t)},Pe={toolDefinition:F,generatingMessage:`Drawing the panel...`,isEnabled:()=>!0,execute:(e,t)=>je(e,t)};Object.defineProperty(exports,"A",{enumerable:!0,get:function(){return o}}),Object.defineProperty(exports,"C",{enumerable:!0,get:function(){return M}}),Object.defineProperty(exports,"D",{enumerable:!0,get:function(){return b}}),Object.defineProperty(exports,"E",{enumerable:!0,get:function(){return O}}),Object.defineProperty(exports,"F",{enumerable:!0,get:function(){return p}}),Object.defineProperty(exports,"M",{enumerable:!0,get:function(){return d}}),Object.defineProperty(exports,"N",{enumerable:!0,get:function(){return n}}),Object.defineProperty(exports,"O",{enumerable:!0,get:function(){return T}}),Object.defineProperty(exports,"P",{enumerable:!0,get:function(){return t}}),Object.defineProperty(exports,"S",{enumerable:!0,get:function(){return k}}),Object.defineProperty(exports,"T",{enumerable:!0,get:function(){return C}}),Object.defineProperty(exports,"_",{enumerable:!0,get:function(){return E}}),Object.defineProperty(exports,"a",{enumerable:!0,get:function(){return W}}),Object.defineProperty(exports,"b",{enumerable:!0,get:function(){return re}}),Object.defineProperty(exports,"c",{enumerable:!0,get:function(){return P}}),Object.defineProperty(exports,"d",{enumerable:!0,get:function(){return te}}),Object.defineProperty(exports,"f",{enumerable:!0,get:function(){return A}}),Object.defineProperty(exports,"g",{enumerable:!0,get:function(){return D}}),Object.defineProperty(exports,"h",{enumerable:!0,get:function(){return m}}),Object.defineProperty(exports,"i",{enumerable:!0,get:function(){return U}}),Object.defineProperty(exports,"j",{enumerable:!0,get:function(){return s}}),Object.defineProperty(exports,"k",{enumerable:!0,get:function(){return r}}),Object.defineProperty(exports,"l",{enumerable:!0,get:function(){return ee}}),Object.defineProperty(exports,"m",{enumerable:!0,get:function(){return F}}),Object.defineProperty(exports,"n",{enumerable:!0,get:function(){return Pe}}),Object.defineProperty(exports,"o",{enumerable:!0,get:function(){return Z}}),Object.defineProperty(exports,"p",{enumerable:!0,get:function(){return g}}),Object.defineProperty(exports,"r",{enumerable:!0,get:function(){return Me}}),Object.defineProperty(exports,"s",{enumerable:!0,get:function(){return h}}),Object.defineProperty(exports,"t",{enumerable:!0,get:function(){return Ne}}),Object.defineProperty(exports,"u",{enumerable:!0,get:function(){return ne}}),Object.defineProperty(exports,"v",{enumerable:!0,get:function(){return _}}),Object.defineProperty(exports,"w",{enumerable:!0,get:function(){return j}}),Object.defineProperty(exports,"x",{enumerable:!0,get:function(){return N}}),Object.defineProperty(exports,"y",{enumerable:!0,get:function(){return S}});
@@ -35,10 +35,10 @@ ${u(e)}
35
35
  }
36
36
  //#endregion
37
37
  //#region src/core/definitions.ts
38
- var m = "presentSlide", h = "defineStoryboard", g = "presentPanel", ee = 4, te = 12, ne = 3, _ = /^[0-9a-f]{12}$/, v = (e) => typeof e == "object" && !!e && !Array.isArray(e), y = (e) => typeof e == "string" ? e.trim() : "", b = (e, t) => e.toLowerCase() === t.toLowerCase(), x = (e) => typeof e == "number" && Number.isInteger(e), S = "presentSlide needs slide and totalSlides (whole numbers, slide from 1 to totalSlides), and either an imagePrompt or html", C = `presentSlide's html is too long: keep a slide under ${r} characters`;
39
- function w(e) {
38
+ var m = "presentSlide", h = "defineStoryboard", g = "presentPanel", ee = 4, te = 12, ne = 3, _ = /^[0-9a-f]{12}$/, v = (e) => typeof e == "object" && !!e && !Array.isArray(e), y = (e) => typeof e == "string" ? e.trim() : "", b = (e, t) => e.toLowerCase() === t.toLowerCase(), x = (e) => typeof e == "number" && Number.isInteger(e), S = "presentSlide needs slide and totalSlides (whole numbers, slide from 1 to totalSlides), and either an imagePrompt or html", re = `presentSlide's html is too long: keep a slide under ${r} characters`;
39
+ function C(e) {
40
40
  let { slide: t, totalSlides: n, title: r, imagePrompt: i } = e, a = y(e.html);
41
- return !x(t) || !x(n) || t < 1 || n < t || !a && !y(i) ? S : a.length > 6e4 ? C : {
41
+ return !x(t) || !x(n) || t < 1 || n < t || !a && !y(i) ? S : a.length > 6e4 ? re : {
42
42
  slide: t,
43
43
  totalSlides: n,
44
44
  title: typeof r == "string" ? r : "",
@@ -47,22 +47,22 @@ function w(e) {
47
47
  mode: e.mode === "steps" ? "steps" : "presentation"
48
48
  };
49
49
  }
50
- var T = ({ slide: e, totalSlides: t, title: n, mode: r }) => {
50
+ var w = "teach its subject in at least two sentences, as a presenter speaking to the audience. Begin with the content itself, never with the slide or your plan: no \"This slide is about…\", \"The first slide shows…\", \"Let's unpack this one\", \"Next, I'll…\". A line about the slide is not an explanation.", T = ({ slide: e, totalSlides: t, title: n, mode: r }) => {
51
51
  let i = n ? ` ("${n}")` : "";
52
52
  if (r === "steps") {
53
53
  let n = `Step ${e} of ${t}${i}`;
54
- return e < t ? `${n} is now on the screen. Explain what to do in this step, then stop and wait while the user does it. When they say they're ready (next, done, go on), call presentSlide for step ${e + 1} with mode "steps". If they ask to go back or to see a step again, call presentSlide for that step.` : `${n}, the last one, is now on the screen. Explain what to do, then wrap up the guide once the user is done.`;
54
+ return e < t ? `${n} is now on the screen. Say what to do in this step, directly ("Crack two eggs into a bowl…", not "This step is about eggs"), then stop and wait while the user does it. When they say they're ready (next, done, go on), call presentSlide for step ${e + 1} with mode "steps". If they ask to go back or to see a step again, call presentSlide for that step.` : `${n}, the last one, is now on the screen. Say what to do, directly, then wrap up the guide once the user is done.`;
55
55
  }
56
56
  let a = `Slide ${e} of ${t}${i}`;
57
- return e < t ? `${a} is now on the screen. Explain it, then, in this same reply and without waiting for the user, call presentSlide for slide ${e + 1}. If the user has asked you to stop, or asked something else, since the slideshow began, answer them instead of going on.` : `${a}, the last one, is now on the screen. Explain it, then wrap up the slideshow.`;
58
- }, re = [
57
+ return e < t ? `${a} is now on the screen. Explain it: ${w} Then, in this same reply and without waiting for the user, call presentSlide for slide ${e + 1}. If the user has asked you to stop, or asked something else, since the slideshow began, answer them instead of going on.` : `${a}, the last one, is now on the screen. Explain it: ${w} Then wrap up the slideshow.`;
58
+ }, ie = [
59
59
  `For an HTML slide, instead of imagePrompt: the slide's content, the inside of <body> only (no <html>, <head> or <body> tags), for a ${t}x720 px canvas, which it should fill (start with a <div class="w-full h-full ...">). Style it with Tailwind CSS v4 classes, which are loaded for you: a clear layout, a large title (text-6xl or so), few words in large type, a color scheme, and inline SVG or emoji for icons and diagrams. There is no network: no <img> from URLs, no links to follow.`,
60
60
  "Animate it so it builds up as you explain it, with MulmoCast's data-animation attributes (the same ones make it move in a movie of the slideshow): data-animation=\"animate\" with data-opacity=\"0,1\", data-translate-x, data-translate-y (px), data-scale, data-rotate (deg), data-width or data-height (\"0,80,%\"), each \"from,to\"; data-animation=\"counter\" with data-from, data-to, data-decimals, data-prefix, data-suffix; data-animation=\"typewriter\" (its text, or data-text). Give every one data-start and data-end in seconds, and optionally data-easing (linear, easeIn, easeOut, easeInOut); stagger the parts with later data-start values so they appear one after another over a few seconds (for example 0, 0.6, 1.2). Set the first frame inline too (style=\"opacity:0\" on an element that fades in).",
61
61
  "CSS animations, transitions and scripts don't play: animate only with data-animation. A <style> for layout is allowed (and Google Fonts by @import)."
62
- ].join(" "), ie = "When the user asks for a slideshow (or to explain something with slides), plan four to six slides, then show them one at a time with presentSlide: slide 1 first, and each next slide only after you have explained the one on the screen. Go on to the last slide without asking whether to continue. A slide is a generated picture (imagePrompt) or a designed slide in HTML (html): use a picture for a scene, an object or a place, and HTML for words, numbers, lists, comparisons, timelines and diagrams, which a picture model draws badly; a slideshow can mix them. When the user asks for HTML slides (slides in HTML, an HTML presentation), this is the tool: make them HTML slides with presentSlide, one call per slide, not one HTML page. When the user wants to be shown how to do something they will do along with you (cooking, folding, fixing, an exercise), make it a step-by-step guide instead: mode \"steps\", one slide per step, and after each step wait for the user to say they are ready. Use generateImage for a single picture, not for slides.", E = {
62
+ ].join(" "), E = "When the user asks for a slideshow (or to explain something with slides), plan four to six slides, then show them one at a time with presentSlide: slide 1 first, and each next slide only after you have explained the one on the screen. Explain the subject, not the slides: say what the slide teaches, not that a slide is about it. Go on to the last slide without asking whether to continue. A slide is a generated picture (imagePrompt) or a designed slide in HTML (html): use a picture for a scene, an object or a place, and HTML for words, numbers, lists, comparisons, timelines and diagrams, which a picture model draws badly; a slideshow can mix them. When the user asks for HTML slides (slides in HTML, an HTML presentation), this is the tool: make them HTML slides with presentSlide, one call per slide, not one HTML page. When the user wants to be shown how to do something they will do along with you (cooking, folding, fixing, an exercise), make it a step-by-step guide instead: mode \"steps\", one slide per step, and after each step wait for the user to say they are ready. Use generateImage for a single picture, not for slides.", D = {
63
63
  type: "function",
64
64
  name: m,
65
- prompt: ie,
65
+ prompt: E,
66
66
  description: "Show one slide of a slideshow, full screen: a picture generated from imagePrompt, or a slide written in HTML (html). Call it once per slide, in order, starting with slide 1. With mode \"steps\" it is a step-by-step guide: one slide per step, and the next step waits for the user.",
67
67
  parameters: {
68
68
  type: "object",
@@ -85,7 +85,7 @@ var T = ({ slide: e, totalSlides: t, title: n, mode: r }) => {
85
85
  },
86
86
  html: {
87
87
  type: "string",
88
- description: re
88
+ description: ie
89
89
  },
90
90
  mode: {
91
91
  type: "string",
@@ -100,7 +100,7 @@ var T = ({ slide: e, totalSlides: t, title: n, mode: r }) => {
100
100
  ]
101
101
  }
102
102
  };
103
- function D(e) {
103
+ function O(e) {
104
104
  let { totalPanels: t } = e;
105
105
  if (!x(t) || t < 1 || t > 12) return "totalPanels must be a whole number from 1 to 12";
106
106
  let n = [];
@@ -121,8 +121,8 @@ function D(e) {
121
121
  interactive: e.interactive === !0
122
122
  };
123
123
  }
124
- var O = ({ title: e, id: t }) => `The cast of "${e}" is now on the screen. Introduce the characters briefly, then, in this same reply and without waiting for the user, call presentPanel for panel 1 with storyboardId "${t}". If the user has asked you to stop, or asked something else, answer them instead of going on.`, k = "presentPanel needs a storyboardId, a panel number (from 1) and an imagePrompt";
125
- function A(e) {
124
+ var k = ({ title: e, id: t }) => `The cast of "${e}" is now on the screen. Introduce the characters briefly, then, in this same reply and without waiting for the user, call presentPanel for panel 1 with storyboardId "${t}". If the user has asked you to stop, or asked something else, answer them instead of going on.`, A = "presentPanel needs a storyboardId, a panel number (from 1) and an imagePrompt";
125
+ function j(e) {
126
126
  let { panel: t } = e, n = y(e.storyboardId), r = y(e.imagePrompt);
127
127
  if (!n || !r || !x(t) || t < 1) return null;
128
128
  let i = (e) => (Array.isArray(e) ? e : []).map(y).filter(Boolean);
@@ -135,14 +135,14 @@ function A(e) {
135
135
  choices: i(e.choices).slice(0, 3)
136
136
  };
137
137
  }
138
- function j(e, t, n) {
138
+ function M(e, t, n) {
139
139
  let { id: r, totalPanels: i } = e;
140
140
  return n.length ? `Panel ${t} of ${i} is now on the screen, with the user's choices: ${n.map((e, t) => `${t + 1}. ${e}`).join(" ")} Tell this part of the story, then read the choices out and ask the user which one they pick, and wait for their answer. Then call presentPanel for panel ${t + 1} with storyboardId "${r}", going on the way they chose.` : t < i ? `Panel ${t} of ${i} is now on the screen. Tell this part of the story, then, in this same reply and without waiting for the user, call presentPanel for panel ${t + 1} with storyboardId "${r}". If the user has asked you to stop, or asked something else, since the story began, answer them instead of going on.` : `Panel ${t} of ${i}, the last one, is now on the screen. Tell this part of the story, then bring it to an end.`;
141
141
  }
142
- var M = "When the user asks for a story, a picture book, a comic or a storyboard, tell it in pictures: first call defineStoryboard with the art style and the characters who appear more than once (it draws a reference sheet for each, so they look the same in every panel), then show the panels one at a time with presentPanel, naming the characters in each, and tell each part of the story when its panel appears. Go on to the last panel without asking whether to continue, unless the story is interactive. When the user wants to decide what happens (an adventure, a story for a child who wants to choose), set interactive, and give two or three choices on two or three of the panels: the story waits there for the user's pick and goes on their way; it still ends at the last panel whichever way it goes. Use presentSlide to explain a topic, not to tell a story.", N = {
142
+ var N = "When the user asks for a story, a picture book, a comic or a storyboard, tell it in pictures: first call defineStoryboard with the art style and the characters who appear more than once (it draws a reference sheet for each, so they look the same in every panel), then show the panels one at a time with presentPanel, naming the characters in each, and tell each part of the story when its panel appears. Go on to the last panel without asking whether to continue, unless the story is interactive. When the user wants to decide what happens (an adventure, a story for a child who wants to choose), set interactive, and give two or three choices on two or three of the panels: the story waits there for the user's pick and goes on their way; it still ends at the last panel whichever way it goes. Use presentSlide to explain a topic, not to tell a story.", P = {
143
143
  type: "function",
144
144
  name: h,
145
- prompt: M,
145
+ prompt: N,
146
146
  description: "Start a story told in pictures: set its art style and draw a reference sheet for each recurring character, shown as the cast. Then call presentPanel for each panel, in order.",
147
147
  parameters: {
148
148
  type: "object",
@@ -189,7 +189,7 @@ var M = "When the user asks for a story, a picture book, a comic or a storyboard
189
189
  "characters"
190
190
  ]
191
191
  }
192
- }, P = {
192
+ }, F = {
193
193
  type: "function",
194
194
  name: g,
195
195
  description: "Show one panel of a storyboard made with defineStoryboard: a picture of the scene with its characters drawn as in their reference sheets, and a caption. Call it once per panel, in order, starting with panel 1.",
@@ -230,32 +230,32 @@ var M = "When the user asks for a story, a picture book, a comic or a storyboard
230
230
  "imagePrompt"
231
231
  ]
232
232
  }
233
- }, F = (e) => typeof e == "object" && !!e && !Array.isArray(e), ae = (e) => F(e) && typeof e.message == "string";
234
- function I(e) {
235
- let t = F(e?.data) ? e.data : {};
233
+ }, I = (e) => typeof e == "object" && !!e && !Array.isArray(e), ae = (e) => I(e) && typeof e.message == "string";
234
+ function L(e) {
235
+ let t = I(e?.data) ? e.data : {};
236
236
  return {
237
237
  ...typeof t.imageData == "string" && { imageData: t.imageData },
238
238
  ...typeof t.imagePath == "string" && { imagePath: t.imagePath }
239
239
  };
240
240
  }
241
- function L(e) {
242
- let t = F(e?.data) ? e.data : {};
241
+ function R(e) {
242
+ let t = I(e?.data) ? e.data : {};
243
243
  return typeof t.html == "string" ? t.html : "";
244
244
  }
245
- var oe = (e) => !!I(e).imageData || !!L(e);
245
+ var oe = (e) => !!L(e).imageData || !!R(e);
246
246
  function se(e, t) {
247
- let n = I(e), r = I(t);
247
+ let n = L(e), r = L(t);
248
248
  if (n.imagePath && r.imagePath) return n.imagePath === r.imagePath;
249
249
  if (n.imageData) return n.imageData === r.imageData;
250
- let i = L(e);
251
- return !!i && i === L(t);
250
+ let i = R(e);
251
+ return !!i && i === R(t);
252
252
  }
253
- var R = (e, t) => e.userSpokeAt === void 0 || e.userSpokeAt > t, z = () => crypto.randomUUID().replace(/-/g, "").slice(0, 12), ce = "artifacts/";
253
+ var ce = (e, t) => e.userSpokeAt === void 0 || e.userSpokeAt > t, z = () => crypto.randomUUID().replace(/-/g, "").slice(0, 12), le = "artifacts/";
254
254
  async function B(e, t) {
255
255
  let n = e.files?.artifacts;
256
256
  if (!e.app?.editImages || !n) return [];
257
257
  let r = [];
258
- for (let e of t) if (e.startsWith(ce)) try {
258
+ for (let e of t) if (e.startsWith(le)) try {
259
259
  await n.exists(e.slice(10)) && r.push(e);
260
260
  } catch {}
261
261
  return r;
@@ -272,12 +272,12 @@ async function V(e, t, n = []) {
272
272
  return { message: `image generation failed: ${e instanceof Error ? e.message : String(e)}` };
273
273
  }
274
274
  }
275
- var le = 50;
276
- function ue(e) {
275
+ var ue = 50;
276
+ function H(e) {
277
277
  let t = /* @__PURE__ */ new Map();
278
278
  return (n) => {
279
279
  let r = n.conversationId ?? "", i = t.get(r);
280
- if (i === void 0 ? i = e() : t.delete(r), t.set(r, i), t.size > le) {
280
+ if (i === void 0 ? i = e() : t.delete(r), t.set(r, i), t.size > ue) {
281
281
  let e = t.keys().next().value;
282
282
  e !== void 0 && t.delete(e);
283
283
  }
@@ -286,20 +286,20 @@ function ue(e) {
286
286
  }
287
287
  //#endregion
288
288
  //#region src/core/records.ts
289
- var H = "slideshows", U = "storyboards", W = {}, G = /* @__PURE__ */ new WeakMap(), K = /* @__PURE__ */ new WeakMap();
290
- function q(e) {
291
- let t = G.get(e);
292
- return t || G.set(e, t = /* @__PURE__ */ new Map()), t;
289
+ var U = "slideshows", W = "storyboards", G = {}, K = /* @__PURE__ */ new WeakMap(), q = /* @__PURE__ */ new WeakMap();
290
+ function J(e) {
291
+ let t = K.get(e);
292
+ return t || K.set(e, t = /* @__PURE__ */ new Map()), t;
293
293
  }
294
294
  function de(t, n) {
295
- let r = K.get(t);
296
- r || K.set(t, r = /* @__PURE__ */ new Map());
295
+ let r = q.get(t);
296
+ r || q.set(t, r = /* @__PURE__ */ new Map());
297
297
  let i = r.get(n);
298
298
  return i || r.set(n, i = e()), i;
299
299
  }
300
- var J = (e, t) => `${e}/${t}.json`;
301
- async function Y(e, t) {
302
- let n = q(e ?? W), r = n.get(t);
300
+ var Y = (e, t) => `${e}/${t}.json`;
301
+ async function X(e, t) {
302
+ let n = J(e ?? G), r = n.get(t);
303
303
  if (r) return r;
304
304
  if (!e) return null;
305
305
  try {
@@ -309,14 +309,14 @@ async function Y(e, t) {
309
309
  return null;
310
310
  }
311
311
  }
312
- async function X(e, t, n) {
313
- return _.test(n) ? Y(e, J(t, n)) : null;
312
+ async function Z(e, t, n) {
313
+ return _.test(n) ? X(e, Y(t, n)) : null;
314
314
  }
315
- async function Z(e, t, n, r) {
316
- let i = J(t, n), a = e ?? W;
315
+ async function Q(e, t, n, r) {
316
+ let i = Y(t, n), a = e ?? G;
317
317
  return de(a, i)(async () => {
318
- let t = r(await Y(e, i));
319
- if (q(a).set(i, t), !e) return !1;
318
+ let t = r(await X(e, i));
319
+ if (J(a).set(i, t), !e) return !1;
320
320
  try {
321
321
  return await e.write(i, JSON.stringify(t, null, 2)), !0;
322
322
  } catch (e) {
@@ -324,8 +324,8 @@ async function Z(e, t, n, r) {
324
324
  }
325
325
  });
326
326
  }
327
- var Q = (e) => `the ${e} could not be saved, so it lasts only until the app or server restarts`, fe = 6e4;
328
- function $() {
327
+ var $ = (e) => `the ${e} could not be saved, so it lasts only until the app or server restarts`, fe = 6e4;
328
+ function pe() {
329
329
  let e = /* @__PURE__ */ new Map();
330
330
  return { claim: (t) => {
331
331
  let n = Date.now();
@@ -343,7 +343,7 @@ function $() {
343
343
  }
344
344
  //#endregion
345
345
  //#region src/core/presentSlide.ts
346
- function pe({ slide: e, totalSlides: t, mode: n }) {
346
+ function me({ slide: e, totalSlides: t, mode: n }) {
347
347
  return n === "steps" ? {
348
348
  step: e,
349
349
  total: t,
@@ -361,22 +361,22 @@ function pe({ slide: e, totalSlides: t, mode: n }) {
361
361
  nextCall: `call presentSlide for slide ${e + 1} of ${t}`
362
362
  };
363
363
  }
364
- var me = (e, { slide: t, totalSlides: n, title: r, imagePrompt: i, html: a }) => JSON.stringify([
364
+ var he = (e, { slide: t, totalSlides: n, title: r, imagePrompt: i, html: a }) => JSON.stringify([
365
365
  e,
366
366
  t,
367
367
  n,
368
368
  r,
369
369
  i,
370
370
  a
371
- ]), he = ue(() => ({
371
+ ]), ge = H(() => ({
372
372
  latest: {
373
373
  presentation: null,
374
374
  steps: null
375
375
  },
376
376
  lastShown: null,
377
- repeats: $()
377
+ repeats: pe()
378
378
  }));
379
- function ge(e, t) {
379
+ function _e(e, t) {
380
380
  let n = e.latest[t.mode], r = n?.totalSlides === t.totalSlides && (t.slide !== 1 || n.firstTitle === t.title);
381
381
  if (n && r) return n;
382
382
  let i = {
@@ -390,7 +390,7 @@ function ge(e, t) {
390
390
  };
391
391
  return e.latest[t.mode] = i, i;
392
392
  }
393
- function _e(e, t, n, r) {
393
+ function ve(e, t, n, r) {
394
394
  t.current = n.slide, t.shownAt = Date.now(), e.lastShown = t;
395
395
  let i = n.mode === "steps" ? "step" : "slide", { uuid: a, ...o } = r;
396
396
  return {
@@ -398,10 +398,10 @@ function _e(e, t, n, r) {
398
398
  message: `${i} ${n.slide} of ${n.totalSlides} is on the screen again, as it was`,
399
399
  instructions: T(n),
400
400
  instructionsRequired: !0,
401
- sequence: pe(n)
401
+ sequence: me(n)
402
402
  };
403
403
  }
404
- function ve(e, t) {
404
+ function ye(e, t) {
405
405
  if (e.mode !== "steps") return e.title ? `A presentation slide titled "${e.title}". ${e.imagePrompt}` : e.imagePrompt;
406
406
  let n = e.title ? `, "${e.title}"` : "";
407
407
  return [
@@ -410,12 +410,12 @@ function ve(e, t) {
410
410
  "Show the action clearly, with little or no text."
411
411
  ].filter(Boolean).join(" ");
412
412
  }
413
- async function ye(e, t, n) {
413
+ async function be(e, t, n) {
414
414
  if (n.html) return {
415
415
  html: n.html,
416
416
  prompt: ""
417
417
  };
418
- let r = t.slides.get(n.slide - 1), i = n.mode === "steps" ? I(r).imagePath : void 0, a = i ? await B(e, [i]) : [], o = ve(n, a.length > 0), s = await V(e, o, a), { imageData: c, imagePath: l } = I(s);
418
+ let r = t.slides.get(n.slide - 1), i = n.mode === "steps" ? L(r).imagePath : void 0, a = i ? await B(e, [i]) : [], o = ye(n, a.length > 0), s = await V(e, o, a), { imageData: c, imagePath: l } = L(s);
419
419
  return c ? {
420
420
  imageData: c,
421
421
  ...l && { imagePath: l },
@@ -425,10 +425,10 @@ async function ye(e, t, n) {
425
425
  sequence: null
426
426
  } };
427
427
  }
428
- async function be(e, t, n) {
429
- let r = await ye(e, t, n);
428
+ async function xe(e, t, n) {
429
+ let r = await be(e, t, n);
430
430
  if ("failed" in r) return r.failed;
431
- let { imageData: i, imagePath: a, html: o, prompt: s } = r, c = t.id, l = await Z(e.files?.artifacts, H, c, (e) => {
431
+ let { imageData: i, imagePath: a, html: o, prompt: s } = r, c = t.id, l = await Q(e.files?.artifacts, U, c, (e) => {
432
432
  let t = e ?? {
433
433
  id: c,
434
434
  title: "",
@@ -459,21 +459,21 @@ async function be(e, t, n) {
459
459
  message: [
460
460
  `${d} ${n.slide} of ${n.totalSlides} of slideshow "${c}" is on the screen`,
461
461
  a ? `saved to ${a}` : "",
462
- l ? "" : Q("slideshow")
462
+ l ? "" : $("slideshow")
463
463
  ].filter(Boolean).join("; "),
464
464
  instructions: T(n),
465
465
  instructionsRequired: !0,
466
- sequence: pe(n)
466
+ sequence: me(n)
467
467
  };
468
468
  }
469
- async function xe(e, t) {
470
- let n = w(t);
469
+ async function Se(e, t) {
470
+ let n = C(t);
471
471
  if (typeof n == "string") return {
472
472
  message: n,
473
473
  sequence: null
474
474
  };
475
- let r = he(e), i = ge(r, n), a = n.mode === "steps";
476
- if (a && n.slide > i.current && i.current > 0 && !R(e, i.shownAt)) {
475
+ let r = ge(e), i = _e(r, n), a = n.mode === "steps";
476
+ if (a && n.slide > i.current && i.current > 0 && !ce(e, i.shownAt)) {
477
477
  console.info(`[sequence] holding step ${n.slide} for the user`);
478
478
  let e = i.shownAt === Infinity ? "is still being drawn" : "is still on the screen";
479
479
  return {
@@ -485,12 +485,12 @@ async function xe(e, t) {
485
485
  if (o) return se(e.currentResult, o) ? {
486
486
  message: `step ${n.slide} of ${n.totalSlides} is already on the screen`,
487
487
  cancelled: !0
488
- } : _e(r, i, n, o);
489
- let s = r.repeats.claim(me(i.id, n));
488
+ } : ve(r, i, n, o);
489
+ let s = r.repeats.claim(he(i.id, n));
490
490
  if ("earlier" in s) {
491
- if (!await s.earlier) return xe(e, t);
491
+ if (!await s.earlier) return Se(e, t);
492
492
  let a = i.slides.get(n.slide);
493
- return a && r.lastShown !== i ? _e(r, i, n, a) : {
493
+ return a && r.lastShown !== i ? ve(r, i, n, a) : {
494
494
  message: `slide ${n.slide} of ${n.totalSlides} is already on the screen`,
495
495
  cancelled: !0
496
496
  };
@@ -502,7 +502,7 @@ async function xe(e, t) {
502
502
  i.current = n.slide, i.shownAt = Infinity;
503
503
  let u = !1;
504
504
  try {
505
- let t = await be(e, i, n);
505
+ let t = await xe(e, i, n);
506
506
  return u = oe(t), u && (i.slides.set(n.slide, t), i.current = n.slide, i.shownAt = Date.now(), r.lastShown = i), t;
507
507
  } finally {
508
508
  c(u), !u && i.current === n.slide && (i.current = l.current, i.shownAt = l.shownAt);
@@ -510,14 +510,14 @@ async function xe(e, t) {
510
510
  }
511
511
  //#endregion
512
512
  //#region src/core/storyboard.ts
513
- var Se = ({ id: e, title: t, totalPanels: n }) => ({
513
+ var Ce = ({ id: e, title: t, totalPanels: n }) => ({
514
514
  step: 0,
515
515
  total: n,
516
516
  kind: "story",
517
517
  label: `The cast of "${t}"`,
518
518
  onShown: "introduce the characters",
519
519
  nextCall: `call presentPanel for panel 1 of ${n} with storyboardId "${e}"`
520
- }), Ce = ({ id: e, totalPanels: t }, n, r) => ({
520
+ }), we = ({ id: e, totalPanels: t }, n, r) => ({
521
521
  step: n,
522
522
  total: t,
523
523
  kind: "story",
@@ -525,14 +525,14 @@ var Se = ({ id: e, title: t, totalPanels: n }) => ({
525
525
  onShown: "tell that part of the story",
526
526
  nextCall: `call presentPanel for panel ${n + 1} of ${t} with storyboardId "${e}"`,
527
527
  ...r.length > 0 && { waitsForUser: !0 }
528
- }), we = (e, t) => e ? `${e}. ${t}` : t, Te = (e, { name: t, description: n }) => we(e, `Character reference sheet of ${t}: ${n}. Full body, front, side and back views, on a plain white background. No text or labels.`);
529
- async function Ee(e, t) {
530
- let n = D(t);
528
+ }), Te = (e, t) => e ? `${e}. ${t}` : t, Ee = (e, { name: t, description: n }) => Te(e, `Character reference sheet of ${t}: ${n}. Full body, front, side and back views, on a plain white background. No text or labels.`);
529
+ async function De(e, t) {
530
+ let n = O(t);
531
531
  if (typeof n == "string") return {
532
532
  message: n,
533
533
  sequence: null
534
534
  };
535
- let r = await Promise.all(n.characters.map((t) => V(e, Te(n.style, t)))), i = r.map(I), a = r.find((e, t) => !i[t]?.imageData);
535
+ let r = await Promise.all(n.characters.map((t) => V(e, Ee(n.style, t)))), i = r.map(L), a = r.find((e, t) => !i[t]?.imageData);
536
536
  if (i.every(({ imageData: e }) => !e) && a) return {
537
537
  ...a,
538
538
  message: `the character sheets couldn't be made: ${a.message}`,
@@ -549,7 +549,7 @@ async function Ee(e, t) {
549
549
  };
550
550
  }),
551
551
  panels: {}
552
- }, s = await Z(e.files?.artifacts, U, o.id, () => o), c = o.characters.filter((e) => e.imagePath).map((e) => `${e.name}: ${e.imagePath}`), l = n.characters.map(({ name: e }, t) => i[t]?.imageData ? null : `${e} (${r[t]?.message ?? ""})`).filter((e) => !!e), u = i.find((e) => e.imageData)?.imageData;
552
+ }, s = await Q(e.files?.artifacts, W, o.id, () => o), c = o.characters.filter((e) => e.imagePath).map((e) => `${e.name}: ${e.imagePath}`), l = n.characters.map(({ name: e }, t) => i[t]?.imageData ? null : `${e} (${r[t]?.message ?? ""})`).filter((e) => !!e), u = i.find((e) => e.imageData)?.imageData;
553
553
  return {
554
554
  data: {
555
555
  storyboardId: o.id,
@@ -570,18 +570,18 @@ async function Ee(e, t) {
570
570
  `storyboard "${o.id}" is ready with ${o.totalPanels} panels; the cast is on the screen`,
571
571
  c.length ? `character sheets saved to ${c.join(", ")}` : "",
572
572
  l.length ? `no sheet for ${l.join("; ")}: they will be drawn from their description` : "",
573
- s ? "" : Q("storyboard")
573
+ s ? "" : $("storyboard")
574
574
  ].filter(Boolean).join("; "),
575
- instructions: O(o),
575
+ instructions: k(o),
576
576
  instructionsRequired: !0,
577
- sequence: Se(o)
577
+ sequence: Ce(o)
578
578
  };
579
579
  }
580
- function De(e, t, n) {
581
- let r = [we(e.style, `Panel ${t.panel} of ${e.totalPanels} of the illustrated story "${e.title}". ${t.imagePrompt}`)], i = 0, a = n.map(({ character: e, hasSheet: t }) => t ? `${e.name} is the character in reference image ${++i}` : `${e.name}: ${e.description}`);
580
+ function Oe(e, t, n) {
581
+ let r = [Te(e.style, `Panel ${t.panel} of ${e.totalPanels} of the illustrated story "${e.title}". ${t.imagePrompt}`)], i = 0, a = n.map(({ character: e, hasSheet: t }) => t ? `${e.name} is the character in reference image ${++i}` : `${e.name}: ${e.description}`);
582
582
  return a.length && r.push(`${a.join(". ")}.`), i && r.push("Draw each character exactly as in their reference image: the same face, hair, clothes and colors. Use the reference images only for how the characters look, not for their pose or the background."), r.push("No captions, speech bubbles or other text in the picture."), r.join(" ");
583
583
  }
584
- async function Oe(e, t, n) {
584
+ async function ke(e, t, n) {
585
585
  let r = [], i = [];
586
586
  for (let a of n.characters) {
587
587
  let n = t.characters.find((e) => b(e.name, a));
@@ -594,15 +594,15 @@ async function Oe(e, t, n) {
594
594
  });
595
595
  }
596
596
  }
597
- let a = i.map(({ sheet: e }) => e).filter((e) => !!e), o = De(t, n, i.map(({ character: e, sheet: t }) => ({
597
+ let a = i.map(({ sheet: e }) => e).filter((e) => !!e), o = Oe(t, n, i.map(({ character: e, sheet: t }) => ({
598
598
  character: e,
599
599
  hasSheet: !!t
600
- }))), s = await V(e, o, a), { imageData: c, imagePath: l } = I(s);
600
+ }))), s = await V(e, o, a), { imageData: c, imagePath: l } = L(s);
601
601
  if (!c) return {
602
602
  ...s,
603
603
  sequence: null
604
604
  };
605
- let u = n.panel < t.totalPanels && n.choices.length >= 2 ? n.choices : [], d = await Z(e.files?.artifacts, U, t.id, (e) => {
605
+ let u = n.panel < t.totalPanels && n.choices.length >= 2 ? n.choices : [], d = await Q(e.files?.artifacts, W, t.id, (e) => {
606
606
  let r = e ?? t;
607
607
  return u.length && (r.interactive = !0), r.panels[String(n.panel)] = {
608
608
  caption: n.caption,
@@ -628,25 +628,25 @@ async function Oe(e, t, n) {
628
628
  `panel ${n.panel} of ${t.totalPanels} is on the screen`,
629
629
  l ? `saved to ${l}` : "",
630
630
  r.length ? `not in the cast, so drawn from the prompt alone: ${r.join(", ")}` : "",
631
- d ? "" : Q("storyboard")
631
+ d ? "" : $("storyboard")
632
632
  ].filter(Boolean).join("; "),
633
- instructions: j(t, n.panel, u),
633
+ instructions: M(t, n.panel, u),
634
634
  instructionsRequired: !0,
635
- sequence: Ce(t, n.panel, u)
635
+ sequence: we(t, n.panel, u)
636
636
  };
637
637
  }
638
- var ke = ue(() => ({
639
- repeats: $(),
638
+ var Ae = H(() => ({
639
+ repeats: pe(),
640
640
  awaitingChoice: /* @__PURE__ */ new Map()
641
641
  }));
642
- async function Ae(e, t) {
643
- let n = A(t);
642
+ async function je(e, t) {
643
+ let n = j(t);
644
644
  if (!n) return {
645
- message: k,
645
+ message: A,
646
646
  sequence: null
647
647
  };
648
- let { storyboardId: r, panel: i } = n, { repeats: a, awaitingChoice: o } = ke(e), s = o.get(r);
649
- if (s && i > s.panel && !R(e, s.shownAt)) return console.info(`[sequence] holding panel ${i} for the user`), {
648
+ let { storyboardId: r, panel: i } = n, { repeats: a, awaitingChoice: o } = Ae(e), s = o.get(r);
649
+ if (s && i > s.panel && !ce(e, s.shownAt)) return console.info(`[sequence] holding panel ${i} for the user`), {
650
650
  message: s.shownAt === Infinity ? `panel ${i} was not shown: panel ${s.panel} is still being drawn. Wait for it before going on.` : `panel ${i} was not shown: the user hasn't picked a choice yet, and panel ${s.panel} is still on the screen. Wait for their answer.`,
651
651
  cancelled: !0
652
652
  };
@@ -654,7 +654,7 @@ async function Ae(e, t) {
654
654
  if ("earlier" in c) return await c.earlier ? {
655
655
  message: `panel ${i} is already on the screen`,
656
656
  cancelled: !0
657
- } : Ae(e, t);
657
+ } : je(e, t);
658
658
  let { settle: l } = c, u = {
659
659
  panel: i,
660
660
  shownAt: Infinity
@@ -662,7 +662,7 @@ async function Ae(e, t) {
662
662
  o.set(r, u);
663
663
  let f = () => o.get(r) === u, p = !1;
664
664
  try {
665
- let t = await X(e.files?.artifacts, U, r);
665
+ let t = await Z(e.files?.artifacts, W, r);
666
666
  if (!t) return {
667
667
  message: `there is no storyboard "${r}"; call defineStoryboard first`,
668
668
  sequence: null
@@ -671,8 +671,8 @@ async function Ae(e, t) {
671
671
  message: `storyboard "${t.id}" has ${t.totalPanels} panels`,
672
672
  sequence: null
673
673
  };
674
- let a = await Oe(e, t, n);
675
- p = !!I(a).imageData;
674
+ let a = await ke(e, t, n);
675
+ p = !!L(a).imageData;
676
676
  let s = a.data;
677
677
  return p && f() && (s?.choices?.length ? o.set(r, {
678
678
  panel: i,
@@ -684,21 +684,21 @@ async function Ae(e, t) {
684
684
  }
685
685
  //#endregion
686
686
  //#region src/core/index.ts
687
- var je = {
688
- toolDefinition: E,
687
+ var Me = {
688
+ toolDefinition: D,
689
689
  generatingMessage: "Making the slide...",
690
690
  isEnabled: () => !0,
691
- execute: (e, t) => xe(e, t)
692
- }, Me = {
693
- toolDefinition: N,
694
- generatingMessage: "Drawing the characters...",
695
- isEnabled: () => !0,
696
- execute: (e, t) => Ee(e, t)
691
+ execute: (e, t) => Se(e, t)
697
692
  }, Ne = {
698
693
  toolDefinition: P,
694
+ generatingMessage: "Drawing the characters...",
695
+ isEnabled: () => !0,
696
+ execute: (e, t) => De(e, t)
697
+ }, Pe = {
698
+ toolDefinition: F,
699
699
  generatingMessage: "Drawing the panel...",
700
700
  isEnabled: () => !0,
701
- execute: (e, t) => Ae(e, t)
701
+ execute: (e, t) => je(e, t)
702
702
  };
703
703
  //#endregion
704
- export { o as A, j as C, b as D, D as E, p as F, d as M, n as N, T as O, t as P, O as S, w as T, ie as _, U as a, C as b, N as c, te as d, k as f, E as g, m as h, H as i, s as j, r as k, ee as l, P as m, Ne as n, X as o, g as p, je as r, h as s, Me as t, ne as u, _ as v, A as w, M as x, S as y };
704
+ export { o as A, M as C, b as D, O as E, p as F, d as M, n as N, T as O, t as P, k as S, C as T, E as _, W as a, re as b, P as c, te as d, A as f, D as g, m as h, U as i, s as j, r as k, ee as l, F as m, Pe as n, Z as o, g as p, Me as r, h as s, Ne as t, ne as u, _ as v, j as w, N as x, S as y };
package/dist/index.cjs CHANGED
@@ -1 +1 @@
1
- Object.defineProperty(exports,Symbol.toStringTag,{value:`Module`});const e=require("./core-OZRdlavD.cjs");exports.DEFINE_STORYBOARD=e.s,exports.DEFINE_STORYBOARD_DEFINITION=e.c,exports.MAX_CHARACTERS=e.l,exports.MAX_CHOICES=e.u,exports.MAX_PANELS=e.d,exports.MAX_SLIDE_HTML=e.k,exports.PANEL_ARGS_ERROR=e.f,exports.PRESENT_PANEL=e.p,exports.PRESENT_PANEL_DEFINITION=e.m,exports.PRESENT_SLIDE=e.h,exports.PRESENT_SLIDE_DEFINITION=e.g,exports.PRESENT_SLIDE_PROMPT=e._,exports.SEQUENCE_ID=e.v,exports.SLIDESHOWS_DIR=e.i,exports.SLIDE_ANIMATION_KINDS=e.A,exports.SLIDE_ARGS_ERROR=e.y,exports.SLIDE_AUTO_END_SECONDS=e.j,exports.SLIDE_CSS_ANIMATIONS_FINISHED=e.M,exports.SLIDE_HEIGHT=e.N,exports.SLIDE_HTML_TOO_LONG=e.b,exports.SLIDE_WIDTH=e.P,exports.STORYBOARDS_DIR=e.a,exports.STORYBOARD_PROMPT=e.x,exports.castShownInstructions=e.S,exports.defineStoryboardPluginCore=e.t,exports.loadRecord=e.o,exports.panelShownInstructions=e.C,exports.parsePanelArgs=e.w,exports.parseSlideArgs=e.T,exports.parseStoryboardArgs=e.E,exports.presentPanelPluginCore=e.n,exports.presentSlidePluginCore=e.r,exports.sameName=e.D,exports.slideHtmlDocument=e.F,exports.slideShownInstructions=e.O;
1
+ Object.defineProperty(exports,Symbol.toStringTag,{value:`Module`});const e=require("./core-Bl4BX0HI.cjs");exports.DEFINE_STORYBOARD=e.s,exports.DEFINE_STORYBOARD_DEFINITION=e.c,exports.MAX_CHARACTERS=e.l,exports.MAX_CHOICES=e.u,exports.MAX_PANELS=e.d,exports.MAX_SLIDE_HTML=e.k,exports.PANEL_ARGS_ERROR=e.f,exports.PRESENT_PANEL=e.p,exports.PRESENT_PANEL_DEFINITION=e.m,exports.PRESENT_SLIDE=e.h,exports.PRESENT_SLIDE_DEFINITION=e.g,exports.PRESENT_SLIDE_PROMPT=e._,exports.SEQUENCE_ID=e.v,exports.SLIDESHOWS_DIR=e.i,exports.SLIDE_ANIMATION_KINDS=e.A,exports.SLIDE_ARGS_ERROR=e.y,exports.SLIDE_AUTO_END_SECONDS=e.j,exports.SLIDE_CSS_ANIMATIONS_FINISHED=e.M,exports.SLIDE_HEIGHT=e.N,exports.SLIDE_HTML_TOO_LONG=e.b,exports.SLIDE_WIDTH=e.P,exports.STORYBOARDS_DIR=e.a,exports.STORYBOARD_PROMPT=e.x,exports.castShownInstructions=e.S,exports.defineStoryboardPluginCore=e.t,exports.loadRecord=e.o,exports.panelShownInstructions=e.C,exports.parsePanelArgs=e.w,exports.parseSlideArgs=e.T,exports.parseStoryboardArgs=e.E,exports.presentPanelPluginCore=e.n,exports.presentSlidePluginCore=e.r,exports.sameName=e.D,exports.slideHtmlDocument=e.F,exports.slideShownInstructions=e.O;
package/dist/index.js CHANGED
@@ -1,2 +1,2 @@
1
- import { A as e, C as t, D as n, E as r, F as i, M as a, N as o, O as s, P as c, S as l, T as u, _ as d, a as f, b as p, c as m, d as h, f as g, g as _, h as v, i as y, j as b, k as x, l as S, m as C, n as w, o as T, p as E, r as D, s as O, t as k, u as A, v as j, w as M, x as N, y as P } from "./core-D3XJ6n_I.js";
1
+ import { A as e, C as t, D as n, E as r, F as i, M as a, N as o, O as s, P as c, S as l, T as u, _ as d, a as f, b as p, c as m, d as h, f as g, g as _, h as v, i as y, j as b, k as x, l as S, m as C, n as w, o as T, p as E, r as D, s as O, t as k, u as A, v as j, w as M, x as N, y as P } from "./core-Dsp7rj6a.js";
2
2
  export { O as DEFINE_STORYBOARD, m as DEFINE_STORYBOARD_DEFINITION, S as MAX_CHARACTERS, A as MAX_CHOICES, h as MAX_PANELS, x as MAX_SLIDE_HTML, g as PANEL_ARGS_ERROR, E as PRESENT_PANEL, C as PRESENT_PANEL_DEFINITION, v as PRESENT_SLIDE, _ as PRESENT_SLIDE_DEFINITION, d as PRESENT_SLIDE_PROMPT, j as SEQUENCE_ID, y as SLIDESHOWS_DIR, e as SLIDE_ANIMATION_KINDS, P as SLIDE_ARGS_ERROR, b as SLIDE_AUTO_END_SECONDS, a as SLIDE_CSS_ANIMATIONS_FINISHED, o as SLIDE_HEIGHT, p as SLIDE_HTML_TOO_LONG, c as SLIDE_WIDTH, f as STORYBOARDS_DIR, N as STORYBOARD_PROMPT, l as castShownInstructions, k as defineStoryboardPluginCore, T as loadRecord, t as panelShownInstructions, M as parsePanelArgs, u as parseSlideArgs, r as parseStoryboardArgs, w as presentPanelPluginCore, D as presentSlidePluginCore, n as sameName, i as slideHtmlDocument, s as slideShownInstructions };
package/dist/vue.cjs CHANGED
@@ -1 +1 @@
1
- Object.defineProperty(exports,Symbol.toStringTag,{value:`Module`});const e=require("./core-OZRdlavD.cjs");let t=require("vue"),n=require("@mulmochat-plugin/ui-image");function r({caption:e,choices:n}){let r=[];return e&&r.push((0,t.h)(`p`,{class:`text-center text-lg text-gray-800 px-4`},e)),n?.length&&r.push((0,t.h)(`ol`,{class:`flex flex-wrap justify-center gap-3 px-4`},n.map((e,n)=>(0,t.h)(`li`,{class:`rounded-full bg-indigo-600 text-white text-xl px-5 py-2 font-medium`},`${n+1}. ${e}`)))),r.length?(0,t.h)(`div`,{class:`flex flex-col gap-2 pb-2`},r):null}function i(e,n=()=>({})){return(0,t.markRaw)((0,t.defineComponent)({name:e,props:{selectedResult:{type:Object,required:!0}},setup(e){return()=>{let i=e.selectedResult.data;return i?.imageData?(0,t.h)(`div`,{class:`h-full w-full flex flex-col bg-white p-2 gap-2`},[(0,t.h)(`div`,{class:`flex-1 min-h-0 flex items-center justify-center`},[(0,t.h)(`img`,{src:i.imageData,alt:i.prompt??``,class:`max-w-full max-h-full object-contain`})]),r(n(i))]):(0,t.h)(`div`,{class:`h-full bg-white`})}}}))}var a=(0,t.defineComponent)({name:`HtmlSlide`,props:{html:{type:String,required:!0}},setup(n){let r=(0,t.ref)(null),i=(0,t.ref)(0),a,o=()=>{let t=r.value;t&&(i.value=Math.min(t.clientWidth/e.P,t.clientHeight/720))};return(0,t.onMounted)(()=>{o(),a=new ResizeObserver(o),r.value&&a.observe(r.value)}),(0,t.onBeforeUnmount)(()=>a?.disconnect()),()=>(0,t.h)(`div`,{ref:r,class:`flex-1 min-h-0 w-full relative overflow-hidden`},i.value>0?[(0,t.h)(`iframe`,{srcdoc:e.F(n.html),sandbox:`allow-scripts`,title:`slide`,width:e.P,height:720,class:`absolute border-0 bg-white shadow`,style:{left:`50%`,top:`50%`,transform:`translate(-50%, -50%) scale(${i.value})`}})]:[])}}),o=i(`PresentSlideImageView`),s=(0,t.markRaw)((0,t.defineComponent)({name:`PresentSlideView`,props:{selectedResult:{type:Object,required:!0}},setup(e){return()=>{let n=e.selectedResult.data?.html;return n?(0,t.h)(`div`,{class:`h-full w-full flex flex-col bg-slate-100 p-2`},[(0,t.h)(a,{key:e.selectedResult.uuid??n,html:n})]):(0,t.h)(o,{selectedResult:e.selectedResult})}}})),c=(0,t.markRaw)((0,t.defineComponent)({name:`PresentSlidePreview`,props:{result:{type:Object,required:!0}},setup(e){return()=>{let r=e.result.data;return r?.html?(0,t.h)(`div`,{class:`aspect-video w-full rounded bg-gradient-to-br from-indigo-600 to-sky-500 text-white flex flex-col items-center justify-center p-2 text-center`},[(0,t.h)(`div`,{class:`text-xs opacity-80`},`Slide ${r.slide} of ${r.totalSlides}`),(0,t.h)(`div`,{class:`text-sm font-semibold leading-tight line-clamp-2`},r.title||e.result.title||``)]):(0,t.h)(n.ImagePreview,{result:e.result})}}}));function l(e){return(0,t.markRaw)((0,t.defineComponent)({name:e,props:{result:{type:Object,required:!0}},setup(e){return()=>(0,t.h)(n.ImagePreview,{result:e.result})}}))}var u=(0,t.markRaw)((0,t.defineComponent)({name:`StoryboardCastView`,props:{selectedResult:{type:Object,required:!0}},setup(e){return()=>{let n=e.selectedResult.data,r=n?.characters??[];return(0,t.h)(`div`,{class:`h-full w-full flex flex-col bg-white p-4`},[(0,t.h)(`h2`,{class:`text-center text-xl font-semibold text-gray-800 mb-3`},n?.title??``),(0,t.h)(`div`,{class:`flex-1 min-h-0 grid gap-3 ${r.length>1?`grid-cols-2`:`grid-cols-1`} auto-rows-fr`},r.map(e=>(0,t.h)(`figure`,{class:`min-h-0 flex flex-col items-center`},[e.imageData?(0,t.h)(`img`,{src:e.imageData,alt:e.name,class:`flex-1 min-h-0 max-w-full object-contain`}):(0,t.h)(`div`,{class:`flex-1`}),(0,t.h)(`figcaption`,{class:`text-lg text-gray-800 mt-1`},e.name)])))])}}})),d=e=>Array.isArray(e)?e.filter(e=>typeof e==`string`):[],f={...e.r,viewComponent:s,previewComponent:c},p={...e.t,viewComponent:u,previewComponent:l(`StoryboardCastPreview`)},m={...e.n,viewComponent:i(`PresentPanelView`,e=>({caption:typeof e.caption==`string`?e.caption:``,choices:d(e.choices)})),previewComponent:l(`PresentPanelPreview`)},h=[f,p,m];exports.DEFINE_STORYBOARD=e.s,exports.DEFINE_STORYBOARD_DEFINITION=e.c,exports.MAX_CHARACTERS=e.l,exports.MAX_CHOICES=e.u,exports.MAX_PANELS=e.d,exports.MAX_SLIDE_HTML=e.k,exports.PANEL_ARGS_ERROR=e.f,exports.PRESENT_PANEL=e.p,exports.PRESENT_PANEL_DEFINITION=e.m,exports.PRESENT_SLIDE=e.h,exports.PRESENT_SLIDE_DEFINITION=e.g,exports.PRESENT_SLIDE_PROMPT=e._,exports.SEQUENCE_ID=e.v,exports.SLIDESHOWS_DIR=e.i,exports.SLIDE_ANIMATION_KINDS=e.A,exports.SLIDE_ARGS_ERROR=e.y,exports.SLIDE_AUTO_END_SECONDS=e.j,exports.SLIDE_CSS_ANIMATIONS_FINISHED=e.M,exports.SLIDE_HEIGHT=e.N,exports.SLIDE_HTML_TOO_LONG=e.b,exports.SLIDE_WIDTH=e.P,exports.STORYBOARDS_DIR=e.a,exports.STORYBOARD_PROMPT=e.x,exports.castShownInstructions=e.S,exports.defineStoryboardPlugin=p,exports.defineStoryboardPluginCore=e.t,exports.loadRecord=e.o,exports.panelShownInstructions=e.C,exports.parsePanelArgs=e.w,exports.parseSlideArgs=e.T,exports.parseStoryboardArgs=e.E,exports.plugins=h,exports.presentPanelPlugin=m,exports.presentPanelPluginCore=e.n,exports.presentSlidePlugin=f,exports.presentSlidePluginCore=e.r,exports.sameName=e.D,exports.slideHtmlDocument=e.F,exports.slideShownInstructions=e.O;
1
+ Object.defineProperty(exports,Symbol.toStringTag,{value:`Module`});const e=require("./core-Bl4BX0HI.cjs");let t=require("vue"),n=require("@mulmochat-plugin/ui-image");function r({caption:e,choices:n}){let r=[];return e&&r.push((0,t.h)(`p`,{class:`text-center text-lg text-gray-800 px-4`},e)),n?.length&&r.push((0,t.h)(`ol`,{class:`flex flex-wrap justify-center gap-3 px-4`},n.map((e,n)=>(0,t.h)(`li`,{class:`rounded-full bg-indigo-600 text-white text-xl px-5 py-2 font-medium`},`${n+1}. ${e}`)))),r.length?(0,t.h)(`div`,{class:`flex flex-col gap-2 pb-2`},r):null}function i(e,n=()=>({})){return(0,t.markRaw)((0,t.defineComponent)({name:e,props:{selectedResult:{type:Object,required:!0}},setup(e){return()=>{let i=e.selectedResult.data;return i?.imageData?(0,t.h)(`div`,{class:`h-full w-full flex flex-col bg-white p-2 gap-2`},[(0,t.h)(`div`,{class:`flex-1 min-h-0 flex items-center justify-center`},[(0,t.h)(`img`,{src:i.imageData,alt:i.prompt??``,class:`max-w-full max-h-full object-contain`})]),r(n(i))]):(0,t.h)(`div`,{class:`h-full bg-white`})}}}))}var a=(0,t.defineComponent)({name:`HtmlSlide`,props:{html:{type:String,required:!0}},setup(n){let r=(0,t.ref)(null),i=(0,t.ref)(0),a,o=()=>{let t=r.value;t&&(i.value=Math.min(t.clientWidth/e.P,t.clientHeight/720))};return(0,t.onMounted)(()=>{o(),a=new ResizeObserver(o),r.value&&a.observe(r.value)}),(0,t.onBeforeUnmount)(()=>a?.disconnect()),()=>(0,t.h)(`div`,{ref:r,class:`flex-1 min-h-0 w-full relative overflow-hidden`},i.value>0?[(0,t.h)(`iframe`,{srcdoc:e.F(n.html),sandbox:`allow-scripts`,title:`slide`,width:e.P,height:720,class:`absolute border-0 bg-white shadow`,style:{left:`50%`,top:`50%`,transform:`translate(-50%, -50%) scale(${i.value})`}})]:[])}}),o=i(`PresentSlideImageView`),s=(0,t.markRaw)((0,t.defineComponent)({name:`PresentSlideView`,props:{selectedResult:{type:Object,required:!0}},setup(e){return()=>{let n=e.selectedResult.data?.html;return n?(0,t.h)(`div`,{class:`h-full w-full flex flex-col bg-slate-100 p-2`},[(0,t.h)(a,{key:e.selectedResult.uuid??n,html:n})]):(0,t.h)(o,{selectedResult:e.selectedResult})}}})),c=(0,t.markRaw)((0,t.defineComponent)({name:`PresentSlidePreview`,props:{result:{type:Object,required:!0}},setup(e){return()=>{let r=e.result.data;return r?.html?(0,t.h)(`div`,{class:`aspect-video w-full rounded bg-gradient-to-br from-indigo-600 to-sky-500 text-white flex flex-col items-center justify-center p-2 text-center`},[(0,t.h)(`div`,{class:`text-xs opacity-80`},`Slide ${r.slide} of ${r.totalSlides}`),(0,t.h)(`div`,{class:`text-sm font-semibold leading-tight line-clamp-2`},r.title||e.result.title||``)]):(0,t.h)(n.ImagePreview,{result:e.result})}}}));function l(e){return(0,t.markRaw)((0,t.defineComponent)({name:e,props:{result:{type:Object,required:!0}},setup(e){return()=>(0,t.h)(n.ImagePreview,{result:e.result})}}))}var u=(0,t.markRaw)((0,t.defineComponent)({name:`StoryboardCastView`,props:{selectedResult:{type:Object,required:!0}},setup(e){return()=>{let n=e.selectedResult.data,r=n?.characters??[];return(0,t.h)(`div`,{class:`h-full w-full flex flex-col bg-white p-4`},[(0,t.h)(`h2`,{class:`text-center text-xl font-semibold text-gray-800 mb-3`},n?.title??``),(0,t.h)(`div`,{class:`flex-1 min-h-0 grid gap-3 ${r.length>1?`grid-cols-2`:`grid-cols-1`} auto-rows-fr`},r.map(e=>(0,t.h)(`figure`,{class:`min-h-0 flex flex-col items-center`},[e.imageData?(0,t.h)(`img`,{src:e.imageData,alt:e.name,class:`flex-1 min-h-0 max-w-full object-contain`}):(0,t.h)(`div`,{class:`flex-1`}),(0,t.h)(`figcaption`,{class:`text-lg text-gray-800 mt-1`},e.name)])))])}}})),d=e=>Array.isArray(e)?e.filter(e=>typeof e==`string`):[],f={...e.r,viewComponent:s,previewComponent:c},p={...e.t,viewComponent:u,previewComponent:l(`StoryboardCastPreview`)},m={...e.n,viewComponent:i(`PresentPanelView`,e=>({caption:typeof e.caption==`string`?e.caption:``,choices:d(e.choices)})),previewComponent:l(`PresentPanelPreview`)},h=[f,p,m];exports.DEFINE_STORYBOARD=e.s,exports.DEFINE_STORYBOARD_DEFINITION=e.c,exports.MAX_CHARACTERS=e.l,exports.MAX_CHOICES=e.u,exports.MAX_PANELS=e.d,exports.MAX_SLIDE_HTML=e.k,exports.PANEL_ARGS_ERROR=e.f,exports.PRESENT_PANEL=e.p,exports.PRESENT_PANEL_DEFINITION=e.m,exports.PRESENT_SLIDE=e.h,exports.PRESENT_SLIDE_DEFINITION=e.g,exports.PRESENT_SLIDE_PROMPT=e._,exports.SEQUENCE_ID=e.v,exports.SLIDESHOWS_DIR=e.i,exports.SLIDE_ANIMATION_KINDS=e.A,exports.SLIDE_ARGS_ERROR=e.y,exports.SLIDE_AUTO_END_SECONDS=e.j,exports.SLIDE_CSS_ANIMATIONS_FINISHED=e.M,exports.SLIDE_HEIGHT=e.N,exports.SLIDE_HTML_TOO_LONG=e.b,exports.SLIDE_WIDTH=e.P,exports.STORYBOARDS_DIR=e.a,exports.STORYBOARD_PROMPT=e.x,exports.castShownInstructions=e.S,exports.defineStoryboardPlugin=p,exports.defineStoryboardPluginCore=e.t,exports.loadRecord=e.o,exports.panelShownInstructions=e.C,exports.parsePanelArgs=e.w,exports.parseSlideArgs=e.T,exports.parseStoryboardArgs=e.E,exports.plugins=h,exports.presentPanelPlugin=m,exports.presentPanelPluginCore=e.n,exports.presentSlidePlugin=f,exports.presentSlidePluginCore=e.r,exports.sameName=e.D,exports.slideHtmlDocument=e.F,exports.slideShownInstructions=e.O;
package/dist/vue.js CHANGED
@@ -1,4 +1,4 @@
1
- import { A as e, C as t, D as n, E as r, F as i, M as a, N as o, O as s, P as c, S as ee, T as l, _ as u, a as d, b as f, c as p, d as m, f as h, g, h as _, i as v, j as y, k as b, l as x, m as S, n as C, o as w, p as T, r as E, s as D, t as O, u as k, v as A, w as j, x as M, y as N } from "./core-D3XJ6n_I.js";
1
+ import { A as e, C as t, D as n, E as r, F as i, M as a, N as o, O as s, P as c, S as ee, T as l, _ as u, a as d, b as f, c as p, d as m, f as h, g, h as _, i as v, j as y, k as b, l as x, m as S, n as C, o as w, p as T, r as E, s as D, t as O, u as k, v as A, w as j, x as M, y as N } from "./core-Dsp7rj6a.js";
2
2
  import { defineComponent as P, h as F, markRaw as I, onBeforeUnmount as L, onMounted as R, ref as z } from "vue";
3
3
  import { ImagePreview as B } from "@mulmochat-plugin/ui-image";
4
4
  //#region src/vue/index.ts
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@gui-chat-plugin/sequence",
3
- "version": "0.4.0",
3
+ "version": "0.4.1",
4
4
  "description": "Slideshows, step-by-step guides and stories told in pictures (presentSlide, defineStoryboard, presentPanel) for GUI Chat Protocol hosts",
5
5
  "type": "module",
6
6
  "main": "./dist/index.cjs",
@@ -1,145 +0,0 @@
1
- let e=require("gui-chat-protocol");var t=1280,n=720,r=6e4,i=`https://cdn.jsdelivr.net/npm/@tailwindcss/browser@4.3.3/dist/index.global.js`,a=`sha384-2ql948lIdLcGEE0/qxNiudyTjgauA3RDJERu5xW75kFCvSl5a9odyQYCb6tEjnmB`,o=[`animate`,`counter`,`typewriter`],s=8,c=`
2
- (() => {
3
- const EASE = {
4
- linear: (t) => t,
5
- easeIn: (t) => t * t,
6
- easeOut: (t) => 1 - (1 - t) * (1 - t),
7
- easeInOut: (t) => (t < 0.5 ? 2 * t * t : 1 - Math.pow(-2 * t + 2, 2) / 2),
8
- };
9
- const AUTO_END = 8;
10
- const TRANSFORMS = [
11
- ["data-translate-x", "translateX", "px"],
12
- ["data-translate-y", "translateY", "px"],
13
- ["data-scale", "scale", ""],
14
- ["data-rotate", "rotate", "deg"],
15
- ["data-rotate-x", "rotateX", "deg"],
16
- ["data-rotate-y", "rotateY", "deg"],
17
- ["data-rotate-z", "rotateZ", "deg"],
18
- ];
19
- const STYLES = [
20
- ["data-opacity", "opacity", ""],
21
- ["data-width", "width", "px"],
22
- ["data-height", "height", "px"],
23
- ];
24
- const number = (value, fallback) => {
25
- const n = Number(value);
26
- return value !== null && value.trim() !== "" && Number.isFinite(n) ? n : fallback;
27
- };
28
- const range = (value, unit) => {
29
- if (value === null) return null;
30
- const parts = value.split(",").map((part) => part.trim());
31
- const from = Number(parts[0]);
32
- const to = Number(parts[1]);
33
- if (!Number.isFinite(from) || !Number.isFinite(to)) return null;
34
- return { from, to, unit: parts[2] || unit };
35
- };
36
- const ranges = (el, table) =>
37
- table
38
- .map(([attr, name, unit]) => [name, range(el.getAttribute(attr), unit)])
39
- .filter(([, r]) => r);
40
- let entries = [];
41
- const collect = () => {
42
- entries = [...document.querySelectorAll("[data-animation]")].map((el) => {
43
- const kind = el.getAttribute("data-animation");
44
- const end = el.getAttribute("data-end");
45
- const entry = {
46
- el,
47
- kind,
48
- start: number(el.getAttribute("data-start"), 0),
49
- end: end === null || end.trim() === "auto" ? null : number(end, null),
50
- ease: EASE[el.getAttribute("data-easing")] || EASE.linear,
51
- };
52
- if (kind === "animate") {
53
- entry.transforms = ranges(el, TRANSFORMS);
54
- entry.styles = ranges(el, STYLES);
55
- } else if (kind === "counter") {
56
- entry.from = number(el.getAttribute("data-from"), 0);
57
- entry.to = number(el.getAttribute("data-to"), 0);
58
- entry.decimals = Math.max(0, Math.round(number(el.getAttribute("data-decimals"), 0)));
59
- entry.prefix = el.getAttribute("data-prefix") || "";
60
- entry.suffix = el.getAttribute("data-suffix") || "";
61
- } else if (kind === "typewriter") {
62
- entry.text = el.getAttribute("data-text") ?? el.textContent;
63
- } else {
64
- return null;
65
- }
66
- return entry;
67
- }).filter(Boolean);
68
- };
69
- const seek = (t) => {
70
- for (const e of entries) {
71
- const end = e.end ?? AUTO_END;
72
- const span = end - e.start;
73
- const p = span > 0 ? Math.min(1, Math.max(0, (t - e.start) / span)) : t >= e.start ? 1 : 0;
74
- const k = e.ease(p);
75
- const at = (r) => r.from + (r.to - r.from) * k;
76
- if (e.kind === "animate") {
77
- if (e.transforms.length) {
78
- e.el.style.transform = e.transforms.map(([name, r]) => name + "(" + at(r) + r.unit + ")").join(" ");
79
- }
80
- for (const [name, r] of e.styles) e.el.style[name] = at(r) + r.unit;
81
- } else if (e.kind === "counter") {
82
- e.el.textContent = e.prefix + (e.from + (e.to - e.from) * k).toFixed(e.decimals) + e.suffix;
83
- } else {
84
- e.el.textContent = e.text.slice(0, Math.floor(e.text.length * k));
85
- }
86
- }
87
- };
88
- window.__slideSeek = seek;
89
- const play = () => {
90
- const last = Math.max(0, ...entries.map((e) => e.end ?? AUTO_END));
91
- const begun = performance.now();
92
- const tick = (now) => {
93
- const t = (now - begun) / 1000;
94
- seek(t);
95
- if (t <= last) requestAnimationFrame(tick);
96
- };
97
- requestAnimationFrame(tick);
98
- };
99
- // Collected once the body is parsed: at DOMContentLoaded, or earlier when
100
- // the fallback shows the slide while a slow Tailwind still holds
101
- // DOMContentLoaded back (the body is parsed by then: readyState is
102
- // "interactive" before deferred scripts run). Played once both are done.
103
- let collected = false;
104
- let shown = false;
105
- const init = () => {
106
- if (collected || document.readyState === "loading") return;
107
- collected = true;
108
- collect();
109
- seek(0);
110
- if (shown) play();
111
- };
112
- const show = () => {
113
- if (shown) return;
114
- init();
115
- shown = true;
116
- document.documentElement.classList.add("ready");
117
- if (collected) play();
118
- };
119
- const ready = () => requestAnimationFrame(() => requestAnimationFrame(show));
120
- const check = () =>
121
- document.querySelector("style:not([type]):not(#slide-base)") ? ready() : setTimeout(check, 30);
122
- addEventListener("DOMContentLoaded", () => {
123
- init();
124
- check();
125
- });
126
- setTimeout(show, 1000);
127
- addEventListener("click", (event) => {
128
- if (event.target instanceof Element && event.target.closest("a, area")) event.preventDefault();
129
- }, true);
130
- })();`,l=[`default-src 'none'`,`script-src 'sha256-0zsqCvkCfq5Z1iJCn46NiAtSAyIr/JDkyNs/Fae1J+Y=' ${i}`,`style-src 'unsafe-inline' https://fonts.googleapis.com`,`font-src https://fonts.gstatic.com data:`,`img-src data: blob:`,`media-src data: blob:`,`connect-src 'none'`,`form-action 'none'`,`base-uri 'none'`].join(`; `),u=e=>e.replace(/<(?=(meta|base|link)\b)/gi,`&lt;`).replace(/shadowroot/gi,`data-no-shadow-root`),d=`*, *::before, *::after { animation-play-state: paused !important; animation-duration: 0s !important; animation-delay: 0s !important; animation-iteration-count: 1 !important; animation-fill-mode: both !important; transition: none !important; }`,f=`
131
- html, body { margin: 0; width: ${t}px; height: 720px; overflow: hidden; }
132
- html:not(.ready) body { visibility: hidden; }
133
- ${d}`;function p(e){return`<!doctype html>
134
- <html lang="en">
135
- <head>
136
- <meta charset="utf-8">
137
- <meta http-equiv="Content-Security-Policy" content="${l}">
138
- <style id="slide-base">${f}</style>
139
- <script>${c}<\/script>
140
- <script defer src="${i}" integrity="${a}" crossorigin="anonymous"><\/script>
141
- </head>
142
- <body class="bg-white text-slate-900 font-sans antialiased">
143
- ${u(e)}
144
- </body>
145
- </html>`}var m=`presentSlide`,h=`defineStoryboard`,g=`presentPanel`,ee=4,te=12,ne=3,_=/^[0-9a-f]{12}$/,v=e=>typeof e==`object`&&!!e&&!Array.isArray(e),y=e=>typeof e==`string`?e.trim():``,b=(e,t)=>e.toLowerCase()===t.toLowerCase(),x=e=>typeof e==`number`&&Number.isInteger(e),S=`presentSlide needs slide and totalSlides (whole numbers, slide from 1 to totalSlides), and either an imagePrompt or html`,C=`presentSlide's html is too long: keep a slide under ${r} characters`;function w(e){let{slide:t,totalSlides:n,title:r,imagePrompt:i}=e,a=y(e.html);return!x(t)||!x(n)||t<1||n<t||!a&&!y(i)?S:a.length>6e4?C:{slide:t,totalSlides:n,title:typeof r==`string`?r:``,imagePrompt:a?``:String(i),...a&&{html:a},mode:e.mode===`steps`?`steps`:`presentation`}}var T=({slide:e,totalSlides:t,title:n,mode:r})=>{let i=n?` ("${n}")`:``;if(r===`steps`){let n=`Step ${e} of ${t}${i}`;return e<t?`${n} is now on the screen. Explain what to do in this step, then stop and wait while the user does it. When they say they're ready (next, done, go on), call presentSlide for step ${e+1} with mode "steps". If they ask to go back or to see a step again, call presentSlide for that step.`:`${n}, the last one, is now on the screen. Explain what to do, then wrap up the guide once the user is done.`}let a=`Slide ${e} of ${t}${i}`;return e<t?`${a} is now on the screen. Explain it, then, in this same reply and without waiting for the user, call presentSlide for slide ${e+1}. If the user has asked you to stop, or asked something else, since the slideshow began, answer them instead of going on.`:`${a}, the last one, is now on the screen. Explain it, then wrap up the slideshow.`},re=[`For an HTML slide, instead of imagePrompt: the slide's content, the inside of <body> only (no <html>, <head> or <body> tags), for a ${t}x720 px canvas, which it should fill (start with a <div class="w-full h-full ...">). Style it with Tailwind CSS v4 classes, which are loaded for you: a clear layout, a large title (text-6xl or so), few words in large type, a color scheme, and inline SVG or emoji for icons and diagrams. There is no network: no <img> from URLs, no links to follow.`,`Animate it so it builds up as you explain it, with MulmoCast's data-animation attributes (the same ones make it move in a movie of the slideshow): data-animation="animate" with data-opacity="0,1", data-translate-x, data-translate-y (px), data-scale, data-rotate (deg), data-width or data-height ("0,80,%"), each "from,to"; data-animation="counter" with data-from, data-to, data-decimals, data-prefix, data-suffix; data-animation="typewriter" (its text, or data-text). Give every one data-start and data-end in seconds, and optionally data-easing (linear, easeIn, easeOut, easeInOut); stagger the parts with later data-start values so they appear one after another over a few seconds (for example 0, 0.6, 1.2). Set the first frame inline too (style="opacity:0" on an element that fades in).`,`CSS animations, transitions and scripts don't play: animate only with data-animation. A <style> for layout is allowed (and Google Fonts by @import).`].join(` `),ie=`When the user asks for a slideshow (or to explain something with slides), plan four to six slides, then show them one at a time with presentSlide: slide 1 first, and each next slide only after you have explained the one on the screen. Go on to the last slide without asking whether to continue. A slide is a generated picture (imagePrompt) or a designed slide in HTML (html): use a picture for a scene, an object or a place, and HTML for words, numbers, lists, comparisons, timelines and diagrams, which a picture model draws badly; a slideshow can mix them. When the user asks for HTML slides (slides in HTML, an HTML presentation), this is the tool: make them HTML slides with presentSlide, one call per slide, not one HTML page. When the user wants to be shown how to do something they will do along with you (cooking, folding, fixing, an exercise), make it a step-by-step guide instead: mode "steps", one slide per step, and after each step wait for the user to say they are ready. Use generateImage for a single picture, not for slides.`,E={type:`function`,name:m,prompt:ie,description:`Show one slide of a slideshow, full screen: a picture generated from imagePrompt, or a slide written in HTML (html). Call it once per slide, in order, starting with slide 1. With mode "steps" it is a step-by-step guide: one slide per step, and the next step waits for the user.`,parameters:{type:`object`,properties:{slide:{type:`integer`,description:`This slide's number, starting at 1.`},totalSlides:{type:`integer`,description:`How many slides the slideshow has. Keep it the same for every slide.`},title:{type:`string`,description:`The slide's title.`},imagePrompt:{type:`string`,description:`For a picture slide: the picture, a clear illustration of its point, with the title as its only large text. Be concrete. For a step, show the action: hands, tools and the object. Leave it out for an HTML slide.`},html:{type:`string`,description:re},mode:{type:`string`,enum:[`presentation`,`steps`],description:`"presentation" (the default) goes on by itself; "steps" is a how-to the user does along with you, and waits for them after each step. Keep it the same for every slide.`}},required:[`slide`,`totalSlides`,`title`]}};function D(e){let{totalPanels:t}=e;if(!x(t)||t<1||t>12)return`totalPanels must be a whole number from 1 to 12`;let n=[];for(let t of Array.isArray(e.characters)?e.characters:[]){let e=v(t)?y(t.name):``,r=v(t)?y(t.description):``;if(!e||!r)return`every character needs a name and a description`;if(n.some(t=>b(t.name,e)))return`two characters are named ${e}`;n.push({name:e,description:r})}return n.length<1||n.length>4?`a storyboard has 1 to 4 characters`:{title:y(e.title),style:y(e.style),totalPanels:t,characters:n,interactive:e.interactive===!0}}var O=({title:e,id:t})=>`The cast of "${e}" is now on the screen. Introduce the characters briefly, then, in this same reply and without waiting for the user, call presentPanel for panel 1 with storyboardId "${t}". If the user has asked you to stop, or asked something else, answer them instead of going on.`,k=`presentPanel needs a storyboardId, a panel number (from 1) and an imagePrompt`;function A(e){let{panel:t}=e,n=y(e.storyboardId),r=y(e.imagePrompt);if(!n||!r||!x(t)||t<1)return null;let i=e=>(Array.isArray(e)?e:[]).map(y).filter(Boolean);return{storyboardId:n,panel:t,characters:i(e.characters),imagePrompt:r,caption:y(e.caption),choices:i(e.choices).slice(0,3)}}function j(e,t,n){let{id:r,totalPanels:i}=e;return n.length?`Panel ${t} of ${i} is now on the screen, with the user's choices: ${n.map((e,t)=>`${t+1}. ${e}`).join(` `)} Tell this part of the story, then read the choices out and ask the user which one they pick, and wait for their answer. Then call presentPanel for panel ${t+1} with storyboardId "${r}", going on the way they chose.`:t<i?`Panel ${t} of ${i} is now on the screen. Tell this part of the story, then, in this same reply and without waiting for the user, call presentPanel for panel ${t+1} with storyboardId "${r}". If the user has asked you to stop, or asked something else, since the story began, answer them instead of going on.`:`Panel ${t} of ${i}, the last one, is now on the screen. Tell this part of the story, then bring it to an end.`}var M=`When the user asks for a story, a picture book, a comic or a storyboard, tell it in pictures: first call defineStoryboard with the art style and the characters who appear more than once (it draws a reference sheet for each, so they look the same in every panel), then show the panels one at a time with presentPanel, naming the characters in each, and tell each part of the story when its panel appears. Go on to the last panel without asking whether to continue, unless the story is interactive. When the user wants to decide what happens (an adventure, a story for a child who wants to choose), set interactive, and give two or three choices on two or three of the panels: the story waits there for the user's pick and goes on their way; it still ends at the last panel whichever way it goes. Use presentSlide to explain a topic, not to tell a story.`,N={type:`function`,name:h,prompt:M,description:`Start a story told in pictures: set its art style and draw a reference sheet for each recurring character, shown as the cast. Then call presentPanel for each panel, in order.`,parameters:{type:`object`,properties:{title:{type:`string`,description:`The story's title.`},style:{type:`string`,description:`The art style of every picture, in one sentence (for example: soft watercolor, children's picture book).`},totalPanels:{type:`integer`,description:`How many panels the story has, at most 12; four to eight is usual.`},interactive:{type:`boolean`,description:`The user chooses what happens: panels can offer choices, and the story waits for the pick.`},characters:{type:`array`,description:`The characters who appear in more than one panel, 1 to 4.`,items:{type:`object`,properties:{name:{type:`string`,description:`A short name, used in presentPanel.`},description:{type:`string`,description:`How they look: age, build, face, hair, clothes and colors. Be concrete: it is drawn once and reused in every panel.`}},required:[`name`,`description`]}}},required:[`title`,`style`,`totalPanels`,`characters`]}},P={type:`function`,name:g,description:`Show one panel of a storyboard made with defineStoryboard: a picture of the scene with its characters drawn as in their reference sheets, and a caption. Call it once per panel, in order, starting with panel 1.`,parameters:{type:`object`,properties:{storyboardId:{type:`string`,description:`The storyboardId defineStoryboard returned.`},panel:{type:`integer`,description:`This panel's number, starting at 1.`},characters:{type:`array`,items:{type:`string`},description:`The names (as in defineStoryboard) of the characters in this panel.`},imagePrompt:{type:`string`,description:`What the panel shows: the setting, what happens, expressions and the camera angle. Refer to characters by name; don't describe their looks again.`},caption:{type:`string`,description:`One short line shown under the picture.`},choices:{type:`array`,items:{type:`string`},description:`Only in an interactive story, and not on the last panel: two or three short options for what happens next. The story waits for the user's pick.`}},required:[`storyboardId`,`panel`,`characters`,`imagePrompt`]}},F=e=>typeof e==`object`&&!!e&&!Array.isArray(e),ae=e=>F(e)&&typeof e.message==`string`;function I(e){let t=F(e?.data)?e.data:{};return{...typeof t.imageData==`string`&&{imageData:t.imageData},...typeof t.imagePath==`string`&&{imagePath:t.imagePath}}}function L(e){let t=F(e?.data)?e.data:{};return typeof t.html==`string`?t.html:``}var oe=e=>!!I(e).imageData||!!L(e);function se(e,t){let n=I(e),r=I(t);if(n.imagePath&&r.imagePath)return n.imagePath===r.imagePath;if(n.imageData)return n.imageData===r.imageData;let i=L(e);return!!i&&i===L(t)}var R=(e,t)=>e.userSpokeAt===void 0||e.userSpokeAt>t,z=()=>crypto.randomUUID().replace(/-/g,``).slice(0,12),ce=`artifacts/`;async function B(e,t){let n=e.files?.artifacts;if(!e.app?.editImages||!n)return[];let r=[];for(let e of t)if(e.startsWith(ce))try{await n.exists(e.slice(10))&&r.push(e)}catch{}return r}async function V(e,t,n=[]){let r=e.app,i=r?.editImages,a=r?.generateImage;try{let e;if(n.length&&i)e=await i(t,[...n]);else if(a)e=await a(t);else return{message:`image generation isn't available`};return ae(e)?e:{message:`image generation returned an unrecognized result`}}catch(e){return{message:`image generation failed: ${e instanceof Error?e.message:String(e)}`}}}var le=50;function ue(e){let t=new Map;return n=>{let r=n.conversationId??``,i=t.get(r);if(i===void 0?i=e():t.delete(r),t.set(r,i),t.size>le){let e=t.keys().next().value;e!==void 0&&t.delete(e)}return i}}var H=`slideshows`,U=`storyboards`,W={},G=new WeakMap,K=new WeakMap;function q(e){let t=G.get(e);return t||G.set(e,t=new Map),t}function de(t,n){let r=K.get(t);r||K.set(t,r=new Map);let i=r.get(n);return i||r.set(n,i=(0,e.createSerialLock)()),i}var J=(e,t)=>`${e}/${t}.json`;async function Y(e,t){let n=q(e??W),r=n.get(t);if(r)return r;if(!e)return null;try{let r=JSON.parse(await e.read(t));return n.set(t,r),r}catch{return null}}async function X(e,t,n){return _.test(n)?Y(e,J(t,n)):null}async function Z(e,t,n,r){let i=J(t,n),a=e??W;return de(a,i)(async()=>{let t=r(await Y(e,i));if(q(a).set(i,t),!e)return!1;try{return await e.write(i,JSON.stringify(t,null,2)),!0}catch(e){return console.warn(`[sequence] could not save`,i,e),!1}})}var Q=e=>`the ${e} could not be saved, so it lasts only until the app or server restarts`,fe=6e4;function $(){let e=new Map;return{claim:t=>{let n=Date.now();for(let[t,r]of e)n-r.at>fe&&e.delete(t);let r=e.get(t);if(r)return{earlier:r.shown};let i=()=>void 0,a=new Promise(e=>i=e);return e.set(t,{at:n,shown:a}),{settle:n=>{!n&&e.get(t)?.shown===a&&e.delete(t),i(n)}}}}}function pe({slide:e,totalSlides:t,mode:n}){return n===`steps`?{step:e,total:t,kind:`guide`,label:`Step ${e} of ${t}`,onShown:`explain it`,nextCall:`call presentSlide for step ${e+1} of ${t} with mode "steps"`,waitsForUser:!0}:{step:e,total:t,kind:`slideshow`,label:`Slide ${e} of ${t}`,onShown:`explain it`,nextCall:`call presentSlide for slide ${e+1} of ${t}`}}var me=(e,{slide:t,totalSlides:n,title:r,imagePrompt:i,html:a})=>JSON.stringify([e,t,n,r,i,a]),he=ue(()=>({latest:{presentation:null,steps:null},lastShown:null,repeats:$()}));function ge(e,t){let n=e.latest[t.mode],r=n?.totalSlides===t.totalSlides&&(t.slide!==1||n.firstTitle===t.title);if(n&&r)return n;let i={id:z(),mode:t.mode,totalSlides:t.totalSlides,firstTitle:t.slide===1?t.title:``,slides:new Map,current:0,shownAt:-1/0};return e.latest[t.mode]=i,i}function _e(e,t,n,r){t.current=n.slide,t.shownAt=Date.now(),e.lastShown=t;let i=n.mode===`steps`?`step`:`slide`,{uuid:a,...o}=r;return{...o,message:`${i} ${n.slide} of ${n.totalSlides} is on the screen again, as it was`,instructions:T(n),instructionsRequired:!0,sequence:pe(n)}}function ve(e,t){if(e.mode!==`steps`)return e.title?`A presentation slide titled "${e.title}". ${e.imagePrompt}`:e.imagePrompt;let n=e.title?`, "${e.title}"`:``;return[`An instructional illustration of step ${e.slide} of ${e.totalSlides}${n}. ${e.imagePrompt}`,t?`The reference image is the previous step: keep the same objects, hands, tools and setting, and show what this step changes.`:``,`Show the action clearly, with little or no text.`].filter(Boolean).join(` `)}async function ye(e,t,n){if(n.html)return{html:n.html,prompt:``};let r=t.slides.get(n.slide-1),i=n.mode===`steps`?I(r).imagePath:void 0,a=i?await B(e,[i]):[],o=ve(n,a.length>0),s=await V(e,o,a),{imageData:c,imagePath:l}=I(s);return c?{imageData:c,...l&&{imagePath:l},prompt:o}:{failed:{...s,sequence:null}}}async function be(e,t,n){let r=await ye(e,t,n);if(`failed`in r)return r.failed;let{imageData:i,imagePath:a,html:o,prompt:s}=r,c=t.id,l=await Z(e.files?.artifacts,H,c,e=>{let t=e??{id:c,title:``,mode:n.mode,totalSlides:n.totalSlides,slides:{}};return n.slide===1&&(t.title=n.title),t.slides[String(n.slide)]={title:n.title,imagePrompt:n.imagePrompt,...a&&{imagePath:a},...o&&{html:o}},t}),u={...i&&{imageData:i},...a&&{imagePath:a},...o&&{html:o},prompt:s,slideshowId:c,slide:n.slide,totalSlides:n.totalSlides,title:n.title,mode:n.mode},d=n.mode===`steps`?`step`:`slide`;return{data:u,title:n.title||`Slide ${n.slide}`,message:[`${d} ${n.slide} of ${n.totalSlides} of slideshow "${c}" is on the screen`,a?`saved to ${a}`:``,l?``:Q(`slideshow`)].filter(Boolean).join(`; `),instructions:T(n),instructionsRequired:!0,sequence:pe(n)}}async function xe(e,t){let n=w(t);if(typeof n==`string`)return{message:n,sequence:null};let r=he(e),i=ge(r,n),a=n.mode===`steps`;if(a&&n.slide>i.current&&i.current>0&&!R(e,i.shownAt)){console.info(`[sequence] holding step ${n.slide} for the user`);let e=i.shownAt===1/0?`is still being drawn`:`is still on the screen`;return{message:`step ${n.slide} was not shown: the user hasn't said they're ready yet, and step ${i.current} ${e}. Wait for them before calling presentSlide for step ${n.slide}.`,cancelled:!0}}let o=a?i.slides.get(n.slide):void 0;if(o)return se(e.currentResult,o)?{message:`step ${n.slide} of ${n.totalSlides} is already on the screen`,cancelled:!0}:_e(r,i,n,o);let s=r.repeats.claim(me(i.id,n));if(`earlier`in s){if(!await s.earlier)return xe(e,t);let a=i.slides.get(n.slide);return a&&r.lastShown!==i?_e(r,i,n,a):{message:`slide ${n.slide} of ${n.totalSlides} is already on the screen`,cancelled:!0}}let{settle:c}=s,l={current:i.current,shownAt:i.shownAt};i.current=n.slide,i.shownAt=1/0;let u=!1;try{let t=await be(e,i,n);return u=oe(t),u&&(i.slides.set(n.slide,t),i.current=n.slide,i.shownAt=Date.now(),r.lastShown=i),t}finally{c(u),!u&&i.current===n.slide&&(i.current=l.current,i.shownAt=l.shownAt)}}var Se=({id:e,title:t,totalPanels:n})=>({step:0,total:n,kind:`story`,label:`The cast of "${t}"`,onShown:`introduce the characters`,nextCall:`call presentPanel for panel 1 of ${n} with storyboardId "${e}"`}),Ce=({id:e,totalPanels:t},n,r)=>({step:n,total:t,kind:`story`,label:`Panel ${n} of ${t}`,onShown:`tell that part of the story`,nextCall:`call presentPanel for panel ${n+1} of ${t} with storyboardId "${e}"`,...r.length>0&&{waitsForUser:!0}}),we=(e,t)=>e?`${e}. ${t}`:t,Te=(e,{name:t,description:n})=>we(e,`Character reference sheet of ${t}: ${n}. Full body, front, side and back views, on a plain white background. No text or labels.`);async function Ee(e,t){let n=D(t);if(typeof n==`string`)return{message:n,sequence:null};let r=await Promise.all(n.characters.map(t=>V(e,Te(n.style,t)))),i=r.map(I),a=r.find((e,t)=>!i[t]?.imageData);if(i.every(({imageData:e})=>!e)&&a)return{...a,message:`the character sheets couldn't be made: ${a.message}`,sequence:null};let o={id:z(),...n,characters:n.characters.map((e,t)=>{let n=i[t]?.imagePath;return{...e,...n&&{imagePath:n}}}),panels:{}},s=await Z(e.files?.artifacts,U,o.id,()=>o),c=o.characters.filter(e=>e.imagePath).map(e=>`${e.name}: ${e.imagePath}`),l=n.characters.map(({name:e},t)=>i[t]?.imageData?null:`${e} (${r[t]?.message??``})`).filter(e=>!!e),u=i.find(e=>e.imageData)?.imageData;return{data:{storyboardId:o.id,title:o.title,totalPanels:o.totalPanels,...u&&{imageData:u},characters:o.characters.map(({name:e,imagePath:t},n)=>{let r=i[n]?.imageData;return{name:e,...r&&{imageData:r},...t&&{imagePath:t}}})},title:o.title,message:[`storyboard "${o.id}" is ready with ${o.totalPanels} panels; the cast is on the screen`,c.length?`character sheets saved to ${c.join(`, `)}`:``,l.length?`no sheet for ${l.join(`; `)}: they will be drawn from their description`:``,s?``:Q(`storyboard`)].filter(Boolean).join(`; `),instructions:O(o),instructionsRequired:!0,sequence:Se(o)}}function De(e,t,n){let r=[we(e.style,`Panel ${t.panel} of ${e.totalPanels} of the illustrated story "${e.title}". ${t.imagePrompt}`)],i=0,a=n.map(({character:e,hasSheet:t})=>t?`${e.name} is the character in reference image ${++i}`:`${e.name}: ${e.description}`);return a.length&&r.push(`${a.join(`. `)}.`),i&&r.push(`Draw each character exactly as in their reference image: the same face, hair, clothes and colors. Use the reference images only for how the characters look, not for their pose or the background.`),r.push(`No captions, speech bubbles or other text in the picture.`),r.join(` `)}async function Oe(e,t,n){let r=[],i=[];for(let a of n.characters){let n=t.characters.find(e=>b(e.name,a));if(!n)r.push(a);else if(!i.some(e=>e.character===n)){let[t]=n.imagePath?await B(e,[n.imagePath]):[];i.push({character:n,sheet:t??null})}}let a=i.map(({sheet:e})=>e).filter(e=>!!e),o=De(t,n,i.map(({character:e,sheet:t})=>({character:e,hasSheet:!!t}))),s=await V(e,o,a),{imageData:c,imagePath:l}=I(s);if(!c)return{...s,sequence:null};let u=n.panel<t.totalPanels&&n.choices.length>=2?n.choices:[],d=await Z(e.files?.artifacts,U,t.id,e=>{let r=e??t;return u.length&&(r.interactive=!0),r.panels[String(n.panel)]={caption:n.caption,characters:i.map(({character:e})=>e.name),imagePrompt:n.imagePrompt,...l&&{imagePath:l},...u.length&&{choices:u}},r});return{data:{imageData:c,...l&&{imagePath:l},prompt:o,storyboardId:t.id,panel:n.panel,totalPanels:t.totalPanels,caption:n.caption,...u.length&&{choices:u}},title:n.caption||`Panel ${n.panel}`,message:[`panel ${n.panel} of ${t.totalPanels} is on the screen`,l?`saved to ${l}`:``,r.length?`not in the cast, so drawn from the prompt alone: ${r.join(`, `)}`:``,d?``:Q(`storyboard`)].filter(Boolean).join(`; `),instructions:j(t,n.panel,u),instructionsRequired:!0,sequence:Ce(t,n.panel,u)}}var ke=ue(()=>({repeats:$(),awaitingChoice:new Map}));async function Ae(e,t){let n=A(t);if(!n)return{message:k,sequence:null};let{storyboardId:r,panel:i}=n,{repeats:a,awaitingChoice:o}=ke(e),s=o.get(r);if(s&&i>s.panel&&!R(e,s.shownAt))return console.info(`[sequence] holding panel ${i} for the user`),{message:s.shownAt===1/0?`panel ${i} was not shown: panel ${s.panel} is still being drawn. Wait for it before going on.`:`panel ${i} was not shown: the user hasn't picked a choice yet, and panel ${s.panel} is still on the screen. Wait for their answer.`,cancelled:!0};let c=a.claim(JSON.stringify(n));if(`earlier`in c)return await c.earlier?{message:`panel ${i} is already on the screen`,cancelled:!0}:Ae(e,t);let{settle:l}=c,u={panel:i,shownAt:1/0},d=o.get(r);o.set(r,u);let f=()=>o.get(r)===u,p=!1;try{let t=await X(e.files?.artifacts,U,r);if(!t)return{message:`there is no storyboard "${r}"; call defineStoryboard first`,sequence:null};if(i>t.totalPanels)return{message:`storyboard "${t.id}" has ${t.totalPanels} panels`,sequence:null};let a=await Oe(e,t,n);p=!!I(a).imageData;let s=a.data;return p&&f()&&(s?.choices?.length?o.set(r,{panel:i,shownAt:Date.now()}):o.delete(r)),a}finally{l(p),!p&&f()&&(d?o.set(r,d):o.delete(r))}}var je={toolDefinition:E,generatingMessage:`Making the slide...`,isEnabled:()=>!0,execute:(e,t)=>xe(e,t)},Me={toolDefinition:N,generatingMessage:`Drawing the characters...`,isEnabled:()=>!0,execute:(e,t)=>Ee(e,t)},Ne={toolDefinition:P,generatingMessage:`Drawing the panel...`,isEnabled:()=>!0,execute:(e,t)=>Ae(e,t)};Object.defineProperty(exports,"A",{enumerable:!0,get:function(){return o}}),Object.defineProperty(exports,"C",{enumerable:!0,get:function(){return j}}),Object.defineProperty(exports,"D",{enumerable:!0,get:function(){return b}}),Object.defineProperty(exports,"E",{enumerable:!0,get:function(){return D}}),Object.defineProperty(exports,"F",{enumerable:!0,get:function(){return p}}),Object.defineProperty(exports,"M",{enumerable:!0,get:function(){return d}}),Object.defineProperty(exports,"N",{enumerable:!0,get:function(){return n}}),Object.defineProperty(exports,"O",{enumerable:!0,get:function(){return T}}),Object.defineProperty(exports,"P",{enumerable:!0,get:function(){return t}}),Object.defineProperty(exports,"S",{enumerable:!0,get:function(){return O}}),Object.defineProperty(exports,"T",{enumerable:!0,get:function(){return w}}),Object.defineProperty(exports,"_",{enumerable:!0,get:function(){return ie}}),Object.defineProperty(exports,"a",{enumerable:!0,get:function(){return U}}),Object.defineProperty(exports,"b",{enumerable:!0,get:function(){return C}}),Object.defineProperty(exports,"c",{enumerable:!0,get:function(){return N}}),Object.defineProperty(exports,"d",{enumerable:!0,get:function(){return te}}),Object.defineProperty(exports,"f",{enumerable:!0,get:function(){return k}}),Object.defineProperty(exports,"g",{enumerable:!0,get:function(){return E}}),Object.defineProperty(exports,"h",{enumerable:!0,get:function(){return m}}),Object.defineProperty(exports,"i",{enumerable:!0,get:function(){return H}}),Object.defineProperty(exports,"j",{enumerable:!0,get:function(){return s}}),Object.defineProperty(exports,"k",{enumerable:!0,get:function(){return r}}),Object.defineProperty(exports,"l",{enumerable:!0,get:function(){return ee}}),Object.defineProperty(exports,"m",{enumerable:!0,get:function(){return P}}),Object.defineProperty(exports,"n",{enumerable:!0,get:function(){return Ne}}),Object.defineProperty(exports,"o",{enumerable:!0,get:function(){return X}}),Object.defineProperty(exports,"p",{enumerable:!0,get:function(){return g}}),Object.defineProperty(exports,"r",{enumerable:!0,get:function(){return je}}),Object.defineProperty(exports,"s",{enumerable:!0,get:function(){return h}}),Object.defineProperty(exports,"t",{enumerable:!0,get:function(){return Me}}),Object.defineProperty(exports,"u",{enumerable:!0,get:function(){return ne}}),Object.defineProperty(exports,"v",{enumerable:!0,get:function(){return _}}),Object.defineProperty(exports,"w",{enumerable:!0,get:function(){return A}}),Object.defineProperty(exports,"x",{enumerable:!0,get:function(){return M}}),Object.defineProperty(exports,"y",{enumerable:!0,get:function(){return S}});