@algorisys/yappydraw 0.8.253

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.
Files changed (43) hide show
  1. package/LICENSE +661 -0
  2. package/README.md +45 -0
  3. package/chunks/AllPackages-DNX4gUvL.js +6879 -0
  4. package/chunks/BaseConfiguration-iE_YypNt.js +4401 -0
  5. package/chunks/Entities-XwxJEcR3.js +467 -0
  6. package/chunks/Factory--zguTNZ7.js +2768 -0
  7. package/chunks/InputJax-BYq2tqUz.js +42 -0
  8. package/chunks/MathItem-DD5NNBjZ.js +76 -0
  9. package/chunks/Options-BStFr0zv.js +199 -0
  10. package/chunks/PrioritizedList-TjDg4i-s.js +39 -0
  11. package/chunks/Styles-DdTYCumM.js +397 -0
  12. package/chunks/TeXAtom-Bp5xoo7F.js +2175 -0
  13. package/chunks/ai-providers-CycU8sO1.js +229 -0
  14. package/chunks/canva-ai-BREIRXSl.js +285 -0
  15. package/chunks/design-generator-C89SKTqv.js +149 -0
  16. package/chunks/drawing-engine-DLFI-cNg.js +903 -0
  17. package/chunks/drawings-store-C-PoHakg.js +109 -0
  18. package/chunks/ds-operations-D5B9Z5vO.js +253 -0
  19. package/chunks/export-game-DOlM1w0F.js +104 -0
  20. package/chunks/game-runtime-Hn9umSvi.js +346 -0
  21. package/chunks/gifenc.esm-48qFK9lH.js +278 -0
  22. package/chunks/html-DxnOvKy4.js +1694 -0
  23. package/chunks/image-utils-CJQBaGoQ.js +37 -0
  24. package/chunks/index-Bm3Inzn8.js +62744 -0
  25. package/chunks/lengths-DNFHULBn.js +70 -0
  26. package/chunks/liteAdaptor-BZby1Qz2.js +919 -0
  27. package/chunks/lucide-solid-D_6t_rbY.js +35452 -0
  28. package/chunks/markdown-to-slides-_1GIcD8M.js +96 -0
  29. package/chunks/mathjax-CnUrFnFS.js +117 -0
  30. package/chunks/mathjax-D6cR72fZ.js +26 -0
  31. package/chunks/morph-animator-7qX2s9j_.js +25 -0
  32. package/chunks/onboarding-tour-CthiVc3W.js +192 -0
  33. package/chunks/rocket-settings-CU8w9S9I.js +100 -0
  34. package/chunks/search-CnWoMV6A.js +384 -0
  35. package/chunks/slide-generator-BG0Oacui.js +553 -0
  36. package/chunks/svg-BvVc02XL.js +12498 -0
  37. package/chunks/tex-Cfi4Kfun.js +442 -0
  38. package/chunks/tinyfly-engine-Wfa50sVI.js +1804 -0
  39. package/chunks/turntable-ai-Bfq-oSsD.js +120 -0
  40. package/chunks/yappy-NspTXSPk.css +1 -0
  41. package/package.json +21 -0
  42. package/yappy.d.ts +34 -0
  43. package/yappy.js +9 -0
@@ -0,0 +1,229 @@
1
+ const d = {
2
+ openai: [
3
+ { id: "gpt-image-1", label: "GPT Image 1 (best; needs verified org)" },
4
+ { id: "dall-e-3", label: "DALL·E 3" }
5
+ ],
6
+ gemini: [],
7
+ anthropic: []
8
+ }, l = "yappy:ai:config";
9
+ function g(e) {
10
+ try {
11
+ return atob(e);
12
+ } catch {
13
+ return e;
14
+ }
15
+ }
16
+ function m() {
17
+ return {
18
+ activeProvider: "openai",
19
+ providers: {
20
+ openai: { apiKey: "", model: "gpt-4o", imageModel: "gpt-image-1", enabled: !0 },
21
+ gemini: { apiKey: "", model: "gemini-2.0-flash", enabled: !0 },
22
+ anthropic: { apiKey: "", model: "claude-sonnet-4-5-20250929", enabled: !0 }
23
+ }
24
+ };
25
+ }
26
+ function i() {
27
+ try {
28
+ const e = localStorage.getItem(l);
29
+ if (e) {
30
+ const n = JSON.parse(e), o = m();
31
+ return {
32
+ activeProvider: n.activeProvider || o.activeProvider,
33
+ providers: {
34
+ openai: { ...o.providers.openai, ...n.providers?.openai },
35
+ gemini: { ...o.providers.gemini, ...n.providers?.gemini },
36
+ anthropic: { ...o.providers.anthropic, ...n.providers?.anthropic }
37
+ }
38
+ };
39
+ }
40
+ } catch {
41
+ }
42
+ return m();
43
+ }
44
+ function y(e) {
45
+ const o = i().providers[e]?.apiKey || "";
46
+ return o ? g(o) : "";
47
+ }
48
+ function v() {
49
+ const e = i();
50
+ return Object.values(e.providers).some((n) => n.apiKey !== "");
51
+ }
52
+ function T(e) {
53
+ return i().providers[e]?.imageModel || d[e][0]?.id;
54
+ }
55
+ function b() {
56
+ const e = i(), n = e.activeProvider;
57
+ return {
58
+ provider: n,
59
+ model: e.providers[n].model,
60
+ apiKey: y(n)
61
+ };
62
+ }
63
+ async function P(e) {
64
+ switch (e.provider) {
65
+ case "openai":
66
+ return f(e);
67
+ case "gemini":
68
+ return h(e);
69
+ case "anthropic":
70
+ return k(e);
71
+ default:
72
+ return { success: !1, content: "", error: `Unknown provider: ${e.provider}` };
73
+ }
74
+ }
75
+ async function f(e) {
76
+ const n = "https://api.openai.com/v1/chat/completions", o = e.images?.length ? [
77
+ ...e.images.map((t) => ({
78
+ type: "image_url",
79
+ image_url: { url: `data:${t.mediaType};base64,${t.base64}`, detail: "high" }
80
+ })),
81
+ { type: "text", text: e.userPrompt }
82
+ ] : e.userPrompt, a = {
83
+ model: e.model,
84
+ messages: [
85
+ { role: "system", content: e.systemPrompt },
86
+ { role: "user", content: o }
87
+ ],
88
+ temperature: e.temperature ?? 0.3,
89
+ max_tokens: e.maxTokens ?? 4096
90
+ };
91
+ try {
92
+ const t = await fetch(n, {
93
+ method: "POST",
94
+ headers: {
95
+ "Content-Type": "application/json",
96
+ Authorization: `Bearer ${e.apiKey}`
97
+ },
98
+ body: JSON.stringify(a)
99
+ });
100
+ if (!t.ok) {
101
+ const r = await t.text().catch(() => "");
102
+ return { success: !1, content: "", error: c("OpenAI", t.status, r) };
103
+ }
104
+ const s = await t.json();
105
+ return {
106
+ success: !0,
107
+ content: s.choices?.[0]?.message?.content || "",
108
+ usage: s.usage ? {
109
+ promptTokens: s.usage.prompt_tokens,
110
+ completionTokens: s.usage.completion_tokens
111
+ } : void 0
112
+ };
113
+ } catch (t) {
114
+ return { success: !1, content: "", error: p("OpenAI", t) };
115
+ }
116
+ }
117
+ async function h(e) {
118
+ const n = `https://generativelanguage.googleapis.com/v1beta/models/${e.model}:generateContent?key=${e.apiKey}`, o = [];
119
+ if (e.images?.length)
120
+ for (const t of e.images)
121
+ o.push({ inlineData: { mimeType: t.mediaType, data: t.base64 } });
122
+ o.push({ text: e.userPrompt });
123
+ const a = {
124
+ systemInstruction: { parts: [{ text: e.systemPrompt }] },
125
+ contents: [{ parts: o }],
126
+ generationConfig: {
127
+ temperature: e.temperature ?? 0.3,
128
+ maxOutputTokens: e.maxTokens ?? 4096
129
+ }
130
+ };
131
+ try {
132
+ const t = await fetch(n, {
133
+ method: "POST",
134
+ headers: { "Content-Type": "application/json" },
135
+ body: JSON.stringify(a)
136
+ });
137
+ if (!t.ok) {
138
+ const r = await t.text().catch(() => "");
139
+ return { success: !1, content: "", error: c("Gemini", t.status, r) };
140
+ }
141
+ const s = await t.json();
142
+ return {
143
+ success: !0,
144
+ content: s.candidates?.[0]?.content?.parts?.[0]?.text || "",
145
+ usage: s.usageMetadata ? {
146
+ promptTokens: s.usageMetadata.promptTokenCount || 0,
147
+ completionTokens: s.usageMetadata.candidatesTokenCount || 0
148
+ } : void 0
149
+ };
150
+ } catch (t) {
151
+ return { success: !1, content: "", error: p("Gemini", t) };
152
+ }
153
+ }
154
+ async function k(e) {
155
+ const n = "https://api.anthropic.com/v1/messages", o = e.images?.length ? [
156
+ ...e.images.map((t) => ({
157
+ type: "image",
158
+ source: { type: "base64", media_type: t.mediaType, data: t.base64 }
159
+ })),
160
+ { type: "text", text: e.userPrompt }
161
+ ] : e.userPrompt, a = {
162
+ model: e.model,
163
+ system: e.systemPrompt,
164
+ messages: [{ role: "user", content: o }],
165
+ max_tokens: e.maxTokens ?? 4096,
166
+ temperature: e.temperature ?? 0.3
167
+ };
168
+ try {
169
+ const t = await fetch(n, {
170
+ method: "POST",
171
+ headers: {
172
+ "Content-Type": "application/json",
173
+ "x-api-key": e.apiKey,
174
+ "anthropic-version": "2023-06-01",
175
+ "anthropic-dangerous-direct-browser-access": "true"
176
+ },
177
+ body: JSON.stringify(a)
178
+ });
179
+ if (!t.ok) {
180
+ const r = await t.text().catch(() => "");
181
+ return { success: !1, content: "", error: c("Anthropic", t.status, r) };
182
+ }
183
+ const s = await t.json();
184
+ return {
185
+ success: !0,
186
+ content: s.content?.[0]?.text || "",
187
+ usage: s.usage ? {
188
+ promptTokens: s.usage.input_tokens,
189
+ completionTokens: s.usage.output_tokens
190
+ } : void 0
191
+ };
192
+ } catch (t) {
193
+ return { success: !1, content: "", error: p("Anthropic", t) };
194
+ }
195
+ }
196
+ function c(e, n, o) {
197
+ let a = "";
198
+ try {
199
+ const t = JSON.parse(o);
200
+ a = t.error?.message || t.error?.status || t.message || "";
201
+ } catch {
202
+ a = o.slice(0, 200);
203
+ }
204
+ switch (n) {
205
+ case 401:
206
+ return `Invalid API key for ${e}. Check your key in AI Settings.`;
207
+ case 403:
208
+ return `Access denied by ${e}. ${a || "Check API key permissions."}`;
209
+ case 429:
210
+ return `Rate limited by ${e}. Please wait a moment and try again.`;
211
+ case 500:
212
+ case 502:
213
+ case 503:
214
+ return `${e} server error (${n}). Please try again later.`;
215
+ default:
216
+ return `${e} error ${n}: ${a || "Unknown error"}`;
217
+ }
218
+ }
219
+ function p(e, n) {
220
+ return n.name === "TypeError" && n.message?.includes("fetch") ? `Network error: unable to reach ${e} API. Check your internet connection.` : n.message?.includes("CORS") || n.message?.includes("cors") ? `CORS error calling ${e}. This provider may not support direct browser calls.` : `Network error calling ${e}: ${n.message || "Unknown error"}`;
221
+ }
222
+ export {
223
+ T as a,
224
+ b,
225
+ P as c,
226
+ y as g,
227
+ v as h,
228
+ i as l
229
+ };
@@ -0,0 +1,285 @@
1
+ import { g as w, a as P, b as E, c as T } from "./ai-providers-CycU8sO1.js";
2
+ import { s as u, b as r, p as y, u as b, Z as B, f as v, g as j } from "./index-Bm3Inzn8.js";
3
+ const z = {
4
+ rewrite: "Rewrite this text to be clearer and more engaging while keeping its meaning and rough length.",
5
+ shorten: "Shorten this text to roughly half its length while keeping the key message.",
6
+ expand: "Expand this text with one or two extra sentences of relevant detail.",
7
+ fix: "Fix any spelling and grammar mistakes. Change nothing else."
8
+ };
9
+ async function C(p, s = "rewrite", i) {
10
+ const { provider: e, model: t, apiKey: a } = E();
11
+ if (!a)
12
+ return r("Add an API key in AI Settings first", "error"), 0;
13
+ const n = p.map((g) => u.elements.find((d) => d.id === g)).filter((g) => !!g && g.type === "text" && !!(g.text || "").trim());
14
+ if (n.length === 0)
15
+ return r("Select a text element first", "info"), 0;
16
+ const o = s === "custom" ? i || "Improve this text." : z[s];
17
+ r("Magic Write…", "loading");
18
+ let l = 0, c = !1;
19
+ for (const g of n) {
20
+ const d = await T({
21
+ provider: e,
22
+ model: t,
23
+ apiKey: a,
24
+ systemPrompt: "You are a copywriter working inside a graphic design tool. Reply with ONLY the final text — no quotes, no markdown, no explanations. Preserve intentional line breaks.",
25
+ userPrompt: `${o}
26
+
27
+ Text:
28
+ ${g.text}`,
29
+ temperature: 0.7,
30
+ maxTokens: 1024
31
+ });
32
+ if (d.success && d.content.trim())
33
+ l === 0 && y(), b(g.id, { text: d.content.trim() }), l++;
34
+ else if (!d.success) {
35
+ r(d.error || "Magic Write failed", "error"), c = !0;
36
+ break;
37
+ }
38
+ }
39
+ return l > 0 ? r(`Magic Write updated ${l} text element${l === 1 ? "" : "s"}`, "success") : c || B(), l;
40
+ }
41
+ async function S(p, s, i) {
42
+ const e = w("openai");
43
+ if (!e) return { dataURL: null, error: "Add an OpenAI API key in AI Settings first" };
44
+ try {
45
+ const t = { model: i, prompt: p, n: 1, size: s };
46
+ i.startsWith("dall-e") && (t.response_format = "b64_json");
47
+ const a = await fetch("https://api.openai.com/v1/images/generations", {
48
+ method: "POST",
49
+ headers: { "Content-Type": "application/json", Authorization: `Bearer ${e}` },
50
+ body: JSON.stringify(t)
51
+ });
52
+ if (!a.ok) {
53
+ const c = await a.text().catch(() => "");
54
+ let g = "";
55
+ try {
56
+ g = JSON.parse(c).error?.message || "";
57
+ } catch {
58
+ g = c.slice(0, 200);
59
+ }
60
+ return { dataURL: null, error: `OpenAI image error ${a.status}: ${g}` };
61
+ }
62
+ const n = await a.json(), o = n.data?.[0]?.b64_json;
63
+ if (o) return { dataURL: `data:image/png;base64,${o}` };
64
+ const l = n.data?.[0]?.url;
65
+ if (l) {
66
+ const g = await (await fetch(l)).blob();
67
+ return { dataURL: await new Promise((m, I) => {
68
+ const h = new FileReader();
69
+ h.onload = () => m(String(h.result)), h.onerror = I, h.readAsDataURL(g);
70
+ }) };
71
+ }
72
+ return { dataURL: null, error: "OpenAI returned no image data" };
73
+ } catch (t) {
74
+ return { dataURL: null, error: `Network error calling OpenAI Images: ${t?.message || t}` };
75
+ }
76
+ }
77
+ function D(p, s, i, e) {
78
+ const t = u.slides[u.activeSlideIndex], a = t ? t.dimensions.width * 0.6 : 512, n = Math.min(1, a / s), o = Math.round(s * n), l = Math.round(i * n), c = t ? t.spatialPosition.x + (t.dimensions.width - o) / 2 : 120, g = t ? t.spatialPosition.y + (t.dimensions.height - l) / 2 : 120, d = {
79
+ id: `image-${Date.now()}-${Math.floor(Math.random() * 1e6)}`,
80
+ type: "image",
81
+ x: c,
82
+ y: g,
83
+ width: o,
84
+ height: l,
85
+ dataURL: p,
86
+ status: "loaded",
87
+ backgroundColor: "transparent",
88
+ fillStyle: "solid",
89
+ strokeColor: "transparent",
90
+ strokeWidth: 0,
91
+ strokeStyle: "solid",
92
+ opacity: 100,
93
+ angle: 0,
94
+ roughness: 0,
95
+ renderStyle: "architectural",
96
+ locked: !1,
97
+ link: null,
98
+ layerId: u.activeLayerId || "default-layer",
99
+ seed: Math.floor(Math.random() * 2 ** 31),
100
+ roundness: null
101
+ };
102
+ return y(), v("elements", (m) => [...m, d]), v("selection", [d.id]), j(), r(`${e} added`, "success"), d.id;
103
+ }
104
+ async function K(p, s = {}) {
105
+ const i = s.size || "1024x1024", e = P("openai"), t = i === "1536x1024" ? "1792x1024" : i === "1024x1536" ? "1024x1792" : "1024x1024";
106
+ r("Generating image…", "loading");
107
+ let a = await S(p, e.startsWith("dall-e") ? t : i, e);
108
+ if (!a.dataURL && e !== "dall-e-3") {
109
+ const l = await S(p, t, "dall-e-3");
110
+ l.dataURL && (a = l);
111
+ }
112
+ if (!a.dataURL)
113
+ return r(a.error || "Image generation failed", "error"), null;
114
+ const [n, o] = i.split("x").map(Number);
115
+ return D(a.dataURL, n || 1024, o || 1024, "AI image");
116
+ }
117
+ const k = (p) => new Promise((s, i) => {
118
+ const e = new Image();
119
+ e.onload = () => s(e), e.onerror = i, e.src = p;
120
+ });
121
+ async function F(p, s) {
122
+ try {
123
+ const [i, e] = await Promise.all([k(p), k(s)]), t = document.createElement("canvas");
124
+ t.width = i.naturalWidth, t.height = i.naturalHeight;
125
+ const a = t.getContext("2d");
126
+ if (!a) return null;
127
+ a.drawImage(i, 0, 0), a.globalCompositeOperation = "destination-in", a.drawImage(e, 0, 0, t.width, t.height);
128
+ const n = a.getImageData(0, 0, t.width, t.height).data, o = n.length / 4, l = 4 * Math.max(1, Math.floor(o / 1e3));
129
+ let c = 0, g = 0;
130
+ for (let d = 3; d < n.length; d += l)
131
+ n[d] < 16 ? c++ : g++;
132
+ return c === 0 || g === 0 ? null : t.toDataURL("image/png");
133
+ } catch {
134
+ return null;
135
+ }
136
+ }
137
+ async function x(p, s) {
138
+ try {
139
+ const i = await fetch("https://api.openai.com/v1/images/edits", {
140
+ method: "POST",
141
+ headers: { Authorization: `Bearer ${s}` },
142
+ body: p
143
+ });
144
+ if (!i.ok) {
145
+ const a = await i.text().catch(() => "");
146
+ let n = "";
147
+ try {
148
+ n = JSON.parse(a).error?.message || "";
149
+ } catch {
150
+ n = a.slice(0, 200);
151
+ }
152
+ return { b64: null, error: `OpenAI image edit error ${i.status}: ${n}` };
153
+ }
154
+ const t = (await i.json()).data?.[0]?.b64_json;
155
+ return t ? { b64: t } : { b64: null, error: "OpenAI returned no image data" };
156
+ } catch (i) {
157
+ return { b64: null, error: `Network error calling OpenAI Images: ${i?.message || i}` };
158
+ }
159
+ }
160
+ async function W(p, s) {
161
+ const i = p || u.selection[0], e = u.elements.find((c) => c.id === i);
162
+ if (!e || e.type !== "image" || !e.dataURL)
163
+ return r("Select an image element first", "info"), !1;
164
+ if (!s?.trim())
165
+ return r("Describe the change first", "info"), !1;
166
+ const t = w("openai");
167
+ if (!t)
168
+ return r("Add an OpenAI API key in AI Settings first", "error"), !1;
169
+ r("Magic Edit…", "loading");
170
+ const a = await (await fetch(e.dataURL)).blob(), n = new FormData();
171
+ n.append("model", "gpt-image-1"), n.append("image", new File([a], "image.png", { type: a.type || "image/png" })), n.append(
172
+ "prompt",
173
+ `${s.trim()}. Apply ONLY this change — keep everything else in the image pixel-identical to the input: same composition, colors, style, and framing.`
174
+ ), n.append("size", "auto");
175
+ const { b64: o, error: l } = await x(n, t);
176
+ return o ? (y(), b(e.id, { dataURL: `data:image/png;base64,${o}` }), r("Magic Edit applied", "success"), !0) : (r(l || "Magic Edit failed", "error"), !1);
177
+ }
178
+ async function J(p, s) {
179
+ const i = p || u.selection[0], e = u.elements.find((c) => c.id === i);
180
+ if (!e || e.type !== "image" || !e.dataURL)
181
+ return r("Select an image element first", "info"), !1;
182
+ if (!s?.trim())
183
+ return r("Describe the new background first", "info"), !1;
184
+ const t = w("openai");
185
+ if (!t)
186
+ return r("Add an OpenAI API key in AI Settings first", "error"), !1;
187
+ r("Replacing background…", "loading");
188
+ const a = await (await fetch(e.dataURL)).blob(), n = new FormData();
189
+ n.append("model", "gpt-image-1"), n.append("image", new File([a], "image.png", { type: a.type || "image/png" })), n.append(
190
+ "prompt",
191
+ `Replace the background behind the main foreground subject with: ${s.trim()}. Keep the foreground subject pixel-identical to the input — do not restyle, repaint, recolor, move, crop, or resize it. Change ONLY the background, blending the new background naturally with realistic lighting and edges around the subject.`
192
+ ), n.append("size", "auto"), n.append("input_fidelity", "high");
193
+ let { b64: o, error: l } = await x(n, t);
194
+ return !o && l?.includes("input_fidelity") && (n.delete("input_fidelity"), { b64: o, error: l } = await x(n, t)), o ? (y(), b(e.id, { dataURL: `data:image/png;base64,${o}` }), r("Background replaced", "success"), !0) : (r(l || "Replace Background failed", "error"), !1);
195
+ }
196
+ async function Y(p, s = {}) {
197
+ const i = p || u.selection[0], e = u.elements.find((c) => c.id === i);
198
+ if (!e || e.type !== "image" || !e.dataURL)
199
+ return r("Select an image element first", "info"), !1;
200
+ const t = w("openai");
201
+ if (!t)
202
+ return r("Add an OpenAI API key in AI Settings first", "error"), !1;
203
+ const a = Math.max(0, s.left ?? 0.25), n = Math.max(0, s.right ?? 0.25), o = Math.max(0, s.top ?? 0.25), l = Math.max(0, s.bottom ?? 0.25);
204
+ if (a + n + o + l === 0) return !1;
205
+ r("Magic Expand…", "loading");
206
+ try {
207
+ const c = await k(e.dataURL), g = c.naturalWidth, d = c.naturalHeight, m = Math.round(g * (1 + a + n)), I = Math.round(d * (1 + o + l)), h = document.createElement("canvas");
208
+ h.width = m, h.height = I;
209
+ const A = h.getContext("2d");
210
+ if (!A)
211
+ return r("Magic Expand failed: no canvas context", "error"), !1;
212
+ A.drawImage(c, Math.round(g * a), Math.round(d * o));
213
+ const R = await new Promise((U, O) => h.toBlob((M) => M ? U(M) : O(new Error("canvas.toBlob failed")), "image/png")), f = new FormData();
214
+ f.append("model", "gpt-image-1"), f.append("image", new File([R], "image.png", { type: "image/png" })), f.append("mask", new File([R], "mask.png", { type: "image/png" })), f.append(
215
+ "prompt",
216
+ (s.prompt?.trim() ? `${s.prompt.trim()}. ` : "") + "Extend the existing image seamlessly into the transparent areas, continuing its scene, lighting, style, and perspective. Keep the original (non-transparent) pixels unchanged."
217
+ ), f.append("size", "auto");
218
+ const { b64: L, error: $ } = await x(f, t);
219
+ return L ? (y(), b(e.id, {
220
+ dataURL: `data:image/png;base64,${L}`,
221
+ x: e.x - e.width * a,
222
+ y: e.y - e.height * o,
223
+ width: e.width * (1 + a + n),
224
+ height: e.height * (1 + o + l)
225
+ }), r("Magic Expand applied", "success"), !0) : (r($ || "Magic Expand failed", "error"), !1);
226
+ } catch (c) {
227
+ return r(`Magic Expand failed: ${c?.message || c}`, "error"), !1;
228
+ }
229
+ }
230
+ async function H(p, s = {}) {
231
+ const i = p || u.selection[0], e = u.elements.find((a) => a.id === i);
232
+ if (!e || e.type !== "image" || !e.dataURL)
233
+ return r("Select an image element first", "info"), !1;
234
+ const t = w("openai");
235
+ if (!t)
236
+ return r("Add an OpenAI API key in AI Settings first", "error"), !1;
237
+ r("Removing background…", "loading");
238
+ try {
239
+ const a = await (await fetch(e.dataURL)).blob(), n = (d) => {
240
+ const m = new FormData();
241
+ return m.append("model", "gpt-image-1"), m.append("image", new File([a], "image.png", { type: a.type || "image/png" })), m.append(
242
+ "prompt",
243
+ "Remove the background completely so it is fully transparent. Keep the foreground subject pixel-identical to the input — do not restyle, repaint, recolor, sharpen, or add any effects, glow, outlines, or shadows. Do not move, crop, or resize the subject."
244
+ ), m.append("background", "transparent"), m.append("size", "auto"), d && m.append("input_fidelity", "high"), m;
245
+ };
246
+ let o = await fetch("https://api.openai.com/v1/images/edits", {
247
+ method: "POST",
248
+ headers: { Authorization: `Bearer ${t}` },
249
+ body: n(!0)
250
+ });
251
+ if (o.status === 400 && (await o.clone().text().catch(() => "")).includes("input_fidelity") && (o = await fetch("https://api.openai.com/v1/images/edits", {
252
+ method: "POST",
253
+ headers: { Authorization: `Bearer ${t}` },
254
+ body: n(!1)
255
+ })), !o.ok) {
256
+ const d = await o.text().catch(() => "");
257
+ let m = "";
258
+ try {
259
+ m = JSON.parse(d).error?.message || "";
260
+ } catch {
261
+ m = d.slice(0, 200);
262
+ }
263
+ return r(`Background removal failed (${o.status}): ${m}`, "error"), !1;
264
+ }
265
+ const c = (await o.json()).data?.[0]?.b64_json;
266
+ if (!c)
267
+ return r("Background removal returned no image", "error"), !1;
268
+ let g = `data:image/png;base64,${c}`;
269
+ if (s.preserveOriginal !== !1) {
270
+ const d = await F(e.dataURL, g);
271
+ d && (g = d);
272
+ }
273
+ return y(), b(e.id, { dataURL: g }), r("Background removed", "success"), !0;
274
+ } catch (a) {
275
+ return r(`Background removal failed: ${a?.message || a}`, "error"), !1;
276
+ }
277
+ }
278
+ export {
279
+ Y as expandImage,
280
+ K as generateImage,
281
+ W as magicEditImage,
282
+ C as magicWrite,
283
+ H as removeBackground,
284
+ J as replaceBackground
285
+ };
@@ -0,0 +1,149 @@
1
+ import { b as x, c as S } from "./ai-providers-CycU8sO1.js";
2
+ import { b as u, _ as A, s as C, f as y, z as M, g as D } from "./index-Bm3Inzn8.js";
3
+ const P = 'You are a senior graphic designer. Reply with ONLY a JSON object, no markdown fences, matching exactly: {"headline": string (max 6 words), "subhead": string (max 12 words), "bullets": string[] (0-4 short items), "cta": string (max 5 words, optional), "palette": {"background": hex, "primary": hex, "accent": hex, "text": hex}}. The palette must be harmonious with strong text/background contrast.';
4
+ function $(r) {
5
+ try {
6
+ const e = r.trim().replace(/^```(?:json)?\s*/i, "").replace(/\s*```$/, ""), n = JSON.parse(e);
7
+ return !n?.headline || !n?.palette?.background ? null : n;
8
+ } catch {
9
+ return null;
10
+ }
11
+ }
12
+ let T = 0;
13
+ const k = (r) => `${r}-${Date.now()}-${++T}`, p = {
14
+ roughness: 0,
15
+ angle: 0,
16
+ renderStyle: "architectural",
17
+ locked: !1,
18
+ link: null,
19
+ layerId: "default-layer",
20
+ strokeStyle: "solid",
21
+ opacity: 100,
22
+ roundness: null,
23
+ seed: () => Math.floor(Math.random() * 2 ** 31)
24
+ }, f = (r, e, n, t, o, s, i, a = {}) => ({
25
+ id: k("text"),
26
+ type: "text",
27
+ x: e,
28
+ y: n,
29
+ width: t,
30
+ height: o,
31
+ text: r,
32
+ fontSize: s,
33
+ fontFamily: "poppins",
34
+ textAlign: "center",
35
+ verticalAlign: "top",
36
+ textColor: i,
37
+ strokeColor: "transparent",
38
+ backgroundColor: "transparent",
39
+ fillStyle: "solid",
40
+ strokeWidth: 0,
41
+ ...p,
42
+ seed: p.seed(),
43
+ ...a
44
+ }), m = (r, e, n, t, o = {}) => ({
45
+ id: k("rect"),
46
+ type: "rectangle",
47
+ x: r,
48
+ y: e,
49
+ width: n,
50
+ height: t,
51
+ strokeColor: "transparent",
52
+ backgroundColor: "#ffffff",
53
+ fillStyle: "solid",
54
+ strokeWidth: 0,
55
+ ...p,
56
+ seed: p.seed(),
57
+ ...o
58
+ });
59
+ function v(r, e, n, t, o) {
60
+ const s = r.palette, i = Math.min(t, o), a = [];
61
+ a.push(m(e, n, t, o, {
62
+ backgroundColor: s.background,
63
+ fillStyle: "linear",
64
+ gradientStops: [
65
+ { color: s.background, offset: 0 },
66
+ { color: s.primary, offset: 1 }
67
+ ],
68
+ gradientDirection: 135
69
+ }));
70
+ const g = t * 0.14;
71
+ a.push(m(e + (t - g) / 2, n + o * 0.14, g, i * 0.012, { backgroundColor: s.accent })), a.push(f(
72
+ r.headline,
73
+ e + t * 0.08,
74
+ n + o * 0.18,
75
+ t * 0.84,
76
+ o * 0.2,
77
+ Math.round(i * 0.085),
78
+ s.text,
79
+ { fontWeight: "bold" }
80
+ ));
81
+ let c = n + o * 0.4;
82
+ r.subhead && (a.push(f(
83
+ r.subhead,
84
+ e + t * 0.1,
85
+ c,
86
+ t * 0.8,
87
+ o * 0.1,
88
+ Math.round(i * 0.04),
89
+ s.text,
90
+ { opacity: 88 }
91
+ )), c += o * 0.13);
92
+ const h = (r.bullets || []).slice(0, 4);
93
+ if (h.length > 0 && a.push(f(
94
+ h.map((l) => `• ${l}`).join(`
95
+ `),
96
+ e + t * 0.12,
97
+ c,
98
+ t * 0.76,
99
+ o * 0.28,
100
+ Math.round(i * 0.032),
101
+ s.text,
102
+ { textAlign: "left", opacity: 92 }
103
+ )), r.cta) {
104
+ const l = t * 0.44, d = i * 0.085, b = n + o * 0.86 - d / 2;
105
+ a.push(m(e + (t - l) / 2, b, l, d, {
106
+ backgroundColor: s.accent,
107
+ borderRadius: d / 2
108
+ })), a.push(f(
109
+ r.cta,
110
+ e + (t - l) / 2,
111
+ b + d * 0.22,
112
+ l,
113
+ d * 0.6,
114
+ Math.round(i * 0.032),
115
+ s.background,
116
+ { fontWeight: "bold", verticalAlign: "middle" }
117
+ ));
118
+ }
119
+ return a;
120
+ }
121
+ async function Y(r, e = { width: 1080, height: 1080 }) {
122
+ const { provider: n, model: t, apiKey: o } = x();
123
+ if (!o)
124
+ return u("Add an API key in AI Settings first", "error"), !1;
125
+ if (!r.trim()) return !1;
126
+ u("Generating design…", "info");
127
+ const s = await S({
128
+ provider: n,
129
+ model: t,
130
+ apiKey: o,
131
+ systemPrompt: P,
132
+ userPrompt: `Design brief: ${r.trim()}
133
+ Format: ${e.width}×${e.height}px.`,
134
+ temperature: 0.8,
135
+ maxTokens: 800
136
+ });
137
+ if (!s.success)
138
+ return u(s.error || "Design generation failed", "error"), !1;
139
+ const i = $(s.content);
140
+ if (!i)
141
+ return u("The AI returned an unusable design — try again", "error"), !1;
142
+ A("design", e);
143
+ const a = C.slides[0], g = a?.spatialPosition.x ?? 0, c = a?.spatialPosition.y ?? 0, h = v(i, g, c, e.width, e.height);
144
+ return y("elements", h), y("selection", []), M(), D(), u("Design generated — edit away", "success"), !0;
145
+ }
146
+ export {
147
+ v as buildDesignElements,
148
+ Y as generateDesign
149
+ };