slides-grab 1.1.5 → 1.2.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.
package/README.md CHANGED
@@ -82,6 +82,7 @@ slides-grab figma # Export an experimental / unstable Figma Slides i
82
82
  slides-grab pdf # Export PDF in capture mode (default)
83
83
  slides-grab pdf --resolution 2160p # Higher-resolution image-backed PDF export
84
84
  slides-grab pdf --mode print # Export searchable/selectable text PDF
85
+ slides-grab tldraw # Render a .tldr diagram into a slide-sized local SVG asset
85
86
  slides-grab list-templates # Show available slide templates
86
87
  slides-grab list-themes # Show available color themes
87
88
  ```
@@ -116,6 +117,27 @@ slides-grab figma --slides-dir decks/my-deck --output decks/my-deck-figma.p
116
117
 
117
118
  > **Warning:** `slides-grab convert` and `slides-grab figma` are currently **experimental / unstable**. Expect best-effort output, layout shifts, and manual cleanup in PowerPoint or Figma.
118
119
 
120
+ ### Tldraw Diagram Assets
121
+
122
+ Use `slides-grab tldraw` when you want a newly authored `tldraw` diagram to fit an exact slide region and remain export-friendly as a local SVG asset. The command supports current-format `.tldr` files and store-snapshot JSON; legacy pre-records `.tldr` files must be reopened and resaved in a current `tldraw` build first:
123
+
124
+ ```bash
125
+ slides-grab tldraw \
126
+ --input decks/my-deck/assets/system.tldr \
127
+ --output decks/my-deck/assets/system.svg \
128
+ --width 640 \
129
+ --height 320 \
130
+ --padding 16
131
+ ```
132
+
133
+ Then reference the generated SVG from your slide HTML with a normal local image:
134
+
135
+ ```html
136
+ <img src="./assets/system.svg" alt="System architecture diagram">
137
+ ```
138
+
139
+ The built-in `diagram-tldraw` template is a simple starting point for this workflow.
140
+
119
141
  ### Figma Workflow
120
142
 
121
143
  ```bash
package/bin/ppt-agent.js CHANGED
@@ -154,6 +154,28 @@ program
154
154
  await runCommand('scripts/figma-export.js', args);
155
155
  });
156
156
 
157
+ program
158
+ .command('tldraw')
159
+ .description('Render a current-format .tldr or store-snapshot JSON file to an exact-size SVG asset for slides')
160
+ .option('--input <path>', 'Input current-format .tldr or snapshot JSON file')
161
+ .option('--output <path>', 'Output SVG asset path')
162
+ .option('--width <number>', 'Exact output width in CSS pixels')
163
+ .option('--height <number>', 'Exact output height in CSS pixels')
164
+ .option('--padding <number>', 'Inner fit padding in CSS pixels')
165
+ .option('--background <css>', 'Optional wrapper background fill')
166
+ .option('--page-id <id>', 'Optional tldraw page id to export')
167
+ .action(async (options = {}) => {
168
+ const args = [];
169
+ if (options.input) args.push('--input', String(options.input));
170
+ if (options.output) args.push('--output', String(options.output));
171
+ if (options.width) args.push('--width', String(options.width));
172
+ if (options.height) args.push('--height', String(options.height));
173
+ if (options.padding) args.push('--padding', String(options.padding));
174
+ if (options.background) args.push('--background', String(options.background));
175
+ if (options.pageId) args.push('--page-id', String(options.pageId));
176
+ await runCommand('scripts/render-tldraw.js', args);
177
+ });
178
+
157
179
  program
158
180
  .command('edit')
159
181
  .description('Start interactive slide editor with Codex image-based edit flow')
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "slides-grab",
3
- "version": "1.1.5",
3
+ "version": "1.2.0",
4
4
  "description": "Agent-first presentation framework — plan, design, and visually edit HTML slides with Claude Code or Codex, then export to PDF or experimental/unstable PPTX/Figma formats",
5
5
  "license": "MIT",
6
6
  "author": "vkehfdl1",
@@ -38,6 +38,7 @@
38
38
  "scripts/figma-export.js",
39
39
  "scripts/html2pdf.js",
40
40
  "scripts/html2pptx.js",
41
+ "scripts/render-tldraw.js",
41
42
  "scripts/validate-slides.js",
42
43
  "skills/",
43
44
  "src/",
@@ -51,7 +52,7 @@
51
52
  "build-viewer": "node scripts/build-viewer.js",
52
53
  "validate": "node scripts/validate-slides.js",
53
54
  "convert": "node convert.cjs",
54
- "test": "node --test tests/editor/editor-codex-edit.test.js tests/pdf/html2pdf.test.js tests/pdf/html2pdf.e2e.test.js tests/figma/figma-export.test.js tests/image-contract/image-contract.test.js tests/validation/validate-slides.test.js tests/skills/installable-skills.test.js",
55
+ "test": "node --test tests/editor/editor-codex-edit.test.js tests/pdf/html2pdf.test.js tests/pdf/html2pdf.e2e.test.js tests/figma/figma-export.test.js tests/image-contract/image-contract.test.js tests/tldraw/render-tldraw.test.js tests/validation/validate-slides.test.js tests/skills/installable-skills.test.js",
55
56
  "test:e2e": "node --test tests/editor/editor-ui.e2e.test.js tests/editor/editor-concurrency.e2e.test.js"
56
57
  },
57
58
  "dependencies": {
@@ -60,7 +61,10 @@
60
61
  "pdf-lib": "^1.17.1",
61
62
  "playwright": "^1.40.0",
62
63
  "pptxgenjs": "^3.12.0",
64
+ "react": "^19.2.4",
65
+ "react-dom": "^19.2.4",
63
66
  "react-icons": "^5.0.0",
64
- "sharp": "^0.33.0"
67
+ "sharp": "^0.33.0",
68
+ "tldraw": "^4.4.1"
65
69
  }
66
70
  }
@@ -3,7 +3,6 @@
3
3
  import { readdir, readFile, writeFile, mkdtemp, rm, mkdir } from 'node:fs/promises';
4
4
  import { watch as fsWatch } from 'node:fs';
5
5
  import { basename, dirname, join, resolve, relative, sep } from 'node:path';
6
- import { spawn } from 'node:child_process';
7
6
  import { fileURLToPath } from 'node:url';
8
7
  import { tmpdir } from 'node:os';
9
8
 
@@ -18,6 +17,10 @@ import {
18
17
  scaleSelectionToScreenshot,
19
18
  writeAnnotatedScreenshot,
20
19
  } from '../src/editor/codex-edit.js';
20
+ import {
21
+ parseEditTimeoutMs,
22
+ runEditSubprocess,
23
+ } from '../src/editor/edit-subprocess.js';
21
24
  import { buildSlideRuntimeHtml } from '../src/image-contract.js';
22
25
 
23
26
  const __filename = fileURLToPath(import.meta.url);
@@ -45,6 +48,7 @@ const SLIDE_FILE_PATTERN = /^slide-.*\.html$/i;
45
48
 
46
49
  const MAX_RUNS = 200;
47
50
  const MAX_LOG_CHARS = 800_000;
51
+ const EDIT_TIMEOUT_MS = parseEditTimeoutMs();
48
52
 
49
53
  function printUsage() {
50
54
  process.stdout.write(`Usage: slides-grab edit [options]\n\n`);
@@ -233,37 +237,24 @@ function randomRunId() {
233
237
  return `run-${ts}-${rand}`;
234
238
  }
235
239
 
240
+ function mirrorRunLog(onLog) {
241
+ return (stream, chunk) => {
242
+ onLog(stream, chunk);
243
+ process[stream].write(chunk);
244
+ };
245
+ }
246
+
236
247
  function spawnCodexEdit({ prompt, imagePath, model, cwd, onLog }) {
237
248
  const codexBin = process.env.PPT_AGENT_CODEX_BIN || 'codex';
238
249
  const args = buildCodexExecArgs({ prompt, imagePath, model });
239
-
240
- return new Promise((resolvePromise, rejectPromise) => {
241
- const child = spawn(codexBin, args, { cwd, stdio: 'pipe' });
242
-
243
- let stdout = '';
244
- let stderr = '';
245
-
246
- child.stdout.on('data', (chunk) => {
247
- const text = chunk.toString();
248
- stdout += text;
249
- onLog('stdout', text);
250
- process.stdout.write(text);
251
- });
252
-
253
- child.stderr.on('data', (chunk) => {
254
- const text = chunk.toString();
255
- stderr += text;
256
- onLog('stderr', text);
257
- process.stderr.write(text);
258
- });
259
-
260
- child.on('close', (code) => {
261
- resolvePromise({ code: code ?? 1, stdout, stderr });
262
- });
263
-
264
- child.on('error', (error) => {
265
- rejectPromise(error);
266
- });
250
+ return runEditSubprocess({
251
+ bin: codexBin,
252
+ args,
253
+ cwd,
254
+ stdio: 'pipe',
255
+ timeoutMs: EDIT_TIMEOUT_MS,
256
+ engineLabel: 'Codex',
257
+ onLog: mirrorRunLog(onLog),
267
258
  });
268
259
  }
269
260
 
@@ -275,37 +266,15 @@ function spawnClaudeEdit({ prompt, imagePath, model, cwd, onLog }) {
275
266
  const env = { ...process.env };
276
267
  delete env.CLAUDECODE;
277
268
 
278
- return new Promise((resolvePromise, rejectPromise) => {
279
- const child = spawn(claudeBin, args, {
280
- cwd,
281
- stdio: ['ignore', 'pipe', 'pipe'],
282
- env,
283
- });
284
-
285
- let stdout = '';
286
- let stderr = '';
287
-
288
- child.stdout.on('data', (chunk) => {
289
- const text = chunk.toString();
290
- stdout += text;
291
- onLog('stdout', text);
292
- process.stdout.write(text);
293
- });
294
-
295
- child.stderr.on('data', (chunk) => {
296
- const text = chunk.toString();
297
- stderr += text;
298
- onLog('stderr', text);
299
- process.stderr.write(text);
300
- });
301
-
302
- child.on('close', (code) => {
303
- resolvePromise({ code: code ?? 1, stdout, stderr });
304
- });
305
-
306
- child.on('error', (error) => {
307
- rejectPromise(error);
308
- });
269
+ return runEditSubprocess({
270
+ bin: claudeBin,
271
+ args,
272
+ cwd,
273
+ env,
274
+ stdio: ['ignore', 'pipe', 'pipe'],
275
+ timeoutMs: EDIT_TIMEOUT_MS,
276
+ engineLabel: 'Claude',
277
+ onLog: mirrorRunLog(onLog),
309
278
  });
310
279
  }
311
280
 
@@ -674,7 +643,7 @@ async function startServer(opts) {
674
643
  const success = result.code === 0;
675
644
  const message = success
676
645
  ? `${engineLabel} edit completed.`
677
- : `${engineLabel} exited with code ${result.code}.`;
646
+ : (result.timeoutMessage || `${engineLabel} exited with code ${result.code}.`);
678
647
 
679
648
  runStore.finishRun(runId, {
680
649
  status: success ? 'success' : 'failed',
@@ -0,0 +1,44 @@
1
+ #!/usr/bin/env node
2
+
3
+ import { resolve } from 'node:path';
4
+ import { fileURLToPath } from 'node:url';
5
+
6
+ import {
7
+ buildFixedSizeSvg,
8
+ buildTldrawImportUrl,
9
+ DEFAULT_TLDRAW_HEIGHT,
10
+ DEFAULT_TLDRAW_OUTPUT,
11
+ DEFAULT_TLDRAW_PADDING,
12
+ DEFAULT_TLDRAW_WIDTH,
13
+ getTldrawUsage,
14
+ loadTldrawInput,
15
+ main,
16
+ normalizeTldrawSnapshot,
17
+ parseTldrawCliArgs,
18
+ renderTldrawFile,
19
+ renderTldrawSnapshot,
20
+ } from '../src/tldraw/render.js';
21
+
22
+ export {
23
+ buildFixedSizeSvg,
24
+ buildTldrawImportUrl,
25
+ DEFAULT_TLDRAW_HEIGHT,
26
+ DEFAULT_TLDRAW_OUTPUT,
27
+ DEFAULT_TLDRAW_PADDING,
28
+ DEFAULT_TLDRAW_WIDTH,
29
+ getTldrawUsage,
30
+ loadTldrawInput,
31
+ normalizeTldrawSnapshot,
32
+ parseTldrawCliArgs,
33
+ renderTldrawFile,
34
+ renderTldrawSnapshot,
35
+ };
36
+
37
+ const isMain = process.argv[1] && resolve(process.argv[1]) === fileURLToPath(import.meta.url);
38
+
39
+ if (isMain) {
40
+ main().catch((error) => {
41
+ console.error(`[slides-grab] ${error.message}`);
42
+ process.exit(1);
43
+ });
44
+ }
@@ -33,9 +33,10 @@ Use the installed **slides-grab-design** skill.
33
33
  3. Run validation: `slides-grab validate --slides-dir <path>`
34
34
  4. If validation fails, automatically fix the slide HTML/CSS until validation passes.
35
35
  5. Build the viewer: `slides-grab build-viewer --slides-dir <path>`
36
- 6. Present viewer to user for review.
37
- 7. Revise individual slides based on feedback, then re-run validation and rebuild the viewer.
38
- 8. Optionally launch the visual editor: `slides-grab edit --slides-dir <path>`
36
+ 6. For complex diagrams (architecture, workflows, relationship maps, multi-node concepts), prefer `tldraw` over hand-built HTML/CSS diagrams. Render the asset with `slides-grab tldraw`, store it under `<slides-dir>/assets/`, and place it in the slide with a normal `<img>`.
37
+ 7. Present viewer to user for review.
38
+ 8. Revise individual slides based on feedback, then re-run validation and rebuild the viewer.
39
+ 9. Optionally launch the visual editor: `slides-grab edit --slides-dir <path>`
39
40
 
40
41
  **Do not proceed to Stage 3 without approval.**
41
42
 
@@ -58,6 +59,7 @@ Use the installed **slides-grab-export** skill.
58
59
  4. **Use `decks/<deck-name>/`** as the slides workspace for multi-deck projects.
59
60
  5. **Call out export risk clearly**: PPTX and Figma export are experimental / unstable and must be described as best-effort output.
60
61
  6. Use the stage skills as the source of truth for plan, design, and export rules.
62
+ 7. When a slide needs a complex diagram, default to a `tldraw`-generated asset unless the user explicitly asks for a different approach.
61
63
 
62
64
  ## Reference
63
65
  - `references/presentation-workflow-reference.md` — archived end-to-end workflow guidance from the legacy skill set
@@ -26,9 +26,10 @@ Use **design-skill** (`.claude/skills/design-skill/SKILL.md`).
26
26
  3. Run validation: `slides-grab validate --slides-dir <path>`
27
27
  4. If validation fails, automatically fix the slide HTML/CSS until validation passes.
28
28
  5. Build the viewer: `node scripts/build-viewer.js --slides-dir <path>`
29
- 6. Present viewer to user for review.
30
- 7. Revise individual slides based on feedback, then re-run validation and rebuild the viewer.
31
- 8. Optionally launch the visual editor: `slides-grab edit --slides-dir <path>`
29
+ 6. For complex diagrams (architecture, workflows, relationship maps, multi-node concepts), prefer `tldraw`. Render a local diagram asset with `slides-grab tldraw`, store it under `<slides-dir>/assets/`, and place it into the slide with a normal `<img>`.
30
+ 7. Present viewer to user for review.
31
+ 8. Revise individual slides based on feedback, then re-run validation and rebuild the viewer.
32
+ 9. Optionally launch the visual editor: `slides-grab edit --slides-dir <path>`
32
33
 
33
34
  **Do not proceed to Stage 3 without approval.**
34
35
 
@@ -50,3 +51,4 @@ Use **pptx-skill** (`.claude/skills/pptx-skill/SKILL.md`).
50
51
  3. **Read each stage's SKILL.md** for detailed rules — this skill only orchestrates.
51
52
  4. **Use `decks/<deck-name>/`** as the slides workspace for multi-deck projects.
52
53
  5. **Call out export risk clearly**: PPTX and Figma export are experimental / unstable and should be described as best-effort output.
54
+ 6. **Prefer tldraw for complex diagrams**: Use `slides-grab tldraw` for diagram-heavy slides unless the user explicitly wants another rendering path.
@@ -23,20 +23,29 @@ Generate high-quality `slide-XX.html` files in the selected slides workspace (`s
23
23
 
24
24
  ## Workflow
25
25
  1. Read approved `slide-outline.md`.
26
- 2. Generate slide HTML files with 2-digit numbering in selected `--slides-dir`.
27
- 3. Run `slides-grab validate --slides-dir <path>` after generation or edits.
28
- 4. If validation fails, automatically fix the source slide HTML/CSS and re-run validation until it passes.
29
- 5. Run `slides-grab build-viewer --slides-dir <path>` only after validation passes.
30
- 6. Iterate on user feedback by editing only requested slide files, then re-run validation and rebuild the viewer.
31
- 7. Keep revising until user approves conversion stage.
26
+ 2. Before generating slides, write a quick **visual thesis** (mood/material/energy), a **content plan** (opener → support/proof → detail/story → close/CTA), and the core design tokens (background, surface, text, muted, accent + display/headline/body/caption roles).
27
+ 3. Generate slide HTML files with 2-digit numbering in selected `--slides-dir`.
28
+ 4. If the deck needs a complex diagram (architecture, workflows, relationship maps, multi-node concepts), create the diagram in `tldraw`, export it with `slides-grab tldraw`, and treat the result as a local slide asset under `<slides-dir>/assets/`.
29
+ 5. Run `slides-grab validate --slides-dir <path>` after generation or edits.
30
+ 6. If validation fails, automatically fix the source slide HTML/CSS and re-run validation until it passes.
31
+ 7. Run `slides-grab build-viewer --slides-dir <path>` only after validation passes.
32
+ 8. Run the slide litmus check from `references/beautiful-slide-defaults.md` before presenting the deck for review.
33
+ 9. Iterate on user feedback by editing only requested slide files, then re-run validation and rebuild the viewer.
34
+ 10. Keep revising until user approves conversion stage.
32
35
 
33
36
  ## Rules
34
37
  - Keep slide size 720pt x 405pt.
35
38
  - Keep semantic text tags (`p`, `h1-h6`, `ul`, `ol`, `li`).
36
39
  - Put local images under `<slides-dir>/assets/` and reference them as `./assets/<file>`.
37
40
  - Allow `data:` URLs when the slide must be fully self-contained.
38
- - Treat remote `https://` images as best-effort only, and never use absolute filesystem paths.
41
+ - Do not leave remote `http(s)://` image URLs in saved slide HTML; download source images into `<slides-dir>/assets/` and reference them as `./assets/<file>`.
39
42
  - Prefer `<img>` for slide imagery and `data-image-placeholder` when no final asset exists.
43
+ - Default to one job per slide, one dominant visual anchor, and copy that scans in seconds.
44
+ - Treat opening slides and section dividers like posters, not dashboards.
45
+ - Default to cardless layouts; only add a card when it improves structure or comprehension.
46
+ - Use whitespace, alignment, scale, cropping, and contrast before adding decorative chrome.
47
+ - Prefer `tldraw` for complex diagrams instead of recreating dense node/edge diagrams directly in HTML/CSS.
48
+ - Use `slides-grab tldraw` plus `templates/diagram-tldraw.html` when that gives a cleaner, more export-friendly result.
40
49
  - Do not present slides for review until `slides-grab validate --slides-dir <path>` passes.
41
50
  - Do not start conversion before approval.
42
51
  - Use the packaged CLI and bundled references only; do not depend on unpublished agent-specific files.
@@ -45,4 +54,5 @@ Generate high-quality `slide-XX.html` files in the selected slides workspace (`s
45
54
  For full constraints and style system, follow:
46
55
  - `references/design-rules.md`
47
56
  - `references/detailed-design-rules.md`
57
+ - `references/beautiful-slide-defaults.md` — slide-specific art direction defaults adapted from OpenAI's frontend design guidance
48
58
  - `references/design-system-full.md` — archived full design system, templates, and advanced pattern guidance
@@ -0,0 +1,45 @@
1
+ # Beautiful Slide Defaults
2
+
3
+ Slide-specific art direction guidance adapted from OpenAI's frontend design guidance for GPT-5.4. Use it to make HTML slides feel deliberate, premium, and instantly scannable without breaking `slides-grab`'s export constraints.
4
+
5
+ ## Working Model
6
+
7
+ Before building the deck, write two things:
8
+
9
+ - **visual thesis** — one sentence describing the mood, material, energy, and imagery treatment
10
+ - **content plan** — opener → support/proof → detail/story → close/CTA or decision
11
+
12
+ If the style direction is still open, gather visual references or a mood board first. Define the core tokens early: `background`, `surface`, `primary text`, `muted text`, `accent`, plus typography roles for `display`, `headline`, `body`, and `caption`.
13
+
14
+ ## Beautiful Defaults for Slides
15
+
16
+ - Start with composition, not components.
17
+ - Treat the opening slide like a poster and make the title or brand the loudest text.
18
+ - Give each slide one job, one primary takeaway, and one dominant visual anchor.
19
+ - Keep copy short enough to scan in seconds.
20
+ - Use whitespace, alignment, scale, cropping, and contrast before adding chrome.
21
+ - Limit the system by default: two typefaces max and one accent color.
22
+ - Default to cardless layouts. Prefer sections, grids, media blocks, dividers, and strong negative space.
23
+ - Use real imagery, product views, diagrams, or data as the main visual idea. Decorative gradients and abstract filler do not count.
24
+ - Keep the first slide free of secondary clutter such as stat strips, metadata piles, or multiple competing callouts unless the brief explicitly demands them.
25
+
26
+ ## Narrative Sequence for Decks
27
+
28
+ Use a narrative rhythm that feels intentional:
29
+
30
+ 1. **Opener** — identity, premise, or promise
31
+ 2. **Support / proof** — key evidence, context, or concrete value
32
+ 3. **Detail / story** — workflow, mechanism, or deeper explanation
33
+ 4. **Close / CTA** — decision, recommendation, next step, or final message
34
+
35
+ Section dividers should reset the visual tempo. Alternate dense proof slides with simpler image-led or statement-led slides so the deck keeps breathing.
36
+
37
+ ## Review Litmus
38
+
39
+ Before showing the deck, ask:
40
+
41
+ - Can the audience grasp the main point of each slide in 3–5 seconds?
42
+ - Does each slide have one dominant idea instead of multiple competing blocks?
43
+ - Is there one real visual anchor, not just decoration?
44
+ - Would this still feel premium without shadows, cards, or extra chrome?
45
+ - Can any line of copy, badge, or callout be removed without losing meaning?
@@ -6,6 +6,7 @@ These are the packaged design rules for installable `slides-grab` skills.
6
6
  - Validate slides: `slides-grab validate --slides-dir <path>`
7
7
  - Build review viewer: `slides-grab build-viewer --slides-dir <path>`
8
8
  - Launch editor: `slides-grab edit --slides-dir <path>`
9
+ - Render `tldraw` diagrams: `slides-grab tldraw --input <path> --output <path>`
9
10
 
10
11
  ## Slide spec
11
12
  - Slide size: `720pt x 405pt` (16:9)
@@ -17,7 +18,10 @@ These are the packaged design rules for installable `slides-grab` skills.
17
18
  ## Asset rules
18
19
  - Store deck-local assets in `<slides-dir>/assets/`
19
20
  - Reference deck-local assets as `./assets/<file>`
21
+ - If an image comes from the web, download it into `<slides-dir>/assets/` before referencing it
22
+ - Use `tldraw`-generated local assets for complex diagrams when possible
20
23
  - Allow `data:` URLs only when the slide must be fully self-contained
24
+ - Do not leave remote `http(s)://` image URLs in saved slide HTML
21
25
  - Never use absolute filesystem paths
22
26
 
23
27
  ## Package-published theme references
@@ -40,10 +44,12 @@ These are the packaged design rules for installable `slides-grab` skills.
40
44
  - `templates/closing.html`
41
45
  - `templates/chart.html`
42
46
  - `templates/diagram.html`
47
+ - `templates/diagram-tldraw.html`
43
48
  - `templates/custom/`
44
49
 
45
50
  ## Review loop
46
51
  - Generate or edit only the needed slide files.
52
+ - Prefer `tldraw` for complex diagrams instead of hand-building dense diagram geometry in HTML/CSS.
47
53
  - Re-run validation after every generation/edit pass.
48
54
  - Rebuild the viewer only after validation passes.
49
55
  - Do not move to export until the user approves the reviewed deck.
@@ -282,6 +282,10 @@ grid-template-columns: 1fr 2.3fr;
282
282
  ### 12. Diagram Slide
283
283
  - Template file: `templates/diagram.html`
284
284
 
285
+ ### 13. Tldraw Diagram Slide
286
+ - Template file: `templates/diagram-tldraw.html`
287
+ - Use this when the slide needs a complex diagram that will be easier to author in `tldraw` and safer to export as a local image asset.
288
+
285
289
  ### Custom Templates
286
290
  - Custom template directory: `templates/custom/`
287
291
  - Users can add template files as drop-in for reuse.
@@ -457,11 +461,13 @@ Store the image at `<slides-dir>/assets/team-photo.png`.
457
461
  <img src="data:image/svg+xml;base64,..." alt="Illustration" style="width: 220pt; height: 140pt; object-fit: cover;">
458
462
  ```
459
463
 
460
- #### Remote URL (Best-Effort Only)
464
+ #### Remote URL Source (Download Before Saving)
461
465
  ```html
462
466
  <img src="https://images.example.com/hero.png" alt="Hero image" style="width: 220pt; height: 140pt; object-fit: cover;">
463
467
  ```
464
468
 
469
+ If the image source starts on the web, download it into `<slides-dir>/assets/` and change the saved slide HTML to `./assets/<file>`.
470
+
465
471
  #### Placeholder (Image Stand-In)
466
472
  ```html
467
473
  <div data-image-placeholder style="width: 220pt; height: 140pt; border: 1px dashed #c7c7c7; background: #f3f4f6; display: flex; align-items: center; justify-content: center;">
@@ -474,7 +480,7 @@ Rules:
474
480
  - Use `./assets/<file>` as the default image contract for slide HTML.
475
481
  - Keep slide assets in `<slides-dir>/assets/`.
476
482
  - `data:` URLs are allowed for fully self-contained slides.
477
- - Remote `https://` URLs are allowed but non-deterministic and should be treated as fallback only.
483
+ - Do not leave remote `http(s)://` image URLs in saved slide HTML; download source images into `<slides-dir>/assets/` and reference them as `./assets/<file>`.
478
484
  - Do not use absolute filesystem paths in slide HTML.
479
485
  - Do not use non-body `background-image` for content imagery; use `<img>` instead.
480
486
  - Use `data-image-placeholder` to reserve space when no image is available yet.
@@ -536,28 +542,30 @@ This skill is **Stage 2**. It works from the `slide-outline.md` approved by the
536
542
  ### Steps
537
543
 
538
544
  1. **Analyze + Design**: Read `slide-outline.md`, decide theme/layout, generate HTML slides
539
- 2. **Validate slides**: After slide generation or edits, automatically run:
545
+ 2. **Diagram choice**: If a slide needs a complex diagram (architecture, workflows, relationship maps, multi-node concepts), prefer `tldraw`. Export the diagram with `slides-grab tldraw` and reference the generated local asset from the slide HTML.
546
+ 3. **Validate slides**: After slide generation or edits, automatically run:
540
547
  ```bash
541
548
  slides-grab validate --slides-dir <path>
542
549
  ```
543
- 3. **Auto-fix validation issues**: If validation fails, fix the source HTML/CSS and re-run validation until it passes
544
- 4. **Auto-build viewer**: After validation passes, automatically run:
550
+ 4. **Auto-fix validation issues**: If validation fails, fix the source HTML/CSS and re-run validation until it passes
551
+ 5. **Auto-build viewer**: After validation passes, automatically run:
545
552
  ```bash
546
553
  node scripts/build-viewer.js --slides-dir <path>
547
554
  ```
548
- 5. **Guide user to review**: Tell the user to check slides in the browser:
555
+ 6. **Guide user to review**: Tell the user to check slides in the browser:
549
556
  ```
550
557
  open <slides-dir>/viewer.html
551
558
  ```
552
- 6. **Revision loop**: When the user requests changes to specific slides:
559
+ 7. **Revision loop**: When the user requests changes to specific slides:
553
560
  - Edit only the relevant HTML file
554
561
  - Re-run `slides-grab validate --slides-dir <path>` and fix any failures
555
562
  - Re-run `node scripts/build-viewer.js --slides-dir <path>` to rebuild the viewer
556
563
  - Guide user to review again
557
- 7. **Completion**: Repeat the revision loop until the user signals approval for PPTX conversion
564
+ 8. **Completion**: Repeat the revision loop until the user signals approval for PPTX conversion
558
565
 
559
566
  ### Absolute Rules
560
567
  - **Never start PPTX conversion without approval** — PPTX conversion is the responsibility of `pptx-skill` and requires explicit user approval.
568
+ - **Prefer tldraw for complex diagrams** — Use `slides-grab tldraw` when the slide needs a non-trivial diagram instead of forcing dense diagram geometry into HTML/CSS.
561
569
  - **Never skip validation** — Run `slides-grab validate --slides-dir <path>` after generation or edits and fix failures before review.
562
570
  - **Never forget to build the viewer** — Run `node scripts/build-viewer.js --slides-dir <path>` every time slides are generated or modified.
563
571
 
@@ -567,6 +575,6 @@ This skill is **Stage 2**. It works from the `slide-outline.md` approved by the
567
575
 
568
576
  1. **CSS gradients**: Not supported in PowerPoint conversion — replace with background images
569
577
  2. **Webfonts**: Always include the Pretendard CDN link
570
- 3. **Image paths**: Use `./assets/<file>` from each `slide-XX.html`; avoid absolute filesystem paths
578
+ 3. **Image paths**: Use `./assets/<file>` from each `slide-XX.html`; avoid absolute filesystem paths and do not leave remote `http(s)://` image URLs in saved slide HTML
571
579
  4. **Colors**: Always include `#` prefix in CSS
572
580
  5. **Text rules**: Never place text directly in div/span
@@ -9,8 +9,9 @@
9
9
  - Always include alt on img tags.
10
10
  - Use `./assets/<file>` as the default image contract for slide HTML.
11
11
  - Keep slide assets in `<slides-dir>/assets/`.
12
+ - Use `tldraw`-generated assets for complex diagrams whenever possible.
12
13
  - `data:` URLs are allowed for fully self-contained slides.
13
- - Remote `https://` URLs are allowed but non-deterministic and fallback only.
14
+ - Do not leave remote `http(s)://` image URLs in saved slide HTML; download source images into `<slides-dir>/assets/` and reference them as `./assets/<file>`.
14
15
  - Do not use absolute filesystem paths in slide HTML.
15
16
  - Do not use non-body `background-image` for content imagery; use `<img>` instead.
16
17
  - Use `data-image-placeholder` to reserve space when no image is available yet.
@@ -23,6 +24,7 @@
23
24
  - After slide generation or edits, run `slides-grab validate --slides-dir <path>`.
24
25
  - After validation passes, run `slides-grab build-viewer --slides-dir <path>`.
25
26
  - Edit only the relevant HTML file during revision loops.
27
+ - Prefer `slides-grab tldraw` + local exported assets for architecture, workflow, relationship, and other complex diagrams.
26
28
  - Never start PPTX conversion without explicit approval.
27
29
  - Never forget to build the viewer after slide changes.
28
30
  - Do not persist runtime-only editor/viewer injections in saved slide HTML.