@popcraft/cli 0.28.0 → 0.29.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.
Files changed (2) hide show
  1. package/dist/popcraft.mjs +1395 -379
  2. package/package.json +2 -2
package/dist/popcraft.mjs CHANGED
@@ -621,16 +621,16 @@ var init_openapi = __esm({
621
621
  id = (name2, description) => ({ name: name2, in: "path", required: true, schema: str, description });
622
622
  query = (name2, schema, description, required2 = false) => ({ name: name2, in: "query", required: required2, schema, description });
623
623
  cursor = query("cursor", str, "The previous page\u2019s `nextCursor`");
624
- op = (tag, summary, scope, response, { responses = {}, ...extra } = {}) => ({
625
- tags: [tag],
624
+ op = (tag2, summary, scope, response, { responses = {}, ...extra } = {}) => ({
625
+ tags: [tag2],
626
626
  summary,
627
627
  security: [{ bearer: scope ? [scope] : [] }],
628
628
  // A 201 in `responses` replaces the default 200; other codes (400, …) are added to the standard errors.
629
629
  responses: { ...responses["201"] ? {} : { "200": response }, ...errors, ...responses },
630
630
  ...extra
631
631
  });
632
- pub = (tag, summary, response, extra = {}) => ({
633
- tags: [tag],
632
+ pub = (tag2, summary, response, extra = {}) => ({
633
+ tags: [tag2],
634
634
  summary,
635
635
  security: [],
636
636
  responses: { "200": response, "404": errors["404"], "429": errors["429"] },
@@ -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.28.0"}`, ...opts.headers };
1191
+ const headers = { "user-agent": `popcraft-cli/${"0.29.0"}`, ...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 {
@@ -9215,8 +9215,8 @@ function cleanEnum(obj2) {
9215
9215
  return Number.isNaN(Number.parseInt(k2, 10));
9216
9216
  }).map((el) => el[1]);
9217
9217
  }
9218
- function base64ToUint8Array(base644) {
9219
- const binaryString = atob(base644);
9218
+ function base64ToUint8Array(base645) {
9219
+ const binaryString = atob(base645);
9220
9220
  const bytes2 = new Uint8Array(binaryString.length);
9221
9221
  for (let i2 = 0; i2 < binaryString.length; i2++) {
9222
9222
  bytes2[i2] = binaryString.charCodeAt(i2);
@@ -9231,9 +9231,9 @@ function uint8ArrayToBase64(bytes2) {
9231
9231
  return btoa(binaryString);
9232
9232
  }
9233
9233
  function base64urlToUint8Array(base64url3) {
9234
- const base644 = base64url3.replace(/-/g, "+").replace(/_/g, "/");
9235
- const padding3 = "=".repeat((4 - base644.length % 4) % 4);
9236
- return base64ToUint8Array(base644 + padding3);
9234
+ const base645 = base64url3.replace(/-/g, "+").replace(/_/g, "/");
9235
+ const padding3 = "=".repeat((4 - base645.length % 4) % 4);
9236
+ return base64ToUint8Array(base645 + padding3);
9237
9237
  }
9238
9238
  function uint8ArrayToBase64url(bytes2) {
9239
9239
  return uint8ArrayToBase64(bytes2).replace(/\+/g, "-").replace(/\//g, "_").replace(/=/g, "");
@@ -10785,8 +10785,8 @@ function isValidBase64(data) {
10785
10785
  function isValidBase64URL(data) {
10786
10786
  if (!base64urlCharset.test(data))
10787
10787
  return false;
10788
- const base644 = data.replace(/[-_]/g, (c2) => c2 === "-" ? "+" : "/");
10789
- const padded = base644.padEnd(Math.ceil(base644.length / 4) * 4, "=");
10788
+ const base645 = data.replace(/[-_]/g, (c2) => c2 === "-" ? "+" : "/");
10789
+ const padded = base645.padEnd(Math.ceil(base645.length / 4) * 4, "=");
10790
10790
  return isValidBase64(padded);
10791
10791
  }
10792
10792
  function isLuhnAlgo(digits) {
@@ -11320,9 +11320,9 @@ function partPattern(schema) {
11320
11320
  return own2;
11321
11321
  }
11322
11322
  if (def.options) {
11323
- const sources = def.options.map(partPattern);
11324
- if (sources.every(Boolean))
11325
- return `^(${sources.map((s) => cleanRegex(s)).join("|")})$`;
11323
+ const sources2 = def.options.map(partPattern);
11324
+ if (sources2.every(Boolean))
11325
+ return `^(${sources2.map((s) => cleanRegex(s)).join("|")})$`;
11326
11326
  }
11327
11327
  return leafPattern(schema);
11328
11328
  }
@@ -24141,8 +24141,8 @@ var init_api2 = __esm({
24141
24141
  });
24142
24142
 
24143
24143
  // node_modules/.pnpm/zod@4.6.5/node_modules/zod/v4/core/to-json-schema.js
24144
- function assignProps(target2, ...sources) {
24145
- for (const source3 of sources) {
24144
+ function assignProps(target2, ...sources2) {
24145
+ for (const source3 of sources2) {
24146
24146
  for (const key5 of Reflect.ownKeys(source3)) {
24147
24147
  if (Object.prototype.propertyIsEnumerable.call(source3, key5)) {
24148
24148
  assignProp(target2, key5, source3[key5]);
@@ -29203,21 +29203,21 @@ function isPrimitive(value3) {
29203
29203
  return value3 == null || typeof value3 === "number" || typeof value3 === "boolean";
29204
29204
  }
29205
29205
  function monadic(fn, cache11, serializer, arg) {
29206
- const cacheKey = isPrimitive(arg) ? arg : serializer(arg);
29207
- let computedValue = cache11.get(cacheKey);
29206
+ const cacheKey2 = isPrimitive(arg) ? arg : serializer(arg);
29207
+ let computedValue = cache11.get(cacheKey2);
29208
29208
  if (typeof computedValue === "undefined") {
29209
29209
  computedValue = fn.call(this, arg);
29210
- cache11.set(cacheKey, computedValue);
29210
+ cache11.set(cacheKey2, computedValue);
29211
29211
  }
29212
29212
  return computedValue;
29213
29213
  }
29214
29214
  function variadic(fn, cache11, serializer) {
29215
29215
  const args2 = Array.prototype.slice.call(arguments, 3);
29216
- const cacheKey = serializer(args2);
29217
- let computedValue = cache11.get(cacheKey);
29216
+ const cacheKey2 = serializer(args2);
29217
+ let computedValue = cache11.get(cacheKey2);
29218
29218
  if (typeof computedValue === "undefined") {
29219
29219
  computedValue = fn.apply(this, args2);
29220
- cache11.set(cacheKey, computedValue);
29220
+ cache11.set(cacheKey2, computedValue);
29221
29221
  }
29222
29222
  return computedValue;
29223
29223
  }
@@ -32568,6 +32568,11 @@ var init_en2 = __esm({
32568
32568
  "command:export.web": "Export as web code\u2026",
32569
32569
  "command:export.webm": "Export animation as WebM",
32570
32570
  "command:file.duplicate": "Duplicate file",
32571
+ "command:font.add": "Add font to file\u2026",
32572
+ "command:font.list": "List fonts in file",
32573
+ "command:font.remove": "Remove font from file",
32574
+ "command:font.teamAdd": "Add team font\u2026",
32575
+ "command:font.teamList": "List team fonts",
32571
32576
  "command:generate.video": "Generate video",
32572
32577
  "command:history.redo": "Redo",
32573
32578
  "command:history.undo": "Undo",
@@ -33622,6 +33627,7 @@ var init_en2 = __esm({
33622
33627
  "fontPicker.handwriting": "Handwriting",
33623
33628
  "fontPicker.light": "Light",
33624
33629
  "fontPicker.medium": "Medium",
33630
+ "fontPicker.missingFont": "{family} is not available here, so this text draws in a fallback font. Upload the font file to use it.",
33625
33631
  "fontPicker.monospace": "Monospace",
33626
33632
  "fontPicker.noFontsFound": "No fonts found",
33627
33633
  "fontPicker.regular": "Regular",
@@ -33629,10 +33635,11 @@ var init_en2 = __esm({
33629
33635
  "fontPicker.searchFonts": "Search fonts...",
33630
33636
  "fontPicker.semiBold": "Semi Bold",
33631
33637
  "fontPicker.serif": "Serif",
33632
- "fontPicker.thatFileIsNotA": "That file is not a TTF, OTF, WOFF or WOFF2 font.",
33638
+ "fontPicker.thatFileIsNotA": "That file is not a TTF, OTF, TTC, WOFF or WOFF2 font.",
33633
33639
  "fontPicker.thatFontFileIsToo": "That font file is too large.",
33634
33640
  "fontPicker.thin": "Thin",
33635
33641
  "fontPicker.uploadFont": "Upload Font...",
33642
+ "fontPicker.uploadTeamFont": "Upload Font to Team...",
33636
33643
  "fontsSection.addFont": "Add font\u2026",
33637
33644
  "fontsSection.duplicateThisThemeToAdd": "Duplicate this theme to add fonts.",
33638
33645
  "fontsSection.duplicateToAddFonts": "Duplicate to add fonts\u2026",
@@ -37251,6 +37258,11 @@ var require_es = __commonJS({
37251
37258
  "command:export.web": "Exportar como c\xF3digo web\u2026",
37252
37259
  "command:export.webm": "Exportar animaci\xF3n como WebM",
37253
37260
  "command:file.duplicate": "Duplicar archivo",
37261
+ "command:font.add": "A\xF1adir fuente al archivo\u2026",
37262
+ "command:font.list": "Listar fuentes en el archivo",
37263
+ "command:font.remove": "Eliminar fuente del archivo",
37264
+ "command:font.teamAdd": "A\xF1adir fuente del equipo\u2026",
37265
+ "command:font.teamList": "Listar fuentes del equipo",
37254
37266
  "command:generate.video": "Generar video",
37255
37267
  "command:history.redo": "Rehacer",
37256
37268
  "command:history.undo": "Deshacer",
@@ -38305,6 +38317,7 @@ var require_es = __commonJS({
38305
38317
  "fontPicker.handwriting": "Manuscrita",
38306
38318
  "fontPicker.light": "Ligera",
38307
38319
  "fontPicker.medium": "Mediana",
38320
+ "fontPicker.missingFont": "{family} no est\xE1 disponible aqu\xED, por lo que este texto se muestra con una fuente de respaldo. Sube el archivo de la fuente para usarla.",
38308
38321
  "fontPicker.monospace": "Monoespaciada",
38309
38322
  "fontPicker.noFontsFound": "No se encontraron fuentes",
38310
38323
  "fontPicker.regular": "Regular",
@@ -38312,10 +38325,11 @@ var require_es = __commonJS({
38312
38325
  "fontPicker.searchFonts": "Buscar fuentes...",
38313
38326
  "fontPicker.semiBold": "Seminegrita",
38314
38327
  "fontPicker.serif": "Serif",
38315
- "fontPicker.thatFileIsNotA": "Ese archivo no es una fuente TTF, OTF, WOFF o WOFF2.",
38328
+ "fontPicker.thatFileIsNotA": "Ese archivo no es una fuente TTF, OTF, TTC, WOFF o WOFF2.",
38316
38329
  "fontPicker.thatFontFileIsToo": "Ese archivo de fuente es demasiado grande.",
38317
38330
  "fontPicker.thin": "Fina",
38318
38331
  "fontPicker.uploadFont": "Subir fuente...",
38332
+ "fontPicker.uploadTeamFont": "Subir fuente al equipo...",
38319
38333
  "fontsSection.addFont": "A\xF1adir fuente\u2026",
38320
38334
  "fontsSection.duplicateThisThemeToAdd": "Duplica este tema para a\xF1adir fuentes.",
38321
38335
  "fontsSection.duplicateToAddFonts": "Duplicar para a\xF1adir fuentes\u2026",
@@ -41934,6 +41948,11 @@ var require_fr = __commonJS({
41934
41948
  "command:export.web": "Exporter en code web\u2026",
41935
41949
  "command:export.webm": "Exporter l\u2019animation en WebM",
41936
41950
  "command:file.duplicate": "Dupliquer le fichier",
41951
+ "command:font.add": "Ajouter une police au fichier\u2026",
41952
+ "command:font.list": "Lister les polices du fichier",
41953
+ "command:font.remove": "Supprimer une police du fichier",
41954
+ "command:font.teamAdd": "Ajouter une police d\u2019\xE9quipe\u2026",
41955
+ "command:font.teamList": "Lister les polices d\u2019\xE9quipe",
41937
41956
  "command:generate.video": "G\xE9n\xE9rer une vid\xE9o",
41938
41957
  "command:history.redo": "R\xE9tablir",
41939
41958
  "command:history.undo": "Annuler",
@@ -42988,6 +43007,7 @@ var require_fr = __commonJS({
42988
43007
  "fontPicker.handwriting": "Manuscrite",
42989
43008
  "fontPicker.light": "L\xE9ger",
42990
43009
  "fontPicker.medium": "Moyen",
43010
+ "fontPicker.missingFont": "{family} n\u2019est pas disponible ici, ce texte est donc affich\xE9 avec une police de secours. T\xE9l\xE9chargez le fichier de police pour l\u2019utiliser.",
42991
43011
  "fontPicker.monospace": "Monospace",
42992
43012
  "fontPicker.noFontsFound": "Aucune police trouv\xE9e",
42993
43013
  "fontPicker.regular": "Normal",
@@ -42995,10 +43015,11 @@ var require_fr = __commonJS({
42995
43015
  "fontPicker.searchFonts": "Rechercher des polices\u2026",
42996
43016
  "fontPicker.semiBold": "Semi-gras",
42997
43017
  "fontPicker.serif": "Avec empattement",
42998
- "fontPicker.thatFileIsNotA": "Ce fichier n\u2019est pas une police TTF, OTF, WOFF ou WOFF2.",
43018
+ "fontPicker.thatFileIsNotA": "Ce fichier n\u2019est pas une police TTF, OTF, TTC, WOFF ou WOFF2.",
42999
43019
  "fontPicker.thatFontFileIsToo": "Ce fichier de police est trop volumineux.",
43000
43020
  "fontPicker.thin": "Fin",
43001
43021
  "fontPicker.uploadFont": "Importer une police\u2026",
43022
+ "fontPicker.uploadTeamFont": "T\xE9l\xE9charger une police d\u2019\xE9quipe...",
43002
43023
  "fontsSection.addFont": "Ajouter une police\u2026",
43003
43024
  "fontsSection.duplicateThisThemeToAdd": "Dupliquez ce th\xE8me pour ajouter des polices.",
43004
43025
  "fontsSection.duplicateToAddFonts": "Dupliquer pour ajouter des polices\u2026",
@@ -46617,6 +46638,11 @@ var require_de = __commonJS({
46617
46638
  "command:export.web": "Als Webcode exportieren\u2026",
46618
46639
  "command:export.webm": "Animation als WebM exportieren",
46619
46640
  "command:file.duplicate": "Datei duplizieren",
46641
+ "command:font.add": "Schriftart zur Datei hinzuf\xFCgen\u2026",
46642
+ "command:font.list": "Schriftarten in Datei auflisten",
46643
+ "command:font.remove": "Schriftart aus Datei entfernen",
46644
+ "command:font.teamAdd": "Team-Schriftart hinzuf\xFCgen\u2026",
46645
+ "command:font.teamList": "Team-Schriftarten auflisten",
46620
46646
  "command:generate.video": "Video generieren",
46621
46647
  "command:history.redo": "Wiederholen",
46622
46648
  "command:history.undo": "R\xFCckg\xE4ngig machen",
@@ -47671,6 +47697,7 @@ var require_de = __commonJS({
47671
47697
  "fontPicker.handwriting": "Handschrift",
47672
47698
  "fontPicker.light": "Leicht",
47673
47699
  "fontPicker.medium": "Mittel",
47700
+ "fontPicker.missingFont": "{family} ist hier nicht verf\xFCgbar, daher wird dieser Text in einer Ersatzschriftart dargestellt. Lade die Schriftartdatei hoch, um sie zu verwenden.",
47674
47701
  "fontPicker.monospace": "Monospace",
47675
47702
  "fontPicker.noFontsFound": "Keine Schriftarten gefunden",
47676
47703
  "fontPicker.regular": "Normal",
@@ -47678,10 +47705,11 @@ var require_de = __commonJS({
47678
47705
  "fontPicker.searchFonts": "Schriftarten suchen...",
47679
47706
  "fontPicker.semiBold": "Halbfett",
47680
47707
  "fontPicker.serif": "Serif",
47681
- "fontPicker.thatFileIsNotA": "Diese Datei ist keine TTF-, OTF-, WOFF- oder WOFF2-Schriftart.",
47708
+ "fontPicker.thatFileIsNotA": "Diese Datei ist keine TTF-, OTF-, TTC-, WOFF- oder WOFF2-Schriftart.",
47682
47709
  "fontPicker.thatFontFileIsToo": "Diese Schriftartdatei ist zu gro\xDF.",
47683
47710
  "fontPicker.thin": "D\xFCnn",
47684
47711
  "fontPicker.uploadFont": "Schriftart hochladen...",
47712
+ "fontPicker.uploadTeamFont": "Schriftart ins Team hochladen...",
47685
47713
  "fontsSection.addFont": "Schriftart hinzuf\xFCgen\u2026",
47686
47714
  "fontsSection.duplicateThisThemeToAdd": "Dupliziere dieses Thema, um Schriftarten hinzuzuf\xFCgen.",
47687
47715
  "fontsSection.duplicateToAddFonts": "Duplizieren, um Schriftarten hinzuzuf\xFCgen\u2026",
@@ -51300,6 +51328,11 @@ var require_it = __commonJS({
51300
51328
  "command:export.web": "Esporta come codice web\u2026",
51301
51329
  "command:export.webm": "Esporta animazione come WebM",
51302
51330
  "command:file.duplicate": "Duplica file",
51331
+ "command:font.add": "Aggiungi font al file\u2026",
51332
+ "command:font.list": "Elenca i font nel file",
51333
+ "command:font.remove": "Rimuovi font dal file",
51334
+ "command:font.teamAdd": "Aggiungi font del team\u2026",
51335
+ "command:font.teamList": "Elenca i font del team",
51303
51336
  "command:generate.video": "Genera video",
51304
51337
  "command:history.redo": "Ripeti",
51305
51338
  "command:history.undo": "Annulla",
@@ -52354,6 +52387,7 @@ var require_it = __commonJS({
52354
52387
  "fontPicker.handwriting": "Scrittura a mano",
52355
52388
  "fontPicker.light": "Leggero",
52356
52389
  "fontPicker.medium": "Medio",
52390
+ "fontPicker.missingFont": "{family} non \xE8 disponibile qui, quindi questo testo viene visualizzato con un font di riserva. Carica il file del font per usarlo.",
52357
52391
  "fontPicker.monospace": "Monospaziato",
52358
52392
  "fontPicker.noFontsFound": "Nessun font trovato",
52359
52393
  "fontPicker.regular": "Regolare",
@@ -52361,10 +52395,11 @@ var require_it = __commonJS({
52361
52395
  "fontPicker.searchFonts": "Cerca font...",
52362
52396
  "fontPicker.semiBold": "Semi grassetto",
52363
52397
  "fontPicker.serif": "Serif",
52364
- "fontPicker.thatFileIsNotA": "Quel file non \xE8 un font TTF, OTF, WOFF o WOFF2.",
52398
+ "fontPicker.thatFileIsNotA": "Quel file non \xE8 un font TTF, OTF, TTC, WOFF o WOFF2.",
52365
52399
  "fontPicker.thatFontFileIsToo": "Quel file font \xE8 troppo grande.",
52366
52400
  "fontPicker.thin": "Sottile",
52367
52401
  "fontPicker.uploadFont": "Carica font...",
52402
+ "fontPicker.uploadTeamFont": "Carica font nel team...",
52368
52403
  "fontsSection.addFont": "Aggiungi font\u2026",
52369
52404
  "fontsSection.duplicateThisThemeToAdd": "Duplica questo tema per aggiungere font.",
52370
52405
  "fontsSection.duplicateToAddFonts": "Duplica per aggiungere font\u2026",
@@ -55983,6 +56018,11 @@ var require_pt_BR = __commonJS({
55983
56018
  "command:export.web": "Exportar como c\xF3digo web\u2026",
55984
56019
  "command:export.webm": "Exportar anima\xE7\xE3o como WebM",
55985
56020
  "command:file.duplicate": "Duplicar arquivo",
56021
+ "command:font.add": "Adicionar fonte ao arquivo\u2026",
56022
+ "command:font.list": "Listar fontes no arquivo",
56023
+ "command:font.remove": "Remover fonte do arquivo",
56024
+ "command:font.teamAdd": "Adicionar fonte da equipe\u2026",
56025
+ "command:font.teamList": "Listar fontes da equipe",
55986
56026
  "command:generate.video": "Gerar v\xEDdeo",
55987
56027
  "command:history.redo": "Refazer",
55988
56028
  "command:history.undo": "Desfazer",
@@ -57037,6 +57077,7 @@ var require_pt_BR = __commonJS({
57037
57077
  "fontPicker.handwriting": "Manuscrita",
57038
57078
  "fontPicker.light": "Leve",
57039
57079
  "fontPicker.medium": "M\xE9dio",
57080
+ "fontPicker.missingFont": "{family} n\xE3o est\xE1 dispon\xEDvel aqui, ent\xE3o este texto ser\xE1 exibido em uma fonte substituta. Carregue o arquivo da fonte para us\xE1-la.",
57040
57081
  "fontPicker.monospace": "Monoespa\xE7ada",
57041
57082
  "fontPicker.noFontsFound": "Nenhuma fonte encontrada",
57042
57083
  "fontPicker.regular": "Regular",
@@ -57044,10 +57085,11 @@ var require_pt_BR = __commonJS({
57044
57085
  "fontPicker.searchFonts": "Pesquisar fontes...",
57045
57086
  "fontPicker.semiBold": "Semi Negrito",
57046
57087
  "fontPicker.serif": "Serifa",
57047
- "fontPicker.thatFileIsNotA": "Esse arquivo n\xE3o \xE9 uma fonte TTF, OTF, WOFF ou WOFF2.",
57088
+ "fontPicker.thatFileIsNotA": "Este arquivo n\xE3o \xE9 uma fonte TTF, OTF, TTC, WOFF ou WOFF2.",
57048
57089
  "fontPicker.thatFontFileIsToo": "Esse arquivo de fonte \xE9 muito grande.",
57049
57090
  "fontPicker.thin": "Fino",
57050
57091
  "fontPicker.uploadFont": "Carregar fonte...",
57092
+ "fontPicker.uploadTeamFont": "Carregar Fonte para a Equipe...",
57051
57093
  "fontsSection.addFont": "Adicionar fonte\u2026",
57052
57094
  "fontsSection.duplicateThisThemeToAdd": "Duplique este tema para adicionar fontes.",
57053
57095
  "fontsSection.duplicateToAddFonts": "Duplicar para adicionar fontes\u2026",
@@ -60666,6 +60708,11 @@ var require_ja = __commonJS({
60666
60708
  "command:export.web": "Web\u30B3\u30FC\u30C9\u3068\u3057\u3066\u30A8\u30AF\u30B9\u30DD\u30FC\u30C8\u2026",
60667
60709
  "command:export.webm": "\u30A2\u30CB\u30E1\u30FC\u30B7\u30E7\u30F3\u3092WebM\u3068\u3057\u3066\u30A8\u30AF\u30B9\u30DD\u30FC\u30C8",
60668
60710
  "command:file.duplicate": "\u30D5\u30A1\u30A4\u30EB\u3092\u8907\u88FD",
60711
+ "command:font.add": "\u30D5\u30A1\u30A4\u30EB\u306B\u30D5\u30A9\u30F3\u30C8\u3092\u8FFD\u52A0\u2026",
60712
+ "command:font.list": "\u30D5\u30A1\u30A4\u30EB\u5185\u306E\u30D5\u30A9\u30F3\u30C8\u3092\u4E00\u89A7\u8868\u793A",
60713
+ "command:font.remove": "\u30D5\u30A1\u30A4\u30EB\u304B\u3089\u30D5\u30A9\u30F3\u30C8\u3092\u524A\u9664",
60714
+ "command:font.teamAdd": "\u30C1\u30FC\u30E0\u30D5\u30A9\u30F3\u30C8\u3092\u8FFD\u52A0\u2026",
60715
+ "command:font.teamList": "\u30C1\u30FC\u30E0\u30D5\u30A9\u30F3\u30C8\u3092\u4E00\u89A7\u8868\u793A",
60669
60716
  "command:generate.video": "\u30D3\u30C7\u30AA\u3092\u751F\u6210",
60670
60717
  "command:history.redo": "\u3084\u308A\u76F4\u3057",
60671
60718
  "command:history.undo": "\u5143\u306B\u623B\u3059",
@@ -61720,6 +61767,7 @@ var require_ja = __commonJS({
61720
61767
  "fontPicker.handwriting": "\u624B\u66F8\u304D",
61721
61768
  "fontPicker.light": "\u7D30\u5B57",
61722
61769
  "fontPicker.medium": "\u4E2D\u5B57",
61770
+ "fontPicker.missingFont": "{family}\u306F\u3053\u3053\u3067\u306F\u5229\u7528\u3067\u304D\u306A\u3044\u305F\u3081\u3001\u3053\u306E\u30C6\u30AD\u30B9\u30C8\u306F\u4EE3\u66FF\u30D5\u30A9\u30F3\u30C8\u3067\u63CF\u753B\u3055\u308C\u307E\u3059\u3002\u4F7F\u7528\u3059\u308B\u306B\u306F\u30D5\u30A9\u30F3\u30C8\u30D5\u30A1\u30A4\u30EB\u3092\u30A2\u30C3\u30D7\u30ED\u30FC\u30C9\u3057\u3066\u304F\u3060\u3055\u3044\u3002",
61723
61771
  "fontPicker.monospace": "\u7B49\u5E45",
61724
61772
  "fontPicker.noFontsFound": "\u30D5\u30A9\u30F3\u30C8\u304C\u898B\u3064\u304B\u308A\u307E\u305B\u3093",
61725
61773
  "fontPicker.regular": "\u6A19\u6E96",
@@ -61727,10 +61775,11 @@ var require_ja = __commonJS({
61727
61775
  "fontPicker.searchFonts": "\u30D5\u30A9\u30F3\u30C8\u3092\u691C\u7D22...",
61728
61776
  "fontPicker.semiBold": "\u534A\u592A\u5B57",
61729
61777
  "fontPicker.serif": "\u30BB\u30EA\u30D5",
61730
- "fontPicker.thatFileIsNotA": "\u305D\u306E\u30D5\u30A1\u30A4\u30EB\u306FTTF\u3001OTF\u3001WOFF\u3001\u307E\u305F\u306FWOFF2\u30D5\u30A9\u30F3\u30C8\u3067\u306F\u3042\u308A\u307E\u305B\u3093\u3002",
61778
+ "fontPicker.thatFileIsNotA": "\u305D\u306E\u30D5\u30A1\u30A4\u30EB\u306FTTF\u3001OTF\u3001TTC\u3001WOFF\u3001\u307E\u305F\u306FWOFF2\u30D5\u30A9\u30F3\u30C8\u3067\u306F\u3042\u308A\u307E\u305B\u3093\u3002",
61731
61779
  "fontPicker.thatFontFileIsToo": "\u305D\u306E\u30D5\u30A9\u30F3\u30C8\u30D5\u30A1\u30A4\u30EB\u306F\u5927\u304D\u3059\u304E\u307E\u3059\u3002",
61732
61780
  "fontPicker.thin": "\u6975\u7D30",
61733
61781
  "fontPicker.uploadFont": "\u30D5\u30A9\u30F3\u30C8\u3092\u30A2\u30C3\u30D7\u30ED\u30FC\u30C9...",
61782
+ "fontPicker.uploadTeamFont": "\u30C1\u30FC\u30E0\u306B\u30D5\u30A9\u30F3\u30C8\u3092\u30A2\u30C3\u30D7\u30ED\u30FC\u30C9\u2026",
61734
61783
  "fontsSection.addFont": "\u30D5\u30A9\u30F3\u30C8\u3092\u8FFD\u52A0\u2026",
61735
61784
  "fontsSection.duplicateThisThemeToAdd": "\u30D5\u30A9\u30F3\u30C8\u3092\u8FFD\u52A0\u3059\u308B\u306B\u306F\u3001\u3053\u306E\u30C6\u30FC\u30DE\u3092\u8907\u88FD\u3057\u3066\u304F\u3060\u3055\u3044\u3002",
61736
61785
  "fontsSection.duplicateToAddFonts": "\u30D5\u30A9\u30F3\u30C8\u3092\u8FFD\u52A0\u3059\u308B\u305F\u3081\u306B\u8907\u88FD\u2026",
@@ -65349,6 +65398,11 @@ var require_ko = __commonJS({
65349
65398
  "command:export.web": "\uC6F9 \uCF54\uB4DC\uB85C \uB0B4\uBCF4\uB0B4\uAE30\u2026",
65350
65399
  "command:export.webm": "\uC560\uB2C8\uBA54\uC774\uC158\uC744 WebM\uC73C\uB85C \uB0B4\uBCF4\uB0B4\uAE30",
65351
65400
  "command:file.duplicate": "\uD30C\uC77C \uBCF5\uC81C",
65401
+ "command:font.add": "\uD30C\uC77C\uC5D0 \uAE00\uAF34 \uCD94\uAC00\u2026",
65402
+ "command:font.list": "\uD30C\uC77C\uC758 \uAE00\uAF34 \uBAA9\uB85D",
65403
+ "command:font.remove": "\uD30C\uC77C\uC5D0\uC11C \uAE00\uAF34 \uC81C\uAC70",
65404
+ "command:font.teamAdd": "\uD300 \uAE00\uAF34 \uCD94\uAC00\u2026",
65405
+ "command:font.teamList": "\uD300 \uAE00\uAF34 \uBAA9\uB85D",
65352
65406
  "command:generate.video": "\uBE44\uB514\uC624 \uC0DD\uC131",
65353
65407
  "command:history.redo": "\uB2E4\uC2DC \uC2E4\uD589",
65354
65408
  "command:history.undo": "\uC2E4\uD589 \uCDE8\uC18C",
@@ -66403,6 +66457,7 @@ var require_ko = __commonJS({
66403
66457
  "fontPicker.handwriting": "\uC190\uAE00\uC528",
66404
66458
  "fontPicker.light": "\uAC00\uB298\uAC8C",
66405
66459
  "fontPicker.medium": "\uC911\uAC04",
66460
+ "fontPicker.missingFont": "{family} \uAE00\uAF34\uC744 \uC0AC\uC6A9\uD560 \uC218 \uC5C6\uC5B4 \uB300\uCCB4 \uAE00\uAF34\uB85C \uD45C\uC2DC\uB429\uB2C8\uB2E4. \uC0AC\uC6A9\uD558\uB824\uBA74 \uAE00\uAF34 \uD30C\uC77C\uC744 \uC5C5\uB85C\uB4DC\uD558\uC138\uC694.",
66406
66461
  "fontPicker.monospace": "\uBAA8\uB178\uC2A4\uD398\uC774\uC2A4",
66407
66462
  "fontPicker.noFontsFound": "\uAE00\uAF34\uC744 \uCC3E\uC744 \uC218 \uC5C6\uC2B5\uB2C8\uB2E4.",
66408
66463
  "fontPicker.regular": "\uBCF4\uD1B5",
@@ -66410,10 +66465,11 @@ var require_ko = __commonJS({
66410
66465
  "fontPicker.searchFonts": "\uAE00\uAF34 \uAC80\uC0C9\u2026",
66411
66466
  "fontPicker.semiBold": "\uBC18\uAD75\uAC8C",
66412
66467
  "fontPicker.serif": "\uC138\uB9AC\uD504",
66413
- "fontPicker.thatFileIsNotA": "\uD574\uB2F9 \uD30C\uC77C\uC740 TTF, OTF, WOFF \uB610\uB294 WOFF2 \uAE00\uAF34\uC774 \uC544\uB2D9\uB2C8\uB2E4.",
66468
+ "fontPicker.thatFileIsNotA": "\uD574\uB2F9 \uD30C\uC77C\uC740 TTF, OTF, TTC, WOFF \uB610\uB294 WOFF2 \uAE00\uAF34\uC774 \uC544\uB2D9\uB2C8\uB2E4.",
66414
66469
  "fontPicker.thatFontFileIsToo": "\uD574\uB2F9 \uAE00\uAF34 \uD30C\uC77C\uC774 \uB108\uBB34 \uD07D\uB2C8\uB2E4.",
66415
66470
  "fontPicker.thin": "\uC587\uAC8C",
66416
66471
  "fontPicker.uploadFont": "\uAE00\uAF34 \uC5C5\uB85C\uB4DC\u2026",
66472
+ "fontPicker.uploadTeamFont": "\uD300\uC5D0 \uAE00\uAF34 \uC5C5\uB85C\uB4DC...",
66417
66473
  "fontsSection.addFont": "\uAE00\uAF34 \uCD94\uAC00\u2026",
66418
66474
  "fontsSection.duplicateThisThemeToAdd": "\uAE00\uAF34\uC744 \uCD94\uAC00\uD558\uB824\uBA74 \uC774 \uD14C\uB9C8\uB97C \uBCF5\uC81C\uD558\uC138\uC694.",
66419
66475
  "fontsSection.duplicateToAddFonts": "\uAE00\uAF34\uC744 \uCD94\uAC00\uD558\uB824\uBA74 \uBCF5\uC81C\u2026",
@@ -70032,6 +70088,11 @@ var require_zh_CN = __commonJS({
70032
70088
  "command:export.web": "\u5BFC\u51FA\u4E3A\u7F51\u9875\u4EE3\u7801\u2026",
70033
70089
  "command:export.webm": "\u5C06\u52A8\u753B\u5BFC\u51FA\u4E3A WebM",
70034
70090
  "command:file.duplicate": "\u590D\u5236\u6587\u4EF6",
70091
+ "command:font.add": "\u6DFB\u52A0\u5B57\u4F53\u5230\u6587\u4EF6\u2026",
70092
+ "command:font.list": "\u5217\u51FA\u6587\u4EF6\u4E2D\u7684\u5B57\u4F53",
70093
+ "command:font.remove": "\u4ECE\u6587\u4EF6\u4E2D\u79FB\u9664\u5B57\u4F53",
70094
+ "command:font.teamAdd": "\u6DFB\u52A0\u56E2\u961F\u5B57\u4F53\u2026",
70095
+ "command:font.teamList": "\u5217\u51FA\u56E2\u961F\u5B57\u4F53",
70035
70096
  "command:generate.video": "\u751F\u6210\u89C6\u9891",
70036
70097
  "command:history.redo": "\u91CD\u505A",
70037
70098
  "command:history.undo": "\u64A4\u9500",
@@ -71086,6 +71147,7 @@ var require_zh_CN = __commonJS({
71086
71147
  "fontPicker.handwriting": "\u624B\u5199",
71087
71148
  "fontPicker.light": "\u7EC6\u4F53",
71088
71149
  "fontPicker.medium": "\u4E2D\u7B49",
71150
+ "fontPicker.missingFont": "{family} \u5728\u6B64\u5904\u4E0D\u53EF\u7528\uFF0C\u56E0\u6B64\u6B64\u6587\u672C\u5C06\u4EE5\u5907\u7528\u5B57\u4F53\u663E\u793A\u3002\u8BF7\u4E0A\u4F20\u5B57\u4F53\u6587\u4EF6\u4EE5\u4F7F\u7528\u5B83\u3002",
71089
71151
  "fontPicker.monospace": "\u7B49\u5BBD",
71090
71152
  "fontPicker.noFontsFound": "\u672A\u627E\u5230\u5B57\u4F53",
71091
71153
  "fontPicker.regular": "\u5E38\u89C4",
@@ -71093,10 +71155,11 @@ var require_zh_CN = __commonJS({
71093
71155
  "fontPicker.searchFonts": "\u641C\u7D22\u5B57\u4F53...",
71094
71156
  "fontPicker.semiBold": "\u534A\u7C97\u4F53",
71095
71157
  "fontPicker.serif": "\u886C\u7EBF",
71096
- "fontPicker.thatFileIsNotA": "\u8BE5\u6587\u4EF6\u4E0D\u662F TTF\u3001OTF\u3001WOFF \u6216 WOFF2 \u5B57\u4F53\u3002",
71158
+ "fontPicker.thatFileIsNotA": "\u8BE5\u6587\u4EF6\u4E0D\u662F TTF\u3001OTF\u3001TTC\u3001WOFF \u6216 WOFF2 \u5B57\u4F53\u3002",
71097
71159
  "fontPicker.thatFontFileIsToo": "\u8BE5\u5B57\u4F53\u6587\u4EF6\u8FC7\u5927\u3002",
71098
71160
  "fontPicker.thin": "\u7EA4\u7EC6\u4F53",
71099
71161
  "fontPicker.uploadFont": "\u4E0A\u4F20\u5B57\u4F53...",
71162
+ "fontPicker.uploadTeamFont": "\u4E0A\u4F20\u5B57\u4F53\u5230\u56E2\u961F...",
71100
71163
  "fontsSection.addFont": "\u6DFB\u52A0\u5B57\u4F53\u2026",
71101
71164
  "fontsSection.duplicateThisThemeToAdd": "\u590D\u5236\u6B64\u4E3B\u9898\u4EE5\u6DFB\u52A0\u5B57\u4F53\u3002",
71102
71165
  "fontsSection.duplicateToAddFonts": "\u590D\u5236\u4EE5\u6DFB\u52A0\u5B57\u4F53\u2026",
@@ -74715,6 +74778,11 @@ var require_zh_TW = __commonJS({
74715
74778
  "command:export.web": "\u532F\u51FA\u70BA\u7DB2\u9801\u7A0B\u5F0F\u78BC\u2026",
74716
74779
  "command:export.webm": "\u5C07\u52D5\u756B\u532F\u51FA\u70BA WebM",
74717
74780
  "command:file.duplicate": "\u8907\u88FD\u6A94\u6848",
74781
+ "command:font.add": "\u65B0\u589E\u5B57\u9AD4\u81F3\u6A94\u6848\u2026",
74782
+ "command:font.list": "\u5217\u51FA\u6A94\u6848\u4E2D\u7684\u5B57\u9AD4",
74783
+ "command:font.remove": "\u5F9E\u6A94\u6848\u4E2D\u79FB\u9664\u5B57\u9AD4",
74784
+ "command:font.teamAdd": "\u65B0\u589E\u5718\u968A\u5B57\u9AD4\u2026",
74785
+ "command:font.teamList": "\u5217\u51FA\u5718\u968A\u5B57\u9AD4",
74718
74786
  "command:generate.video": "\u7522\u751F\u5F71\u7247",
74719
74787
  "command:history.redo": "\u91CD\u505A",
74720
74788
  "command:history.undo": "\u5FA9\u539F",
@@ -75769,6 +75837,7 @@ var require_zh_TW = __commonJS({
75769
75837
  "fontPicker.handwriting": "\u624B\u5BEB",
75770
75838
  "fontPicker.light": "\u7D30\u9AD4",
75771
75839
  "fontPicker.medium": "\u4E2D\u7B49",
75840
+ "fontPicker.missingFont": "{family} \u5728\u6B64\u8655\u4E0D\u53EF\u7528\uFF0C\u56E0\u6B64\u6B64\u6587\u5B57\u5C07\u4EE5\u5099\u7528\u5B57\u9AD4\u7E6A\u88FD\u3002\u8ACB\u4E0A\u50B3\u5B57\u9AD4\u6A94\u6848\u4EE5\u4F7F\u7528\u5B83\u3002",
75772
75841
  "fontPicker.monospace": "\u7B49\u5BEC\u5B57\u9AD4",
75773
75842
  "fontPicker.noFontsFound": "\u627E\u4E0D\u5230\u5B57\u9AD4",
75774
75843
  "fontPicker.regular": "\u6A19\u6E96",
@@ -75776,10 +75845,11 @@ var require_zh_TW = __commonJS({
75776
75845
  "fontPicker.searchFonts": "\u641C\u5C0B\u5B57\u9AD4\u2026",
75777
75846
  "fontPicker.semiBold": "\u534A\u7C97\u9AD4",
75778
75847
  "fontPicker.serif": "\u896F\u7DDA\u5B57\u9AD4",
75779
- "fontPicker.thatFileIsNotA": "\u8A72\u6A94\u6848\u4E0D\u662F TTF\u3001OTF\u3001WOFF \u6216 WOFF2 \u5B57\u9AD4\u3002",
75848
+ "fontPicker.thatFileIsNotA": "\u8A72\u6A94\u6848\u4E0D\u662F TTF\u3001OTF\u3001TTC\u3001WOFF \u6216 WOFF2 \u5B57\u9AD4\u3002",
75780
75849
  "fontPicker.thatFontFileIsToo": "\u8A72\u5B57\u9AD4\u6A94\u6848\u592A\u5927\u3002",
75781
75850
  "fontPicker.thin": "\u6975\u7D30\u9AD4",
75782
75851
  "fontPicker.uploadFont": "\u4E0A\u50B3\u5B57\u9AD4\u2026",
75852
+ "fontPicker.uploadTeamFont": "\u4E0A\u50B3\u5B57\u9AD4\u81F3\u5718\u968A...",
75783
75853
  "fontsSection.addFont": "\u65B0\u589E\u5B57\u9AD4\u2026",
75784
75854
  "fontsSection.duplicateThisThemeToAdd": "\u8907\u88FD\u6B64\u4E3B\u984C\u4EE5\u65B0\u589E\u5B57\u9AD4\u3002",
75785
75855
  "fontsSection.duplicateToAddFonts": "\u8907\u88FD\u4EE5\u65B0\u589E\u5B57\u9AD4\u2026",
@@ -79398,6 +79468,11 @@ var require_ru = __commonJS({
79398
79468
  "command:export.web": "\u042D\u043A\u0441\u043F\u043E\u0440\u0442\u0438\u0440\u043E\u0432\u0430\u0442\u044C \u043A\u0430\u043A \u0432\u0435\u0431-\u043A\u043E\u0434\u2026",
79399
79469
  "command:export.webm": "\u042D\u043A\u0441\u043F\u043E\u0440\u0442\u0438\u0440\u043E\u0432\u0430\u0442\u044C \u0430\u043D\u0438\u043C\u0430\u0446\u0438\u044E \u043A\u0430\u043A WebM",
79400
79470
  "command:file.duplicate": "\u0414\u0443\u0431\u043B\u0438\u0440\u043E\u0432\u0430\u0442\u044C \u0444\u0430\u0439\u043B",
79471
+ "command:font.add": "\u0414\u043E\u0431\u0430\u0432\u0438\u0442\u044C \u0448\u0440\u0438\u0444\u0442 \u0432 \u0444\u0430\u0439\u043B\u2026",
79472
+ "command:font.list": "\u0421\u043F\u0438\u0441\u043E\u043A \u0448\u0440\u0438\u0444\u0442\u043E\u0432 \u0432 \u0444\u0430\u0439\u043B\u0435",
79473
+ "command:font.remove": "\u0423\u0434\u0430\u043B\u0438\u0442\u044C \u0448\u0440\u0438\u0444\u0442 \u0438\u0437 \u0444\u0430\u0439\u043B\u0430",
79474
+ "command:font.teamAdd": "\u0414\u043E\u0431\u0430\u0432\u0438\u0442\u044C \u043A\u043E\u043C\u0430\u043D\u0434\u043D\u044B\u0439 \u0448\u0440\u0438\u0444\u0442\u2026",
79475
+ "command:font.teamList": "\u0421\u043F\u0438\u0441\u043E\u043A \u043A\u043E\u043C\u0430\u043D\u0434\u043D\u044B\u0445 \u0448\u0440\u0438\u0444\u0442\u043E\u0432",
79401
79476
  "command:generate.video": "\u0421\u0433\u0435\u043D\u0435\u0440\u0438\u0440\u043E\u0432\u0430\u0442\u044C \u0432\u0438\u0434\u0435\u043E",
79402
79477
  "command:history.redo": "\u041F\u043E\u0432\u0442\u043E\u0440\u0438\u0442\u044C",
79403
79478
  "command:history.undo": "\u041E\u0442\u043C\u0435\u043D\u0438\u0442\u044C",
@@ -80452,6 +80527,7 @@ var require_ru = __commonJS({
80452
80527
  "fontPicker.handwriting": "\u0420\u0443\u043A\u043E\u043F\u0438\u0441\u043D\u044B\u0439",
80453
80528
  "fontPicker.light": "\u0421\u0432\u0435\u0442\u043B\u044B\u0439",
80454
80529
  "fontPicker.medium": "\u0421\u0440\u0435\u0434\u043D\u0438\u0439",
80530
+ "fontPicker.missingFont": "{family} \u043D\u0435\u0434\u043E\u0441\u0442\u0443\u043F\u0435\u043D \u0437\u0434\u0435\u0441\u044C, \u043F\u043E\u044D\u0442\u043E\u043C\u0443 \u044D\u0442\u043E\u0442 \u0442\u0435\u043A\u0441\u0442 \u043E\u0442\u043E\u0431\u0440\u0430\u0436\u0430\u0435\u0442\u0441\u044F \u0437\u0430\u043F\u0430\u0441\u043D\u044B\u043C \u0448\u0440\u0438\u0444\u0442\u043E\u043C. \u0417\u0430\u0433\u0440\u0443\u0437\u0438\u0442\u0435 \u0444\u0430\u0439\u043B \u0448\u0440\u0438\u0444\u0442\u0430, \u0447\u0442\u043E\u0431\u044B \u0438\u0441\u043F\u043E\u043B\u044C\u0437\u043E\u0432\u0430\u0442\u044C \u0435\u0433\u043E.",
80455
80531
  "fontPicker.monospace": "\u041C\u043E\u043D\u043E\u0448\u0438\u0440\u0438\u043D\u043D\u044B\u0439",
80456
80532
  "fontPicker.noFontsFound": "\u0428\u0440\u0438\u0444\u0442\u044B \u043D\u0435 \u043D\u0430\u0439\u0434\u0435\u043D\u044B",
80457
80533
  "fontPicker.regular": "\u041E\u0431\u044B\u0447\u043D\u044B\u0439",
@@ -80459,10 +80535,11 @@ var require_ru = __commonJS({
80459
80535
  "fontPicker.searchFonts": "\u041F\u043E\u0438\u0441\u043A \u0448\u0440\u0438\u0444\u0442\u043E\u0432\u2026",
80460
80536
  "fontPicker.semiBold": "\u041F\u043E\u043B\u0443\u0436\u0438\u0440\u043D\u044B\u0439",
80461
80537
  "fontPicker.serif": "\u0421 \u0437\u0430\u0441\u0435\u0447\u043A\u0430\u043C\u0438",
80462
- "fontPicker.thatFileIsNotA": "\u042D\u0442\u043E\u0442 \u0444\u0430\u0439\u043B \u043D\u0435 \u044F\u0432\u043B\u044F\u0435\u0442\u0441\u044F \u0448\u0440\u0438\u0444\u0442\u043E\u043C TTF, OTF, WOFF \u0438\u043B\u0438 WOFF2.",
80538
+ "fontPicker.thatFileIsNotA": "\u042D\u0442\u043E\u0442 \u0444\u0430\u0439\u043B \u043D\u0435 \u044F\u0432\u043B\u044F\u0435\u0442\u0441\u044F \u0448\u0440\u0438\u0444\u0442\u043E\u043C TTF, OTF, TTC, WOFF \u0438\u043B\u0438 WOFF2.",
80463
80539
  "fontPicker.thatFontFileIsToo": "\u042D\u0442\u043E\u0442 \u0444\u0430\u0439\u043B \u0448\u0440\u0438\u0444\u0442\u0430 \u0441\u043B\u0438\u0448\u043A\u043E\u043C \u0431\u043E\u043B\u044C\u0448\u043E\u0439.",
80464
80540
  "fontPicker.thin": "\u0422\u043E\u043D\u043A\u0438\u0439",
80465
80541
  "fontPicker.uploadFont": "\u0417\u0430\u0433\u0440\u0443\u0437\u0438\u0442\u044C \u0448\u0440\u0438\u0444\u0442\u2026",
80542
+ "fontPicker.uploadTeamFont": "\u0417\u0430\u0433\u0440\u0443\u0437\u0438\u0442\u044C \u0448\u0440\u0438\u0444\u0442 \u0432 \u043A\u043E\u043C\u0430\u043D\u0434\u0443...",
80466
80543
  "fontsSection.addFont": "\u0414\u043E\u0431\u0430\u0432\u0438\u0442\u044C \u0448\u0440\u0438\u0444\u0442\u2026",
80467
80544
  "fontsSection.duplicateThisThemeToAdd": "\u0414\u0443\u0431\u043B\u0438\u0440\u0443\u0439\u0442\u0435 \u044D\u0442\u0443 \u0442\u0435\u043C\u0443, \u0447\u0442\u043E\u0431\u044B \u0434\u043E\u0431\u0430\u0432\u0438\u0442\u044C \u0448\u0440\u0438\u0444\u0442\u044B.",
80468
80545
  "fontsSection.duplicateToAddFonts": "\u0414\u0443\u0431\u043B\u0438\u0440\u043E\u0432\u0430\u0442\u044C, \u0447\u0442\u043E\u0431\u044B \u0434\u043E\u0431\u0430\u0432\u0438\u0442\u044C \u0448\u0440\u0438\u0444\u0442\u044B\u2026",
@@ -84081,6 +84158,11 @@ var require_ar = __commonJS({
84081
84158
  "command:export.web": "\u062A\u0635\u062F\u064A\u0631 \u0643\u0631\u0645\u0632 \u0648\u064A\u0628\u2026",
84082
84159
  "command:export.webm": "\u062A\u0635\u062F\u064A\u0631 \u0627\u0644\u0631\u0633\u0648\u0645 \u0627\u0644\u0645\u062A\u062D\u0631\u0643\u0629 \u0643\u0640 WebM",
84083
84160
  "command:file.duplicate": "\u062A\u0643\u0631\u0627\u0631 \u0627\u0644\u0645\u0644\u0641",
84161
+ "command:font.add": "\u0625\u0636\u0627\u0641\u0629 \u062E\u0637 \u0625\u0644\u0649 \u0627\u0644\u0645\u0644\u0641\u2026",
84162
+ "command:font.list": "\u0633\u0631\u062F \u0627\u0644\u062E\u0637\u0648\u0637 \u0641\u064A \u0627\u0644\u0645\u0644\u0641",
84163
+ "command:font.remove": "\u0625\u0632\u0627\u0644\u0629 \u0627\u0644\u062E\u0637 \u0645\u0646 \u0627\u0644\u0645\u0644\u0641",
84164
+ "command:font.teamAdd": "\u0625\u0636\u0627\u0641\u0629 \u062E\u0637 \u0627\u0644\u0641\u0631\u064A\u0642\u2026",
84165
+ "command:font.teamList": "\u0633\u0631\u062F \u062E\u0637\u0648\u0637 \u0627\u0644\u0641\u0631\u064A\u0642",
84084
84166
  "command:generate.video": "\u0625\u0646\u0634\u0627\u0621 \u0641\u064A\u062F\u064A\u0648",
84085
84167
  "command:history.redo": "\u0625\u0639\u0627\u062F\u0629",
84086
84168
  "command:history.undo": "\u062A\u0631\u0627\u062C\u0639",
@@ -85135,6 +85217,7 @@ var require_ar = __commonJS({
85135
85217
  "fontPicker.handwriting": "\u062E\u0637 \u0627\u0644\u064A\u062F",
85136
85218
  "fontPicker.light": "\u062E\u0641\u064A\u0641",
85137
85219
  "fontPicker.medium": "\u0645\u062A\u0648\u0633\u0637",
85220
+ "fontPicker.missingFont": "{family} \u063A\u064A\u0631 \u0645\u062A\u0648\u0641\u0631 \u0647\u0646\u0627\u060C \u0644\u0630\u0627 \u064A\u062A\u0645 \u0639\u0631\u0636 \u0647\u0630\u0627 \u0627\u0644\u0646\u0635 \u0628\u062E\u0637 \u0627\u062D\u062A\u064A\u0627\u0637\u064A. \u062D\u0645\u0651\u0644 \u0645\u0644\u0641 \u0627\u0644\u062E\u0637 \u0644\u0627\u0633\u062A\u062E\u062F\u0627\u0645\u0647.",
85138
85221
  "fontPicker.monospace": "\u0623\u062D\u0627\u062F\u064A \u0627\u0644\u0645\u0633\u0627\u0641\u0629",
85139
85222
  "fontPicker.noFontsFound": "\u0644\u0645 \u064A\u062A\u0645 \u0627\u0644\u0639\u062B\u0648\u0631 \u0639\u0644\u0649 \u062E\u0637\u0648\u0637",
85140
85223
  "fontPicker.regular": "\u0639\u0627\u062F\u064A",
@@ -85142,10 +85225,11 @@ var require_ar = __commonJS({
85142
85225
  "fontPicker.searchFonts": "\u0627\u0644\u0628\u062D\u062B \u0639\u0646 \u062E\u0637\u0648\u0637...",
85143
85226
  "fontPicker.semiBold": "\u0634\u0628\u0647 \u0639\u0631\u064A\u0636",
85144
85227
  "fontPicker.serif": "\u0630\u0648 \u0630\u064A\u0644",
85145
- "fontPicker.thatFileIsNotA": "\u0647\u0630\u0627 \u0627\u0644\u0645\u0644\u0641 \u0644\u064A\u0633 \u062E\u0637\u064B\u0627 \u0645\u0646 \u0646\u0648\u0639 TTF \u0623\u0648 OTF \u0623\u0648 WOFF \u0623\u0648 WOFF2.",
85228
+ "fontPicker.thatFileIsNotA": "\u0647\u0630\u0627 \u0627\u0644\u0645\u0644\u0641 \u0644\u064A\u0633 \u062E\u0637\u064B\u0627 \u0645\u0646 \u0646\u0648\u0639 TTF \u0623\u0648 OTF \u0623\u0648 TTC \u0623\u0648 WOFF \u0623\u0648 WOFF2.",
85146
85229
  "fontPicker.thatFontFileIsToo": "\u0645\u0644\u0641 \u0627\u0644\u062E\u0637 \u0647\u0630\u0627 \u0643\u0628\u064A\u0631 \u062C\u062F\u064B\u0627.",
85147
85230
  "fontPicker.thin": "\u0631\u0641\u064A\u0639",
85148
85231
  "fontPicker.uploadFont": "\u0631\u0641\u0639 \u062E\u0637...",
85232
+ "fontPicker.uploadTeamFont": "\u062A\u062D\u0645\u064A\u0644 \u062E\u0637 \u0625\u0644\u0649 \u0627\u0644\u0641\u0631\u064A\u0642...",
85149
85233
  "fontsSection.addFont": "\u0625\u0636\u0627\u0641\u0629 \u062E\u0637\u2026",
85150
85234
  "fontsSection.duplicateThisThemeToAdd": "\u0627\u0646\u0633\u062E \u0647\u0630\u0627 \u0627\u0644\u0645\u0638\u0647\u0631 \u0644\u0625\u0636\u0627\u0641\u0629 \u062E\u0637\u0648\u0637.",
85151
85235
  "fontsSection.duplicateToAddFonts": "\u0646\u0633\u062E \u0644\u0625\u0636\u0627\u0641\u0629 \u062E\u0637\u0648\u0637\u2026",
@@ -88764,6 +88848,11 @@ var require_hi = __commonJS({
88764
88848
  "command:export.web": "\u0935\u0947\u092C \u0915\u094B\u0921 \u0915\u0947 \u0930\u0942\u092A \u092E\u0947\u0902 \u0928\u093F\u0930\u094D\u092F\u093E\u0924 \u0915\u0930\u0947\u0902\u2026",
88765
88849
  "command:export.webm": "\u090F\u0928\u093F\u092E\u0947\u0936\u0928 \u0915\u094B WebM \u0915\u0947 \u0930\u0942\u092A \u092E\u0947\u0902 \u0928\u093F\u0930\u094D\u092F\u093E\u0924 \u0915\u0930\u0947\u0902",
88766
88850
  "command:file.duplicate": "\u092B\u093C\u093E\u0907\u0932 \u0921\u0941\u092A\u094D\u0932\u093F\u0915\u0947\u091F \u0915\u0930\u0947\u0902",
88851
+ "command:font.add": "\u092B\u093C\u093E\u0907\u0932 \u092E\u0947\u0902 \u092B\u093C\u0949\u0928\u094D\u091F \u091C\u094B\u0921\u093C\u0947\u0902\u2026",
88852
+ "command:font.list": "\u092B\u093C\u093E\u0907\u0932 \u092E\u0947\u0902 \u092B\u093C\u0949\u0928\u094D\u091F \u0938\u0942\u091A\u0940\u092C\u0926\u094D\u0927 \u0915\u0930\u0947\u0902",
88853
+ "command:font.remove": "\u092B\u093C\u093E\u0907\u0932 \u0938\u0947 \u092B\u093C\u0949\u0928\u094D\u091F \u0939\u091F\u093E\u090F\u0901",
88854
+ "command:font.teamAdd": "\u091F\u0940\u092E \u092B\u093C\u0949\u0928\u094D\u091F \u091C\u094B\u0921\u093C\u0947\u0902\u2026",
88855
+ "command:font.teamList": "\u091F\u0940\u092E \u092B\u093C\u0949\u0928\u094D\u091F \u0938\u0942\u091A\u0940\u092C\u0926\u094D\u0927 \u0915\u0930\u0947\u0902",
88767
88856
  "command:generate.video": "\u0935\u0940\u0921\u093F\u092F\u094B \u091C\u0928\u0930\u0947\u091F \u0915\u0930\u0947\u0902",
88768
88857
  "command:history.redo": "\u092B\u093F\u0930 \u0938\u0947 \u0915\u0930\u0947\u0902",
88769
88858
  "command:history.undo": "\u092A\u0942\u0930\u094D\u0935\u0935\u0924 \u0915\u0930\u0947\u0902",
@@ -89818,6 +89907,7 @@ var require_hi = __commonJS({
89818
89907
  "fontPicker.handwriting": "\u0939\u0938\u094D\u0924\u0932\u0947\u0916\u0928",
89819
89908
  "fontPicker.light": "\u0932\u093E\u0907\u091F",
89820
89909
  "fontPicker.medium": "\u092E\u0940\u0921\u093F\u092F\u092E",
89910
+ "fontPicker.missingFont": "{family} \u092F\u0939\u093E\u0901 \u0909\u092A\u0932\u092C\u094D\u0927 \u0928\u0939\u0940\u0902 \u0939\u0948, \u0907\u0938\u0932\u093F\u090F \u092F\u0939 \u091F\u0947\u0915\u094D\u0938\u094D\u091F \u090F\u0915 \u092B\u093C\u0949\u0932\u092C\u0948\u0915 \u092B\u093C\u0949\u0928\u094D\u091F \u092E\u0947\u0902 \u0916\u0940\u0902\u091A\u093E \u0917\u092F\u093E \u0939\u0948\u0964 \u0907\u0938\u0915\u093E \u0909\u092A\u092F\u094B\u0917 \u0915\u0930\u0928\u0947 \u0915\u0947 \u0932\u093F\u090F \u092B\u093C\u0949\u0928\u094D\u091F \u092B\u093C\u093E\u0907\u0932 \u0905\u092A\u0932\u094B\u0921 \u0915\u0930\u0947\u0902\u0964",
89821
89911
  "fontPicker.monospace": "\u092E\u094B\u0928\u094B\u0938\u094D\u092A\u0947\u0938",
89822
89912
  "fontPicker.noFontsFound": "\u0915\u094B\u0908 \u092B\u093C\u0949\u0928\u094D\u091F \u0928\u0939\u0940\u0902 \u092E\u093F\u0932\u093E",
89823
89913
  "fontPicker.regular": "\u0930\u0947\u0917\u0941\u0932\u0930",
@@ -89825,10 +89915,11 @@ var require_hi = __commonJS({
89825
89915
  "fontPicker.searchFonts": "\u092B\u093C\u0949\u0928\u094D\u091F \u0916\u094B\u091C\u0947\u0902...",
89826
89916
  "fontPicker.semiBold": "\u0938\u0947\u092E\u0940 \u092C\u094B\u0932\u094D\u0921",
89827
89917
  "fontPicker.serif": "\u0938\u0947\u0930\u093F\u092B\u093C",
89828
- "fontPicker.thatFileIsNotA": "\u0935\u0939 \u092B\u093C\u093E\u0907\u0932 TTF, OTF, WOFF \u092F\u093E WOFF2 \u092B\u093C\u0949\u0928\u094D\u091F \u0928\u0939\u0940\u0902 \u0939\u0948\u0964",
89918
+ "fontPicker.thatFileIsNotA": "\u0935\u0939 \u092B\u093C\u093E\u0907\u0932 TTF, OTF, TTC, WOFF \u092F\u093E WOFF2 \u092B\u093C\u0949\u0928\u094D\u091F \u0928\u0939\u0940\u0902 \u0939\u0948\u0964",
89829
89919
  "fontPicker.thatFontFileIsToo": "\u0935\u0939 \u092B\u093C\u0949\u0928\u094D\u091F \u092B\u093C\u093E\u0907\u0932 \u092C\u0939\u0941\u0924 \u092C\u0921\u093C\u0940 \u0939\u0948\u0964",
89830
89920
  "fontPicker.thin": "\u0925\u093F\u0928",
89831
89921
  "fontPicker.uploadFont": "\u092B\u093C\u0949\u0928\u094D\u091F \u0905\u092A\u0932\u094B\u0921 \u0915\u0930\u0947\u0902...",
89922
+ "fontPicker.uploadTeamFont": "\u091F\u0940\u092E \u092E\u0947\u0902 \u092B\u093C\u0949\u0928\u094D\u091F \u0905\u092A\u0932\u094B\u0921 \u0915\u0930\u0947\u0902...",
89832
89923
  "fontsSection.addFont": "\u092B\u093C\u0949\u0928\u094D\u091F \u091C\u094B\u0921\u093C\u0947\u0902\u2026",
89833
89924
  "fontsSection.duplicateThisThemeToAdd": "\u092B\u093C\u0949\u0928\u094D\u091F \u091C\u094B\u0921\u093C\u0928\u0947 \u0915\u0947 \u0932\u093F\u090F \u0907\u0938 \u0925\u0940\u092E \u0915\u094B \u0921\u0941\u092A\u094D\u0932\u093F\u0915\u0947\u091F \u0915\u0930\u0947\u0902\u0964",
89834
89925
  "fontsSection.duplicateToAddFonts": "\u092B\u093C\u0949\u0928\u094D\u091F \u091C\u094B\u0921\u093C\u0928\u0947 \u0915\u0947 \u0932\u093F\u090F \u0921\u0941\u092A\u094D\u0932\u093F\u0915\u0947\u091F \u0915\u0930\u0947\u0902\u2026",
@@ -93119,23 +93210,23 @@ function source(key5) {
93119
93210
  return SOURCE_CATALOG[key5];
93120
93211
  }
93121
93212
  function formatter(key5, fallback2) {
93122
- const cacheKey = `${current}\0${key5}`;
93123
- const hit = formats.get(cacheKey);
93213
+ const cacheKey2 = `${current}\0${key5}`;
93214
+ const hit = formats.get(cacheKey2);
93124
93215
  if (hit) return hit;
93125
93216
  const info2 = localeInfo(current);
93126
- const english = source(key5) ?? fallback2;
93127
- if (english === void 0) return null;
93128
- let message = TRANSLATIONS[current]?.[key5] ?? english;
93217
+ const english2 = source(key5) ?? fallback2;
93218
+ if (english2 === void 0) return null;
93219
+ let message = TRANSLATIONS[current]?.[key5] ?? english2;
93129
93220
  if (info2.pseudo) {
93130
- let ast = asts.get(english);
93221
+ let ast = asts.get(english2);
93131
93222
  if (!ast) {
93132
- ast = parse6(english, { ignoreTag: true });
93133
- asts.set(english, ast);
93223
+ ast = parse6(english2, { ignoreTag: true });
93224
+ asts.set(english2, ast);
93134
93225
  }
93135
93226
  message = pseudoAst(ast, info2.pseudo);
93136
93227
  }
93137
93228
  const f2 = new intl_messageformat_default(message, intlLocale(), void 0, { ignoreTag: true });
93138
- formats.set(cacheKey, f2);
93229
+ formats.set(cacheKey2, f2);
93139
93230
  return f2;
93140
93231
  }
93141
93232
  function run(key5, values3, fallback2) {
@@ -99670,8 +99761,8 @@ function clockOf(nodes, inst, elapsed, run4) {
99670
99761
  if (!comp) return null;
99671
99762
  if (run4?.scrub !== void 0) return { comp, ct: run4.scrub, live: !!run4.gliding || !!run4.from };
99672
99763
  const m = playbackOf(nodes, inst, comp);
99673
- const started7 = startedAt(m, elapsed, run4);
99674
- return { comp, ct: instanceTime(started7, m), live: playbackLive(started7, m) || !!run4?.from };
99764
+ const started8 = startedAt(m, elapsed, run4);
99765
+ return { comp, ct: instanceTime(started8, m), live: playbackLive(started8, m) || !!run4?.from };
99675
99766
  }
99676
99767
  function poseInstance(w, vid, inst, elapsed, depth2, clock2 = clockOf(w.nodes, inst, elapsed, w.runtime.get(vid))) {
99677
99768
  const { nodes } = w;
@@ -101762,15 +101853,15 @@ var require_tiny_inflate = __commonJS({
101762
101853
  d.bitcount += 8;
101763
101854
  }
101764
101855
  var sum = 0, cur = 0, len3 = 0;
101765
- var tag = d.tag;
101856
+ var tag2 = d.tag;
101766
101857
  do {
101767
- cur = 2 * cur + (tag & 1);
101768
- tag >>>= 1;
101858
+ cur = 2 * cur + (tag2 & 1);
101859
+ tag2 >>>= 1;
101769
101860
  ++len3;
101770
101861
  sum += t3.table[len3];
101771
101862
  cur -= t3.table[len3];
101772
101863
  } while (cur >= 0);
101773
- d.tag = tag;
101864
+ d.tag = tag2;
101774
101865
  d.bitcount -= len3;
101775
101866
  return t3.trans[sum + cur];
101776
101867
  }
@@ -102099,9 +102190,9 @@ var require_dfa = __commonJS({
102099
102190
  */
102100
102191
  apply(str4, actions) {
102101
102192
  for (var [start2, end, tags] of this.match(str4)) {
102102
- for (var tag of tags) {
102103
- if (typeof actions[tag] === "function") {
102104
- actions[tag](start2, end, str4.slice(start2, end + 1));
102193
+ for (var tag2 of tags) {
102194
+ if (typeof actions[tag2] === "function") {
102195
+ actions[tag2](start2, end, str4.slice(start2, end + 1));
102105
102196
  }
102106
102197
  }
102107
102198
  }
@@ -228582,27 +228673,27 @@ function $12727730ddfc8bfe$export$d02631cccf789723(index2, end) {
228582
228673
  while (index2 < end) range3.push(index2++);
228583
228674
  return range3;
228584
228675
  }
228585
- function $12727730ddfc8bfe$export$94fdf11bafc8de6b(base644) {
228586
- let bufferLength = base644.length * 0.75;
228587
- if (base644[base644.length - 1] === "=") {
228676
+ function $12727730ddfc8bfe$export$94fdf11bafc8de6b(base645) {
228677
+ let bufferLength = base645.length * 0.75;
228678
+ if (base645[base645.length - 1] === "=") {
228588
228679
  bufferLength--;
228589
- if (base644[base644.length - 2] === "=") bufferLength--;
228680
+ if (base645[base645.length - 2] === "=") bufferLength--;
228590
228681
  }
228591
228682
  let bytes2 = new Uint8Array(bufferLength);
228592
228683
  let p2 = 0;
228593
- for (let i2 = 0, len3 = base644.length; i2 < len3; i2 += 4) {
228594
- let encoded1 = $12727730ddfc8bfe$var$LOOKUP[base644.charCodeAt(i2)];
228595
- let encoded2 = $12727730ddfc8bfe$var$LOOKUP[base644.charCodeAt(i2 + 1)];
228596
- let encoded3 = $12727730ddfc8bfe$var$LOOKUP[base644.charCodeAt(i2 + 2)];
228597
- let encoded4 = $12727730ddfc8bfe$var$LOOKUP[base644.charCodeAt(i2 + 3)];
228684
+ for (let i2 = 0, len3 = base645.length; i2 < len3; i2 += 4) {
228685
+ let encoded1 = $12727730ddfc8bfe$var$LOOKUP[base645.charCodeAt(i2)];
228686
+ let encoded2 = $12727730ddfc8bfe$var$LOOKUP[base645.charCodeAt(i2 + 1)];
228687
+ let encoded3 = $12727730ddfc8bfe$var$LOOKUP[base645.charCodeAt(i2 + 2)];
228688
+ let encoded4 = $12727730ddfc8bfe$var$LOOKUP[base645.charCodeAt(i2 + 3)];
228598
228689
  bytes2[p2++] = encoded1 << 2 | encoded2 >> 4;
228599
228690
  bytes2[p2++] = (encoded2 & 15) << 4 | encoded3 >> 2;
228600
228691
  bytes2[p2++] = (encoded3 & 3) << 6 | encoded4 & 63;
228601
228692
  }
228602
228693
  return bytes2;
228603
228694
  }
228604
- function $130d1a642ebcd2b7$export$ce50e82f12a827a4(tag) {
228605
- return $130d1a642ebcd2b7$var$OPENTYPE_SCRIPTS[tag];
228695
+ function $130d1a642ebcd2b7$export$ce50e82f12a827a4(tag2) {
228696
+ return $130d1a642ebcd2b7$var$OPENTYPE_SCRIPTS[tag2];
228606
228697
  }
228607
228698
  function $130d1a642ebcd2b7$export$e5cb25e204fb8450(string4) {
228608
228699
  let len3 = string4.length;
@@ -234358,13 +234449,13 @@ var init_module2 = __esm({
234358
234449
  $816c07a04b6dba87$var$Directory.preEncode = function() {
234359
234450
  if (!Array.isArray(this.tables)) {
234360
234451
  let tables = [];
234361
- for (let tag in this.tables) {
234362
- let table3 = this.tables[tag];
234452
+ for (let tag2 in this.tables) {
234453
+ let table3 = this.tables[tag2];
234363
234454
  if (table3) tables.push({
234364
- tag,
234455
+ tag: tag2,
234365
234456
  checkSum: 0,
234366
- offset: new VoidPointer((0, $c3395722bea751e2$export$2e2bcd8739ae039)[tag], table3),
234367
- length: (0, $c3395722bea751e2$export$2e2bcd8739ae039)[tag].size(table3)
234457
+ offset: new VoidPointer((0, $c3395722bea751e2$export$2e2bcd8739ae039)[tag2], table3),
234458
+ length: (0, $c3395722bea751e2$export$2e2bcd8739ae039)[tag2].size(table3)
234368
234459
  });
234369
234460
  }
234370
234461
  this.tables = tables;
@@ -235015,9 +235106,9 @@ var init_module2 = __esm({
235015
235106
  };
235016
235107
  $130d1a642ebcd2b7$var$OPENTYPE_SCRIPTS = {};
235017
235108
  for (let script2 in $130d1a642ebcd2b7$var$UNICODE_SCRIPTS) {
235018
- let tag = $130d1a642ebcd2b7$var$UNICODE_SCRIPTS[script2];
235019
- if (Array.isArray(tag)) for (let t3 of tag) $130d1a642ebcd2b7$var$OPENTYPE_SCRIPTS[t3] = script2;
235020
- else $130d1a642ebcd2b7$var$OPENTYPE_SCRIPTS[tag] = script2;
235109
+ let tag2 = $130d1a642ebcd2b7$var$UNICODE_SCRIPTS[script2];
235110
+ if (Array.isArray(tag2)) for (let t3 of tag2) $130d1a642ebcd2b7$var$OPENTYPE_SCRIPTS[t3] = script2;
235111
+ else $130d1a642ebcd2b7$var$OPENTYPE_SCRIPTS[tag2] = script2;
235021
235112
  }
235022
235113
  $130d1a642ebcd2b7$var$RTL = {
235023
235114
  arab: true,
@@ -235093,7 +235184,7 @@ var init_module2 = __esm({
235093
235184
  this.language = language || null;
235094
235185
  this.direction = direction || $130d1a642ebcd2b7$export$9fddb9d0dd7d8a54(script2);
235095
235186
  this.features = {};
235096
- if (Array.isArray(features)) for (let tag of features) this.features[tag] = true;
235187
+ if (Array.isArray(features)) for (let tag2 of features) this.features[tag2] = true;
235097
235188
  else if (typeof features === "object") this.features = features;
235098
235189
  }
235099
235190
  };
@@ -235997,13 +236088,13 @@ var init_module2 = __esm({
235997
236088
  }
235998
236089
  setFeatureOverrides(features) {
235999
236090
  if (Array.isArray(features)) this.add(features);
236000
- else if (typeof features === "object") for (let tag in features) {
236001
- if (features[tag]) this.add(tag);
236002
- else if (this.allFeatures[tag] != null) {
236003
- let stage = this.stages[this.allFeatures[tag]];
236004
- stage.splice(stage.indexOf(tag), 1);
236005
- delete this.allFeatures[tag];
236006
- delete this.globalFeatures[tag];
236091
+ else if (typeof features === "object") for (let tag2 in features) {
236092
+ if (features[tag2]) this.add(tag2);
236093
+ else if (this.allFeatures[tag2] != null) {
236094
+ let stage = this.stages[this.allFeatures[tag2]];
236095
+ stage.splice(stage.indexOf(tag2), 1);
236096
+ delete this.allFeatures[tag2];
236097
+ delete this.globalFeatures[tag2];
236007
236098
  }
236008
236099
  }
236009
236100
  }
@@ -236518,13 +236609,13 @@ var init_module2 = __esm({
236518
236609
  }
236519
236610
  lookupsForFeatures(userFeatures = [], exclude) {
236520
236611
  let lookups = [];
236521
- for (let tag of userFeatures) {
236522
- let feature = this.features[tag];
236612
+ for (let tag2 of userFeatures) {
236613
+ let feature = this.features[tag2];
236523
236614
  if (!feature) continue;
236524
236615
  for (let lookupIndex of feature.lookupListIndexes) {
236525
236616
  if (exclude && exclude.indexOf(lookupIndex) !== -1) continue;
236526
236617
  lookups.push({
236527
- feature: tag,
236618
+ feature: tag2,
236528
236619
  index: lookupIndex,
236529
236620
  lookup: this.table.lookupList.get(lookupIndex)
236530
236621
  });
@@ -239917,8 +240008,8 @@ var init_module2 = __esm({
239917
240008
  }
239918
240009
  return this._tables[table3.tag];
239919
240010
  }
239920
- _getTableStream(tag) {
239921
- let table3 = this.directory.tables[tag];
240011
+ _getTableStream(tag2) {
240012
+ let table3 = this.directory.tables[tag2];
239922
240013
  if (table3) {
239923
240014
  this.stream.pos = table3.offset;
239924
240015
  return this.stream;
@@ -240293,9 +240384,9 @@ var init_module2 = __esm({
240293
240384
  this._tables = {};
240294
240385
  this._glyphs = {};
240295
240386
  this._decodeDirectory();
240296
- for (let tag in this.directory.tables) {
240297
- let table3 = this.directory.tables[tag];
240298
- if ((0, $c3395722bea751e2$export$2e2bcd8739ae039)[tag] && table3.length > 0) Object.defineProperty(this, tag, {
240387
+ for (let tag2 in this.directory.tables) {
240388
+ let table3 = this.directory.tables[tag2];
240389
+ if ((0, $c3395722bea751e2$export$2e2bcd8739ae039)[tag2] && table3.length > 0) Object.defineProperty(this, tag2, {
240299
240390
  get: this._getTable.bind(this, table3)
240300
240391
  });
240301
240392
  }
@@ -240362,8 +240453,8 @@ var init_module2 = __esm({
240362
240453
  _startOffset: 0
240363
240454
  });
240364
240455
  }
240365
- _getTableStream(tag) {
240366
- let table3 = this.directory.tables[tag];
240456
+ _getTableStream(tag2) {
240457
+ let table3 = this.directory.tables[tag2];
240367
240458
  if (table3) {
240368
240459
  this.stream.pos = table3.offset;
240369
240460
  if (table3.compLength < table3.length) {
@@ -240525,8 +240616,8 @@ var init_module2 = __esm({
240525
240616
  this.stream.pos = this._dataPos;
240526
240617
  let buffer = this.stream.readBuffer(this.directory.totalCompressedSize);
240527
240618
  let decompressedSize = 0;
240528
- for (let tag in this.directory.tables) {
240529
- let entry = this.directory.tables[tag];
240619
+ for (let tag2 in this.directory.tables) {
240620
+ let entry = this.directory.tables[tag2];
240530
240621
  entry.offset = decompressedSize;
240531
240622
  decompressedSize += entry.transformLength != null ? entry.transformLength : entry.length;
240532
240623
  }
@@ -240747,6 +240838,12 @@ var init_module2 = __esm({
240747
240838
  });
240748
240839
 
240749
240840
  // lib/engine/text/fontkit-lazy.ts
240841
+ var fontkit_lazy_exports = {};
240842
+ __export(fontkit_lazy_exports, {
240843
+ createFont: () => createFont,
240844
+ createFontSync: () => createFontSync,
240845
+ loadFontkit: () => loadFontkit
240846
+ });
240750
240847
  function loadFontkit() {
240751
240848
  return loading2 ??= Promise.resolve().then(() => (init_module2(), module_exports)).then((m) => loaded = m);
240752
240849
  }
@@ -242740,8 +242837,8 @@ function parseCatalog(rows) {
242740
242837
  for (const [family, cat, up, it, axisStr] of rows) {
242741
242838
  const axes = {};
242742
242839
  for (const part of axisStr ? axisStr.split(";") : []) {
242743
- const [tag, min2, max3] = part.split(":");
242744
- axes[tag] = [Number(min2), Number(max3)];
242840
+ const [tag2, min2, max3] = part.split(":");
242841
+ axes[tag2] = [Number(min2), Number(max3)];
242745
242842
  }
242746
242843
  out.set(family, { family, category: FONT_CATEGORIES[cat] ?? "sans", weights: fromMask(up), italics: fromMask(it), axes });
242747
242844
  }
@@ -243112,6 +243209,8 @@ var init_google_fonts = __esm({
243112
243209
  var fonts_exports = {};
243113
243210
  __export(fonts_exports, {
243114
243211
  MAX_FONT_BYTES: () => MAX_FONT_BYTES,
243212
+ TEAM_FONT_SCHEME: () => TEAM_FONT_SCHEME,
243213
+ customFacesOf: () => customFacesOf,
243115
243214
  customFontBytes: () => customFontBytes,
243116
243215
  customFontRegistry: () => customFontRegistry,
243117
243216
  ensureFontLoaded: () => ensureFontLoaded,
@@ -243120,16 +243219,29 @@ __export(fonts_exports, {
243120
243219
  isFontBytes: () => isFontBytes,
243121
243220
  loadCustomFont: () => loadCustomFont,
243122
243221
  loadedFonts: () => loadedFonts,
243222
+ onCustomFacesChanged: () => onCustomFacesChanged,
243223
+ pickCustomFace: () => pickCustomFace,
243123
243224
  previewFamily: () => previewFamily,
243124
- setCustomFontLookup: () => setCustomFontLookup
243225
+ setCustomFaces: () => setCustomFaces,
243226
+ setCustomFontLookup: () => setCustomFontLookup,
243227
+ setTeamFontResolver: () => setTeamFontResolver
243125
243228
  });
243126
243229
  function isFontBytes(bytes2) {
243127
243230
  if (bytes2.length < 12 || bytes2.length > MAX_FONT_BYTES) return false;
243128
- const tag = String.fromCharCode(bytes2[0], bytes2[1], bytes2[2], bytes2[3]);
243129
- return tag === "OTTO" || tag === "true" || tag === "ttcf" || tag === "wOFF" || tag === "wOF2" || bytes2[0] === 0 && bytes2[1] === 1 && bytes2[2] === 0 && bytes2[3] === 0;
243231
+ const tag2 = String.fromCharCode(bytes2[0], bytes2[1], bytes2[2], bytes2[3]);
243232
+ return tag2 === "OTTO" || tag2 === "true" || tag2 === "ttcf" || tag2 === "wOFF" || tag2 === "wOF2" || bytes2[0] === 0 && bytes2[1] === 1 && bytes2[2] === 0 && bytes2[3] === 0;
243233
+ }
243234
+ function setTeamFontResolver(fn) {
243235
+ teamFontResolver = fn;
243130
243236
  }
243131
243237
  async function customFontBytes(src) {
243132
243238
  try {
243239
+ if (src.startsWith(TEAM_FONT_SCHEME)) {
243240
+ const blob2 = teamFontResolver ? await teamFontResolver(src) : null;
243241
+ if (!blob2 || blob2.size > MAX_FONT_BYTES) return null;
243242
+ const bytes3 = new Uint8Array(await blob2.arrayBuffer());
243243
+ return isFontBytes(bytes3) ? bytes3 : null;
243244
+ }
243133
243245
  const blob = isMediaUrl(src) ? await loadMediaBlob(src) : /^(data|blob):/.test(src) ? await (await fetch(src)).blob() : null;
243134
243246
  if (!blob || blob.size > MAX_FONT_BYTES) return null;
243135
243247
  const bytes2 = new Uint8Array(await blob.arrayBuffer());
@@ -243138,6 +243250,35 @@ async function customFontBytes(src) {
243138
243250
  return null;
243139
243251
  }
243140
243252
  }
243253
+ function setCustomFaces(family, list2) {
243254
+ const prev = customFaces.get(family) ?? [];
243255
+ if (prev.length === list2.length && prev.every((f2, i2) => faceSig(f2) === faceSig(list2[i2]))) return false;
243256
+ if (list2.length) {
243257
+ customFaces.set(family, [...list2]);
243258
+ customFontRegistry.set(family, list2[0].src);
243259
+ } else {
243260
+ customFaces.delete(family);
243261
+ customFontRegistry.delete(family);
243262
+ }
243263
+ for (const k2 of [...loadedFonts]) if (k2.endsWith(`-${family}`)) loadedFonts.delete(k2);
243264
+ facesChanged?.(family);
243265
+ return true;
243266
+ }
243267
+ function onCustomFacesChanged(fn) {
243268
+ facesChanged = fn;
243269
+ }
243270
+ function pickCustomFace(family, italic, weight) {
243271
+ const list2 = customFaces.get(family);
243272
+ if (!list2?.length) return null;
243273
+ const style = italic ? "italic" : "normal";
243274
+ const pool = list2.some((f2) => (f2.style ?? "normal") === style) ? list2.filter((f2) => (f2.style ?? "normal") === style) : list2;
243275
+ const score = (f2) => {
243276
+ const w = f2.weight ?? 400;
243277
+ const d = Math.abs(w - weight);
243278
+ return d * 2 + (d && (weight > 400 ? w < weight : w > weight) ? 1 : 0);
243279
+ };
243280
+ return pool.reduce((best, f2) => score(f2) < score(best) ? f2 : best);
243281
+ }
243141
243282
  async function internLegacyFonts(fonts) {
243142
243283
  if (!fonts.some((f2) => f2.dataUrl?.startsWith("data:"))) return fonts;
243143
243284
  const out = [];
@@ -243226,7 +243367,7 @@ function ensureFontPreview(family) {
243226
243367
  previewed.delete(family);
243227
243368
  });
243228
243369
  }
243229
- var loadedFonts, customFontRegistry, MAX_FONT_BYTES, customFontLookup, previewed, previewFamily;
243370
+ var loadedFonts, customFontRegistry, MAX_FONT_BYTES, TEAM_FONT_SCHEME, teamFontResolver, customFaces, faceSig, facesChanged, customFacesOf, customFontLookup, previewed, previewFamily;
243230
243371
  var init_fonts = __esm({
243231
243372
  "lib/engine/text/fonts.ts"() {
243232
243373
  "use strict";
@@ -243235,6 +243376,12 @@ var init_fonts = __esm({
243235
243376
  loadedFonts = /* @__PURE__ */ new Set();
243236
243377
  customFontRegistry = /* @__PURE__ */ new Map();
243237
243378
  MAX_FONT_BYTES = 32 * 1024 * 1024;
243379
+ TEAM_FONT_SCHEME = "team-font:";
243380
+ teamFontResolver = null;
243381
+ customFaces = /* @__PURE__ */ new Map();
243382
+ faceSig = (f2) => `${f2.src}|${f2.weight ?? 400}|${f2.style ?? "normal"}|${f2.face ?? 0}`;
243383
+ facesChanged = null;
243384
+ customFacesOf = (family) => customFaces.get(family) ?? [];
243238
243385
  customFontLookup = () => void 0;
243239
243386
  previewed = /* @__PURE__ */ new Set();
243240
243387
  previewFamily = (family) => `pc-preview ${family}`;
@@ -244791,6 +244938,7 @@ __export(shaper_exports, {
244791
244938
  effectiveVariations: () => effectiveVariations,
244792
244939
  faceIdFor: () => faceIdFor,
244793
244940
  faceLoading: () => faceLoading,
244941
+ faceOf: () => faceOf,
244794
244942
  fontIdentity: () => fontIdentity,
244795
244943
  getFace: () => getFace,
244796
244944
  getFaceEpoch: () => getFaceEpoch,
@@ -244865,9 +245013,17 @@ function pickWoff2FromCss(css, italic) {
244865
245013
  const latin = blocks.find((b) => b.subset === "latin" && styleOk(b.body)) ?? blocks.find((b) => styleOk(b.body)) ?? blocks[0];
244866
245014
  return latin ? urlOf(latin.body) : null;
244867
245015
  }
245016
+ async function customFaceBytes(family, italic, weight) {
245017
+ const picked = pickCustomFace(family, italic, weight);
245018
+ const src = picked?.src ?? customFontRegistry.get(family);
245019
+ if (!src) return null;
245020
+ const bytes2 = await customFontBytes(src);
245021
+ return bytes2 ? { bytes: bytes2, face: picked?.face ?? 0 } : null;
245022
+ }
245023
+ function faceOf(created, face = 0) {
245024
+ return "fonts" in created ? created.fonts[face] ?? created.fonts[0] : created;
245025
+ }
244868
245026
  async function fetchFontBytes(family, italic, weight) {
244869
- const custom2 = customFontRegistry.get(family);
244870
- if (custom2) return customFontBytes(custom2);
244871
245027
  if (NO_BYTES.has(family)) return null;
244872
245028
  if (!isGoogleFont(family)) await loadGoogleCatalog();
244873
245029
  if (!isGoogleFont(family)) return null;
@@ -244942,14 +245098,15 @@ function getFace(family, italic, weight) {
244942
245098
  }
244943
245099
  const state = { font: null, loading: true, failed: false };
244944
245100
  faces.set(key5, state);
244945
- trackLoad(fetchFontBytes(family, italic, weight).then(async (raw) => {
244946
- if (!raw) {
245101
+ const custom2 = customFontRegistry.has(family);
245102
+ trackLoad((custom2 ? customFaceBytes(family, italic, weight) : fetchFontBytes(family, italic, weight).then((bytes2) => bytes2 ? { bytes: bytes2, face: 0 } : null)).then(async (got) => {
245103
+ if (!got) {
244947
245104
  state.failed = true;
244948
245105
  return;
244949
245106
  }
244950
- const bytes2 = await toSfnt(raw);
245107
+ const bytes2 = await toSfnt(got.bytes);
244951
245108
  const created = await createFont(bytes2);
244952
- state.font = "fonts" in created ? created.fonts[0] : created;
245109
+ state.font = faceOf(created, got.face);
244953
245110
  state.bytes = bytes2;
244954
245111
  if (!customFontRegistry.has(family) && typeof FontFace !== "undefined") {
244955
245112
  try {
@@ -245004,12 +245161,12 @@ function onFaceInvalidated(fn) {
245004
245161
  function emitFaceInvalidated(keyPrefix) {
245005
245162
  for (const fn of faceInvalidationListeners) fn(keyPrefix);
245006
245163
  }
245007
- function registerFaceBytes(family, italic, weight, bytes2) {
245164
+ function registerFaceBytes(family, italic, weight, bytes2, face = 0) {
245008
245165
  faceEpoch++;
245009
245166
  const key5 = faceKey(family, italic, weight);
245010
245167
  const replaced = !!faces.get(key5)?.font;
245011
245168
  const created = createFontSync(bytes2);
245012
- faces.set(key5, { font: "fonts" in created ? created.fonts[0] : created, bytes: bytes2, loading: false, failed: false });
245169
+ faces.set(key5, { font: faceOf(created, face), bytes: bytes2, loading: false, failed: false });
245013
245170
  if (replaced) {
245014
245171
  for (const k2 of [...runCache.keys()]) if (k2.startsWith(`${key5}|`)) runCache.delete(k2);
245015
245172
  for (const k2 of [...variationCache.keys()]) if (k2.startsWith(`${key5}|`)) variationCache.delete(k2);
@@ -245030,15 +245187,16 @@ function invalidateFace(family) {
245030
245187
  runCache.clear();
245031
245188
  variationCache.clear();
245032
245189
  emitFaceInvalidated(`${family}|`);
245190
+ notifyFacesChanged(family);
245033
245191
  }
245034
245192
  function effectiveVariations(font, weight, variations) {
245035
245193
  const axes = font.variationAxes || {};
245036
245194
  const out = {};
245037
- for (const [tag, axis] of Object.entries(axes)) {
245038
- let v = variations?.[tag];
245039
- if (v === void 0 && tag === "wght") v = weight;
245195
+ for (const [tag2, axis] of Object.entries(axes)) {
245196
+ let v = variations?.[tag2];
245197
+ if (v === void 0 && tag2 === "wght") v = weight;
245040
245198
  if (v === void 0) continue;
245041
- out[tag] = Math.max(axis.min, Math.min(axis.max, v));
245199
+ out[tag2] = Math.max(axis.min, Math.min(axis.max, v));
245042
245200
  }
245043
245201
  return out;
245044
245202
  }
@@ -245170,8 +245328,9 @@ var init_shaper = __esm({
245170
245328
  RUN_CACHE_MAX = 4e3;
245171
245329
  NO_BYTES = /* @__PURE__ */ new Set(["Arial", "Helvetica", "Times New Roman", "Courier New", "Georgia", "system-ui", "sans-serif", "serif", "monospace"]);
245172
245330
  faceKey = (family, italic, weight) => (
245173
- // Variable families share one face per style; static families need a file per weight.
245174
- isStaticGoogleFont(family) ? `${family}|${italic ? "i" : "n"}|${weight}` : `${family}|${italic ? "i" : "n"}`
245331
+ // Variable families share one face per style; static families need a file per weight, and so does a custom family
245332
+ // with several files (a Regular and a Bold), each weight finding its nearest file.
245333
+ isStaticGoogleFont(family) || customFacesOf(family).length > 1 ? `${family}|${italic ? "i" : "n"}|${weight}` : `${family}|${italic ? "i" : "n"}`
245175
245334
  );
245176
245335
  fontIds = /* @__PURE__ */ new WeakMap();
245177
245336
  fontIdSerial = 0;
@@ -245180,6 +245339,7 @@ var init_shaper = __esm({
245180
245339
  changedFamilies = /* @__PURE__ */ new Set();
245181
245340
  notifyScheduled = false;
245182
245341
  faceInvalidationListeners = /* @__PURE__ */ new Set();
245342
+ onCustomFacesChanged(invalidateFace);
245183
245343
  patchedFonts = /* @__PURE__ */ new WeakSet();
245184
245344
  shapingDepth = 0;
245185
245345
  if (typeof window !== "undefined") window.__vpShaper = { shapeRun, getFace, describeFace, faces };
@@ -253288,8 +253448,8 @@ function createPixelSlice(set4, get4) {
253288
253448
  const n = node2(id3);
253289
253449
  if (!n) return;
253290
253450
  const colors2 = ["#e9720c", "#0c8ce9", "#34c759", "#af52de", "#ff2d55", "#ffcc00"];
253291
- const tag = { id: v4_default(), name: `Tag ${n.tags.length + 1}`, from: clampFrame(n, Math.min(from2, to)), to: clampFrame(n, Math.max(from2, to)), direction: "FORWARD", color: colors2[n.tags.length % colors2.length] };
253292
- commit(id3, { tags: [...n.tags, tag] }, "Add tag");
253451
+ const tag2 = { id: v4_default(), name: `Tag ${n.tags.length + 1}`, from: clampFrame(n, Math.min(from2, to)), to: clampFrame(n, Math.max(from2, to)), direction: "FORWARD", color: colors2[n.tags.length % colors2.length] };
253452
+ commit(id3, { tags: [...n.tags, tag2] }, "Add tag");
253293
253453
  },
253294
253454
  pixelUpdateTag: (id3, tagId, patch) => {
253295
253455
  const n = node2(id3);
@@ -254982,6 +255142,138 @@ var init_washi = __esm({
254982
255142
  }
254983
255143
  });
254984
255144
 
255145
+ // lib/fonts/document-fonts.ts
255146
+ var document_fonts_exports = {};
255147
+ __export(document_fonts_exports, {
255148
+ addDocumentFont: () => addDocumentFont,
255149
+ documentFontFiles: () => documentFontFiles,
255150
+ documentFontHashes: () => documentFontHashes,
255151
+ embedDocumentFonts: () => embedDocumentFonts,
255152
+ faceLabel: () => faceLabel,
255153
+ fontStyleOf: () => fontStyleOf,
255154
+ fontWeightOf: () => fontWeightOf,
255155
+ internDocumentFonts: () => internDocumentFonts,
255156
+ matchFonts: () => matchFonts,
255157
+ mergeFonts: () => mergeFonts,
255158
+ missingFontMessage: () => missingFontMessage,
255159
+ missingFonts: () => missingFonts,
255160
+ removeDocumentFonts: () => removeDocumentFonts,
255161
+ usedFontFamilies: () => usedFontFamilies
255162
+ });
255163
+ function faceLabel(f2) {
255164
+ return `${f2.family} ${fontWeightOf(f2)}${fontStyleOf(f2) === "italic" ? " italic" : ""}`;
255165
+ }
255166
+ function addDocumentFont(doc2, font) {
255167
+ const kept = (doc2.fonts ?? []).filter((f2) => !sameSlot(f2, font));
255168
+ return { ...doc2, fonts: [...kept, font] };
255169
+ }
255170
+ function matchFonts(doc2, match2) {
255171
+ return (doc2.fonts ?? []).filter((f2) => match2.id ? f2.id === match2.id : !!match2.family && f2.family === match2.family && (match2.weight === void 0 || fontWeightOf(f2) === match2.weight) && (match2.style === void 0 || fontStyleOf(f2) === match2.style));
255172
+ }
255173
+ function removeDocumentFonts(doc2, match2) {
255174
+ const removed = matchFonts(doc2, match2);
255175
+ if (!removed.length) return { doc: doc2, removed };
255176
+ const fonts = (doc2.fonts ?? []).filter((f2) => !removed.includes(f2));
255177
+ const { fonts: _old, ...rest } = doc2;
255178
+ void _old;
255179
+ return { doc: fonts.length ? { ...rest, fonts } : rest, removed };
255180
+ }
255181
+ function usedFontFamilies(doc2) {
255182
+ const out = /* @__PURE__ */ new Map();
255183
+ const note2 = (family, id3) => {
255184
+ if (!family) return;
255185
+ const ids2 = out.get(family) ?? out.set(family, []).get(family);
255186
+ if (!ids2.includes(id3)) ids2.push(id3);
255187
+ };
255188
+ for (const n of Object.values(doc2.nodes)) {
255189
+ if (n.type !== "TEXT") continue;
255190
+ const t3 = n;
255191
+ const style = t3.textStyleId ? doc2.styles?.[t3.textStyleId] : void 0;
255192
+ note2(style?.fontFamily ?? t3.fontFamily, t3.id);
255193
+ for (const s of t3.styledSegments ?? []) note2(s.fontFamily, t3.id);
255194
+ }
255195
+ return out;
255196
+ }
255197
+ function missingFonts(doc2, available) {
255198
+ const carried = new Set((doc2.fonts ?? []).map((f2) => f2.family));
255199
+ return [...usedFontFamilies(doc2)].filter(([family]) => !carried.has(family) && !available(family)).map(([family, nodeIds]) => ({ family, nodeIds })).sort((a, b) => a.family.localeCompare(b.family));
255200
+ }
255201
+ function missingFontMessage(m) {
255202
+ return `${m.family} is not available: ${m.nodeIds.length} text${m.nodeIds.length === 1 ? "" : "s"} draw${m.nodeIds.length === 1 ? "s" : ""} in a fallback font. Add the font file to the file (font.add) to use it.`;
255203
+ }
255204
+ function decodeBase64DataUrl(url4) {
255205
+ const comma = url4.indexOf(",");
255206
+ if (!url4.startsWith("data:") || comma < 0 || !url4.slice(0, comma).includes(";base64")) return null;
255207
+ try {
255208
+ const bin = atob(url4.slice(comma + 1));
255209
+ const out = new Uint8Array(bin.length);
255210
+ for (let i2 = 0; i2 < bin.length; i2++) out[i2] = bin.charCodeAt(i2);
255211
+ return out;
255212
+ } catch {
255213
+ return null;
255214
+ }
255215
+ }
255216
+ async function embedDocumentFonts(doc2) {
255217
+ if (!doc2.fonts?.length) return doc2;
255218
+ const fonts = await Promise.all(doc2.fonts.map(async (f2) => {
255219
+ if (f2.data || !isMediaUrl(f2.src)) return f2;
255220
+ const data = await mediaToDataUrl(f2.src);
255221
+ return data ? { ...f2, data } : f2;
255222
+ }));
255223
+ return { ...doc2, fonts };
255224
+ }
255225
+ function internDocumentFonts(doc2) {
255226
+ if (doc2.fonts === void 0) return doc2;
255227
+ if (!Array.isArray(doc2.fonts)) {
255228
+ const { fonts: _f, ...rest } = doc2;
255229
+ void _f;
255230
+ return rest;
255231
+ }
255232
+ const fonts = [];
255233
+ for (const raw of doc2.fonts) {
255234
+ const f2 = raw;
255235
+ if (!f2 || typeof f2 !== "object" || typeof f2.family !== "string" || !f2.family || typeof f2.src !== "string") continue;
255236
+ const { data, ...rest } = f2;
255237
+ let src = rest.src;
255238
+ const bytes2 = typeof data === "string" ? decodeBase64DataUrl(data) : null;
255239
+ if (bytes2) {
255240
+ const hash3 = hashBytesSync(bytes2);
255241
+ putReceivedMedia(hash3, "application/octet-stream", bytes2);
255242
+ src = MEDIA_SCHEME + hash3;
255243
+ }
255244
+ if (!isMediaUrl(src)) continue;
255245
+ fonts.push({ ...rest, id: typeof rest.id === "string" && rest.id ? rest.id : `font-${hashOf(src)}-${fontWeightOf(rest)}-${fontStyleOf(rest)}`, src });
255246
+ }
255247
+ return { ...doc2, fonts };
255248
+ }
255249
+ async function documentFontFiles(doc2) {
255250
+ const out = {};
255251
+ await Promise.all(documentFontHashes(doc2).map(async (hash3) => {
255252
+ const blob = await loadMediaBlob(MEDIA_SCHEME + hash3);
255253
+ if (blob) out[hash3] = new Uint8Array(await blob.arrayBuffer());
255254
+ }));
255255
+ return out;
255256
+ }
255257
+ function mergeFonts(fonts, incoming) {
255258
+ if (!incoming?.length) return fonts ? [...fonts] : void 0;
255259
+ const out = [...fonts ?? []];
255260
+ for (const f2 of incoming) if (!out.some((o) => sameSlot(o, f2))) out.push(f2);
255261
+ return out;
255262
+ }
255263
+ var fontWeightOf, fontStyleOf, sameSlot, hashOf, documentFontHashes;
255264
+ var init_document_fonts = __esm({
255265
+ "lib/fonts/document-fonts.ts"() {
255266
+ "use strict";
255267
+ init_media_store();
255268
+ init_media_hash();
255269
+ fontWeightOf = (f2) => f2.weight ?? 400;
255270
+ fontStyleOf = (f2) => f2.style ?? "normal";
255271
+ sameSlot = (a, b) => a.family === b.family && fontWeightOf(a) === fontWeightOf(b) && fontStyleOf(a) === fontStyleOf(b);
255272
+ hashOf = (src) => isMediaUrl(src) ? src.slice(MEDIA_SCHEME.length) : null;
255273
+ documentFontHashes = (doc2) => [...new Set((doc2.fonts ?? []).flatMap((f2) => hashOf(f2.src) ? [hashOf(f2.src)] : []))];
255274
+ }
255275
+ });
255276
+
254985
255277
  // lib/templates/apply.ts
254986
255278
  var apply_exports2 = {};
254987
255279
  __export(apply_exports2, {
@@ -255025,7 +255317,7 @@ function addTree(document2, t3, map2, rootId, parentId, ox, oy) {
255025
255317
  }
255026
255318
  function mergeRecords(doc2, t3, map2, roots) {
255027
255319
  const p2 = t3.payload;
255028
- if (!p2.styles && !p2.variables && !p2.variableCollections && !p2.libraries && !p2.compositions && !p2.collections) return doc2;
255320
+ if (!p2.styles && !p2.variables && !p2.variableCollections && !p2.libraries && !p2.compositions && !p2.collections && !p2.fonts?.length) return doc2;
255029
255321
  const merged = { ...doc2 };
255030
255322
  if (p2.styles) merged.styles = { ...doc2.styles, ...rewriteIds(p2.styles, map2) };
255031
255323
  if (p2.variables) merged.variables = { ...doc2.variables, ...rewriteIds(p2.variables, map2) };
@@ -255037,6 +255329,7 @@ function mergeRecords(doc2, t3, map2, roots) {
255037
255329
  if (p2.libraries) merged.libraries = { ...p2.libraries, ...doc2.libraries };
255038
255330
  const comps = p2.compositions && roots ? Object.fromEntries(Object.entries(p2.compositions).filter(([, c2]) => c2.clips.every((clip) => roots.has(clip.frameId)))) : p2.compositions;
255039
255331
  if (comps && Object.keys(comps).length) merged.compositions = { ...doc2.compositions, ...rewriteIds(comps, map2) };
255332
+ if (p2.fonts?.length) merged.fonts = mergeFonts(doc2.fonts, p2.fonts);
255040
255333
  return merged;
255041
255334
  }
255042
255335
  function mergeLibraryNodes(doc2, t3) {
@@ -255101,6 +255394,7 @@ var init_apply2 = __esm({
255101
255394
  init_dist_node();
255102
255395
  init_scene_graph();
255103
255396
  init_libraries();
255397
+ init_document_fonts();
255104
255398
  init_page_presets();
255105
255399
  init_print_pages();
255106
255400
  variantOf = (t3, sizeId) => sizeId && t3.payload.variants.find((v) => v.sizeId === sizeId) || t3.payload.variants[0];
@@ -258801,10 +259095,10 @@ function retargetPath(node2, parent, path) {
258801
259095
  return propertiesOf(node2, parent).find((p2) => patternOf(p2.path) === pattern)?.path ?? null;
258802
259096
  }
258803
259097
  function pasteKeys(nodes, frameId, clip, targets, at4) {
258804
- const sources = [];
258805
- for (const tr of clip.tracks) if (!sources.includes(tr.source)) sources.push(tr.source);
259098
+ const sources2 = [];
259099
+ for (const tr of clip.tracks) if (!sources2.includes(tr.source)) sources2.push(tr.source);
258806
259100
  const onto = targets.filter((id3) => nodes[id3]);
258807
- const plan2 = !onto.length ? sources.filter((id3) => nodes[id3]).map((id3) => [id3, id3]) : sources.length === 1 ? onto.map((id3) => [sources[0], id3]) : sources.slice(0, onto.length).map((s, i2) => [s, onto[i2]]);
259101
+ const plan2 = !onto.length ? sources2.filter((id3) => nodes[id3]).map((id3) => [id3, id3]) : sources2.length === 1 ? onto.map((id3) => [sources2[0], id3]) : sources2.slice(0, onto.length).map((s, i2) => [s, onto[i2]]);
258808
259102
  const result = { edits: [], keys: [] };
258809
259103
  for (const [source3, targetId] of plan2) {
258810
259104
  const rest = nodes[targetId];
@@ -259835,10 +260129,10 @@ function recordSlugs(doc2, collectionId) {
259835
260129
  const taken = /* @__PURE__ */ new Set();
259836
260130
  for (const r of recordsIn(doc2, collectionId)) {
259837
260131
  const base = slugify2(field ? r.values[field.id] : "") || slugify2(r.id) || "item";
259838
- let slug3 = base;
259839
- for (let n = 2; taken.has(slug3); n++) slug3 = `${base}-${n}`;
259840
- taken.add(slug3);
259841
- out.set(r.id, slug3);
260132
+ let slug4 = base;
260133
+ for (let n = 2; taken.has(slug4); n++) slug4 = `${base}-${n}`;
260134
+ taken.add(slug4);
260135
+ out.set(r.id, slug4);
259842
260136
  }
259843
260137
  return out;
259844
260138
  }
@@ -260528,6 +260822,150 @@ var init_library_link = __esm({
260528
260822
  }
260529
260823
  });
260530
260824
 
260825
+ // lib/fonts/sfnt.ts
260826
+ var sfnt_exports = {};
260827
+ __export(sfnt_exports, {
260828
+ collectionSize: () => collectionSize,
260829
+ extractCollectionFace: () => extractCollectionFace,
260830
+ fontExtension: () => fontExtension,
260831
+ fontFormat: () => fontFormat,
260832
+ fontMime: () => fontMime
260833
+ });
260834
+ function fontFormat(bytes2) {
260835
+ if (bytes2.length < 12) return null;
260836
+ const t3 = tag(bytes2);
260837
+ if (t3 === "ttcf") return "ttc";
260838
+ if (t3 === "wOFF") return "woff";
260839
+ if (t3 === "wOF2") return "woff2";
260840
+ if (t3 === "OTTO") return "otf";
260841
+ if (t3 === "true" || bytes2[0] === 0 && bytes2[1] === 1 && bytes2[2] === 0 && bytes2[3] === 0) return "ttf";
260842
+ return null;
260843
+ }
260844
+ function fontMime(bytes2) {
260845
+ const f2 = fontFormat(bytes2);
260846
+ return f2 === "ttc" ? "font/collection" : f2 ? `font/${f2}` : "application/octet-stream";
260847
+ }
260848
+ function collectionSize(bytes2) {
260849
+ if (fontFormat(bytes2) !== "ttc") return 1;
260850
+ return new DataView(bytes2.buffer, bytes2.byteOffset, bytes2.byteLength).getUint32(8);
260851
+ }
260852
+ function extractCollectionFace(bytes2, index2) {
260853
+ if (fontFormat(bytes2) !== "ttc") return bytes2;
260854
+ const view2 = new DataView(bytes2.buffer, bytes2.byteOffset, bytes2.byteLength);
260855
+ const count2 = view2.getUint32(8);
260856
+ if (!Number.isInteger(index2) || index2 < 0 || index2 >= count2) throw new RangeError(`The collection has ${count2} faces (0\u2013${count2 - 1}); there is no face ${index2}`);
260857
+ const dir = view2.getUint32(12 + index2 * 4);
260858
+ const numTables = view2.getUint16(dir + 4);
260859
+ const tables = Array.from({ length: numTables }, (_, i2) => {
260860
+ const rec = dir + 12 + i2 * 16;
260861
+ return { tag: view2.getUint32(rec), checksum: view2.getUint32(rec + 4), offset: view2.getUint32(rec + 8), length: view2.getUint32(rec + 12) };
260862
+ });
260863
+ const head2 = 12 + numTables * 16;
260864
+ const size6 = tables.reduce((n, t3) => n + (t3.length + 3 & ~3), head2);
260865
+ const out = new Uint8Array(size6);
260866
+ const w = new DataView(out.buffer);
260867
+ for (let i2 = 0; i2 < 12; i2++) out[i2] = bytes2[dir + i2];
260868
+ let at4 = head2;
260869
+ tables.forEach((t3, i2) => {
260870
+ const rec = 12 + i2 * 16;
260871
+ w.setUint32(rec, t3.tag);
260872
+ w.setUint32(rec + 4, t3.checksum);
260873
+ w.setUint32(rec + 8, at4);
260874
+ w.setUint32(rec + 12, t3.length);
260875
+ out.set(bytes2.subarray(t3.offset, t3.offset + t3.length), at4);
260876
+ at4 += t3.length + 3 & ~3;
260877
+ });
260878
+ return out;
260879
+ }
260880
+ var tag, fontExtension;
260881
+ var init_sfnt = __esm({
260882
+ "lib/fonts/sfnt.ts"() {
260883
+ "use strict";
260884
+ tag = (b, at4 = 0) => String.fromCharCode(b[at4], b[at4 + 1], b[at4 + 2], b[at4 + 3]);
260885
+ fontExtension = (format) => format ?? "bin";
260886
+ }
260887
+ });
260888
+
260889
+ // lib/fonts/runtime.ts
260890
+ var runtime_exports2 = {};
260891
+ __export(runtime_exports2, {
260892
+ findMissingFonts: () => findMissingFonts,
260893
+ fontAvailable: () => fontAvailable,
260894
+ fontSource: () => fontSource,
260895
+ loadFontsForMeasuring: () => loadFontsForMeasuring,
260896
+ setFontSource: () => setFontSource
260897
+ });
260898
+ function setFontSource(kind, fonts) {
260899
+ const next2 = fonts ?? [];
260900
+ if (sources[kind] === next2) return;
260901
+ sources[kind] = next2;
260902
+ const byFamily = /* @__PURE__ */ new Map();
260903
+ for (const f2 of sources.document) (byFamily.get(f2.family) ?? byFamily.set(f2.family, []).get(f2.family)).push(toFace(f2));
260904
+ for (const f2 of sources.team) if (!sources.document.some((d) => d.family === f2.family)) (byFamily.get(f2.family) ?? byFamily.set(f2.family, []).get(f2.family)).push(toFace(f2));
260905
+ for (const family of [...ours]) if (!byFamily.has(family)) {
260906
+ setCustomFaces(family, []);
260907
+ ours.delete(family);
260908
+ }
260909
+ for (const [family, faces2] of byFamily) {
260910
+ ours.add(family);
260911
+ if (setCustomFaces(family, faces2)) void registerCss(family, faces2);
260912
+ }
260913
+ }
260914
+ function fontAvailable(family) {
260915
+ return customFontRegistry.has(family) || customFacesOf(family).length > 0 || isGoogleFont(family);
260916
+ }
260917
+ async function registerCss(family, faces2) {
260918
+ if (typeof FontFace === "undefined" || typeof document === "undefined") return;
260919
+ for (const f2 of faces2) {
260920
+ try {
260921
+ const bytes2 = await customFontBytes(f2.src);
260922
+ if (!bytes2) continue;
260923
+ const one = extractCollectionFace(bytes2, f2.face ?? 0);
260924
+ const face = new FontFace(family, one.slice().buffer, { weight: String(f2.weight ?? 400), style: f2.style ?? "normal" });
260925
+ document.fonts.add(await face.load());
260926
+ } catch {
260927
+ }
260928
+ }
260929
+ }
260930
+ async function loadFontsForMeasuring(fonts) {
260931
+ if (!fonts.length) return [];
260932
+ const [{ loadFontkit: loadFontkit2 }, { registerFaceBytes: registerFaceBytes2, toSfnt: toSfnt2 }] = await Promise.all([Promise.resolve().then(() => (init_fontkit_lazy(), fontkit_lazy_exports)), Promise.resolve().then(() => (init_shaper(), shaper_exports))]);
260933
+ await loadFontkit2();
260934
+ setFontSource("document", fonts);
260935
+ const failed2 = [];
260936
+ for (const f2 of fonts) {
260937
+ const raw = await customFontBytes(f2.src);
260938
+ if (!raw) {
260939
+ failed2.push(f2);
260940
+ continue;
260941
+ }
260942
+ try {
260943
+ registerFaceBytes2(f2.family, fontStyleOf(f2) === "italic", fontWeightOf(f2), await toSfnt2(raw), f2.face ?? 0);
260944
+ } catch {
260945
+ failed2.push(f2);
260946
+ }
260947
+ }
260948
+ return failed2;
260949
+ }
260950
+ async function findMissingFonts(doc2) {
260951
+ const [{ missingFonts: missingFonts2 }, { loadGoogleCatalog: loadGoogleCatalog2 }] = await Promise.all([Promise.resolve().then(() => (init_document_fonts(), document_fonts_exports)), Promise.resolve().then(() => (init_google_catalog(), google_catalog_exports))]);
260952
+ await loadGoogleCatalog2().catch(() => null);
260953
+ return missingFonts2(doc2, fontAvailable);
260954
+ }
260955
+ var sources, ours, toFace, fontSource;
260956
+ var init_runtime3 = __esm({
260957
+ "lib/fonts/runtime.ts"() {
260958
+ init_fonts();
260959
+ init_google_fonts();
260960
+ init_document_fonts();
260961
+ init_sfnt();
260962
+ sources = { document: [], team: [] };
260963
+ ours = /* @__PURE__ */ new Set();
260964
+ toFace = (f2) => ({ src: f2.src, weight: fontWeightOf(f2), style: fontStyleOf(f2), ...f2.face ? { face: f2.face } : {} });
260965
+ fontSource = (kind) => sources[kind];
260966
+ }
260967
+ });
260968
+
260531
260969
  // lib/plugins/plugin-store.ts
260532
260970
  var plugin_store_exports = {};
260533
260971
  __export(plugin_store_exports, {
@@ -269695,6 +270133,9 @@ function finishDocument(ydoc, base, nodes) {
269695
270133
  const site = meta3.get("site");
269696
270134
  if (site && typeof site === "object") doc2.site = site;
269697
270135
  else delete doc2.site;
270136
+ const fonts = meta3.get("fonts");
270137
+ if (Array.isArray(fonts) && fonts.length) doc2.fonts = fonts;
270138
+ else delete doc2.fonts;
269698
270139
  for (const f2 of RECORD_FIELDS) {
269699
270140
  const ymap = ydoc.getMap(f2);
269700
270141
  if (ymap.size) {
@@ -269744,7 +270185,7 @@ var init_ydoc = __esm({
269744
270185
  init_yjs();
269745
270186
  LOCAL_ORIGIN = "popcraft-local";
269746
270187
  RECORD_FIELDS = ["styles", "variables", "variableCollections", "libraries", "compositions", "collections", "records", "codeModules", "pluginData"];
269747
- META_FIELDS = ["name", "thumbnailNodeId", "voteResults", "settings", "site"];
270188
+ META_FIELDS = ["name", "thumbnailNodeId", "voteResults", "settings", "site", "fonts"];
269748
270189
  sameSyncedFields = (prev, next2) => prev.nodes === next2.nodes && prev.pages === next2.pages && META_FIELDS.every((f2) => prev[f2] === next2[f2]) && RECORD_FIELDS.every((f2) => prev[f2] === next2[f2]);
269749
270190
  yRecordMaps = (ydoc) => RECORD_FIELDS.map((f2) => ydoc.getMap(f2));
269750
270191
  TRACK_PREFIX = "motion.tracks/";
@@ -271151,7 +271592,7 @@ function templateFromDocument(doc2, meta3, o = {}) {
271151
271592
  nodes,
271152
271593
  variants,
271153
271594
  pages: pages2,
271154
- media: mediaHashes({ nodes, compositions: doc2.compositions, records: doc2.records }),
271595
+ media: mediaHashes({ nodes, compositions: doc2.compositions, records: doc2.records, fonts: doc2.fonts }),
271155
271596
  styles: { ...deps.styles, ...doc2.styles },
271156
271597
  variables: { ...deps.variables, ...doc2.variables },
271157
271598
  variableCollections: { ...deps.variableCollections, ...doc2.variableCollections },
@@ -271160,7 +271601,11 @@ function templateFromDocument(doc2, meta3, o = {}) {
271160
271601
  ...doc2.settings?.facingPages ? { facingPages: true } : {},
271161
271602
  ...doc2.settings?.showAdvance || doc2.settings?.showLoop ? { show: { ...doc2.settings.showAdvance ? { advance: doc2.settings.showAdvance } : {}, ...doc2.settings.showLoop ? { loop: true } : {} } } : {},
271162
271603
  ...doc2.thumbnailNodeId && nodes[doc2.thumbnailNodeId] ? { coverNodeId: doc2.thumbnailNodeId } : {},
271163
- ...doc2.compositions && Object.keys(doc2.compositions).length ? { compositions: JSON.parse(JSON.stringify(doc2.compositions)) } : {}
271604
+ ...doc2.compositions && Object.keys(doc2.compositions).length ? { compositions: JSON.parse(JSON.stringify(doc2.compositions)) } : {},
271605
+ ...doc2.fonts?.length ? { fonts: doc2.fonts.map(({ data: _d, ...f2 }) => {
271606
+ void _d;
271607
+ return { ...f2 };
271608
+ }) } : {}
271164
271609
  };
271165
271610
  return { meta: makeMeta(meta3, doc2.settings?.kind ?? "CANVAS", nodes, doc2.variables, doc2.styles), payload };
271166
271611
  }
@@ -273102,8 +273547,8 @@ var init_misc = __esm({
273102
273547
  return null;
273103
273548
  }
273104
273549
  };
273105
- base64ToBytes2 = (base644) => {
273106
- const decoded = atob(base644);
273550
+ base64ToBytes2 = (base645) => {
273551
+ const decoded = atob(base645);
273107
273552
  const bytes2 = new Uint8Array(decoded.length);
273108
273553
  for (let i2 = 0; i2 < decoded.length; i2++) {
273109
273554
  bytes2[i2] = decoded.charCodeAt(i2);
@@ -279096,8 +279541,8 @@ var init_isobmff_demuxer = __esm({
279096
279541
  break;
279097
279542
  }
279098
279543
  slice2.skip(4);
279099
- const tag = readU8(slice2);
279100
- assert2(tag === 3);
279544
+ const tag2 = readU8(slice2);
279545
+ assert2(tag2 === 3);
279101
279546
  readIsomVariableInteger(slice2);
279102
279547
  slice2.skip(2);
279103
279548
  const mixed = readU8(slice2);
@@ -284081,8 +284526,8 @@ var init_mp3_demuxer = __esm({
284081
284526
  if (isThenable(slice2))
284082
284527
  slice2 = await slice2;
284083
284528
  assert2(slice2);
284084
- const tag = readAscii(slice2, 3);
284085
- if (tag === "TAG") {
284529
+ const tag2 = readAscii(slice2, 3);
284530
+ if (tag2 === "TAG") {
284086
284531
  parseId3V1Tag(slice2, this.metadataTags);
284087
284532
  }
284088
284533
  }
@@ -290667,9 +291112,9 @@ var init_hls_demuxer = __esm({
290667
291112
  }
290668
291113
  }
290669
291114
  if (audioGroupId !== null && !containsAudioCodecs) {
290670
- const matchingAudioMediaTag = mediaTags.find((tag) => {
290671
- const groupId = tag.attributes.get("group-id");
290672
- const type = tag.attributes.get("type");
291115
+ const matchingAudioMediaTag = mediaTags.find((tag2) => {
291116
+ const groupId = tag2.attributes.get("group-id");
291117
+ const type = tag2.attributes.get("type");
290673
291118
  return groupId === audioGroupId && type.toLowerCase() === "audio";
290674
291119
  });
290675
291120
  outer: if (matchingAudioMediaTag) {
@@ -296748,12 +297193,12 @@ var init_id3 = __esm({
296748
297193
  };
296749
297194
  readId3V2Header = (slice2) => {
296750
297195
  const startPos = slice2.filePos;
296751
- const tag = readAscii(slice2, 3);
297196
+ const tag2 = readAscii(slice2, 3);
296752
297197
  const majorVersion = readU8(slice2);
296753
297198
  const revision = readU8(slice2);
296754
297199
  const flags = readU8(slice2);
296755
297200
  const sizeRaw = readU32Be(slice2);
296756
- if (tag !== "ID3" || majorVersion === 255 || revision === 255 || (sizeRaw & 2155905152) !== 0) {
297201
+ if (tag2 !== "ID3" || majorVersion === 255 || revision === 255 || (sizeRaw & 2155905152) !== 0) {
296757
297202
  slice2.filePos = startPos;
296758
297203
  return null;
296759
297204
  }
@@ -307296,8 +307741,8 @@ function parseXml(src) {
307296
307741
  const top = stack[stack.length - 1];
307297
307742
  if (m[1] !== void 0) top.text += m[1];
307298
307743
  else if (m[2]) {
307299
- const tag = m[2].replace(/^.*:/, "").toLowerCase();
307300
- for (let i2 = stack.length - 1; i2 > 0; i2--) if (stack[i2].tag === tag) {
307744
+ const tag2 = m[2].replace(/^.*:/, "").toLowerCase();
307745
+ for (let i2 = stack.length - 1; i2 > 0; i2--) if (stack[i2].tag === tag2) {
307301
307746
  stack.length = i2;
307302
307747
  break;
307303
307748
  }
@@ -307613,10 +308058,10 @@ function parseCss(text) {
307613
308058
  for (const sel of m[1].split(",")) {
307614
308059
  const s = sel.trim();
307615
308060
  if (!/^[\w-]*(?:[.#][\w-]+)*$/.test(s) || !s) continue;
307616
- const tag = /^[\w-]+/.exec(s)?.[0];
308061
+ const tag2 = /^[\w-]+/.exec(s)?.[0];
307617
308062
  const cls = [...s.matchAll(/\.([\w-]+)/g)].map((x2) => x2[1]);
307618
308063
  const id3 = /#([\w-]+)/.exec(s)?.[1];
307619
- rules.push({ selector: { tag: tag?.toLowerCase(), cls, id: id3 }, decls, order: rules.length });
308064
+ rules.push({ selector: { tag: tag2?.toLowerCase(), cls, id: id3 }, decls, order: rules.length });
307620
308065
  }
307621
308066
  }
307622
308067
  return rules;
@@ -307801,7 +308246,7 @@ function applyEffects(item, effects) {
307801
308246
  item.effects = [...item.effects ?? [], ...effects.effects ?? []];
307802
308247
  }
307803
308248
  function walkElement(el, parentStyle, m, ctx2, out) {
307804
- const tag = el.tag;
308249
+ const tag2 = el.tag;
307805
308250
  const style = inherit(parentStyle, ownStyle(el, ctx2.css));
307806
308251
  if (style.display === "none") return;
307807
308252
  const local = mul2(m, parseTransform(el.attrs.transform));
@@ -307809,8 +308254,8 @@ function walkElement(el, parentStyle, m, ctx2, out) {
307809
308254
  const name2 = el.attrs.id || el.attrs["inkscape:label"] || "";
307810
308255
  ctx2.depth++;
307811
308256
  try {
307812
- if (tag === "g" || tag === "a" || tag === "switch" || tag === "svg") {
307813
- const inner = tag === "svg" ? mul2(local, viewBoxMatrix(el)) : local;
308257
+ if (tag2 === "g" || tag2 === "a" || tag2 === "switch" || tag2 === "svg") {
308258
+ const inner = tag2 === "svg" ? mul2(local, viewBoxMatrix(el)) : local;
307814
308259
  const children = [];
307815
308260
  for (const c2 of el.children) walk3(c2, style, inner, ctx2, children);
307816
308261
  if (!children.length) return;
@@ -307818,7 +308263,7 @@ function walkElement(el, parentStyle, m, ctx2, out) {
307818
308263
  else out.push({ kind: "group", name: name2 || "Group", children, opacity });
307819
308264
  return;
307820
308265
  }
307821
- if (tag === "use") {
308266
+ if (tag2 === "use") {
307822
308267
  const ref3 = ctx2.ids.get((el.attrs.href ?? el.attrs["xlink:href"] ?? "").replace(/^#/, ""));
307823
308268
  if (!ref3) return;
307824
308269
  const moved3 = mul2(local, [1, 0, 0, 1, len2(el.attrs.x), len2(el.attrs.y)]);
@@ -307829,7 +308274,7 @@ function walkElement(el, parentStyle, m, ctx2, out) {
307829
308274
  else if (children.length) out.push({ kind: "group", name: name2 || "Group", children, opacity });
307830
308275
  return;
307831
308276
  }
307832
- if (tag === "image") {
308277
+ if (tag2 === "image") {
307833
308278
  const href = (el.attrs.href ?? el.attrs["xlink:href"] ?? "").trim();
307834
308279
  const w = len2(el.attrs.width), h = len2(el.attrs.height);
307835
308280
  if (!/^(data:image\/|https?:)/i.test(href) || w <= 0 || h <= 0 || style.visibility === "hidden") return;
@@ -307850,7 +308295,7 @@ function walkElement(el, parentStyle, m, ctx2, out) {
307850
308295
  });
307851
308296
  return;
307852
308297
  }
307853
- if (tag === "text") {
308298
+ if (tag2 === "text") {
307854
308299
  if (style.visibility === "hidden") return;
307855
308300
  const characters = textLines(el);
307856
308301
  if (!characters) return;
@@ -307884,7 +308329,7 @@ function walkElement(el, parentStyle, m, ctx2, out) {
307884
308329
  const paths = toVectorPaths(subs, local);
307885
308330
  const bounds2 = pathBounds(paths);
307886
308331
  if (!bounds2) return;
307887
- const fill = tag === "line" ? null : paintFor(style.fill ?? "black", style, ctx2, local, bounds2, len2(style["fill-opacity"], 1));
308332
+ const fill = tag2 === "line" ? null : paintFor(style.fill ?? "black", style, ctx2, local, bounds2, len2(style["fill-opacity"], 1));
307888
308333
  const strokePaint = paintFor(style.stroke, style, ctx2, local, bounds2, 1);
307889
308334
  const strokeWidth2 = len2(style["stroke-width"], 1) * scaleOf(local);
307890
308335
  const strokeColor = strokePaint?.type === "SOLID" ? strokePaint.color : strokePaint?.gradientStops?.[0]?.color;
@@ -307899,7 +308344,7 @@ function walkElement(el, parentStyle, m, ctx2, out) {
307899
308344
  if (!fill && !strokes.length) return;
307900
308345
  out.push({
307901
308346
  kind: "vector",
307902
- name: name2 || (tag === "path" ? "Vector" : tag[0].toUpperCase() + tag.slice(1)),
308347
+ name: name2 || (tag2 === "path" ? "Vector" : tag2[0].toUpperCase() + tag2.slice(1)),
307903
308348
  paths,
307904
308349
  fills: fill ? [fill] : [],
307905
308350
  strokes,
@@ -308353,7 +308798,7 @@ function sampleIndices(count2, n) {
308353
308798
  async function exportAnimation(renderer, doc2, spec, dest, opts = {}) {
308354
308799
  const { signal, onProgress } = opts;
308355
308800
  const { range: range3, width, height } = spec;
308356
- const started7 = performance.now();
308801
+ const started8 = performance.now();
308357
308802
  const heap0 = heapUsed();
308358
308803
  let peak = heap0 ?? 0;
308359
308804
  const noteHeap = () => {
@@ -308428,7 +308873,7 @@ async function exportAnimation(renderer, doc2, spec, dest, opts = {}) {
308428
308873
  });
308429
308874
  throw e;
308430
308875
  }
308431
- const ms2 = performance.now() - started7;
308876
+ const ms2 = performance.now() - started8;
308432
308877
  const heap1 = heapUsed();
308433
308878
  return {
308434
308879
  frames: range3.count,
@@ -309396,7 +309841,7 @@ function startCloudSync() {
309396
309841
  notice("View only \u2014 ask the owner for edit access");
309397
309842
  return;
309398
309843
  }
309399
- if (!activeLink || collab?.isApplyingRemote() || doc2.nodes === prev.nodes && doc2.compositions === prev.compositions && doc2.site === prev.site) return;
309844
+ if (!activeLink || collab?.isApplyingRemote() || doc2.nodes === prev.nodes && doc2.compositions === prev.compositions && doc2.site === prev.site && doc2.fonts === prev.fonts) return;
309400
309845
  let found = false;
309401
309846
  if (doc2.compositions !== prev.compositions) {
309402
309847
  for (const h of mediaHashes(doc2.compositions ?? {})) if (!uploaded.get(activeLink.key)?.has(h) && !pendingMedia.has(h)) {
@@ -309410,6 +309855,13 @@ function startCloudSync() {
309410
309855
  found = true;
309411
309856
  }
309412
309857
  }
309858
+ if (doc2.fonts !== prev.fonts) {
309859
+ for (const h of mediaHashes(doc2.fonts ?? [])) if (!uploaded.get(activeLink.key)?.has(h) && !pendingMedia.has(h)) {
309860
+ void sendMediaLive(`media://${h}`);
309861
+ pendingMedia.add(h);
309862
+ found = true;
309863
+ }
309864
+ }
309413
309865
  for (const id3 in doc2.nodes) {
309414
309866
  const n = doc2.nodes[id3];
309415
309867
  if (prev.nodes[id3] === n) continue;
@@ -309650,7 +310102,6 @@ async function dispatchShaped(key5, options) {
309650
310102
  var onViolation;
309651
310103
  var init_dispatch = __esm({
309652
310104
  "lib/commands/dispatch.ts"() {
309653
- "use strict";
309654
310105
  init_errors();
309655
310106
  init_registry();
309656
310107
  init_confirm();
@@ -309886,13 +310337,13 @@ function scaleRGBA(rgba, w, h, scale) {
309886
310337
  }
309887
310338
  return out;
309888
310339
  }
309889
- function tagFrameOrder(node2, tag) {
309890
- const from2 = tag ? Math.max(0, tag.from) : 0;
309891
- const to = tag ? Math.min(node2.frames.length - 1, tag.to) : node2.frames.length - 1;
310340
+ function tagFrameOrder(node2, tag2) {
310341
+ const from2 = tag2 ? Math.max(0, tag2.from) : 0;
310342
+ const to = tag2 ? Math.min(node2.frames.length - 1, tag2.to) : node2.frames.length - 1;
309892
310343
  const fwd = [];
309893
310344
  for (let i2 = from2; i2 <= to; i2++) fwd.push(i2);
309894
- if (!tag || tag.direction === "FORWARD") return fwd;
309895
- if (tag.direction === "REVERSE") return fwd.reverse();
310345
+ if (!tag2 || tag2.direction === "FORWARD") return fwd;
310346
+ if (tag2.direction === "REVERSE") return fwd.reverse();
309896
310347
  return fwd.length > 2 ? [...fwd, ...fwd.slice(1, -1).reverse()] : fwd;
309897
310348
  }
309898
310349
  function pixelFrameSVGBody(node2, frame2) {
@@ -313345,6 +313796,7 @@ function textNodeToSVG(node2, ctx2) {
313345
313796
  const resolved = resolveThreadNode(ctx2.doc.nodes, substitutePageTokens(resolveTextNodeStyles(node2, ctx2.styles), pageTokenContext(ctx2.doc.nodes, node2.id), ctx2.doc.settings?.pageNumbering), atlas, 1);
313346
313797
  if (resolved.textPath || resolved.textArea) return shapedTextToSVG(attachTextPath(resolved, ctx2.doc.nodes), ctx2);
313347
313798
  if (resolved.styledSegments?.length) return null;
313799
+ if (resolved.fontFamily && customFontRegistry.has(resolved.fontFamily)) return shapedTextToSVG(resolved, ctx2);
313348
313800
  const fillAttr = textFillAttr(resolved, node2, ctx2);
313349
313801
  if (fillAttr === null) return null;
313350
313802
  const layout2 = layoutText(resolved, atlas, 1);
@@ -313816,6 +314268,7 @@ var init_svg_export = __esm({
313816
314268
  init_variables();
313817
314269
  init_scene_graph();
313818
314270
  init_layout2();
314271
+ init_fonts();
313819
314272
  init_routing();
313820
314273
  init_native_registry();
313821
314274
  init_export();
@@ -314605,7 +315058,7 @@ function postscriptNameOf(font) {
314605
315058
  if (!off.length) return own2;
314606
315059
  return `${family}_${off.map((a) => `${Math.round(a.v * 100) / 100}${psSafe(a.tag)}`).join("_")}`;
314607
315060
  }
314608
- function fontWeightOf(font) {
315061
+ function fontWeightOf2(font) {
314609
315062
  const f2 = font;
314610
315063
  const k2 = f2.fvar?.axis?.findIndex((a) => a.axisTag.trim() === "wght") ?? -1;
314611
315064
  if (k2 >= 0 && f2.variationCoords?.length) return Math.round(f2.variationCoords[k2]);
@@ -314681,9 +315134,9 @@ var init_fonts2 = __esm({
314681
315134
  isCFF = true;
314682
315135
  }
314683
315136
  const scale = 1e3 / f2.unitsPerEm;
314684
- const tag = "PCSUB+";
314685
- const base = tag + postscriptNameOf(f2);
314686
- const weight = fontWeightOf(f2);
315137
+ const tag2 = "PCSUB+";
315138
+ const base = tag2 + postscriptNameOf(f2);
315139
+ const weight = fontWeightOf2(f2);
314687
315140
  const fileId = isCFF ? await this.w.flateStream("/Subtype /CIDFontType0C", program) : await this.w.flateStream(`/Length1 ${program.length}`, program);
314688
315141
  const bbox3 = f2.bbox;
314689
315142
  const descriptor = this.w.object(
@@ -314808,8 +315261,8 @@ function pageBox(node2, doc2, opts) {
314808
315261
  const bleedOn = opts.bleed ?? print2;
314809
315262
  const b = bleedOn ? (print2 ? node2.print?.bleed : void 0) ?? doc2.settings?.bleed ?? { top: 0, right: 0, bottom: 0, left: 0 } : { top: 0, right: 0, bottom: 0, left: 0 };
314810
315263
  const marks = !!opts.marks && print2;
314811
- const slug3 = bleedOn && print2 ? doc2.settings?.slug ?? 0 : 0;
314812
- const pad = (marks ? MARK_GAP + MARK_LEN : 0) + slug3;
315264
+ const slug4 = bleedOn && print2 ? doc2.settings?.slug ?? 0 : 0;
315265
+ const pad = (marks ? MARK_GAP + MARK_LEN : 0) + slug4;
314813
315266
  const media2 = { minX: trim2.minX - b.left - pad, minY: trim2.minY - b.top - pad, maxX: trim2.maxX + b.right + pad, maxY: trim2.maxY + b.bottom + pad };
314814
315267
  const bleed = { minX: trim2.minX - b.left, minY: trim2.minY - b.top, maxX: trim2.maxX + b.right, maxY: trim2.maxY + b.bottom };
314815
315268
  return { trim: trim2, bleed, media: media2, marks, print: print2 };
@@ -314895,10 +315348,10 @@ async function exportNodesToPDF(renderer, nodes, scaleOrOpts, doc2, styles) {
314895
315348
  const b = bleedOn ? root2.print?.bleed ?? doc2.settings?.bleed ?? { top: 0, right: 0, bottom: 0, left: 0 } : { top: 0, right: 0, bottom: 0, left: 0 };
314896
315349
  void crop;
314897
315350
  const pad = geo.marks ? MARK_GAP + MARK_LEN : 0;
314898
- const slug3 = doc2.settings?.slug ?? 0;
315351
+ const slug4 = doc2.settings?.slug ?? 0;
314899
315352
  geo.trim = { minX: 0, minY: 0, maxX: sheet.width, maxY: sheet.height };
314900
315353
  geo.bleed = { minX: -b.left, minY: -b.top, maxX: sheet.width + b.right, maxY: sheet.height + b.bottom };
314901
- geo.media = { minX: geo.bleed.minX - pad - slug3, minY: geo.bleed.minY - pad - slug3, maxX: geo.bleed.maxX + pad + slug3, maxY: geo.bleed.maxY + pad + slug3 };
315354
+ geo.media = { minX: geo.bleed.minX - pad - slug4, minY: geo.bleed.minY - pad - slug4, maxX: geo.bleed.maxX + pad + slug4, maxY: geo.bleed.maxY + pad + slug4 };
314902
315355
  }
314903
315356
  const dpi = opts.dpi ?? (geo.print ? 300 : 144);
314904
315357
  const res = { ats: !!opts.ats, color: color4, fonts, gstates: /* @__PURE__ */ new Map(), images: /* @__PURE__ */ new Map(), shadings: /* @__PURE__ */ new Map(), forms: [], reserve: () => w.reserve() };
@@ -315097,8 +315550,8 @@ async function runPixelExport(node2, setting, doc2) {
315097
315550
  await layers2.ensureAllPixelLayers(grid, doc2);
315098
315551
  const last3 = grid.frames.length - 1;
315099
315552
  const range3 = setting.gifRange && { from: Math.max(0, Math.min(last3, setting.gifRange.from)), to: Math.max(0, Math.min(last3, setting.gifRange.to)) };
315100
- const tag = range3 ? { id: "range", name: "range", from: Math.min(range3.from, range3.to), to: Math.max(range3.from, range3.to), direction: "FORWARD", color: "" } : grid.tags.find((t3) => t3.id === setting.gifTag) ?? null;
315101
- const bytes2 = px5.pixelGIF(grid, { scale, tag });
315553
+ const tag2 = range3 ? { id: "range", name: "range", from: Math.min(range3.from, range3.to), to: Math.max(range3.from, range3.to), direction: "FORWARD", color: "" } : grid.tags.find((t3) => t3.id === setting.gifTag) ?? null;
315554
+ const bytes2 = px5.pixelGIF(grid, { scale, tag: tag2 });
315102
315555
  downloadBlob(new Blob([bytes2.slice().buffer], { type: "image/gif" }), name2);
315103
315556
  return true;
315104
315557
  }
@@ -315597,7 +316050,6 @@ function videoPixelSize(resolution, aspect) {
315597
316050
  var VIDEO_ASPECTS, VIDEO_RESOLUTIONS, SEEDANCE_ASPECTS, range, VIDEO_MODELS, DEFAULT_VIDEO_MODEL, videoModel, VIDEO_LIMITS;
315598
316051
  var init_video_models = __esm({
315599
316052
  "lib/ai/video-models.ts"() {
315600
- "use strict";
315601
316053
  VIDEO_ASPECTS = ["16:9", "9:16", "1:1", "4:3", "3:4", "21:9"];
315602
316054
  VIDEO_RESOLUTIONS = ["480p", "720p", "1080p"];
315603
316055
  SEEDANCE_ASPECTS = ["16:9", "9:16", "1:1", "4:3", "3:4", "21:9"];
@@ -315751,9 +316203,9 @@ async function requestVideo(req, opts = {}, rt = {}) {
315751
316203
  const t0 = now2();
315752
316204
  const report2 = (phase, spec2) => opts.onProgress?.({ phase, elapsed: now2() - t0, spec: spec2 });
315753
316205
  report2("starting");
315754
- const started7 = await (await aiFetch("/api/ai/video", { json: req, signal: opts.signal })).json();
315755
- const { job, spec } = started7;
315756
- const warnings = [...started7.warnings ?? []];
316206
+ const started8 = await (await aiFetch("/api/ai/video", { json: req, signal: opts.signal })).json();
316207
+ const { job, spec } = started8;
316208
+ const warnings = [...started8.warnings ?? []];
315757
316209
  let misses = 0;
315758
316210
  try {
315759
316211
  for (; ; ) {
@@ -321147,7 +321599,7 @@ function pictureOf(node2) {
321147
321599
  function elementOf(node2, ctx2) {
321148
321600
  const motion = ctx2.still ? void 0 : node2.motion;
321149
321601
  const spec = ctx2.spec ?? null;
321150
- const tag = node2.input ? node2.input.tag : node2.link ? "a" : node2.tag ?? (node2.text ? "p" : "div");
321602
+ const tag2 = node2.input ? node2.input.tag : node2.link ? "a" : node2.tag ?? (node2.text ? "p" : "div");
321151
321603
  const attrs = { ...node2.attrs };
321152
321604
  if (node2.input) Object.assign(attrs, node2.input.attrs);
321153
321605
  if (node2.link && !node2.input) {
@@ -321158,10 +321610,10 @@ function elementOf(node2, ctx2) {
321158
321610
  }
321159
321611
  }
321160
321612
  return {
321161
- tag,
321613
+ tag: tag2,
321162
321614
  attrs,
321163
321615
  // A tag's own look (a button's border, a link's underline, a list's bullets) is not the layer's: under its declarations.
321164
- style: { ...node2.link || node2.tag || node2.input ? TAG_RESET[tag] : void 0, ...placementStyle(node2, ctx2.isRoot), ...node2.style, ...motion ? motion.style : {}, ...hiddenAtStart(spec, node2) ? HIDDEN_AT_START : {} },
321616
+ style: { ...node2.link || node2.tag || node2.input ? TAG_RESET[tag2] : void 0, ...placementStyle(node2, ctx2.isRoot), ...node2.style, ...motion ? motion.style : {}, ...hiddenAtStart(spec, node2) ? HIDDEN_AT_START : {} },
321165
321617
  // A field's words are its placeholder (an attribute), not its content.
321166
321618
  ...node2.text && !node2.input ? { text: node2.text.characters } : {},
321167
321619
  ...node2.text && node2.runs && !node2.input ? { runs: node2.runs } : {},
@@ -321239,7 +321691,7 @@ function instanceWebMotion(doc2, instance, style) {
321239
321691
  const ids2 = /* @__PURE__ */ new Set();
321240
321692
  for (const s of samples) for (const id3 in s) if (id3.includes("::")) ids2.add(id3);
321241
321693
  const children = /* @__PURE__ */ new Map();
321242
- const tag = instance.id.replace(/[^a-zA-Z0-9]/g, "").slice(-6);
321694
+ const tag2 = instance.id.replace(/[^a-zA-Z0-9]/g, "").slice(-6);
321243
321695
  let n = 0;
321244
321696
  for (const id3 of ids2) {
321245
321697
  const restNode = resolveVirtualNode2(doc2.nodes, id3);
@@ -321247,7 +321699,7 @@ function instanceWebMotion(doc2, instance, style) {
321247
321699
  const frames = keyframesOf(times2, samples.map((s) => declarationsOf(s[id3] ?? restNode, restNode, style)), len3);
321248
321700
  if (!frames) continue;
321249
321701
  children.set(id3, {
321250
- name: `motion-${tag}-${n++}`,
321702
+ name: `motion-${tag2}-${n++}`,
321251
321703
  frames,
321252
321704
  durationMs: m.speed > 0 ? Math.round(len3 / m.speed) : 0,
321253
321705
  delayMs: Math.round(m.start),
@@ -321590,7 +322042,7 @@ function frameWebMotion(doc2, frameId, style) {
321590
322042
  for (const p2 of poses) for (const id3 in p2) if (id3 !== frameId && p2[id3] !== nodes[id3]) ids2.add(id3);
321591
322043
  const loops = frameRunsOn(nodes, frameId);
321592
322044
  const out = /* @__PURE__ */ new Map();
321593
- const tag = frameId.replace(/[^a-zA-Z0-9]/g, "").slice(-6);
322045
+ const tag2 = frameId.replace(/[^a-zA-Z0-9]/g, "").slice(-6);
321594
322046
  let n = 0;
321595
322047
  for (const id3 of ids2) {
321596
322048
  const rest = id3.includes("::") ? resolveVirtualNode2(nodes, id3) : nodes[id3];
@@ -321598,7 +322050,7 @@ function frameWebMotion(doc2, frameId, style) {
321598
322050
  const frames = keyframesOf(times2, poses.map((p2) => declarationsOf(p2[id3] ?? rest, rest, style)), len3);
321599
322051
  if (!frames) continue;
321600
322052
  out.set(id3, {
321601
- name: `timeline-${tag}-${n++}`,
322053
+ name: `timeline-${tag2}-${n++}`,
321602
322054
  frames,
321603
322055
  durationMs: Math.round(len3),
321604
322056
  delayMs: 0,
@@ -322036,8 +322488,8 @@ function buildPlainTree(doc2, nodeId2, opts = {}, start2, hooks = {}) {
322036
322488
  if (slugField) return { link: filled2, href: `${base === "/" ? "" : base}/${itemMark(fieldKey(slugField.name))}`, screen: filled2.frameId };
322037
322489
  const slugs = recordSlugs(doc2, of);
322038
322490
  const rec = it?.collection.id === of ? it.record.id : slugs.keys().next().value;
322039
- const slug3 = rec ? slugs.get(rec) : void 0;
322040
- return slug3 ? { link: filled2, href: `${base === "/" ? "" : base}/${slug3}`, screen: `${filled2.frameId}~${rec}` } : { link: filled2, href: null };
322491
+ const slug4 = rec ? slugs.get(rec) : void 0;
322492
+ return slug4 ? { link: filled2, href: `${base === "/" ? "" : base}/${slug4}`, screen: `${filled2.frameId}~${rec}` } : { link: filled2, href: null };
322041
322493
  }
322042
322494
  return { link: filled2, href: base ?? null, screen: filled2.frameId };
322043
322495
  }
@@ -322156,20 +322608,20 @@ function buildPlainTree(doc2, nodeId2, opts = {}, start2, hooks = {}) {
322156
322608
  const control0 = fields.get(raw.id);
322157
322609
  const field = control0 && item && control0.value !== void 0 && hasItemToken(control0.value) ? { ...control0, value: itemText(control0.value, item.collection, item.record) } : control0;
322158
322610
  if (field) {
322159
- const tag = field.kind === "TEXTAREA" ? "textarea" : field.kind === "SELECT" ? "select" : "input";
322611
+ const tag2 = field.kind === "TEXTAREA" ? "textarea" : field.kind === "SELECT" ? "select" : "input";
322160
322612
  const words = node2.characters;
322161
322613
  web.input = {
322162
- tag,
322614
+ tag: tag2,
322163
322615
  attrs: {
322164
- ...tag === "input" ? { type: field.inputType ?? "text" } : {},
322616
+ ...tag2 === "input" ? { type: field.inputType ?? "text" } : {},
322165
322617
  ...field.name ? { name: field.name } : {},
322166
- ...tag !== "select" && (field.placeholder ?? words) ? { placeholder: field.placeholder ?? words } : {},
322618
+ ...tag2 !== "select" && (field.placeholder ?? words) ? { placeholder: field.placeholder ?? words } : {},
322167
322619
  ...field.required ? { required: "" } : {},
322168
- ...tag === "input" && field.value !== void 0 ? { value: field.value } : {},
322620
+ ...tag2 === "input" && field.value !== void 0 ? { value: field.value } : {},
322169
322621
  "aria-label": node2.semantics?.label ?? field.placeholder ?? field.name ?? web.name
322170
322622
  },
322171
- ...tag === "select" ? { options: field.options ?? [] } : {},
322172
- ...tag !== "input" && field.value !== void 0 ? { value: field.value } : {},
322623
+ ...tag2 === "select" ? { options: field.options ?? [] } : {},
322624
+ ...tag2 !== "input" && field.value !== void 0 ? { value: field.value } : {},
322173
322625
  ...field.variableId ? { variable: field.variableId } : {}
322174
322626
  };
322175
322627
  }
@@ -324478,15 +324930,15 @@ var init_lottie = __esm({
324478
324930
  function externalizeBitmaps(site) {
324479
324931
  const files = [];
324480
324932
  const names = /* @__PURE__ */ new Map();
324481
- const fileFor = (type, base644) => {
324482
- const hit = names.get(base644);
324933
+ const fileFor = (type, base645) => {
324934
+ const hit = names.get(base645);
324483
324935
  if (hit) return hit;
324484
324936
  const name2 = `${ASSET_DIR}img-${names.size + 1}.${EXT[type]}`;
324485
- names.set(base644, name2);
324486
- files.push({ path: name2, content: Uint8Array.from(atob(base644), (c2) => c2.charCodeAt(0)) });
324937
+ names.set(base645, name2);
324938
+ files.push({ path: name2, content: Uint8Array.from(atob(base645), (c2) => c2.charCodeAt(0)) });
324487
324939
  return name2;
324488
324940
  };
324489
- const move = (text) => text.replace(DATA, (_m, type, base644) => fileFor(type, base644));
324941
+ const move = (text) => text.replace(DATA, (_m, type, base645) => fileFor(type, base645));
324490
324942
  for (const page of site.pages) {
324491
324943
  eachNode(page.tree.root, (n) => {
324492
324944
  const a = n.asset;
@@ -324625,11 +325077,21 @@ function fontsURL(families) {
324625
325077
  const q = [...families].map(([f2, w]) => `family=${encodeURIComponent(f2).replace(/%20/g, "+")}:wght@${w.join(";")}`);
324626
325078
  return q.length ? `https://fonts.googleapis.com/css2?${q.join("&")}&display=swap` : null;
324627
325079
  }
324628
- var fontsHref;
325080
+ function fontFaceRules(faces2) {
325081
+ return (faces2 ?? []).map((f2) => `@font-face {
325082
+ font-family: ${cssString(f2.family)};
325083
+ src: url(${cssString(f2.url)}) format("${f2.format}");
325084
+ font-weight: ${f2.weight};
325085
+ font-style: ${f2.style};
325086
+ font-display: swap;
325087
+ }`);
325088
+ }
325089
+ var fontsHref, cssString;
324629
325090
  var init_fonts3 = __esm({
324630
325091
  "lib/io/web/fonts.ts"() {
324631
325092
  "use strict";
324632
- fontsHref = (tree) => fontsURL(fontFamilies(tree));
325093
+ fontsHref = (tree) => fontsURL([...fontFamilies(tree)].filter(([family]) => !tree.fontFaces?.some((f2) => f2.family === family)));
325094
+ cssString = (s) => `"${s.replace(/["\\]/g, "\\$&").replace(/[\n\r]/g, " ").replace(/</g, "\\3c ")}"`;
324633
325095
  }
324634
325096
  });
324635
325097
 
@@ -324672,7 +325134,7 @@ function actionData(ix) {
324672
325134
  return { k: "orbit", t: a.target, tt: a.tiltTarget, d: a.degreesPerPx, tilt: a.tilt ? 1 : 0, lo: a.tiltRange[0], hi: a.tiltRange[1] };
324673
325135
  }
324674
325136
  var declarations;
324675
- var init_runtime3 = __esm({
325137
+ var init_runtime4 = __esm({
324676
325138
  "lib/io/web/runtime.ts"() {
324677
325139
  "use strict";
324678
325140
  init_runtimes();
@@ -324706,7 +325168,7 @@ function serializeHTML(tree, opts = {}) {
324706
325168
  const emit8 = (node2, depth2, isRoot) => {
324707
325169
  const indent = " ".repeat(depth2);
324708
325170
  const el = elementOf(node2, { isRoot, spec, listened, still: opts.inline });
324709
- const { tag, style } = el;
325171
+ const { tag: tag2, style } = el;
324710
325172
  let attrs;
324711
325173
  if (opts.inline || el.pc) {
324712
325174
  attrs = ` style="${escapeHTML(styleMapToInline(style))}"`;
@@ -324746,13 +325208,13 @@ ${styleMapToCSSText(shared, " ")}
324746
325208
  const body2 = el.input.tag === "select" ? (el.input.options ?? []).map((o) => `
324747
325209
  ${indent} <option value="${escapeHTML(o.value)}"${o.value === el.input.value ? " selected" : ""}>${escapeHTML(o.label)}</option>`).join("") + `
324748
325210
  ${indent}` : escapeHTML(el.input.value ?? "");
324749
- return `${indent}<${tag}${attrs}>${body2}</${tag}>`;
325211
+ return `${indent}<${tag2}${attrs}>${body2}</${tag2}>`;
324750
325212
  }
324751
325213
  const check2 = el.check ? `
324752
325214
  ${indent} <input${Object.entries(el.check.attrs).map(([k2, v]) => ` ${k2}="${escapeHTML(v)}"`).join("")} style="${CHECK_STYLE}" />` : "";
324753
- if (el.html !== void 0) return `${indent}<${tag}${attrs}>${el.html}</${tag}>`;
325215
+ if (el.html !== void 0) return `${indent}<${tag2}${attrs}>${el.html}</${tag2}>`;
324754
325216
  const words = el.runs ? el.runs.map(runMarkup).join("") : el.text !== void 0 ? escapeHTML(el.text) : null;
324755
- if (words !== null && !el.picture && !node2.children.length && !node2.repeat && !check2 && !sends?.fields) return `${indent}<${tag}${attrs}>${words}</${tag}>`;
325217
+ if (words !== null && !el.picture && !node2.children.length && !node2.repeat && !check2 && !sends?.fields) return `${indent}<${tag2}${attrs}>${words}</${tag2}>`;
324756
325218
  const inner = [
324757
325219
  el.runs ? `
324758
325220
  ${indent} ${el.runs.map(runMarkup).join("")}` : el.text !== void 0 ? `
@@ -324763,8 +325225,8 @@ ${indent} ${sends.fields}`] : [],
324763
325225
  ...listed(node2, depth2),
324764
325226
  check2
324765
325227
  ].join("");
324766
- return inner ? `${indent}<${tag}${attrs}>${inner}
324767
- ${indent}</${tag}>` : `${indent}<${tag}${attrs}></${tag}>`;
325228
+ return inner ? `${indent}<${tag2}${attrs}>${inner}
325229
+ ${indent}</${tag2}>` : `${indent}<${tag2}${attrs}></${tag2}>`;
324768
325230
  };
324769
325231
  const listed = (node2, depth2) => {
324770
325232
  const loop = node2.repeat && opts.lists?.(node2);
@@ -324801,7 +325263,9 @@ ${body}${note2}${script2}`;
324801
325263
  '<meta name="viewport" content="width=device-width, initial-scale=1" />',
324802
325264
  `<title>${escapeHTML(opts.title ?? tree.root.name)}</title>`,
324803
325265
  ...fonts ? [`<link rel="stylesheet" href="${escapeHTML(fonts)}" />`] : [],
324804
- ...opts.inline ? [] : ["<style>", "body { margin: 0; }", ...rules, "</style>"],
325266
+ // The file's own fonts, shipped with the page (lib/fonts/web-fonts.ts).
325267
+ ...opts.inline && tree.fontFaces?.length ? ["<style>", ...fontFaceRules(tree.fontFaces), "</style>"] : [],
325268
+ ...opts.inline ? [] : ["<style>", "body { margin: 0; }", ...fontFaceRules(tree.fontFaces), ...rules, "</style>"],
324805
325269
  "</head>",
324806
325270
  "<body>",
324807
325271
  body + note2 + script2,
@@ -324831,7 +325295,7 @@ var init_html = __esm({
324831
325295
  "use strict";
324832
325296
  init_css();
324833
325297
  init_motion();
324834
- init_runtime3();
325298
+ init_runtime4();
324835
325299
  init_state_machine2();
324836
325300
  init_element();
324837
325301
  init_fonts3();
@@ -324906,9 +325370,11 @@ var init_files = __esm({
324906
325370
  // lib/io/web/project/static.ts
324907
325371
  function pageHTML(site, page, lang, lost = false, origin) {
324908
325372
  const up = lost ? "/" : routeUp(page.route);
324909
- const fonts = fontsURL(site.fonts.map((f2) => [f2.family, f2.weights]));
325373
+ const fonts = fontsURL(site.fonts.filter((f2) => !site.fontFaces?.some((s) => s.family === f2.family)).map((f2) => [f2.family, f2.weights]));
324910
325374
  const rules = [
324911
325375
  "html,body{margin:0;height:100%}#pc-root{min-height:100%;position:relative}*{box-sizing:border-box}",
325376
+ // The file's own fonts, shipped in the site's fonts/ folder.
325377
+ ...fontFaceRules(site.fontFaces?.map((f2) => ({ ...f2, url: `${up}${f2.url}` }))),
324912
325378
  ...site.tokens ? tokensCSS(site.tokens) : [],
324913
325379
  ...page.media ?? site.pages.find((p2) => p2.screen && p2.screen === page.screen && p2.media)?.media ?? []
324914
325380
  ];
@@ -324983,15 +325449,15 @@ function serializeTailwind(tree) {
324983
325449
  const emit8 = (node2, depth2, isRoot) => {
324984
325450
  const indent = " ".repeat(depth2);
324985
325451
  const cls = tailwindFor({ ...placementStyle(node2, isRoot), ...node2.style });
324986
- const tag = node2.text ? "p" : "div";
325452
+ const tag2 = node2.text ? "p" : "div";
324987
325453
  const inner = [];
324988
325454
  if (node2.text) inner.push(`${indent} ${escapeHTML(node2.text.characters)}`);
324989
325455
  const picture2 = pictureOf(node2);
324990
325456
  if (picture2) inner.push(picture2.kind === "svg" ? `${indent} ${picture2.svg}` : picture2.kind === "img" ? `${indent} <img src="${picture2.src}" width="${node2.width}" height="${node2.height}" alt="${escapeHTML(altFor(node2))}" />` : `${indent} <!-- ${picture2.reason} -->`);
324991
325457
  for (const c2 of node2.children) inner.push(emit8(c2, depth2 + 1, false));
324992
- return inner.length ? `${indent}<${tag} class="${cls}">
325458
+ return inner.length ? `${indent}<${tag2} class="${cls}">
324993
325459
  ${inner.join("\n")}
324994
- ${indent}</${tag}>` : `${indent}<${tag} class="${cls}"></${tag}>`;
325460
+ ${indent}</${tag2}>` : `${indent}<${tag2} class="${cls}"></${tag2}>`;
324995
325461
  };
324996
325462
  return emit8(tree.root, 0, true);
324997
325463
  }
@@ -325073,7 +325539,7 @@ ${pad} )}`).join("\n")}
325073
325539
  ${pad}</>`;
325074
325540
  }
325075
325541
  const el = elementOf(node2, { isRoot, spec, listened: machine ? listened : void 0 });
325076
- const { tag } = el;
325542
+ const { tag: tag2 } = el;
325077
325543
  const bound = opts.behaviour?.bindings(node2.id) ?? null;
325078
325544
  const fonted = opts.fontFamily && el.style["font-family"] ? { ...el.style, "font-family": opts.fontFamily(el.style["font-family"]) } : el.style;
325079
325545
  const style = node2.hidden && !bound?.visible && !el.pc ? { ...fonted, display: "none" } : fonted;
@@ -325090,7 +325556,7 @@ ${pad}</>`;
325090
325556
  };
325091
325557
  const handlers = opts.behaviour?.events(node2.id, { variant: chosen && layerId(node2.id) === chosen.instance ? node2.variant : void 0, changeTo }) ?? {};
325092
325558
  for (const [event, handler] of Object.entries(handlers)) attrs += ` ${event}={${inItem ? handler.split(ITEM_ID).join("item.id") : handler}}`;
325093
- if (handlers.onClick && !NATIVELY_INTERACTIVE.has(tag)) attrs += ` role="button" tabIndex={0} onKeyDown={e => { if (e.key === 'Enter' || e.key === ' ') { e.preventDefault(); e.currentTarget.click() } }}`;
325559
+ if (handlers.onClick && !NATIVELY_INTERACTIVE.has(tag2)) attrs += ` role="button" tabIndex={0} onKeyDown={e => { if (e.key === 'Enter' || e.key === ' ') { e.preventDefault(); e.currentTarget.click() } }}`;
325094
325560
  const sends = node2.action ? opts.formAction?.(node2) : null;
325095
325561
  if (sends) attrs += ` action={${sends}}`;
325096
325562
  if (el.keyframes) attrs += ' data-motion-child=""';
@@ -325106,7 +325572,7 @@ ${pad}</>`;
325106
325572
  if (el.input) return `${pad}<select${attrs}${el.input.value ? fieldValue(el.input.value) : ""}>
325107
325573
  ${(el.input.options ?? []).map((o) => `${pad} <option value=${JSON.stringify(o.value)}>${jsxText(o.label)}</option>`).join("\n")}
325108
325574
  ${pad}</select>`;
325109
- if (el.html !== void 0) return `${pad}<${tag}${attrs} dangerouslySetInnerHTML={{ __html: ${JSON.stringify(el.html)} }} />`;
325575
+ if (el.html !== void 0) return `${pad}<${tag2}${attrs} dangerouslySetInnerHTML={{ __html: ${JSON.stringify(el.html)} }} />`;
325110
325576
  const inner = [];
325111
325577
  const drawn2 = node2.code ? opts.code?.(node2) : null;
325112
325578
  if (drawn2) inner.push(`${pad} ${drawn2}`);
@@ -325134,9 +325600,9 @@ ${pad} ))}`);
325134
325600
  else for (const c2 of node2.children) inner.push(emit8(c2, depth2 + 1, false));
325135
325601
  if (el.check) inner.push(`${pad} <input${Object.entries(el.check.attrs).map(([k2, v]) => jsxAttr(k2, v)).join("")} style={{ position: 'absolute', inset: 0, width: '100%', height: '100%', margin: 0, opacity: 0, cursor: 'pointer' }} />`);
325136
325602
  if (isRoot && sheetNeeded()) inner.unshift(`${pad} <style>{KEYFRAMES}</style>`);
325137
- const whole = !inner.length ? `${pad}<${tag}${attrs} />` : `${pad}<${tag}${attrs}>
325603
+ const whole = !inner.length ? `${pad}<${tag2}${attrs} />` : `${pad}<${tag2}${attrs}>
325138
325604
  ${inner.join("\n")}
325139
- ${pad}</${tag}>`;
325605
+ ${pad}</${tag2}>`;
325140
325606
  return bound?.visible && !isRoot ? `${pad}{${bound.visible} && (
325141
325607
  ${whole}
325142
325608
  ${pad})}` : whole;
@@ -325198,9 +325664,9 @@ ${body}
325198
325664
  }`;
325199
325665
  }
325200
325666
  function elementType(node2) {
325201
- const tag = elementOf(node2, { isRoot: true }).tag;
325667
+ const tag2 = elementOf(node2, { isRoot: true }).tag;
325202
325668
  const known = { div: "HTMLDivElement", section: "HTMLElement", main: "HTMLElement", header: "HTMLElement", footer: "HTMLElement", nav: "HTMLElement", article: "HTMLElement", aside: "HTMLElement", form: "HTMLFormElement", a: "HTMLAnchorElement", button: "HTMLButtonElement", ul: "HTMLUListElement", li: "HTMLLIElement" };
325203
- return known[tag] ?? "HTMLElement";
325669
+ return known[tag2] ?? "HTMLElement";
325204
325670
  }
325205
325671
  var jsxText, template, JSX_ATTR, NATIVELY_INTERACTIVE, BOOLEAN_ATTR, jsxAttr, itemJsx, itemAttr, itemStyle, ITEM_ID;
325206
325672
  var init_react2 = __esm({
@@ -325212,7 +325678,7 @@ var init_react2 = __esm({
325212
325678
  init_fonts3();
325213
325679
  init_naming();
325214
325680
  init_motion();
325215
- init_runtime3();
325681
+ init_runtime4();
325216
325682
  init_state_machine2();
325217
325683
  init_tailwind();
325218
325684
  jsxText = (s) => `{'${s.replace(/\\/g, "\\\\").replace(/'/g, "\\'").replace(/\n/g, "\\n")}'}`;
@@ -325935,7 +326401,7 @@ var init_package = __esm({
325935
326401
  "packages/runtime/package.json"() {
325936
326402
  package_default = {
325937
326403
  name: "@popcraft/runtime",
325938
- version: "0.28.0",
326404
+ version: "0.29.0",
325939
326405
  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.",
325940
326406
  license: "MIT",
325941
326407
  homepage: "https://popcraft.app/docs/exporting/nextjs",
@@ -326026,8 +326492,8 @@ function unique(base, taken) {
326026
326492
  }
326027
326493
  function projectFonts(site) {
326028
326494
  return site.fonts.filter((f2) => googleSet.has(f2.family)).map((f2) => {
326029
- const slug3 = f2.family.toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-|-$/g, "");
326030
- return { family: f2.family, ident: f2.family.replace(/[^A-Za-z0-9]+/g, "_"), variable: `--font-${slug3}`, weights: f2.weights, variableFont: !NON_VARIABLE_FONTS.has(f2.family) };
326495
+ const slug4 = f2.family.toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-|-$/g, "");
326496
+ return { family: f2.family, ident: f2.family.replace(/[^A-Za-z0-9]+/g, "_"), variable: `--font-${slug4}`, weights: f2.weights, variableFont: !NON_VARIABLE_FONTS.has(f2.family) };
326031
326497
  });
326032
326498
  }
326033
326499
  function nextProjectFiles(site, doc2, opts = {}) {
@@ -340453,7 +340919,7 @@ var require_trace_mapping_umd = __commonJS({
340453
340919
  return a[COLUMN] - b[COLUMN];
340454
340920
  }
340455
340921
  function buildBySources(decoded, memos) {
340456
- const sources = memos.map(() => []);
340922
+ const sources2 = memos.map(() => []);
340457
340923
  for (let i2 = 0; i2 < decoded.length; i2++) {
340458
340924
  const line = decoded[i2];
340459
340925
  for (let j = 0; j < line.length; j++) {
@@ -340462,19 +340928,19 @@ var require_trace_mapping_umd = __commonJS({
340462
340928
  const sourceIndex2 = seg[SOURCES_INDEX];
340463
340929
  const sourceLine = seg[SOURCE_LINE];
340464
340930
  const sourceColumn = seg[SOURCE_COLUMN];
340465
- const source3 = sources[sourceIndex2];
340931
+ const source3 = sources2[sourceIndex2];
340466
340932
  const segs = source3[sourceLine] || (source3[sourceLine] = []);
340467
340933
  segs.push([sourceColumn, i2, seg[COLUMN]]);
340468
340934
  }
340469
340935
  }
340470
- for (let i2 = 0; i2 < sources.length; i2++) {
340471
- const source3 = sources[i2];
340936
+ for (let i2 = 0; i2 < sources2.length; i2++) {
340937
+ const source3 = sources2[i2];
340472
340938
  for (let j = 0; j < source3.length; j++) {
340473
340939
  const line = source3[j];
340474
340940
  if (line) line.sort(sortComparator);
340475
340941
  }
340476
340942
  }
340477
- return sources;
340943
+ return sources2;
340478
340944
  }
340479
340945
  var found = false;
340480
340946
  function binarySearch(haystack, needle, low, high) {
@@ -340541,7 +341007,7 @@ var require_trace_mapping_umd = __commonJS({
340541
341007
  return new TraceMap(parsed2, mapUrl);
340542
341008
  }
340543
341009
  const mappings = [];
340544
- const sources = [];
341010
+ const sources2 = [];
340545
341011
  const sourcesContent = [];
340546
341012
  const names = [];
340547
341013
  const ignoreList = [];
@@ -340549,7 +341015,7 @@ var require_trace_mapping_umd = __commonJS({
340549
341015
  parsed2,
340550
341016
  mapUrl,
340551
341017
  mappings,
340552
- sources,
341018
+ sources2,
340553
341019
  sourcesContent,
340554
341020
  names,
340555
341021
  ignoreList,
@@ -340562,14 +341028,14 @@ var require_trace_mapping_umd = __commonJS({
340562
341028
  version: 3,
340563
341029
  file: parsed2.file,
340564
341030
  names,
340565
- sources,
341031
+ sources: sources2,
340566
341032
  sourcesContent,
340567
341033
  mappings,
340568
341034
  ignoreList
340569
341035
  };
340570
341036
  return presortedDecodedMap(joined);
340571
341037
  };
340572
- function recurse(input2, mapUrl, mappings, sources, sourcesContent, names, ignoreList, lineOffset, columnOffset, stopLine, stopColumn) {
341038
+ function recurse(input2, mapUrl, mappings, sources2, sourcesContent, names, ignoreList, lineOffset, columnOffset, stopLine, stopColumn) {
340573
341039
  const { sections } = input2;
340574
341040
  for (let i2 = 0; i2 < sections.length; i2++) {
340575
341041
  const { map: map2, offset } = sections[i2];
@@ -340588,7 +341054,7 @@ var require_trace_mapping_umd = __commonJS({
340588
341054
  map2,
340589
341055
  mapUrl,
340590
341056
  mappings,
340591
- sources,
341057
+ sources2,
340592
341058
  sourcesContent,
340593
341059
  names,
340594
341060
  ignoreList,
@@ -340599,15 +341065,15 @@ var require_trace_mapping_umd = __commonJS({
340599
341065
  );
340600
341066
  }
340601
341067
  }
340602
- function addSection(input2, mapUrl, mappings, sources, sourcesContent, names, ignoreList, lineOffset, columnOffset, stopLine, stopColumn) {
341068
+ function addSection(input2, mapUrl, mappings, sources2, sourcesContent, names, ignoreList, lineOffset, columnOffset, stopLine, stopColumn) {
340603
341069
  const parsed2 = parse7(input2);
340604
341070
  if ("sections" in parsed2) return recurse(...arguments);
340605
341071
  const map2 = new TraceMap(parsed2, mapUrl);
340606
- const sourcesOffset = sources.length;
341072
+ const sourcesOffset = sources2.length;
340607
341073
  const namesOffset = names.length;
340608
341074
  const decoded = decodedMappings(map2);
340609
341075
  const { resolvedSources, sourcesContent: contents, ignoreList: ignores } = map2;
340610
- append(sources, resolvedSources);
341076
+ append(sources2, resolvedSources);
340611
341077
  append(names, map2.names);
340612
341078
  if (contents) append(sourcesContent, contents);
340613
341079
  else for (let i2 = 0; i2 < resolvedSources.length; i2++) sourcesContent.push(null);
@@ -340651,16 +341117,16 @@ var require_trace_mapping_umd = __commonJS({
340651
341117
  const isString2 = typeof map2 === "string";
340652
341118
  if (!isString2 && map2._decodedMemo) return map2;
340653
341119
  const parsed2 = parse7(map2);
340654
- const { version: version7, file: file2, names, sourceRoot, sources, sourcesContent } = parsed2;
341120
+ const { version: version7, file: file2, names, sourceRoot, sources: sources2, sourcesContent } = parsed2;
340655
341121
  this.version = version7;
340656
341122
  this.file = file2;
340657
341123
  this.names = names || [];
340658
341124
  this.sourceRoot = sourceRoot;
340659
- this.sources = sources;
341125
+ this.sources = sources2;
340660
341126
  this.sourcesContent = sourcesContent;
340661
341127
  this.ignoreList = parsed2.ignoreList || parsed2.x_google_ignoreList || void 0;
340662
341128
  const resolve6 = resolver(mapUrl, sourceRoot);
340663
- this.resolvedSources = sources.map(resolve6);
341129
+ this.resolvedSources = sources2.map(resolve6);
340664
341130
  const { mappings } = parsed2;
340665
341131
  if (typeof mappings === "string") {
340666
341132
  this._encoded = mappings;
@@ -340767,8 +341233,8 @@ var require_trace_mapping_umd = __commonJS({
340767
341233
  }
340768
341234
  }
340769
341235
  function sourceIndex(map2, source3) {
340770
- const { sources, resolvedSources } = map2;
340771
- let index2 = sources.indexOf(source3);
341236
+ const { sources: sources2, resolvedSources } = map2;
341237
+ let index2 = sources2.indexOf(source3);
340772
341238
  if (index2 === -1) index2 = resolvedSources.indexOf(source3);
340773
341239
  return index2;
340774
341240
  }
@@ -340840,11 +341306,11 @@ var require_trace_mapping_umd = __commonJS({
340840
341306
  line--;
340841
341307
  if (line < 0) throw new Error(LINE_GTR_ZERO);
340842
341308
  if (column < 0) throw new Error(COL_GTR_EQ_ZERO);
340843
- const { sources, resolvedSources } = map2;
340844
- let sourceIndex2 = sources.indexOf(source3);
341309
+ const { sources: sources2, resolvedSources } = map2;
341310
+ let sourceIndex2 = sources2.indexOf(source3);
340845
341311
  if (sourceIndex2 === -1) sourceIndex2 = resolvedSources.indexOf(source3);
340846
341312
  if (sourceIndex2 === -1) return all4 ? [] : GMapping(null, null);
340847
- const bySourceMemos = (_a4 = cast(map2))._bySourceMemos || (_a4._bySourceMemos = sources.map(memoizedState));
341313
+ const bySourceMemos = (_a4 = cast(map2))._bySourceMemos || (_a4._bySourceMemos = sources2.map(memoizedState));
340848
341314
  const generated = (_b2 = cast(map2))._bySources || (_b2._bySources = buildBySources(decodedMappings(map2), bySourceMemos));
340849
341315
  const segments = generated[sourceIndex2][line];
340850
341316
  if (segments == null) return all4 ? [] : GMapping(null, null);
@@ -341024,21 +341490,21 @@ var require_gen_mapping_umd = __commonJS({
341024
341490
  };
341025
341491
  function setSourceContent(map2, source3, content) {
341026
341492
  const {
341027
- _sources: sources,
341493
+ _sources: sources2,
341028
341494
  _sourcesContent: sourcesContent
341029
341495
  // _originalScopes: originalScopes,
341030
341496
  } = cast2(map2);
341031
- const index2 = put3(sources, source3);
341497
+ const index2 = put3(sources2, source3);
341032
341498
  sourcesContent[index2] = content;
341033
341499
  }
341034
341500
  function setIgnore(map2, source3, ignore = true) {
341035
341501
  const {
341036
- _sources: sources,
341502
+ _sources: sources2,
341037
341503
  _sourcesContent: sourcesContent,
341038
341504
  _ignoreList: ignoreList
341039
341505
  // _originalScopes: originalScopes,
341040
341506
  } = cast2(map2);
341041
- const index2 = put3(sources, source3);
341507
+ const index2 = put3(sources2, source3);
341042
341508
  if (index2 === sourcesContent.length) sourcesContent[index2] = null;
341043
341509
  if (ignore) put3(ignoreList, index2);
341044
341510
  else remove(ignoreList, index2);
@@ -341046,7 +341512,7 @@ var require_gen_mapping_umd = __commonJS({
341046
341512
  function toDecodedMap(map2) {
341047
341513
  const {
341048
341514
  _mappings: mappings,
341049
- _sources: sources,
341515
+ _sources: sources2,
341050
341516
  _sourcesContent: sourcesContent,
341051
341517
  _names: names,
341052
341518
  _ignoreList: ignoreList
@@ -341059,7 +341525,7 @@ var require_gen_mapping_umd = __commonJS({
341059
341525
  file: map2.file || void 0,
341060
341526
  names: names.array,
341061
341527
  sourceRoot: map2.sourceRoot || void 0,
341062
- sources: sources.array,
341528
+ sources: sources2.array,
341063
341529
  sourcesContent,
341064
341530
  mappings,
341065
341531
  // originalScopes,
@@ -341087,7 +341553,7 @@ var require_gen_mapping_umd = __commonJS({
341087
341553
  }
341088
341554
  function allMappings(map2) {
341089
341555
  const out = [];
341090
- const { _mappings: mappings, _sources: sources, _names: names } = cast2(map2);
341556
+ const { _mappings: mappings, _sources: sources2, _names: names } = cast2(map2);
341091
341557
  for (let i2 = 0; i2 < mappings.length; i2++) {
341092
341558
  const line = mappings[i2];
341093
341559
  for (let j = 0; j < line.length; j++) {
@@ -341097,7 +341563,7 @@ var require_gen_mapping_umd = __commonJS({
341097
341563
  let original = void 0;
341098
341564
  let name2 = void 0;
341099
341565
  if (seg.length !== 1) {
341100
- source3 = sources.array[seg[SOURCES_INDEX]];
341566
+ source3 = sources2.array[seg[SOURCES_INDEX]];
341101
341567
  original = { line: seg[SOURCE_LINE] + 1, column: seg[SOURCE_COLUMN] };
341102
341568
  if (seg.length === 5) name2 = names.array[seg[NAMES_INDEX]];
341103
341569
  }
@@ -341109,7 +341575,7 @@ var require_gen_mapping_umd = __commonJS({
341109
341575
  function addSegmentInternal(skipable, map2, genLine, genColumn, source3, sourceLine, sourceColumn, name2, content) {
341110
341576
  const {
341111
341577
  _mappings: mappings,
341112
- _sources: sources,
341578
+ _sources: sources2,
341113
341579
  _sourcesContent: sourcesContent,
341114
341580
  _names: names
341115
341581
  // _originalScopes: originalScopes,
@@ -341122,7 +341588,7 @@ var require_gen_mapping_umd = __commonJS({
341122
341588
  }
341123
341589
  assert4(sourceLine);
341124
341590
  assert4(sourceColumn);
341125
- const sourcesIndex = put3(sources, source3);
341591
+ const sourcesIndex = put3(sources2, source3);
341126
341592
  const namesIndex = name2 ? put3(names, name2) : NO_NAME;
341127
341593
  if (sourcesIndex === sourcesContent.length) sourcesContent[sourcesIndex] = content != null ? content : null;
341128
341594
  if (skipable && skipSource(line, index2, sourcesIndex, sourceLine, sourceColumn, namesIndex)) {
@@ -342333,9 +342799,9 @@ var require_types2 = __commonJS({
342333
342799
  RegExp: new BasicType(getIsNativeChecker("[object RegExp]"), "is not a RegExp")
342334
342800
  };
342335
342801
  var nativeToString = Object.prototype.toString;
342336
- function getIsNativeChecker(tag) {
342802
+ function getIsNativeChecker(tag2) {
342337
342803
  return function(v) {
342338
- return typeof v === "object" && v && nativeToString.call(v) === tag;
342804
+ return typeof v === "object" && v && nativeToString.call(v) === tag2;
342339
342805
  };
342340
342806
  }
342341
342807
  if (typeof Buffer !== "undefined") {
@@ -350713,7 +351179,7 @@ var init_protocol2 = __esm({
350713
351179
  });
350714
351180
 
350715
351181
  // lib/code/hash.ts
350716
- function hashOf(text) {
351182
+ function hashOf2(text) {
350717
351183
  let h = 5381;
350718
351184
  for (let i2 = 0; i2 < text.length; i2++) h = (h << 5) + h + text.charCodeAt(i2) | 0;
350719
351185
  return (h >>> 0).toString(36);
@@ -351678,6 +352144,55 @@ var init_project = __esm({
351678
352144
  }
351679
352145
  });
351680
352146
 
352147
+ // lib/fonts/web-fonts.ts
352148
+ var web_fonts_exports = {};
352149
+ __export(web_fonts_exports, {
352150
+ webFontFaces: () => webFontFaces
352151
+ });
352152
+ function base644(bytes2) {
352153
+ let bin = "";
352154
+ for (let i2 = 0; i2 < bytes2.length; i2 += 32768) bin += String.fromCharCode(...bytes2.subarray(i2, i2 + 32768));
352155
+ return btoa(bin);
352156
+ }
352157
+ async function webFontFaces(doc2, trees, mode, dir = "fonts") {
352158
+ const used = new Set(trees.flatMap((t3) => [...fontFamilies(t3).keys()]));
352159
+ const faces2 = [];
352160
+ const files = [];
352161
+ for (const f2 of doc2.fonts ?? []) {
352162
+ if (!used.has(f2.family)) continue;
352163
+ const blob = await loadMediaBlob(f2.src);
352164
+ if (!blob) continue;
352165
+ const raw = new Uint8Array(await blob.arrayBuffer());
352166
+ const format = fontFormat(raw);
352167
+ if (!format) continue;
352168
+ const bytes2 = format === "ttc" ? extractCollectionFace(raw, f2.face ?? 0) : raw;
352169
+ const own2 = fontFormat(bytes2) ?? format;
352170
+ const weight = fontWeightOf(f2), style = fontStyleOf(f2);
352171
+ let url4;
352172
+ if (mode === "files") {
352173
+ const name2 = `${dir}/${slug3(f2.family)}-${weight}${style === "italic" ? "-italic" : ""}.${EXT2[own2]}`;
352174
+ if (!files.some((x2) => x2.name === name2)) files.push({ name: name2, bytes: bytes2 });
352175
+ url4 = name2;
352176
+ } else {
352177
+ url4 = `data:font/${EXT2[own2]};base64,${base644(bytes2)}`;
352178
+ }
352179
+ faces2.push({ family: f2.family, weight, style, url: url4, format: CSS_FORMAT[own2] });
352180
+ }
352181
+ return { faces: faces2, files };
352182
+ }
352183
+ var CSS_FORMAT, EXT2, slug3;
352184
+ var init_web_fonts = __esm({
352185
+ "lib/fonts/web-fonts.ts"() {
352186
+ init_fonts3();
352187
+ init_media_store();
352188
+ init_document_fonts();
352189
+ init_sfnt();
352190
+ CSS_FORMAT = { ttf: "truetype", ttc: "truetype", otf: "opentype", woff: "woff", woff2: "woff2" };
352191
+ EXT2 = { ttf: "ttf", ttc: "ttf", otf: "otf", woff: "woff", woff2: "woff2" };
352192
+ slug3 = (s) => s.toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-|-$/g, "") || "font";
352193
+ }
352194
+ });
352195
+
351681
352196
  // lib/io/web/project/components.ts
351682
352197
  var components_exports = {};
351683
352198
  __export(components_exports, {
@@ -351937,7 +352452,7 @@ function shopifyThemeFiles(doc2, screens, o = {}) {
351937
352452
  let kind = storefrontPageKind(s, doc2, route2 ?? (i2 === 0 ? "/" : void 0));
351938
352453
  if (kind !== "page" && used.has(kind)) kind = "page";
351939
352454
  used.add(kind);
351940
- const slug3 = fileBase(s.name).toLowerCase() || `page-${i2 + 1}`;
352455
+ const slug4 = fileBase(s.name).toLowerCase() || `page-${i2 + 1}`;
351941
352456
  let tree = located(holder.pages[i2].tree);
351942
352457
  if (s.about?.schema) tree = { ...tree, root: liquidNode(tree.root, s.about.schema, s.about.schema === "commerce.product" ? "product" : "collection") };
351943
352458
  const relist = (n) => {
@@ -351977,15 +352492,15 @@ function shopifyThemeFiles(doc2, screens, o = {}) {
351977
352492
  });
351978
352493
  const prelude = kind === "search" ? "{%- liquid\n if search.performed\n assign pc_results = search.results | where: 'object_type', 'product'\n else\n assign pc_results = collections.all.products\n endif\n-%}\n" : "";
351979
352494
  const title = s.name;
351980
- files.push({ path: `sections/popcraft-${slug3}.liquid`, content: `${prelude}${html}
352495
+ files.push({ path: `sections/popcraft-${slug4}.liquid`, content: `${prelude}${html}
351981
352496
 
351982
352497
  {% schema %}
351983
352498
  ${JSON.stringify({ name: `${title} (PopCraft)`, settings: [] }, null, 2)}
351984
352499
  {% endschema %}
351985
352500
  ` });
351986
- sections.push({ kind, slug: slug3, title });
351987
- const template2 = kind === "page" ? `page.${slug3}` : kind;
351988
- files.push({ path: `templates/${template2}.json`, content: `${JSON.stringify({ sections: { main: { type: `popcraft-${slug3}`, settings: {} } }, order: ["main"] }, null, 2)}
352501
+ sections.push({ kind, slug: slug4, title });
352502
+ const template2 = kind === "page" ? `page.${slug4}` : kind;
352503
+ files.push({ path: `templates/${template2}.json`, content: `${JSON.stringify({ sections: { main: { type: `popcraft-${slug4}`, settings: {} } }, order: ["main"] }, null, 2)}
351989
352504
  ` });
351990
352505
  }
351991
352506
  const plain2 = (template2, title, body) => {
@@ -352715,6 +353230,22 @@ async function docAtTime(doc2, ids2, time4) {
352715
353230
  const nodes = poseNodesAt2(doc2.nodes, ids2, time4, frameId);
352716
353231
  return nodes === doc2.nodes ? doc2 : { ...doc2, nodes };
352717
353232
  }
353233
+ function reportsMissingFonts(command) {
353234
+ const run4 = command.run;
353235
+ return {
353236
+ ...command,
353237
+ run: async (args2, ctx2) => {
353238
+ const result = await run4(args2, ctx2);
353239
+ const [{ findMissingFonts: findMissingFonts2 }, { missingFontMessage: missingFontMessage2 }] = await Promise.all([Promise.resolve().then(() => (init_runtime3(), runtime_exports2)), Promise.resolve().then(() => (init_document_fonts(), document_fonts_exports))]);
353240
+ const missing = await findMissingFonts2(ctx2.doc());
353241
+ if (!missing.length) return result;
353242
+ const warnings = missing.map(missingFontMessage2);
353243
+ ctx2.notice(`Missing font${missing.length === 1 ? "" : "s"}: ${missing.map((m) => m.family).join(", ")}. Those texts were exported in a fallback font.`, { error: true });
353244
+ const data = result.data === void 0 ? { warnings } : result.data && typeof result.data === "object" && !Array.isArray(result.data) ? { ...result.data, warnings } : result.data;
353245
+ return { ...result, summary: `${result.summary} (missing font${missing.length === 1 ? "" : "s"}: ${missing.map((m) => m.family).join(", ")}, drawn in a fallback)`, data };
353246
+ }
353247
+ };
353248
+ }
352718
353249
  function animationTarget(args2, ctx2, doc2) {
352719
353250
  if (args2.composition) {
352720
353251
  if (!doc2.compositions?.[args2.composition]) throw new ToolError(`There is no composition "${args2.composition}".`);
@@ -352785,7 +353316,7 @@ async function runLottieExport(renderer, doc2, spec, filename, ctx2, memoryDesti
352785
353316
  const support = lottieSupport2(doc2, spec.target);
352786
353317
  if (!support.ok) throw new ToolError(`Lottie cannot carry this animation: ${support.blockers.join("; ")}. Export MP4, WebM or GIF instead.`);
352787
353318
  ctx2.progress?.(0, spec.range.count, "Writing Lottie");
352788
- const started7 = performance.now();
353319
+ const started8 = performance.now();
352789
353320
  const out = await exportLottie3(renderer, doc2, spec, filename.replace(/\.[^.]+$/, ""), { stateMachine });
352790
353321
  if (ctx2.signal?.aborted) throw new ToolError("Export cancelled.");
352791
353322
  const dest = ctx2.destination ? await ctx2.destination(filename, FORMAT_MIME2[spec.format]) : memoryDestination2(filename, FORMAT_MIME2[spec.format]);
@@ -352803,7 +353334,7 @@ async function runLottieExport(renderer, doc2, spec, filename, ctx2, memoryDesti
352803
353334
  const notes = [.../* @__PURE__ */ new Set([...support.warnings, ...out.notes])];
352804
353335
  return {
352805
353336
  summary: `Exported ${plural2(spec.range.count, "frame")} (${secs} s at ${spec.range.fps} fps, ${spec.width}\xD7${spec.height}) as ${dest.name}${notes.length ? ` \u2014 ${notes.join("; ")}` : ""}`,
352806
- data: { filename: dest.name, frames: spec.range.count, fps: spec.range.fps, width: spec.width, height: spec.height, bytes: out.bytes.length, ms: Math.round(performance.now() - started7), msPerFrame: (performance.now() - started7) / spec.range.count, keys: out.stats, warnings: notes }
353337
+ data: { filename: dest.name, frames: spec.range.count, fps: spec.range.fps, width: spec.width, height: spec.height, bytes: out.bytes.length, ms: Math.round(performance.now() - started8), msPerFrame: (performance.now() - started8) / spec.range.count, keys: out.stats, warnings: notes }
352807
353338
  };
352808
353339
  }
352809
353340
  async function exportSite(doc2, pageId2, packaging, styling = "css", siteUrl) {
@@ -352816,11 +353347,13 @@ async function exportSite(doc2, pageId2, packaging, styling = "css", siteUrl) {
352816
353347
  const site = await completeSite2(doc2, pageId2);
352817
353348
  if (!site.pages.length) throw new ToolError("This page has no screens: a top-level frame is a page of the site.");
352818
353349
  const share = await shareImageFiles2(doc2, site, packaging === "next" ? "public/" : "");
353350
+ const shipped = packaging === "site" ? await (await Promise.resolve().then(() => (init_web_fonts(), web_fonts_exports))).webFontFaces(doc2, site.pages.map((p2) => p2.tree), "files") : null;
353351
+ if (shipped?.faces.length) site.fontFaces = shipped.faces;
352819
353352
  const files = [...packaging === "next" ? await nextFilesOf2(site, doc2, { styling }) : await staticFilesOf2(site, { origin: siteUrl }).catch((e) => {
352820
353353
  throw e instanceof NoSiteRuntime2 ? new ToolError(`${e.message} A static site cannot be exported.`) : e;
352821
353354
  }), ...share];
352822
353355
  const base = fileBase2(doc2.name);
352823
- downloadBlob2(zipFiles2(files.map((f2) => ({ name: f2.path, bytes: bytesOf2(f2) }))), `${base}.zip`);
353356
+ downloadBlob2(zipFiles2([...files.map((f2) => ({ name: f2.path, bytes: bytesOf2(f2) })), ...shipped?.files ?? []]), `${base}.zip`);
352824
353357
  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 } };
352825
353358
  }
352826
353359
  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;
@@ -352839,7 +353372,7 @@ var init_export2 = __esm({
352839
353372
  init_tree();
352840
353373
  MAX_INLINE_BYTES = 15e5;
352841
353374
  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.");
352842
- exportSvg = defineCommand({
353375
+ exportSvg = reportsMissingFonts(defineCommand({
352843
353376
  id: "export.svg",
352844
353377
  title: "Export SVG",
352845
353378
  domain: "export",
@@ -352872,8 +353405,8 @@ var init_export2 = __esm({
352872
353405
  data: { id: node2.id, truncated: clipped, svg: clipped ? svg.slice(0, max3) : svg }
352873
353406
  };
352874
353407
  }
352875
- });
352876
- exportNodes = defineCommand({
353408
+ }));
353409
+ exportNodes = reportsMissingFonts(defineCommand({
352877
353410
  id: "export.nodes",
352878
353411
  title: "Export layers",
352879
353412
  domain: "export",
@@ -352955,8 +353488,8 @@ var init_export2 = __esm({
352955
353488
  }
352956
353489
  };
352957
353490
  }
352958
- });
352959
- exportPdf = defineCommand({
353491
+ }));
353492
+ exportPdf = reportsMissingFonts(defineCommand({
352960
353493
  id: "export.pdf",
352961
353494
  title: "Export as PDF",
352962
353495
  domain: "export",
@@ -353007,7 +353540,7 @@ var init_export2 = __esm({
353007
353540
  downloadBlob2(blob, filename);
353008
353541
  return { summary: `Exported ${plural2(nodes.length, "page")} as ${filename}`, data: { filename, pages: nodes.length, bytes: blob.size } };
353009
353542
  }
353010
- });
353543
+ }));
353011
353544
  exportCopy = defineCommand({
353012
353545
  id: "export.copy",
353013
353546
  title: "Copy as image",
@@ -353046,7 +353579,7 @@ var init_export2 = __esm({
353046
353579
  return { summary: `Copied "${node2.name}" as ${format}`, data: { id: node2.id, format } };
353047
353580
  }
353048
353581
  });
353049
- exportPages = defineCommand({
353582
+ exportPages = reportsMissingFonts(defineCommand({
353050
353583
  id: "export.pages",
353051
353584
  title: "Export pages as images",
353052
353585
  domain: "export",
@@ -353098,8 +353631,8 @@ var init_export2 = __esm({
353098
353631
  downloadBlob2(zipFiles2(files), filename);
353099
353632
  return { summary: `Exported ${plural2(files.length, "page")} at ${dpi} dpi as ${filename}`, data: { filename, pages: files.length, dpi, format } };
353100
353633
  }
353101
- });
353102
- exportPptx = defineCommand({
353634
+ }));
353635
+ exportPptx = reportsMissingFonts(defineCommand({
353103
353636
  id: "export.pptx",
353104
353637
  title: "Export as PowerPoint",
353105
353638
  domain: "export",
@@ -353137,7 +353670,7 @@ var init_export2 = __esm({
353137
353670
  downloadBlob2(blob, filename);
353138
353671
  return { summary: `Exported ${plural2(nodes.length, "slide")} as ${filename}`, data: { filename, slides: nodes.length, bytes: blob.size } };
353139
353672
  }
353140
- });
353673
+ }));
353141
353674
  animationParams = external_exports.object({
353142
353675
  id: external_exports.string().optional().describe("The frame or motion component whose timeline to export; defaults to the selected frame."),
353143
353676
  composition: external_exports.string().optional().describe("A composition (scene sequence) to export instead of a frame: its scenes and transitions."),
@@ -353196,7 +353729,7 @@ var init_export2 = __esm({
353196
353729
  name: "export_lottie",
353197
353730
  description: `Write ${TARGET.replace(" and \u2014 for video \u2014 its sound", "")} as a Lottie (bodymovin JSON, or a .lottie zip) the user downloads: vector shapes, fills, strokes, masks, text as outlines and images as embedded assets, with our keys and bezier / hold easing where Lottie can say them and every other curve, behaviour and text animator keyed frame by frame. Refuses what Lottie cannot carry (shader fills, blurs, glass, halftone, 3D, video) and lists what it baked. The timeline's markers go in as Lottie markers; a .lottie also carries the frame's state machine. Options: frame rate, range, container, stateMachine.`
353198
353731
  });
353199
- exportWeb = defineCommand({
353732
+ exportWeb = reportsMissingFonts(defineCommand({
353200
353733
  id: "export.web",
353201
353734
  title: "Export as web code",
353202
353735
  domain: "export",
@@ -353227,20 +353760,23 @@ var init_export2 = __esm({
353227
353760
  const { downloadBlob: downloadBlob2 } = await Promise.resolve().then(() => (init_download(), download_exports));
353228
353761
  const tree = webTreeFor2(doc2, node2.id, lang, { nodeCap: EXPORT_NODE_CAP, fullImageUrls: true });
353229
353762
  if (flatten3(tree.root).some((n) => n.asset)) await resolveWebAssets2(tree, rendererAssetResolvers2(doc2));
353763
+ const { webFontFaces: webFontFaces2 } = await Promise.resolve().then(() => (init_web_fonts(), web_fonts_exports));
353764
+ const shipped = await webFontFaces2(doc2, [tree], args2.images === "files" ? "files" : "data");
353765
+ if (shipped.faces.length) tree.fontFaces = shipped.faces;
353230
353766
  const base = fileBase2(node2.name || doc2.name);
353231
353767
  const filename = `${base}.${extensionFor2(lang)}`;
353232
353768
  if (args2.images === "files") {
353233
353769
  const { zipFiles: zipFiles2 } = await Promise.resolve().then(() => (init_zip_export(), zip_export_exports));
353234
353770
  const images = externalAssets2(tree, base);
353235
- const files = [{ name: filename, bytes: new TextEncoder().encode(serializeFor2(lang, tree, { document: true })) }, ...images];
353771
+ const files = [{ name: filename, bytes: new TextEncoder().encode(serializeFor2(lang, tree, { document: true })) }, ...images, ...shipped.files];
353236
353772
  downloadBlob2(zipFiles2(files), `${base}.zip`);
353237
- return { summary: `Exported ${filename} and ${plural2(images.length, "image")} as ${base}.zip`, data: { filename, images: images.length } };
353773
+ return { summary: `Exported ${filename} and ${plural2(images.length, "image")}${shipped.files.length ? ` and ${plural2(shipped.files.length, "font")}` : ""} as ${base}.zip`, data: { filename, images: images.length, fonts: shipped.files.length } };
353238
353774
  }
353239
353775
  const markup = serializeFor2(lang, tree, { document: true });
353240
353776
  downloadBlob2(new Blob([markup], { type: spec.mime }), filename);
353241
- return { summary: `Exported ${node2.name || "layer"} as ${filename}`, data: { filename, format, bytes: markup.length, truncated: tree.truncated } };
353777
+ return { summary: `Exported ${node2.name || "layer"} as ${filename}`, data: { filename, format, bytes: markup.length, truncated: tree.truncated, ...shipped.faces.length ? { fonts: shipped.faces.length } : {} } };
353242
353778
  }
353243
- });
353779
+ }));
353244
353780
  APP_STOREFRONT_TARGETS = STOREFRONT_TARGET_IDS.filter((t3) => t3 !== "shopify-theme");
353245
353781
  exportStorefront = defineCommand({
353246
353782
  id: "export.storefront",
@@ -359068,7 +359604,7 @@ var init_sites = __esm({
359068
359604
  setSiteVersion = (key5, version7) => api(`/api/sites/${key5}`, { method: "PATCH", json: { currentVersion: version7 } });
359069
359605
  workspaceSites = (workspaceId) => api(`/api/workspaces/${encodeURIComponent(workspaceId)}/sites?t=${Date.now()}`);
359070
359606
  deleteSite = (key5) => api(`/api/sites/${key5}`, { method: "DELETE" });
359071
- renameSite = (key5, slug3) => api(`/api/sites/${key5}`, { method: "PATCH", json: { slug: slug3 } });
359607
+ renameSite = (key5, slug4) => api(`/api/sites/${key5}`, { method: "PATCH", json: { slug: slug4 } });
359072
359608
  }
359073
359609
  });
359074
359610
 
@@ -359079,7 +359615,7 @@ __export(publish_site_exports, {
359079
359615
  openFileKey: () => openFileKey,
359080
359616
  publishOpenFile: () => publishOpenFile
359081
359617
  });
359082
- async function publishOpenFile(slug3, progress2 = {}) {
359618
+ async function publishOpenFile(slug4, progress2 = {}) {
359083
359619
  progress2.onBuild?.();
359084
359620
  const key5 = openFileKey() ?? await uploadActiveDocument();
359085
359621
  const { document: document2, currentPageId } = useEditorStore.getState();
@@ -359089,8 +359625,8 @@ async function publishOpenFile(slug3, progress2 = {}) {
359089
359625
  const share = await shareImageFiles2(document2, built);
359090
359626
  const files = [...await staticFilesOf2(built), ...share];
359091
359627
  const site = (await siteStatus(key5)).site;
359092
- if (site && slug3 && slug3 !== site.slug) await renameSite(key5, slug3);
359093
- const published = await publishSite(key5, files, { slug: slug3, onProgress: progress2.onUpload });
359628
+ if (site && slug4 && slug4 !== site.slug) await renameSite(key5, slug4);
359629
+ const published = await publishSite(key5, files, { slug: slug4, onProgress: progress2.onUpload });
359094
359630
  return { ...published, key: key5, pages: built.pages.length, shareImage: built.share ? `${published.url.replace(/\/+$/, "")}/${built.share.image}` : null };
359095
359631
  }
359096
359632
  var NoScreens, openFileKey;
@@ -359248,8 +359784,8 @@ function validSitePath(path) {
359248
359784
  return path.split("/").every((seg) => /^[A-Za-z0-9._~-]+$/.test(seg) && seg !== "." && seg !== "..");
359249
359785
  }
359250
359786
  function cleanSlug(raw) {
359251
- const slug3 = raw.toLowerCase().normalize("NFKD").replace(/[^a-z0-9]+/g, "-").replace(/^-+|-+$/g, "").slice(0, 40).replace(/-+$/, "");
359252
- return slug3.length >= 3 && !RESERVED3.has(slug3) ? slug3 : null;
359787
+ const slug4 = raw.toLowerCase().normalize("NFKD").replace(/[^a-z0-9]+/g, "-").replace(/^-+|-+$/g, "").slice(0, 40).replace(/-+$/, "");
359788
+ return slug4.length >= 3 && !RESERVED3.has(slug4) ? slug4 : null;
359253
359789
  }
359254
359790
  function suggestedSlug(name2, id3) {
359255
359791
  const tail = id3.toLowerCase().replace(/[^a-z0-9]/g, "").slice(-6);
@@ -360502,7 +361038,7 @@ function computeAppliedTheme(s) {
360502
361038
  const keywords = !isDesktop() && effectiveAccent(s) === "system" && accentApplies(themeId, lookup) ? `${systemAccentCss(themes.get(themeId).type)}
360503
361039
  ` : "";
360504
361040
  const extra = collectCss(themeId, lookup).map(sanitizeThemeCss).join("\n");
360505
- const fontCss = collectFonts(themeId, lookup).map((f2) => `@font-face { font-family: ${cssString(f2.family)}; src: url(${cssString(f2.src)}); font-weight: ${f2.weight ?? "100 900"}; font-style: ${f2.style ?? "normal"}; font-display: swap; }`).join("\n");
361041
+ const fontCss = collectFonts(themeId, lookup).map((f2) => `@font-face { font-family: ${cssString2(f2.family)}; src: url(${cssString2(f2.src)}); font-weight: ${f2.weight ?? "100 900"}; font-style: ${f2.style ?? "normal"}; font-display: swap; }`).join("\n");
360506
361042
  return {
360507
361043
  themeId,
360508
361044
  type: themes.get(themeId).type,
@@ -360532,7 +361068,7 @@ function usePickableThemes() {
360532
361068
  const localThemes = useThemeStore((s) => s.localThemes);
360533
361069
  return (0, import_react9.useMemo)(() => pickableThemes({ userThemes, pluginThemes, localThemes }), [userThemes, pluginThemes, localThemes]);
360534
361070
  }
360535
- var import_react9, IDB_KEY, useThemeStore, cssString, defaultAccent, effectiveAccent;
361071
+ var import_react9, IDB_KEY, useThemeStore, cssString2, defaultAccent, effectiveAccent;
360536
361072
  var init_theme_store = __esm({
360537
361073
  "lib/theme/theme-store.ts"() {
360538
361074
  init_contrast();
@@ -360660,7 +361196,7 @@ var init_theme_store = __esm({
360660
361196
  })
360661
361197
  };
360662
361198
  });
360663
- cssString = (v) => `"${v.replace(/["\\]/g, "")}"`;
361199
+ cssString2 = (v) => `"${v.replace(/["\\]/g, "")}"`;
360664
361200
  defaultAccent = () => isDesktop() && storePlatform() !== "ios" && storePlatform() !== "android" ? "system" : "lavender";
360665
361201
  effectiveAccent = (s) => s.accent ?? defaultAccent();
360666
361202
  }
@@ -363501,8 +364037,12 @@ __export(json_export_exports, {
363501
364037
  downloadJSON: () => downloadJSON,
363502
364038
  exportToJSON: () => exportToJSON,
363503
364039
  importFromJSON: () => importFromJSON,
363504
- importJSONFile: () => importJSONFile
364040
+ importJSONFile: () => importJSONFile,
364041
+ portableDocument: () => portableDocument
363505
364042
  });
364043
+ async function portableDocument(document2) {
364044
+ return embedDocumentFonts({ ...document2, nodes: await embedNodeMedia(document2.nodes) });
364045
+ }
363506
364046
  function exportToJSON(document2) {
363507
364047
  const exportData = {
363508
364048
  version: "1.0.0",
@@ -363513,7 +364053,7 @@ function exportToJSON(document2) {
363513
364053
  return JSON.stringify(exportData, null, 2);
363514
364054
  }
363515
364055
  async function downloadJSON(document2, filename = "document.json") {
363516
- const json3 = exportToJSON({ ...document2, nodes: await embedNodeMedia(document2.nodes) });
364056
+ const json3 = exportToJSON(await portableDocument(document2));
363517
364057
  const blob = new Blob([json3], { type: "application/json" });
363518
364058
  const url4 = URL.createObjectURL(blob);
363519
364059
  const link2 = window.document.createElement("a");
@@ -363531,7 +364071,7 @@ function importFromJSON(jsonString) {
363531
364071
  console.error("Invalid document format");
363532
364072
  return null;
363533
364073
  }
363534
- return data.document;
364074
+ return internDocumentFonts(data.document);
363535
364075
  } catch (error62) {
363536
364076
  console.error("Failed to parse JSON:", error62);
363537
364077
  return null;
@@ -363552,6 +364092,7 @@ function importJSONFile(file2) {
363552
364092
  var init_json_export = __esm({
363553
364093
  "lib/io/json-export.ts"() {
363554
364094
  init_media_store();
364095
+ init_document_fonts();
363555
364096
  }
363556
364097
  });
363557
364098
 
@@ -364384,7 +364925,7 @@ var init_api5 = __esm({
364384
364925
 
364385
364926
  // node_modules/.pnpm/@popcraft+plugins@1.0.0_patch_hash=6826cb40a12857607fa1f7d7d102e5d8316bd483c1ff06865dac73139dfe709b/node_modules/@popcraft/plugins/dist/generated/runtime.js
364386
364927
  var MAIN_RUNTIME, UI_RUNTIME;
364387
- var init_runtime4 = __esm({
364928
+ var init_runtime5 = __esm({
364388
364929
  "node_modules/.pnpm/@popcraft+plugins@1.0.0_patch_hash=6826cb40a12857607fa1f7d7d102e5d8316bd483c1ff06865dac73139dfe709b/node_modules/@popcraft/plugins/dist/generated/runtime.js"() {
364389
364930
  MAIN_RUNTIME = '"use strict";\n(() => {\n // src/runtime/rpc.ts\n function createRpcClient() {\n let port = null;\n const queue = [];\n const pending = {};\n const listeners = {};\n let nextId = 1;\n function send(msg) {\n if (port) port.postMessage(msg);\n else queue.push(msg);\n }\n function call(method, params) {\n return new Promise((resolve, reject) => {\n const id = nextId++;\n pending[id] = { resolve, reject };\n send({ kind: "rpc", id, method, params });\n });\n }\n function emit(event, data) {\n for (const cb of (listeners[event] || []).slice()) {\n try {\n cb(data);\n } catch (e) {\n console.error(e);\n }\n }\n }\n window.addEventListener("message", (e) => {\n const data = e.data;\n if (e.source !== window.parent || !data || data.type !== "popcraft-plugin-port" || port) return;\n port = e.ports[0];\n port.onmessage = (ev) => {\n const m = ev.data || {};\n if (m.kind === "result" && m.id !== void 0 && pending[m.id]) {\n const p = pending[m.id];\n delete pending[m.id];\n if (m.error) p.reject(new Error(m.error));\n else p.resolve(m.result);\n } else if (m.kind === "event" && m.event) {\n emit(m.event, m.data);\n }\n };\n for (const msg of queue.splice(0)) port.postMessage(msg);\n });\n return {\n call,\n send,\n on(event, cb) {\n (listeners[event] = listeners[event] || []).push(cb);\n },\n off(event, cb) {\n listeners[event] = (listeners[event] || []).filter((x) => x !== cb);\n }\n };\n }\n\n // src/runtime/main.ts\n function clone(v) {\n return v === void 0 ? {} : JSON.parse(JSON.stringify(v));\n }\n function createMainApi(rpc = createRpcClient()) {\n const uiHandlers = [];\n let uiOnMessage = null;\n const uiQueue = [];\n function deliverUI(msg) {\n for (const cb of uiHandlers) {\n try {\n cb(msg);\n } catch (e) {\n console.error(e);\n }\n }\n if (typeof uiOnMessage === "function") {\n try {\n uiOnMessage(msg);\n } catch (e) {\n console.error(e);\n }\n }\n }\n function flushUI() {\n if (uiHandlers.length || typeof uiOnMessage === "function") uiQueue.splice(0).forEach(deliverUI);\n }\n rpc.on("uimessage", (msg) => {\n if (!uiHandlers.length && typeof uiOnMessage !== "function") uiQueue.push(msg);\n else deliverUI(msg);\n });\n let widgetDef = null;\n const widgetQueue = [];\n function renderWidget(state) {\n const handlers = {};\n function walk(el, path) {\n if (!el || typeof el !== "object") return el;\n const out = {};\n for (const k of Object.keys(el)) {\n const v = el[k];\n if (k === "children") {\n out.children = (Array.isArray(v) ? v : [v]).filter((c) => c !== null && c !== void 0 && c !== false).map((c, i) => walk(c, path + "." + i));\n } else if (k === "onClick" && typeof v === "function") {\n handlers[path] = v;\n out.onClick = path;\n } else {\n out[k] = v;\n }\n }\n return out;\n }\n return { tree: walk(widgetDef.render(state), "root"), handlers };\n }\n function initialWidgetState() {\n const s = widgetDef && widgetDef.initialState;\n return clone(typeof s === "function" ? s() : s);\n }\n function commitWidget(nodeId, state) {\n return rpc.call("widgetUpdate", { id: nodeId, state, tree: renderWidget(clone(state)).tree });\n }\n function handleWidgetClick(e) {\n Promise.resolve().then(() => {\n const state = clone(e.state);\n const rendered = renderWidget(state);\n const h = rendered.handlers[e.handler] || widgetDef.handlers && widgetDef.handlers[e.handler];\n if (typeof h !== "function") return;\n return Promise.resolve(h(state, { nodeId: e.nodeId })).then((ret) => commitWidget(e.nodeId, ret === void 0 ? state : ret));\n }).catch((err) => rpc.send({ kind: "error", message: String((err == null ? void 0 : err.message) || err) }));\n }\n rpc.on("widgetclick", (e) => {\n if (widgetDef) handleWidgetClick(e);\n else widgetQueue.push(e);\n });\n const popcraft = {\n /** Which menu command the user picked, or null when the plugin ran some other way. */\n command: null,\n /** Host import mode when launched as an importer, else null. */\n importMode: null,\n /** Pending import file when the host handed one over, else null. */\n importFile: null,\n /** Pending export request (File \u2192 Export \u2192 this plugin\'s format), else null. */\n exportRequest: null,\n getSelection: () => rpc.call("getSelection"),\n setSelection: (ids) => rpc.call("setSelection", { ids }),\n getNode: (id) => rpc.call("getNode", { id }),\n findNodes: (query) => rpc.call("findNodes", query || {}),\n getCurrentPage: () => rpc.call("getCurrentPage"),\n createNode: (type, props) => rpc.call("createNode", { type, props: props || {} }),\n updateNode: (id, props) => rpc.call("updateNode", { id, props }),\n deleteNode: (id) => rpc.call("deleteNode", { id }),\n setText: (id, characters) => rpc.call("setText", { id, characters }),\n /** Put TEXT layers on a path (another layer\'s outline, or their own arc, circle or wave), or tune one: brackets, alignment, placement, effect, overflow. */\n setTextPath: (opts) => rpc.call("setTextPath", opts || {}),\n /** Area type: flow a TEXT layer inside a closed shape, kept `inset` px in. */\n flowTextIntoShape: (opts) => rpc.call("flowTextIntoShape", opts || {}),\n /** Take TEXT layers off their path or out of their shape (or free every text linked to a path / shape). */\n detachText: (opts) => rpc.call("detachText", opts || {}),\n /** Auto-size TEXT layers\' type to their box, shape or path. */\n setTextFit: (opts) => rpc.call("setTextFit", opts || {}),\n createPage: (name) => rpc.call("createPage", name != null ? { name: String(name) } : {}),\n setCurrentPage: (pageId) => rpc.call("setCurrentPage", { pageId }),\n createImage: (opts) => rpc.call("createImage", opts || {}),\n createDocument: (opts) => rpc.call("createDocument", opts || {}),\n getImportMode: () => rpc.call("getImportMode"),\n getImportFile: () => rpc.call("getImportFile"),\n /**\n * The open page as a storefront design in a neutral form, for an exporter that writes its own store\'s templates:\n * each page\'s HTML with the store\'s data marked (`{{page.title}}`, `{{item.price}}`, `<!-- pc:each \u2026 -->` lists,\n * `data-pc-action` forms), and its collections with their commerce schema and sample records.\n */\n getStorefront: () => rpc.call("getStorefront"),\n /**\n * A design\'s data (docs: Collections): a collection and its fields (`schema`: what it stands for, e.g.\n * `commerce.product`, whose fields are made for it), its records, and reading them.\n */\n editCollection: (opts) => rpc.call("editCollection", opts || {}),\n editRecords: (opts) => rpc.call("editRecords", opts || {}),\n getRecords: (opts) => rpc.call("getRecords", opts || {}),\n /** A layer as a web page\'s form control (a FORM\'s `formAction`, an INPUT\'s name and value), repeated per record, a page\'s address, its semantics. */\n setControl: (opts) => rpc.call("setControl", opts || {}),\n setRepeat: (opts) => rpc.call("setRepeat", opts || {}),\n setRoute: (opts) => rpc.call("setRoute", opts || {}),\n setSemantics: (opts) => rpc.call("setSemantics", opts || {}),\n /** Which record layers are about (one product, picked from a collection), and which of its fields a layer\'s words, picture or an instance\'s properties follow. */\n setRecord: (opts) => rpc.call("setRecord", opts || {}),\n bindField: (opts) => rpc.call("bindField", opts || {}),\n /** The site\'s environment: public settings its host reads by name when it is deployed (never a secret: the file keeps them). */\n getSiteEnvironment: () => rpc.call("getSiteEnvironment"),\n setSiteEnvironment: (set) => rpc.call("setSiteEnvironment", { set }),\n /** What this plugin keeps with the open file (its settings for this design), under its own id; JSON only. */\n getFileData: (key) => rpc.call("getFileData", { key }),\n setFileData: (key, value) => rpc.call("setFileData", { key, value }),\n /** A store\'s project built from the open page, zipped (needs `export`): what an exporter saves with `saveExport`. */\n getStorefrontFiles: (target) => rpc.call("getStorefrontFiles", { target }),\n getExportRequest: () => rpc.call("getExportRequest"),\n /** Save the exporter\'s file (once per export request); the host enforces the contributed extension. */\n saveExport: (file) => rpc.call("saveExport", file || {}),\n /**\n * Presentation audio (docs/plugins/presentation-audio.md): the deck\'s slides, notes, narration and timing; the\n * soundtrack\'s settings, bed and stinger.\n */\n getPresentationAudio: (opts) => rpc.call("getPresentationAudio", opts || {}),\n /** Change the soundtrack\'s settings (voice, style, mood, loudness, beat alignment, levels) and re-time it. */\n setPresentationAudioSettings: (opts) => rpc.call("setPresentationAudioSettings", opts || {}),\n /** Put a sound in (a slide\'s narration, the bed or the stinger): bytes are normalised to the soundtrack\'s target and stored. */\n setPresentationAudioClip: (opts) => rpc.call("setPresentationAudioClip", opts || {}),\n removePresentationAudioClip: (opts) => rpc.call("removePresentationAudioClip", opts || {}),\n /** Re-time: fixed slide lengths (ms, null clears) and beat-aligned changes. */\n setPresentationTiming: (opts) => rpc.call("setPresentationTiming", opts || {}),\n /** The mix as the export carries it: loudness, true peak, and (wav: true) the 48 kHz stereo WAV. */\n getPresentationMix: (opts) => rpc.call("getPresentationMix", opts || {}),\n /** Ask the user to generate with AI (the panel opens with the request filled in; the user decides). */\n requestPresentationAudio: (opts) => rpc.call("requestPresentationAudio", opts || {}),\n /** Editor commands: each takes the arguments documented in docs/plugins/methods.md (the agent tool of the same purpose). */\n moveNodes: (opts) => rpc.call("moveNodes", opts || {}),\n resizeNodes: (opts) => rpc.call("resizeNodes", opts || {}),\n renameNodes: (opts) => rpc.call("renameNodes", opts || {}),\n reparentNodes: (opts) => rpc.call("reparentNodes", opts || {}),\n duplicateNodes: (opts) => rpc.call("duplicateNodes", opts || {}),\n groupNodes: (opts) => rpc.call("groupNodes", opts || {}),\n ungroupNodes: (opts) => rpc.call("ungroupNodes", opts || {}),\n alignNodes: (opts) => rpc.call("alignNodes", opts || {}),\n distributeNodes: (opts) => rpc.call("distributeNodes", opts || {}),\n flipNodes: (opts) => rpc.call("flipNodes", opts || {}),\n rotateNodes: (opts) => rpc.call("rotateNodes", opts || {}),\n reorderNodes: (opts) => rpc.call("reorderNodes", opts || {}),\n setLocked: (opts) => rpc.call("setLocked", opts || {}),\n setVisible: (opts) => rpc.call("setVisible", opts || {}),\n setAutoLayout: (opts) => rpc.call("setAutoLayout", opts || {}),\n importSvg: (opts) => rpc.call("importSvg", opts || {}),\n measureNodes: (opts) => rpc.call("measureNodes", opts || {}),\n setFills: (opts) => rpc.call("setFills", opts || {}),\n setStrokes: (opts) => rpc.call("setStrokes", opts || {}),\n setEffects: (opts) => rpc.call("setEffects", opts || {}),\n replaceColor: (opts) => rpc.call("replaceColor", opts || {}),\n setTypography: (opts) => rpc.call("setTypography", opts || {}),\n applyStyle: (opts) => rpc.call("applyStyle", opts || {}),\n createComponent: (opts) => rpc.call("createComponent", opts || {}),\n createInstance: (opts) => rpc.call("createInstance", opts || {}),\n renamePage: (opts) => rpc.call("renamePage", opts || {}),\n getDocumentOutline: (opts) => rpc.call("getDocumentOutline", opts || {}),\n setPageSetup: (opts) => rpc.call("setPageSetup", opts || {}),\n setShowAdvance: (opts) => rpc.call("setShowAdvance", opts || {}),\n booleanOperation: (opts) => rpc.call("booleanOperation", opts || {}),\n flattenNodes: (opts) => rpc.call("flattenNodes", opts || {}),\n outlineStroke: (opts) => rpc.call("outlineStroke", opts || {}),\n setMask: (opts) => rpc.call("setMask", opts || {}),\n setMaskType: (opts) => rpc.call("setMaskType", opts || {}),\n shapeBuilder: (opts) => rpc.call("shapeBuilder", opts || {}),\n setKeyframes: (opts) => rpc.call("setKeyframes", opts || {}),\n getAnimation: (opts) => rpc.call("getAnimation", opts || {}),\n getCompositions: (opts) => rpc.call("getCompositions", opts || {}),\n editBehaviours: (opts) => rpc.call("editBehaviours", opts || {}),\n setTimeline: (opts) => rpc.call("setTimeline", opts || {}),\n setLayerTiming: (opts) => rpc.call("setLayerTiming", opts || {}),\n editTextAnimation: (opts) => rpc.call("editTextAnimation", opts || {}),\n edit3DScene: (opts) => rpc.call("edit3DScene", opts || {}),\n setInstancePlayback: (opts) => rpc.call("setInstancePlayback", opts || {}),\n editComponentProperty: (opts) => rpc.call("editComponentProperty", opts || {}),\n setShaderFill: (opts) => rpc.call("setShaderFill", opts || {}),\n createComposition: (opts) => rpc.call("createComposition", opts || {}),\n editComposition: (opts) => rpc.call("editComposition", opts || {}),\n editStateMachine: (opts) => rpc.call("editStateMachine", opts || {}),\n getStateMachine: (opts) => rpc.call("getStateMachine", opts || {}),\n applyMotionPreset: (opts) => rpc.call("applyMotionPreset", opts || {}),\n staggerMotion: (opts) => rpc.call("staggerMotion", opts || {}),\n createMotionComponent: (opts) => rpc.call("createMotionComponent", opts || {}),\n addAudio: (opts) => rpc.call("addAudio", opts || {}),\n editFrameAudio: (opts) => rpc.call("editFrameAudio", opts || {}),\n editVideoClip: (opts) => rpc.call("editVideoClip", opts || {}),\n detectAudioOnsets: (opts) => rpc.call("detectAudioOnsets", opts || {}),\n cutToBeat: (opts) => rpc.call("cutToBeat", opts || {}),\n editPrototype: (opts) => rpc.call("editPrototype", opts || {}),\n usePresentationFallbackAudio: (opts) => rpc.call("usePresentationFallbackAudio", opts || {}),\n /** Bring a Lottie, PDF or PopCraft file into the open document (the `importFile` field is the file an importer was handed). */\n importDocumentFile: (opts) => rpc.call("importDocumentFile", opts || {}),\n getStyles: () => rpc.call("getStyles"),\n createPaintStyle: (name, paints) => rpc.call("createPaintStyle", { name, paints }),\n getVariables: () => rpc.call("getVariables"),\n setVariableValue: (variableId, modeId, value) => rpc.call("setVariableValue", { variableId, modeId, value }),\n exportNode: (id, options) => rpc.call("exportNode", { id, options: options || {} }),\n openExternal: (url) => rpc.call("openExternal", { url }),\n notify: (message, options) => rpc.call("notify", { message: String(message), error: !!(options && options.error) }),\n showUI: (options) => rpc.call("showUI", options || {}),\n hideUI: () => rpc.call("hideUI"),\n /** Ends the run. The optional message is shown as a notification. */\n closePlugin: (message) => rpc.call("closePlugin", { message }),\n storage: {\n get: (key) => rpc.call("storageGet", { key }),\n set: (key, value) => rpc.call("storageSet", { key, value })\n },\n ui: {\n get onmessage() {\n return uiOnMessage;\n },\n set onmessage(cb) {\n uiOnMessage = cb;\n flushUI();\n },\n postMessage: (msg) => rpc.send({ kind: "toUI", data: msg }),\n on: (cb) => {\n uiHandlers.push(cb);\n flushUI();\n }\n },\n widget: {\n register(def) {\n if (!def || typeof def.render !== "function") throw new Error("popcraft.widget.register needs a render(state) function");\n widgetDef = def;\n widgetQueue.splice(0).forEach(handleWidgetClick);\n },\n insert(options) {\n if (!widgetDef) return Promise.reject(new Error("Call popcraft.widget.register first"));\n const o = options || {};\n const state = o.state !== void 0 ? clone(o.state) : initialWidgetState();\n return rpc.call("widgetInsert", { state, tree: renderWidget(state).tree, x: o.x, y: o.y });\n },\n getState: (nodeId) => rpc.call("widgetGet", { id: nodeId }),\n setState(nodeId, state) {\n if (!widgetDef) return Promise.reject(new Error("Call popcraft.widget.register first"));\n return commitWidget(nodeId, clone(state));\n }\n },\n on: (event, cb) => rpc.on(event, cb),\n off: (event, cb) => rpc.off(event, cb)\n };\n rpc.on("init", (data) => {\n var _a, _b, _c;\n popcraft.command = data.command;\n popcraft.importMode = (_a = data.importMode) != null ? _a : null;\n popcraft.importFile = (_b = data.importFile) != null ? _b : null;\n popcraft.exportRequest = (_c = data.exportRequest) != null ? _c : null;\n });\n return popcraft;\n }\n function installMainApi() {\n const rpc = createRpcClient();\n const api = createMainApi(rpc);\n const w = window;\n w.__popcraftRpc = rpc;\n w.popcraft = api;\n w.vizpops = api;\n window.addEventListener("error", (e) => rpc.send({ kind: "error", message: String(e.message || e) }));\n window.addEventListener("unhandledrejection", (e) => rpc.send({ kind: "error", message: String(e.reason && e.reason.message || e.reason) }));\n return api;\n }\n\n // src/runtime/main.entry.ts\n installMainApi();\n})();';
364390
364931
  UI_RUNTIME = '"use strict";\n(() => {\n // src/runtime/rpc.ts\n function createRpcClient() {\n let port = null;\n const queue = [];\n const pending = {};\n const listeners = {};\n let nextId = 1;\n function send(msg) {\n if (port) port.postMessage(msg);\n else queue.push(msg);\n }\n function call(method, params) {\n return new Promise((resolve, reject) => {\n const id = nextId++;\n pending[id] = { resolve, reject };\n send({ kind: "rpc", id, method, params });\n });\n }\n function emit(event, data) {\n for (const cb of (listeners[event] || []).slice()) {\n try {\n cb(data);\n } catch (e) {\n console.error(e);\n }\n }\n }\n window.addEventListener("message", (e) => {\n const data = e.data;\n if (e.source !== window.parent || !data || data.type !== "popcraft-plugin-port" || port) return;\n port = e.ports[0];\n port.onmessage = (ev) => {\n const m = ev.data || {};\n if (m.kind === "result" && m.id !== void 0 && pending[m.id]) {\n const p = pending[m.id];\n delete pending[m.id];\n if (m.error) p.reject(new Error(m.error));\n else p.resolve(m.result);\n } else if (m.kind === "event" && m.event) {\n emit(m.event, m.data);\n }\n };\n for (const msg of queue.splice(0)) port.postMessage(msg);\n });\n return {\n call,\n send,\n on(event, cb) {\n (listeners[event] = listeners[event] || []).push(cb);\n },\n off(event, cb) {\n listeners[event] = (listeners[event] || []).filter((x) => x !== cb);\n }\n };\n }\n\n // src/runtime/ui.ts\n function createUiApi(rpc = createRpcClient()) {\n const popcraft = {\n onmessage: null,\n postMessage: (msg) => rpc.send({ kind: "fromUI", data: msg }),\n close: () => rpc.send({ kind: "closeUI" })\n };\n rpc.on("message", (msg) => {\n if (typeof popcraft.onmessage === "function") popcraft.onmessage(msg);\n window.dispatchEvent(new MessageEvent("message", { data: { pluginMessage: msg } }));\n });\n return popcraft;\n }\n function installUiApi() {\n const rpc = createRpcClient();\n const api = createUiApi(rpc);\n const w = window;\n w.__popcraftRpc = rpc;\n w.popcraft = api;\n w.vizpops = api;\n return api;\n }\n\n // src/runtime/ui.entry.ts\n installUiApi();\n})();';
@@ -364420,7 +364961,7 @@ function buildUIDocument(uiHtml, network) {
364420
364961
  var escapeScript;
364421
364962
  var init_host2 = __esm({
364422
364963
  "node_modules/.pnpm/@popcraft+plugins@1.0.0_patch_hash=6826cb40a12857607fa1f7d7d102e5d8316bd483c1ff06865dac73139dfe709b/node_modules/@popcraft/plugins/dist/host.js"() {
364423
- init_runtime4();
364964
+ init_runtime5();
364424
364965
  escapeScript = (code) => code.replace(/<\/script/gi, "<\\/script");
364425
364966
  }
364426
364967
  });
@@ -364455,7 +364996,7 @@ var init_dist = __esm({
364455
364996
  "node_modules/.pnpm/@popcraft+plugins@1.0.0_patch_hash=6826cb40a12857607fa1f7d7d102e5d8316bd483c1ff06865dac73139dfe709b/node_modules/@popcraft/plugins/dist/index.js"() {
364456
364997
  init_host2();
364457
364998
  init_main();
364458
- init_runtime4();
364999
+ init_runtime5();
364459
365000
  init_types9();
364460
365001
  init_widget();
364461
365002
  }
@@ -364511,9 +365052,9 @@ button[data-variant="primary"] {
364511
365052
  }`;
364512
365053
  }
364513
365054
  function withPluginTheme(html, css = pluginThemeCss()) {
364514
- const tag = `<style data-pc="plugin-theme">${css}</style>`;
364515
- if (/<head[^>]*>/i.test(html)) return html.replace(/<head[^>]*>/i, (m) => m + tag);
364516
- return tag + html;
365055
+ const tag2 = `<style data-pc="plugin-theme">${css}</style>`;
365056
+ if (/<head[^>]*>/i.test(html)) return html.replace(/<head[^>]*>/i, (m) => m + tag2);
365057
+ return tag2 + html;
364517
365058
  }
364518
365059
  var init_ui_theme = __esm({
364519
365060
  "lib/plugins/ui-theme.ts"() {
@@ -364958,7 +365499,9 @@ function mergeImportedDocument(target2, imported, pageId2) {
364958
365499
  variables: { ...target2.variables, ...rewriteIds(imported.variables ?? {}, map2) },
364959
365500
  variableCollections: { ...target2.variableCollections, ...rewriteIds(imported.variableCollections ?? {}, map2) },
364960
365501
  // A library the open file already uses keeps its own version; the import only adds ones it lacks.
364961
- ...imported.libraries ? { libraries: { ...imported.libraries, ...target2.libraries } } : {}
365502
+ ...imported.libraries ? { libraries: { ...imported.libraries, ...target2.libraries } } : {},
365503
+ // The imported file's fonts come too, so its texts keep their type; a face the open file has for that slot stays.
365504
+ ...imported.fonts?.length ? { fonts: mergeFonts(target2.fonts, imported.fonts) } : {}
364962
365505
  };
364963
365506
  return { document: document2, added, addedPages };
364964
365507
  }
@@ -364966,6 +365509,7 @@ var init_import_merge = __esm({
364966
365509
  "lib/document/import-merge.ts"() {
364967
365510
  init_dist_node();
364968
365511
  init_libraries();
365512
+ init_document_fonts();
364969
365513
  }
364970
365514
  });
364971
365515
 
@@ -374761,9 +375305,9 @@ var init_pdf2 = __esm({
374761
375305
  FontFaceObject = class {
374762
375306
  compiledGlyphs = /* @__PURE__ */ Object.create(null);
374763
375307
  #fontData;
374764
- constructor(translatedData, inspectFont = null, charProcOperatorList, extra) {
375308
+ constructor(translatedData, inspectFont2 = null, charProcOperatorList, extra) {
374765
375309
  this.#fontData = translatedData;
374766
- this._inspectFont = inspectFont;
375310
+ this._inspectFont = inspectFont2;
374767
375311
  if (charProcOperatorList) {
374768
375312
  this.charProcOperatorList = charProcOperatorList;
374769
375313
  }
@@ -377233,12 +377777,12 @@ fn fs_main(in : VertexOutput) -> @location(0) vec4<f32> {
377233
377777
  const fillColor2 = this.current.fillColor;
377234
377778
  const isPatternFill = this.current.patternFill;
377235
377779
  const currentTransform = getCurrentTransform(ctx2);
377236
- let cache11, cacheKey, scaled, maskCanvas;
377780
+ let cache11, cacheKey2, scaled, maskCanvas;
377237
377781
  if ((img.bitmap || img.data) && img.count > 1) {
377238
377782
  const mainKey = img.bitmap || img.data.buffer;
377239
- cacheKey = JSON.stringify(isPatternFill ? currentTransform : [currentTransform.slice(0, 4), fillColor2]);
377783
+ cacheKey2 = JSON.stringify(isPatternFill ? currentTransform : [currentTransform.slice(0, 4), fillColor2]);
377240
377784
  cache11 = this._cachedBitmapsMap.getOrInsertComputed(mainKey, makeMap);
377241
- const cachedImage = cache11.get(cacheKey);
377785
+ const cachedImage = cache11.get(cacheKey2);
377242
377786
  if (cachedImage && !isPatternFill) {
377243
377787
  const offsetX2 = Math.round(Math.min(currentTransform[0], currentTransform[2]) + currentTransform[4]);
377244
377788
  const offsetY2 = Math.round(Math.min(currentTransform[1], currentTransform[3]) + currentTransform[5]);
@@ -377278,7 +377822,7 @@ fn fs_main(in : VertexOutput) -> @location(0) vec4<f32> {
377278
377822
  maskCanvas = null;
377279
377823
  }
377280
377824
  if (cache11 && isPatternFill) {
377281
- cache11.set(cacheKey, scaled);
377825
+ cache11.set(cacheKey2, scaled);
377282
377826
  scaledEntry = null;
377283
377827
  maskCanvas = null;
377284
377828
  }
@@ -377296,7 +377840,7 @@ fn fs_main(in : VertexOutput) -> @location(0) vec4<f32> {
377296
377840
  fillCtx.fillStyle = isPatternFill ? fillColor2.getPattern(ctx2, this, inverse, PathType.FILL, opIdx) : fillColor2;
377297
377841
  fillCtx.fillRect(0, 0, width, height);
377298
377842
  if (cache11 && !isPatternFill) {
377299
- cache11.set(cacheKey, fillCanvas.canvas);
377843
+ cache11.set(cacheKey2, fillCanvas.canvas);
377300
377844
  }
377301
377845
  this.dependencyTracker?.recordDependencies(opIdx, Dependencies.transformAndFill);
377302
377846
  return {
@@ -377687,8 +378231,8 @@ fn fs_main(in : VertexOutput) -> @location(0) vec4<f32> {
377687
378231
  }
377688
378232
  return true;
377689
378233
  }
377690
- #endKnockoutElement(started7) {
377691
- if (!started7) {
378234
+ #endKnockoutElement(started8) {
378235
+ if (!started8) {
377692
378236
  return;
377693
378237
  }
377694
378238
  const tempEntry = this.#knockoutTempCanvasEntry;
@@ -377903,7 +378447,7 @@ fn fs_main(in : VertexOutput) -> @location(0) vec4<f32> {
377903
378447
  this.ctx.closePath();
377904
378448
  }
377905
378449
  stroke(opIdx, path, consumePath = true) {
377906
- const started7 = consumePath && this.#beginKnockoutElement(this.current.strokeAlpha);
378450
+ const started8 = consumePath && this.#beginKnockoutElement(this.current.strokeAlpha);
377907
378451
  const ctx2 = this.ctx;
377908
378452
  const strokeColor = this.current.strokeColor;
377909
378453
  ctx2.globalAlpha = this.current.strokeAlpha;
@@ -377928,13 +378472,13 @@ fn fs_main(in : VertexOutput) -> @location(0) vec4<f32> {
377928
378472
  this.consumePath(opIdx, path, this.current.getClippedPathBoundingBox(PathType.STROKE, getCurrentTransform(this.ctx)));
377929
378473
  }
377930
378474
  ctx2.globalAlpha = this.current.fillAlpha;
377931
- this.#endKnockoutElement(started7);
378475
+ this.#endKnockoutElement(started8);
377932
378476
  }
377933
378477
  closeStroke(opIdx, path) {
377934
378478
  this.stroke(opIdx, path);
377935
378479
  }
377936
378480
  fill(opIdx, path, consumePath = true) {
377937
- const started7 = consumePath && this.#beginKnockoutElement(this.current.fillAlpha);
378481
+ const started8 = consumePath && this.#beginKnockoutElement(this.current.fillAlpha);
377938
378482
  const ctx2 = this.ctx;
377939
378483
  const fillColor2 = this.current.fillColor;
377940
378484
  const isPatternFill = this.current.patternFill;
@@ -377951,7 +378495,7 @@ fn fs_main(in : VertexOutput) -> @location(0) vec4<f32> {
377951
378495
  this.consumePath(opIdx, path, intersect2);
377952
378496
  }
377953
378497
  this.current.tilingPatternDims = null;
377954
- this.#endKnockoutElement(started7);
378498
+ this.#endKnockoutElement(started8);
377955
378499
  return;
377956
378500
  }
377957
378501
  const baseTransform = fillColor2.isModifyingCurrentTransform() ? ctx2.getTransform() : null;
@@ -377980,18 +378524,18 @@ fn fs_main(in : VertexOutput) -> @location(0) vec4<f32> {
377980
378524
  if (consumePath) {
377981
378525
  this.consumePath(opIdx, path, intersect2);
377982
378526
  }
377983
- this.#endKnockoutElement(started7);
378527
+ this.#endKnockoutElement(started8);
377984
378528
  }
377985
378529
  eoFill(opIdx, path) {
377986
378530
  this.pendingEOFill = true;
377987
378531
  this.fill(opIdx, path);
377988
378532
  }
377989
378533
  fillStroke(opIdx, path) {
377990
- const started7 = this.#beginKnockoutElement(Math.min(this.current.fillAlpha, this.current.strokeAlpha));
378534
+ const started8 = this.#beginKnockoutElement(Math.min(this.current.fillAlpha, this.current.strokeAlpha));
377991
378535
  this.fill(opIdx, path, false);
377992
378536
  this.stroke(opIdx, path, false);
377993
378537
  this.consumePath(opIdx, path);
377994
- this.#endKnockoutElement(started7);
378538
+ this.#endKnockoutElement(started8);
377995
378539
  }
377996
378540
  eoFillStroke(opIdx, path) {
377997
378541
  this.pendingEOFill = true;
@@ -378008,10 +378552,10 @@ fn fs_main(in : VertexOutput) -> @location(0) vec4<f32> {
378008
378552
  this.consumePath(opIdx, path);
378009
378553
  }
378010
378554
  rawFillPath(opIdx, path) {
378011
- const started7 = this.#beginKnockoutElement(this.current.fillAlpha);
378555
+ const started8 = this.#beginKnockoutElement(this.current.fillAlpha);
378012
378556
  this.ctx.fill(path);
378013
378557
  this.dependencyTracker?.recordDependencies(opIdx, Dependencies.rawFillPath).recordOperation(opIdx);
378014
- this.#endKnockoutElement(started7);
378558
+ this.#endKnockoutElement(started8);
378015
378559
  }
378016
378560
  clip(opIdx) {
378017
378561
  this.dependencyTracker?.recordFutureForcedDependency("clipMode", opIdx);
@@ -378247,10 +378791,10 @@ fn fs_main(in : VertexOutput) -> @location(0) vec4<f32> {
378247
378791
  const current3 = this.current;
378248
378792
  const font = current3.font;
378249
378793
  if (font.isType3Font) {
378250
- const started8 = this.#beginKnockoutElement(current3.fillAlpha);
378794
+ const started9 = this.#beginKnockoutElement(current3.fillAlpha);
378251
378795
  this.showType3Text(opIdx, glyphs);
378252
378796
  this.dependencyTracker?.recordShowTextOperation(opIdx);
378253
- this.#endKnockoutElement(started8);
378797
+ this.#endKnockoutElement(started9);
378254
378798
  return;
378255
378799
  }
378256
378800
  const fontSize = current3.fontSize;
@@ -378258,7 +378802,7 @@ fn fs_main(in : VertexOutput) -> @location(0) vec4<f32> {
378258
378802
  this.dependencyTracker?.recordOperation(opIdx);
378259
378803
  return;
378260
378804
  }
378261
- const started7 = this.#beginKnockoutElement(current3.fillAlpha);
378805
+ const started8 = this.#beginKnockoutElement(current3.fillAlpha);
378262
378806
  const ctx2 = this.ctx;
378263
378807
  const fontSizeScale = current3.fontSizeScale;
378264
378808
  const charSpacing = current3.charSpacing;
@@ -378329,7 +378873,7 @@ fn fs_main(in : VertexOutput) -> @location(0) vec4<f32> {
378329
378873
  current3.x += width * widthAdvanceScale * textHScale;
378330
378874
  ctx2.restore();
378331
378875
  this.compose();
378332
- this.#endKnockoutElement(started7);
378876
+ this.#endKnockoutElement(started8);
378333
378877
  return;
378334
378878
  }
378335
378879
  let x2 = 0, i2;
@@ -378399,7 +378943,7 @@ fn fs_main(in : VertexOutput) -> @location(0) vec4<f32> {
378399
378943
  ctx2.restore();
378400
378944
  this.compose();
378401
378945
  this.dependencyTracker?.recordShowTextOperation(opIdx);
378402
- this.#endKnockoutElement(started7);
378946
+ this.#endKnockoutElement(started8);
378403
378947
  }
378404
378948
  showType3Text(opIdx, glyphs) {
378405
378949
  const ctx2 = this.ctx;
@@ -378531,7 +379075,7 @@ fn fs_main(in : VertexOutput) -> @location(0) vec4<f32> {
378531
379075
  if (!this.contentVisible) {
378532
379076
  return;
378533
379077
  }
378534
- const started7 = this.#beginKnockoutElement(this.current.fillAlpha);
379078
+ const started8 = this.#beginKnockoutElement(this.current.fillAlpha);
378535
379079
  const ctx2 = this.ctx;
378536
379080
  this.save(opIdx);
378537
379081
  const pattern = this._getPattern(opIdx, objId2);
@@ -378552,7 +379096,7 @@ fn fs_main(in : VertexOutput) -> @location(0) vec4<f32> {
378552
379096
  this.dependencyTracker?.resetBBox(opIdx).recordFullPageBBox(opIdx).recordDependencies(opIdx, Dependencies.transform).recordDependencies(opIdx, Dependencies.fill).recordOperation(opIdx);
378553
379097
  this.compose(this.current.getClippedPathBoundingBox());
378554
379098
  this.restore(opIdx);
378555
- this.#endKnockoutElement(started7);
379099
+ this.#endKnockoutElement(started8);
378556
379100
  }
378557
379101
  beginInlineImage() {
378558
379102
  unreachable("Should not call beginInlineImage");
@@ -378928,7 +379472,7 @@ fn fs_main(in : VertexOutput) -> @location(0) vec4<f32> {
378928
379472
  const count2 = img.count;
378929
379473
  img = this.getObject(opIdx, img.data, img);
378930
379474
  img.count = count2;
378931
- const started7 = this.#beginKnockoutElement(this.current.fillAlpha);
379475
+ const started8 = this.#beginKnockoutElement(this.current.fillAlpha);
378932
379476
  const ctx2 = this.ctx;
378933
379477
  const mask = this._createMaskCanvas(opIdx, img);
378934
379478
  const maskCanvas = mask.canvas;
@@ -378941,14 +379485,14 @@ fn fs_main(in : VertexOutput) -> @location(0) vec4<f32> {
378941
379485
  this.canvasFactory.destroy(mask.canvasEntry);
378942
379486
  }
378943
379487
  this.compose();
378944
- this.#endKnockoutElement(started7);
379488
+ this.#endKnockoutElement(started8);
378945
379489
  }
378946
379490
  paintImageMaskXObjectRepeat(opIdx, img, scaleX, skewX = 0, skewY = 0, scaleY, positions) {
378947
379491
  if (!this.contentVisible) {
378948
379492
  return;
378949
379493
  }
378950
379494
  img = this.getObject(opIdx, img.data, img);
378951
- const started7 = this.#beginKnockoutElement(this.current.fillAlpha);
379495
+ const started8 = this.#beginKnockoutElement(this.current.fillAlpha);
378952
379496
  const ctx2 = this.ctx;
378953
379497
  ctx2.save();
378954
379498
  const currentTransform = getCurrentTransform(ctx2);
@@ -378967,13 +379511,13 @@ fn fs_main(in : VertexOutput) -> @location(0) vec4<f32> {
378967
379511
  }
378968
379512
  this.compose();
378969
379513
  this.dependencyTracker?.recordOperation(opIdx);
378970
- this.#endKnockoutElement(started7);
379514
+ this.#endKnockoutElement(started8);
378971
379515
  }
378972
379516
  paintImageMaskXObjectGroup(opIdx, images) {
378973
379517
  if (!this.contentVisible) {
378974
379518
  return;
378975
379519
  }
378976
- const started7 = this.#beginKnockoutElement(this.current.fillAlpha);
379520
+ const started8 = this.#beginKnockoutElement(this.current.fillAlpha);
378977
379521
  const ctx2 = this.ctx;
378978
379522
  const fillColor2 = this.current.fillColor;
378979
379523
  const isPatternFill = this.current.patternFill;
@@ -379004,7 +379548,7 @@ fn fs_main(in : VertexOutput) -> @location(0) vec4<f32> {
379004
379548
  }
379005
379549
  this.compose();
379006
379550
  this.dependencyTracker?.recordOperation(opIdx);
379007
- this.#endKnockoutElement(started7);
379551
+ this.#endKnockoutElement(started8);
379008
379552
  }
379009
379553
  paintImageXObject(opIdx, objId2) {
379010
379554
  if (!this.contentVisible) {
@@ -379076,7 +379620,7 @@ fn fs_main(in : VertexOutput) -> @location(0) vec4<f32> {
379076
379620
  }
379077
379621
  const width = imgData.width;
379078
379622
  const height = imgData.height;
379079
- const started7 = this.#beginKnockoutElement(this.current.fillAlpha);
379623
+ const started8 = this.#beginKnockoutElement(this.current.fillAlpha);
379080
379624
  const ctx2 = this.ctx;
379081
379625
  this.save(opIdx);
379082
379626
  const {
@@ -379113,13 +379657,13 @@ fn fs_main(in : VertexOutput) -> @location(0) vec4<f32> {
379113
379657
  }
379114
379658
  this.compose();
379115
379659
  this.restore(opIdx);
379116
- this.#endKnockoutElement(started7);
379660
+ this.#endKnockoutElement(started8);
379117
379661
  }
379118
379662
  paintInlineImageXObjectGroup(opIdx, imgData, map2) {
379119
379663
  if (!this.contentVisible) {
379120
379664
  return;
379121
379665
  }
379122
- const started7 = this.#beginKnockoutElement(this.current.fillAlpha);
379666
+ const started8 = this.#beginKnockoutElement(this.current.fillAlpha);
379123
379667
  const ctx2 = this.ctx;
379124
379668
  let imgToPaint;
379125
379669
  let inlineImgCanvas = null;
@@ -379147,31 +379691,31 @@ fn fs_main(in : VertexOutput) -> @location(0) vec4<f32> {
379147
379691
  }
379148
379692
  this.dependencyTracker?.recordOperation(opIdx);
379149
379693
  this.compose();
379150
- this.#endKnockoutElement(started7);
379694
+ this.#endKnockoutElement(started8);
379151
379695
  }
379152
379696
  paintSolidColorImageMask(opIdx) {
379153
379697
  if (!this.contentVisible) {
379154
379698
  return;
379155
379699
  }
379156
- const started7 = this.#beginKnockoutElement(this.current.fillAlpha);
379700
+ const started8 = this.#beginKnockoutElement(this.current.fillAlpha);
379157
379701
  this.dependencyTracker?.resetBBox(opIdx).recordBBox(opIdx, this.ctx, 0, 1, 0, 1).recordDependencies(opIdx, Dependencies.fill).recordOperation(opIdx);
379158
379702
  this.ctx.fillRect(0, 0, 1, 1);
379159
379703
  this.compose();
379160
- this.#endKnockoutElement(started7);
379704
+ this.#endKnockoutElement(started8);
379161
379705
  }
379162
- markPoint(opIdx, tag) {
379706
+ markPoint(opIdx, tag2) {
379163
379707
  }
379164
- markPointProps(opIdx, tag, properties) {
379708
+ markPointProps(opIdx, tag2, properties) {
379165
379709
  }
379166
- beginMarkedContent(opIdx, tag) {
379710
+ beginMarkedContent(opIdx, tag2) {
379167
379711
  this.dependencyTracker?.beginMarkedContent(opIdx);
379168
379712
  this.markedContentStack.push({
379169
379713
  visible: true
379170
379714
  });
379171
379715
  }
379172
- beginMarkedContentProps(opIdx, tag, properties) {
379716
+ beginMarkedContentProps(opIdx, tag2, properties) {
379173
379717
  this.dependencyTracker?.beginMarkedContent(opIdx);
379174
- if (tag === "OC") {
379718
+ if (tag2 === "OC") {
379175
379719
  this.markedContentStack.push({
379176
379720
  visible: this.optionalContentConfig.isVisible(properties)
379177
379721
  });
@@ -381423,11 +381967,11 @@ fn fs_main(in : VertexOutput) -> @location(0) vec4<f32> {
381423
381967
  const intentArgs = this._transport.getRenderingIntent(intent, annotationMode, printAnnotationStorage, isEditing);
381424
381968
  const {
381425
381969
  renderingIntent,
381426
- cacheKey
381970
+ cacheKey: cacheKey2
381427
381971
  } = intentArgs;
381428
381972
  this.#pendingCleanup = false;
381429
381973
  optionalContentConfigPromise ||= this._transport.getOptionalContentConfig(renderingIntent);
381430
- const intentState = this._intentStates.getOrInsertComputed(cacheKey, makeObj);
381974
+ const intentState = this._intentStates.getOrInsertComputed(cacheKey2, makeObj);
381431
381975
  if (intentState.streamReaderCancelTimeout) {
381432
381976
  clearTimeout(intentState.streamReaderCancelTimeout);
381433
381977
  intentState.streamReaderCancelTimeout = null;
@@ -381647,8 +382191,8 @@ fn fs_main(in : VertexOutput) -> @location(0) vec4<f32> {
381647
382191
  this.#pendingCleanup = false;
381648
382192
  return true;
381649
382193
  }
381650
- _startRenderPage(transparency, cacheKey) {
381651
- const intentState = this._intentStates.get(cacheKey);
382194
+ _startRenderPage(transparency, cacheKey2) {
382195
+ const intentState = this._intentStates.get(cacheKey2);
381652
382196
  if (!intentState) {
381653
382197
  return;
381654
382198
  }
@@ -381671,7 +382215,7 @@ fn fs_main(in : VertexOutput) -> @location(0) vec4<f32> {
381671
382215
  }
381672
382216
  _pumpOperatorList({
381673
382217
  renderingIntent,
381674
- cacheKey,
382218
+ cacheKey: cacheKey2,
381675
382219
  annotationStorageSerializable,
381676
382220
  modifiedIds
381677
382221
  }) {
@@ -381683,12 +382227,12 @@ fn fs_main(in : VertexOutput) -> @location(0) vec4<f32> {
381683
382227
  pageId: this.#pagesMapper.getPageId(this._pageIndex + 1) - 1,
381684
382228
  pageIndex: this._pageIndex,
381685
382229
  intent: renderingIntent,
381686
- cacheKey,
382230
+ cacheKey: cacheKey2,
381687
382231
  annotationStorage: map2,
381688
382232
  modifiedIds
381689
382233
  }, void 0, transfer);
381690
382234
  const reader = readableStream.getReader();
381691
- const intentState = this._intentStates.get(cacheKey);
382235
+ const intentState = this._intentStates.get(cacheKey2);
381692
382236
  intentState.streamReader = reader;
381693
382237
  const pump = () => {
381694
382238
  reader.read().then(({
@@ -382260,8 +382804,8 @@ fn fs_main(in : VertexOutput) -> @location(0) vec4<f32> {
382260
382804
  break;
382261
382805
  }
382262
382806
  const fontData = new FontInfo(exportedData);
382263
- const inspectFont = this._params.pdfBug && globalThis.FontInspector?.enabled ? (font2, url4) => globalThis.FontInspector.fontAdded(font2, url4) : null;
382264
- const font = new FontFaceObject(fontData, inspectFont, exportedData.charProcOperatorList, exportedData.extra);
382807
+ const inspectFont2 = this._params.pdfBug && globalThis.FontInspector?.enabled ? (font2, url4) => globalThis.FontInspector.fontAdded(font2, url4) : null;
382808
+ const font = new FontFaceObject(fontData, inspectFont2, exportedData.charProcOperatorList, exportedData.extra);
382265
382809
  this.fontLoader.bind(font).catch(() => messageHandler.sendWithPromise("FontFallback", {
382266
382810
  id: id3
382267
382811
  })).finally(() => {
@@ -394100,8 +394644,10 @@ async function buildImportedDocument(file2) {
394100
394644
  }
394101
394645
  if (ext === ".json" || ext === ".popcraft" || ext === ".vizpops") {
394102
394646
  try {
394103
- const imported = JSON.parse(await file2.text());
394104
- if (!imported?.id || !imported?.nodes || !imported?.pages?.length) return null;
394647
+ const parsed2 = JSON.parse(await file2.text());
394648
+ if (!parsed2?.id || !parsed2?.nodes || !parsed2?.pages?.length) return null;
394649
+ const { internDocumentFonts: internDocumentFonts2 } = await Promise.resolve().then(() => (init_document_fonts(), document_fonts_exports));
394650
+ const imported = internDocumentFonts2(parsed2);
394105
394651
  const document2 = { ...imported, name: seedName || imported.name || "Imported" };
394106
394652
  const pageId2 = document2.pages[0];
394107
394653
  return { document: document2, frameIds: document2.nodes[pageId2]?.childIds?.slice() ?? [] };
@@ -395431,6 +395977,457 @@ var init_integration = __esm({
395431
395977
  }
395432
395978
  });
395433
395979
 
395980
+ // lib/fonts/inspect.ts
395981
+ var inspect_exports = {};
395982
+ __export(inspect_exports, {
395983
+ chooseFace: () => chooseFace,
395984
+ inspectFont: () => inspectFont,
395985
+ listFaces: () => listFaces
395986
+ });
395987
+ function describe4(face, index2) {
395988
+ const os2 = face["OS/2"];
395989
+ const family = english(face.name?.records?.preferredFamily) ?? face.familyName ?? "";
395990
+ const subfamily = english(face.name?.records?.preferredSubfamily) ?? face.subfamilyName ?? "";
395991
+ const italic = !!os2?.fsSelection?.italic || (face.italicAngle ?? 0) !== 0 || /italic|oblique/i.test(subfamily);
395992
+ const weight = os2?.usWeightClass && os2.usWeightClass >= 1 && os2.usWeightClass <= 1e3 ? os2.usWeightClass : 400;
395993
+ return { index: index2, family, subfamily, fullName: face.fullName ?? `${family} ${subfamily}`.trim(), postscriptName: face.postscriptName ?? "", weight, style: italic ? "italic" : "normal" };
395994
+ }
395995
+ async function inspectFont(bytes2) {
395996
+ const format = fontFormat(bytes2);
395997
+ if (!format) throw new Error("That is not a font file (TrueType, OpenType, a collection, WOFF or WOFF2).");
395998
+ const created = await createFont(await toSfnt(bytes2));
395999
+ const list2 = "fonts" in created ? created.fonts : [created];
396000
+ return { format, faces: list2.map((f2, i2) => describe4(f2, i2)) };
396001
+ }
396002
+ function chooseFace(info2, choice) {
396003
+ if (choice === void 0 || choice === "") return info2.faces[0];
396004
+ const n = typeof choice === "number" ? choice : /^\d+$/.test(choice.trim()) ? Number(choice) : null;
396005
+ if (n !== null) {
396006
+ const hit2 = info2.faces[n];
396007
+ if (!hit2) throw new Error(`There is no face ${n}. ${listFaces(info2)}`);
396008
+ return hit2;
396009
+ }
396010
+ const key5 = (s) => s.toLowerCase().replace(/[\s_-]+/g, "");
396011
+ const want = key5(String(choice));
396012
+ const hit = info2.faces.find((f2) => key5(f2.postscriptName) === want || key5(f2.fullName) === want || key5(f2.subfamily) === want) ?? info2.faces.find((f2) => key5(f2.fullName).includes(want) || key5(f2.postscriptName).includes(want));
396013
+ if (!hit) throw new Error(`No face is called "${choice}". ${listFaces(info2)}`);
396014
+ return hit;
396015
+ }
396016
+ var english, listFaces;
396017
+ var init_inspect = __esm({
396018
+ "lib/fonts/inspect.ts"() {
396019
+ init_fontkit_lazy();
396020
+ init_shaper();
396021
+ init_sfnt();
396022
+ english = (r) => r ? r.en ?? Object.values(r)[0] : void 0;
396023
+ listFaces = (info2) => `The file has ${info2.faces.length} face${info2.faces.length === 1 ? "" : "s"}: ${info2.faces.map((f2) => `${f2.index} ${f2.fullName || f2.postscriptName}`).join(", ")}.`;
396024
+ }
396025
+ });
396026
+
396027
+ // lib/commands/font.ts
396028
+ async function fontBytes(args2, ctx2) {
396029
+ const { MAX_FONT_BYTES: MAX_FONT_BYTES3, isFontBytes: isFontBytes2 } = await Promise.resolve().then(() => (init_fonts(), fonts_exports));
396030
+ let got = null;
396031
+ if (args2.file) {
396032
+ if (!ctx2.can("files")) throw new CommandError("Only the CLI reads font files by path. Pass the file as src (a data URL), or upload it in the font picker.", "unsupported");
396033
+ try {
396034
+ got = { bytes: await ctx2.use("files").read(args2.file), fileName: args2.file.replace(/^.*[\\/]/, "") };
396035
+ } catch (e) {
396036
+ throw new CommandError(`Cannot read ${args2.file}: ${e.message}`, "invalid_params");
396037
+ }
396038
+ } else if (args2.src) {
396039
+ const { isMediaUrl: isMediaUrl2, loadMediaBlob: loadMediaBlob2 } = await Promise.resolve().then(() => (init_media_store(), media_store_exports));
396040
+ if (isMediaUrl2(args2.src)) {
396041
+ const blob = await loadMediaBlob2(args2.src);
396042
+ if (!blob) throw new CommandError(`${args2.src} is not on this device.`, "not_found");
396043
+ got = { bytes: new Uint8Array(await blob.arrayBuffer()) };
396044
+ } else if (/^data:[^,]*;base64,/.test(args2.src)) {
396045
+ const bin = atob(args2.src.slice(args2.src.indexOf(",") + 1));
396046
+ got = { bytes: Uint8Array.from(bin, (c2) => c2.charCodeAt(0)) };
396047
+ } else throw new CommandError("src is a base64 data URL or a media:// ref.", "invalid_params");
396048
+ } else if (ctx2.actor.kind === "user" && typeof document !== "undefined") {
396049
+ const file2 = await pickFontFile();
396050
+ if (!file2) throw new CommandError("No font file chosen.", "failed");
396051
+ got = { bytes: new Uint8Array(await file2.arrayBuffer()), fileName: file2.name };
396052
+ } else {
396053
+ throw new CommandError("Give the font file: file (a path, in the CLI) or src (a data URL or media:// ref).", "invalid_params");
396054
+ }
396055
+ if (got.bytes.length > MAX_FONT_BYTES3) throw new CommandError(`That font file is over ${MAX_FONT_BYTES3 / 1024 / 1024} MB.`, "invalid_params");
396056
+ if (!isFontBytes2(got.bytes)) throw new CommandError("That is not a font file (TrueType, OpenType, a collection, WOFF or WOFF2).", "invalid_params");
396057
+ return got;
396058
+ }
396059
+ function pickFontFile() {
396060
+ return new Promise((resolve6) => {
396061
+ const input2 = document.createElement("input");
396062
+ input2.type = "file";
396063
+ input2.accept = ".ttf,.otf,.ttc,.otc,.woff,.woff2";
396064
+ input2.style.display = "none";
396065
+ let settled2 = false;
396066
+ const done = (f2) => {
396067
+ if (settled2) return;
396068
+ settled2 = true;
396069
+ input2.remove();
396070
+ resolve6(f2);
396071
+ };
396072
+ input2.addEventListener("change", () => done(input2.files?.[0] ?? null));
396073
+ input2.addEventListener("cancel", () => done(null));
396074
+ document.body.appendChild(input2);
396075
+ input2.click();
396076
+ });
396077
+ }
396078
+ async function resolveFace(bytes2, args2) {
396079
+ const { inspectFont: inspectFont2, chooseFace: chooseFace2 } = await Promise.resolve().then(() => (init_inspect(), inspect_exports));
396080
+ let info2;
396081
+ try {
396082
+ info2 = await inspectFont2(bytes2);
396083
+ } catch (e) {
396084
+ throw new CommandError(e.message, "invalid_params");
396085
+ }
396086
+ let face;
396087
+ try {
396088
+ face = chooseFace2(info2, args2.face);
396089
+ } catch (e) {
396090
+ throw new CommandError(e.message, "invalid_params");
396091
+ }
396092
+ const family = args2.family?.trim() || face.family;
396093
+ if (!family) throw new CommandError("The file names no family: pass family.", "invalid_params");
396094
+ return { info: info2, face, family, weight: args2.weight ?? face.weight, style: args2.style ?? face.style };
396095
+ }
396096
+ var MAX_SRC, faceParam, brief4, fontAdd, fontList, fontRemove, fontCommands;
396097
+ var init_font = __esm({
396098
+ "lib/commands/font.ts"() {
396099
+ "use strict";
396100
+ init_zod();
396101
+ init_errors();
396102
+ init_types5();
396103
+ init_doc_helpers();
396104
+ MAX_SRC = 48 * 1024 * 1024;
396105
+ faceParam = external_exports.union([external_exports.number().int().min(0).max(255), external_exports.string().trim().min(1).max(200)]).describe('In a collection (.ttc/.otc): the face to use, by index from 0 or by name ("Bold", "Helvetica-Bold"). font_list with the file lists them.');
396106
+ brief4 = (f2) => ({ id: f2.id, family: f2.family, weight: f2.weight ?? 400, style: f2.style ?? "normal", ...f2.face ? { face: f2.face } : {}, src: f2.src, ...f2.fileName ? { fileName: f2.fileName } : {}, ...f2.postscriptName ? { postscriptName: f2.postscriptName } : {} });
396107
+ fontAdd = defineCommand({
396108
+ id: "font.add",
396109
+ title: "Add font to file",
396110
+ domain: "font",
396111
+ effect: "document",
396112
+ permission: "write",
396113
+ undoLabel: "Add font",
396114
+ params: external_exports.object({
396115
+ family: external_exports.string().trim().min(1).max(200).optional().describe("The family name texts will use (default: the name in the file). Texts set in it draw in this file."),
396116
+ file: external_exports.string().min(1).max(4096).optional().describe("A font file on this machine, read by the CLI: .ttf, .otf, .ttc, .woff or .woff2."),
396117
+ src: external_exports.string().max(MAX_SRC).optional().describe("The font file as a base64 data URL, or a media:// ref already on this device."),
396118
+ weight: external_exports.number().int().min(1).max(1e3).optional().describe("The weight this face stands for (default: the file's)."),
396119
+ style: external_exports.enum(["normal", "italic"]).optional().describe("normal or italic (default: the file's)."),
396120
+ face: faceParam.optional()
396121
+ }).strict(),
396122
+ expose: {
396123
+ ui: { label: "Add font to file\u2026", keywords: ["font", "typeface", "upload", "ttf", "otf", "ttc", "woff", "type", "custom font"] },
396124
+ agent: {
396125
+ name: "add_font",
396126
+ description: "Carry a font file in this file so texts can be set in it (and every export draws it): src is the file as a base64 data URL or a media:// ref; family defaults to the name in the file, weight and style to the face's. For a collection (.ttc), face picks one by index or name. A face already in that family, weight and style is replaced. Then set texts' fontFamily to the family."
396127
+ }
396128
+ },
396129
+ run: async (args2, ctx2) => {
396130
+ const { bytes: bytes2, fileName: fileName2 } = await fontBytes(args2, ctx2);
396131
+ const { face, family, weight, style, info: info2 } = await resolveFace(bytes2, args2);
396132
+ const { internBytes: internBytes2 } = await Promise.resolve().then(() => (init_media_store(), media_store_exports));
396133
+ const { fontMime: fontMime2 } = await Promise.resolve().then(() => (init_sfnt(), sfnt_exports));
396134
+ const { addDocumentFont: addDocumentFont2 } = await Promise.resolve().then(() => (init_document_fonts(), document_fonts_exports));
396135
+ const src = internBytes2(bytes2, fontMime2(bytes2));
396136
+ const font = {
396137
+ id: `font-${src.slice(8, 20)}-${face.index}-${weight}-${style === "italic" ? "i" : "n"}`,
396138
+ family,
396139
+ src,
396140
+ weight,
396141
+ style,
396142
+ ...face.index ? { face: face.index } : {},
396143
+ ...fileName2 ? { fileName: fileName2 } : {},
396144
+ ...face.postscriptName ? { postscriptName: face.postscriptName } : {}
396145
+ };
396146
+ ctx2.commit(addDocumentFont2(ctx2.doc(), font), "Add font");
396147
+ const many = info2.faces.length > 1;
396148
+ const note2 = many && args2.face === void 0 ? ` (face 0 of ${info2.faces.length}: pass face to choose another)` : many ? ` (face ${face.index} of ${info2.faces.length})` : "";
396149
+ return {
396150
+ summary: `Added ${family} ${weight}${style === "italic" ? " italic" : ""} to the file${note2}`,
396151
+ data: { font: brief4(font), ...many ? { faces: info2.faces } : {} }
396152
+ };
396153
+ }
396154
+ });
396155
+ fontList = defineCommand({
396156
+ id: "font.list",
396157
+ title: "List fonts",
396158
+ domain: "font",
396159
+ effect: "none",
396160
+ permission: "read",
396161
+ params: external_exports.object({
396162
+ file: external_exports.string().min(1).max(4096).optional().describe("List the faces of this font file instead (the CLI): a collection's faces, to choose one for font.add."),
396163
+ src: external_exports.string().max(MAX_SRC).optional().describe("List the faces of this font file instead: a base64 data URL or a media:// ref.")
396164
+ }).strict(),
396165
+ expose: {
396166
+ ui: { label: "List fonts in file", keywords: ["font", "fonts", "missing font", "typeface"] },
396167
+ agent: {
396168
+ name: "list_fonts",
396169
+ readOnly: true,
396170
+ description: "The font files this file carries (family, weight, style, face), the families its texts use, and the MISSING ones: families nothing can draw, whose texts fall back to another font. With src, lists the faces of that font file instead (a collection's, to pick one for add_font)."
396171
+ }
396172
+ },
396173
+ run: async (args2, ctx2) => {
396174
+ if (args2.file || args2.src) {
396175
+ const { bytes: bytes2 } = await fontBytes(args2, ctx2);
396176
+ const { inspectFont: inspectFont2 } = await Promise.resolve().then(() => (init_inspect(), inspect_exports));
396177
+ const info2 = await inspectFont2(bytes2).catch((e) => {
396178
+ throw new CommandError(e.message, "invalid_params");
396179
+ });
396180
+ return { summary: `${plural2(info2.faces.length, "face")} (${info2.format})`, data: info2 };
396181
+ }
396182
+ const doc2 = ctx2.doc();
396183
+ const [{ usedFontFamilies: usedFontFamilies2 }, { findMissingFonts: findMissingFonts2 }] = await Promise.all([Promise.resolve().then(() => (init_document_fonts(), document_fonts_exports)), Promise.resolve().then(() => (init_runtime3(), runtime_exports2))]);
396184
+ const missing = await findMissingFonts2(doc2);
396185
+ const fonts = (doc2.fonts ?? []).map(brief4);
396186
+ const used = [...usedFontFamilies2(doc2)].map(([family, ids2]) => ({ family, texts: ids2.length }));
396187
+ return {
396188
+ summary: `${plural2(fonts.length, "font")} in the file${missing.length ? `; missing: ${missing.map((m) => m.family).join(", ")}` : ""}`,
396189
+ data: { fonts, used, missing: missing.map((m) => ({ family: m.family, texts: m.nodeIds.length, nodeIds: m.nodeIds.slice(0, 50) })) }
396190
+ };
396191
+ }
396192
+ });
396193
+ fontRemove = defineCommand({
396194
+ id: "font.remove",
396195
+ title: "Remove font from file",
396196
+ domain: "font",
396197
+ effect: "document",
396198
+ permission: "write",
396199
+ undoLabel: "Remove font",
396200
+ params: external_exports.object({
396201
+ id: external_exports.string().min(1).max(200).optional().describe("The face's id from font_list."),
396202
+ family: external_exports.string().trim().min(1).max(200).optional().describe("Every face of this family (narrowed by weight and style when given)."),
396203
+ weight: external_exports.number().int().min(1).max(1e3).optional(),
396204
+ style: external_exports.enum(["normal", "italic"]).optional()
396205
+ }).strict(),
396206
+ expose: {
396207
+ ui: { label: "Remove font from file", palette: false },
396208
+ agent: {
396209
+ name: "remove_font",
396210
+ description: "Stop carrying a font in this file: by id (from list_fonts) or by family, narrowed by weight and style. Texts set in it then draw in a fallback font and are reported missing."
396211
+ }
396212
+ },
396213
+ run: async (args2, ctx2) => {
396214
+ if (!args2.id && !args2.family) throw new CommandError("Name the font: id, or family.", "invalid_params");
396215
+ const { removeDocumentFonts: removeDocumentFonts2, faceLabel: faceLabel2 } = await Promise.resolve().then(() => (init_document_fonts(), document_fonts_exports));
396216
+ const { doc: doc2, removed } = removeDocumentFonts2(ctx2.doc(), args2);
396217
+ if (!removed.length) throw new CommandError(`No font in the file matches ${args2.id ?? args2.family}.`, "not_found");
396218
+ ctx2.commit(doc2, "Remove font");
396219
+ return { summary: `Removed ${removed.map(faceLabel2).join(", ")}`, data: { removed: removed.map(brief4) } };
396220
+ }
396221
+ });
396222
+ fontCommands = [fontAdd, fontList, fontRemove];
396223
+ }
396224
+ });
396225
+
396226
+ // lib/fonts/team-fonts.ts
396227
+ function teamFontPath(src) {
396228
+ const m = new RegExp(`^${TEAM_FONT_SCHEME}([^/]+)/([^/]+)$`).exec(src);
396229
+ return m ? `/api/workspaces/${encodeURIComponent(m[1])}/fonts/${encodeURIComponent(m[2])}` : null;
396230
+ }
396231
+ var teamFontMeta, teamFontSrc;
396232
+ var init_team_fonts = __esm({
396233
+ "lib/fonts/team-fonts.ts"() {
396234
+ "use strict";
396235
+ init_zod();
396236
+ init_fonts();
396237
+ teamFontMeta = external_exports.object({
396238
+ family: external_exports.string().trim().min(1).max(200),
396239
+ weight: external_exports.coerce.number().int().min(1).max(1e3).default(400),
396240
+ style: external_exports.enum(["normal", "italic"]).default("normal"),
396241
+ face: external_exports.coerce.number().int().min(0).max(255).default(0),
396242
+ fileName: external_exports.string().max(300).nullable().default(null)
396243
+ });
396244
+ teamFontSrc = (f2) => `${TEAM_FONT_SCHEME}${f2.workspaceId}/${f2.id}`;
396245
+ }
396246
+ });
396247
+
396248
+ // lib/fonts/team-client.ts
396249
+ var team_client_exports = {};
396250
+ __export(team_client_exports, {
396251
+ refreshTeamFonts: () => refreshTeamFonts,
396252
+ removeTeamFont: () => removeTeamFont,
396253
+ startTeamFonts: () => startTeamFonts,
396254
+ teamFontWorkspace: () => teamFontWorkspace,
396255
+ uploadTeamFont: () => uploadTeamFont,
396256
+ useTeamFonts: () => useTeamFonts
396257
+ });
396258
+ function teamFontWorkspace() {
396259
+ return activeTeamWorkspaceId() ?? useHyperyTeam.getState().personalWorkspaceId ?? null;
396260
+ }
396261
+ async function refreshTeamFonts(workspaceId = teamFontWorkspace()) {
396262
+ if (!cloudUser() || !workspaceId) {
396263
+ useTeamFonts.setState({ workspaceId: null, fonts: [], error: null });
396264
+ publish([]);
396265
+ return [];
396266
+ }
396267
+ useTeamFonts.setState({ loading: true, error: null, workspaceId });
396268
+ try {
396269
+ const { fonts } = await api(`/api/workspaces/${encodeURIComponent(workspaceId)}/fonts`);
396270
+ if (useTeamFonts.getState().workspaceId === workspaceId) {
396271
+ useTeamFonts.setState({ fonts });
396272
+ publish(fonts);
396273
+ }
396274
+ return fonts;
396275
+ } catch (e) {
396276
+ useTeamFonts.setState({ error: e.message });
396277
+ return useTeamFonts.getState().fonts;
396278
+ } finally {
396279
+ useTeamFonts.setState({ loading: false });
396280
+ }
396281
+ }
396282
+ async function uploadTeamFont(bytes2, meta3, workspaceId = teamFontWorkspace()) {
396283
+ if (!cloudUser() || !workspaceId) throw new Error("Sign in to add fonts to your team.");
396284
+ const headers = { "content-type": "application/octet-stream", "x-font-family": encodeURIComponent(meta3.family) };
396285
+ if (meta3.weight !== void 0) headers["x-font-weight"] = String(meta3.weight);
396286
+ if (meta3.style) headers["x-font-style"] = meta3.style;
396287
+ if (meta3.face !== void 0) headers["x-font-face"] = String(meta3.face);
396288
+ if (meta3.fileName) headers["x-font-file-name"] = encodeURIComponent(meta3.fileName);
396289
+ const { font } = await api(`/api/workspaces/${encodeURIComponent(workspaceId)}/fonts`, { method: "POST", headers, body: bytes2.slice().buffer });
396290
+ await refreshTeamFonts(workspaceId);
396291
+ return font;
396292
+ }
396293
+ async function removeTeamFont(id3, workspaceId = teamFontWorkspace()) {
396294
+ if (!cloudUser() || !workspaceId) throw new Error("Sign in to manage your team's fonts.");
396295
+ const out = await api(`/api/workspaces/${encodeURIComponent(workspaceId)}/fonts/${encodeURIComponent(id3)}`, { method: "DELETE" });
396296
+ await refreshTeamFonts(workspaceId);
396297
+ return out;
396298
+ }
396299
+ async function teamFontBlob(src) {
396300
+ const cached3 = await get2(cacheKey(src)).catch(() => void 0);
396301
+ if (cached3) return cached3;
396302
+ const path = teamFontPath(src);
396303
+ if (!path) return null;
396304
+ try {
396305
+ const token = await accessToken();
396306
+ const res = await fetch(path, { headers: token ? { authorization: `Bearer ${token}` } : {} });
396307
+ if (!res.ok) return null;
396308
+ const blob = await res.blob();
396309
+ void set3(cacheKey(src), blob).catch(() => {
396310
+ });
396311
+ return blob;
396312
+ } catch {
396313
+ return null;
396314
+ }
396315
+ }
396316
+ function startTeamFonts() {
396317
+ if (started4 || typeof window === "undefined") return;
396318
+ started4 = true;
396319
+ setTeamFontResolver(teamFontBlob);
396320
+ onCloudSessionChange(() => {
396321
+ void refreshTeamFonts();
396322
+ });
396323
+ let last3 = teamFontWorkspace();
396324
+ useHyperyTeam.subscribe(() => {
396325
+ const next2 = teamFontWorkspace();
396326
+ if (next2 !== last3) {
396327
+ last3 = next2;
396328
+ void refreshTeamFonts(next2);
396329
+ }
396330
+ });
396331
+ void refreshTeamFonts();
396332
+ }
396333
+ var useTeamFonts, publish, cacheKey, started4;
396334
+ var init_team_client = __esm({
396335
+ "lib/fonts/team-client.ts"() {
396336
+ init_esm();
396337
+ init_api4();
396338
+ init_session();
396339
+ init_team();
396340
+ init_idb();
396341
+ init_fonts();
396342
+ init_runtime3();
396343
+ init_team_fonts();
396344
+ useTeamFonts = create2(() => ({ workspaceId: null, fonts: [], loading: false, error: null }));
396345
+ publish = (fonts) => setFontSource("team", fonts.map((f2) => ({ family: f2.family, src: teamFontSrc(f2), weight: f2.weight, style: f2.style, face: f2.face })));
396346
+ cacheKey = (src) => `popcraft-team-font:${src}`;
396347
+ started4 = false;
396348
+ }
396349
+ });
396350
+
396351
+ // lib/commands/font-team.ts
396352
+ var workspaceParam, fontTeamList, fontTeamAdd, fontTeamRemove, fontTeamCommands;
396353
+ var init_font_team = __esm({
396354
+ "lib/commands/font-team.ts"() {
396355
+ "use strict";
396356
+ init_zod();
396357
+ init_types5();
396358
+ init_doc_helpers();
396359
+ init_font();
396360
+ workspaceParam = external_exports.string().min(1).max(200).optional().describe("Workspace id (default: the open file's team, else your own).");
396361
+ fontTeamList = defineCommand({
396362
+ id: "font.teamList",
396363
+ title: "List team fonts",
396364
+ domain: "media",
396365
+ effect: "none",
396366
+ permission: "read",
396367
+ params: external_exports.object({ workspace: workspaceParam }).strict(),
396368
+ expose: {
396369
+ ui: { label: "List team fonts", keywords: ["font", "team", "brand", "typeface"] },
396370
+ agent: { name: "list_team_fonts", readOnly: true, description: "The team's fonts: faces uploaded once that every file of the team can use (family, weight, style)." }
396371
+ },
396372
+ run: async (args2) => {
396373
+ const { refreshTeamFonts: refreshTeamFonts2 } = await Promise.resolve().then(() => (init_team_client(), team_client_exports));
396374
+ const fonts = await refreshTeamFonts2(args2.workspace);
396375
+ return { summary: plural2(fonts.length, "team font"), data: { fonts: fonts.map((f2) => ({ id: f2.id, family: f2.family, weight: f2.weight, style: f2.style, face: f2.face, fileName: f2.fileName })) } };
396376
+ }
396377
+ });
396378
+ fontTeamAdd = defineCommand({
396379
+ id: "font.teamAdd",
396380
+ title: "Add team font",
396381
+ domain: "media",
396382
+ effect: "none",
396383
+ permission: "write",
396384
+ params: external_exports.object({
396385
+ workspace: workspaceParam,
396386
+ family: external_exports.string().trim().min(1).max(200).optional().describe("The family name texts will use (default: the name in the file)."),
396387
+ file: external_exports.string().min(1).max(4096).optional().describe("A font file on this machine, read by the CLI."),
396388
+ src: external_exports.string().max(MAX_SRC).optional().describe("The font file as a base64 data URL, or a media:// ref on this device."),
396389
+ weight: external_exports.number().int().min(1).max(1e3).optional(),
396390
+ style: external_exports.enum(["normal", "italic"]).optional(),
396391
+ face: faceParam.optional()
396392
+ }).strict(),
396393
+ expose: {
396394
+ ui: { label: "Add team font\u2026", keywords: ["font", "team", "brand", "upload", "typeface"] },
396395
+ agent: { name: "add_team_font", description: "Upload a font to the team, once, for every file of the team: src is the file as a base64 data URL or media:// ref. It counts toward the team's storage." }
396396
+ },
396397
+ run: async (args2, ctx2) => {
396398
+ const { bytes: bytes2, fileName: fileName2 } = await fontBytes(args2, ctx2);
396399
+ const { face, family, weight, style } = await resolveFace(bytes2, args2);
396400
+ const { uploadTeamFont: uploadTeamFont2 } = await Promise.resolve().then(() => (init_team_client(), team_client_exports));
396401
+ const font = await uploadTeamFont2(bytes2, { family, weight, style, face: face.index, fileName: fileName2 }, args2.workspace);
396402
+ return { summary: `Added ${family} ${weight}${style === "italic" ? " italic" : ""} to the team`, data: { font } };
396403
+ }
396404
+ });
396405
+ fontTeamRemove = defineCommand({
396406
+ id: "font.teamRemove",
396407
+ title: "Remove team font",
396408
+ domain: "media",
396409
+ effect: "none",
396410
+ permission: null,
396411
+ params: external_exports.object({ workspace: workspaceParam, id: external_exports.string().min(1).max(200).describe("The face's id from list_team_fonts.") }).strict(),
396412
+ confirm: {
396413
+ level: "confirm",
396414
+ summary: (p2) => `Remove font ${p2.id} from the team`,
396415
+ detail: () => "Every file of the team that sets text in it draws that text in a fallback font, unless the file carries the font itself."
396416
+ },
396417
+ expose: {
396418
+ ui: { label: "Remove team font", palette: false },
396419
+ agent: { name: "remove_team_font", description: "Remove a font from the team (list_team_fonts). Files that use it fall back to another font unless they carry it themselves. The user approves every call." }
396420
+ },
396421
+ run: async (args2) => {
396422
+ const { removeTeamFont: removeTeamFont2 } = await Promise.resolve().then(() => (init_team_client(), team_client_exports));
396423
+ const out = await removeTeamFont2(args2.id, args2.workspace);
396424
+ return { summary: `Removed the team font${out.freed ? " and freed its storage" : ""}`, data: out };
396425
+ }
396426
+ });
396427
+ fontTeamCommands = [fontTeamList, fontTeamAdd];
396428
+ }
396429
+ });
396430
+
395434
396431
  // lib/client/versions.ts
395435
396432
  var versions_exports = {};
395436
396433
  __export(versions_exports, {
@@ -395553,8 +396550,8 @@ function versionLabel(v) {
395553
396550
  return `Autosave ${formatDate(v.createdAt, { month: "short", day: "numeric", hour: "numeric", minute: "2-digit" })}`;
395554
396551
  }
395555
396552
  function startLocalCheckpoints() {
395556
- if (started4 || typeof window === "undefined") return;
395557
- started4 = true;
396553
+ if (started5 || typeof window === "undefined") return;
396554
+ started5 = true;
395558
396555
  let editingSince = null;
395559
396556
  let lastDocId = useEditorStore.getState().document.id;
395560
396557
  let checkedBeforeEditing = false;
@@ -395588,7 +396585,7 @@ function startLocalCheckpoints() {
395588
396585
  });
395589
396586
  }, 6e4);
395590
396587
  }
395591
- var CHECKPOINT_EVERY_MS, KEEP_LOCAL_AUTO, listKey, snapKey, fromServer, docCache, started4;
396588
+ var CHECKPOINT_EVERY_MS, KEEP_LOCAL_AUTO, listKey, snapKey, fromServer, docCache, started5;
395592
396589
  var init_versions3 = __esm({
395593
396590
  "lib/client/versions.ts"() {
395594
396591
  init_format();
@@ -395613,7 +396610,7 @@ var init_versions3 = __esm({
395613
396610
  authorImage: v.author?.image ?? null
395614
396611
  });
395615
396612
  docCache = /* @__PURE__ */ new Map();
395616
- started4 = false;
396613
+ started5 = false;
395617
396614
  if (typeof module !== "undefined") module.hot?.decline();
395618
396615
  }
395619
396616
  });
@@ -395826,6 +396823,7 @@ var init_dangerous = __esm({
395826
396823
  init_publish();
395827
396824
  init_integration();
395828
396825
  init_media();
396826
+ init_font_team();
395829
396827
  init_version3();
395830
396828
  init_restricted();
395831
396829
  confirmTierCommands2 = [
@@ -395837,6 +396835,7 @@ var init_dangerous = __esm({
395837
396835
  ...publishCommands,
395838
396836
  ...integrationConfirmCommands,
395839
396837
  mediaDelete,
396838
+ fontTeamRemove,
395840
396839
  pluginRun
395841
396840
  ];
395842
396841
  dangerousCommands = [...confirmTierCommands2, ...restrictedCommands];
@@ -396223,7 +397222,7 @@ function hashRoots(doc2, roots) {
396223
397222
  n.childIds.forEach(walk4);
396224
397223
  };
396225
397224
  roots.forEach(walk4);
396226
- return hashOf(parts.join("\n"));
397225
+ return hashOf2(parts.join("\n"));
396227
397226
  }
396228
397227
  function freeSpot(doc2, pageId2) {
396229
397228
  const kids = (doc2.nodes[pageId2]?.childIds ?? []).map((id3) => doc2.nodes[id3]).filter(Boolean);
@@ -397545,8 +398544,8 @@ function pluginCommand(plugins) {
397545
398544
  }
397546
398545
  function registerAppCommands() {
397547
398546
  registerCommand(...appCommands);
397548
- if (started5 || typeof window === "undefined") return;
397549
- started5 = true;
398547
+ if (started6 || typeof window === "undefined") return;
398548
+ started6 = true;
397550
398549
  void Promise.resolve().then(() => (init_theme_store(), theme_store_exports)).then(({ useThemeStore: useThemeStore2, pickableThemes: pickableThemes2 }) => {
397551
398550
  const sync = () => registerCommand(themeCommand(pickableThemes2(useThemeStore2.getState())));
397552
398551
  sync();
@@ -397558,7 +398557,7 @@ function registerAppCommands() {
397558
398557
  usePluginStore2.subscribe(sync);
397559
398558
  });
397560
398559
  }
397561
- var none, emit6, store5, MODE_IDS, MODE_ALIASES, modeSet, modeEdit, PANELS, panelOpen, panelToggle, dialogOpen, aiOpen, docAction, TOOLS, toolSet, toolPlace, nodeRasterize, nodeOps, canvasToggle, popcornOpen, viewSetBreakpoint, appCommands, started5;
398560
+ var none, emit6, store5, MODE_IDS, MODE_ALIASES, modeSet, modeEdit, PANELS, panelOpen, panelToggle, dialogOpen, aiOpen, docAction, TOOLS, toolSet, toolPlace, nodeRasterize, nodeOps, canvasToggle, popcornOpen, viewSetBreakpoint, appCommands, started6;
397562
398561
  var init_app = __esm({
397563
398562
  "lib/commands/app.ts"() {
397564
398563
  init_zod();
@@ -397954,7 +398953,7 @@ var init_app = __esm({
397954
398953
  }
397955
398954
  });
397956
398955
  appCommands = [modeSet, modeEdit, nodeRasterize, panelOpen, panelToggle, dialogOpen, aiOpen, docAction, toolSet, toolPlace, nodeOps, canvasToggle, viewSetBreakpoint, popcornOpen, pageGo];
397957
- started5 = false;
398956
+ started6 = false;
397958
398957
  }
397959
398958
  });
397960
398959
 
@@ -398200,8 +399199,8 @@ function reportToolbarWidth() {
398200
399199
  }, 250);
398201
399200
  }
398202
399201
  function startDesktopTab() {
398203
- if (started6 || !isDesktopTabs()) return;
398204
- started6 = true;
399202
+ if (started7 || !isDesktopTabs()) return;
399203
+ started7 = true;
398205
399204
  const html = document.documentElement;
398206
399205
  const mark2 = () => {
398207
399206
  if (html.dataset.desktop !== "tabs") html.dataset.desktop = "tabs";
@@ -398237,7 +399236,7 @@ function startDesktopTab() {
398237
399236
  if (msg.type === "deleted") window.location.replace(EDITOR_HOME);
398238
399237
  });
398239
399238
  }
398240
- var openTab, openCloudFileTab, isHomeTab, started6;
399239
+ var openTab, openCloudFileTab, isHomeTab, started7;
398241
399240
  var init_tabs = __esm({
398242
399241
  "lib/desktop/tabs.ts"() {
398243
399242
  init_editor_store();
@@ -398248,7 +399247,7 @@ var init_tabs = __esm({
398248
399247
  openTab = (path, title) => invoke("tab_open", { url: path, activate: true, title });
398249
399248
  openCloudFileTab = (key5, name2) => openTab(cloudFilePath(key5), name2);
398250
399249
  isHomeTab = () => isDesktopTabs() && tabTarget(window.location.pathname, window.location.search).kind === "home";
398251
- started6 = false;
399250
+ started7 = false;
398252
399251
  }
398253
399252
  });
398254
399253
 
@@ -400359,8 +401358,8 @@ var init_import2 = __esm({
400359
401358
  run: async (args2, ctx2) => {
400360
401359
  const ext = (args2.name.match(/\.[^.]+$/)?.[0] ?? "").toLowerCase();
400361
401360
  if (!EXTENSIONS2.includes(ext)) throw new ToolError(`import_file takes ${EXTENSIONS2.join(", ")} files, not "${args2.name}".`);
400362
- const sources = [args2.text, args2.base64, args2.url].filter((v) => v !== void 0).length;
400363
- if (sources !== 1) throw new ToolError("Pass exactly one of text, base64 or url.");
401361
+ const sources2 = [args2.text, args2.base64, args2.url].filter((v) => v !== void 0).length;
401362
+ if (sources2 !== 1) throw new ToolError("Pass exactly one of text, base64 or url.");
400364
401363
  let body;
400365
401364
  if (args2.text !== void 0) body = args2.text;
400366
401365
  else if (args2.base64 !== void 0) body = Uint8Array.from(atob(args2.base64), (c2) => c2.charCodeAt(0));
@@ -401045,8 +402044,8 @@ var init_presentation_audio = __esm({
401045
402044
  },
401046
402045
  run: async (args2, ctx2) => {
401047
402046
  const page = pageOf3(ctx2, args2.pageId);
401048
- const sources = [args2.mediaHash, args2.url, args2.bytes].filter((v) => v !== void 0).length;
401049
- if (sources !== 1) throw new ToolError("Pass exactly one of mediaHash, url or bytes.");
402047
+ const sources2 = [args2.mediaHash, args2.url, args2.bytes].filter((v) => v !== void 0).length;
402048
+ if (sources2 !== 1) throw new ToolError("Pass exactly one of mediaHash, url or bytes.");
401050
402049
  if (args2.role === "voice" && !args2.frameId) throw new ToolError("Name the slide (frameId) whose narration this is.");
401051
402050
  let base = ctx2.doc();
401052
402051
  if (!soundtrackOf(base, page)) base = doc(() => configure(base, page, {}));
@@ -401277,6 +402276,8 @@ var init_builtin4 = __esm({
401277
402276
  init_integration();
401278
402277
  init_site3();
401279
402278
  init_import2();
402279
+ init_font();
402280
+ init_font_team();
401280
402281
  init_presentation_audio();
401281
402282
  builtinCommands = [
401282
402283
  // was read.ts
@@ -401451,7 +402452,10 @@ var init_builtin4 = __esm({
401451
402452
  // a copy of the open file as a new file (lib/commands/file.ts) (appended, as above)
401452
402453
  fileDuplicate,
401453
402454
  // a whiteboard as one picture, or its stickies as Markdown / CSV (lib/popcorn/board-export.ts) (appended, as above)
401454
- exportBoard
402455
+ exportBoard,
402456
+ // the font files a file carries, and the team's (lib/fonts) (appended, as above)
402457
+ ...fontCommands,
402458
+ ...fontTeamCommands
401455
402459
  ];
401456
402460
  uiOnlyCommands = [
401457
402461
  exportPdf,
@@ -402573,6 +403577,7 @@ var init_editor_store = __esm({
402573
403577
  init_libraries();
402574
403578
  init_library_link();
402575
403579
  init_fonts();
403580
+ init_runtime3();
402576
403581
  STICKY_PROP_KEYS = [
402577
403582
  "strokes",
402578
403583
  "fills",
@@ -406407,6 +407412,7 @@ var init_editor_store = __esm({
406407
407412
  useMode = () => useEditorStore((state) => state.mode);
406408
407413
  if (typeof module !== "undefined") module.hot?.decline();
406409
407414
  setCustomFontLookup((family) => useEditorStore.getState().customFonts.find((f2) => f2.name === family));
407415
+ useEditorStore.subscribe((s) => s.document.fonts, (fonts) => setFontSource("document", fonts), { fireImmediately: true });
406410
407416
  }
406411
407417
  });
406412
407418
 
@@ -406644,7 +407650,7 @@ function readPopcraft(path) {
406644
407650
  const doc2 = importFromJSON(text) ?? (() => {
406645
407651
  try {
406646
407652
  const bare = JSON.parse(text);
406647
- return bare && bare.nodes && Array.isArray(bare.pages) ? bare : null;
407653
+ return bare && bare.nodes && Array.isArray(bare.pages) ? internDocumentFonts(bare) : null;
406648
407654
  } catch {
406649
407655
  return null;
406650
407656
  }
@@ -406653,7 +407659,7 @@ function readPopcraft(path) {
406653
407659
  return doc2;
406654
407660
  }
406655
407661
  async function writePopcraft(path, doc2) {
406656
- const json3 = exportToJSON({ ...doc2, nodes: await embedNodeMedia(doc2.nodes) });
407662
+ const json3 = exportToJSON(await portableDocument(doc2));
406657
407663
  mkdirSync3(dirname(path) || ".", { recursive: true });
406658
407664
  const tmp = `${path}.${process.pid}.tmp`;
406659
407665
  writeFileSync3(tmp, json3);
@@ -406708,6 +407714,7 @@ function createHeadlessContext(opts = {}) {
406708
407714
  can: (name2) => cliCapabilities().includes(name2),
406709
407715
  use: (name2) => {
406710
407716
  if (name2 === "storage") return storage;
407717
+ if (name2 === "files") return { read: async (path) => new Uint8Array(readFileSync6(path)) };
406711
407718
  if (name2 === "generate" && hyperySignedIn()) return headlessGenerate(ctx2);
406712
407719
  throw new CommandError(`The CLI cannot provide ${name2}.`, "unsupported");
406713
407720
  },
@@ -406774,11 +407781,11 @@ var init_headless2 = __esm({
406774
407781
  init_seams();
406775
407782
  init_scene_graph();
406776
407783
  init_json_export();
406777
- init_media_store();
407784
+ init_document_fonts();
406778
407785
  init_hypery();
406779
407786
  init_recorders();
406780
407787
  init_run_node();
406781
- CLI_CAPABILITIES = ["storage"];
407788
+ CLI_CAPABILITIES = ["storage", "files"];
406782
407789
  cliCapabilities = () => hyperySignedIn() ? [...CLI_CAPABILITIES, "generate"] : CLI_CAPABILITIES;
406783
407790
  registered2 = false;
406784
407791
  noStorage = { getItem: () => null, setItem: () => {
@@ -407229,6 +408236,7 @@ var commands_exports = {};
407229
408236
  __export(commands_exports, {
407230
408237
  GLOBAL_SWITCHES: () => GLOBAL_SWITCHES,
407231
408238
  commandHelp: () => commandHelp,
408239
+ missingFontWarnings: () => missingFontWarnings,
407232
408240
  reviewInEditor: () => reviewInEditor,
407233
408241
  runCommandsList: () => runCommandsList,
407234
408242
  runNew: () => runNew,
@@ -407307,24 +408315,32 @@ function stepsFrom(value3) {
407307
408315
  return { command, params: params2 };
407308
408316
  });
407309
408317
  }
407310
- function printResult(out, id3, result, files = []) {
408318
+ function printResult(out, id3, result, files = [], warnings = []) {
407311
408319
  if (out.json) {
407312
- out.line(JSON.stringify({ command: id3, summary: result.summary, ...result.data !== void 0 ? { data: result.data } : {}, ...files.length ? { files } : {} }, null, 2));
408320
+ out.line(JSON.stringify({ command: id3, summary: result.summary, ...result.data !== void 0 ? { data: result.data } : {}, ...files.length ? { files } : {}, ...warnings.length ? { warnings } : {} }, null, 2));
407313
408321
  return;
407314
408322
  }
407315
408323
  out.line(result.summary);
407316
408324
  if (result.data !== void 0 && result.data !== null) out.line(typeof result.data === "string" ? result.data : JSON.stringify(result.data, null, 2));
407317
408325
  for (const f2 of files) out.line(`Wrote ${f2}`);
407318
408326
  }
408327
+ async function missingFontWarnings(doc2) {
408328
+ const [{ missingFontMessage: missingFontMessage2 }, { findMissingFonts: findMissingFonts2 }] = await Promise.all([Promise.resolve().then(() => (init_document_fonts(), document_fonts_exports)), Promise.resolve().then(() => (init_runtime3(), runtime_exports2))]);
408329
+ return (await findMissingFonts2(doc2)).map(missingFontMessage2);
408330
+ }
407319
408331
  async function step2(command, params2, flags, rc) {
407320
408332
  const where = availability2(command);
407321
408333
  if (where === "plugin" || where === "signin" || where === "app" || where === "unavailable") throw new CliError(`${command.id}: ${WHERE_HELP[where]}`);
407322
408334
  if (where === "browser") {
407323
- if (flagBool(flags, "dryRun")) return { result: { summary: `Would run ${command.id} in the editor (dry run)` }, files: [] };
408335
+ const doc2 = currentDocument();
408336
+ const warnings = await missingFontWarnings(doc2);
408337
+ for (const w of warnings) rc.out.info(`warning: ${w}`);
408338
+ if (flagBool(flags, "dryRun")) return { result: { summary: `Would run ${command.id} in the editor (dry run)` }, files: [], warnings };
407324
408339
  const { runInEditor: runInEditor2 } = await Promise.resolve().then(() => (init_render2(), render_exports));
408340
+ const { documentFontFiles: documentFontFiles2 } = await Promise.resolve().then(() => (init_document_fonts(), document_fonts_exports));
407325
408341
  const download = specOf(command).flags.some((f2) => f2.param === "download" && f2.type === "boolean") && params2.download === void 0 ? { download: true } : {};
407326
- const done = await runInEditor2(currentDocument(), command.id, { ...params2, ...download }, { appUrl: rc.appUrl, surface: command.expose.ui ? "ui" : "agent", headful: flagBool(flags, "headful"), out: flagString(flags, "out"), info: rc.out.info });
407327
- return { result: done.result ?? { summary: `Ran ${command.id}` }, files: done.files };
408342
+ const done = await runInEditor2(doc2, command.id, { ...params2, ...download }, { appUrl: rc.appUrl, surface: command.expose.ui ? "ui" : "agent", headful: flagBool(flags, "headful"), out: flagString(flags, "out"), info: rc.out.info, media: await documentFontFiles2(doc2) });
408343
+ return { result: done.result ?? { summary: `Ran ${command.id}` }, files: done.files, warnings };
407328
408344
  }
407329
408345
  const ctx2 = createHeadlessContext({ storageDir: configDir() });
407330
408346
  const result = await runHeadless(command.id, params2, ctx2);
@@ -407417,10 +408433,10 @@ ${commandHelp(command)}`);
407417
408433
  const data = [];
407418
408434
  for (const s of steps) {
407419
408435
  try {
407420
- const { result, files } = await step2(s.command, batch ? resolveStepRefs(s.params, data) : s.params, flags, rc);
408436
+ const { result, files, warnings = [] } = await step2(s.command, batch ? resolveStepRefs(s.params, data) : s.params, flags, rc);
407421
408437
  data.push(result.data);
407422
- if (batch) results.push({ command: s.command.id, summary: result.summary, ...result.data !== void 0 ? { data: result.data } : {}, ...files.length ? { files } : {} });
407423
- else printResult(out, s.command.id, result, files);
408438
+ if (batch) results.push({ command: s.command.id, summary: result.summary, ...result.data !== void 0 ? { data: result.data } : {}, ...files.length ? { files } : {}, ...warnings.length ? { warnings } : {} });
408439
+ else printResult(out, s.command.id, result, files, warnings);
407424
408440
  if (batch && !out.json) out.line(`\u2713 ${s.command.id}: ${result.summary}`);
407425
408441
  if (declined(result)) {
407426
408442
  refused = true;
@@ -408736,7 +409752,7 @@ init_resources();
408736
409752
  init_desktop();
408737
409753
  init_hypery();
408738
409754
  import { createInterface } from "node:readline";
408739
- var VERSION2 = "0.28.0";
409755
+ var VERSION2 = "0.29.0";
408740
409756
  var HELP = `popcraft ${VERSION2} \u2014 the PopCraft command line
408741
409757
 
408742
409758
  Files (headless, on .popcraft files):