Extract Static HTML
Extract a self-contained static HTML file from any web application.
Which Strategy to Use
You MUST ask the user to choose which strategy to use before proceeding. Present the options clearly, recommend Strategy A as the preferred default, and provide a brief pros/cons summary for each option to help them make an informed decision.
|
Strategy A (Puppeteer) |
Strategy B (Browser Subagent) |
| When |
App runs locally, no auth wall |
Need to interact with page first (click, fill forms) |
| Fidelity |
Highest — computed styles resolved |
High — rendered DOM |
| Setup |
Zero — no mock needed |
Zero — no mock needed |
| Framework |
Any |
Any |
| Output |
Writes to file — no size limit |
May truncate in agent context |
[!WARNING]
Checkpoint — User Confirmation Required.
You MUST ask the user which strategy they prefer before proceeding.
Present the comparison table above, recommend Strategy A as the default, and
wait for explicit approval. Do NOT make the decision yourself or proceed
until the user confirms.
Strategy A: Puppeteer Snapshot (Recommended)
Launches headless Chrome, captures the fully rendered DOM, and produces a self-contained HTML file with all CSS inlined and images as base64. Works with any framework — no MockPage.jsx needed.
Prerequisites
- App running locally (e.g.,
npm run dev)
- Node.js with
puppeteer available (check: node -e "require('puppeteer')")
Workflow
Start the App and note the port.
[!WARNING]
Checkpoint — User Confirmation Required.
After starting the local server, you MUST pause and ask the user for
confirmation before running the snapshot script or launching a browser
subagent. Report the URL and port to the user so they can verify the app
is running and rendering correctly. Do NOT proceed to the snapshot
step until the user confirms.
Run the Snapshot Script:
npx tsx <SKILL_DIR>/scripts/snapshot.ts \
--url http://localhost:5173 \
--output .stitch/home.html \
--wait 2000
Multiple pages — run once per route:
npx tsx <SKILL_DIR>/scripts/snapshot.ts \
--url http://localhost:5173 --output .stitch/home.html --wait 2000
npx tsx <SKILL_DIR>/scripts/snapshot.ts \
--url http://localhost:5173/pricing --output .stitch/pricing.html --wait 2000
npx tsx <SKILL_DIR>/scripts/snapshot.ts \
--url http://localhost:5173/dashboard --output .stitch/dashboard.html --wait 2000 --html-class dark
Clean Up Dev Server:
If a local dev server was started specifically for snapshot extraction, make sure to stop the server process or terminate the background task once extraction is completed.
Script Flags
| Flag |
Default |
Description |
--url |
(required) |
URL to capture |
--output |
(required) |
Output file path |
--wait |
1000 |
Extra wait (ms) after network idle. Increase for lazy-loading apps. |
--viewport |
1280x800 |
Viewport size as WIDTHxHEIGHT |
--html-class |
— |
Class(es) for <html> element (e.g., dark) |
--remove-fixed |
false |
Remove fixed/sticky elements (cookie banners, chat widgets) |
--full-height |
false |
Resize viewport to full scroll height |
--title |
— |
Override page title (set to the route path, e.g. /dashboard or /settings/profile) |
--auth-script |
— |
Path to a JS/TS module that exports a default async (page) => void function for authentication |
--inline-canvas |
false |
Convert <canvas> elements (ECharts, Chart.js, D3) to base64 <img> tags |
What It Does Automatically
- Captures all CSSOM rules from
document.styleSheets (preserves dynamic Vite/Tailwind dev styles and CSS-in-JS)
- Inlines all
<link rel="stylesheet"> → <style> blocks
- Converts
<img> src and srcset → base64 data URIs (skips external fonts)
- Inlines same-origin and relative icon font files (
@font-face) as base64 data URIs so ligatures never render as ASCII text
- Inlines
<source srcset> URLs as base64
- Removes failed/dead
srcset entries so the browser falls back to the inlined src
- Removes
<script> tags, Vite HMR dev style blocks (createHotContext, import.meta.hot), and dev overlays
- Resolves relative CSS
url() paths before inlining
Framework Notes
| Framework |
Notes |
| React + Vite |
Works out of the box. --wait 1000. |
| Next.js |
--wait 3000 for SSR hydration. URL: http://localhost:3000. <img srcset> from /_next/image is auto-inlined as base64. |
| Angular (@angular/cli / v17+) |
Works out of the box with ng serve (default URL: http://localhost:4200). --wait 2000 for Angular Material / PrimeNG animation hydration and lazy-loaded routes. |
| Vue / Nuxt |
Works out of the box. |
| Svelte / SvelteKit |
Works out of the box. |
| Storybook |
Use story URL: --url http://localhost:6006/?path=/story/... |
| SSR (Webpack) |
May need longer --wait. |
Troubleshooting
| Issue |
Solution |
| Images missing |
Increase --wait |
| Images show as broken after server stops |
Verify srcset was inlined — check log for "Inlined N images". If srcset URLs failed, they are auto-removed so src (inlined) is used. |
| Icons display as text / Serif unstyled font |
Ensure snapshot.ts captures CSSOM from document.styleSheets (step 0) and same-origin icon fonts (@font-face) are inlined as base64 data URIs. |
Next.js /_next/image not inlined |
Ensure the dev server is running when snapshot runs — the script fetches optimized images from the running server. |
| Dark mode not applied |
--html-class dark |
| Cookie banner in output |
--remove-fixed |
| Page requires login |
Use --auth-script ./auth.ts (see Auth-Gated Pages below) |
| Charts/graphs show as blank boxes |
Use --inline-canvas to serialize <canvas> to base64 <img> |
Cannot find module 'puppeteer' |
npm install -g puppeteer |
Auth-Gated Pages
For apps with login guards (Vue Router beforeEach, React ProtectedRoute, etc.), create a small auth script that runs in the Puppeteer session:
// auth-myapp.ts
import type { Page } from 'puppeteer';
export default async function authenticate(page: Page) {
// Example 1: Fill and submit a login form
await page.type('#username', 'admin');
await page.type('#password', 'password123');
await page.click('#login-button');
await page.waitForNavigation({ waitUntil: 'networkidle2' });
// Example 2: Inject cookies/localStorage directly
// await page.evaluate(() => {
// localStorage.setItem('token', 'mock-jwt-token');
// });
// Example 3: Call the app's own login API via module injection (Vue/Vite)
// await page.evaluate(() => {
// return new Promise((resolve) => {
// const script = document.createElement('script');
// script.type = 'module';
// script.textContent = `
// import { useUserStore } from '/src/store/modules/user.ts';
// import { fetchLogin } from '/src/api/auth.ts';
// const res = await fetchLogin({ userName: 'Admin', password: '123456' });
// useUserStore().setToken(res.token, res.refreshToken);
// window.dispatchEvent(new CustomEvent('auth-done'));
// `;
// document.head.appendChild(script);
// window.addEventListener('auth-done', () => resolve(true), { once: true });
// });
// });
}
Then use it:
npx tsx <SKILL_DIR>/scripts/snapshot.ts \
--url http://localhost:5173/#/dashboard \
--output .stitch/dashboard.html \
--auth-script ./auth-myapp.ts \
--inline-canvas \
--wait 5000
The script navigates to the --url first (which may redirect to login), runs your auth function, then re-navigates to the original --url with the authenticated session.
Strategy B: Browser Subagent Capture
Use when you need to interact with the page (click buttons, fill forms, navigate tabs) before capturing. The browser subagent gives you full control but output may truncate for large pages.
Workflow
Start the App locally.
Navigate using a browser subagent.
Interact as needed (click, scroll, fill forms).
Extract DOM: document.documentElement.outerHTML
[!WARNING]
Large pages may truncate. To handle this:
- Remove
<style> tags before extraction: document.querySelectorAll('style').forEach(el => el.remove())
- Re-add styles statically (Tailwind CDN link, source CSS)
Save to file.
Appendix: Static Fallback (MockPage.jsx)
[!NOTE]
This method is a last resort for when the app cannot run locally (broken deps, missing backend, auth walls with no bypass). It requires manually flattening React components into a single JSX file. Prefer Strategy A whenever possible.
When to Use
- App can't run locally at all
- Page requires auth with no mock/bypass
- You need a specific UI state that's impossible to reach by navigation (error screens, empty states)
Quick Reference
npx tsx <SKILL_DIR>/scripts/extract_inline_html.ts \
--index-css src/css/App.css \
--extra-css index.html \
--outdir .stitch \
--page src/MockPage.jsx:Page.html:"Page Title"
Key flags: --no-tailwind (non-Tailwind apps), --html-class dark (dark mode), --css-files (extra CSS files).
Auto-detection: Tailwind config is auto-detected. @apply directives automatically use <style type="text/tailwindcss">.
MockPage.jsx Rules
- Include the full layout — header, sidebar, footer (read
App.js first)
- Flatten all conditionals — pick one state, remove all ternaries and
&& guards
- Hardcode all data — replace
{variable} with concrete values, unroll .map() loops
- Preserve logos — use
<img> with local paths (post-process will inline them)
- Remove floating elements — cookie banners, chat widgets, feedback buttons
Post-Processing
Inline local images:
npx tsx <SKILL_DIR>/scripts/post_process.ts \
.stitch/Page.html --base-dir <app-directory>
Cross-Client Portability
This skill is written to stay usable across GitHub Copilot, Claude Code, and Codex.
- GitHub Copilot: keep the folder in a Copilot-visible skill path or wrap the
workflow in project instructions when folder discovery is unavailable.
- Claude Code: keep the folder in a local skills directory or a compatible plugin source.
- Codex: install or sync the folder into
$CODEX_HOME/skills/stitch-extract-static-html and restart Codex after major changes.
MCP Availability And Fallback
Preferred MCP Server: Stitch MCP
- Fallback prompt: "Use the Extract Static HTML skill without MCP. Follow the documented local or manual fallback, show the selected tool surface, and report the verification evidence."
- Use local
.stitch/ artifacts, exported HTML or screenshots, bundled scripts, and the Stitch web UI when the host does not expose the needed Stitch MCP operation.
- Do not claim screen lookup, generation, editing, or variant MCP calls unless those tools are present in the active host tool list.
- Do not claim an MCP operation was used when the active host does not expose it.
Anti-Patterns
- Claiming a Stitch screen-generation, screen-editing, or screen-retrieval MCP call succeeded when the active host does not expose that tool.
- Uploading files, screenshots, HTML, markdown, or design assets to Stitch without user-approved destination and artifact details.
- Reading, printing, storing, or committing Stitch API keys, MCP config secrets, cookies, or credential-bearing files.
- Treating generated design or code as final without local render, syntax, or artifact verification.
- Collapsing this workflow into a broader frontend/design skill when Stitch-specific files, project IDs, or design-system assets matter.
Verification Protocol
Before claiming this skill was applied successfully:
- Pass/fail: The output HTML exists under
.stitch/.
- Pass/fail: Capture route, viewport, wait time, and special flags are recorded.
- Pass/fail: Important images are inlined or intentionally left as stable external URLs.
- Pass/fail: No authenticated personal content, cookies, tokens, or private user data were captured.
- Pressure-test scenario: Repeat the workflow with Stitch MCP screen tools unavailable and confirm the fallback path remains honest and actionable.
- Success metric: The user can identify the exact artifact, project/design-system target, and verification evidence without relying on unstated MCP behavior.
Related Skills
1---2name: stitch-extract-static-html3description: Capture a self-contained static HTML snapshot from a running app or mock component so it can be reviewed or uploaded to Stitch.4license: Apache-2.05---6# Extract Static HTML
7
8Extract a self-contained static HTML file from any web application.
9
10## Which Strategy to Use
11
12You MUST ask the user to choose which strategy to use before proceeding. Present the options clearly, **recommend Strategy A** as the preferred default, and **provide a brief pros/cons summary** for each option to help them make an informed decision.
13
14| | Strategy A (Puppeteer) | Strategy B (Browser Subagent) |
15| :--- | :--- | :--- |
16| **When** | App runs locally, no auth wall | Need to interact with page first (click, fill forms) |
17| **Fidelity** | **Highest — computed styles resolved** | High — rendered DOM |
18| **Setup** | **Zero — no mock needed** | Zero — no mock needed |
19| **Framework** | **Any** | Any |
20| **Output** | **Writes to file — no size limit** | May truncate in agent context |
21
22> [!WARNING]
23> **Checkpoint — User Confirmation Required.**
24> You **MUST** ask the user which strategy they prefer before proceeding.
25> Present the comparison table above, recommend Strategy A as the default, and
26> wait for explicit approval. Do **NOT** make the decision yourself or proceed
27> until the user confirms.
28
29***
30
31## Strategy A: Puppeteer Snapshot (Recommended)
32
33Launches headless Chrome, captures the fully rendered DOM, and produces a self-contained HTML file with all CSS inlined and images as base64. Works with **any framework** — no MockPage.jsx needed.
34
35### Prerequisites
36
37- App running locally (e.g., `npm run dev`)
38- Node.js with `puppeteer` available (check: `node -e "require('puppeteer')"`)
39
40### Workflow
41
421. **Start the App** and note the port.
43
44 > [!WARNING]
45 > **Checkpoint — User Confirmation Required.**
46 > After starting the local server, you **MUST** pause and ask the user for
47 > confirmation before running the snapshot script or launching a browser
48 > subagent. Report the URL and port to the user so they can verify the app
49 > is running and rendering correctly. Do **NOT** proceed to the snapshot
50 > step until the user confirms.
51
522. **Run the Snapshot Script**:
53 ```bash
54 npx tsx <SKILL_DIR>/scripts/snapshot.ts \
55 --url http://localhost:5173 \
56 --output .stitch/home.html \
57 --wait 2000
58 ```
59
603. **Multiple pages** — run once per route:
61 ```bash
62 npx tsx <SKILL_DIR>/scripts/snapshot.ts \
63 --url http://localhost:5173 --output .stitch/home.html --wait 2000
64 npx tsx <SKILL_DIR>/scripts/snapshot.ts \
65 --url http://localhost:5173/pricing --output .stitch/pricing.html --wait 2000
66 npx tsx <SKILL_DIR>/scripts/snapshot.ts \
67 --url http://localhost:5173/dashboard --output .stitch/dashboard.html --wait 2000 --html-class dark
68 ```
69
704. **Clean Up Dev Server**:
71 If a local dev server was started specifically for snapshot extraction, make sure to stop the server process or terminate the background task once extraction is completed.
72
73
74### Script Flags
75
76| Flag | Default | Description |
77| :--- | :--- | :--- |
78| `--url` | *(required)* | URL to capture |
79| `--output` | *(required)* | Output file path |
80| `--wait` | `1000` | Extra wait (ms) after network idle. Increase for lazy-loading apps. |
81| `--viewport` | `1280x800` | Viewport size as `WIDTHxHEIGHT` |
82| `--html-class` | — | Class(es) for `<html>` element (e.g., `dark`) |
83| `--remove-fixed` | `false` | Remove fixed/sticky elements (cookie banners, chat widgets) |
84| `--full-height` | `false` | Resize viewport to full scroll height |
85| `--title` | — | Override page title (set to the route path, e.g. `/dashboard` or `/settings/profile`) |
86| `--auth-script` | — | Path to a JS/TS module that exports a default `async (page) => void` function for authentication |
87| `--inline-canvas` | `false` | Convert `<canvas>` elements (ECharts, Chart.js, D3) to base64 `<img>` tags |
88
89### What It Does Automatically
90
91- Captures all CSSOM rules from `document.styleSheets` (preserves dynamic Vite/Tailwind dev styles and CSS-in-JS)
92- Inlines all `<link rel="stylesheet">` → `<style>` blocks
93- Converts `<img>` `src` **and `srcset`** → base64 data URIs (skips external fonts)
94- Inlines same-origin and relative icon font files (`@font-face`) as base64 data URIs so ligatures never render as ASCII text
95- Inlines `<source srcset>` URLs as base64
96- Removes failed/dead `srcset` entries so the browser falls back to the inlined `src`
97- Removes `<script>` tags, Vite HMR dev style blocks (`createHotContext`, `import.meta.hot`), and dev overlays
98- Resolves relative CSS `url()` paths before inlining
99
100### Framework Notes
101
102| Framework | Notes |
103| :--- | :--- |
104| **React + Vite** | Works out of the box. `--wait 1000`. |
105| **Next.js** | `--wait 3000` for SSR hydration. URL: `http://localhost:3000`. `<img srcset>` from `/_next/image` is auto-inlined as base64. |
106| **Angular (@angular/cli / v17+)** | Works out of the box with `ng serve` (default URL: `http://localhost:4200`). `--wait 2000` for Angular Material / PrimeNG animation hydration and lazy-loaded routes. |
107| **Vue / Nuxt** | Works out of the box. |
108| **Svelte / SvelteKit** | Works out of the box. |
109| **Storybook** | Use story URL: `--url http://localhost:6006/?path=/story/...` |
110| **SSR (Webpack)** | May need longer `--wait`. |
111
112### Troubleshooting
113
114| Issue | Solution |
115| :--- | :--- |
116| Images missing | Increase `--wait` |
117| Images show as broken after server stops | Verify `srcset` was inlined — check log for "Inlined N images". If `srcset` URLs failed, they are auto-removed so `src` (inlined) is used. |
118| Icons display as text / Serif unstyled font | Ensure `snapshot.ts` captures CSSOM from `document.styleSheets` (step 0) and same-origin icon fonts (`@font-face`) are inlined as base64 data URIs. |
119| Next.js `/_next/image` not inlined | Ensure the dev server is running when snapshot runs — the script fetches optimized images from the running server. |
120| Dark mode not applied | `--html-class dark` |
121| Cookie banner in output | `--remove-fixed` |
122| Page requires login | Use `--auth-script ./auth.ts` (see Auth-Gated Pages below) |
123| Charts/graphs show as blank boxes | Use `--inline-canvas` to serialize `<canvas>` to base64 `<img>` |
124| `Cannot find module 'puppeteer'` | `npm install -g puppeteer` |
125
126### Auth-Gated Pages
127
128For apps with login guards (Vue Router `beforeEach`, React `ProtectedRoute`, etc.), create a small auth script that runs in the Puppeteer session:
129
130```ts
131// auth-myapp.ts
132import type { Page } from 'puppeteer';
133
134export default async function authenticate(page: Page) {
135 // Example 1: Fill and submit a login form
136 await page.type('#username', 'admin');
137 await page.type('#password', 'password123');
138 await page.click('#login-button');
139 await page.waitForNavigation({ waitUntil: 'networkidle2' });
140
141 // Example 2: Inject cookies/localStorage directly
142 // await page.evaluate(() => {
143 // localStorage.setItem('token', 'mock-jwt-token');
144 // });
145
146 // Example 3: Call the app's own login API via module injection (Vue/Vite)
147 // await page.evaluate(() => {
148 // return new Promise((resolve) => {
149 // const script = document.createElement('script');
150 // script.type = 'module';
151 // script.textContent = `
152 // import { useUserStore } from '/src/store/modules/user.ts';
153 // import { fetchLogin } from '/src/api/auth.ts';
154 // const res = await fetchLogin({ userName: 'Admin', password: '123456' });
155 // useUserStore().setToken(res.token, res.refreshToken);
156 // window.dispatchEvent(new CustomEvent('auth-done'));
157 // `;
158 // document.head.appendChild(script);
159 // window.addEventListener('auth-done', () => resolve(true), { once: true });
160 // });
161 // });
162}
163```
164
165Then use it:
166```bash
167npx tsx <SKILL_DIR>/scripts/snapshot.ts \
168 --url http://localhost:5173/#/dashboard \
169 --output .stitch/dashboard.html \
170 --auth-script ./auth-myapp.ts \
171 --inline-canvas \
172 --wait 5000
173```
174
175The script navigates to the `--url` first (which may redirect to login), runs your auth function, then **re-navigates** to the original `--url` with the authenticated session.
176
177***
178
179## Strategy B: Browser Subagent Capture
180
181Use when you need to **interact with the page** (click buttons, fill forms, navigate tabs) before capturing. The browser subagent gives you full control but output may truncate for large pages.
182
183### Workflow
184
1851. **Start the App** locally.
1862. **Navigate** using a browser subagent.
1873. **Interact** as needed (click, scroll, fill forms).
1884. **Extract DOM**: `document.documentElement.outerHTML`
189
190 > [!WARNING]
191 > Large pages may truncate. To handle this:
192 > - Remove `<style>` tags before extraction: `document.querySelectorAll('style').forEach(el => el.remove())`
193 > - Re-add styles statically (Tailwind CDN link, source CSS)
1945. **Save** to file.
195
196***
197
198## Appendix: Static Fallback (MockPage.jsx)
199
200> [!NOTE]
201> This method is a **last resort** for when the app cannot run locally (broken deps, missing backend, auth walls with no bypass). It requires manually flattening React components into a single JSX file. **Prefer Strategy A whenever possible.**
202
203### When to Use
204
205- App can't run locally at all
206- Page requires auth with no mock/bypass
207- You need a specific UI state that's impossible to reach by navigation (error screens, empty states)
208
209### Quick Reference
210
211```bash
212npx tsx <SKILL_DIR>/scripts/extract_inline_html.ts \
213 --index-css src/css/App.css \
214 --extra-css index.html \
215 --outdir .stitch \
216 --page src/MockPage.jsx:Page.html:"Page Title"
217```
218
219**Key flags**: `--no-tailwind` (non-Tailwind apps), `--html-class dark` (dark mode), `--css-files` (extra CSS files).
220
221**Auto-detection**: Tailwind config is auto-detected. `@apply` directives automatically use `<style type="text/tailwindcss">`.
222
223### MockPage.jsx Rules
224
2251. **Include the full layout** — header, sidebar, footer (read `App.js` first)
2262. **Flatten all conditionals** — pick one state, remove all ternaries and `&&` guards
2273. **Hardcode all data** — replace `{variable}` with concrete values, unroll `.map()` loops
2284. **Preserve logos** — use `<img>` with local paths (post-process will inline them)
2295. **Remove floating elements** — cookie banners, chat widgets, feedback buttons
230
231### Post-Processing
232
233Inline local images:
234```bash
235npx tsx <SKILL_DIR>/scripts/post_process.ts \
236 .stitch/Page.html --base-dir <app-directory>
237```
238
239<!-- MCP:START -->
240
241<!-- PORTABILITY:START -->
242## Cross-Client Portability
243
244This skill is written to stay usable across GitHub Copilot, Claude Code, and Codex.
245
246- GitHub Copilot: keep the folder in a Copilot-visible skill path or wrap the
247 workflow in project instructions when folder discovery is unavailable.
248- Claude Code: keep the folder in a local skills directory or a compatible plugin source.
249- Codex: install or sync the folder into
250 `$CODEX_HOME/skills/stitch-extract-static-html` and restart Codex after major changes.
251
252<!-- PORTABILITY:END -->
253
254## MCP Availability And Fallback
255
256Preferred MCP Server: Stitch MCP
257
258- Fallback prompt: "Use the Extract Static HTML skill without MCP. Follow the documented local or manual fallback, show the selected tool surface, and report the verification evidence."
259- Use local `.stitch/` artifacts, exported HTML or screenshots, bundled scripts, and the Stitch web UI when the host does not expose the needed Stitch MCP operation.
260- Do not claim screen lookup, generation, editing, or variant MCP calls unless those tools are present in the active host tool list.
261- Do not claim an MCP operation was used when the active host does not expose it.
262
263<!-- MCP:END -->
264
265## Anti-Patterns
266
267- Claiming a Stitch screen-generation, screen-editing, or screen-retrieval MCP call succeeded when the active host does not expose that tool.
268- Uploading files, screenshots, HTML, markdown, or design assets to Stitch without user-approved destination and artifact details.
269- Reading, printing, storing, or committing Stitch API keys, MCP config secrets, cookies, or credential-bearing files.
270- Treating generated design or code as final without local render, syntax, or artifact verification.
271- Collapsing this workflow into a broader frontend/design skill when Stitch-specific files, project IDs, or design-system assets matter.
272
273## Verification Protocol
274
275Before claiming this skill was applied successfully:
276
2771. Pass/fail: The output HTML exists under `.stitch/`.
2782. Pass/fail: Capture route, viewport, wait time, and special flags are recorded.
2793. Pass/fail: Important images are inlined or intentionally left as stable external URLs.
2804. Pass/fail: No authenticated personal content, cookies, tokens, or private user data were captured.
2815. Pressure-test scenario: Repeat the workflow with Stitch MCP screen tools unavailable and confirm the fallback path remains honest and actionable.
2826. Success metric: The user can identify the exact artifact, project/design-system target, and verification evidence without relying on unstated MCP behavior.
283
284## Related Skills
285
286- [stitch-code-to-design](../stitch-code-to-design/SKILL.md): Use when the task also needs this adjacent Stitch workflow.
287- [stitch-upload-to-stitch](../stitch-upload-to-stitch/SKILL.md): Use when the task also needs this adjacent Stitch workflow.
288- [web-testing](../web-testing/SKILL.md): Use when the task also needs this adjacent Stitch workflow.
289- [vite-development](../vite-development/SKILL.md): Use when the task also needs this adjacent Stitch workflow.