figma-local 1.1.0 → 1.3.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 +78 -17
- package/bin/fig-start +28 -12
- package/package.json +1 -1
- package/src/index.js +159 -5
package/README.md
CHANGED
|
@@ -51,6 +51,12 @@ npm install -g figma-local
|
|
|
51
51
|
|
|
52
52
|
Gives you `fig` and `fig-start` globally on your PATH.
|
|
53
53
|
|
|
54
|
+
**Update to latest:**
|
|
55
|
+
|
|
56
|
+
```bash
|
|
57
|
+
npm update -g figma-local
|
|
58
|
+
```
|
|
59
|
+
|
|
54
60
|
### curl (one-line)
|
|
55
61
|
|
|
56
62
|
```bash
|
|
@@ -74,7 +80,7 @@ npx figma-local read
|
|
|
74
80
|
|
|
75
81
|
```bash
|
|
76
82
|
git clone https://github.com/thepreakerebi/figma-local.git
|
|
77
|
-
cd figma-
|
|
83
|
+
cd figma-local
|
|
78
84
|
npm install && npm install -g .
|
|
79
85
|
```
|
|
80
86
|
|
|
@@ -93,32 +99,66 @@ npm install && npm install -g .
|
|
|
93
99
|
|
|
94
100
|
## Setup (one time only)
|
|
95
101
|
|
|
96
|
-
### 1
|
|
102
|
+
### Step 1 — Install the CLI
|
|
97
103
|
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
104
|
+
Pick one of the install methods above (npm recommended):
|
|
105
|
+
|
|
106
|
+
```bash
|
|
107
|
+
npm install -g figma-local
|
|
108
|
+
```
|
|
103
109
|
|
|
104
|
-
|
|
110
|
+
Verify it worked:
|
|
105
111
|
|
|
106
112
|
```bash
|
|
107
|
-
fig
|
|
113
|
+
fig --help
|
|
108
114
|
```
|
|
109
115
|
|
|
110
|
-
|
|
116
|
+
### Step 2 — Import the Figma plugin into Figma Desktop
|
|
117
|
+
|
|
118
|
+
The plugin lets figma-local talk to Figma. You only need to do this once per Figma account.
|
|
119
|
+
|
|
120
|
+
1. Open **Figma Desktop** (not the browser — the desktop app)
|
|
121
|
+
2. Open any design file
|
|
122
|
+
3. Click the **hamburger menu** (☰) in the top-left corner
|
|
123
|
+
4. Go to **Plugins → Development → Import plugin from manifest...**
|
|
124
|
+
5. In the file picker, navigate to the plugin folder:
|
|
125
|
+
- If you installed via **npm**: run `echo "$(npm root -g)/figma-local/plugin"` in your terminal to get the path, then navigate there
|
|
126
|
+
- If you cloned the **repo**: go to `figma-local/plugin/` in the cloned folder
|
|
127
|
+
6. Select `manifest.json` → click **Open**
|
|
128
|
+
7. You should see **"Figma Local"** appear in your plugin list
|
|
129
|
+
8. *(Optional but recommended)* Right-click **Figma Local** in the plugin list → **Add to toolbar** for one-click access
|
|
130
|
+
|
|
131
|
+
### Step 3 — Connect and verify
|
|
132
|
+
|
|
133
|
+
1. In Figma, start the plugin: **Plugins → Development → Figma Local** (or click it in your toolbar)
|
|
134
|
+
2. You should see a small widget that says **"Figma Local"** with a connecting status
|
|
135
|
+
3. In your terminal, run:
|
|
136
|
+
|
|
137
|
+
```bash
|
|
138
|
+
fig connect --safe
|
|
139
|
+
```
|
|
140
|
+
|
|
141
|
+
4. The plugin widget should show a **green dot** and say **"Connected"**
|
|
142
|
+
5. Try reading your canvas:
|
|
143
|
+
|
|
144
|
+
```bash
|
|
145
|
+
fig read
|
|
146
|
+
```
|
|
147
|
+
|
|
148
|
+
If you see a list of frames, you're all set!
|
|
111
149
|
|
|
112
150
|
---
|
|
113
151
|
|
|
114
152
|
## Every session after that
|
|
115
153
|
|
|
116
|
-
```
|
|
117
|
-
1. Open Figma
|
|
118
|
-
2.
|
|
154
|
+
```bash
|
|
155
|
+
# 1. Open Figma Desktop and your design file
|
|
156
|
+
# 2. Click "Figma Local" in the toolbar (or Plugins → Development → Figma Local)
|
|
157
|
+
# 3. In your terminal:
|
|
158
|
+
fig-start --safe
|
|
119
159
|
```
|
|
120
160
|
|
|
121
|
-
Claude Code reads `CLAUDE.md` and knows every command automatically.
|
|
161
|
+
This connects to Figma and launches Claude Code. Claude reads `CLAUDE.md` and knows every `fig` command automatically.
|
|
122
162
|
|
|
123
163
|
---
|
|
124
164
|
|
|
@@ -249,13 +289,34 @@ fig prompt "Login" \
|
|
|
249
289
|
|
|
250
290
|
Generates ~45 tokens of structured text instead of attaching a Figma frame (300–500+ hidden tokens). **91–97% smaller input, more consistent AI output.**
|
|
251
291
|
|
|
292
|
+
### Screenshots
|
|
293
|
+
|
|
294
|
+
```bash
|
|
295
|
+
fig screenshot # Screenshot current selection
|
|
296
|
+
fig screenshot --node "123:456" # Screenshot a specific node
|
|
297
|
+
fig screenshot --link "https://..." # Screenshot from a Figma link
|
|
298
|
+
fig screenshot -o design.png -s 2 # Save to file at 2x scale
|
|
299
|
+
fig screenshot -f svg -o icon.svg # Export as SVG
|
|
300
|
+
```
|
|
301
|
+
|
|
252
302
|
### Verify & compare
|
|
253
303
|
|
|
254
304
|
```bash
|
|
255
|
-
fig verify
|
|
256
|
-
fig verify --
|
|
305
|
+
fig verify # Screenshot of selection for AI review
|
|
306
|
+
fig verify --link "https://..." # Verify from a Figma link
|
|
307
|
+
fig verify --node "123:456" # Verify a specific node
|
|
308
|
+
fig verify --compare "https://..." # Diff prototype vs Figma design → correction prompts
|
|
309
|
+
|
|
310
|
+
# Visual comparison between any two sources
|
|
311
|
+
fig compare --a selection --b "123:456" # Compare selection vs a node
|
|
312
|
+
fig compare --a design.png --b "123:456" # Compare a screenshot file vs a Figma node
|
|
313
|
+
fig compare --a design.png --b coded.png # Compare two screenshot files
|
|
314
|
+
fig compare --a-link "https://..." --b-link "https://..." # Compare two Figma links
|
|
315
|
+
fig compare --a "123:456" --b "789:012" # Compare two nodes by ID
|
|
257
316
|
```
|
|
258
317
|
|
|
318
|
+
Sources for `--a` and `--b` can be: `selection`, a node ID (`123:456`), or a file path (`screenshot.png`). Use `--a-link` / `--b-link` for Figma selection URLs.
|
|
319
|
+
|
|
259
320
|
### Export
|
|
260
321
|
|
|
261
322
|
```bash
|
|
@@ -392,7 +453,7 @@ Issues and PRs welcome. For major changes, open an issue first to discuss.
|
|
|
392
453
|
|
|
393
454
|
```bash
|
|
394
455
|
git clone https://github.com/thepreakerebi/figma-local.git
|
|
395
|
-
cd figma-
|
|
456
|
+
cd figma-local
|
|
396
457
|
npm install
|
|
397
458
|
node src/index.js --help
|
|
398
459
|
npm test
|
package/bin/fig-start
CHANGED
|
@@ -123,11 +123,14 @@ for arg in "$@"; do
|
|
|
123
123
|
done
|
|
124
124
|
|
|
125
125
|
if [ "$1" = "--setup" ]; then
|
|
126
|
-
printf "${BOLD}Enter the path to your figma-
|
|
126
|
+
printf "${BOLD}Enter the absolute path to your figma-local folder:${NC} "
|
|
127
127
|
read -r repo_path < /dev/tty
|
|
128
128
|
repo_path="${repo_path/#\~/$HOME}"
|
|
129
|
-
if [
|
|
130
|
-
|
|
129
|
+
if [[ "$repo_path" != /* ]]; then
|
|
130
|
+
repo_path="$(cd "$repo_path" 2>/dev/null && pwd)"
|
|
131
|
+
fi
|
|
132
|
+
if [ -z "$repo_path" ] || [ ! -f "$repo_path/src/index.js" ]; then
|
|
133
|
+
echo -e "${RED}Not a valid figma-local folder.${NC} Expected src/index.js inside it."
|
|
131
134
|
exit 1
|
|
132
135
|
fi
|
|
133
136
|
save_repo_path "$repo_path"
|
|
@@ -139,21 +142,34 @@ fi
|
|
|
139
142
|
REPO_PATH=$(get_repo_path)
|
|
140
143
|
|
|
141
144
|
if [ -z "$REPO_PATH" ] || [ ! -d "$REPO_PATH" ]; then
|
|
142
|
-
# Try to find it relative to this script
|
|
145
|
+
# Try to find it relative to this script (works for both git clone and npm -g installs)
|
|
143
146
|
SCRIPT_DIR="$(cd "$(dirname "$0")/.." && pwd)"
|
|
144
147
|
if [ -f "$SCRIPT_DIR/src/index.js" ]; then
|
|
145
148
|
REPO_PATH="$SCRIPT_DIR"
|
|
146
149
|
save_repo_path "$REPO_PATH"
|
|
147
150
|
else
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
151
|
+
# Try npm global install location
|
|
152
|
+
NPM_GLOBAL="$(npm root -g 2>/dev/null)/figma-local"
|
|
153
|
+
if [ -f "$NPM_GLOBAL/src/index.js" ]; then
|
|
154
|
+
REPO_PATH="$NPM_GLOBAL"
|
|
155
|
+
save_repo_path "$REPO_PATH"
|
|
156
|
+
else
|
|
157
|
+
echo -e "${YELLOW}figma-local repo not configured.${NC}"
|
|
158
|
+
echo -e "${DIM}If you installed via npm, run: fig-start --setup${NC}"
|
|
159
|
+
printf "${BOLD}Enter the absolute path to your figma-local folder:${NC} "
|
|
160
|
+
read -r REPO_PATH < /dev/tty
|
|
161
|
+
REPO_PATH="${REPO_PATH/#\~/$HOME}"
|
|
162
|
+
# Convert relative paths to absolute
|
|
163
|
+
if [[ "$REPO_PATH" != /* ]]; then
|
|
164
|
+
REPO_PATH="$(cd "$REPO_PATH" 2>/dev/null && pwd)"
|
|
165
|
+
fi
|
|
166
|
+
if [ -z "$REPO_PATH" ] || [ ! -f "$REPO_PATH/src/index.js" ]; then
|
|
167
|
+
echo -e "${RED}Not a valid figma-local folder.${NC} Expected src/index.js inside it."
|
|
168
|
+
echo -e "${DIM}Tip: use the full path, e.g. /Users/yourname/figma-local${NC}"
|
|
169
|
+
exit 1
|
|
170
|
+
fi
|
|
171
|
+
save_repo_path "$REPO_PATH"
|
|
155
172
|
fi
|
|
156
|
-
save_repo_path "$REPO_PATH"
|
|
157
173
|
fi
|
|
158
174
|
fi
|
|
159
175
|
|
package/package.json
CHANGED
package/src/index.js
CHANGED
|
@@ -5205,18 +5205,30 @@ const exp = program
|
|
|
5205
5205
|
|
|
5206
5206
|
exp
|
|
5207
5207
|
.command('screenshot')
|
|
5208
|
-
.description('Take a screenshot of selected node or
|
|
5208
|
+
.description('Take a screenshot of selected node, specific node, or from a Figma link')
|
|
5209
5209
|
.option('-o, --output <file>', 'Output file', 'screenshot.png')
|
|
5210
5210
|
.option('-s, --scale <number>', 'Export scale (1-4)', '2')
|
|
5211
5211
|
.option('-f, --format <format>', 'Format: png, jpg, svg, pdf', 'png')
|
|
5212
|
+
.option('--node <id>', 'Screenshot a specific node by ID')
|
|
5213
|
+
.option('--link <url>', 'Screenshot a node from a Figma selection link')
|
|
5212
5214
|
.action((options) => {
|
|
5213
5215
|
checkConnection();
|
|
5214
5216
|
const format = options.format.toUpperCase();
|
|
5215
5217
|
const scale = parseFloat(options.scale);
|
|
5218
|
+
let nodeResolver;
|
|
5219
|
+
if (options.link) {
|
|
5220
|
+
const nodeId = parseNodeIdFromLink(options.link);
|
|
5221
|
+
if (!nodeId) { console.error(chalk.red('✗'), 'Could not parse node ID from link'); process.exit(1); }
|
|
5222
|
+
nodeResolver = `node = await figma.getNodeByIdAsync('${nodeId}');`;
|
|
5223
|
+
} else if (options.node) {
|
|
5224
|
+
nodeResolver = `node = await figma.getNodeByIdAsync('${options.node}');`;
|
|
5225
|
+
} else {
|
|
5226
|
+
nodeResolver = `const sel = figma.currentPage.selection; node = sel.length > 0 ? sel[0] : figma.currentPage;`;
|
|
5227
|
+
}
|
|
5216
5228
|
const code = `(async () => {
|
|
5217
|
-
|
|
5218
|
-
|
|
5219
|
-
if (!node) return { error: 'No
|
|
5229
|
+
let node;
|
|
5230
|
+
${nodeResolver}
|
|
5231
|
+
if (!node) return { error: 'No node found' };
|
|
5220
5232
|
if (!('exportAsync' in node)) return { error: 'Node cannot be exported' };
|
|
5221
5233
|
const bytes = await node.exportAsync({ format: '${format}', constraint: { type: 'SCALE', value: ${scale} } });
|
|
5222
5234
|
return {
|
|
@@ -5333,14 +5345,25 @@ program
|
|
|
5333
5345
|
.option('--save [path]', 'Save as PNG file (default: /tmp/figma-verify-{id}.png)')
|
|
5334
5346
|
.option('--compare <url>', 'Compare against a prototype/preview URL and generate correction prompts')
|
|
5335
5347
|
.option('--compare-save <path>', 'Save prototype screenshot to this path when using --compare')
|
|
5348
|
+
.option('--link <url>', 'Verify a node from a Figma selection link')
|
|
5349
|
+
.option('--node <id>', 'Verify a specific node by ID')
|
|
5336
5350
|
.action(async (nodeId, options) => {
|
|
5337
5351
|
checkConnection();
|
|
5338
5352
|
const scale = parseFloat(options.scale);
|
|
5339
5353
|
const maxDim = parseInt(options.max);
|
|
5340
5354
|
|
|
5355
|
+
// Resolve node: --link > --node > positional nodeId > selection
|
|
5356
|
+
let resolvedNodeId = nodeId;
|
|
5357
|
+
if (options.link) {
|
|
5358
|
+
resolvedNodeId = parseNodeIdFromLink(options.link);
|
|
5359
|
+
if (!resolvedNodeId) { console.error(chalk.red('✗'), 'Could not parse node ID from link'); process.exit(1); }
|
|
5360
|
+
} else if (options.node) {
|
|
5361
|
+
resolvedNodeId = options.node;
|
|
5362
|
+
}
|
|
5363
|
+
|
|
5341
5364
|
const code = `(async () => {
|
|
5342
5365
|
let node;
|
|
5343
|
-
${
|
|
5366
|
+
${resolvedNodeId ? `node = await figma.getNodeByIdAsync('${resolvedNodeId}');` : `
|
|
5344
5367
|
const sel = figma.currentPage.selection;
|
|
5345
5368
|
node = sel.length > 0 ? sel[0] : null;
|
|
5346
5369
|
`}
|
|
@@ -5441,6 +5464,137 @@ program
|
|
|
5441
5464
|
}
|
|
5442
5465
|
});
|
|
5443
5466
|
|
|
5467
|
+
// ============ COMPARE (Visual Comparison) ============
|
|
5468
|
+
|
|
5469
|
+
function exportNodeScreenshot(nodeResolver, scale, maxDim) {
|
|
5470
|
+
const code = `(async () => {
|
|
5471
|
+
let node;
|
|
5472
|
+
${nodeResolver}
|
|
5473
|
+
if (!node) return { error: 'No node found' };
|
|
5474
|
+
if (!('exportAsync' in node)) return { error: 'Node cannot be exported' };
|
|
5475
|
+
const nodeWidth = node.width || 100;
|
|
5476
|
+
const nodeHeight = node.height || 100;
|
|
5477
|
+
let finalScale = ${scale};
|
|
5478
|
+
const maxNodeDim = Math.max(nodeWidth, nodeHeight);
|
|
5479
|
+
if (maxNodeDim * finalScale > ${maxDim}) finalScale = ${maxDim} / maxNodeDim;
|
|
5480
|
+
if (maxNodeDim * finalScale > 7500) finalScale = 7500 / maxNodeDim;
|
|
5481
|
+
const bytes = await node.exportAsync({ format: 'PNG', constraint: { type: 'SCALE', value: finalScale } });
|
|
5482
|
+
return {
|
|
5483
|
+
name: node.name,
|
|
5484
|
+
id: node.id,
|
|
5485
|
+
type: node.type,
|
|
5486
|
+
width: Math.round(nodeWidth * finalScale),
|
|
5487
|
+
height: Math.round(nodeHeight * finalScale),
|
|
5488
|
+
originalWidth: Math.round(nodeWidth),
|
|
5489
|
+
originalHeight: Math.round(nodeHeight),
|
|
5490
|
+
bytes: Array.from(bytes)
|
|
5491
|
+
};
|
|
5492
|
+
})()`;
|
|
5493
|
+
return figmaEvalSync(code);
|
|
5494
|
+
}
|
|
5495
|
+
|
|
5496
|
+
program
|
|
5497
|
+
.command('compare')
|
|
5498
|
+
.description('Compare two things visually: screenshots, Figma nodes, or a mix. Outputs both images for AI analysis.')
|
|
5499
|
+
.option('--a <source>', 'First source: file path, node ID, or "selection"', 'selection')
|
|
5500
|
+
.option('--b <source>', 'Second source: file path, node ID, or Figma link')
|
|
5501
|
+
.option('--a-link <url>', 'First source from a Figma selection link')
|
|
5502
|
+
.option('--b-link <url>', 'Second source from a Figma selection link')
|
|
5503
|
+
.option('-s, --scale <number>', 'Export scale for Figma nodes', '1')
|
|
5504
|
+
.option('--max <pixels>', 'Max dimension for exports', '2000')
|
|
5505
|
+
.option('--save-dir <dir>', 'Directory to save comparison images', '/tmp')
|
|
5506
|
+
.addHelpText('after', `
|
|
5507
|
+
Examples:
|
|
5508
|
+
fig compare --a selection --b "123:456" Compare selection vs a node
|
|
5509
|
+
fig compare --a design.png --b "123:456" Compare a screenshot file vs a Figma node
|
|
5510
|
+
fig compare --a design.png --b coded.png Compare two screenshot files
|
|
5511
|
+
fig compare --a-link "https://..." --b-link "https://..." Compare two Figma links
|
|
5512
|
+
fig compare --a selection --b-link "https://..." Compare selection vs a Figma link
|
|
5513
|
+
fig compare --a "123:456" --b "789:012" Compare two nodes by ID
|
|
5514
|
+
`)
|
|
5515
|
+
.action((options) => {
|
|
5516
|
+
checkConnection();
|
|
5517
|
+
const scale = parseFloat(options.scale);
|
|
5518
|
+
const maxDim = parseInt(options.max);
|
|
5519
|
+
const saveDir = options.saveDir;
|
|
5520
|
+
const timestamp = Date.now();
|
|
5521
|
+
|
|
5522
|
+
function resolveSource(source, linkOpt, label) {
|
|
5523
|
+
// If it's a --link option
|
|
5524
|
+
if (linkOpt) {
|
|
5525
|
+
const nodeId = parseNodeIdFromLink(linkOpt);
|
|
5526
|
+
if (!nodeId) { console.error(chalk.red('✗'), `Could not parse node ID from ${label} link`); process.exit(1); }
|
|
5527
|
+
const result = exportNodeScreenshot(`node = await figma.getNodeByIdAsync('${nodeId}');`, scale, maxDim);
|
|
5528
|
+
if (result.error) { console.error(chalk.red('✗'), `${label}: ${result.error}`); process.exit(1); }
|
|
5529
|
+
const filePath = `${saveDir}/figma-compare-${label}-${timestamp}.png`;
|
|
5530
|
+
writeFileSync(filePath, Buffer.from(result.bytes));
|
|
5531
|
+
return { type: 'figma-node', name: result.name, id: result.id, nodeType: result.type, width: result.width, height: result.height, originalWidth: result.originalWidth, originalHeight: result.originalHeight, path: filePath };
|
|
5532
|
+
}
|
|
5533
|
+
|
|
5534
|
+
// File path (existing screenshot)
|
|
5535
|
+
if (source && existsSync(source)) {
|
|
5536
|
+
return { type: 'file', name: source.split('/').pop(), path: source };
|
|
5537
|
+
}
|
|
5538
|
+
|
|
5539
|
+
// "selection"
|
|
5540
|
+
if (source === 'selection') {
|
|
5541
|
+
const result = exportNodeScreenshot(`const sel = figma.currentPage.selection; node = sel.length > 0 ? sel[0] : null;`, scale, maxDim);
|
|
5542
|
+
if (result.error) { console.error(chalk.red('✗'), `${label}: ${result.error}`); process.exit(1); }
|
|
5543
|
+
const filePath = `${saveDir}/figma-compare-${label}-${timestamp}.png`;
|
|
5544
|
+
writeFileSync(filePath, Buffer.from(result.bytes));
|
|
5545
|
+
return { type: 'figma-node', name: result.name, id: result.id, nodeType: result.type, width: result.width, height: result.height, originalWidth: result.originalWidth, originalHeight: result.originalHeight, path: filePath };
|
|
5546
|
+
}
|
|
5547
|
+
|
|
5548
|
+
// Node ID (contains ":")
|
|
5549
|
+
if (source && source.includes(':')) {
|
|
5550
|
+
const result = exportNodeScreenshot(`node = await figma.getNodeByIdAsync('${source}');`, scale, maxDim);
|
|
5551
|
+
if (result.error) { console.error(chalk.red('✗'), `${label}: ${result.error}`); process.exit(1); }
|
|
5552
|
+
const filePath = `${saveDir}/figma-compare-${label}-${timestamp}.png`;
|
|
5553
|
+
writeFileSync(filePath, Buffer.from(result.bytes));
|
|
5554
|
+
return { type: 'figma-node', name: result.name, id: result.id, nodeType: result.type, width: result.width, height: result.height, originalWidth: result.originalWidth, originalHeight: result.originalHeight, path: filePath };
|
|
5555
|
+
}
|
|
5556
|
+
|
|
5557
|
+
console.error(chalk.red('✗'), `${label}: "${source}" is not a valid file path, node ID, or "selection"`);
|
|
5558
|
+
process.exit(1);
|
|
5559
|
+
}
|
|
5560
|
+
|
|
5561
|
+
const sourceA = resolveSource(options.a, options.aLink, 'a');
|
|
5562
|
+
const sourceB = resolveSource(options.b, options.bLink, 'b');
|
|
5563
|
+
|
|
5564
|
+
console.log(chalk.bold('\n## Visual Comparison\n'));
|
|
5565
|
+
console.log(chalk.cyan('Source A:'), sourceA.name, sourceA.type === 'figma-node' ? `(${sourceA.nodeType} ${sourceA.id}, ${sourceA.originalWidth}x${sourceA.originalHeight})` : '(file)');
|
|
5566
|
+
console.log(chalk.cyan('Source B:'), sourceB.name, sourceB.type === 'figma-node' ? `(${sourceB.nodeType} ${sourceB.id}, ${sourceB.originalWidth}x${sourceB.originalHeight})` : '(file)');
|
|
5567
|
+
console.log('');
|
|
5568
|
+
console.log(chalk.green('Image A:'), sourceA.path);
|
|
5569
|
+
console.log(chalk.green('Image B:'), sourceB.path);
|
|
5570
|
+
console.log('');
|
|
5571
|
+
|
|
5572
|
+
// Output structured data for AI agents
|
|
5573
|
+
console.log(JSON.stringify({
|
|
5574
|
+
mode: 'visual-comparison',
|
|
5575
|
+
sourceA: { ...sourceA, bytes: undefined },
|
|
5576
|
+
sourceB: { ...sourceB, bytes: undefined },
|
|
5577
|
+
instructions: [
|
|
5578
|
+
`1. Open and examine Image A: ${sourceA.path}`,
|
|
5579
|
+
`2. Open and examine Image B: ${sourceB.path}`,
|
|
5580
|
+
'3. Compare them visually for differences in:',
|
|
5581
|
+
' - Layout and spacing (padding, margins, gaps)',
|
|
5582
|
+
' - Colors (backgrounds, text, borders)',
|
|
5583
|
+
' - Typography (font size, weight, line-height)',
|
|
5584
|
+
' - Border radius and shadows',
|
|
5585
|
+
' - Missing or extra elements',
|
|
5586
|
+
' - Alignment and positioning',
|
|
5587
|
+
'4. Output a structured gap report with specific differences',
|
|
5588
|
+
'5. For each difference, provide the exact values from both sources',
|
|
5589
|
+
],
|
|
5590
|
+
gapReportTemplate: {
|
|
5591
|
+
matches: '(list elements that match between A and B)',
|
|
5592
|
+
differences: '(table: element | property | value_in_A | value_in_B | severity)',
|
|
5593
|
+
summary: '(brief overall assessment: how closely do they match)',
|
|
5594
|
+
}
|
|
5595
|
+
}, null, 2));
|
|
5596
|
+
});
|
|
5597
|
+
|
|
5444
5598
|
// ============ EVAL ============
|
|
5445
5599
|
|
|
5446
5600
|
program
|