slides-grab 1.0.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 (51) hide show
  1. package/AGENTS.md +80 -0
  2. package/LICENSE +21 -0
  3. package/PROGRESS.md +39 -0
  4. package/README.md +120 -0
  5. package/SETUP.md +51 -0
  6. package/bin/ppt-agent.js +204 -0
  7. package/convert.cjs +184 -0
  8. package/package.json +51 -0
  9. package/prd.json +135 -0
  10. package/prd.md +104 -0
  11. package/scripts/editor-server.js +779 -0
  12. package/scripts/html2pdf.js +217 -0
  13. package/scripts/validate-slides.js +416 -0
  14. package/skills/ppt-design-skill/SKILL.md +38 -0
  15. package/skills/ppt-plan-skill/SKILL.md +37 -0
  16. package/skills/ppt-pptx-skill/SKILL.md +37 -0
  17. package/skills/ppt-presentation-skill/SKILL.md +57 -0
  18. package/src/editor/codex-edit.js +213 -0
  19. package/src/editor/editor.html +1733 -0
  20. package/src/editor/js/editor-bbox.js +332 -0
  21. package/src/editor/js/editor-chat.js +56 -0
  22. package/src/editor/js/editor-direct-edit.js +110 -0
  23. package/src/editor/js/editor-dom.js +55 -0
  24. package/src/editor/js/editor-init.js +284 -0
  25. package/src/editor/js/editor-navigation.js +54 -0
  26. package/src/editor/js/editor-select.js +264 -0
  27. package/src/editor/js/editor-send.js +157 -0
  28. package/src/editor/js/editor-sse.js +163 -0
  29. package/src/editor/js/editor-state.js +32 -0
  30. package/src/editor/js/editor-utils.js +167 -0
  31. package/src/editor/screenshot.js +73 -0
  32. package/src/resolve.js +159 -0
  33. package/templates/chart.html +121 -0
  34. package/templates/closing.html +54 -0
  35. package/templates/content.html +50 -0
  36. package/templates/contents.html +60 -0
  37. package/templates/cover.html +64 -0
  38. package/templates/custom/.gitkeep +0 -0
  39. package/templates/custom/README.md +7 -0
  40. package/templates/diagram.html +98 -0
  41. package/templates/quote.html +31 -0
  42. package/templates/section-divider.html +43 -0
  43. package/templates/split-layout.html +41 -0
  44. package/templates/statistics.html +55 -0
  45. package/templates/team.html +49 -0
  46. package/templates/timeline.html +59 -0
  47. package/themes/corporate.css +8 -0
  48. package/themes/executive.css +10 -0
  49. package/themes/modern-dark.css +9 -0
  50. package/themes/sage.css +9 -0
  51. package/themes/warm.css +8 -0
package/package.json ADDED
@@ -0,0 +1,51 @@
1
+ {
2
+ "name": "slides-grab",
3
+ "version": "1.0.0",
4
+ "description": "Agent-first presentation framework — plan, design, and visually edit HTML slides with Claude Code or Codex, then export to PPTX/PDF",
5
+ "license": "MIT",
6
+ "author": "vkehfdl1",
7
+ "repository": {
8
+ "type": "git",
9
+ "url": "git+https://github.com/vkehfdl1/slides-grab.git"
10
+ },
11
+ "homepage": "https://github.com/vkehfdl1/slides-grab#readme",
12
+ "bugs": {
13
+ "url": "https://github.com/vkehfdl1/slides-grab/issues"
14
+ },
15
+ "keywords": [
16
+ "presentation",
17
+ "pptx",
18
+ "slides",
19
+ "html-slides",
20
+ "slide-editor",
21
+ "claude",
22
+ "codex",
23
+ "ai-agent",
24
+ "ppt"
25
+ ],
26
+ "engines": {
27
+ "node": ">=18.0.0"
28
+ },
29
+ "type": "module",
30
+ "bin": {
31
+ "slides-grab": "./bin/ppt-agent.js"
32
+ },
33
+ "scripts": {
34
+ "html2pptx": "node .claude/skills/pptx-skill/scripts/html2pptx.js",
35
+ "build-viewer": "node scripts/build-viewer.js",
36
+ "validate": "node scripts/validate-slides.js",
37
+ "convert": "node convert.cjs",
38
+ "codex:install-skills": "node scripts/install-codex-skills.js --force",
39
+ "test": "node --test tests/editor/editor-codex-edit.test.js tests/pdf/html2pdf.test.js",
40
+ "test:e2e": "node --test tests/editor/editor-ui.e2e.test.js tests/editor/editor-concurrency.e2e.test.js"
41
+ },
42
+ "dependencies": {
43
+ "commander": "^12.1.0",
44
+ "express": "^5.2.1",
45
+ "pdf-lib": "^1.17.1",
46
+ "playwright": "^1.40.0",
47
+ "pptxgenjs": "^3.12.0",
48
+ "react-icons": "^5.0.0",
49
+ "sharp": "^0.33.0"
50
+ }
51
+ }
package/prd.json ADDED
@@ -0,0 +1,135 @@
1
+ {
2
+ "project": "slides-grab",
3
+ "branchName": "main",
4
+ "description": "slides-grab\ub97c npm \ud328\ud0a4\uc9c0\ub85c \ubc30\ud3ec\ud558\uae30 \uc704\ud55c \uae30\ubc18 \uad6c\uc870\ub97c \uad6c\ucd95\ud55c\ub2e4. SETUP.md \uc791\uc131, README.md \uc5c5\ub370\uc774\ud2b8, CLI \uae30\ubcf8 \ubf08\ub300, agentskills.io \ud45c\uc900 SKILL.md frontmatter \uc801\uc6a9. npm publish \uc790\uccb4\ub294 \uc774\ubc88 \ubc94\uc704\uc5d0 \ud3ec\ud568\ud558\uc9c0 \uc54a\ub294\ub2e4.",
5
+ "userStories": [
6
+ {
7
+ "id": "US-001",
8
+ "title": "\ud15c\ud50c\ub9bf \uc2dc\uc2a4\ud15c \uc678\ubd80\ud654",
9
+ "description": "design-skill/SKILL.md(963\uc904)\uc5d0 \ub0b4\uc7a5\ub41c 10\uac1c \uc2ac\ub77c\uc774\ub4dc \ud15c\ud50c\ub9bf\uacfc 5\uac1c \uceec\ub7ec \ud314\ub808\ud2b8\ub97c \ub3c5\ub9bd \ud30c\uc77c\ub85c \ubd84\ub9ac\ud55c\ub2e4. \uc5d0\uc774\uc804\ud2b8\uac00 \ucc38\uc870\ud560 \uc218 \uc788\ub294 \uc608\uc2dc \ud30c\uc77c\ub85c \uc874\uc7ac\ud558\uba70, \uc0ac\uc6a9\uc790\uac00 \ucee4\uc2a4\ud140 \ud15c\ud50c\ub9bf\uc744 drop-in\uc73c\ub85c \ucd94\uac00\ud560 \uc218 \uc788\ub294 \uad6c\uc870\ub97c \ub9cc\ub4e0\ub2e4.",
10
+ "acceptanceCriteria": [
11
+ "REQ-001 `templates/` \ub514\ub809\ud1a0\ub9ac\uc5d0 10\uac1c HTML \ud15c\ud50c\ub9bf \ud30c\uc77c\uc774 \uc874\uc7ac\ud55c\ub2e4 (cover.html, contents.html, section-divider.html, content.html, statistics.html, split-layout.html, team.html, quote.html, timeline.html, closing.html)",
12
+ "REQ-002 `themes/` \ub514\ub809\ud1a0\ub9ac\uc5d0 5\uac1c CSS \ud14c\ub9c8 \ud30c\uc77c\uc774 \uc874\uc7ac\ud55c\ub2e4 (executive.css, sage.css, modern-dark.css, corporate.css, warm.css)",
13
+ "REQ-003 design-skill/SKILL.md\uc5d0\uc11c HTML \ucf54\ub4dc \ube14\ub85d\uc774 \uc81c\uac70\ub418\uace0, \ub300\uc2e0 `templates/`\uc640 `themes/` \uacbd\ub85c\ub97c \ucc38\uc870\ud558\ub3c4\ub85d \uc5c5\ub370\uc774\ud2b8\ub41c\ub2e4",
14
+ "REQ-004 design-skill/SKILL.md\uc758 \ub514\uc790\uc778 \ucca0\ud559, \uaddc\uce59, \uc81c\uc57d\uc0ac\ud56d \uc139\uc158\uc740 \uadf8\ub300\ub85c \uc720\uc9c0\ub41c\ub2e4",
15
+ "REQ-005 `templates/custom/` \ub514\ub809\ud1a0\ub9ac\uac00 \uc874\uc7ac\ud558\uace0, \uc0ac\uc6a9\uc790\uac00 \uc5ec\uae30\uc5d0 \ucee4\uc2a4\ud140 \ud15c\ud50c\ub9bf\uc744 \ucd94\uac00\ud560 \uc218 \uc788\ub2e4"
16
+ ],
17
+ "priority": 1,
18
+ "passes": true,
19
+ "notes": ""
20
+ },
21
+ {
22
+ "id": "US-002",
23
+ "title": "Playwright \uae30\ubc18 \uad6c\uc870\ud654 \uac80\uc99d \uc2a4\ud06c\ub9bd\ud2b8",
24
+ "description": "HTML \uc2ac\ub77c\uc774\ub4dc \uc0dd\uc131 \ud6c4 Playwright\ub85c \ub80c\ub354\ub9c1\ud558\uc5ec overflow, \ud14d\uc2a4\ud2b8 \uc798\ub9bc, \uc694\uc18c \uacb9\uce68 \ub4f1 \uad6c\uc870\uc801 \ubb38\uc81c\ub97c \ud504\ub85c\uadf8\ub798\ubc0d\uc801\uc73c\ub85c \uc790\ub3d9 \ud0d0\uc9c0\ud558\ub294 \uac80\uc99d \uc2a4\ud06c\ub9bd\ud2b8\ub97c \ub9cc\ub4e0\ub2e4. VLM \ud638\ucd9c \uc5c6\uc774 \ube44\uc6a9 0\uc73c\ub85c \uae30\ubcf8 \ud488\uc9c8\uc744 \ubcf4\uc7a5\ud55c\ub2e4.",
25
+ "acceptanceCriteria": [
26
+ "REQ-006 `scripts/validate-slides.js`\uac00 \uc874\uc7ac\ud558\uace0, `node scripts/validate-slides.js` \uba85\ub839\uc73c\ub85c \uc2e4\ud589 \uac00\ub2a5\ud558\ub2e4",
27
+ "REQ-007 \uc2ac\ub77c\uc774\ub4dc \ud504\ub808\uc784(720pt \u00d7 405pt) \ubc16\uc73c\ub85c \ub118\uce58\ub294 \uc694\uc18c\ub97c \ud0d0\uc9c0\ud55c\ub2e4 (boundingBox \uac80\uc0ac)",
28
+ "REQ-008 `scrollHeight > clientHeight`\uc778 \ud14d\uc2a4\ud2b8 \uc694\uc18c(\ud14d\uc2a4\ud2b8 \uc798\ub9bc)\ub97c \ud0d0\uc9c0\ud55c\ub2e4",
29
+ "REQ-009 \uac19\uc740 \ub808\ubca8 \uc694\uc18c\ub4e4\uc758 boundingBox \uad50\ucc28(\uacb9\uce68)\ub97c \ud0d0\uc9c0\ud55c\ub2e4",
30
+ "REQ-010 \uacb0\uacfc\ub97c JSON \ud615\uc2dd\uc73c\ub85c \ucd9c\ub825\ud55c\ub2e4 (slide\ubcc4 status: pass/fail, critical \uc774\uc288 \ubaa9\ub85d, warning \ubaa9\ub85d, summary)",
31
+ "REQ-011 `slides/` \ub514\ub809\ud1a0\ub9ac\uc758 \ubaa8\ub4e0 `slide-*.html` \ud30c\uc77c\uc744 \uc790\ub3d9\uc73c\ub85c \uac80\uc99d\ud55c\ub2e4"
32
+ ],
33
+ "priority": 2,
34
+ "passes": true,
35
+ "notes": ""
36
+ },
37
+ {
38
+ "id": "US-003",
39
+ "title": "VLM Provider \ud45c\uc900 \uc778\ud130\ud398\uc774\uc2a4 (Vercel AI SDK)",
40
+ "description": "Vercel AI SDK\ub97c \uc0ac\uc6a9\ud558\uc5ec VLM(Vision Language Model)\uc5d0 \uc774\ubbf8\uc9c0\ub97c \ubcf4\ub0b4\uace0 \ubd84\uc11d \uacb0\uacfc\ub97c \ubc1b\ub294 \ud1b5\ud569 \uc778\ud130\ud398\uc774\uc2a4\ub97c \uad6c\ud604\ud55c\ub2e4. Gemini, Claude, OpenAI \ud504\ub85c\ubc14\uc774\ub354\ub97c \uad50\uccb4 \uac00\ub2a5\ud558\uac8c \uc9c0\uc6d0\ud55c\ub2e4. JavaScript\ub85c \uc791\uc131\ud55c\ub2e4.",
41
+ "acceptanceCriteria": [
42
+ "REQ-012 `ai`, `@ai-sdk/google`, `@ai-sdk/anthropic` \ud328\ud0a4\uc9c0\uac00 package.json dependencies\uc5d0 \ucd94\uac00\ub41c\ub2e4",
43
+ "REQ-013 `src/vlm/analyze.js`\uc5d0 `analyzeImage(imagePath, prompt, config)` \ud568\uc218\uac00 \uc874\uc7ac\ud558\uace0 export\ub41c\ub2e4",
44
+ "REQ-014 `src/vlm/analyze.js`\uc5d0 `analyzeImages(imagePaths, prompt, config)` \ud568\uc218\uac00 \uc874\uc7ac\ud558\uace0 export\ub41c\ub2e4 (\uc5ec\ub7ec \uc774\ubbf8\uc9c0 \ub3d9\uc2dc \ubd84\uc11d)",
45
+ "REQ-015 config \uac1d\uccb4\ub85c `{ provider: \"google\"|\"anthropic\"|\"openai\", model: \"\ubaa8\ub378\uba85\", maxTokens, temperature }`\ub97c \ubc1b\ub294\ub2e4",
46
+ "REQ-016 \ud658\uacbd \ubcc0\uc218 `GEMINI_API_KEY` \ub610\ub294 `ANTHROPIC_API_KEY`\ub85c API \ud0a4\ub97c \uc124\uc815\ud560 \uc218 \uc788\ub2e4",
47
+ "REQ-017 \ubc18\ud658\uac12\uc740 `{ content: string, usage: { inputTokens, outputTokens } }` \ud615\ud0dc\uc774\ub2e4"
48
+ ],
49
+ "priority": 3,
50
+ "passes": true,
51
+ "notes": ""
52
+ },
53
+ {
54
+ "id": "US-004",
55
+ "title": "\ucc28\ud2b8/\ub2e4\uc774\uc5b4\uadf8\ub7a8/\uc774\ubbf8\uc9c0 HTML \ub77c\uc774\ube0c\ub7ec\ub9ac \uc9c0\uc6d0",
56
+ "description": "design-skill\uc774 Chart.js(\ucc28\ud2b8), Mermaid(\ub2e4\uc774\uc5b4\uadf8\ub7a8), \uc778\ub77c\uc778 SVG(\uc544\uc774\ucf58), \uc774\ubbf8\uc9c0\ub97c \ud65c\uc6a9\ud560 \uc218 \uc788\ub3c4\ub85d CDN \ub9c1\ud06c, \uc0ac\uc6a9\ubc95 \uac00\uc774\ub4dc, \uc608\uc2dc \ud15c\ud50c\ub9bf\uc744 \ucd94\uac00\ud55c\ub2e4. html2pptx.js\uc5d0\uc11c JS \ub77c\uc774\ube0c\ub7ec\ub9ac \ub80c\ub354\ub9c1 \ub300\uae30 \ub85c\uc9c1\ub3c4 \ucd94\uac00\ud55c\ub2e4.",
57
+ "acceptanceCriteria": [
58
+ "REQ-018 design-skill/SKILL.md\uc5d0 Chart.js CDN \ub9c1\ud06c\uc640 \uc0ac\uc6a9 \uc608\uc2dc(bar, line, pie \ucc28\ud2b8)\uac00 \ud3ec\ud568\ub41c\ub2e4",
59
+ "REQ-019 design-skill/SKILL.md\uc5d0 Mermaid CDN \ub9c1\ud06c\uc640 \uc0ac\uc6a9 \uc608\uc2dc(flowchart, sequence diagram)\uac00 \ud3ec\ud568\ub41c\ub2e4",
60
+ "REQ-020 design-skill/SKILL.md\uc5d0 \uc778\ub77c\uc778 SVG \uc544\uc774\ucf58 \uc791\uc131 \uac00\uc774\ub4dc\uac00 \ud3ec\ud568\ub41c\ub2e4",
61
+ "REQ-021 design-skill/SKILL.md\uc5d0 \uc774\ubbf8\uc9c0 \uc0ac\uc6a9 \uaddc\uce59(\ub85c\uceec \uacbd\ub85c, URL, \ud50c\ub808\uc774\uc2a4\ud640\ub354)\uc774 \ud3ec\ud568\ub41c\ub2e4",
62
+ "REQ-022 `templates/chart.html` \uc608\uc2dc \ud15c\ud50c\ub9bf\uc774 \uc874\uc7ac\ud55c\ub2e4 (Chart.js \ucc28\ud2b8\uac00 \ud3ec\ud568\ub41c \uc2ac\ub77c\uc774\ub4dc)",
63
+ "REQ-023 `templates/diagram.html` \uc608\uc2dc \ud15c\ud50c\ub9bf\uc774 \uc874\uc7ac\ud55c\ub2e4 (Mermaid \ub2e4\uc774\uc5b4\uadf8\ub7a8\uc774 \ud3ec\ud568\ub41c \uc2ac\ub77c\uc774\ub4dc)",
64
+ "REQ-024 html2pptx.js(\ub610\ub294 \uad00\ub828 \ubcc0\ud658 \uc2a4\ud06c\ub9bd\ud2b8)\uc5d0\uc11c Chart.js/Mermaid \ub80c\ub354\ub9c1 \uc644\ub8cc\ub97c \ub300\uae30\ud558\ub294 \ub85c\uc9c1\uc774 \uc788\ub2e4"
65
+ ],
66
+ "priority": 4,
67
+ "passes": true,
68
+ "notes": ""
69
+ },
70
+ {
71
+ "id": "US-005",
72
+ "title": "VLM \uae30\ubc18 \uc2ac\ub77c\uc774\ub4dc \uc790\ub3d9 \ud3ec\ub9f7 \uac80\uc99d",
73
+ "description": "VLM Provider \uc778\ud130\ud398\uc774\uc2a4(US-003)\ub97c \uc0ac\uc6a9\ud558\uc5ec \uc2ac\ub77c\uc774\ub4dc \uc2a4\ud06c\ub9b0\uc0f7\uc744 VLM\uc5d0 \ubcf4\ub0b4\uace0, \uc2dc\uac01\uc801 \ud3ec\ub9f7 \ubb38\uc81c(overflow, \ub2e8\uc5b4 \uc798\ub9bc, \uacb9\uce68, \uac00\ub3c5\uc131)\ub97c \ud0d0\uc9c0\ud558\ub294 \uac80\uc99d \uc2a4\ud06c\ub9bd\ud2b8\ub97c \ub9cc\ub4e0\ub2e4. \uc0ac\uc6a9\uc790\uac00 \uba85\uc2dc\uc801\uc73c\ub85c \uc694\uccad\ud560 \ub54c\ub9cc \uc2e4\ud589\ub418\uba70, \ucd5c\ub300 \ubc18\ubcf5 \ud69f\uc218\ub97c \uc124\uc815\ud560 \uc218 \uc788\ub2e4. \uc0ac\uc6a9\uc790\ub294 \ubdf0\uc5b4\uc5d0\uc11c \uc9c1\uc811 VLM\uc744 \ud1b5\ud574 \uc218\uc815\uc744 \uc694\uad6c\ud560 \uc218 \uc788\ub2e4.",
74
+ "acceptanceCriteria": [
75
+ "REQ-025 `scripts/vlm-validate.js`\uac00 \uc874\uc7ac\ud558\uace0 \uc2e4\ud589 \uac00\ub2a5\ud558\ub2e4",
76
+ "REQ-026 \uac01 \uc2ac\ub77c\uc774\ub4dc\ub97c Playwright\ub85c \uc2a4\ud06c\ub9b0\uc0f7(1600\u00d7900px)\ud558\uc5ec VLM\uc5d0 \uc804\uc1a1\ud55c\ub2e4",
77
+ "REQ-027 VLM \ud53c\ub4dc\ubc31\uc744 \uad6c\uc870\ud654\ub41c JSON\uc73c\ub85c \ud30c\uc2f1\ud55c\ub2e4 (slide, issues \ubc30\uc5f4, pass/fail)",
78
+ "REQ-028 `--max-iterations` \uc635\uc158\uc73c\ub85c \ucd5c\ub300 \ubc18\ubcf5 \ud69f\uc218\ub97c \uc124\uc815\ud560 \uc218 \uc788\ub2e4 (\uae30\ubcf8\uac12 3)",
79
+ "REQ-029 `--provider`\uc640 `--model` \uc635\uc158\uc73c\ub85c VLM \ud504\ub85c\ubc14\uc774\ub354\uc640 \ubaa8\ub378\uc744 \uc9c0\uc815\ud560 \uc218 \uc788\ub2e4 (\uae30\ubcf8\uac12 google/gemini-2.0-flash)",
80
+ "REQ-030 US-003\uc758 `analyzeImage()` \ud568\uc218\ub97c \uc0ac\uc6a9\ud55c\ub2e4"
81
+ ],
82
+ "priority": 5,
83
+ "passes": true,
84
+ "notes": ""
85
+ },
86
+ {
87
+ "id": "US-006",
88
+ "title": "PDF \ucd9c\ub825 \uc9c0\uc6d0",
89
+ "description": "HTML \uc2ac\ub77c\uc774\ub4dc\ub97c PDF\ub85c \ubcc0\ud658\ud558\ub294 \uc2a4\ud06c\ub9bd\ud2b8\ub97c \ub9cc\ub4e0\ub2e4. Playwright\uc758 page.pdf()\ub97c \uc0ac\uc6a9\ud558\uc5ec \uac01 \uc2ac\ub77c\uc774\ub4dc\ub97c PDF\ub85c \ub80c\ub354\ub9c1\ud558\uace0, pdf-lib\ub85c \ud558\ub098\uc758 PDF\ub85c \ubcd1\ud569\ud55c\ub2e4.",
90
+ "acceptanceCriteria": [
91
+ "REQ-031 `pdf-lib` \ud328\ud0a4\uc9c0\uac00 package.json dependencies\uc5d0 \ucd94\uac00\ub41c\ub2e4",
92
+ "REQ-032 `scripts/html2pdf.js`\uac00 \uc874\uc7ac\ud558\uace0 `node scripts/html2pdf.js` \uba85\ub839\uc73c\ub85c \uc2e4\ud589 \uac00\ub2a5\ud558\ub2e4",
93
+ "REQ-033 slides/ \ub514\ub809\ud1a0\ub9ac\uc758 \ubaa8\ub4e0 slide-*.html\uc744 \uc21c\uc11c\ub300\ub85c PDF\ub85c \ubcc0\ud658\ud55c\ub2e4",
94
+ "REQ-034 `printBackground: true` \uc635\uc158\uc73c\ub85c \ubc30\uacbd\uc0c9\uc774 \ubcf4\uc874\ub41c\ub2e4 (\ub2e4\ud06c \ud14c\ub9c8\uc5d0\uc11c \ud544\uc218)",
95
+ "REQ-035 \uac1c\ubcc4 \uc2ac\ub77c\uc774\ub4dc PDF\ub97c \ud558\ub098\uc758 \ud30c\uc77c\ub85c \ubcd1\ud569\ud558\uc5ec \ucd5c\uc885 PDF\ub97c \ucd9c\ub825\ud55c\ub2e4",
96
+ "REQ-036 `--output` \uc635\uc158\uc73c\ub85c \ucd9c\ub825 \ud30c\uc77c \uacbd\ub85c\ub97c \uc9c0\uc815\ud560 \uc218 \uc788\ub2e4"
97
+ ],
98
+ "priority": 6,
99
+ "passes": true,
100
+ "notes": ""
101
+ },
102
+ {
103
+ "id": "US-007",
104
+ "title": "VLM \uae30\ubc18 \uc0ac\uc6a9\uc790 \uc2a4\ud0c0\uc77c \ucd94\ucd9c",
105
+ "description": "\uc0ac\uc6a9\uc790\uac00 \uc81c\uacf5\ud55c PPTX \ub610\ub294 PDF \ud30c\uc77c\uc5d0\uc11c \uc2ac\ub77c\uc774\ub4dc\ub97c \uc2a4\ud06c\ub9b0\uc0f7\ud558\uace0, VLM\uc73c\ub85c \ub514\uc790\uc778 \uc2dc\uc2a4\ud15c(\uceec\ub7ec, \ud3f0\ud2b8, \ub808\uc774\uc544\uc6c3, \ud1a4)\uc744 \ubd84\uc11d\ud558\uc5ec style-config.md\ub85c \ucd9c\ub825\ud55c\ub2e4. \uae34 \ud504\ub808\uc820\ud14c\uc774\uc158\uc740 \ub79c\ub364 \uc0d8\ud50c\ub9c1\uc73c\ub85c \ube44\uc6a9\uc744 \ucd5c\uc801\ud654\ud55c\ub2e4.",
106
+ "acceptanceCriteria": [
107
+ "REQ-037 `scripts/extract-style.js`\uac00 \uc874\uc7ac\ud558\uace0 \uc2e4\ud589 \uac00\ub2a5\ud558\ub2e4",
108
+ "REQ-038 PPTX \ud30c\uc77c\uc744 \uc785\ub825\ubc1b\uc544 \uc2ac\ub77c\uc774\ub4dc\ubcc4 \uc2a4\ud06c\ub9b0\uc0f7\uc744 \uc0dd\uc131\ud560 \uc218 \uc788\ub2e4 (LibreOffice \ub610\ub294 Playwright \ud65c\uc6a9)",
109
+ "REQ-039 PDF \ud30c\uc77c\uc744 \uc785\ub825\ubc1b\uc544 \ud398\uc774\uc9c0\ubcc4 \uc2a4\ud06c\ub9b0\uc0f7\uc744 \uc0dd\uc131\ud560 \uc218 \uc788\ub2e4 (Poppler pdftoppm \ud65c\uc6a9)",
110
+ "REQ-040 \uc2ac\ub77c\uc774\ub4dc\uac00 10\uc7a5 \uc774\uc0c1\uc774\uba74 \ub79c\ub364 \uc0d8\ud50c\ub9c1(5~8\uc7a5)\uc744 \uc218\ud589\ud55c\ub2e4. \uccab \ubc88\uc9f8(\ud45c\uc9c0)\uc640 \ub9c8\uc9c0\ub9c9(\ub9c8\ubb34\ub9ac) \uc2ac\ub77c\uc774\ub4dc\ub294 \ud56d\uc0c1 \ud3ec\ud568\ud55c\ub2e4",
111
+ "REQ-041 US-003\uc758 `analyzeImages()` \ud568\uc218\ub97c \uc0ac\uc6a9\ud558\uc5ec VLM\uc5d0 \ubd84\uc11d\uc744 \uc694\uccad\ud55c\ub2e4",
112
+ "REQ-042 \uacb0\uacfc\ub97c `style-config.md`\ub85c \ucd9c\ub825\ud55c\ub2e4 (\uceec\ub7ec \ud314\ub808\ud2b8, \ud3f0\ud2b8 \uc2dc\uc2a4\ud15c, \ub808\uc774\uc544\uc6c3 \ud328\ud134, \uc2ac\ub77c\uc774\ub4dc \ud0c0\uc785, \uc804\uccb4 \ud1a4 \ud3ec\ud568)"
113
+ ],
114
+ "priority": 7,
115
+ "passes": true,
116
+ "notes": ""
117
+ },
118
+ {
119
+ "id": "US-008",
120
+ "title": "\ud504\ub85c\uc81d\ud2b8 \ud328\ud0a4\uc9d5 \uae30\ubc18 \uad6c\uc870",
121
+ "description": "slides-grab\ub97c npm \ud328\ud0a4\uc9c0\ub85c \ubc30\ud3ec\ud558\uae30 \uc704\ud55c \uae30\ubc18 \uad6c\uc870\ub97c \uad6c\ucd95\ud55c\ub2e4. SETUP.md \uc791\uc131, README.md \uc5c5\ub370\uc774\ud2b8, CLI \uae30\ubcf8 \ubf08\ub300, agentskills.io \ud45c\uc900 SKILL.md frontmatter \uc801\uc6a9. npm publish \uc790\uccb4\ub294 \uc774\ubc88 \ubc94\uc704\uc5d0 \ud3ec\ud568\ud558\uc9c0 \uc54a\ub294\ub2e4.",
122
+ "acceptanceCriteria": [
123
+ "REQ-043 `SETUP.md`\uac00 \uc874\uc7ac\ud558\uace0, macOS(brew), Ubuntu(apt), Windows(winget) \ubcc4 \uc6d0\ub77c\uc774\ub108 \uc124\uce58 \uba85\ub839\uc774 \ud3ec\ud568\ub41c\ub2e4",
124
+ "REQ-044 `README.md`\uc5d0 SETUP.md \ub0b4\uc6a9\uc774 \ud3ec\ud568\ub418\uc5b4 \uc0ac\uc6a9\uc790\uac00 \ubcf5\ubd99\uc73c\ub85c \uc124\uce58\ud560 \uc218 \uc788\ub2e4",
125
+ "REQ-045 `bin/slides-grab.js`\uc5d0 CLI \uae30\ubcf8 \ubf08\ub300\uac00 \uc874\uc7ac\ud55c\ub2e4 (commander \ud328\ud0a4\uc9c0 \uc0ac\uc6a9, `slides-grab --help` \ucd9c\ub825 \uac00\ub2a5)",
126
+ "REQ-046 CLI\uc5d0 `build-viewer`, `validate`, `convert` \uc11c\ube0c\ucee4\ub9e8\ub4dc\uac00 \uc815\uc758\ub41c\ub2e4 (\uac01 \uc2a4\ud06c\ub9bd\ud2b8\ub97c \ud638\ucd9c\ud558\ub294 \ub798\ud37c)",
127
+ "REQ-047 package.json\uc5d0 `\"bin\": { \"slides-grab\": \"./bin/slides-grab.js\" }`\uac00 \uc124\uc815\ub41c\ub2e4",
128
+ "REQ-048 \ubaa8\ub4e0 SKILL.md \ud30c\uc77c\uc5d0 agentskills.io \ud45c\uc900 frontmatter(name, description)\uac00 \ud3ec\ud568\ub41c\ub2e4"
129
+ ],
130
+ "priority": 8,
131
+ "passes": true,
132
+ "notes": ""
133
+ }
134
+ ]
135
+ }
package/prd.md ADDED
@@ -0,0 +1,104 @@
1
+ # PRD
2
+
3
+ ## Project
4
+ - Name: slides-grab
5
+ - Branch: main
6
+ - Description: Agent-first PPT framework — AI 에이전트가 HTML 슬라이드를 직접 작성하고, 3단계 파이프라인(Planning→Design→Conversion)으로 고품질 PPTX/PDF를 생성하는 프레임워크. 이번 PRD는 프레임워크의 핵심 기능 확장(VLM 검증, 차트 지원, 스타일 추출)과 배포 기반(npm 패키지, Skills 표준)을 구축한다.
7
+
8
+ ## User Stories
9
+
10
+ ### US-001
11
+ - Title: 템플릿 시스템 외부화
12
+ - Priority: 1
13
+ - Description: design-skill/SKILL.md(963줄)에 내장된 10개 슬라이드 템플릿과 5개 컬러 팔레트를 독립 파일로 분리한다. 에이전트가 참조할 수 있는 예시 파일로 존재하며, 사용자가 커스텀 템플릿을 drop-in으로 추가할 수 있는 구조를 만든다.
14
+ - Acceptance Criteria:
15
+ - REQ-001 `templates/` 디렉토리에 10개 HTML 템플릿 파일이 존재한다 (cover.html, contents.html, section-divider.html, content.html, statistics.html, split-layout.html, team.html, quote.html, timeline.html, closing.html)
16
+ - REQ-002 `themes/` 디렉토리에 5개 CSS 테마 파일이 존재한다 (executive.css, sage.css, modern-dark.css, corporate.css, warm.css)
17
+ - REQ-003 design-skill/SKILL.md에서 HTML 코드 블록이 제거되고, 대신 `templates/`와 `themes/` 경로를 참조하도록 업데이트된다
18
+ - REQ-004 design-skill/SKILL.md의 디자인 철학, 규칙, 제약사항 섹션은 그대로 유지된다
19
+ - REQ-005 `templates/custom/` 디렉토리가 존재하고, 사용자가 여기에 커스텀 템플릿을 추가할 수 있다
20
+
21
+ ### US-002
22
+ - Title: Playwright 기반 구조화 검증 스크립트
23
+ - Priority: 2
24
+ - Description: HTML 슬라이드 생성 후 Playwright로 렌더링하여 overflow, 텍스트 잘림, 요소 겹침 등 구조적 문제를 프로그래밍적으로 자동 탐지하는 검증 스크립트를 만든다. VLM 호출 없이 비용 0으로 기본 품질을 보장한다.
25
+ - Acceptance Criteria:
26
+ - REQ-006 `scripts/validate-slides.js`가 존재하고, `node scripts/validate-slides.js` 명령으로 실행 가능하다
27
+ - REQ-007 슬라이드 프레임(720pt × 405pt) 밖으로 넘치는 요소를 탐지한다 (boundingBox 검사)
28
+ - REQ-008 `scrollHeight > clientHeight`인 텍스트 요소(텍스트 잘림)를 탐지한다
29
+ - REQ-009 같은 레벨 요소들의 boundingBox 교차(겹침)를 탐지한다
30
+ - REQ-010 결과를 JSON 형식으로 출력한다 (slide별 status: pass/fail, critical 이슈 목록, warning 목록, summary)
31
+ - REQ-011 `slides/` 디렉토리의 모든 `slide-*.html` 파일을 자동으로 검증한다
32
+
33
+ ### US-003
34
+ - Title: VLM Provider 표준 인터페이스 (Vercel AI SDK)
35
+ - Priority: 3
36
+ - Description: Vercel AI SDK를 사용하여 VLM(Vision Language Model)에 이미지를 보내고 분석 결과를 받는 통합 인터페이스를 구현한다. Gemini, Claude, OpenAI 프로바이더를 교체 가능하게 지원한다. JavaScript로 작성한다.
37
+ - Acceptance Criteria:
38
+ - REQ-012 `ai`, `@ai-sdk/google`, `@ai-sdk/anthropic` 패키지가 package.json dependencies에 추가된다
39
+ - REQ-013 `src/vlm/analyze.js`에 `analyzeImage(imagePath, prompt, config)` 함수가 존재하고 export된다
40
+ - REQ-014 `src/vlm/analyze.js`에 `analyzeImages(imagePaths, prompt, config)` 함수가 존재하고 export된다 (여러 이미지 동시 분석)
41
+ - REQ-015 config 객체로 `{ provider: "google"|"anthropic"|"openai", model: "모델명", maxTokens, temperature }`를 받는다
42
+ - REQ-016 환경 변수 `GEMINI_API_KEY` 또는 `ANTHROPIC_API_KEY`로 API 키를 설정할 수 있다
43
+ - REQ-017 반환값은 `{ content: string, usage: { inputTokens, outputTokens } }` 형태이다
44
+
45
+ ### US-004
46
+ - Title: 차트/다이어그램/이미지 HTML 라이브러리 지원
47
+ - Priority: 4
48
+ - Description: design-skill이 Chart.js(차트), Mermaid(다이어그램), 인라인 SVG(아이콘), 이미지를 활용할 수 있도록 CDN 링크, 사용법 가이드, 예시 템플릿을 추가한다. html2pptx.js에서 JS 라이브러리 렌더링 대기 로직도 추가한다.
49
+ - Acceptance Criteria:
50
+ - REQ-018 design-skill/SKILL.md에 Chart.js CDN 링크와 사용 예시(bar, line, pie 차트)가 포함된다
51
+ - REQ-019 design-skill/SKILL.md에 Mermaid CDN 링크와 사용 예시(flowchart, sequence diagram)가 포함된다
52
+ - REQ-020 design-skill/SKILL.md에 인라인 SVG 아이콘 작성 가이드가 포함된다
53
+ - REQ-021 design-skill/SKILL.md에 이미지 사용 규칙(로컬 경로, URL, 플레이스홀더)이 포함된다
54
+ - REQ-022 `templates/chart.html` 예시 템플릿이 존재한다 (Chart.js 차트가 포함된 슬라이드)
55
+ - REQ-023 `templates/diagram.html` 예시 템플릿이 존재한다 (Mermaid 다이어그램이 포함된 슬라이드)
56
+ - REQ-024 html2pptx.js(또는 관련 변환 스크립트)에서 Chart.js/Mermaid 렌더링 완료를 대기하는 로직이 있다
57
+
58
+ ### US-005
59
+ - Title: VLM 기반 슬라이드 자동 포맷 검증
60
+ - Priority: 5
61
+ - Description: VLM Provider 인터페이스(US-003)를 사용하여 슬라이드 스크린샷을 VLM에 보내고, 시각적 포맷 문제(overflow, 단어 잘림, 겹침, 가독성)를 탐지하는 검증 스크립트를 만든다. 사용자가 명시적으로 요청할 때만 실행되며, 최대 반복 횟수를 설정할 수 있다. 사용자는 뷰어에서 직접 VLM을 통해 수정을 요구할 수 있다.
62
+ - Acceptance Criteria:
63
+ - REQ-025 `scripts/vlm-validate.js`가 존재하고 실행 가능하다
64
+ - REQ-026 각 슬라이드를 Playwright로 스크린샷(1600×900px)하여 VLM에 전송한다
65
+ - REQ-027 VLM 피드백을 구조화된 JSON으로 파싱한다 (slide, issues 배열, pass/fail)
66
+ - REQ-028 `--max-iterations` 옵션으로 최대 반복 횟수를 설정할 수 있다 (기본값 3)
67
+ - REQ-029 `--provider`와 `--model` 옵션으로 VLM 프로바이더와 모델을 지정할 수 있다 (기본값 google/gemini-2.0-flash)
68
+ - REQ-030 US-003의 `analyzeImage()` 함수를 사용한다
69
+
70
+ ### US-006
71
+ - Title: PDF 출력 지원
72
+ - Priority: 6
73
+ - Description: HTML 슬라이드를 PDF로 변환하는 스크립트를 만든다. Playwright의 page.pdf()를 사용하여 각 슬라이드를 PDF로 렌더링하고, pdf-lib로 하나의 PDF로 병합한다.
74
+ - Acceptance Criteria:
75
+ - REQ-031 `pdf-lib` 패키지가 package.json dependencies에 추가된다
76
+ - REQ-032 `scripts/html2pdf.js`가 존재하고 `node scripts/html2pdf.js` 명령으로 실행 가능하다
77
+ - REQ-033 slides/ 디렉토리의 모든 slide-*.html을 순서대로 PDF로 변환한다
78
+ - REQ-034 `printBackground: true` 옵션으로 배경색이 보존된다 (다크 테마에서 필수)
79
+ - REQ-035 개별 슬라이드 PDF를 하나의 파일로 병합하여 최종 PDF를 출력한다
80
+ - REQ-036 `--output` 옵션으로 출력 파일 경로를 지정할 수 있다
81
+
82
+ ### US-007
83
+ - Title: VLM 기반 사용자 스타일 추출
84
+ - Priority: 7
85
+ - Description: 사용자가 제공한 PPTX 또는 PDF 파일에서 슬라이드를 스크린샷하고, VLM으로 디자인 시스템(컬러, 폰트, 레이아웃, 톤)을 분석하여 style-config.md로 출력한다. 긴 프레젠테이션은 랜덤 샘플링으로 비용을 최적화한다.
86
+ - Acceptance Criteria:
87
+ - REQ-037 `scripts/extract-style.js`가 존재하고 실행 가능하다
88
+ - REQ-038 PPTX 파일을 입력받아 슬라이드별 스크린샷을 생성할 수 있다 (LibreOffice 또는 Playwright 활용)
89
+ - REQ-039 PDF 파일을 입력받아 페이지별 스크린샷을 생성할 수 있다 (Poppler pdftoppm 활용)
90
+ - REQ-040 슬라이드가 10장 이상이면 랜덤 샘플링(5~8장)을 수행한다. 첫 번째(표지)와 마지막(마무리) 슬라이드는 항상 포함한다
91
+ - REQ-041 US-003의 `analyzeImages()` 함수를 사용하여 VLM에 분석을 요청한다
92
+ - REQ-042 결과를 `style-config.md`로 출력한다 (컬러 팔레트, 폰트 시스템, 레이아웃 패턴, 슬라이드 타입, 전체 톤 포함)
93
+
94
+ ### US-008
95
+ - Title: 프로젝트 패키징 기반 구조
96
+ - Priority: 8
97
+ - Description: slides-grab를 npm 패키지로 배포하기 위한 기반 구조를 구축한다. SETUP.md 작성, README.md 업데이트, CLI 기본 뼈대, agentskills.io 표준 SKILL.md frontmatter 적용. npm publish 자체는 이번 범위에 포함하지 않는다.
98
+ - Acceptance Criteria:
99
+ - REQ-043 `SETUP.md`가 존재하고, macOS(brew), Ubuntu(apt), Windows(winget) 별 원라이너 설치 명령이 포함된다
100
+ - REQ-044 `README.md`에 SETUP.md 내용이 포함되어 사용자가 복붙으로 설치할 수 있다
101
+ - REQ-045 `bin/slides-grab.js`에 CLI 기본 뼈대가 존재한다 (commander 패키지 사용, `slides-grab --help` 출력 가능)
102
+ - REQ-046 CLI에 `build-viewer`, `validate`, `convert` 서브커맨드가 정의된다 (각 스크립트를 호출하는 래퍼)
103
+ - REQ-047 package.json에 `"bin": { "slides-grab": "./bin/slides-grab.js" }`가 설정된다
104
+ - REQ-048 모든 SKILL.md 파일에 agentskills.io 표준 frontmatter(name, description)가 포함된다