@iamdangavin/claude-skill-vitepress-docs 3.0.1 → 3.1.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.
@@ -0,0 +1,158 @@
1
+ ---
2
+ name: vitedocs:brand
3
+ description: Configure colors, fonts, logo, and favicon for VitePress docs.
4
+ allowed-tools:
5
+ - Read
6
+ - Write
7
+ - Edit
8
+ - Bash
9
+ - Glob
10
+ - Grep
11
+ - AskUserQuestion
12
+ ---
13
+
14
+ ## Mode: brand
15
+
16
+ ### Step 1 — Locate docs paths
17
+
18
+ Check the manifest(s) to find all configured docs folders. If no manifest exists, scan for `.vitepress/config.mjs` files across the known focus paths. Present what was found so the user can confirm before proceeding.
19
+
20
+ ### Step 2 — Shared or per-path branding
21
+
22
+ If more than one docs path is found, ask:
23
+
24
+ - header: "Branding scope"
25
+ - question: "How should branding be applied across your docs?"
26
+ - options:
27
+ - "Same brand across all docs"
28
+ - "Different brand per path — I'll configure each one separately"
29
+
30
+ If per-path: complete all brand questions for path 1 before moving to path 2 — never ask about two paths simultaneously.
31
+
32
+ ### Step 3 — Brand questions
33
+
34
+ Ask these once (shared) or once per path (per-path). Always label the header with the path name when in per-path mode so the user knows which repo they're configuring.
35
+
36
+ **B-Q1 — Primary brand color** (plain text): Ask — "What is the primary brand color? (hex, e.g. `#E63946`). This becomes the link, button, and accent color throughout the docs."
37
+
38
+ From this single hex value, derive the full VitePress brand palette automatically:
39
+ - `--vp-c-brand-1`: the base hex
40
+ - `--vp-c-brand-2`: 15% lighter
41
+ - `--vp-c-brand-3`: 30% lighter
42
+ - `--vp-c-brand-soft`: the hex at 12% opacity (for backgrounds)
43
+
44
+ Also derive dark mode variants — slightly brighter versions of each to account for dark backgrounds. Present the derived palette to the user before writing anything.
45
+
46
+ **B-Q2 — Logo:**
47
+ - header: "Logo"
48
+ - question: "Do you have a logo to use in the docs nav?"
49
+ - options:
50
+ - "Yes — I'll provide the path to the file"
51
+ - "Text only — use the site title"
52
+ - "Skip for now"
53
+
54
+ If yes: ask as plain text — "What is the path to the logo file? (SVG or PNG recommended, e.g. `public/logo.svg`)"
55
+
56
+ **B-Q3 — Favicon:**
57
+ - header: "Favicon"
58
+ - question: "Do you have a favicon?"
59
+ - options:
60
+ - "Yes — I'll provide the path"
61
+ - "Use the logo as favicon"
62
+ - "Skip for now"
63
+
64
+ If yes: ask as plain text — "Path to favicon? (e.g. `public/favicon.ico` or `public/favicon.svg`)"
65
+
66
+ **B-Q4 — Font:**
67
+ - header: "Font"
68
+ - question: "What font should the docs use?"
69
+ - options:
70
+ - "VitePress default (Inter)"
71
+ - "System font stack (no external load)"
72
+ - "Google Font — I'll tell you which"
73
+ - "Custom — I'll provide the CSS import"
74
+
75
+ If Google Font: ask as plain text — "Which Google Font family? (e.g. `Outfit`, `DM Sans`)"
76
+ If custom: ask as plain text — "Paste your @import or @font-face CSS."
77
+
78
+ **B-Q5 — Dark mode:**
79
+ - header: "Dark mode"
80
+ - question: "How should dark mode colors work?"
81
+ - options:
82
+ - "Auto-derive from brand color (recommended)"
83
+ - "I want to set a custom dark mode accent color"
84
+ - "Use VitePress default dark mode"
85
+
86
+ If custom: ask as plain text — "What hex color for dark mode accent?"
87
+
88
+ ### Step 4 — Preview palette
89
+
90
+ Before writing any files, present the full derived palette as a table:
91
+
92
+ ```
93
+ Light mode
94
+ --vp-c-brand-1: #E63946
95
+ --vp-c-brand-2: #EB5E6A
96
+ --vp-c-brand-3: #F28B93
97
+ --vp-c-brand-soft: #E6394620
98
+
99
+ Dark mode
100
+ --vp-c-brand-1: #F05A64
101
+ --vp-c-brand-2: #F47980
102
+ --vp-c-brand-3: #F7A0A5
103
+ --vp-c-brand-soft: #F05A6420
104
+ ```
105
+
106
+ Then ask:
107
+
108
+ - header: "Palette"
109
+ - question: "Does this palette look right?"
110
+ - options:
111
+ - "Yes — apply it"
112
+ - "Adjust the base color — I'll give you a new hex"
113
+ - "Manually tweak individual values"
114
+
115
+ If adjust: take the new hex and re-derive. If manual: ask as plain text for each value to change.
116
+
117
+ ### Step 5 — Write brand files
118
+
119
+ For each docs path being branded:
120
+
121
+ **`.vitepress/theme/index.css`** — append the brand variables block. Do not remove existing entries — only add or update the brand vars:
122
+
123
+ ```css
124
+ :root {
125
+ --vp-c-brand-1: HEX1;
126
+ --vp-c-brand-2: HEX2;
127
+ --vp-c-brand-3: HEX3;
128
+ --vp-c-brand-soft: HEXSOFT;
129
+ /* FONT_VARS if custom font selected */
130
+ }
131
+
132
+ .dark {
133
+ --vp-c-brand-1: DARK_HEX1;
134
+ --vp-c-brand-2: DARK_HEX2;
135
+ --vp-c-brand-3: DARK_HEX3;
136
+ --vp-c-brand-soft: DARK_HEXSOFT;
137
+ }
138
+ ```
139
+
140
+ If a Google Font was selected, add the `@import` at the top of the CSS file and set `--vp-font-family-base`.
141
+
142
+ **`.vitepress/config.mjs`** — add to `themeConfig`:
143
+ - `logo` field if a logo was provided
144
+ - `favicon` via `head` entry if a favicon was provided
145
+
146
+ Read the existing config before editing. Make only targeted additions — do not rewrite unrelated sections.
147
+
148
+ ### Step 6 — Summary
149
+
150
+ ```
151
+ Branded X docs path(s).
152
+
153
+ Files updated:
154
+ PATH/.vitepress/theme/index.css — brand palette + font
155
+ PATH/.vitepress/config.mjs — logo, favicon
156
+
157
+ Run the local dev server to preview: npm run dev
158
+ ```
@@ -0,0 +1,288 @@
1
+ ---
2
+ name: vitedocs:capture
3
+ description: Capture screenshots and record interaction videos for VitePress docs. Uploads videos to GitHub Releases.
4
+ allowed-tools:
5
+ - Read
6
+ - Write
7
+ - Edit
8
+ - Bash
9
+ - Glob
10
+ - Grep
11
+ - AskUserQuestion
12
+ ---
13
+
14
+ # vitedocs:capture
15
+
16
+ This mode reads `.vitepress/docs-manifest.json`. Run `/vitedocs:generate` first if no manifest exists yet.
17
+
18
+ Handles two capture types from the manifest:
19
+ - **screenshot** (`"type": "screenshot"`) — static PNG via Playwright
20
+ - **video** (`"type": "video"`) — recorded interaction with step captions, uploaded to GitHub Releases
21
+
22
+ ---
23
+
24
+ ## Step 1 — Gather capture details
25
+
26
+ **Q1 — Source:**
27
+ - header: "Capture source"
28
+ - question: "Where should I capture from?"
29
+ - options:
30
+ - "Local dev server — I'll capture from a running server"
31
+ - "Deployed URL — give me the base URL"
32
+
33
+ If deployed: ask as plain text — "What is the base URL?"
34
+
35
+ **Q2 — Stack type** (only if local):
36
+ - header: "Project type"
37
+ - question: "What type of project is this?"
38
+ - options:
39
+ - "Node/npm — you can optionally start the server for me"
40
+ - "WordPress, PHP, or other non-Node stack"
41
+ - "Static files"
42
+
43
+ **Q3 — Server status** (only if local Node):
44
+ - header: "Dev server"
45
+ - question: "Is the dev server already running?"
46
+ - options:
47
+ - "Already running"
48
+ - "Not running — please start it for me"
49
+
50
+ If starting: ask as plain text — "What command starts it? And what URL/port does it run on?"
51
+
52
+ **Q4 — Authentication:**
53
+ - header: "Login required?"
54
+ - question: "Does reaching the target screens require login?"
55
+ - options:
56
+ - "No — all target screens are public"
57
+ - "Yes — I'll provide credentials"
58
+
59
+ If yes: ask as plain text — "Please provide the username and password. ⚠️ Credentials are used only to drive the browser in this session — they will NEVER be written to any file, the manifest, or anywhere outside this conversation."
60
+
61
+ **Q5 — Scope:**
62
+ - header: "Capture scope"
63
+ - question: "Which items should I capture?"
64
+ - options:
65
+ - "All placeholders from the manifest (screenshots + videos)"
66
+ - "Screenshots only"
67
+ - "Videos only"
68
+ - "Specific items — I'll tell you which"
69
+
70
+ If specific: ask as plain text — "Which pages or capture names?"
71
+
72
+ **Q6 — GitHub repo** (ask only if manifest contains any video entries in scope):
73
+ - header: "GitHub repo"
74
+ - question: "Videos are uploaded to GitHub Releases. What is the GitHub repo?"
75
+ - options:
76
+ - "Same repo as the docs"
77
+ - "Different repo — I'll type it"
78
+
79
+ If different: ask as plain text — "What is the repo? (full URL or `owner/repo`)"
80
+
81
+ Wait for all answers before proceeding.
82
+
83
+ ---
84
+
85
+ ## Step 2 — Find all pending captures
86
+
87
+ Read `.vitepress/docs-manifest.json`. Filter to:
88
+ - Screenshots where `"placeholder": true`
89
+ - Videos where `"videoUrl": ""`
90
+
91
+ Group by type. If no manifest exists, scan all markdown files for `VideoDemo` and image references in `public/screenshots/` or `public/videos/`.
92
+
93
+ Report what was found:
94
+ ```
95
+ Found 4 pending captures:
96
+ Screenshots (2): timer-main.png, settings-overview.png
97
+ Videos (2): timer-start.webm, form-submit.webm
98
+ ```
99
+
100
+ ---
101
+
102
+ ## Step 3 — Capture screenshots
103
+
104
+ Run ALL screenshots as a single batched heredoc — one bash approval covers the entire set.
105
+
106
+ **⛔ Credential rule — NEVER write credentials to any file.** All scripts run as inline bash heredocs. Credentials are passed directly as inline values within the heredoc and exist only in memory.
107
+
108
+ **For pages requiring auth:** drive a login flow before navigating to target URLs. If no credentials were given, skip auth-gated items and list them in the summary.
109
+
110
+ Batch all screenshots into one heredoc:
111
+
112
+ ```bash
113
+ node --input-type=module << 'SCRIPT'
114
+ import { chromium } from '/opt/homebrew/lib/node_modules/playwright/index.mjs';
115
+ const browser = await chromium.launch({ channel: 'chrome', args: ['--no-sandbox'] });
116
+
117
+ const captures = [
118
+ { url: 'BASE_URL/PATH_1', path: 'OUTPUT_PATH_1', settle: SETTLE_MS },
119
+ { url: 'BASE_URL/PATH_2', path: 'OUTPUT_PATH_2', settle: SETTLE_MS },
120
+ ];
121
+
122
+ for (const cap of captures) {
123
+ const page = await browser.newPage({ viewport: { width: 1440, height: 900 } });
124
+ await page.goto(cap.url, { waitUntil: 'load', timeout: 60000 });
125
+ await page.waitForTimeout(cap.settle);
126
+ await page.screenshot({ path: cap.path, fullPage: false });
127
+ await page.close();
128
+ console.log('Captured', cap.path);
129
+ }
130
+
131
+ await browser.close();
132
+ SCRIPT
133
+ ```
134
+
135
+ Adjust `settle` based on stack: WordPress/non-SPA → `500`, Next.js/SPA → `2000`–`4000`.
136
+
137
+ After the batch completes, display each captured image inline with the Read tool for verification.
138
+
139
+ ---
140
+
141
+ ## Step 4 — Capture videos
142
+
143
+ Capture each video one at a time (each needs its own heredoc due to the unique step sequence).
144
+
145
+ For each video entry, run a heredoc that:
146
+ 1. Records the screen with `recordVideo`
147
+ 2. Executes the steps from the manifest, tracking elapsed time for each
148
+ 3. Captures a poster PNG at the final step
149
+ 4. Moves the video from the temp dir to the final output path
150
+ 5. Generates the `.vtt` caption file (written to disk — goes in git)
151
+ 6. Prints the step timings as JSON
152
+
153
+ ```bash
154
+ node --input-type=module << 'SCRIPT'
155
+ import { chromium } from '/opt/homebrew/lib/node_modules/playwright/index.mjs';
156
+ import { writeFileSync, mkdirSync, readdirSync, renameSync } from 'fs';
157
+ import { dirname } from 'path';
158
+
159
+ const VIDEO_TMP = 'DOCS_FOLDER/public/videos/.tmp';
160
+ const VIDEO_OUT = 'DOCS_FOLDER/public/videos/CAPTURE_NAME.webm';
161
+ const VTT_OUT = 'DOCS_FOLDER/public/videos/CAPTURE_NAME.vtt';
162
+ const POSTER_OUT = 'DOCS_FOLDER/public/screenshots/CAPTURE_NAME-poster.png';
163
+ const BASE_URL = 'BASE_URL';
164
+ const CAPTURE_URL = 'CAPTURE_PATH';
165
+
166
+ mkdirSync(VIDEO_TMP, { recursive: true });
167
+ mkdirSync(dirname(VIDEO_OUT), { recursive: true });
168
+ mkdirSync(dirname(POSTER_OUT), { recursive: true });
169
+
170
+ const browser = await chromium.launch({ channel: 'chrome', args: ['--no-sandbox'] });
171
+ const context = await browser.newContext({
172
+ viewport: { width: 1440, height: 900 },
173
+ recordVideo: { dir: VIDEO_TMP, size: { width: 1440, height: 900 } }
174
+ });
175
+ const page = await context.newPage();
176
+
177
+ const t0 = Date.now();
178
+ const elapsed = () => (Date.now() - t0) / 1000;
179
+ const stepTimings = [];
180
+
181
+ await page.goto(`${BASE_URL}${CAPTURE_URL}`, { waitUntil: 'load', timeout: 60000 });
182
+ await page.waitForTimeout(800);
183
+
184
+ // STEPS — substituted from manifest steps array:
185
+ // stepTimings.push({ caption: 'CAPTION', time: elapsed() }); await page.click('SELECTOR'); await page.waitForTimeout(MS);
186
+ // stepTimings.push({ caption: 'CAPTION', time: elapsed() }); await page.waitForTimeout(MS);
187
+
188
+ await page.screenshot({ path: POSTER_OUT });
189
+ const duration = elapsed();
190
+
191
+ await context.close();
192
+ await browser.close();
193
+
194
+ // Move recorded video to final path
195
+ const files = readdirSync(VIDEO_TMP).filter(f => f.endsWith('.webm'));
196
+ if (files.length) renameSync(`${VIDEO_TMP}/${files[0]}`, VIDEO_OUT);
197
+
198
+ // Generate VTT
199
+ const toVTT = s => {
200
+ const m = Math.floor(s / 60);
201
+ const sec = (s % 60).toFixed(3).padStart(6, '0');
202
+ return `${String(m).padStart(2,'0')}:${sec}`;
203
+ };
204
+ let vtt = 'WEBVTT\n\n';
205
+ stepTimings.forEach((step, i) => {
206
+ const end = i < stepTimings.length - 1 ? stepTimings[i + 1].time : duration;
207
+ vtt += `${toVTT(step.time)} --> ${toVTT(end)}\n${step.caption}\n\n`;
208
+ });
209
+ writeFileSync(VTT_OUT, vtt);
210
+
211
+ console.log(JSON.stringify({ stepTimings, duration }));
212
+ SCRIPT
213
+ ```
214
+
215
+ After each video runs:
216
+ 1. Display the poster image inline with the Read tool so the user can verify the final frame
217
+ 2. Update the manifest entry with the step timings (replace the action-based steps from generate with timed steps)
218
+ 3. The `.vtt` file is now on disk — it goes in git as-is
219
+
220
+ ---
221
+
222
+ ## Step 5 — GitHub Releases upload
223
+
224
+ After all videos are captured, provide upload instructions for each video file:
225
+
226
+ ```
227
+ Videos are ready for upload to GitHub Releases.
228
+
229
+ 1. Go to: https://github.com/OWNER/REPO/releases
230
+ 2. Create a release tagged `docs-media` (or open the existing one)
231
+ — This is a dedicated release just for doc assets, not tied to code versions.
232
+ 3. Attach these files:
233
+ public/videos/timer-start.webm
234
+ public/videos/form-submit.webm
235
+ 4. Once uploaded, each file will have a URL like:
236
+ https://github.com/OWNER/REPO/releases/download/docs-media/timer-start.webm
237
+ ```
238
+
239
+ Then ask:
240
+
241
+ - header: "Upload complete?"
242
+ - question: "Have you uploaded the videos to GitHub Releases?"
243
+ - options:
244
+ - "Yes — update the manifest and docs"
245
+ - "I'll do it later — skip for now"
246
+
247
+ If yes: update each video entry in the manifest with the correct `videoUrl`. Also update any `<VideoDemo src="...">` placeholders in the markdown files with the real URL.
248
+
249
+ If skip: leave `videoUrl: ""` in the manifest. The VideoDemo component will still render the step list and poster — it just won't have a playable video until the URL is filled in.
250
+
251
+ ---
252
+
253
+ ## Step 6 — Rewrite prose around captures
254
+
255
+ After all captures complete:
256
+ - For each screenshot: go back to the doc page and rewrite the surrounding paragraph to match what's actually in the screenshot
257
+ - For each video: verify the step captions in the doc match what was captured — update if anything looks off
258
+
259
+ Read each screenshot with the Read tool to inform the rewrite.
260
+
261
+ ---
262
+
263
+ ## Step 7 — Update manifest
264
+
265
+ For each successfully captured item:
266
+ - Screenshots: set `"placeholder": false`, record capture timestamp
267
+ - Videos: set step timings, `vtt` path, `poster` path, and `videoUrl` (once uploaded)
268
+
269
+ ---
270
+
271
+ ## Step 8 — Summary
272
+
273
+ ```
274
+ Captured X screenshots, Y videos.
275
+
276
+ Screenshots:
277
+ ✓ timer-main.png
278
+ ✓ settings-overview.png
279
+
280
+ Videos:
281
+ ✓ timer-start.webm — poster captured, VTT written, awaiting upload
282
+ ✓ form-submit.webm — poster captured, VTT written, awaiting upload
283
+
284
+ Upload to: https://github.com/OWNER/REPO/releases/tag/docs-media
285
+
286
+ Prose rewritten in X doc pages.
287
+ Run /vitedocs:sync after future code changes to keep docs current.
288
+ ```