slides-grab 1.1.3 → 1.1.5

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
@@ -31,16 +31,16 @@ Paste one of these into your coding agent:
31
31
  **Claude Code:**
32
32
 
33
33
  ```
34
- Read https://raw.githubusercontent.com/vkehfdl1/slides-grab/main/docs/prompts/setup-claude.md and follow every step.
34
+ Read https://raw.githubusercontent.com/vkehfdl1/slides-grab/main/docs/installation/claude.md and follow every step.
35
35
  ```
36
36
 
37
37
  **Codex:**
38
38
 
39
39
  ```
40
- Read https://raw.githubusercontent.com/vkehfdl1/slides-grab/main/docs/prompts/setup-codex.md and follow every step.
40
+ Read https://raw.githubusercontent.com/vkehfdl1/slides-grab/main/docs/installation/codex.md and follow every step.
41
41
  ```
42
42
 
43
- Or clone manually:
43
+ Or use the repo directly if you want to develop on slides-grab itself:
44
44
 
45
45
  ```bash
46
46
  git clone https://github.com/vkehfdl1/slides-grab.git && cd slides-grab
@@ -49,6 +49,14 @@ npm ci && npx playwright install chromium
49
49
 
50
50
  > Requires **Node.js >= 18**.
51
51
 
52
+ ### No-clone install
53
+
54
+ ```bash
55
+ npm install slides-grab
56
+ npx playwright install chromium
57
+ npx skills add ./node_modules/slides-grab -g -a codex -a claude-code --yes --copy
58
+ ```
59
+
52
60
  ## Why This Project?
53
61
 
54
62
  There are many AI tools that generate slide HTML. Almost none let you **visually point at what you want changed** and iterate in-place. slides-grab fills that gap:
@@ -118,19 +126,25 @@ This command reuses the HTML to PPTX pipeline and emits a `.pptx` deck intended
118
126
 
119
127
  ## Installation Guides
120
128
 
121
- - [Claude Code setup](docs/prompts/setup-claude.md)
122
- - [Codex setup](docs/prompts/setup-codex.md)
123
129
  - [Claude detailed guide](docs/installation/claude.md)
124
130
  - [Codex detailed guide](docs/installation/codex.md)
125
131
 
126
132
  ## npm Package
127
133
 
128
- Also available as an npm package for standalone CLI usage:
134
+ Also available as an npm package for standalone CLI + skill usage:
129
135
 
130
136
  ```bash
131
137
  npm install slides-grab
132
138
  ```
133
139
 
140
+ Install shared agent skills with Vercel Agent Skills:
141
+
142
+ ```bash
143
+ npx skills add ./node_modules/slides-grab -g -a codex -a claude-code --yes --copy
144
+ ```
145
+
146
+ This npm-install path is enough for normal usage. Clone the repo only when you want to modify or contribute to `slides-grab` itself.
147
+
134
148
  ## Project Structure
135
149
 
136
150
  ```
@@ -139,8 +153,7 @@ src/editor/ Visual editor (HTML + JS client modules)
139
153
  scripts/ Build, validate, convert, editor server
140
154
  templates/ Slide HTML templates (cover, content, chart, ...)
141
155
  themes/ Color themes (modern-dark, executive, sage, ...)
142
- .claude/skills/ Claude Code skill definitions
143
- skills/ Codex skill definitions
156
+ skills/ Shared Vercel-installable agent skills + references
144
157
  docs/ Installation & usage guides
145
158
  ```
146
159
 
package/bin/ppt-agent.js CHANGED
@@ -167,18 +167,6 @@ program
167
167
  await runCommand('scripts/editor-server.js', args);
168
168
  });
169
169
 
170
- program
171
- .command('install-codex-skills')
172
- .description('Install project Codex skills into $CODEX_HOME/skills (default: ~/.codex/skills)')
173
- .option('--force', 'Overwrite existing skill directories')
174
- .option('--dry-run', 'Preview what would be installed')
175
- .action(async (options = {}) => {
176
- const args = [];
177
- if (options.force) args.push('--force');
178
- if (options.dryRun) args.push('--dry-run');
179
- await runCommand('scripts/install-codex-skills.js', args);
180
- });
181
-
182
170
  // --- Template/theme discovery commands ---
183
171
 
184
172
  program
package/convert.cjs CHANGED
@@ -1,239 +1,12 @@
1
- const PptxGenJS = require('pptxgenjs');
2
- const { chromium } = require('playwright');
3
- const path = require('path');
4
- const fs = require('fs');
5
- const sharp = require('sharp');
6
1
  const {
7
- getResolutionChoices,
8
- getResolutionSize,
9
- normalizeResolutionPreset,
10
- } = require('./src/export-resolution.cjs');
11
-
12
- // Inline a simplified version that uses Playwright Chromium (not Chrome)
13
- const DEFAULT_SLIDES_DIR = 'slides';
14
- const DEFAULT_OUTPUT = 'output.pptx';
15
- const DEFAULT_RESOLUTION = '2160p';
16
- const DEFAULT_CAPTURE_VIEWPORT = { width: 960, height: 540 };
17
- const DEFAULT_CAPTURE_DEVICE_SCALE_FACTOR = 2;
18
- const TARGET_RASTER_DPI = 150;
19
- const TARGET_SLIDE_SIZE_IN = { width: 13.33, height: 7.5 };
20
-
21
- function normalizeDimension(value, fallback) {
22
- if (!Number.isFinite(value) || value <= 0) {
23
- return fallback;
24
- }
25
- return Math.max(1, Math.round(value));
26
- }
27
-
28
- function buildPageOptions(resolution = '') {
29
- const targetResolution = getResolutionSize(resolution);
30
- return {
31
- viewport: {
32
- width: DEFAULT_CAPTURE_VIEWPORT.width,
33
- height: DEFAULT_CAPTURE_VIEWPORT.height,
34
- },
35
- deviceScaleFactor: targetResolution
36
- ? targetResolution.height / DEFAULT_CAPTURE_VIEWPORT.height
37
- : DEFAULT_CAPTURE_DEVICE_SCALE_FACTOR,
38
- };
39
- }
40
-
41
- function getTargetRasterSize(resolution = '') {
42
- const targetResolution = getResolutionSize(resolution);
43
- if (targetResolution) {
44
- return targetResolution;
45
- }
46
-
47
- return {
48
- width: Math.round(TARGET_SLIDE_SIZE_IN.width * TARGET_RASTER_DPI),
49
- height: Math.round(TARGET_SLIDE_SIZE_IN.height * TARGET_RASTER_DPI),
50
- };
51
- }
52
-
53
- function printUsage() {
54
- process.stdout.write(
55
- [
56
- 'Usage: node convert.cjs [options]',
57
- '',
58
- 'Options:',
59
- ` --slides-dir <path> Slide directory (default: ${DEFAULT_SLIDES_DIR})`,
60
- ` --output <path> Output pptx path (default: ${DEFAULT_OUTPUT})`,
61
- ` --resolution <preset> Raster size preset: ${getResolutionChoices().join('|')}|4k (default: ${DEFAULT_RESOLUTION})`,
62
- ' -h, --help Show this help message',
63
- ].join('\n'),
64
- );
65
- process.stdout.write('\n');
66
- }
67
-
68
- function readOptionValue(args, index, optionName) {
69
- const next = args[index + 1];
70
- if (!next || next.startsWith('-')) {
71
- throw new Error(`Missing value for ${optionName}.`);
72
- }
73
- return next;
74
- }
75
-
76
- function parseArgs(args) {
77
- const options = {
78
- slidesDir: DEFAULT_SLIDES_DIR,
79
- output: DEFAULT_OUTPUT,
80
- resolution: DEFAULT_RESOLUTION,
81
- help: false,
82
- };
83
-
84
- for (let i = 0; i < args.length; i += 1) {
85
- const arg = args[i];
86
- if (arg === '-h' || arg === '--help') {
87
- options.help = true;
88
- continue;
89
- }
90
-
91
- if (arg === '--slides-dir') {
92
- options.slidesDir = readOptionValue(args, i, '--slides-dir');
93
- i += 1;
94
- continue;
95
- }
96
-
97
- if (arg.startsWith('--slides-dir=')) {
98
- options.slidesDir = arg.slice('--slides-dir='.length);
99
- continue;
100
- }
101
-
102
- if (arg === '--output') {
103
- options.output = readOptionValue(args, i, '--output');
104
- i += 1;
105
- continue;
106
- }
107
-
108
- if (arg.startsWith('--output=')) {
109
- options.output = arg.slice('--output='.length);
110
- continue;
111
- }
112
-
113
- if (arg === '--resolution') {
114
- options.resolution = normalizeResolutionPreset(readOptionValue(args, i, '--resolution'));
115
- i += 1;
116
- continue;
117
- }
118
-
119
- if (arg.startsWith('--resolution=')) {
120
- options.resolution = normalizeResolutionPreset(arg.slice('--resolution='.length));
121
- continue;
122
- }
123
-
124
- throw new Error(`Unknown option: ${arg}`);
125
- }
126
-
127
- if (typeof options.slidesDir !== 'string' || options.slidesDir.trim() === '') {
128
- throw new Error('--slides-dir must be a non-empty string.');
129
- }
130
-
131
- if (typeof options.output !== 'string' || options.output.trim() === '') {
132
- throw new Error('--output must be a non-empty string.');
133
- }
134
-
135
- options.slidesDir = options.slidesDir.trim();
136
- options.output = options.output.trim();
137
- options.resolution = normalizeResolutionPreset(options.resolution);
138
- return options;
139
- }
140
-
141
- async function convertSlide(htmlFile, pres, browser, options = {}) {
142
- const filePath = path.isAbsolute(htmlFile) ? htmlFile : path.join(process.cwd(), htmlFile);
143
-
144
- const page = await browser.newPage(buildPageOptions(options.resolution));
145
- await page.goto(`file://${filePath}`);
146
-
147
- const bodyDimensions = await page.evaluate(() => {
148
- const body = document.body;
149
- const style = window.getComputedStyle(body);
150
- return {
151
- width: parseFloat(style.width),
152
- height: parseFloat(style.height),
153
- };
154
- });
155
-
156
- await page.setViewportSize({
157
- width: normalizeDimension(bodyDimensions.width, DEFAULT_CAPTURE_VIEWPORT.width),
158
- height: normalizeDimension(bodyDimensions.height, DEFAULT_CAPTURE_VIEWPORT.height)
159
- });
160
-
161
- // Take screenshot and add as full-slide image
162
- const screenshot = await page.screenshot({ type: 'png' });
163
- await page.close();
164
-
165
- // Resize to exact slide dimensions (13.33" x 7.5" at 150 DPI)
166
- const targetSize = getTargetRasterSize(options.resolution);
167
-
168
- const resized = await sharp(screenshot)
169
- .resize(targetSize.width, targetSize.height, { fit: 'fill' })
170
- .png()
171
- .toBuffer();
172
-
173
- const tmpPath = path.join(process.env.TMPDIR || '/tmp', `slide-${Date.now()}-${Math.random().toString(36).slice(2)}.png`);
174
- fs.writeFileSync(tmpPath, resized);
175
-
176
- const slide = pres.addSlide();
177
- slide.addImage({
178
- path: tmpPath,
179
- x: 0,
180
- y: 0,
181
- w: '100%',
182
- h: '100%'
183
- });
184
-
185
- return tmpPath;
186
- }
187
-
188
- async function main() {
189
- const options = parseArgs(process.argv.slice(2));
190
- if (options.help) {
191
- printUsage();
192
- return;
193
- }
194
-
195
- const pres = new PptxGenJS();
196
- pres.layout = 'LAYOUT_WIDE'; // 16:9
197
-
198
- const slidesDir = path.resolve(process.cwd(), options.slidesDir);
199
- const { ensureSlidesPassValidation } = await import('./scripts/validate-slides.js');
200
- await ensureSlidesPassValidation(slidesDir, { exportLabel: 'PPTX export' });
201
- const files = fs.readdirSync(slidesDir)
202
- .filter(f => f.endsWith('.html'))
203
- .sort();
204
-
205
- console.log(`Converting ${files.length} slides...`);
206
-
207
- // Launch Chromium (not Chrome)
208
- const browser = await chromium.launch();
209
- const tmpFiles = [];
210
-
211
- for (const file of files) {
212
- const filePath = path.join(slidesDir, file);
213
- console.log(` Processing: ${file}`);
214
- try {
215
- const tmpPath = await convertSlide(filePath, pres, browser, { resolution: options.resolution });
216
- tmpFiles.push(tmpPath);
217
- console.log(` ✓ ${file} done`);
218
- } catch (err) {
219
- console.error(` ✗ ${file} error: ${err.message}`);
220
- }
221
- }
222
-
223
- await browser.close();
224
-
225
- const outputFile = path.resolve(process.cwd(), options.output);
226
- await pres.writeFile({ fileName: outputFile });
227
- console.log(`\nSaved: ${outputFile}`);
228
-
229
- // Cleanup tmp files
230
- for (const f of tmpFiles) {
231
- try { fs.unlinkSync(f); } catch {}
232
- }
233
- }
2
+ buildPageOptions,
3
+ getTargetRasterSize,
4
+ main,
5
+ parseArgs,
6
+ } = require('./src/pptx-raster-export.cjs');
234
7
 
235
8
  if (require.main === module) {
236
- main().catch(err => {
9
+ main().catch((err) => {
237
10
  console.error('Fatal error:', err);
238
11
  process.exit(1);
239
12
  });
@@ -242,5 +15,6 @@ if (require.main === module) {
242
15
  module.exports = {
243
16
  buildPageOptions,
244
17
  getTargetRasterSize,
18
+ main,
245
19
  parseArgs,
246
20
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "slides-grab",
3
- "version": "1.1.3",
3
+ "version": "1.1.5",
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,7 +38,6 @@
38
38
  "scripts/figma-export.js",
39
39
  "scripts/html2pdf.js",
40
40
  "scripts/html2pptx.js",
41
- "scripts/install-codex-skills.js",
42
41
  "scripts/validate-slides.js",
43
42
  "skills/",
44
43
  "src/",
@@ -52,8 +51,7 @@
52
51
  "build-viewer": "node scripts/build-viewer.js",
53
52
  "validate": "node scripts/validate-slides.js",
54
53
  "convert": "node convert.cjs",
55
- "codex:install-skills": "node scripts/install-codex-skills.js --force",
56
- "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",
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",
57
55
  "test:e2e": "node --test tests/editor/editor-ui.e2e.test.js tests/editor/editor-concurrency.e2e.test.js"
58
56
  },
59
57
  "dependencies": {
@@ -403,7 +403,6 @@ export async function normalizeBodyToSlideFrame(page, slideFrame) {
403
403
  const documentElement = document.documentElement;
404
404
 
405
405
  body.style.margin = '0';
406
- body.style.padding = '0';
407
406
  body.style.width = `${width}px`;
408
407
  body.style.height = `${height}px`;
409
408
  body.style.minWidth = `${width}px`;
@@ -15,7 +15,7 @@ Guides you through the complete presentation pipeline from topic to exported fil
15
15
 
16
16
  ### Stage 1 — Plan
17
17
 
18
- Use **slides-grab-plan** (`skills/slides-grab-plan/SKILL.md`).
18
+ Use the installed **slides-grab-plan** skill.
19
19
 
20
20
  1. Take user's topic, audience, and tone.
21
21
  2. Create `slide-outline.md`.
@@ -26,13 +26,13 @@ Use **slides-grab-plan** (`skills/slides-grab-plan/SKILL.md`).
26
26
 
27
27
  ### Stage 2 — Design
28
28
 
29
- Use **slides-grab-design** (`skills/slides-grab-design/SKILL.md`).
29
+ Use the installed **slides-grab-design** skill.
30
30
 
31
31
  1. Read approved `slide-outline.md`.
32
32
  2. Generate `slide-*.html` files in the slides workspace (default: `slides/`).
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
- 5. Build the viewer: `node scripts/build-viewer.js --slides-dir <path>`
35
+ 5. Build the viewer: `slides-grab build-viewer --slides-dir <path>`
36
36
  6. Present viewer to user for review.
37
37
  7. Revise individual slides based on feedback, then re-run validation and rebuild the viewer.
38
38
  8. Optionally launch the visual editor: `slides-grab edit --slides-dir <path>`
@@ -41,7 +41,7 @@ Use **slides-grab-design** (`skills/slides-grab-design/SKILL.md`).
41
41
 
42
42
  ### Stage 3 — Export
43
43
 
44
- Use **slides-grab-export** (`skills/slides-grab-export/SKILL.md`).
44
+ Use the installed **slides-grab-export** skill.
45
45
 
46
46
  1. Confirm user wants conversion.
47
47
  2. Export to PPTX: `slides-grab convert --slides-dir <path> --output <name>.pptx` (**experimental / unstable**)
@@ -57,4 +57,7 @@ Use **slides-grab-export** (`skills/slides-grab-export/SKILL.md`).
57
57
  3. **Read each stage's SKILL.md** for detailed rules — this skill only orchestrates.
58
58
  4. **Use `decks/<deck-name>/`** as the slides workspace for multi-deck projects.
59
59
  5. **Call out export risk clearly**: PPTX and Figma export are experimental / unstable and must be described as best-effort output.
60
- 6. For full design constraints, refer to `.claude/skills/design-skill/SKILL.md`.
60
+ 6. Use the stage skills as the source of truth for plan, design, and export rules.
61
+
62
+ ## Reference
63
+ - `references/presentation-workflow-reference.md` — archived end-to-end workflow guidance from the legacy skill set
@@ -0,0 +1,52 @@
1
+ # Presentation Skill - Full Workflow Orchestrator
2
+
3
+ Guides you through the complete presentation pipeline from topic to exported file.
4
+
5
+ ---
6
+
7
+ ## Workflow
8
+
9
+ ### Stage 1 — Plan
10
+
11
+ Use **plan-skill** (`.claude/skills/plan-skill/SKILL.md`).
12
+
13
+ 1. Take user's topic, audience, and tone.
14
+ 2. Delegate outline creation to `organizer-agent`.
15
+ 3. Present `slide-outline.md` to user.
16
+ 4. Revise until user explicitly approves.
17
+
18
+ **Do not proceed to Stage 2 without approval.**
19
+
20
+ ### Stage 2 — Design
21
+
22
+ Use **design-skill** (`.claude/skills/design-skill/SKILL.md`).
23
+
24
+ 1. Read approved `slide-outline.md`.
25
+ 2. Generate `slide-*.html` files in the slides workspace (default: `slides/`).
26
+ 3. Run validation: `slides-grab validate --slides-dir <path>`
27
+ 4. If validation fails, automatically fix the slide HTML/CSS until validation passes.
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>`
32
+
33
+ **Do not proceed to Stage 3 without approval.**
34
+
35
+ ### Stage 3 — Export
36
+
37
+ Use **pptx-skill** (`.claude/skills/pptx-skill/SKILL.md`).
38
+
39
+ 1. Confirm user wants conversion.
40
+ 2. Export to PPTX: `slides-grab convert --slides-dir <path> --output <name>.pptx` (**experimental / unstable**)
41
+ 3. Export to PDF (if requested): `slides-grab pdf --slides-dir <path> --output <name>.pdf`
42
+ 4. Report results.
43
+
44
+ ---
45
+
46
+ ## Rules
47
+
48
+ 1. **Always follow the stage order**: Plan → Design → Export.
49
+ 2. **Get explicit user approval** before advancing to the next stage.
50
+ 3. **Read each stage's SKILL.md** for detailed rules — this skill only orchestrates.
51
+ 4. **Use `decks/<deck-name>/`** as the slides workspace for multi-deck projects.
52
+ 5. **Call out export risk clearly**: PPTX and Figma export are experimental / unstable and should be described as best-effort output.
@@ -26,7 +26,7 @@ Generate high-quality `slide-XX.html` files in the selected slides workspace (`s
26
26
  2. Generate slide HTML files with 2-digit numbering in selected `--slides-dir`.
27
27
  3. Run `slides-grab validate --slides-dir <path>` after generation or edits.
28
28
  4. If validation fails, automatically fix the source slide HTML/CSS and re-run validation until it passes.
29
- 5. Run `node scripts/build-viewer.js --slides-dir <path>` only after validation passes.
29
+ 5. Run `slides-grab build-viewer --slides-dir <path>` only after validation passes.
30
30
  6. Iterate on user feedback by editing only requested slide files, then re-run validation and rebuild the viewer.
31
31
  7. Keep revising until user approves conversion stage.
32
32
 
@@ -39,7 +39,10 @@ Generate high-quality `slide-XX.html` files in the selected slides workspace (`s
39
39
  - Prefer `<img>` for slide imagery and `data-image-placeholder` when no final asset exists.
40
40
  - Do not present slides for review until `slides-grab validate --slides-dir <path>` passes.
41
41
  - Do not start conversion before approval.
42
+ - Use the packaged CLI and bundled references only; do not depend on unpublished agent-specific files.
42
43
 
43
44
  ## Reference
44
45
  For full constraints and style system, follow:
45
- - `.claude/skills/design-skill/SKILL.md`
46
+ - `references/design-rules.md`
47
+ - `references/detailed-design-rules.md`
48
+ - `references/design-system-full.md` — archived full design system, templates, and advanced pattern guidance
@@ -0,0 +1,49 @@
1
+ # slides-grab Design Reference
2
+
3
+ These are the packaged design rules for installable `slides-grab` skills.
4
+
5
+ ## Package-first commands
6
+ - Validate slides: `slides-grab validate --slides-dir <path>`
7
+ - Build review viewer: `slides-grab build-viewer --slides-dir <path>`
8
+ - Launch editor: `slides-grab edit --slides-dir <path>`
9
+
10
+ ## Slide spec
11
+ - Slide size: `720pt x 405pt` (16:9)
12
+ - Font: Pretendard
13
+ - Semantic text tags only: `p`, `h1-h6`, `ul`, `ol`, `li`
14
+ - CSS colors must include `#`
15
+ - Avoid CSS gradients for PPTX-targeted decks
16
+
17
+ ## Asset rules
18
+ - Store deck-local assets in `<slides-dir>/assets/`
19
+ - Reference deck-local assets as `./assets/<file>`
20
+ - Allow `data:` URLs only when the slide must be fully self-contained
21
+ - Never use absolute filesystem paths
22
+
23
+ ## Package-published theme references
24
+ - `themes/executive.css`
25
+ - `themes/sage.css`
26
+ - `themes/modern-dark.css`
27
+ - `themes/corporate.css`
28
+ - `themes/warm.css`
29
+
30
+ ## Package-published template references
31
+ - `templates/cover.html`
32
+ - `templates/contents.html`
33
+ - `templates/section-divider.html`
34
+ - `templates/content.html`
35
+ - `templates/statistics.html`
36
+ - `templates/split-layout.html`
37
+ - `templates/team.html`
38
+ - `templates/quote.html`
39
+ - `templates/timeline.html`
40
+ - `templates/closing.html`
41
+ - `templates/chart.html`
42
+ - `templates/diagram.html`
43
+ - `templates/custom/`
44
+
45
+ ## Review loop
46
+ - Generate or edit only the needed slide files.
47
+ - Re-run validation after every generation/edit pass.
48
+ - Rebuild the viewer only after validation passes.
49
+ - Do not move to export until the user approves the reviewed deck.