@popcraft/kit 0.53.0 → 0.53.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (77) hide show
  1. package/dist/chunks/{agent-VDTFMQFH.js → agent-SED37SYN.js} +1 -1
  2. package/dist/chunks/{builtin-B425EDUG.js → builtin-6C24JNML.js} +4 -3
  3. package/dist/chunks/{buy-credits-YD6DBAQB.js → buy-credits-L4YYC7OH.js} +2 -2
  4. package/dist/chunks/{check-template-QIUI3LQM.js → check-template-EE5TET2G.js} +3 -2
  5. package/dist/chunks/{chunk-U5UFIM2E.js → chunk-32OBPYVY.js} +1 -1
  6. package/dist/chunks/{chunk-SMF4YIFH.js → chunk-3OXHJA4W.js} +1 -1
  7. package/dist/chunks/{chunk-V4SNTWZO.js → chunk-3OZO3VDZ.js} +4 -4
  8. package/dist/chunks/{chunk-MY5CBA5H.js → chunk-7DRZUU3D.js} +121 -63
  9. package/dist/chunks/{chunk-UDUHQLOJ.js → chunk-AEVF4O3X.js} +2 -2
  10. package/dist/chunks/{chunk-SD7QCT7C.js → chunk-AYWP3RXA.js} +4 -4
  11. package/dist/chunks/{chunk-MJMCMLHB.js → chunk-BKRXB4FD.js} +1 -1
  12. package/dist/chunks/{chunk-HGUHRTIM.js → chunk-DGM2NZSE.js} +2 -2
  13. package/dist/chunks/{chunk-PUFEIOUT.js → chunk-E6DRH2F2.js} +1 -1
  14. package/dist/chunks/{chunk-A3MCE2OL.js → chunk-F6NLCJI5.js} +45 -5
  15. package/dist/chunks/{chunk-EKKA4A5J.js → chunk-FLGDAOPE.js} +60 -101
  16. package/dist/chunks/{chunk-6Q7JYDNH.js → chunk-FM4WN2UV.js} +4 -4
  17. package/dist/chunks/{chunk-MGWBSGMA.js → chunk-GMUR223M.js} +2 -2
  18. package/dist/chunks/{chunk-5AMNMH7S.js → chunk-GNOX55UB.js} +9 -9
  19. package/dist/chunks/{chunk-XMO6D5A2.js → chunk-GUGOVTVN.js} +55 -7
  20. package/dist/chunks/{chunk-IROVLB4V.js → chunk-HS4CR6HU.js} +19 -5
  21. package/dist/chunks/{chunk-B4DDU5KM.js → chunk-L6TWTQWB.js} +2 -2
  22. package/dist/chunks/{chunk-LHKOU6BP.js → chunk-M5MBUFEB.js} +1 -1
  23. package/dist/chunks/{chunk-AN2LMY4M.js → chunk-MGNS52I2.js} +4 -4
  24. package/dist/chunks/{chunk-NPTJQ2AF.js → chunk-NBFZY6QK.js} +1 -1
  25. package/dist/chunks/{chunk-GPNEAC5E.js → chunk-NDMT4BWH.js} +1 -1
  26. package/dist/chunks/{chunk-7XLYPWQL.js → chunk-NYGQP3I2.js} +4 -4
  27. package/dist/chunks/{chunk-U54RHZSX.js → chunk-OE2LGHLL.js} +3 -3
  28. package/dist/chunks/chunk-OLQTCVWP.js +92 -0
  29. package/dist/chunks/{chunk-T4FFRJAH.js → chunk-OWWBFGCR.js} +3 -3
  30. package/dist/chunks/{chunk-VLEZSLRZ.js → chunk-TRTT3FG2.js} +5 -5
  31. package/dist/chunks/{chunk-WXMIWRZM.js → chunk-WENYC56A.js} +11 -11
  32. package/dist/chunks/{chunk-EISISJQ4.js → chunk-Y6MJOYOD.js} +8 -8
  33. package/dist/chunks/{client-O2YCQZT7.js → client-FHS3A5KE.js} +1 -1
  34. package/dist/chunks/{client-4LUUUMO2.js → client-FZXXX7Z4.js} +2 -2
  35. package/dist/chunks/{client-AMMTXTFS.js → client-JTMPIRKQ.js} +3 -3
  36. package/dist/chunks/{client-actions-L7II3NNB.js → client-actions-3KZRX52M.js} +13 -12
  37. package/dist/chunks/{dangerous-RSWVATGA.js → dangerous-D6BD66C2.js} +4 -3
  38. package/dist/chunks/{delete-current-file-E46EEPRC.js → delete-current-file-EUYQ4W5Y.js} +7 -6
  39. package/dist/chunks/{editor-seams-UO4QUUQH.js → editor-seams-SJRRQFZT.js} +18 -17
  40. package/dist/chunks/{editor-store-V43NADG6.js → editor-store-AXRJNCRC.js} +5 -5
  41. package/dist/chunks/{export-PGMO7YEU.js → export-ILWWIDBI.js} +1 -1
  42. package/dist/chunks/{export-watermark-XHQOOPR7.js → export-watermark-MYKTALXF.js} +7 -6
  43. package/dist/chunks/{eyedropper-4D6OK4VM.js → eyedropper-EZ33OG43.js} +3 -2
  44. package/dist/chunks/{generate-media-XMD232CS.js → generate-media-ODWN3RNS.js} +4 -4
  45. package/dist/chunks/{host-WX77JQ2K.js → host-K6K7OOJY.js} +12 -11
  46. package/dist/chunks/{integrations-LOGIGZY2.js → integrations-TPVN7WNB.js} +1 -1
  47. package/dist/chunks/{libraries-R63ARXMI.js → libraries-L7RTUME7.js} +7 -6
  48. package/dist/chunks/{live-QLSNGZ3Y.js → live-SODTH6AK.js} +3 -2
  49. package/dist/chunks/{lottie-CBQTJRYU.js → lottie-ZWAKIFY2.js} +4 -4
  50. package/dist/chunks/{media-tool-TXQINVAR.js → media-tool-76BJQ4EH.js} +4 -3
  51. package/dist/chunks/{new-file-UUBSWKHK.js → new-file-4B74SA7T.js} +5 -4
  52. package/dist/chunks/{pdf-NHOWFQ66.js → pdf-HK3GJ6QP.js} +3 -3
  53. package/dist/chunks/{player-check-4LAIMR3H.js → player-check-3HTULNTP.js} +4 -4
  54. package/dist/chunks/{plugin-CUBE33JW.js → plugin-OFAK7X55.js} +3 -2
  55. package/dist/chunks/{plugin-import-C5S2SHFZ.js → plugin-import-FHPXNY5S.js} +23 -22
  56. package/dist/chunks/{pptx-LHJRZA42.js → pptx-O7RRDHAR.js} +2 -2
  57. package/dist/chunks/{presence-UQHDKT4A.js → presence-CLCMZPNT.js} +4 -3
  58. package/dist/chunks/{project-KEEZ7XYP.js → project-RJ3UIR3F.js} +3 -3
  59. package/dist/chunks/{publish-site-UL2ISNZU.js → publish-site-NYDQQTVZ.js} +8 -7
  60. package/dist/chunks/{publish-store-2TTGS2LW.js → publish-store-YNPQKV6P.js} +5 -5
  61. package/dist/chunks/{raster-actions-KYYBZLGY.js → raster-actions-MC3CT72Z.js} +3 -2
  62. package/dist/chunks/{reference-images-CYSRQG7A.js → reference-images-TAWHPRYN.js} +2 -2
  63. package/dist/chunks/{resolvers-BQ5WXLUC.js → resolvers-UTQHZ6ET.js} +5 -5
  64. package/dist/chunks/{runner-ULBSWTOK.js → runner-YB2KJMV5.js} +30 -24
  65. package/dist/chunks/{store-OUZ5GTY5.js → store-RMG4PHWL.js} +14 -13
  66. package/dist/chunks/{storefront-prepare-EXR7OIWW.js → storefront-prepare-6IUMZTCQ.js} +1 -1
  67. package/dist/chunks/{svg-export-J2YVV3WM.js → svg-export-LMGINUQK.js} +5 -5
  68. package/dist/chunks/{svg-place-ZAG7VYF6.js → svg-place-LWB4XU2O.js} +2 -1
  69. package/dist/chunks/{sync-A56IG32K.js → sync-K72H36V7.js} +7 -6
  70. package/dist/chunks/{tabs-UWETDGQJ.js → tabs-56YA6CWU.js} +10 -9
  71. package/dist/chunks/{team-5VEJ3OZ6.js → team-35KCR2TX.js} +1 -1
  72. package/dist/chunks/{team-client-SG3SVF4G.js → team-client-NJYR2EHQ.js} +1 -1
  73. package/dist/chunks/{tools-2TCRJ6YI.js → tools-HSZSBWOP.js} +4 -2
  74. package/dist/chunks/{ui-commands-HVPH6ZXC.js → ui-commands-J54KK6XU.js} +20 -19
  75. package/dist/chunks/{versions-BIJCROBJ.js → versions-X2TC2RMO.js} +7 -6
  76. package/dist/index.js +1 -1
  77. package/package.json +1 -1
@@ -18,7 +18,7 @@ import {
18
18
  ringsCmds,
19
19
  shapeCmds,
20
20
  vectorCmds
21
- } from "./chunk-NPTJQ2AF.js";
21
+ } from "./chunk-NBFZY6QK.js";
22
22
  import {
23
23
  strokeBehindFill
24
24
  } from "./chunk-YZKSEJHZ.js";
@@ -9,7 +9,7 @@ import {
9
9
  } from "./chunk-7SMURRFY.js";
10
10
  import {
11
11
  activeTeamWorkspaceId
12
- } from "./chunk-GPNEAC5E.js";
12
+ } from "./chunk-NDMT4BWH.js";
13
13
  import {
14
14
  ApiError,
15
15
  GUEST_FILE_LIMIT,
@@ -23,7 +23,7 @@ import {
23
23
  } from "./chunk-TZQJDYMB.js";
24
24
  import {
25
25
  markLibraryDocument
26
- } from "./chunk-EKKA4A5J.js";
26
+ } from "./chunk-FLGDAOPE.js";
27
27
  import {
28
28
  create
29
29
  } from "./chunk-QLJLPV5R.js";
@@ -6,7 +6,7 @@ const __filename = __popcraftPath(import.meta.url);
6
6
  const __dirname = __popcraftDirname(__filename);
7
7
  import {
8
8
  useEditorStore
9
- } from "./chunk-EKKA4A5J.js";
9
+ } from "./chunk-FLGDAOPE.js";
10
10
  import {
11
11
  announce
12
12
  } from "./chunk-DV7XWPVL.js";
@@ -13,7 +13,7 @@ import {
13
13
  agentTool,
14
14
  agentToolList,
15
15
  registerCommands
16
- } from "./chunk-6Q7JYDNH.js";
16
+ } from "./chunk-FM4WN2UV.js";
17
17
  import {
18
18
  dispatch
19
19
  } from "./chunk-OQZFD4BD.js";
@@ -58,14 +58,53 @@ function toolSpecs(names) {
58
58
  function: { name: t.name, description: t.description, parameters: toolParameters(t.parameters) }
59
59
  }));
60
60
  }
61
+ function parseToolArgs(text) {
62
+ try {
63
+ return JSON.parse(text);
64
+ } catch {
65
+ }
66
+ let depth = 0, inStr = false, esc = false;
67
+ const stack = [];
68
+ for (let i = 0; i < text.length; i++) {
69
+ const c = text[i];
70
+ if (inStr) {
71
+ if (esc) esc = false;
72
+ else if (c === "\\") esc = true;
73
+ else if (c === '"') inStr = false;
74
+ continue;
75
+ }
76
+ if (c === '"') inStr = true;
77
+ else if (c === "{" || c === "[") {
78
+ stack.push(c === "{" ? "}" : "]");
79
+ depth++;
80
+ } else if (c === "}" || c === "]") {
81
+ stack.pop();
82
+ depth--;
83
+ if (depth === 0) {
84
+ try {
85
+ return JSON.parse(text.slice(0, i + 1));
86
+ } catch {
87
+ return void 0;
88
+ }
89
+ }
90
+ }
91
+ }
92
+ if (!stack.length) return void 0;
93
+ try {
94
+ return JSON.parse(text + (inStr ? '"' : "") + stack.reverse().join(""));
95
+ } catch {
96
+ return void 0;
97
+ }
98
+ }
61
99
  async function runTool(name, argsText, ctx) {
62
100
  let raw = {};
63
101
  if (argsText.trim()) {
64
- try {
65
- raw = JSON.parse(argsText);
66
- } catch {
67
- throw new ToolError(`The arguments for ${name} were not valid JSON.`, "invalid_params");
102
+ const parsed = parseToolArgs(argsText);
103
+ if (parsed === void 0) {
104
+ console.warn(`[agent] unparseable arguments for ${name}:`, argsText.slice(0, 500));
105
+ throw new ToolError(`The arguments for ${name} were not valid JSON. Send one JSON object.`, "invalid_params");
68
106
  }
107
+ raw = parsed;
69
108
  }
70
109
  return dispatch(name, {
71
110
  surface: "agent",
@@ -86,5 +125,6 @@ export {
86
125
  getTool,
87
126
  allTools,
88
127
  toolSpecs,
128
+ parseToolArgs,
89
129
  runTool
90
130
  };
@@ -34,6 +34,11 @@ import {
34
34
  spanOf,
35
35
  stopsOf
36
36
  } from "./chunk-VXB34VXD.js";
37
+ import {
38
+ rebuildVectorData,
39
+ scaleSubtreePatches,
40
+ scaleVectorPaths
41
+ } from "./chunk-OLQTCVWP.js";
37
42
  import {
38
43
  hrefOf,
39
44
  opensNewTab,
@@ -55,8 +60,9 @@ import {
55
60
  } from "./chunk-BNQZIEZX.js";
56
61
  import {
57
62
  computeBooleanMultiPoly,
63
+ nonzeroMultiPoly,
58
64
  require_polygon_clipping_cjs
59
- } from "./chunk-XMO6D5A2.js";
65
+ } from "./chunk-GUGOVTVN.js";
60
66
  import {
61
67
  selectionWorldBounds
62
68
  } from "./chunk-R5O3E5HI.js";
@@ -2303,8 +2309,15 @@ function nodeWorldMultiPoly(doc, id) {
2303
2309
  return mp.map((poly) => poly.map((ring) => ring.map(([x, y]) => place(x, y))));
2304
2310
  }
2305
2311
  const rings = nodeWorldRings(doc, id);
2306
- const mode = node.type === "VECTOR" && node.fillRule === "EVENODD" ? "xor" : "union";
2307
- return combineRings(rings, mode);
2312
+ if (node.type === "VECTOR") {
2313
+ if (node.fillRule === "EVENODD") return combineRings(rings, "xor");
2314
+ try {
2315
+ return nonzeroMultiPoly(rings);
2316
+ } catch {
2317
+ return combineRings(rings, "union");
2318
+ }
2319
+ }
2320
+ return combineRings(rings, "union");
2308
2321
  }
2309
2322
  function nodeAreaMultiPoly(doc, id) {
2310
2323
  if (!doc.nodes[id]) return [];
@@ -2314,10 +2327,20 @@ function nodeAreaMultiPoly(doc, id) {
2314
2327
  }
2315
2328
  function flattenNodesMultiPoly(doc, ids) {
2316
2329
  const operands = [];
2317
- for (const id of ids) {
2318
- const mp = nodeAreaMultiPoly(doc, id);
2319
- if (mp.length > 0) operands.push(mp);
2320
- }
2330
+ const visit = (id) => {
2331
+ const n = doc.nodes[id];
2332
+ if (!n || n.visible === false) return;
2333
+ if (n.type !== "GROUP") {
2334
+ const mp = n.type === "FRAME" || n.type === "COMPONENT" || n.type === "INSTANCE" || n.type === "SECTION" ? (n.fills ?? []).some((f) => f.visible !== false) ? nodeWorldMultiPoly(doc, id) : [] : nodeAreaMultiPoly(doc, id);
2335
+ if (mp.length > 0) operands.push(mp);
2336
+ }
2337
+ if (n.type !== "BOOLEAN") for (const c of n.childIds ?? []) visit(c);
2338
+ };
2339
+ ids.forEach(visit);
2340
+ return unionAll(operands);
2341
+ }
2342
+ function unionAll(mps) {
2343
+ const operands = mps.filter((mp) => mp.length > 0);
2321
2344
  if (operands.length === 0) return [];
2322
2345
  try {
2323
2346
  return operands.length > 1 ? import_polygon_clipping2.default.union(operands[0], ...operands.slice(1)) : operands[0];
@@ -4588,7 +4611,7 @@ function createPopcornSlice(set2, get2) {
4588
4611
  privateMode: false,
4589
4612
  setPrivateMode: (on) => {
4590
4613
  set2({ privateMode: on });
4591
- void import("./presence-UQHDKT4A.js").then((m) => m.setPresencePrivate(on)).catch(() => {
4614
+ void import("./presence-CLCMZPNT.js").then((m) => m.setPresencePrivate(on)).catch(() => {
4592
4615
  });
4593
4616
  },
4594
4617
  /** Reveal every private item THIS user created (they sync to collaborators). Others' stay theirs. */
@@ -4976,25 +4999,6 @@ function resolveTipStamp(dyn) {
4976
4999
  }
4977
5000
  if (typeof window !== "undefined") window.__vpTipStamp = getTipStamp;
4978
5001
 
4979
- // lib/document/scale-geometry.ts
4980
- init_define_POPCRAFT_COMPONENT_IDS();
4981
- var scalePoint = (p, sx, sy) => ({
4982
- ...p,
4983
- x: p.x * sx,
4984
- y: p.y * sy,
4985
- // Bezier handles live in the same space as the point and have to scale with it, or a stretched curve
4986
- // keeps its original curvature and bulges out of the shape.
4987
- handleIn: p.handleIn ? { x: p.handleIn.x * sx, y: p.handleIn.y * sy } : void 0,
4988
- handleOut: p.handleOut ? { x: p.handleOut.x * sx, y: p.handleOut.y * sy } : void 0
4989
- });
4990
- function scaleVectorPaths(paths, sx, sy, rebuild) {
4991
- if (!paths?.length || sx === 1 && sy === 1) return paths;
4992
- return paths.map((path) => {
4993
- const points = path.points.map((p) => scalePoint(p, sx, sy));
4994
- return { ...path, points, data: rebuild(points, path.closed) };
4995
- });
4996
- }
4997
-
4998
5002
  // lib/editor/viewport.ts
4999
5003
  init_define_POPCRAFT_COMPONENT_IDS();
5000
5004
  var size = null;
@@ -6652,7 +6656,7 @@ var useEditorStore = create()(
6652
6656
  // A copy is a new file, so it is cloud-backed like any other (see lib/client/cloud/new-file.ts).
6653
6657
  // Returns '' when it was refused (offline, signed out, plan full) or failed; nothing is left behind.
6654
6658
  duplicateDocument: async (id) => {
6655
- const { duplicateDocumentToCloud } = await import("./sync-A56IG32K.js");
6659
+ const { duplicateDocumentToCloud } = await import("./sync-K72H36V7.js");
6656
6660
  return duplicateDocumentToCloud(id);
6657
6661
  },
6658
6662
  deleteDocument: async (id) => {
@@ -7877,10 +7881,10 @@ var useEditorStore = create()(
7877
7881
  if ("childIds" in node && node.childIds.length > 0) {
7878
7882
  newDoc = applyConstraints(newDoc, id, node.width, node.height, newWidth, newHeight);
7879
7883
  }
7880
- if (node.type === "GROUP" && node.width > 0 && node.height > 0) {
7881
- const scaleX = newWidth / node.width;
7882
- const scaleY = newHeight / node.height;
7883
- newDoc = scaleChildrenRecursively(newDoc, id, scaleX, scaleY);
7884
+ if ((node.type === "GROUP" || node.type === "VECTOR") && node.width > 0 && node.height > 0) {
7885
+ for (const [pid, patch] of scaleSubtreePatches(newDoc.nodes, id, newWidth / node.width, newHeight / node.height)) {
7886
+ newDoc = updateNode(newDoc, pid, patch);
7887
+ }
7884
7888
  } else if (node.type === "TABLE" && node.width > 0 && node.height > 0) {
7885
7889
  const table = node;
7886
7890
  const totalW = (table.colWidths || []).reduce((a, b) => a + b, 0) || 1;
@@ -8889,23 +8893,35 @@ var useEditorStore = create()(
8889
8893
  const geo = multiPolyToVectorGeometry(mp);
8890
8894
  if (!geo) return;
8891
8895
  const first = doc.nodes[state.selection[0]];
8896
+ const firstFills = (id) => {
8897
+ const n = doc.nodes[id];
8898
+ if (!n) return void 0;
8899
+ if (n.fills?.length && n.type !== "GROUP") return n.fills;
8900
+ for (const c of n.childIds ?? []) {
8901
+ const f = firstFills(c);
8902
+ if (f) return f;
8903
+ }
8904
+ return void 0;
8905
+ };
8906
+ const fills = state.selection.map(firstFills).find(Boolean);
8892
8907
  const vectorNode = createVector({
8893
8908
  ...geo,
8894
- fills: first?.fills?.length ? first.fills : [{ type: "SOLID", color: { r: 0.85, g: 0.85, b: 0.85, a: 1 }, visible: true }],
8909
+ fills: fills ?? [{ type: "SOLID", color: { r: 0.85, g: 0.85, b: 0.85, a: 1 }, visible: true }],
8895
8910
  strokes: [],
8896
8911
  fillRule: "EVENODD",
8897
8912
  name: state.selection.length > 1 ? "Flattened" : `${first?.name ?? "Vector"} (flattened)`
8898
8913
  });
8899
8914
  doc = addNode(doc, vectorNode, state.currentPageId);
8915
+ const parentId = first?.parentId;
8916
+ if (parentId && parentId !== state.currentPageId && doc.nodes[parentId]) {
8917
+ const placed2 = placementUnder(doc, vectorNode.id, parentId);
8918
+ if (placed2) doc = reparentNode(updateNode(doc, vectorNode.id, placed2), vectorNode.id, parentId);
8919
+ }
8900
8920
  state.selection.forEach((id) => {
8901
8921
  if (doc.nodes[id]) doc = removeNode(doc, id);
8902
8922
  });
8903
- const command = createCommand("FLATTEN", "Flatten selection", documentBefore, doc);
8904
- set2({
8905
- document: doc,
8906
- history: pushCommand(state.history, command),
8907
- selection: [vectorNode.id]
8908
- });
8923
+ if (documentBefore !== doc) get2().commitDocument(doc, "Flatten selection");
8924
+ set2({ selection: [vectorNode.id] });
8909
8925
  },
8910
8926
  joinPaths: () => {
8911
8927
  const state = get2();
@@ -10115,9 +10131,9 @@ if (typeof window !== "undefined") {
10115
10131
  if (typeof window !== "undefined" && navigator.webdriver) {
10116
10132
  window.__vpDesign = async (script, o = {}) => {
10117
10133
  const [{ registerBuiltinTools, runTool }, { editorToolContext }, { createDesignPreview }] = await Promise.all([
10118
- import("./tools-2TCRJ6YI.js").then(async (m) => ({ ...m, registerBuiltinTools: (await import("./builtin-B425EDUG.js")).registerBuiltinTools })),
10119
- import("./editor-seams-UO4QUUQH.js"),
10120
- import("./live-QLSNGZ3Y.js")
10134
+ import("./tools-HSZSBWOP.js").then(async (m) => ({ ...m, registerBuiltinTools: (await import("./builtin-6C24JNML.js")).registerBuiltinTools })),
10135
+ import("./editor-seams-SJRRQFZT.js"),
10136
+ import("./live-SODTH6AK.js")
10121
10137
  ]);
10122
10138
  registerBuiltinTools();
10123
10139
  const args = JSON.stringify({ ...o.name ? { name: o.name } : {}, ...o.size ? { size: o.size } : {}, ...o.frame ? { frame: o.frame } : {}, script });
@@ -10174,7 +10190,7 @@ if (typeof window !== "undefined" && navigator.webdriver) {
10174
10190
  return { type, width: spec.width, height: spec.height, b64: btoa(bin) };
10175
10191
  };
10176
10192
  window.__vpLottieCheck = async (what, at) => {
10177
- const [{ lottieCheckFrames }, { getActiveRenderer: getActiveRenderer2 }] = await Promise.all([import("./player-check-4LAIMR3H.js"), import("./renderer-registry-JWAJEHL4.js")]);
10193
+ const [{ lottieCheckFrames }, { getActiveRenderer: getActiveRenderer2 }] = await Promise.all([import("./player-check-3HTULNTP.js"), import("./renderer-registry-JWAJEHL4.js")]);
10178
10194
  const renderer = getActiveRenderer2();
10179
10195
  if (!renderer) throw new Error("no renderer on this route");
10180
10196
  const doc = useEditorStore.getState().document;
@@ -10215,37 +10231,6 @@ if (typeof window !== "undefined" && navigator.webdriver) {
10215
10231
  return Object.keys(doc.nodes).length;
10216
10232
  };
10217
10233
  }
10218
- function rebuildVectorData(points, closed) {
10219
- if (points.length < 2) return [];
10220
- const data = [];
10221
- data.push("M", points[0].x, points[0].y);
10222
- for (let i = 1; i < points.length; i++) {
10223
- const prev = points[i - 1];
10224
- const curr = points[i];
10225
- if (prev.handleOut && curr.handleIn) {
10226
- data.push("C", prev.handleOut.x, prev.handleOut.y, curr.handleIn.x, curr.handleIn.y, curr.x, curr.y);
10227
- } else if (prev.handleOut) {
10228
- data.push("Q", prev.handleOut.x, prev.handleOut.y, curr.x, curr.y);
10229
- } else if (curr.handleIn) {
10230
- data.push("Q", curr.handleIn.x, curr.handleIn.y, curr.x, curr.y);
10231
- } else {
10232
- data.push("L", curr.x, curr.y);
10233
- }
10234
- }
10235
- if (closed) {
10236
- const prev = points[points.length - 1];
10237
- const curr = points[0];
10238
- if (prev.handleOut && curr.handleIn) {
10239
- data.push("C", prev.handleOut.x, prev.handleOut.y, curr.handleIn.x, curr.handleIn.y, curr.x, curr.y);
10240
- } else if (prev.handleOut) {
10241
- data.push("Q", prev.handleOut.x, prev.handleOut.y, curr.x, curr.y);
10242
- } else if (curr.handleIn) {
10243
- data.push("Q", curr.handleIn.x, curr.handleIn.y, curr.x, curr.y);
10244
- }
10245
- data.push("Z");
10246
- }
10247
- return data;
10248
- }
10249
10234
  function fixCorruptedVectors(doc) {
10250
10235
  let changed = false;
10251
10236
  const newNodes = { ...doc.nodes };
@@ -10402,30 +10387,6 @@ function recoverPointsFromData(data) {
10402
10387
  }
10403
10388
  return points;
10404
10389
  }
10405
- function scaleChildrenRecursively(doc, parentId, scaleX, scaleY) {
10406
- const parent = doc.nodes[parentId];
10407
- if (!parent || !parent.childIds) return doc;
10408
- const newDoc = { ...doc, nodes: { ...doc.nodes } };
10409
- const processNode = (nodeId) => {
10410
- const node = newDoc.nodes[nodeId];
10411
- if (!node) return;
10412
- const updates = {
10413
- x: node.x * scaleX,
10414
- y: node.y * scaleY,
10415
- width: node.width * scaleX,
10416
- height: node.height * scaleY
10417
- };
10418
- if (node.type === "TEXT") {
10419
- updates.fontSize = (node.fontSize ?? 16) * Math.min(scaleX, scaleY);
10420
- }
10421
- newDoc.nodes[nodeId] = { ...node, ...updates };
10422
- if (node.childIds) {
10423
- node.childIds.forEach(processNode);
10424
- }
10425
- };
10426
- parent.childIds.forEach(processNode);
10427
- return newDoc;
10428
- }
10429
10390
  if (typeof module !== "undefined") module.hot?.decline();
10430
10391
  function placeInstance(document2, mainComponentId, pageId, x, y) {
10431
10392
  const main = document2.nodes[mainComponentId];
@@ -10455,13 +10416,11 @@ export {
10455
10416
  tabPrefsOnly,
10456
10417
  MAX_OPEN_NODES,
10457
10418
  useEditorStore,
10458
- rebuildVectorData,
10459
10419
  useSelection,
10460
10420
  useActiveTool,
10461
10421
  useCamera,
10462
10422
  useCurrentPageId,
10463
10423
  useDocument,
10464
10424
  useMode,
10465
- recoverPointsFromData,
10466
- scaleChildrenRecursively
10425
+ recoverPointsFromData
10467
10426
  };
@@ -40,7 +40,7 @@ async function underReviewKit(doc, kit) {
40
40
  return settleMeasuredLayout({ ...kitted, nodes });
41
41
  }
42
42
  async function renderDocument(doc, nodeIds, options) {
43
- const { selectionReferenceImages } = await import("./reference-images-CYSRQG7A.js");
43
+ const { selectionReferenceImages } = await import("./reference-images-TAWHPRYN.js");
44
44
  if (options?.kit) {
45
45
  doc = await underReviewKit(doc, options.kit);
46
46
  }
@@ -57,19 +57,19 @@ async function renderDocument(doc, nodeIds, options) {
57
57
  function generateCapability(ctx) {
58
58
  return async (prompt, options = {}) => {
59
59
  if (options.format === "audio") {
60
- const { requestAudio } = await import("./client-AMMTXTFS.js");
60
+ const { requestAudio } = await import("./client-JTMPIRKQ.js");
61
61
  const { signal: signal2, format: _f, ...rest2 } = options;
62
62
  void _f;
63
63
  return requestAudio({ prompt, ...rest2 }, signal2 ?? ctx.signal);
64
64
  }
65
65
  if (options.format === "video") {
66
- const { generateVideoFile } = await import("./generate-media-XMD232CS.js");
66
+ const { generateVideoFile } = await import("./generate-media-ODWN3RNS.js");
67
67
  const { format: _f, signal: signal2, ...rest2 } = options;
68
68
  void _f;
69
69
  return generateVideoFile({ ...rest2, prompt, doc: ctx.doc() }, { signal: signal2 ?? ctx.signal });
70
70
  }
71
71
  const [{ requestImage }, { effectiveImageModel, useAiStore }] = await Promise.all([
72
- import("./client-AMMTXTFS.js"),
72
+ import("./client-JTMPIRKQ.js"),
73
73
  import("./client-store-3YCO6KV5.js")
74
74
  ]);
75
75
  const modelId = effectiveImageModel(useAiStore.getState());
@@ -91,9 +91,9 @@ async function placeStockPhoto(photo, opts = {}) {
91
91
  }
92
92
  async function placePicture(imported, opts = {}) {
93
93
  const [{ useEditorStore }, { photoFrameOf }, { placeImage }] = await Promise.all([
94
- import("./editor-store-V43NADG6.js"),
94
+ import("./editor-store-AXRJNCRC.js"),
95
95
  import("../lib/document/photo-frames.js"),
96
- import("./media-tool-TXQINVAR.js")
96
+ import("./media-tool-76BJQ4EH.js")
97
97
  ]);
98
98
  const st = useEditorStore.getState();
99
99
  const frame = photoFrameOf(st.document.nodes, opts.targetId !== void 0 ? opts.targetId : st.selection[0] ?? null);
@@ -8,7 +8,7 @@ import {
8
8
  needsSelection,
9
9
  pageGo,
10
10
  selectionIsPicture
11
- } from "./chunk-MY5CBA5H.js";
11
+ } from "./chunk-7DRZUU3D.js";
12
12
  import {
13
13
  external_exports
14
14
  } from "./chunk-VOOUF5TT.js";
@@ -31,7 +31,7 @@ var none = external_exports.object({});
31
31
  var emit = (name, detail) => {
32
32
  if (typeof window !== "undefined") window.dispatchEvent(new CustomEvent(name, { detail }));
33
33
  };
34
- var store = () => import("./editor-store-V43NADG6.js").then((m) => m.useEditorStore.getState());
34
+ var store = () => import("./editor-store-AXRJNCRC.js").then((m) => m.useEditorStore.getState());
35
35
  var MODE_IDS = MODE_LIST.map((m) => m.id);
36
36
  var MODE_ALIASES = { JAM: "POPCORN", DEV: "VIEW" };
37
37
  var modeSet = defineCommand({
@@ -167,7 +167,7 @@ var dialogOpen = defineCommand({
167
167
  (await import("./plan-limit-YTIOM3WO.js")).openPlanDialog();
168
168
  break;
169
169
  case "credits":
170
- await (await import("./buy-credits-YD6DBAQB.js")).buyAiCredits();
170
+ await (await import("./buy-credits-L4YYC7OH.js")).buyAiCredits();
171
171
  break;
172
172
  case "tokens":
173
173
  emit("popcraft-open-tokens");
@@ -213,7 +213,7 @@ var aiOpen = defineCommand({
213
213
  ] } },
214
214
  run: async ({ dialog, skillId }) => {
215
215
  if (dialog) (await import("./client-store-3YCO6KV5.js")).openAiDialog(dialog);
216
- else (await import("./store-OUZ5GTY5.js")).openAgentPanel({ skillId: skillId ?? null });
216
+ else (await import("./store-RMG4PHWL.js")).openAgentPanel({ skillId: skillId ?? null });
217
217
  return { summary: dialog ? `Opened AI ${dialog}` : "Opened the agent" };
218
218
  }
219
219
  });
@@ -226,7 +226,7 @@ var agentContinue = defineCommand({
226
226
  params: external_exports.object({}),
227
227
  expose: { ui: { label: "AI: Continue the agent\u2019s last turn", keywords: ["ai", "agent", "continue", "resume", "retry", "keep going"] } },
228
228
  run: async () => {
229
- const resumed = await (await import("./runner-ULBSWTOK.js")).continueTurn();
229
+ const resumed = await (await import("./runner-YB2KJMV5.js")).continueTurn();
230
230
  return { summary: resumed ? "Continued the agent" : "Nothing to continue" };
231
231
  }
232
232
  });
@@ -305,11 +305,11 @@ var toolPlace = defineCommand({
305
305
  run: async ({ what }) => {
306
306
  if (what === "media") {
307
307
  const s = await store();
308
- const { placeMediaFromPicker } = await import("./media-tool-TXQINVAR.js");
308
+ const { placeMediaFromPicker } = await import("./media-tool-76BJQ4EH.js");
309
309
  await placeMediaFromPicker({ kind: "point", x: s.camera.x, y: s.camera.y });
310
310
  return { summary: "Placing media" };
311
311
  }
312
- const { beginEyedrop } = await import("./eyedropper-4D6OK4VM.js");
312
+ const { beginEyedrop } = await import("./eyedropper-EZ33OG43.js");
313
313
  void beginEyedrop();
314
314
  return { summary: "Pick a color" };
315
315
  }
@@ -327,7 +327,7 @@ var nodeRasterize = defineCommand({
327
327
  keywords: ["rasterize", "raster", "flatten", "pixels", "paint layer", "erase", "bitmap"]
328
328
  } },
329
329
  run: async () => {
330
- const { flattenSelectionToPaintLayer } = await import("./raster-actions-KYYBZLGY.js");
330
+ const { flattenSelectionToPaintLayer } = await import("./raster-actions-MC3CT72Z.js");
331
331
  await flattenSelectionToPaintLayer();
332
332
  return { summary: "Rasterized" };
333
333
  }
@@ -438,7 +438,7 @@ function pluginCommand(plugins) {
438
438
  params: external_exports.object({ pluginId: external_exports.string(), commandId: external_exports.string() }),
439
439
  expose: { ui: { label: "Run plugin", keywords: ["plugin", "extension", "run"], variants, palette: variants.length ? void 0 : false } },
440
440
  run: async ({ pluginId, commandId }) => {
441
- await (await import("./host-WX77JQ2K.js")).runPlugin(pluginId, commandId);
441
+ await (await import("./host-K6K7OOJY.js")).runPlugin(pluginId, commandId);
442
442
  return { summary: "Plugin started" };
443
443
  }
444
444
  });
@@ -1744,12 +1744,59 @@ var require_polygon_clipping_cjs = __commonJS({
1744
1744
 
1745
1745
  // lib/engine/vector-geometry-cache.ts
1746
1746
  init_define_POPCRAFT_COMPONENT_IDS();
1747
- var import_polygon_clipping2 = __toESM(require_polygon_clipping_cjs());
1747
+ var import_polygon_clipping3 = __toESM(require_polygon_clipping_cjs());
1748
1748
  init_flatten();
1749
1749
 
1750
1750
  // lib/engine/geometry/triangulate.ts
1751
1751
  init_define_POPCRAFT_COMPONENT_IDS();
1752
+ var import_polygon_clipping2 = __toESM(require_polygon_clipping_cjs());
1753
+
1754
+ // lib/engine/geometry/winding.ts
1755
+ init_define_POPCRAFT_COMPONENT_IDS();
1752
1756
  var import_polygon_clipping = __toESM(require_polygon_clipping_cjs());
1757
+ var signedArea = (r) => {
1758
+ let a = 0;
1759
+ for (let i = 0, j = r.length - 1; i < r.length; j = i++) a += (r[j][0] - r[i][0]) * (r[j][1] + r[i][1]);
1760
+ return a / 2;
1761
+ };
1762
+ var inside = ([x, y], r) => {
1763
+ let c = false;
1764
+ for (let i = 0, j = r.length - 1; i < r.length; j = i++) {
1765
+ const [xi, yi] = r[i], [xj, yj] = r[j];
1766
+ if (yi > y !== yj > y && x < (xj - xi) * (y - yi) / (yj - yi) + xi) c = !c;
1767
+ }
1768
+ return c;
1769
+ };
1770
+ function interiorPoint(r) {
1771
+ let cx = 0, cy = 0;
1772
+ for (const [x, y] of r) {
1773
+ cx += x;
1774
+ cy += y;
1775
+ }
1776
+ const centroid = [cx / r.length, cy / r.length];
1777
+ if (inside(centroid, r)) return centroid;
1778
+ const [a, b, c] = [r[0], r[1], r[2] ?? r[0]];
1779
+ return [(a[0] + b[0] + c[0]) / 3, (a[1] + b[1] + c[1]) / 3];
1780
+ }
1781
+ function nonzeroMultiPoly(rings) {
1782
+ const usable = rings.filter((r) => r.length >= 3);
1783
+ if (!usable.length) return [];
1784
+ const polys = usable.map((r) => [r]);
1785
+ if (usable.length === 1) return import_polygon_clipping.default.union(polys[0]);
1786
+ const areas = usable.map(signedArea);
1787
+ const add = [], sub = [];
1788
+ usable.forEach((r, i) => {
1789
+ const p = interiorPoint(r);
1790
+ let w = Math.sign(areas[i]);
1791
+ usable.forEach((o, j) => {
1792
+ if (j !== i && Math.abs(areas[j]) > Math.abs(areas[i]) && inside(p, o)) w += Math.sign(areas[j]);
1793
+ });
1794
+ (w === 0 ? sub : add).push(polys[i]);
1795
+ });
1796
+ if (!add.length) return [];
1797
+ const filled = import_polygon_clipping.default.union(add[0], ...add.slice(1));
1798
+ return sub.length ? import_polygon_clipping.default.difference(filled, ...sub) : filled;
1799
+ }
1753
1800
 
1754
1801
  // lib/engine/vector-geometry-cache.ts
1755
1802
  init_shape_outline();
@@ -1771,7 +1818,7 @@ function computeBooleanMultiPoly(node, allNodes) {
1771
1818
  const asPolys = rings.map((r) => [r]);
1772
1819
  let mp;
1773
1820
  try {
1774
- mp = asPolys.length > 1 ? import_polygon_clipping2.default.union(asPolys[0], ...asPolys.slice(1)) : asPolys;
1821
+ mp = asPolys.length > 1 ? import_polygon_clipping3.default.union(asPolys[0], ...asPolys.slice(1)) : asPolys;
1775
1822
  } catch {
1776
1823
  mp = asPolys;
1777
1824
  }
@@ -1783,14 +1830,14 @@ function computeBooleanMultiPoly(node, allNodes) {
1783
1830
  try {
1784
1831
  const rest = operands.slice(1);
1785
1832
  if (rest.length > 0) {
1786
- if (op === "SUBTRACT") result = import_polygon_clipping2.default.difference(operands[0], ...rest);
1787
- else if (op === "INTERSECT") result = import_polygon_clipping2.default.intersection(operands[0], ...rest);
1788
- else if (op === "EXCLUDE") result = import_polygon_clipping2.default.xor(operands[0], ...rest);
1789
- else result = import_polygon_clipping2.default.union(operands[0], ...rest);
1833
+ if (op === "SUBTRACT") result = import_polygon_clipping3.default.difference(operands[0], ...rest);
1834
+ else if (op === "INTERSECT") result = import_polygon_clipping3.default.intersection(operands[0], ...rest);
1835
+ else if (op === "EXCLUDE") result = import_polygon_clipping3.default.xor(operands[0], ...rest);
1836
+ else result = import_polygon_clipping3.default.union(operands[0], ...rest);
1790
1837
  }
1791
1838
  } catch {
1792
1839
  try {
1793
- result = import_polygon_clipping2.default.union(operands[0], ...operands.slice(1));
1840
+ result = import_polygon_clipping3.default.union(operands[0], ...operands.slice(1));
1794
1841
  } catch {
1795
1842
  result = operands[0];
1796
1843
  }
@@ -1800,5 +1847,6 @@ function computeBooleanMultiPoly(node, allNodes) {
1800
1847
 
1801
1848
  export {
1802
1849
  require_polygon_clipping_cjs,
1850
+ nonzeroMultiPoly,
1803
1851
  computeBooleanMultiPoly
1804
1852
  };
@@ -4,6 +4,9 @@ import { dirname as __popcraftDirname } from 'node:path';
4
4
  const require = __popcraftRequire(import.meta.url);
5
5
  const __filename = __popcraftPath(import.meta.url);
6
6
  const __dirname = __popcraftDirname(__filename);
7
+ import {
8
+ scaleSubtreePatches
9
+ } from "./chunk-OLQTCVWP.js";
7
10
  import {
8
11
  importSVG
9
12
  } from "./chunk-7DATU5VX.js";
@@ -45,11 +48,22 @@ function placeSvgLayers(doc, parentId, svg, place) {
45
48
  if (n.type === "IMAGE" && !doc.nodes[n.id] && url?.startsWith("data:")) nodes[n.id] = { ...n, imageUrl: place.intern(url) };
46
49
  }
47
50
  }
48
- const minX = Math.min(...kids.map((k) => k.x)), minY = Math.min(...kids.map((k) => k.y));
49
- const maxX = Math.max(...kids.map((k) => k.x + k.width)), maxY = Math.max(...kids.map((k) => k.y + k.height));
50
- for (const k of kids) nodes[k.id] = { ...nodes[k.id], x: k.x - minX, y: k.y - minY };
51
- const w = Math.max(1, maxX - minX), h = Math.max(1, maxY - minY);
52
- nodes[frame.id] = { ...nodes[frame.id], x: Math.round(place.cx - w / 2), y: Math.round(place.cy - h / 2), width: w, height: h };
51
+ const minX = Math.min(...kids.map((k2) => k2.x)), minY = Math.min(...kids.map((k2) => k2.y));
52
+ const maxX = Math.max(...kids.map((k2) => k2.x + k2.width)), maxY = Math.max(...kids.map((k2) => k2.y + k2.height));
53
+ for (const k2 of kids) nodes[k2.id] = { ...nodes[k2.id], x: k2.x - minX, y: k2.y - minY };
54
+ let w = Math.max(1, maxX - minX), h = Math.max(1, maxY - minY);
55
+ const f = place.fit;
56
+ const k = f && (f.width || f.height) ? Math.min(f.width ? f.width / w : Infinity, f.height ? f.height / h : Infinity) : 1;
57
+ if (k !== 1 && Number.isFinite(k) && k > 0) {
58
+ const wrapper = { childIds: kids.map((c) => c.id) };
59
+ for (const [id, patch] of scaleSubtreePatches({ ...nodes, [frame.id]: { ...nodes[frame.id], ...wrapper } }, frame.id, k, k, false)) {
60
+ nodes[id] = { ...nodes[id], ...patch };
61
+ }
62
+ w *= k;
63
+ h *= k;
64
+ }
65
+ const topLeft = place.anchor === "top-left";
66
+ nodes[frame.id] = { ...nodes[frame.id], x: Math.round(topLeft ? place.cx : place.cx - w / 2), y: Math.round(topLeft ? place.cy : place.cy - h / 2), width: w, height: h };
53
67
  return { doc: { ...next, nodes }, id: frame.id };
54
68
  }
55
69
 
@@ -7,10 +7,10 @@ const __dirname = __popcraftDirname(__filename);
7
7
  import {
8
8
  builtinCommands,
9
9
  registerBuiltinCommands
10
- } from "./chunk-MY5CBA5H.js";
10
+ } from "./chunk-7DRZUU3D.js";
11
11
  import {
12
12
  toolView
13
- } from "./chunk-6Q7JYDNH.js";
13
+ } from "./chunk-FM4WN2UV.js";
14
14
  import {
15
15
  init_define_POPCRAFT_COMPONENT_IDS
16
16
  } from "./chunk-WKDVCZ45.js";
@@ -6,7 +6,7 @@ const __filename = __popcraftPath(import.meta.url);
6
6
  const __dirname = __popcraftDirname(__filename);
7
7
  import {
8
8
  hyperyRequestHeaders
9
- } from "./chunk-U5UFIM2E.js";
9
+ } from "./chunk-32OBPYVY.js";
10
10
  import {
11
11
  aiAvailability,
12
12
  effectiveChatModel,