@gui-chat-plugin/sequence 0.4.0 → 0.5.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -4,9 +4,9 @@ var t = 1280, n = 720, r = 6e4, i = "https://cdn.jsdelivr.net/npm/@tailwindcss/b
4
4
  "animate",
5
5
  "counter",
6
6
  "typewriter"
7
- ], s = 8, c = "\n(() => {\n const EASE = {\n linear: (t) => t,\n easeIn: (t) => t * t,\n easeOut: (t) => 1 - (1 - t) * (1 - t),\n easeInOut: (t) => (t < 0.5 ? 2 * t * t : 1 - Math.pow(-2 * t + 2, 2) / 2),\n };\n const AUTO_END = 8;\n const TRANSFORMS = [\n [\"data-translate-x\", \"translateX\", \"px\"],\n [\"data-translate-y\", \"translateY\", \"px\"],\n [\"data-scale\", \"scale\", \"\"],\n [\"data-rotate\", \"rotate\", \"deg\"],\n [\"data-rotate-x\", \"rotateX\", \"deg\"],\n [\"data-rotate-y\", \"rotateY\", \"deg\"],\n [\"data-rotate-z\", \"rotateZ\", \"deg\"],\n ];\n const STYLES = [\n [\"data-opacity\", \"opacity\", \"\"],\n [\"data-width\", \"width\", \"px\"],\n [\"data-height\", \"height\", \"px\"],\n ];\n const number = (value, fallback) => {\n const n = Number(value);\n return value !== null && value.trim() !== \"\" && Number.isFinite(n) ? n : fallback;\n };\n const range = (value, unit) => {\n if (value === null) return null;\n const parts = value.split(\",\").map((part) => part.trim());\n const from = Number(parts[0]);\n const to = Number(parts[1]);\n if (!Number.isFinite(from) || !Number.isFinite(to)) return null;\n return { from, to, unit: parts[2] || unit };\n };\n const ranges = (el, table) =>\n table\n .map(([attr, name, unit]) => [name, range(el.getAttribute(attr), unit)])\n .filter(([, r]) => r);\n let entries = [];\n const collect = () => {\n entries = [...document.querySelectorAll(\"[data-animation]\")].map((el) => {\n const kind = el.getAttribute(\"data-animation\");\n const end = el.getAttribute(\"data-end\");\n const entry = {\n el,\n kind,\n start: number(el.getAttribute(\"data-start\"), 0),\n end: end === null || end.trim() === \"auto\" ? null : number(end, null),\n ease: EASE[el.getAttribute(\"data-easing\")] || EASE.linear,\n };\n if (kind === \"animate\") {\n entry.transforms = ranges(el, TRANSFORMS);\n entry.styles = ranges(el, STYLES);\n } else if (kind === \"counter\") {\n entry.from = number(el.getAttribute(\"data-from\"), 0);\n entry.to = number(el.getAttribute(\"data-to\"), 0);\n entry.decimals = Math.max(0, Math.round(number(el.getAttribute(\"data-decimals\"), 0)));\n entry.prefix = el.getAttribute(\"data-prefix\") || \"\";\n entry.suffix = el.getAttribute(\"data-suffix\") || \"\";\n } else if (kind === \"typewriter\") {\n entry.text = el.getAttribute(\"data-text\") ?? el.textContent;\n } else {\n return null;\n }\n return entry;\n }).filter(Boolean);\n };\n const seek = (t) => {\n for (const e of entries) {\n const end = e.end ?? AUTO_END;\n const span = end - e.start;\n const p = span > 0 ? Math.min(1, Math.max(0, (t - e.start) / span)) : t >= e.start ? 1 : 0;\n const k = e.ease(p);\n const at = (r) => r.from + (r.to - r.from) * k;\n if (e.kind === \"animate\") {\n if (e.transforms.length) {\n e.el.style.transform = e.transforms.map(([name, r]) => name + \"(\" + at(r) + r.unit + \")\").join(\" \");\n }\n for (const [name, r] of e.styles) e.el.style[name] = at(r) + r.unit;\n } else if (e.kind === \"counter\") {\n e.el.textContent = e.prefix + (e.from + (e.to - e.from) * k).toFixed(e.decimals) + e.suffix;\n } else {\n e.el.textContent = e.text.slice(0, Math.floor(e.text.length * k));\n }\n }\n };\n window.__slideSeek = seek;\n const play = () => {\n const last = Math.max(0, ...entries.map((e) => e.end ?? AUTO_END));\n const begun = performance.now();\n const tick = (now) => {\n const t = (now - begun) / 1000;\n seek(t);\n if (t <= last) requestAnimationFrame(tick);\n };\n requestAnimationFrame(tick);\n };\n // Collected once the body is parsed: at DOMContentLoaded, or earlier when\n // the fallback shows the slide while a slow Tailwind still holds\n // DOMContentLoaded back (the body is parsed by then: readyState is\n // \"interactive\" before deferred scripts run). Played once both are done.\n let collected = false;\n let shown = false;\n const init = () => {\n if (collected || document.readyState === \"loading\") return;\n collected = true;\n collect();\n seek(0);\n if (shown) play();\n };\n const show = () => {\n if (shown) return;\n init();\n shown = true;\n document.documentElement.classList.add(\"ready\");\n if (collected) play();\n };\n const ready = () => requestAnimationFrame(() => requestAnimationFrame(show));\n const check = () =>\n document.querySelector(\"style:not([type]):not(#slide-base)\") ? ready() : setTimeout(check, 30);\n addEventListener(\"DOMContentLoaded\", () => {\n init();\n check();\n });\n setTimeout(show, 1000);\n addEventListener(\"click\", (event) => {\n if (event.target instanceof Element && event.target.closest(\"a, area\")) event.preventDefault();\n }, true);\n})();", l = [
7
+ ], s = 8, c = "\n(() => {\n const EASE = {\n linear: (t) => t,\n easeIn: (t) => t * t,\n easeOut: (t) => 1 - (1 - t) * (1 - t),\n easeInOut: (t) => (t < 0.5 ? 2 * t * t : 1 - Math.pow(-2 * t + 2, 2) / 2),\n };\n const AUTO_END = 8;\n const TRANSFORMS = [\n [\"data-translate-x\", \"translateX\", \"px\"],\n [\"data-translate-y\", \"translateY\", \"px\"],\n [\"data-scale\", \"scale\", \"\"],\n [\"data-rotate\", \"rotate\", \"deg\"],\n [\"data-rotate-x\", \"rotateX\", \"deg\"],\n [\"data-rotate-y\", \"rotateY\", \"deg\"],\n [\"data-rotate-z\", \"rotateZ\", \"deg\"],\n ];\n const STYLES = [\n [\"data-opacity\", \"opacity\", \"\"],\n [\"data-width\", \"width\", \"px\"],\n [\"data-height\", \"height\", \"px\"],\n ];\n const number = (value, fallback) => {\n const n = Number(value);\n return value !== null && value.trim() !== \"\" && Number.isFinite(n) ? n : fallback;\n };\n const range = (value, unit) => {\n if (value === null) return null;\n const parts = value.split(\",\").map((part) => part.trim());\n const from = Number(parts[0]);\n const to = Number(parts[1]);\n if (!Number.isFinite(from) || !Number.isFinite(to)) return null;\n return { from, to, unit: parts[2] || unit };\n };\n const ranges = (el, table) =>\n table\n .map(([attr, name, unit]) => [name, range(el.getAttribute(attr), unit)])\n .filter(([, r]) => r);\n let entries = [];\n const collect = () => {\n entries = [...document.querySelectorAll(\"[data-animation]\")].map((el) => {\n const kind = el.getAttribute(\"data-animation\");\n const end = el.getAttribute(\"data-end\");\n const entry = {\n el,\n kind,\n start: number(el.getAttribute(\"data-start\"), 0),\n end: end === null || end.trim() === \"auto\" ? null : number(end, null),\n ease: EASE[el.getAttribute(\"data-easing\")] || EASE.linear,\n };\n if (kind === \"animate\") {\n entry.transforms = ranges(el, TRANSFORMS);\n entry.styles = ranges(el, STYLES);\n } else if (kind === \"counter\") {\n entry.from = number(el.getAttribute(\"data-from\"), 0);\n entry.to = number(el.getAttribute(\"data-to\"), 0);\n entry.decimals = Math.max(0, Math.round(number(el.getAttribute(\"data-decimals\"), 0)));\n entry.prefix = el.getAttribute(\"data-prefix\") || \"\";\n entry.suffix = el.getAttribute(\"data-suffix\") || \"\";\n } else if (kind === \"typewriter\") {\n entry.text = el.getAttribute(\"data-text\") ?? el.textContent;\n } else {\n return null;\n }\n return entry;\n }).filter(Boolean);\n };\n const seek = (t) => {\n for (const e of entries) {\n const end = e.end ?? AUTO_END;\n const span = end - e.start;\n const p = span > 0 ? Math.min(1, Math.max(0, (t - e.start) / span)) : t >= e.start ? 1 : 0;\n const k = e.ease(p);\n const at = (r) => r.from + (r.to - r.from) * k;\n if (e.kind === \"animate\") {\n if (e.transforms.length) {\n e.el.style.transform = e.transforms.map(([name, r]) => name + \"(\" + at(r) + r.unit + \")\").join(\" \");\n }\n for (const [name, r] of e.styles) e.el.style[name] = at(r) + r.unit;\n } else if (e.kind === \"counter\") {\n e.el.textContent = e.prefix + (e.from + (e.to - e.from) * k).toFixed(e.decimals) + e.suffix;\n } else {\n e.el.textContent = e.text.slice(0, Math.floor(e.text.length * k));\n }\n }\n };\n window.__slideSeek = seek;\n const fit = () => {\n for (const el of document.querySelectorAll(\"[data-fit]\")) {\n let size = parseFloat(getComputedStyle(el).fontSize);\n while (size > 12 && (el.scrollHeight > el.clientHeight + 1 || el.scrollWidth > el.clientWidth + 1)) {\n size -= 1;\n el.style.fontSize = size + \"px\";\n }\n }\n };\n const play = () => {\n const last = Math.max(0, ...entries.map((e) => e.end ?? AUTO_END));\n const begun = performance.now();\n const tick = (now) => {\n const t = (now - begun) / 1000;\n seek(t);\n if (t <= last) requestAnimationFrame(tick);\n };\n requestAnimationFrame(tick);\n };\n // Collected once the body is parsed: at DOMContentLoaded, or earlier when\n // the fallback shows the slide while a slow Tailwind still holds\n // DOMContentLoaded back (the body is parsed by then: readyState is\n // \"interactive\" before deferred scripts run). Played once both are done.\n let collected = false;\n let shown = false;\n const init = () => {\n if (collected || document.readyState === \"loading\") return;\n collected = true;\n collect();\n seek(0);\n if (shown) play();\n };\n const show = () => {\n if (shown) return;\n init();\n fit();\n shown = true;\n document.documentElement.classList.add(\"ready\");\n if (collected) play();\n };\n const ready = () => requestAnimationFrame(() => requestAnimationFrame(show));\n const check = () =>\n document.querySelector(\"style:not([type]):not(#slide-base)\") ? ready() : setTimeout(check, 30);\n addEventListener(\"DOMContentLoaded\", () => {\n init();\n check();\n });\n setTimeout(show, 1000);\n addEventListener(\"click\", (event) => {\n if (event.target instanceof Element && event.target.closest(\"a, area\")) event.preventDefault();\n }, true);\n})();", l = [
8
8
  "default-src 'none'",
9
- `script-src 'sha256-0zsqCvkCfq5Z1iJCn46NiAtSAyIr/JDkyNs/Fae1J+Y=' ${i}`,
9
+ `script-src 'sha256-bNBxv6ehYc2PHOgmTReFSYsrxiGvq6aqqg9m5RwS7Lc=' ${i}`,
10
10
  "style-src 'unsafe-inline' https://fonts.googleapis.com",
11
11
  "font-src https://fonts.gstatic.com data:",
12
12
  "img-src data: blob:",
@@ -14,56 +14,121 @@ var t = 1280, n = 720, r = 6e4, i = "https://cdn.jsdelivr.net/npm/@tailwindcss/b
14
14
  "connect-src 'none'",
15
15
  "form-action 'none'",
16
16
  "base-uri 'none'"
17
- ].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 = `
17
+ ].join("; "), u = {
18
+ "&": "&amp;",
19
+ "<": "&lt;",
20
+ ">": "&gt;",
21
+ "\"": "&quot;"
22
+ }, d = (e) => e.replace(/[&<>"]/g, (e) => u[e] ?? e), f = (e) => e.replace(/<(?=(meta|base|link)\b)/gi, "&lt;").replace(/shadowroot/gi, "data-no-shadow-root"), p = "*, *::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; }", ee = `
18
23
  html, body { margin: 0; width: ${t}px; height: 720px; overflow: hidden; }
19
24
  html:not(.ready) body { visibility: hidden; }
20
- ${d}`;
21
- function p(e) {
25
+ ${p}`;
26
+ function te(e) {
22
27
  return `<!doctype html>
23
28
  <html lang="en">
24
29
  <head>
25
30
  <meta charset="utf-8">
26
31
  <meta http-equiv="Content-Security-Policy" content="${l}">
27
- <style id="slide-base">${f}</style>
32
+ <style id="slide-base">${ee}</style>
28
33
  <script>${c}<\/script>
29
34
  <script defer src="${i}" integrity="${a}" crossorigin="anonymous"><\/script>
30
35
  </head>
31
36
  <body class="bg-white text-slate-900 font-sans antialiased">
32
- ${u(e)}
37
+ ${f(e)}
38
+ </body>
39
+ </html>`;
40
+ }
41
+ //#endregion
42
+ //#region src/core/chartSlide.ts
43
+ var m = [
44
+ "bar",
45
+ "line",
46
+ "pie",
47
+ "doughnut",
48
+ "radar",
49
+ "polarArea",
50
+ "scatter",
51
+ "bubble"
52
+ ], h = "https://cdn.jsdelivr.net/npm/chart.js@4.5.1/dist/chart.umd.min.js", ne = "sha384-jb8JQMbMoBUzgWatfe6COACi2ljcDdZQ2OxczGA3bGNeWe+6DChMTBJemed7ZnvJ", re = "\n(() => {\n const fail = (why) => {\n document.getElementById(\"chart-error\").textContent = why;\n document.documentElement.classList.add(\"failed\");\n };\n addEventListener(\"DOMContentLoaded\", () => {\n if (!window.Chart) return fail(\"The chart couldn't be drawn: Chart.js didn't load.\");\n let config;\n try {\n config = JSON.parse(document.getElementById(\"chart-config\").textContent);\n } catch {\n return fail(\"The chart couldn't be drawn: its configuration isn't valid.\");\n }\n Chart.defaults.font.size = 22;\n Chart.defaults.color = \"#334155\";\n Chart.defaults.animation.duration = 1200;\n config.options = { ...config.options, responsive: true, maintainAspectRatio: false };\n try {\n new Chart(document.getElementById(\"chart\"), config);\n } catch (error) {\n fail(\"The chart couldn't be drawn: \" + (error && error.message ? error.message : error));\n }\n });\n})();", ie = [
53
+ "default-src 'none'",
54
+ `script-src 'sha256-TfZZxJX+yWgzYLy7zqsMa85OJEaC+zNLIpKLDZVnUqA=' ${h}`,
55
+ "style-src 'unsafe-inline'",
56
+ "img-src data: blob:",
57
+ "connect-src 'none'",
58
+ "form-action 'none'",
59
+ "base-uri 'none'"
60
+ ].join("; "), ae = `
61
+ html, body { margin: 0; width: ${t}px; height: 720px; overflow: hidden; background: #ffffff; color: #0f172a; font-family: ui-sans-serif, system-ui, sans-serif; }
62
+ body { box-sizing: border-box; padding: 40px 64px 48px; display: flex; flex-direction: column; gap: 24px; }
63
+ h1 { margin: 0; font-size: 52px; font-weight: 800; color: #1e3a8a; line-height: 1.15; text-align: center; }
64
+ .chart { position: relative; flex: 1; min-height: 0; }
65
+ #chart-error { display: none; margin: auto; font-size: 28px; color: #b91c1c; }
66
+ .failed .chart { display: none; }
67
+ .failed #chart-error { display: block; }`, oe = (e) => JSON.stringify(e).replace(/</g, "\\u003c");
68
+ function se(e, t) {
69
+ return `<!doctype html>
70
+ <html lang="en">
71
+ <head>
72
+ <meta charset="utf-8">
73
+ <meta http-equiv="Content-Security-Policy" content="${ie}">
74
+ <style>${ae}</style>
75
+ <script>${re}<\/script>
76
+ <script defer src="${h}" integrity="${ne}" crossorigin="anonymous"><\/script>
77
+ <script type="application/json" id="chart-config">${oe(t)}<\/script>
78
+ </head>
79
+ <body>
80
+ ${e ? `<h1>${d(e)}</h1>` : ""}
81
+ <div class="chart"><canvas id="chart"></canvas></div>
82
+ <p id="chart-error"></p>
33
83
  </body>
34
84
  </html>`;
35
85
  }
36
86
  //#endregion
37
87
  //#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) {
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 : {
88
+ var g = "presentSlide", _ = "defineStoryboard", v = "presentPanel", ce = 4, le = 12, ue = 3, de = /^[0-9a-f]{12}$/, y = (e) => typeof e == "object" && !!e && !Array.isArray(e), b = (e) => typeof e == "string" ? e.trim() : "", x = (e, t) => e.toLowerCase() === t.toLowerCase(), S = (e) => typeof e == "number" && Number.isInteger(e), fe = "presentSlide needs slide and totalSlides (whole numbers, slide from 1 to totalSlides), and one of imagePrompt, html, markdown or chart", C = `presentSlide's slide is too long: keep its html, markdown or chart under ${r} characters`, w = `presentSlide's chart must be a Chart.js configuration: an object with type (${m.join(", ")}), data ({ labels, datasets }) and optionally options`;
89
+ function pe(e) {
90
+ let t = e;
91
+ if (typeof t == "string") try {
92
+ t = JSON.parse(t);
93
+ } catch {
94
+ return null;
95
+ }
96
+ if (!y(t) || !y(t.data)) return null;
97
+ let n = t.type;
98
+ return !m.some((e) => e === n) || t.options !== void 0 && !y(t.options) ? null : t;
99
+ }
100
+ function me(e) {
101
+ let { slide: t, totalSlides: n, title: r, imagePrompt: i } = e, a = b(e.html), o = a ? "" : b(e.markdown), s = !a && !o && e.chart !== void 0 && e.chart !== null;
102
+ if (!S(t) || !S(n) || t < 1 || n < t || !a && !o && !s && !b(i)) return fe;
103
+ let c = s ? pe(e.chart) : null;
104
+ return s && !c ? w : Math.max(a.length, o.length, c ? JSON.stringify(c).length : 0) > 6e4 ? C : {
42
105
  slide: t,
43
106
  totalSlides: n,
44
107
  title: typeof r == "string" ? r : "",
45
- imagePrompt: a ? "" : String(i),
108
+ imagePrompt: !a && !o && !c ? String(i) : "",
46
109
  ...a && { html: a },
110
+ ...o && { markdown: o },
111
+ ...c && { chart: c },
47
112
  mode: e.mode === "steps" ? "steps" : "presentation"
48
113
  };
49
114
  }
50
- var T = ({ slide: e, totalSlides: t, title: n, mode: r }) => {
115
+ var he = "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
116
  let i = n ? ` ("${n}")` : "";
52
117
  if (r === "steps") {
53
118
  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.`;
119
+ 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
120
  }
56
121
  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 = [
122
+ return e < t ? `${a} is now on the screen. Explain it: ${he} 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: ${he} Then wrap up the slideshow.`;
123
+ }, ge = [
59
124
  `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
125
  "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
126
  "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 = {
127
+ ].join(" "), _e = "For a Markdown slide, instead of imagePrompt: the slide in Markdown (GitHub's: headings, lists, bold, tables, code), with math in TeX between $...$ inline or $$...$$ for a displayed equation (on lines of its own). Start with a # heading, and keep it to what fits on one slide: a heading and a few lines, a list or an equation or two. Write a dollar sign that isn't math as \\$.", ve = `For a chart slide, instead of imagePrompt: a Chart.js configuration as JSON text, {"type": ..., "data": ...}: { type, data: { labels, datasets: [{ label, data, backgroundColor }] }, options }. type is one of ${m.join(", ")}. It is drawn under the slide's title, so leave out options.plugins.title; give the datasets colors, and the axes titles (options.scales.x.title) when their units aren't obvious. JSON values only: no functions.`, ye = "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), a chart (chart), a text slide in Markdown (markdown) or a designed slide in HTML (html): use a picture for a scene, an object or a place; a chart for numbers to compare, a trend or proportions; Markdown for equations and formulas (TeX math), definitions, short lists and small tables; and HTML for designed layouts, comparisons, timelines and diagrams. A picture model draws words, numbers and math badly, so they go on the other kinds; 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 = {
63
128
  type: "function",
64
- name: m,
65
- prompt: ie,
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.",
129
+ name: g,
130
+ prompt: ye,
131
+ description: "Show one slide of a slideshow, full screen: a picture generated from imagePrompt, a chart (chart), a slide written in Markdown with TeX math (markdown), or a slide written in HTML (html). Give one of the four. 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
132
  parameters: {
68
133
  type: "object",
69
134
  properties: {
@@ -81,11 +146,19 @@ var T = ({ slide: e, totalSlides: t, title: n, mode: r }) => {
81
146
  },
82
147
  imagePrompt: {
83
148
  type: "string",
84
- 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."
149
+ 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 a chart, Markdown or HTML slide."
85
150
  },
86
151
  html: {
87
152
  type: "string",
88
- description: re
153
+ description: ge
154
+ },
155
+ markdown: {
156
+ type: "string",
157
+ description: _e
158
+ },
159
+ chart: {
160
+ type: "string",
161
+ description: ve
89
162
  },
90
163
  mode: {
91
164
  type: "string",
@@ -102,20 +175,20 @@ var T = ({ slide: e, totalSlides: t, title: n, mode: r }) => {
102
175
  };
103
176
  function D(e) {
104
177
  let { totalPanels: t } = e;
105
- if (!x(t) || t < 1 || t > 12) return "totalPanels must be a whole number from 1 to 12";
178
+ if (!S(t) || t < 1 || t > 12) return "totalPanels must be a whole number from 1 to 12";
106
179
  let n = [];
107
180
  for (let t of Array.isArray(e.characters) ? e.characters : []) {
108
- let e = v(t) ? y(t.name) : "", r = v(t) ? y(t.description) : "";
181
+ let e = y(t) ? b(t.name) : "", r = y(t) ? b(t.description) : "";
109
182
  if (!e || !r) return "every character needs a name and a description";
110
- if (n.some((t) => b(t.name, e))) return `two characters are named ${e}`;
183
+ if (n.some((t) => x(t.name, e))) return `two characters are named ${e}`;
111
184
  n.push({
112
185
  name: e,
113
186
  description: r
114
187
  });
115
188
  }
116
189
  return n.length < 1 || n.length > 4 ? "a storyboard has 1 to 4 characters" : {
117
- title: y(e.title),
118
- style: y(e.style),
190
+ title: b(e.title),
191
+ style: b(e.style),
119
192
  totalPanels: t,
120
193
  characters: n,
121
194
  interactive: e.interactive === !0
@@ -123,15 +196,15 @@ function D(e) {
123
196
  }
124
197
  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
198
  function A(e) {
126
- let { panel: t } = e, n = y(e.storyboardId), r = y(e.imagePrompt);
127
- if (!n || !r || !x(t) || t < 1) return null;
128
- let i = (e) => (Array.isArray(e) ? e : []).map(y).filter(Boolean);
199
+ let { panel: t } = e, n = b(e.storyboardId), r = b(e.imagePrompt);
200
+ if (!n || !r || !S(t) || t < 1) return null;
201
+ let i = (e) => (Array.isArray(e) ? e : []).map(b).filter(Boolean);
129
202
  return {
130
203
  storyboardId: n,
131
204
  panel: t,
132
205
  characters: i(e.characters),
133
206
  imagePrompt: r,
134
- caption: y(e.caption),
207
+ caption: b(e.caption),
135
208
  choices: i(e.choices).slice(0, 3)
136
209
  };
137
210
  }
@@ -141,7 +214,7 @@ function j(e, t, n) {
141
214
  }
142
215
  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 = {
143
216
  type: "function",
144
- name: h,
217
+ name: _,
145
218
  prompt: M,
146
219
  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
220
  parameters: {
@@ -191,7 +264,7 @@ var M = "When the user asks for a story, a picture book, a comic or a storyboard
191
264
  }
192
265
  }, P = {
193
266
  type: "function",
194
- name: g,
267
+ name: v,
195
268
  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.",
196
269
  parameters: {
197
270
  type: "object",
@@ -230,7 +303,7 @@ var M = "When the user asks for a story, a picture book, a comic or a storyboard
230
303
  "imagePrompt"
231
304
  ]
232
305
  }
233
- }, F = (e) => typeof e == "object" && !!e && !Array.isArray(e), ae = (e) => F(e) && typeof e.message == "string";
306
+ }, F = (e) => typeof e == "object" && !!e && !Array.isArray(e), be = (e) => F(e) && typeof e.message == "string";
234
307
  function I(e) {
235
308
  let t = F(e?.data) ? e.data : {};
236
309
  return {
@@ -242,42 +315,48 @@ function L(e) {
242
315
  let t = F(e?.data) ? e.data : {};
243
316
  return typeof t.html == "string" ? t.html : "";
244
317
  }
245
- var oe = (e) => !!I(e).imageData || !!L(e);
246
- function se(e, t) {
318
+ function R(e) {
319
+ let t = F(e?.data) ? e.data : {};
320
+ return F(t.chart) ? JSON.stringify(t.chart) : "";
321
+ }
322
+ var xe = (e) => !!I(e).imageData || !!L(e) || !!R(e);
323
+ function Se(e, t) {
247
324
  let n = I(e), r = I(t);
248
325
  if (n.imagePath && r.imagePath) return n.imagePath === r.imagePath;
249
326
  if (n.imageData) return n.imageData === r.imageData;
250
327
  let i = L(e);
251
- return !!i && i === L(t);
328
+ if (i) return i === L(t);
329
+ let a = R(e);
330
+ return !!a && a === R(t);
252
331
  }
253
- var R = (e, t) => e.userSpokeAt === void 0 || e.userSpokeAt > t, z = () => crypto.randomUUID().replace(/-/g, "").slice(0, 12), ce = "artifacts/";
254
- async function B(e, t) {
332
+ var z = (e, t) => e.userSpokeAt === void 0 || e.userSpokeAt > t, B = () => crypto.randomUUID().replace(/-/g, "").slice(0, 12), Ce = "artifacts/";
333
+ async function V(e, t) {
255
334
  let n = e.files?.artifacts;
256
335
  if (!e.app?.editImages || !n) return [];
257
336
  let r = [];
258
- for (let e of t) if (e.startsWith(ce)) try {
337
+ for (let e of t) if (e.startsWith(Ce)) try {
259
338
  await n.exists(e.slice(10)) && r.push(e);
260
339
  } catch {}
261
340
  return r;
262
341
  }
263
- async function V(e, t, n = []) {
342
+ async function H(e, t, n = []) {
264
343
  let r = e.app, i = r?.editImages, a = r?.generateImage;
265
344
  try {
266
345
  let e;
267
346
  if (n.length && i) e = await i(t, [...n]);
268
347
  else if (a) e = await a(t);
269
348
  else return { message: "image generation isn't available" };
270
- return ae(e) ? e : { message: "image generation returned an unrecognized result" };
349
+ return be(e) ? e : { message: "image generation returned an unrecognized result" };
271
350
  } catch (e) {
272
351
  return { message: `image generation failed: ${e instanceof Error ? e.message : String(e)}` };
273
352
  }
274
353
  }
275
- var le = 50;
276
- function ue(e) {
354
+ var we = 50;
355
+ function U(e) {
277
356
  let t = /* @__PURE__ */ new Map();
278
357
  return (n) => {
279
358
  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) {
359
+ if (i === void 0 ? i = e() : t.delete(r), t.set(r, i), t.size > we) {
281
360
  let e = t.keys().next().value;
282
361
  e !== void 0 && t.delete(e);
283
362
  }
@@ -285,21 +364,112 @@ function ue(e) {
285
364
  };
286
365
  }
287
366
  //#endregion
367
+ //#region src/core/markdownSlide.ts
368
+ var W = "slide-md", Te = `
369
+ .${W} { box-sizing: border-box; width: ${t}px; height: 720px; padding: 56px 80px; overflow: hidden; display: flex; flex-direction: column; justify-content: center; gap: 0.5em; background: #ffffff; color: #0f172a; font-family: ui-sans-serif, system-ui, sans-serif; line-height: 1.35; }
370
+ .${W} > * { margin: 0; }
371
+ .${W} h1 { font-size: 1.9em; font-weight: 800; color: #1e3a8a; line-height: 1.15; }
372
+ .${W} h2 { font-size: 1.5em; font-weight: 700; color: #1e40af; line-height: 1.2; }
373
+ .${W} h3 { font-size: 1.2em; font-weight: 700; color: #334155; }
374
+ .${W} ul, .${W} ol { padding-left: 1.3em; display: flex; flex-direction: column; gap: 0.3em; }
375
+ .${W} ul { list-style: disc; }
376
+ .${W} ol { list-style: decimal; }
377
+ .${W} li > ul, .${W} li > ol { margin-top: 0.3em; font-size: 0.9em; }
378
+ .${W} li::marker { color: #2563eb; }
379
+ .${W} strong { font-weight: 700; color: #1e3a8a; }
380
+ .${W} em { font-style: italic; }
381
+ .${W} a { color: #2563eb; text-decoration: underline; }
382
+ .${W} code { font-family: ui-monospace, monospace; font-size: 0.85em; background: #f1f5f9; border-radius: 0.2em; padding: 0.05em 0.3em; }
383
+ .${W} pre { background: #0f172a; color: #e2e8f0; border-radius: 0.4em; padding: 0.6em 0.8em; font-size: 0.75em; overflow: hidden; }
384
+ .${W} pre code { background: none; padding: 0; color: inherit; }
385
+ .${W} blockquote { border-left: 0.2em solid #93c5fd; padding-left: 0.8em; color: #475569; font-style: italic; }
386
+ .${W} table { border-collapse: collapse; font-size: 0.85em; align-self: flex-start; }
387
+ .${W} th, .${W} td { border: 1px solid #cbd5e1; padding: 0.25em 0.7em; text-align: left; }
388
+ .${W} th { background: #eff6ff; font-weight: 700; }
389
+ .${W} hr { border: 0; border-top: 2px solid #e2e8f0; }
390
+ .${W} img { max-width: 100%; max-height: 60%; }
391
+ .${W} .math-display { display: block; text-align: center; font-size: 1.15em; }
392
+ .${W} math { font-family: "Latin Modern Math", "STIX Two Math", "Cambria Math", math; }
393
+ .${W} mtd { padding: 0.1em 0.4em; }
394
+ .${W} mtd:first-child { padding-left: 0; }
395
+ .${W} mtd:last-child { padding-right: 0; }
396
+ .${W} .math-error { color: #b91c1c; font-family: ui-monospace, monospace; }`;
397
+ function Ee(e) {
398
+ let t = e.split("\n").filter((e) => e.trim()).length, n = e.length;
399
+ return t <= 5 && n <= 250 ? 40 : t <= 8 && n <= 450 ? 34 : t <= 12 && n <= 700 ? 28 : 24;
400
+ }
401
+ var De = /^[ \t]*(?:\$\$([\s\S]+?)\$\$|\\\[([\s\S]+?)\\\])[ \t]*(?:\n|$)/, Oe = /^(?:\$\$(.+?)\$\$|\$(?!\s)((?:\\.|[^\\$\n])+?)(?<!\s)\$(?!\d)|\\\((.+?)\\\))/;
402
+ function ke(e) {
403
+ return [{
404
+ name: "blockMath",
405
+ level: "block",
406
+ start: (e) => {
407
+ let t = /(^|\n)(?=[ \t]*(?:\$\$|\\\[))/.exec(e);
408
+ return t ? t.index + (t[1] ?? "").length : void 0;
409
+ },
410
+ tokenizer(e) {
411
+ let t = De.exec(e);
412
+ if (t) return {
413
+ type: "blockMath",
414
+ raw: t[0],
415
+ text: (t[1] ?? t[2] ?? "").trim()
416
+ };
417
+ },
418
+ renderer: (t) => `<div class="math-display">${e(String(t.text), !0)}</div>\n`
419
+ }, {
420
+ name: "inlineMath",
421
+ level: "inline",
422
+ start: (e) => e.match(/(?<!\\)\$|\\\(/)?.index,
423
+ tokenizer(e) {
424
+ let t = Oe.exec(e);
425
+ if (t) return {
426
+ type: "inlineMath",
427
+ raw: t[0],
428
+ text: (t[1] ?? t[2] ?? t[3] ?? "").trim(),
429
+ display: t[1] !== void 0
430
+ };
431
+ },
432
+ renderer: (t) => e(String(t.text), t.display === !0)
433
+ }];
434
+ }
435
+ var Ae = /(<\/mi>|<\/mn>|<\/mrow>|<mo[^>]*>[)\]]<\/mo>)?(<mi(?: mathvariant="normal")?>[A-Za-z]{2,}<\/mi>)<mo>\u2061<\/mo>/g, je = "<mspace width=\"0.1667em\"></mspace>", Me = (e) => e.replace(Ae, (e, t, n) => `${t ? t + je : ""}${n}<mo lspace="0" rspace="0.1667em">\u2061</mo>`);
436
+ async function G(e) {
437
+ let [{ Marked: t }, { default: n }] = await Promise.all([import("marked"), import("katex")]), r = (e, t) => {
438
+ try {
439
+ return Me(n.renderToString(e, {
440
+ output: "mathml",
441
+ displayMode: t,
442
+ throwOnError: !0
443
+ }));
444
+ } catch {
445
+ return `<code class="math-error">${d(e)}</code>`;
446
+ }
447
+ }, i = new t({
448
+ gfm: !0,
449
+ breaks: !1
450
+ });
451
+ i.use({ extensions: ke(r) });
452
+ let a = await i.parse(e);
453
+ return `<style>${Te}</style>
454
+ <div class="${W}" data-fit style="font-size: ${Ee(e)}px">
455
+ ${a}</div>`;
456
+ }
457
+ //#endregion
288
458
  //#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;
293
- }
294
- function de(t, n) {
295
- let r = K.get(t);
296
- r || K.set(t, r = /* @__PURE__ */ new Map());
459
+ var K = "slideshows", q = "storyboards", J = {}, Y = /* @__PURE__ */ new WeakMap(), X = /* @__PURE__ */ new WeakMap();
460
+ function Ne(e) {
461
+ let t = Y.get(e);
462
+ return t || Y.set(e, t = /* @__PURE__ */ new Map()), t;
463
+ }
464
+ function Pe(t, n) {
465
+ let r = X.get(t);
466
+ r || X.set(t, r = /* @__PURE__ */ new Map());
297
467
  let i = r.get(n);
298
468
  return i || r.set(n, i = e()), i;
299
469
  }
300
- var J = (e, t) => `${e}/${t}.json`;
301
- async function Y(e, t) {
302
- let n = q(e ?? W), r = n.get(t);
470
+ var Fe = (e, t) => `${e}/${t}.json`;
471
+ async function Ie(e, t) {
472
+ let n = Ne(e ?? J), r = n.get(t);
303
473
  if (r) return r;
304
474
  if (!e) return null;
305
475
  try {
@@ -309,14 +479,14 @@ async function Y(e, t) {
309
479
  return null;
310
480
  }
311
481
  }
312
- async function X(e, t, n) {
313
- return _.test(n) ? Y(e, J(t, n)) : null;
482
+ async function Le(e, t, n) {
483
+ return de.test(n) ? Ie(e, Fe(t, n)) : null;
314
484
  }
315
485
  async function Z(e, t, n, r) {
316
- let i = J(t, n), a = e ?? W;
317
- return de(a, i)(async () => {
318
- let t = r(await Y(e, i));
319
- if (q(a).set(i, t), !e) return !1;
486
+ let i = Fe(t, n), a = e ?? J;
487
+ return Pe(a, i)(async () => {
488
+ let t = r(await Ie(e, i));
489
+ if (Ne(a).set(i, t), !e) return !1;
320
490
  try {
321
491
  return await e.write(i, JSON.stringify(t, null, 2)), !0;
322
492
  } catch (e) {
@@ -324,12 +494,12 @@ async function Z(e, t, n, r) {
324
494
  }
325
495
  });
326
496
  }
327
- var Q = (e) => `the ${e} could not be saved, so it lasts only until the app or server restarts`, fe = 6e4;
328
- function $() {
497
+ var Q = (e) => `the ${e} could not be saved, so it lasts only until the app or server restarts`, Re = 6e4;
498
+ function ze() {
329
499
  let e = /* @__PURE__ */ new Map();
330
500
  return { claim: (t) => {
331
501
  let n = Date.now();
332
- for (let [t, r] of e) n - r.at > fe && e.delete(t);
502
+ for (let [t, r] of e) n - r.at > Re && e.delete(t);
333
503
  let r = e.get(t);
334
504
  if (r) return { earlier: r.shown };
335
505
  let i = () => void 0, a = new Promise((e) => i = e);
@@ -343,7 +513,7 @@ function $() {
343
513
  }
344
514
  //#endregion
345
515
  //#region src/core/presentSlide.ts
346
- function pe({ slide: e, totalSlides: t, mode: n }) {
516
+ function Be({ slide: e, totalSlides: t, mode: n }) {
347
517
  return n === "steps" ? {
348
518
  step: e,
349
519
  total: t,
@@ -361,26 +531,28 @@ function pe({ slide: e, totalSlides: t, mode: n }) {
361
531
  nextCall: `call presentSlide for slide ${e + 1} of ${t}`
362
532
  };
363
533
  }
364
- var me = (e, { slide: t, totalSlides: n, title: r, imagePrompt: i, html: a }) => JSON.stringify([
534
+ var Ve = (e, { slide: t, totalSlides: n, title: r, imagePrompt: i, html: a, markdown: o, chart: s }) => JSON.stringify([
365
535
  e,
366
536
  t,
367
537
  n,
368
538
  r,
369
539
  i,
370
- a
371
- ]), he = ue(() => ({
540
+ a,
541
+ o,
542
+ s
543
+ ]), He = U(() => ({
372
544
  latest: {
373
545
  presentation: null,
374
546
  steps: null
375
547
  },
376
548
  lastShown: null,
377
- repeats: $()
549
+ repeats: ze()
378
550
  }));
379
- function ge(e, t) {
551
+ function Ue(e, t) {
380
552
  let n = e.latest[t.mode], r = n?.totalSlides === t.totalSlides && (t.slide !== 1 || n.firstTitle === t.title);
381
553
  if (n && r) return n;
382
554
  let i = {
383
- id: z(),
555
+ id: B(),
384
556
  mode: t.mode,
385
557
  totalSlides: t.totalSlides,
386
558
  firstTitle: t.slide === 1 ? t.title : "",
@@ -390,7 +562,7 @@ function ge(e, t) {
390
562
  };
391
563
  return e.latest[t.mode] = i, i;
392
564
  }
393
- function _e(e, t, n, r) {
565
+ function $(e, t, n, r) {
394
566
  t.current = n.slide, t.shownAt = Date.now(), e.lastShown = t;
395
567
  let i = n.mode === "steps" ? "step" : "slide", { uuid: a, ...o } = r;
396
568
  return {
@@ -398,10 +570,10 @@ function _e(e, t, n, r) {
398
570
  message: `${i} ${n.slide} of ${n.totalSlides} is on the screen again, as it was`,
399
571
  instructions: T(n),
400
572
  instructionsRequired: !0,
401
- sequence: pe(n)
573
+ sequence: Be(n)
402
574
  };
403
575
  }
404
- function ve(e, t) {
576
+ function We(e, t) {
405
577
  if (e.mode !== "steps") return e.title ? `A presentation slide titled "${e.title}". ${e.imagePrompt}` : e.imagePrompt;
406
578
  let n = e.title ? `, "${e.title}"` : "";
407
579
  return [
@@ -410,12 +582,21 @@ function ve(e, t) {
410
582
  "Show the action clearly, with little or no text."
411
583
  ].filter(Boolean).join(" ");
412
584
  }
413
- async function ye(e, t, n) {
585
+ async function Ge(e, t, n) {
414
586
  if (n.html) return {
415
587
  html: n.html,
416
588
  prompt: ""
417
589
  };
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);
590
+ if (n.chart) return {
591
+ chart: n.chart,
592
+ prompt: ""
593
+ };
594
+ if (n.markdown) return {
595
+ html: await G(n.markdown),
596
+ markdown: n.markdown,
597
+ prompt: ""
598
+ };
599
+ let r = t.slides.get(n.slide - 1), i = n.mode === "steps" ? I(r).imagePath : void 0, a = i ? await V(e, [i]) : [], o = We(n, a.length > 0), s = await H(e, o, a), { imageData: c, imagePath: l } = I(s);
419
600
  return c ? {
420
601
  imageData: c,
421
602
  ...l && { imagePath: l },
@@ -425,12 +606,12 @@ async function ye(e, t, n) {
425
606
  sequence: null
426
607
  } };
427
608
  }
428
- async function be(e, t, n) {
429
- let r = await ye(e, t, n);
609
+ async function Ke(e, t, n) {
610
+ let r = await Ge(e, t, n);
430
611
  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) => {
612
+ let { imageData: i, imagePath: a, html: o, markdown: s, chart: c, prompt: l } = r, u = t.id, d = await Z(e.files?.artifacts, K, u, (e) => {
432
613
  let t = e ?? {
433
- id: c,
614
+ id: u,
434
615
  title: "",
435
616
  mode: n.mode,
436
617
  totalSlides: n.totalSlides,
@@ -440,40 +621,44 @@ async function be(e, t, n) {
440
621
  title: n.title,
441
622
  imagePrompt: n.imagePrompt,
442
623
  ...a && { imagePath: a },
443
- ...o && { html: o }
624
+ ...o && { html: o },
625
+ ...s && { markdown: s },
626
+ ...c && { chart: c }
444
627
  }, t;
445
- }), u = {
628
+ }), f = {
446
629
  ...i && { imageData: i },
447
630
  ...a && { imagePath: a },
448
631
  ...o && { html: o },
449
- prompt: s,
450
- slideshowId: c,
632
+ ...s && { markdown: s },
633
+ ...c && { chart: c },
634
+ prompt: l,
635
+ slideshowId: u,
451
636
  slide: n.slide,
452
637
  totalSlides: n.totalSlides,
453
638
  title: n.title,
454
639
  mode: n.mode
455
- }, d = n.mode === "steps" ? "step" : "slide";
640
+ }, p = n.mode === "steps" ? "step" : "slide";
456
641
  return {
457
- data: u,
642
+ data: f,
458
643
  title: n.title || `Slide ${n.slide}`,
459
644
  message: [
460
- `${d} ${n.slide} of ${n.totalSlides} of slideshow "${c}" is on the screen`,
645
+ `${p} ${n.slide} of ${n.totalSlides} of slideshow "${u}" is on the screen`,
461
646
  a ? `saved to ${a}` : "",
462
- l ? "" : Q("slideshow")
647
+ d ? "" : Q("slideshow")
463
648
  ].filter(Boolean).join("; "),
464
649
  instructions: T(n),
465
650
  instructionsRequired: !0,
466
- sequence: pe(n)
651
+ sequence: Be(n)
467
652
  };
468
653
  }
469
- async function xe(e, t) {
470
- let n = w(t);
654
+ async function qe(e, t) {
655
+ let n = me(t);
471
656
  if (typeof n == "string") return {
472
657
  message: n,
473
658
  sequence: null
474
659
  };
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)) {
660
+ let r = He(e), i = Ue(r, n), a = n.mode === "steps";
661
+ if (a && n.slide > i.current && i.current > 0 && !z(e, i.shownAt)) {
477
662
  console.info(`[sequence] holding step ${n.slide} for the user`);
478
663
  let e = i.shownAt === Infinity ? "is still being drawn" : "is still on the screen";
479
664
  return {
@@ -482,15 +667,15 @@ async function xe(e, t) {
482
667
  };
483
668
  }
484
669
  let o = a ? i.slides.get(n.slide) : void 0;
485
- if (o) return se(e.currentResult, o) ? {
670
+ if (o) return Se(e.currentResult, o) ? {
486
671
  message: `step ${n.slide} of ${n.totalSlides} is already on the screen`,
487
672
  cancelled: !0
488
- } : _e(r, i, n, o);
489
- let s = r.repeats.claim(me(i.id, n));
673
+ } : $(r, i, n, o);
674
+ let s = r.repeats.claim(Ve(i.id, n));
490
675
  if ("earlier" in s) {
491
- if (!await s.earlier) return xe(e, t);
676
+ if (!await s.earlier) return qe(e, t);
492
677
  let a = i.slides.get(n.slide);
493
- return a && r.lastShown !== i ? _e(r, i, n, a) : {
678
+ return a && r.lastShown !== i ? $(r, i, n, a) : {
494
679
  message: `slide ${n.slide} of ${n.totalSlides} is already on the screen`,
495
680
  cancelled: !0
496
681
  };
@@ -502,22 +687,22 @@ async function xe(e, t) {
502
687
  i.current = n.slide, i.shownAt = Infinity;
503
688
  let u = !1;
504
689
  try {
505
- let t = await be(e, i, n);
506
- return u = oe(t), u && (i.slides.set(n.slide, t), i.current = n.slide, i.shownAt = Date.now(), r.lastShown = i), t;
690
+ let t = await Ke(e, i, n);
691
+ return u = xe(t), u && (i.slides.set(n.slide, t), i.current = n.slide, i.shownAt = Date.now(), r.lastShown = i), t;
507
692
  } finally {
508
693
  c(u), !u && i.current === n.slide && (i.current = l.current, i.shownAt = l.shownAt);
509
694
  }
510
695
  }
511
696
  //#endregion
512
697
  //#region src/core/storyboard.ts
513
- var Se = ({ id: e, title: t, totalPanels: n }) => ({
698
+ var Je = ({ id: e, title: t, totalPanels: n }) => ({
514
699
  step: 0,
515
700
  total: n,
516
701
  kind: "story",
517
702
  label: `The cast of "${t}"`,
518
703
  onShown: "introduce the characters",
519
704
  nextCall: `call presentPanel for panel 1 of ${n} with storyboardId "${e}"`
520
- }), Ce = ({ id: e, totalPanels: t }, n, r) => ({
705
+ }), Ye = ({ id: e, totalPanels: t }, n, r) => ({
521
706
  step: n,
522
707
  total: t,
523
708
  kind: "story",
@@ -525,21 +710,21 @@ var Se = ({ id: e, title: t, totalPanels: n }) => ({
525
710
  onShown: "tell that part of the story",
526
711
  nextCall: `call presentPanel for panel ${n + 1} of ${t} with storyboardId "${e}"`,
527
712
  ...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) {
713
+ }), Xe = (e, t) => e ? `${e}. ${t}` : t, Ze = (e, { name: t, description: n }) => Xe(e, `Character reference sheet of ${t}: ${n}. Full body, front, side and back views, on a plain white background. No text or labels.`);
714
+ async function Qe(e, t) {
530
715
  let n = D(t);
531
716
  if (typeof n == "string") return {
532
717
  message: n,
533
718
  sequence: null
534
719
  };
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);
720
+ let r = await Promise.all(n.characters.map((t) => H(e, Ze(n.style, t)))), i = r.map(I), a = r.find((e, t) => !i[t]?.imageData);
536
721
  if (i.every(({ imageData: e }) => !e) && a) return {
537
722
  ...a,
538
723
  message: `the character sheets couldn't be made: ${a.message}`,
539
724
  sequence: null
540
725
  };
541
726
  let o = {
542
- id: z(),
727
+ id: B(),
543
728
  ...n,
544
729
  characters: n.characters.map((e, t) => {
545
730
  let n = i[t]?.imagePath;
@@ -549,7 +734,7 @@ async function Ee(e, t) {
549
734
  };
550
735
  }),
551
736
  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;
737
+ }, s = await Z(e.files?.artifacts, q, 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
738
  return {
554
739
  data: {
555
740
  storyboardId: o.id,
@@ -574,35 +759,35 @@ async function Ee(e, t) {
574
759
  ].filter(Boolean).join("; "),
575
760
  instructions: O(o),
576
761
  instructionsRequired: !0,
577
- sequence: Se(o)
762
+ sequence: Je(o)
578
763
  };
579
764
  }
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}`);
765
+ function $e(e, t, n) {
766
+ let r = [Xe(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
767
  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
768
  }
584
- async function Oe(e, t, n) {
769
+ async function et(e, t, n) {
585
770
  let r = [], i = [];
586
771
  for (let a of n.characters) {
587
- let n = t.characters.find((e) => b(e.name, a));
772
+ let n = t.characters.find((e) => x(e.name, a));
588
773
  if (!n) r.push(a);
589
774
  else if (!i.some((e) => e.character === n)) {
590
- let [t] = n.imagePath ? await B(e, [n.imagePath]) : [];
775
+ let [t] = n.imagePath ? await V(e, [n.imagePath]) : [];
591
776
  i.push({
592
777
  character: n,
593
778
  sheet: t ?? null
594
779
  });
595
780
  }
596
781
  }
597
- let a = i.map(({ sheet: e }) => e).filter((e) => !!e), o = De(t, n, i.map(({ character: e, sheet: t }) => ({
782
+ let a = i.map(({ sheet: e }) => e).filter((e) => !!e), o = $e(t, n, i.map(({ character: e, sheet: t }) => ({
598
783
  character: e,
599
784
  hasSheet: !!t
600
- }))), s = await V(e, o, a), { imageData: c, imagePath: l } = I(s);
785
+ }))), s = await H(e, o, a), { imageData: c, imagePath: l } = I(s);
601
786
  if (!c) return {
602
787
  ...s,
603
788
  sequence: null
604
789
  };
605
- let u = n.panel < t.totalPanels && n.choices.length >= 2 ? n.choices : [], d = await Z(e.files?.artifacts, U, t.id, (e) => {
790
+ let u = n.panel < t.totalPanels && n.choices.length >= 2 ? n.choices : [], d = await Z(e.files?.artifacts, q, t.id, (e) => {
606
791
  let r = e ?? t;
607
792
  return u.length && (r.interactive = !0), r.panels[String(n.panel)] = {
608
793
  caption: n.caption,
@@ -632,21 +817,21 @@ async function Oe(e, t, n) {
632
817
  ].filter(Boolean).join("; "),
633
818
  instructions: j(t, n.panel, u),
634
819
  instructionsRequired: !0,
635
- sequence: Ce(t, n.panel, u)
820
+ sequence: Ye(t, n.panel, u)
636
821
  };
637
822
  }
638
- var ke = ue(() => ({
639
- repeats: $(),
823
+ var tt = U(() => ({
824
+ repeats: ze(),
640
825
  awaitingChoice: /* @__PURE__ */ new Map()
641
826
  }));
642
- async function Ae(e, t) {
827
+ async function nt(e, t) {
643
828
  let n = A(t);
644
829
  if (!n) return {
645
830
  message: k,
646
831
  sequence: null
647
832
  };
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`), {
833
+ let { storyboardId: r, panel: i } = n, { repeats: a, awaitingChoice: o } = tt(e), s = o.get(r);
834
+ if (s && i > s.panel && !z(e, s.shownAt)) return console.info(`[sequence] holding panel ${i} for the user`), {
650
835
  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
836
  cancelled: !0
652
837
  };
@@ -654,7 +839,7 @@ async function Ae(e, t) {
654
839
  if ("earlier" in c) return await c.earlier ? {
655
840
  message: `panel ${i} is already on the screen`,
656
841
  cancelled: !0
657
- } : Ae(e, t);
842
+ } : nt(e, t);
658
843
  let { settle: l } = c, u = {
659
844
  panel: i,
660
845
  shownAt: Infinity
@@ -662,7 +847,7 @@ async function Ae(e, t) {
662
847
  o.set(r, u);
663
848
  let f = () => o.get(r) === u, p = !1;
664
849
  try {
665
- let t = await X(e.files?.artifacts, U, r);
850
+ let t = await Le(e.files?.artifacts, q, r);
666
851
  if (!t) return {
667
852
  message: `there is no storyboard "${r}"; call defineStoryboard first`,
668
853
  sequence: null
@@ -671,7 +856,7 @@ async function Ae(e, t) {
671
856
  message: `storyboard "${t.id}" has ${t.totalPanels} panels`,
672
857
  sequence: null
673
858
  };
674
- let a = await Oe(e, t, n);
859
+ let a = await et(e, t, n);
675
860
  p = !!I(a).imageData;
676
861
  let s = a.data;
677
862
  return p && f() && (s?.choices?.length ? o.set(r, {
@@ -684,21 +869,21 @@ async function Ae(e, t) {
684
869
  }
685
870
  //#endregion
686
871
  //#region src/core/index.ts
687
- var je = {
872
+ var rt = {
688
873
  toolDefinition: E,
689
874
  generatingMessage: "Making the slide...",
690
875
  isEnabled: () => !0,
691
- execute: (e, t) => xe(e, t)
692
- }, Me = {
876
+ execute: (e, t) => qe(e, t)
877
+ }, it = {
693
878
  toolDefinition: N,
694
879
  generatingMessage: "Drawing the characters...",
695
880
  isEnabled: () => !0,
696
- execute: (e, t) => Ee(e, t)
697
- }, Ne = {
881
+ execute: (e, t) => Qe(e, t)
882
+ }, at = {
698
883
  toolDefinition: P,
699
884
  generatingMessage: "Drawing the panel...",
700
885
  isEnabled: () => !0,
701
- execute: (e, t) => Ae(e, t)
886
+ execute: (e, t) => nt(e, t)
702
887
  };
703
888
  //#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 };
889
+ export { T as A, M as C, me as D, A as E, s as F, p as I, n as L, se as M, r as N, D as O, o as P, t as R, C as S, j as T, E as _, q as a, fe as b, _ as c, ue as d, le as f, g, P as h, K as i, m as j, x as k, N as l, v as m, at as n, Le as o, k as p, rt as r, G as s, it as t, ce as u, ye as v, O as w, w as x, de as y, te as z };