@marver-design/marver 0.17.0 → 0.19.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 (48) hide show
  1. package/CHANGELOG.md +96 -0
  2. package/README.md +3 -1
  3. package/dist/bake-kaf5kGZ7.mjs +747 -0
  4. package/dist/{build-D_g53Bp2.mjs → build-7ed5H2vT.mjs} +215 -13
  5. package/dist/cli.mjs +19 -11
  6. package/dist/{comments-oYcZ3cE-.mjs → comments-ClVgfQib.mjs} +1 -1
  7. package/dist/{daemon-Bbh_jmui.mjs → daemon-DbHvLQUL.mjs} +1 -1
  8. package/dist/{dev-LnIISva5.mjs → dev-D3mP2x27.mjs} +205 -10
  9. package/dist/{init-B7YhcN2o.mjs → init-BQYCS3EU.mjs} +2 -2
  10. package/dist/{manifest-CaslQIAO.mjs → manifest-B01PSyDc.mjs} +34 -7
  11. package/dist/{marver-id-gate-D6By7XHj.mjs → marver-id-gate-B_idGdHm.mjs} +1 -1
  12. package/dist/{plugin-D2msH1cj.mjs → plugin-DI-7NAnx.mjs} +108 -29
  13. package/dist/{poster-BEjUcQP3.mjs → poster-DNh6N27C.mjs} +1 -1
  14. package/dist/publish-bakes-Dp-ZFk3d.mjs +216 -0
  15. package/dist/{serve-Bcwfpvhl.mjs → serve-z5qtj_wJ.mjs} +3 -3
  16. package/dist/{share-Gqo_Ygqw.mjs → share--bdSc4G5.mjs} +1 -1
  17. package/dist/{shot-BzQ0PXKH.mjs → shot-BFEuYbaz.mjs} +1 -1
  18. package/dist/{shot-DlmTO8AF.mjs → shot-DMDvDbeP.mjs} +14 -7
  19. package/dist/{work-lzC-lPY0.mjs → work-0YopuMt9.mjs} +1 -1
  20. package/docs/publish.md +27 -5
  21. package/docs/sticky-notes.md +43 -0
  22. package/package.json +2 -1
  23. package/src/client/content/diagram.tsx +27 -1
  24. package/src/client/content/index.tsx +2 -2
  25. package/src/client/content/md.ts +48 -0
  26. package/src/client/frame-host/bridge.js +4 -9
  27. package/src/client/frame-host/main.tsx +20 -6
  28. package/src/client/shell/App.tsx +14 -63
  29. package/src/client/shell/Comments.tsx +77 -14
  30. package/src/client/shell/Play.tsx +6 -3
  31. package/src/client/shell/canvas/Canvas.tsx +12 -3
  32. package/src/client/shell/canvas/FrameNode.tsx +99 -89
  33. package/src/client/shell/canvas/Sticky.tsx +284 -0
  34. package/src/client/shell/canvas/admission.ts +70 -0
  35. package/src/client/shell/canvas/sleep.ts +194 -0
  36. package/src/client/shell/goto.ts +72 -0
  37. package/src/client/shell/notes.ts +151 -0
  38. package/src/client/shell/store.ts +36 -18
  39. package/src/client/shell/styles.css +92 -25
  40. package/src/client/shell/tidy.ts +20 -2
  41. package/src/shared/sleep-rule.ts +41 -0
  42. package/templates/AGENTS-embedded.md +15 -0
  43. package/templates/AGENTS-studio.md +15 -0
  44. package/templates/instructions/craft.md +9 -0
  45. package/templates/instructions/publish.md +62 -9
  46. package/templates/instructions/shape.md +62 -0
  47. package/src/client/frame-host/serialize.ts +0 -195
  48. package/src/client/shell/canvas/snapshots.ts +0 -233
@@ -1,13 +1,156 @@
1
- import { i as ROUTE, n as NAME } from "./cli.mjs";
1
+ import { a as ROUTE, r as NAME } from "./cli.mjs";
2
2
  import { a as listBoardFiles, d as flatten, f as isBoardName, n as checkBoardsDir, s as readRegistry, t as boardFields, u as buildTree } from "./boards-BmxcT3Lc.mjs";
3
- import { l as detectHost, n as scanFrames, s as loadConfig } from "./manifest-CaslQIAO.mjs";
4
- import { n as tailwind3Css, r as tailwind4Plugin, t as marverPlugin } from "./plugin-D2msH1cj.mjs";
3
+ import { c as loadConfig, r as scanFrames, u as detectHost } from "./manifest-B01PSyDc.mjs";
4
+ import { n as tailwind3Css, r as tailwind4Plugin, t as marverPlugin } from "./plugin-DI-7NAnx.mjs";
5
5
  import { cpSync, existsSync, mkdirSync, readFileSync, realpathSync, rmSync, writeFileSync } from "node:fs";
6
6
  import { basename, dirname, join, sep } from "node:path";
7
7
  import { fileURLToPath } from "node:url";
8
8
  import { createHash, randomBytes } from "node:crypto";
9
9
  import { build } from "vite";
10
10
  import react from "@vitejs/plugin-react";
11
+ import { Marked } from "marked";
12
+ //#region src/server/css-fix.ts
13
+ /** Every `-webkit-backdrop-filter` declaration (the property itself, never a custom property that
14
+ * happens to end in it) is mirrored by the standard one right after it, in order, importance and
15
+ * all - the standard cascade then resolves exactly as the prefixed one did - unless the declaration
16
+ * list it belongs to declares the standard property already. The list is the enclosing block's own
17
+ * declarations: nested rules, their preludes included, are blanked. Strings and comments are masked
18
+ * first, so a brace or a declaration inside one is content, not syntax; values come from the
19
+ * original text. */
20
+ function keepBackdropFilter(css) {
21
+ const masked = maskCustomProperties(maskParens(css.replace(/\/\*[\s\S]*?\*\/|"(?:[^"\\]|\\.)*"|'(?:[^'\\]|\\.)*'|\\[\s\S]/g, (m) => " ".repeat(m.length))));
22
+ const PREFIXED = /(^|[^-\w])-webkit-backdrop-filter\s*:/gi;
23
+ const seen = /* @__PURE__ */ new Set();
24
+ const edits = [];
25
+ for (const m of masked.matchAll(PREFIXED)) {
26
+ const p = m.index + m[1].length;
27
+ let depth = 0, open = -1;
28
+ for (let i = p - 1; i >= 0; i--) {
29
+ const c = masked[i];
30
+ if (c === "}") depth++;
31
+ else if (c === "{") {
32
+ if (depth === 0) {
33
+ open = i;
34
+ break;
35
+ }
36
+ depth--;
37
+ }
38
+ }
39
+ if (open < 0 || seen.has(open)) continue;
40
+ seen.add(open);
41
+ let close = masked.length;
42
+ depth = 0;
43
+ for (let i = open + 1; i < masked.length; i++) {
44
+ const c = masked[i];
45
+ if (c === "{") depth++;
46
+ else if (c === "}") {
47
+ if (depth === 0) {
48
+ close = i;
49
+ break;
50
+ }
51
+ depth--;
52
+ }
53
+ }
54
+ const own = masked.slice(open + 1, close).split("");
55
+ depth = 0;
56
+ let seg = 0;
57
+ for (let i = 0; i < own.length; i++) {
58
+ const c = own[i];
59
+ if (depth === 0 && c === ";") {
60
+ seg = i + 1;
61
+ continue;
62
+ }
63
+ if (c === "{") {
64
+ if (depth === 0) for (let k = seg; k < i; k++) own[k] = " ";
65
+ depth++;
66
+ }
67
+ if (depth) own[i] = " ";
68
+ if (c === "}") {
69
+ depth--;
70
+ if (depth === 0) seg = i + 1;
71
+ }
72
+ }
73
+ const list = own.join("");
74
+ const decls = [];
75
+ let paren = 0, from = 0;
76
+ for (let i = 0; i <= list.length; i++) {
77
+ const c = list[i];
78
+ if (c === "(" || c === "[") paren++;
79
+ else if (c === ")" || c === "]") paren = Math.max(0, paren - 1);
80
+ if (i === list.length || c === ";" && paren === 0) {
81
+ const text = list.slice(from, i), colon = text.indexOf(":");
82
+ if (colon > 0) decls.push({
83
+ prop: text.slice(0, colon).trim().toLowerCase(),
84
+ valueAt: from + colon + 1,
85
+ end: i
86
+ });
87
+ from = i + 1;
88
+ }
89
+ }
90
+ if (decls.some((x) => x.prop === "backdrop-filter")) continue;
91
+ for (const x of decls) {
92
+ if (x.prop !== "-webkit-backdrop-filter") continue;
93
+ const value = css.slice(open + 1 + x.valueAt, open + 1 + x.end).trim();
94
+ if (value) edits.push({
95
+ at: open + 1 + x.end,
96
+ text: `;backdrop-filter:${value}`
97
+ });
98
+ }
99
+ }
100
+ let out = css;
101
+ for (const e of edits.sort((a, b) => b.at - a.at)) out = out.slice(0, e.at) + e.text + out.slice(e.at);
102
+ return out;
103
+ }
104
+ /** What sits inside parentheses is a value - `var(--f,{})`, `url(#a{b)` - never a rule: blanked,
105
+ * same length (values are copied from the original text). */
106
+ function maskParens(masked) {
107
+ const out = masked.split("");
108
+ let depth = 0;
109
+ for (let i = 0; i < out.length; i++) {
110
+ const c = out[i];
111
+ if (c === ")" && depth) {
112
+ depth--;
113
+ continue;
114
+ }
115
+ if (depth) out[i] = " ";
116
+ if (c === "(") depth++;
117
+ }
118
+ return out.join("");
119
+ }
120
+ /** A custom property's value may hold anything, braces, brackets and semicolons included (CSS
121
+ * Variables 1): blanked, same length, so no brace or property name inside one reads as syntax. */
122
+ function maskCustomProperties(masked) {
123
+ const out = masked.split("");
124
+ const re = /(^|[;{\s])--[^\s:;{}]+\s*:/g;
125
+ for (const m of masked.matchAll(re)) {
126
+ let depth = 0, i = m.index + m[0].length;
127
+ for (; i < masked.length; i++) {
128
+ const c = masked[i];
129
+ if (c === "(" || c === "[" || c === "{") depth++;
130
+ else if (c === ")" || c === "]" || c === "}") {
131
+ if (depth === 0) break;
132
+ depth--;
133
+ } else if (c === ";" && depth === 0) break;
134
+ out[i] = " ";
135
+ }
136
+ re.lastIndex = i;
137
+ }
138
+ return out.join("");
139
+ }
140
+ function cssFixPlugin() {
141
+ return {
142
+ name: "marver:css-fix",
143
+ transform(code, id) {
144
+ if (!/\.css$/.test(id.split("?")[0])) return;
145
+ const fixed = keepBackdropFilter(code);
146
+ return fixed === code ? void 0 : {
147
+ code: fixed,
148
+ map: null
149
+ };
150
+ }
151
+ };
152
+ }
153
+ //#endregion
11
154
  //#region src/server/build.ts
12
155
  /**
13
156
  * `marver build` - the static adapter.
@@ -51,7 +194,37 @@ function scanAssetRefs(src, moduleId) {
51
194
  }
52
195
  if (posterM) out.push(posterM[1]);
53
196
  }
54
- for (const tpl of templates) for (const m of tpl.matchAll(/!\[[^\]]*\]\(([^)\s"']+)\)/g)) out.push(m[1]);
197
+ for (const tpl of templates) out.push(...markdownImageRefs(tpl.slice(1, -1)));
198
+ return out;
199
+ }
200
+ /** Markdown images in prose, through the parser: inline and reference-style, titles and
201
+ * parentheses in paths handled, code never counted. Decoded the way the client's assetUrl
202
+ * decodes (one pass; a path still carrying `%` is refused there and skipped here). Md content
203
+ * inside frames and sticky notes alike. */
204
+ function markdownImageRefs(md) {
205
+ const out = [];
206
+ const walk = (tokens) => {
207
+ for (const t of tokens) {
208
+ if (t.type === "image" && typeof t.href === "string") {
209
+ let p = t.href.trim();
210
+ try {
211
+ p = decodeURIComponent(p);
212
+ } catch {
213
+ continue;
214
+ }
215
+ if (!p.includes("%")) out.push(p);
216
+ }
217
+ if (t.type !== "code" && t.type !== "codespan") {
218
+ if (Array.isArray(t.tokens)) walk(t.tokens);
219
+ if (Array.isArray(t.items)) walk(t.items);
220
+ if (Array.isArray(t.rows)) for (const row of t.rows) walk(row.map((c) => ({ tokens: c.tokens })));
221
+ if (Array.isArray(t.header)) walk(t.header.map((c) => ({ tokens: c.tokens })));
222
+ }
223
+ }
224
+ };
225
+ try {
226
+ walk(new Marked({ gfm: true }).lexer(md));
227
+ } catch {}
55
228
  return out;
56
229
  }
57
230
  /** Same shape the client's assetUrl accepts: relative, inside design/assets/, no tricks. */
@@ -193,12 +366,13 @@ function publishedManifest(manifest, pubFrames, publishedNames, strip) {
193
366
  ...manifest.project ? { project: manifest.project } : {},
194
367
  ...pubFolders.length ? { folders: pubFolders } : {},
195
368
  ...pubBoards.length ? { boards: pubBoards } : {},
196
- scenes: manifest.scenes.filter((s) => pubScenes.has(s.name)).map(({ name, title, description, brief }) => ({
369
+ scenes: manifest.scenes.filter((s) => pubScenes.has(s.name)).map(({ name, title, description, brief, note }) => ({
197
370
  name,
198
371
  frames: pubFrames.filter((f) => f.scene === name).length,
199
372
  ...title ? { title } : {},
200
373
  ...description ? { description } : {},
201
- ...brief && !strip ? { brief } : {}
374
+ ...brief && !strip ? { brief } : {},
375
+ ...note ? { note } : {}
202
376
  })),
203
377
  frames: pubFrames
204
378
  };
@@ -306,7 +480,7 @@ export function layoutChain(fileKey) {
306
480
  }
307
481
  `;
308
482
  }
309
- async function buildSite(root, boardsFlag, allBoardsFlag, embedSeeds) {
483
+ async function buildSite(root, boardsFlag, allBoardsFlag, embedSeeds, textures = true) {
310
484
  const config = await loadConfig(root);
311
485
  const host = detectHost(root);
312
486
  const pkgDir = packageDir();
@@ -332,10 +506,11 @@ async function buildSite(root, boardsFlag, allBoardsFlag, embedSeeds) {
332
506
  for (const b of Object.values(boards)) for (const node of Array.isArray(b?.nodes) ? b.nodes : []) if (typeof node?.frame === "string") wanted.add(node.frame);
333
507
  frames = manifest.frames.filter((f) => wanted.has(f.id));
334
508
  }
335
- const pubManifest = publishedManifest(manifest, strip ? frames.map((f) => ({
509
+ const pubFrames = strip ? frames.map((f) => ({
336
510
  ...f,
337
511
  file: opaquePath(f.id, f.kind === "html" ? ".html" : "")
338
- })) : frames, publishedNames, strip);
512
+ })) : frames;
513
+ const pubManifest = publishedManifest(manifest, pubFrames, publishedNames, strip);
339
514
  for (const n of publishedNames) {
340
515
  const pb = policy.boards[n];
341
516
  if (pb?.type !== "slides" && pb?.open !== "slides") continue;
@@ -367,7 +542,9 @@ async function buildSite(root, boardsFlag, allBoardsFlag, embedSeeds) {
367
542
  const t = boardFields(allBoards[n], isBoardName).title;
368
543
  return t ? [[n, t]] : [];
369
544
  }));
545
+ const bakeGen = textures ? Date.now() : void 0;
370
546
  const data = {
547
+ bakes: bakeGen,
371
548
  manifest: pubManifest,
372
549
  boards,
373
550
  names: publishedNames,
@@ -413,7 +590,7 @@ async function buildSite(root, boardsFlag, allBoardsFlag, embedSeeds) {
413
590
  clientDir,
414
591
  config,
415
592
  detectedThemeCss: host.themeCss
416
- }));
593
+ }), cssFixPlugin());
417
594
  process.env.NODE_ENV = "production";
418
595
  const result = await build({
419
596
  configFile: false,
@@ -462,7 +639,7 @@ async function buildSite(root, boardsFlag, allBoardsFlag, embedSeeds) {
462
639
  const page = (srcDir, entryName, outPath) => {
463
640
  const entry = chunks.find((c) => c.isEntry && c.name === entryName);
464
641
  const links = cssFor(entryName).map((f) => `<link rel="stylesheet" href="/${f}" />`).join("\n ");
465
- const html = readFileSync(join(clientDir, srcDir, "index.html"), "utf8").replaceAll("{{ROUTE}}", ROUTE).replace("<script type=\"module\" src=\"{{ENTRY}}\"><\/script>", `${links}\n <script type="module" src="/${entry.fileName}"><\/script>`);
642
+ const html = readFileSync(join(clientDir, srcDir, "index.html"), "utf8").replaceAll("{{ROUTE}}", ROUTE).replace("<script type=\"module\" src=\"{{ENTRY}}\"><\/script>", `${links}\n <script type="module" src="/${entry.fileName}"><\/script>`).replace(/<head([^>]*)>/, (m) => entryName === "frame" && bakeGen ? `${m}\n <meta name="mv-bakes" content="${bakeGen}">` : m);
466
643
  mkdirSync(dirname(join(outDir, outPath)), { recursive: true });
467
644
  writeFileSync(join(outDir, outPath), html);
468
645
  };
@@ -470,7 +647,7 @@ async function buildSite(root, boardsFlag, allBoardsFlag, embedSeeds) {
470
647
  page("frame-host", "frame", `${ROUTE.slice(1)}/frame/index.html`);
471
648
  page("stage", "stage", `${ROUTE.slice(1)}/stage/index.html`);
472
649
  cpSync(join(clientDir, "shell", "favicon"), join(outDir, ROUTE.slice(1), "favicon"), { recursive: true });
473
- cpSync(join(clientDir, "frame-host", "bridge.js"), join(outDir, "assets", "bridge.js"));
650
+ for (const f of ["bridge.js", "inspect.js"]) cpSync(join(clientDir, "frame-host", f), join(outDir, "assets", f));
474
651
  const frameCss = cssFor("frame").map((f) => `<link rel="stylesheet" href="/${f}" />`).join("\n");
475
652
  for (const f of frames.filter((x) => x.kind === "html")) {
476
653
  const src = readFileSync(join(root, f.file), "utf8");
@@ -478,6 +655,7 @@ async function buildSite(root, boardsFlag, allBoardsFlag, embedSeeds) {
478
655
  let html = src.includes("</head>") ? src.replace("</head>", `${inject}</head>`) : inject + src;
479
656
  const shim = `<script>(function(){var a=Element.prototype.attachShadow;if(a)Element.prototype.attachShadow=function(i){if(i&&i.mode==='closed')window.__mvClosedShadow=1;return a.call(this,i)};})();<\/script>`;
480
657
  html = /<head[^>]*>/i.test(html) ? html.replace(/<head[^>]*>/i, (m) => m + shim) : shim + html;
658
+ if (bakeGen) html = /<head[^>]*>/i.test(html) ? html.replace(/<head[^>]*>/i, (m) => `${m}<meta name="mv-bakes" content="${bakeGen}">`) : `<meta name="mv-bakes" content="${bakeGen}">` + html;
481
659
  const dest = strip ? opaquePath(f.id, ".html") : f.file;
482
660
  mkdirSync(dirname(join(outDir, dest)), { recursive: true });
483
661
  writeFileSync(join(outDir, dest), html);
@@ -500,11 +678,12 @@ async function buildSite(root, boardsFlag, allBoardsFlag, embedSeeds) {
500
678
  const rel = file.startsWith(rootP + "/") ? file.slice(rootP.length + 1) : file;
501
679
  for (const r of scanAssetRefs(src, rel)) refs.add(r);
502
680
  }
681
+ for (const note of [...pubManifest.frames.map((f) => f.note), ...pubManifest.scenes.map((s) => s.note)]) if (note) for (const r of markdownImageRefs(note)) refs.add(r);
503
682
  let copiedAssets = 0;
504
683
  const realAssets = existsSync(assetsDir) ? realpathSync(assetsDir) : null;
505
684
  for (const r of refs) {
506
685
  if (!isLocalAssetRef(r) || !r.endsWith(".poster.png") || existsSync(join(assetsDir, r))) continue;
507
- const { ensurePoster } = await import("./poster-BEjUcQP3.mjs");
686
+ const { ensurePoster } = await import("./poster-DNh6N27C.mjs");
508
687
  const g = await ensurePoster(assetsDir, r.slice(0, -11));
509
688
  if (!g.ok) throw new Error(`design/assets/${r}: ${g.error}`);
510
689
  console.log(` poster: rendered design/assets/${r} (${g.width}×${g.height})`);
@@ -569,8 +748,31 @@ async function buildSite(root, boardsFlag, allBoardsFlag, embedSeeds) {
569
748
  ...config.share.frontDoor === false ? { frontDoor: false } : {},
570
749
  ...config.share.notify === false ? { notify: false } : {}
571
750
  }));
751
+ let textureLine = " textures: skipped (--no-textures)";
752
+ if (textures && bakeGen) {
753
+ const { bakePublished } = await import("./publish-bakes-Dp-ZFk3d.mjs");
754
+ const pubFrameFile = new Map(pubFrames.map((f) => [f.id, f]));
755
+ const r = await bakePublished({
756
+ root,
757
+ outDir,
758
+ gen: bakeGen,
759
+ boards,
760
+ themes: config.themes,
761
+ log: (l) => console.log(l),
762
+ frames: pubFrames,
763
+ viewports: config.viewports,
764
+ allScenes: includeAll,
765
+ urlFor: (id, theme) => {
766
+ const f = pubFrameFile.get(id);
767
+ if (!f) return null;
768
+ return f.kind === "html" ? `/${f.file}?theme=${encodeURIComponent(theme)}&r=${bakeGen}` : `/__mv/frame/?id=${encodeURIComponent(id)}&theme=${encodeURIComponent(theme)}&r=${bakeGen}`;
769
+ }
770
+ });
771
+ textureLine = r === null ? ` textures: none - no Chrome on this machine; frames with glass will rest live (install Chrome, or ship as is)` : r.asked === 0 ? " textures: nothing to compile" : ` textures: ${r.asleep} frame view${r.asleep === 1 ? "" : "s"} asleep under certified glass, ${r.live} with live glass, ${r.plain} without effects (${r.asked} asked: every published node x ${config.themes.length || 1} theme${config.themes.length === 1 ? "" : "s"}; ${(r.bytes / 1024).toFixed(0)} KB, ${(r.ms / 1e3).toFixed(1)} s)`;
772
+ }
572
773
  console.log(`\n ${NAME} build → design/.dist`);
573
774
  console.log(` boards: ${publishedNames.map((n) => `${n} (${rights[n]})`).join(", ")}`);
775
+ console.log(textureLine);
574
776
  console.log(` frames: ${frames.length}${includeAll ? "" : ` of ${manifest.frames.length} (build-time filter)`}`);
575
777
  if (copiedAssets) console.log(` assets: ${copiedAssets} referenced file${copiedAssets === 1 ? "" : "s"} from design/assets/ (unreferenced assets never ship)`);
576
778
  if (!includeAll && existsSync(join(root, "public"))) console.log(` note: the host public/ directory ships in full - the --boards filter covers frames, not public assets`);
package/dist/cli.mjs CHANGED
@@ -1,4 +1,5 @@
1
1
  #!/usr/bin/env node
2
+ import { t as __exportAll } from "./rolldown-runtime-D7D4PA-g.mjs";
2
3
  import { cac } from "cac";
3
4
  import { readFileSync, realpathSync } from "node:fs";
4
5
  import { dirname, join, resolve } from "node:path";
@@ -31,6 +32,13 @@ function slideSize(frame) {
31
32
  return frame.slide ? SLIDE_INTRINSIC : null;
32
33
  }
33
34
  //#endregion
35
+ //#region src/cli/name.ts
36
+ var name_exports = /* @__PURE__ */ __exportAll({
37
+ NAME: () => NAME,
38
+ PKG: () => PKG,
39
+ ROUTE: () => ROUTE
40
+ });
41
+ //#endregion
34
42
  //#region src/cli/index.ts
35
43
  const [major, minor] = process.versions.node.split(".").map(Number);
36
44
  if (major < 22 || major === 22 && minor < 18) {
@@ -64,14 +72,14 @@ const resolve$1 = (dir) => {
64
72
  };
65
73
  const cli = cac(NAME);
66
74
  cli.command("init", "Scaffold design/ in this repo").option("--mode <mode>", "studio | embedded", { default: "studio" }).option("--no-demo", "Skip the demo scene (the demo ships unless this flag is passed)").option("--root <dir>", "Host repo root", { default: "." }).action(async (opts) => {
67
- const { init } = await import("./init-B7YhcN2o.mjs");
75
+ const { init } = await import("./init-BQYCS3EU.mjs");
68
76
  init(resolve$1(opts.root), {
69
77
  mode: opts.mode === "embedded" ? "embedded" : "studio",
70
78
  demo: opts.demo !== false
71
79
  });
72
80
  });
73
81
  for (const [name, desc] of [["dev", "Start the local canvas (everything on: hot reload, comments, Live Jam)"], ["canvas", "Start the local canvas - same as dev"]]) cli.command(name, desc).option("--root <dir>", "Host repo root", { default: "." }).option("--port <port>", "Port (default 5199)").action(async (opts) => {
74
- const { dev } = await import("./dev-LnIISva5.mjs");
82
+ const { dev } = await import("./dev-D3mP2x27.mjs");
75
83
  let port;
76
84
  if (opts.port !== void 0) {
77
85
  const n = Number(opts.port);
@@ -80,18 +88,18 @@ for (const [name, desc] of [["dev", "Start the local canvas (everything on: hot
80
88
  }
81
89
  await dev(resolve$1(opts.root), port);
82
90
  });
83
- cli.command("build", "Static export → design/.dist (what ships comes from design/publish.json - publishing is default-closed)").option("--boards <names>", "Publish only these boards (comma-separated); overrides the publish policy").option("--all-boards", "Publish every board - the loud override for the default-closed policy").option("--embed-seeds", "Copy comment history INTO the web root (identifying - every event carries its author's email)").option("--root <dir>", "Host repo root", { default: "." }).action(async (opts) => {
84
- const { buildSite } = await import("./build-D_g53Bp2.mjs");
91
+ cli.command("build", "Static export → design/.dist (what ships comes from design/publish.json - publishing is default-closed)").option("--boards <names>", "Publish only these boards (comma-separated); overrides the publish policy").option("--all-boards", "Publish every board - the loud override for the default-closed policy").option("--embed-seeds", "Copy comment history INTO the web root (identifying - every event carries its author's email)").option("--no-textures", "Skip compiling the glass textures the published frames rest under (needs Chrome; a CI without one skips on its own)").option("--root <dir>", "Host repo root", { default: "." }).action(async (opts) => {
92
+ const { buildSite } = await import("./build-7ed5H2vT.mjs");
85
93
  try {
86
94
  const boards = opts.boards === void 0 ? void 0 : typeof opts.boards === "string" ? opts.boards : "";
87
- await buildSite(resolve$1(opts.root), boards, opts.allBoards === true, opts.embedSeeds === true);
95
+ await buildSite(resolve$1(opts.root), boards, opts.allBoards === true, opts.embedSeeds === true, opts.textures !== false && !process.env.MARVER_NO_TEXTURES);
88
96
  } catch (err) {
89
97
  console.error(`[${NAME}] build failed: ${err.message}`);
90
98
  process.exit(1);
91
99
  }
92
100
  });
93
101
  cli.command("serve", "Serve design/.dist (set MARVER_PASSWORD to gate it)").option("--root <dir>", "Host repo root", { default: "." }).option("--port <port>", "Port (default $PORT or 4199)").action(async (opts) => {
94
- const { serve } = await import("./serve-Bcwfpvhl.mjs");
102
+ const { serve } = await import("./serve-z5qtj_wJ.mjs");
95
103
  let port;
96
104
  if (opts.port !== void 0) {
97
105
  const n = Number(opts.port);
@@ -100,7 +108,7 @@ cli.command("serve", "Serve design/.dist (set MARVER_PASSWORD to gate it)").opti
100
108
  serve(resolve$1(opts.root), port);
101
109
  });
102
110
  cli.command("comments <action> [value]", "Comment collaboration: connect <url> · sync · list · reply <thread> · resolve <thread> · invite <email> · revoke <email>").option("--root <dir>", "Host repo root", { default: "." }).option("--token <token>", "connect: the canvas's MARVER_CLI_TOKEN (default $MARVER_CLI_TOKEN) - the identity-mode path").option("--invite <token>", "connect: claim this invite instead of signing in").option("--canvas-password <password>", "connect: the canvas gate password (default $MARVER_PASSWORD or prompt)").option("--email <email>", "connect: account email (skips the prompt)").option("--password <password>", "connect: account password (skips the prompt - mind your shell history)").option("--name <name>", "connect --invite: display name for the new account").option("--open", "list: only unresolved threads").option("--json", "list: machine-readable output").option("--board <board>", "scope to one board").option("--body <text>", "reply: the reply text").option("--addressed-in <frame>", "resolve: the variant frame that answered the feedback").action(async (action, value, opts) => {
103
- const { commentsCommand } = await import("./comments-oYcZ3cE-.mjs");
111
+ const { commentsCommand } = await import("./comments-ClVgfQib.mjs");
104
112
  try {
105
113
  await commentsCommand(resolve$1(opts.root), action, value, opts);
106
114
  } catch (err) {
@@ -109,7 +117,7 @@ cli.command("comments <action> [value]", "Comment collaboration: connect <url>
109
117
  }
110
118
  });
111
119
  cli.command("share <action> [value]", "Sharing roster (owner): add <who> · remove <who> · block/unblock <email> · general <mode> · list · requests · explain <who> · who").option("--root <dir>", "Host repo root", { default: "." }).option("--role <role>", "add / requests --approve: view (default) or comment").option("--expires <iso>", "add: expiry timestamp, e.g. 2026-12-31T00:00:00Z").option("--approve <email>", "requests: approve this pending request (canvas-wide in v1)").option("--decline <email>", "requests: decline this pending request (silent to the asker)").option("--json", "list: machine-readable output").action(async (action, value, opts) => {
112
- const { shareCommand } = await import("./share-Gqo_Ygqw.mjs");
120
+ const { shareCommand } = await import("./share--bdSc4G5.mjs");
113
121
  try {
114
122
  await shareCommand(resolve$1(opts.root), action, value, opts);
115
123
  } catch (err) {
@@ -118,7 +126,7 @@ cli.command("share <action> [value]", "Sharing roster (owner): add <who> · remo
118
126
  }
119
127
  });
120
128
  cli.command("work <action> [...frames]", "Working state on the canvas: start <scene/frame ...> · done <scene/frame ...> | --all · list").option("--root <dir>", "Host repo root", { default: "." }).option("--ttl <minutes>", "start: minutes before the glow self-expires (default 10, max 30)").option("--all", "done: clear every working frame").action(async (action, frames, opts) => {
121
- const { workCommand } = await import("./work-lzC-lPY0.mjs");
129
+ const { workCommand } = await import("./work-0YopuMt9.mjs");
122
130
  try {
123
131
  await workCommand(resolve$1(opts.root), action, frames ?? [], opts);
124
132
  } catch (err) {
@@ -136,7 +144,7 @@ cli.command("boards", "The sidebar as files: every folder and board in reading o
136
144
  }
137
145
  });
138
146
  cli.command("shot [...frames]", "Render frames headless and print the PNG paths (needs `dev` running): ids, --scene <name> or --all").option("--root <dir>", "Host repo root", { default: "." }).option("--scene <name>", "Every frame of one scene").option("--all", "Every frame of the canvas").option("--theme <name>", "Theme to render (default: light)").option("--scale <n>", "Device pixels per CSS px, 1-4 (default: 2; 4 for print-quality stills)").option("--json", "Print the results as JSON ({ results: [...] }) instead of paths").action(async (frames, opts) => {
139
- const { shotCommand } = await import("./shot-BzQ0PXKH.mjs");
147
+ const { shotCommand } = await import("./shot-BFEuYbaz.mjs");
140
148
  try {
141
149
  await shotCommand(resolve$1(opts.root), frames, opts);
142
150
  } catch (err) {
@@ -148,4 +156,4 @@ cli.help();
148
156
  cli.version(version());
149
157
  cli.parse();
150
158
  //#endregion
151
- export { slideSize as a, ROUTE as i, NAME as n, PKG as r, CONTENT_WIDTH as t };
159
+ export { ROUTE as a, PKG as i, CONTENT_WIDTH as n, slideSize as o, NAME as r, name_exports as t };
@@ -1,4 +1,4 @@
1
- import { n as NAME } from "./cli.mjs";
1
+ import { r as NAME } from "./cli.mjs";
2
2
  import { n as replay } from "./events-B3LBn74P.mjs";
3
3
  import { i as readLog, r as listBoards, t as appendEvents } from "./comments-DZyobpxG.mjs";
4
4
  import { a as syncOnce, i as loadCollab, n as connectClaim, r as connectToken, t as connect } from "./sync-BZaCWqK-.mjs";
@@ -1,7 +1,7 @@
1
1
  import { n as replay } from "./events-B3LBn74P.mjs";
2
2
  import { i as readLog, r as listBoards, t as appendEvents } from "./comments-DZyobpxG.mjs";
3
3
  import { n as localProfile } from "./profile-BjAPAJSb.mjs";
4
- import { i as toFrameId } from "./manifest-CaslQIAO.mjs";
4
+ import { a as toFrameId } from "./manifest-B01PSyDc.mjs";
5
5
  import { workActivity } from "./work-CLrmY-vQ.mjs";
6
6
  import { r as deviceId, t as has } from "./ledger-Bu0BjqIe.mjs";
7
7
  import { closeSync, existsSync, fsyncSync, mkdirSync, openSync, readFileSync, readdirSync, renameSync, rmSync, statSync, unlinkSync, watch, writeFileSync, writeSync } from "node:fs";