frameshot-mcp 0.3.0 → 0.6.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
@@ -2,13 +2,24 @@
2
2
 
3
3
  [![npm version](https://img.shields.io/npm/v/frameshot-mcp)](https://www.npmjs.com/package/frameshot-mcp) [![npm downloads](https://img.shields.io/npm/dm/frameshot-mcp)](https://www.npmjs.com/package/frameshot-mcp) [![GitHub stars](https://img.shields.io/github/stars/kamegoro/frameshot)](https://github.com/kamegoro/frameshot) [![CI](https://github.com/kamegoro/frameshot/actions/workflows/ci.yml/badge.svg)](https://github.com/kamegoro/frameshot/actions/workflows/ci.yml) [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
4
4
 
5
- > Give your AI agent eyes. Render UI components and get screenshots back in 120ms.
5
+ > **Give your AI agent eyes.** One MCP call, one screenshot 120ms. Stop coding blind.
6
6
 
7
- <!-- TODO: demo GIF here -->
8
- <!-- ![demo](docs/demo.gif) -->
7
+ <p align="center">
8
+ <img src="docs/demo.svg" alt="frameshot demo — AI writes code, frameshot renders it, AI sees and self-corrects" width="720" />
9
+ </p>
10
+
11
+ ## The Problem
12
+
13
+ AI coding agents (Claude Code, Cursor, Copilot, Cline) write UI code **blind**. They generate HTML/CSS/React but never see the rendered result. You end up:
14
+
15
+ - Switching to the browser to check every change
16
+ - Screenshotting and pasting back into chat
17
+ - Burning tokens on fix loops that never converge
18
+
19
+ **frameshot closes this loop.** The agent calls one tool, gets a screenshot back in 120ms, and self-corrects.
9
20
 
10
21
  ```
11
- AI writes code → AI calls frameshot → AI sees the result → AI self-corrects
22
+ AI writes code → frameshot renders → AI sees result → AI self-corrects → ships
12
23
  ```
13
24
 
14
25
  ## Install
@@ -18,7 +29,7 @@ claude mcp add frameshot -- npx frameshot-mcp@latest
18
29
  ```
19
30
 
20
31
  <details>
21
- <summary>Cursor / VS Code / Other</summary>
32
+ <summary>Cursor / VS Code / Windsurf / Other MCP clients</summary>
22
33
 
23
34
  ```json
24
35
  {
@@ -33,62 +44,104 @@ claude mcp add frameshot -- npx frameshot-mcp@latest
33
44
 
34
45
  </details>
35
46
 
36
- ## Tools
37
-
38
- | Tool | What it does |
39
- |------|-------------|
40
- | `render_component` | Render React/Vue/Svelte/HTML → screenshot. Tailwind built-in. |
41
- | `render_responsive` | Render at mobile + tablet + desktop in one call. |
42
- | `render_variants` | Render multiple prop/state variants in one call. |
43
- | `screenshot_url` | Screenshot any URL (e.g. localhost:3000). |
44
- | `audit_a11y` | Run axe-core accessibility audit on your component. |
45
- | `diff_component` | Visual regression: compare before/after code, get pixel diff. |
46
- | `capture_animation` | Capture CSS animation frames over time (multi-screenshot). |
47
+ ## What it does
48
+
49
+ | Tool | Purpose |
50
+ |------|---------|
51
+ | `render_component` | Render React/Vue/Svelte/HTML code → screenshot. Tailwind built-in. |
52
+ | `render_file` | Render a file from disk (auto-detects framework from extension). |
53
+ | `screenshot_url` | Screenshot any URL (localhost:3000, staging, prod). |
54
+ | `render_responsive` | Mobile + tablet + desktop in one call. |
55
+ | `render_variants` | Multiple prop/state variants at once. |
56
+ | `render_theme` | Light + dark mode side-by-side. |
57
+ | `render_interaction` | Simulate click/hover/type, then screenshot result. |
58
+ | `render_grid` | Multiple snippets in a labeled grid image. |
59
+ | `diff_component` | Before/after pixel diff with % changed. |
60
+ | `audit_a11y` | axe-core accessibility audit (WCAG violations). |
61
+ | `perf_audit` | DOM element count, depth, render timing. |
62
+ | `render_matrix` | Viewport × theme matrix in one call. |
63
+ | `capture_animation` | Multi-frame CSS animation capture. |
64
+ | `diff_reference` | Compare render against a reference image (Figma QA). |
65
+ | `render_catalog` | Render all components in a directory (zero-config Storybook). |
66
+ | `snapshot_save` | Save render as named baseline snapshot. |
67
+ | `snapshot_check` | Compare current render against saved snapshot. |
68
+ | `snapshot_list` | List all saved snapshots. |
47
69
 
48
70
  ### Example
49
71
 
50
72
  ```typescript
73
+ // AI renders its own output to verify
51
74
  render_component({
52
75
  code: `function App() {
53
- return <div className="p-8 bg-blue-500 text-white rounded-xl">Hello</div>
76
+ return (
77
+ <div className="p-8 bg-gradient-to-r from-blue-500 to-purple-600 text-white rounded-2xl shadow-xl">
78
+ <h1 className="text-3xl font-bold">Pricing</h1>
79
+ <p className="text-5xl mt-4">$29<span className="text-lg">/mo</span></p>
80
+ </div>
81
+ )
54
82
  }`,
55
- framework: "react",
56
- darkMode: true,
57
- engines: ["chromium", "firefox", "webkit"]
83
+ framework: "react"
58
84
  })
85
+ // → Screenshot returned in 118ms. AI can see it looks correct.
59
86
  ```
60
87
 
61
88
  ## Why frameshot?
62
89
 
63
- | | Storybook | frameshot |
64
- |---|-----------|-----------|
65
- | Setup | .stories.tsx + addons + server | **Zero** |
66
- | Speed | Dev server startup | **~120ms** |
67
- | Cross-browser | Chromatic ($149+/mo) | **Free** |
68
- | AI-native | Needs pre-written stories | **Any code snippet** |
90
+ | | Storybook | Chromatic/Percy | Browser MCP | **frameshot** |
91
+ |---|-----------|-----------------|-------------|---------------|
92
+ | Setup | stories + addons + server | SaaS signup + billing | Browser install | **`npx` — done** |
93
+ | Speed | Dev server startup | Cloud round-trip | 2-5s | **~120ms** |
94
+ | Cost | Free (stories = labor) | $149-800+/mo | Free | **Free forever** |
95
+ | AI-native | Needs pre-written stories | No MCP support | Full-page only | **Any code snippet** |
96
+ | Frameworks | React (+ addons) | Whatever Storybook supports | HTML only | **React/Vue/Svelte/HTML** |
97
+ | Cross-browser | Chromatic ($$$) | Per-snapshot pricing | Single browser | **3 engines, free** |
69
98
 
70
99
  ## Performance
71
100
 
72
101
  | Scenario | Time |
73
102
  |----------|------|
74
103
  | Warm render | **~120ms** |
75
- | Cold start | ~4s |
76
- | 3 engines parallel | ~300ms |
104
+ | Cold start (first run) | ~4s |
105
+ | 3 browsers in parallel | ~300ms |
106
+ | Responsive (3 viewports) | ~350ms |
107
+
108
+ Browser pool stays warm between calls. Tailwind CSS is pre-cached. Sub-200ms after first run.
109
+
110
+ ## GitHub Action
111
+
112
+ Add visual previews to every PR — free Chromatic alternative:
113
+
114
+ ```yaml
115
+ # .github/workflows/visual-preview.yml
116
+ name: Visual Preview
117
+ on: [pull_request]
118
+ jobs:
119
+ preview:
120
+ runs-on: ubuntu-latest
121
+ steps:
122
+ - uses: actions/checkout@v4
123
+ - uses: kamegoro/frameshot@main
124
+ with:
125
+ paths: "./src/components/*.tsx"
126
+ framework: react
127
+ ```
77
128
 
78
- Browser pool stays warm. Tailwind pre-cached. Sub-200ms after first run.
129
+ Screenshots are posted as a PR comment automatically.
79
130
 
80
131
  ## Recipes
81
132
 
82
- - [Claude Code skill setup](examples/claude-code-skill.md) — Auto-preview components with `/project:preview`
83
- - [Cursor rules](examples/cursor-rules.md) — Auto-verify UI on every edit
133
+ - [Claude Code skill](examples/claude-code-skill.md) — Auto-preview on `/project:preview`
134
+ - [Cursor rules](examples/cursor-rules.md) — Verify UI on every edit
84
135
 
85
136
  ## Development
86
137
 
87
138
  ```bash
88
139
  git clone https://github.com/kamegoro/frameshot.git && cd frameshot
89
- npm install && npx playwright install chromium && npm run build
140
+ npm install && npx playwright install chromium && npm run build && npm test
90
141
  ```
91
142
 
143
+ See [CONTRIBUTING.md](CONTRIBUTING.md) for details.
144
+
92
145
  ## License
93
146
 
94
147
  MIT
package/action.yml ADDED
@@ -0,0 +1,130 @@
1
+ name: "frameshot — Visual Preview"
2
+ description: "Render components and attach before/after screenshots to PRs. Free visual regression for every pull request."
3
+ branding:
4
+ icon: "camera"
5
+ color: "blue"
6
+
7
+ inputs:
8
+ paths:
9
+ description: "Glob patterns for component files to render (newline or comma separated)"
10
+ required: true
11
+ framework:
12
+ description: "Framework: react, vue, svelte, or html"
13
+ required: false
14
+ default: "react"
15
+ width:
16
+ description: "Viewport width (px)"
17
+ required: false
18
+ default: "1280"
19
+ height:
20
+ description: "Viewport height (px)"
21
+ required: false
22
+ default: "800"
23
+ dark-mode:
24
+ description: "Render with dark mode"
25
+ required: false
26
+ default: "false"
27
+ tailwind-version:
28
+ description: "Tailwind CSS version (3 or 4)"
29
+ required: false
30
+ default: "3"
31
+ comment:
32
+ description: "Post a PR comment with screenshots"
33
+ required: false
34
+ default: "true"
35
+ token:
36
+ description: "GitHub token for PR comments"
37
+ required: false
38
+ default: ${{ github.token }}
39
+
40
+ runs:
41
+ using: "composite"
42
+ steps:
43
+ - name: Setup Node.js
44
+ uses: actions/setup-node@v4
45
+ with:
46
+ node-version: "20"
47
+
48
+ - name: Install frameshot
49
+ shell: bash
50
+ run: npm install -g frameshot-mcp@latest
51
+
52
+ - name: Install Playwright Chromium
53
+ shell: bash
54
+ run: npx playwright install chromium
55
+
56
+ - name: Render changed components
57
+ id: render
58
+ shell: bash
59
+ env:
60
+ INPUT_PATHS: ${{ inputs.paths }}
61
+ INPUT_FRAMEWORK: ${{ inputs.framework }}
62
+ INPUT_WIDTH: ${{ inputs.width }}
63
+ INPUT_HEIGHT: ${{ inputs.height }}
64
+ INPUT_DARK_MODE: ${{ inputs.dark-mode }}
65
+ INPUT_TAILWIND_VERSION: ${{ inputs.tailwind-version }}
66
+ run: |
67
+ node "${{ github.action_path }}/scripts/render-changed.mjs"
68
+
69
+ - name: Comment on PR
70
+ if: inputs.comment == 'true' && github.event_name == 'pull_request'
71
+ uses: actions/github-script@v9
72
+ env:
73
+ SCREENSHOTS_DIR: ${{ github.workspace }}/.frameshot-screenshots
74
+ with:
75
+ github-token: ${{ inputs.token }}
76
+ script: |
77
+ const fs = require('fs');
78
+ const path = require('path');
79
+ const dir = process.env.SCREENSHOTS_DIR;
80
+
81
+ if (!fs.existsSync(dir)) {
82
+ console.log('No screenshots generated');
83
+ return;
84
+ }
85
+
86
+ const files = fs.readdirSync(dir).filter(f => f.endsWith('.png'));
87
+ if (files.length === 0) {
88
+ console.log('No screenshot files found');
89
+ return;
90
+ }
91
+
92
+ // Upload screenshots as artifacts and build comment
93
+ let body = '## 📸 frameshot — Visual Preview\n\n';
94
+ body += '| Component | Screenshot |\n|---|---|\n';
95
+
96
+ for (const file of files) {
97
+ const name = file.replace('.png', '').replace(/_/g, '/');
98
+ const imgPath = path.join(dir, file);
99
+ const imgData = fs.readFileSync(imgPath, 'base64');
100
+ body += `| \`${name}\` | <img src="data:image/png;base64,${imgData}" width="400" /> |\n`;
101
+ }
102
+
103
+ body += '\n---\n*Generated by [frameshot](https://github.com/kamegoro/frameshot)*';
104
+
105
+ // Find existing comment
106
+ const { data: comments } = await github.rest.issues.listComments({
107
+ owner: context.repo.owner,
108
+ repo: context.repo.repo,
109
+ issue_number: context.issue.number,
110
+ });
111
+
112
+ const existing = comments.find(c =>
113
+ c.body?.includes('📸 frameshot — Visual Preview')
114
+ );
115
+
116
+ if (existing) {
117
+ await github.rest.issues.updateComment({
118
+ owner: context.repo.owner,
119
+ repo: context.repo.repo,
120
+ comment_id: existing.id,
121
+ body,
122
+ });
123
+ } else {
124
+ await github.rest.issues.createComment({
125
+ owner: context.repo.owner,
126
+ repo: context.repo.repo,
127
+ issue_number: context.issue.number,
128
+ body,
129
+ });
130
+ }