@popcraft/cli 0.24.1 → 0.24.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 (2) hide show
  1. package/dist/popcraft.mjs +61 -17
  2. package/package.json +2 -2
package/dist/popcraft.mjs CHANGED
@@ -1188,7 +1188,7 @@ function operations(spec = openapi) {
1188
1188
  }
1189
1189
  async function call(target2, method, path, opts = {}) {
1190
1190
  const qs = new URLSearchParams(opts.query ?? {}).toString();
1191
- const headers = { "user-agent": `popcraft-cli/${"0.24.1"}`, ...opts.headers };
1191
+ const headers = { "user-agent": `popcraft-cli/${"0.24.2"}`, ...opts.headers };
1192
1192
  if (target2.token) headers.authorization = `Bearer ${target2.token}`;
1193
1193
  if (opts.contentType) headers["content-type"] = opts.contentType;
1194
1194
  try {
@@ -256903,6 +256903,7 @@ __export(pose_exports, {
256903
256903
  bakeMotion: () => bakeMotion,
256904
256904
  evaluatePose: () => evaluatePose,
256905
256905
  frameTimeline: () => frameTimeline,
256906
+ poseNodesAt: () => poseNodesAt,
256906
256907
  poseOver: () => poseOver,
256907
256908
  posedNode: () => posedNode,
256908
256909
  reevaluatePose: () => reevaluatePose,
@@ -257037,6 +257038,19 @@ function bakeMotion(nodes, frameId, time4) {
257037
257038
  noteChanged(nodes, baked, ids2);
257038
257039
  return baked;
257039
257040
  }
257041
+ function poseNodesAt(nodes, ids2, time4, frameId) {
257042
+ const frames = [];
257043
+ for (const id3 of ids2) {
257044
+ let owner;
257045
+ for (let n = nodes[id3]; n && n.type !== "PAGE"; n = n.parentId ? nodes[n.parentId] : void 0) {
257046
+ if ((n.type === "FRAME" || n.type === "COMPONENT") && (frameId ? n.id === frameId : hasFrameMotion(nodes, n.id))) owner = n.id;
257047
+ }
257048
+ if (owner && !frames.includes(owner)) frames.push(owner);
257049
+ }
257050
+ let out = nodes;
257051
+ for (const f2 of frames) out = evaluatePose(out, { kind: "frame", frameId: f2 }, Math.max(0, time4)).nodes;
257052
+ return out;
257053
+ }
257040
257054
  function posedNode(nodes, id3, frameId, time4) {
257041
257055
  const node2 = nodes[id3];
257042
257056
  if (!node2) return void 0;
@@ -308912,7 +308926,6 @@ async function createFreshFileOrExplain(place4 = {}, seed2 = {}) {
308912
308926
  var online, goesLocal;
308913
308927
  var init_new_file = __esm({
308914
308928
  "lib/client/cloud/new-file.ts"() {
308915
- "use strict";
308916
308929
  init_scene_graph();
308917
308930
  init_print_pages();
308918
308931
  init_page_presets();
@@ -309828,6 +309841,7 @@ function documentForExport(doc2) {
309828
309841
  continue;
309829
309842
  }
309830
309843
  nodes[id3] = { ...node2, fills: fills.filter((p2) => !excluded(p2)) };
309844
+ carryTextPose(node2, nodes[id3]);
309831
309845
  changed = true;
309832
309846
  }
309833
309847
  return changed ? { ...doc2, nodes } : doc2;
@@ -309836,6 +309850,7 @@ var excluded, hasExcludedFill;
309836
309850
  var init_export_fills = __esm({
309837
309851
  "lib/document/export-fills.ts"() {
309838
309852
  "use strict";
309853
+ init_text_animators();
309839
309854
  excluded = (p2) => p2.includeInExport === false;
309840
309855
  hasExcludedFill = (fills) => !!fills?.some(excluded);
309841
309856
  }
@@ -325922,7 +325937,7 @@ var init_package = __esm({
325922
325937
  "packages/runtime/package.json"() {
325923
325938
  package_default = {
325924
325939
  name: "@popcraft/runtime",
325925
- version: "0.24.1",
325940
+ version: "0.24.2",
325926
325941
  description: "What code exported from PopCraft shares: the meaning of expressions (operators and functions) and, as it grows, the parts of a design's behaviour that are common code rather than generated React.",
325927
325942
  license: "MIT",
325928
325943
  homepage: "https://popcraft.app/docs/exporting/nextjs",
@@ -352686,6 +352701,24 @@ var init_board_export = __esm({
352686
352701
  });
352687
352702
 
352688
352703
  // lib/commands/export.ts
352704
+ async function docAtTime(doc2, ids2, time4) {
352705
+ let frameId;
352706
+ if (time4 === void 0) {
352707
+ try {
352708
+ const { useEditorStore: useEditorStore2 } = await Promise.resolve().then(() => (init_editor_store(), editor_store_exports));
352709
+ const st = useEditorStore2.getState();
352710
+ const target2 = st.transport?.target;
352711
+ if (st.mode !== "ANIMATE" || target2?.kind !== "frame") return doc2;
352712
+ time4 = st.transport.time;
352713
+ frameId = target2.frameId;
352714
+ } catch {
352715
+ return doc2;
352716
+ }
352717
+ }
352718
+ const { poseNodesAt: poseNodesAt2 } = await Promise.resolve().then(() => (init_pose(), pose_exports));
352719
+ const nodes = poseNodesAt2(doc2.nodes, ids2, time4, frameId);
352720
+ return nodes === doc2.nodes ? doc2 : { ...doc2, nodes };
352721
+ }
352689
352722
  function animationTarget(args2, ctx2, doc2) {
352690
352723
  if (args2.composition) {
352691
352724
  if (!doc2.compositions?.[args2.composition]) throw new ToolError(`There is no composition "${args2.composition}".`);
@@ -352794,7 +352827,7 @@ async function exportSite(doc2, pageId2, packaging, styling = "css", siteUrl) {
352794
352827
  downloadBlob2(zipFiles2(files.map((f2) => ({ name: f2.path, bytes: bytesOf2(f2) }))), `${base}.zip`);
352795
352828
  return { summary: `Exported ${plural2(site.pages.length, "page")} as ${packaging === "next" ? "a Next.js project" : "a static site"} (${base}.zip)`, data: { filename: `${base}.zip`, packaging, pages: site.pages.map((p2) => p2.route), files: files.length } };
352796
352829
  }
352797
- var MAX_INLINE_BYTES, exportSvg, exportNodes, exportPdf, exportCopy, exportPages, exportPptx, animationParams, videoParams, gifParams, lottieParams, animationCommand, TARGET, exportMp4, exportWebm, exportGif, exportPngSequence, exportLottie2, exportWeb, APP_STOREFRONT_TARGETS, exportStorefront, exportBoard;
352830
+ var MAX_INLINE_BYTES, timeParam, exportSvg, exportNodes, exportPdf, exportCopy, exportPages, exportPptx, animationParams, videoParams, gifParams, lottieParams, animationCommand, TARGET, exportMp4, exportWebm, exportGif, exportPngSequence, exportLottie2, exportWeb, APP_STOREFRONT_TARGETS, exportStorefront, exportBoard;
352798
352831
  var init_export2 = __esm({
352799
352832
  "lib/commands/export.ts"() {
352800
352833
  "use strict";
@@ -352809,6 +352842,7 @@ var init_export2 = __esm({
352809
352842
  init_formats();
352810
352843
  init_tree();
352811
352844
  MAX_INLINE_BYTES = 15e5;
352845
+ timeParam = external_exports.number().min(0).optional().describe("Moment (ms) of the frame's timeline to export animated layers at. Defaults to the playhead when the frame is open in Animate, else the layers at rest.");
352812
352846
  exportSvg = defineCommand({
352813
352847
  id: "export.svg",
352814
352848
  title: "Export SVG",
@@ -352818,7 +352852,8 @@ var init_export2 = __esm({
352818
352852
  needs: ["canvas"],
352819
352853
  params: external_exports.object({
352820
352854
  id: external_exports.string().describe("Node to export."),
352821
- maxChars: external_exports.number().int().min(500).max(2e5).optional().describe("Truncate the markup at this many characters (default 20000).")
352855
+ maxChars: external_exports.number().int().min(500).max(2e5).optional().describe("Truncate the markup at this many characters (default 20000)."),
352856
+ time: timeParam
352822
352857
  }),
352823
352858
  expose: {
352824
352859
  agent: {
@@ -352827,7 +352862,7 @@ var init_export2 = __esm({
352827
352862
  }
352828
352863
  },
352829
352864
  run: async (args2, ctx2) => {
352830
- const doc2 = ctx2.doc();
352865
+ const doc2 = await docAtTime(ctx2.doc(), [args2.id], args2.time);
352831
352866
  const node2 = nodeOrThrow(doc2, args2.id);
352832
352867
  const renderer = ctx2.use("canvas")();
352833
352868
  if (!renderer) throw new ToolError("SVG export needs the canvas renderer, which is not running (the editor canvas may not have initialised WebGPU). Use get_node or measure instead.");
@@ -352857,7 +352892,8 @@ var init_export2 = __esm({
352857
352892
  scale: external_exports.number().min(0.1).max(8).optional().describe("With format: pixel scale factor (default 1; 2 for @2x)."),
352858
352893
  suffix: external_exports.string().max(20).optional().describe('With format: added to each file name ("@2x").'),
352859
352894
  download: external_exports.boolean().optional().describe("Save the files to the user's downloads folder. Off by default \u2014 never turn it on unless the user asked for a file."),
352860
- singlePdf: external_exports.boolean().optional().describe("For PDF only: put every layer in one document, one page each (default true).")
352895
+ singlePdf: external_exports.boolean().optional().describe("For PDF only: put every layer in one document, one page each (default true)."),
352896
+ time: timeParam
352861
352897
  }),
352862
352898
  expose: {
352863
352899
  ui: {
@@ -352879,8 +352915,8 @@ var init_export2 = __esm({
352879
352915
  }
352880
352916
  },
352881
352917
  run: async (args2, ctx2) => {
352882
- const doc2 = ctx2.doc();
352883
352918
  const ids2 = targetIds(args2.ids, ctx2.selection(), "export_nodes");
352919
+ const doc2 = await docAtTime(ctx2.doc(), ids2, args2.time);
352884
352920
  const nodes = ids2.map((id3) => nodeOrThrow(doc2, id3));
352885
352921
  const renderer = ctx2.use("canvas")();
352886
352922
  if (!renderer) throw new ToolError("Exporting needs the canvas renderer, which is not running (the editor canvas may not have initialised WebGPU). Use measure or export_svg instead.");
@@ -352943,7 +352979,8 @@ var init_export2 = __esm({
352943
352979
  spreads: external_exports.boolean().optional().describe("Facing pages on one sheet (2\u20133, 4\u20135 \u2026). Same as layout: spreads."),
352944
352980
  splitSpreads: external_exports.boolean().optional().describe("Cut an oversized sheet (a centrefold) into single pages so the file has ONE page size \u2014 what almost every printer requires. Off for the printers that take a spread as one image and cut it themselves. Default true."),
352945
352981
  layout: external_exports.enum(["pages", "spreads", "booklet", "nup2", "nup4"]).optional().describe("How pages sit on each printed sheet: one each, reader spreads, a saddle-stitch booklet to fold and staple, or two/four to a sheet."),
352946
- ats: external_exports.boolean().optional().describe("ATS-friendly: all text embedded, reading order, real spaces; gradient text becomes solid.")
352982
+ ats: external_exports.boolean().optional().describe("ATS-friendly: all text embedded, reading order, real spaces; gradient text becomes solid."),
352983
+ time: timeParam
352947
352984
  }),
352948
352985
  expose: {
352949
352986
  ui: { label: "Export as PDF", keywords: ["pdf", "export", "download", "print"] }
@@ -352960,12 +352997,15 @@ var init_export2 = __esm({
352960
352997
  nodes = frames.length ? frames : roots;
352961
352998
  }
352962
352999
  if (!nodes.length) throw new ToolError("There is nothing on this page to export.");
353000
+ const posed2 = await docAtTime(doc2, nodes.map((n) => n.id), args2.time);
353001
+ nodes = nodes.map((n) => posed2.nodes[n.id] ?? n);
352963
353002
  const { exportNodesToPDF: exportNodesToPDF2 } = await Promise.resolve().then(() => (init_pdf(), pdf_exports));
352964
353003
  const { downloadBlob: downloadBlob2 } = await Promise.resolve().then(() => (init_download(), download_exports));
352965
- const { scale, ids: _ids, ...print2 } = args2;
353004
+ const { scale, ids: _ids, time: _time, ...print2 } = args2;
352966
353005
  void _ids;
353006
+ void _time;
352967
353007
  const opts = Object.values(print2).some((v) => v !== void 0) ? { ...print2 } : scale ?? 1;
352968
- const blob = await exportNodesToPDF2(renderer, nodes, opts, doc2, doc2.styles);
353008
+ const blob = await exportNodesToPDF2(renderer, nodes, opts, posed2, posed2.styles);
352969
353009
  if (!blob) throw new ToolError("Those layers produced no PDF \u2014 they may be empty, hidden or zero-sized.");
352970
353010
  const filename = `${doc2.name || "export"}.pdf`;
352971
353011
  downloadBlob2(blob, filename);
@@ -352982,7 +353022,8 @@ var init_export2 = __esm({
352982
353022
  params: external_exports.object({
352983
353023
  id: external_exports.string().optional().describe("Layer to copy. Defaults to the first selected one."),
352984
353024
  format: external_exports.enum(["PNG", "SVG"]).optional().describe("Default PNG."),
352985
- scale: external_exports.number().min(0.1).max(8).optional().describe("PNG only; default 2.")
353025
+ scale: external_exports.number().min(0.1).max(8).optional().describe("PNG only; default 2."),
353026
+ time: timeParam
352986
353027
  }),
352987
353028
  expose: {
352988
353029
  ui: {
@@ -352996,9 +353037,9 @@ var init_export2 = __esm({
352996
353037
  }
352997
353038
  },
352998
353039
  run: async (args2, ctx2) => {
352999
- const doc2 = ctx2.doc();
353000
353040
  const id3 = args2.id ?? ctx2.selection()[0];
353001
353041
  if (!id3) throw new ToolError("Nothing is selected, so there is nothing to copy.");
353042
+ const doc2 = await docAtTime(ctx2.doc(), [id3], args2.time);
353002
353043
  const node2 = nodeOrThrow(doc2, id3);
353003
353044
  const renderer = ctx2.use("canvas")();
353004
353045
  if (!renderer) throw new ToolError("Copying a layer needs the canvas renderer, which is not running.");
@@ -353019,7 +353060,8 @@ var init_export2 = __esm({
353019
353060
  params: external_exports.object({
353020
353061
  ids: external_exports.array(external_exports.string()).max(500).optional().describe("Defaults to the selection, then to the page's print pages / top-level frames."),
353021
353062
  format: external_exports.enum(["PNG", "JPG", "WEBP"]).optional().describe("Default PNG."),
353022
- dpi: external_exports.number().min(36).max(1200).optional().describe("Resolution; 96 is 1:1 with the canvas. Print pages default to 300.")
353063
+ dpi: external_exports.number().min(36).max(1200).optional().describe("Resolution; 96 is 1:1 with the canvas. Print pages default to 300."),
353064
+ time: timeParam
353023
353065
  }),
353024
353066
  expose: {
353025
353067
  ui: { label: "Export pages as images", keywords: ["zip", "export", "pages", "png", "jpg", "dpi", "print"] },
@@ -353042,6 +353084,8 @@ var init_export2 = __esm({
353042
353084
  }
353043
353085
  }
353044
353086
  if (!nodes.length) throw new ToolError("There is nothing on this page to export.");
353087
+ const posed2 = await docAtTime(doc2, nodes.map((n) => n.id), args2.time);
353088
+ nodes = nodes.map((n) => posed2.nodes[n.id] ?? n);
353045
353089
  const format = args2.format ?? "PNG";
353046
353090
  const dpi = args2.dpi ?? (doc2.settings?.kind === "PRINT" ? doc2.settings.dpi ?? 300 : 96);
353047
353091
  const { exportNodeToBlob: exportNodeToBlob2 } = await Promise.resolve().then(() => (init_export(), export_exports));
@@ -353050,7 +353094,7 @@ var init_export2 = __esm({
353050
353094
  const files = [];
353051
353095
  const pad = String(nodes.length).length;
353052
353096
  for (let i2 = 0; i2 < nodes.length; i2++) {
353053
- const blob = await exportNodeToBlob2(renderer, nodes[i2], { suffix: "", format, scale: dpi / 96, dpi }, doc2, doc2.styles);
353097
+ const blob = await exportNodeToBlob2(renderer, nodes[i2], { suffix: "", format, scale: dpi / 96, dpi }, posed2, posed2.styles);
353054
353098
  if (blob) files.push({ name: `${String(i2 + 1).padStart(pad, "0")}-${(nodes[i2].name || "page").replace(/[\\/:*?"<>|]+/g, "_")}.${format.toLowerCase()}`, bytes: new Uint8Array(await blob.arrayBuffer()) });
353055
353099
  }
353056
353100
  if (!files.length) throw new ToolError("Those layers produced no images \u2014 they may be empty, hidden or zero-sized.");
@@ -396011,7 +396055,6 @@ function record(source, namespaces, globals, limits) {
396011
396055
  var HELPER_NAMES;
396012
396056
  var init_helper_names = __esm({
396013
396057
  "lib/agent/design-script/helper-names.ts"() {
396014
- "use strict";
396015
396058
  HELPER_NAMES = ["draw", "marks", "fit", "motion", "captions", "overlays", "texture", "pointer", "windows", "devices", "type", "beat", "web", "social", "video", "site", "effects"];
396016
396059
  }
396017
396060
  });
@@ -401201,6 +401244,7 @@ function registerBuiltinCommands() {
401201
401244
  var builtinCommands, uiOnlyCommands;
401202
401245
  var init_builtin4 = __esm({
401203
401246
  "lib/commands/builtin.ts"() {
401247
+ "use strict";
401204
401248
  init_registry();
401205
401249
  init_node();
401206
401250
  init_node();
@@ -408697,7 +408741,7 @@ init_resources();
408697
408741
  init_desktop();
408698
408742
  init_hypery();
408699
408743
  import { createInterface } from "node:readline";
408700
- var VERSION2 = "0.24.1";
408744
+ var VERSION2 = "0.24.2";
408701
408745
  var HELP = `popcraft ${VERSION2} \u2014 the PopCraft command line
408702
408746
 
408703
408747
  Files (headless, on .popcraft files):
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@popcraft/cli",
3
- "version": "0.24.1",
3
+ "version": "0.24.2",
4
4
  "description": "The PopCraft command line: edit .popcraft files headlessly, call the REST API, publish to the marketplace and manage the desktop app's local plugins, themes, fonts, skills and agents.",
5
5
  "license": "MIT",
6
6
  "homepage": "https://popcraft.app/docs/api/cli",
@@ -34,7 +34,7 @@
34
34
  "esbuild": "0.28.2"
35
35
  },
36
36
  "dependencies": {
37
- "@popcraft/kit": "0.24.1"
37
+ "@popcraft/kit": "0.24.2"
38
38
  },
39
39
  "scripts": {
40
40
  "build": "node build.mjs",