@bilalba/fig-mcp 1.0.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 +112 -0
- package/dist/compare-get-vector.d.ts +2 -0
- package/dist/compare-get-vector.d.ts.map +1 -0
- package/dist/compare-get-vector.js +124 -0
- package/dist/compare-get-vector.js.map +1 -0
- package/dist/compare-mcp-vs-direct.d.ts +2 -0
- package/dist/compare-mcp-vs-direct.d.ts.map +1 -0
- package/dist/compare-mcp-vs-direct.js +173 -0
- package/dist/compare-mcp-vs-direct.js.map +1 -0
- package/dist/compare-renderers.d.ts +2 -0
- package/dist/compare-renderers.d.ts.map +1 -0
- package/dist/compare-renderers.js +110 -0
- package/dist/compare-renderers.js.map +1 -0
- package/dist/debug/debug-stroke-geom.d.ts +2 -0
- package/dist/debug/debug-stroke-geom.d.ts.map +1 -0
- package/dist/debug/debug-stroke-geom.js +67 -0
- package/dist/debug/debug-stroke-geom.js.map +1 -0
- package/dist/debug/debug-transforms.d.ts +2 -0
- package/dist/debug/debug-transforms.d.ts.map +1 -0
- package/dist/debug/debug-transforms.js +97 -0
- package/dist/debug/debug-transforms.js.map +1 -0
- package/dist/debug/debug-vertex.d.ts +2 -0
- package/dist/debug/debug-vertex.d.ts.map +1 -0
- package/dist/debug/debug-vertex.js +72 -0
- package/dist/debug/debug-vertex.js.map +1 -0
- package/dist/debug-group.d.ts +5 -0
- package/dist/debug-group.d.ts.map +1 -0
- package/dist/debug-group.js +44 -0
- package/dist/debug-group.js.map +1 -0
- package/dist/debug-stroke-geom.d.ts +2 -0
- package/dist/debug-stroke-geom.d.ts.map +1 -0
- package/dist/debug-stroke-geom.js +67 -0
- package/dist/debug-stroke-geom.js.map +1 -0
- package/dist/debug-transforms.d.ts +2 -0
- package/dist/debug-transforms.d.ts.map +1 -0
- package/dist/debug-transforms.js +97 -0
- package/dist/debug-transforms.js.map +1 -0
- package/dist/debug-vertex.d.ts +2 -0
- package/dist/debug-vertex.d.ts.map +1 -0
- package/dist/debug-vertex.js +72 -0
- package/dist/debug-vertex.js.map +1 -0
- package/dist/decode-vector-network.d.ts +5 -0
- package/dist/decode-vector-network.d.ts.map +1 -0
- package/dist/decode-vector-network.js +160 -0
- package/dist/decode-vector-network.js.map +1 -0
- package/dist/experimental/paint-utils.d.ts +35 -0
- package/dist/experimental/paint-utils.d.ts.map +1 -0
- package/dist/experimental/paint-utils.js +105 -0
- package/dist/experimental/paint-utils.js.map +1 -0
- package/dist/experimental/render-screen-v2.d.ts +32 -0
- package/dist/experimental/render-screen-v2.d.ts.map +1 -0
- package/dist/experimental/render-screen-v2.js +366 -0
- package/dist/experimental/render-screen-v2.js.map +1 -0
- package/dist/experimental/render-screen.d.ts +26 -0
- package/dist/experimental/render-screen.d.ts.map +1 -0
- package/dist/experimental/render-screen.js +547 -0
- package/dist/experimental/render-screen.js.map +1 -0
- package/dist/experimental/render-types.d.ts +43 -0
- package/dist/experimental/render-types.d.ts.map +1 -0
- package/dist/experimental/render-types.js +22 -0
- package/dist/experimental/render-types.js.map +1 -0
- package/dist/experimental/render-utils.d.ts +38 -0
- package/dist/experimental/render-utils.d.ts.map +1 -0
- package/dist/experimental/render-utils.js +126 -0
- package/dist/experimental/render-utils.js.map +1 -0
- package/dist/experimental/screenshot.d.ts +11 -0
- package/dist/experimental/screenshot.d.ts.map +1 -0
- package/dist/experimental/screenshot.js +26 -0
- package/dist/experimental/screenshot.js.map +1 -0
- package/dist/experimental/vector-renderer.d.ts +31 -0
- package/dist/experimental/vector-renderer.d.ts.map +1 -0
- package/dist/experimental/vector-renderer.js +427 -0
- package/dist/experimental/vector-renderer.js.map +1 -0
- package/dist/explore-images.d.ts +9 -0
- package/dist/explore-images.d.ts.map +1 -0
- package/dist/explore-images.js +307 -0
- package/dist/explore-images.js.map +1 -0
- package/dist/http-server.d.ts +8 -0
- package/dist/http-server.d.ts.map +1 -0
- package/dist/http-server.js +95 -0
- package/dist/http-server.js.map +1 -0
- package/dist/index.d.ts +9 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +34 -0
- package/dist/index.js.map +1 -0
- package/dist/inspect-fig.d.ts +16 -0
- package/dist/inspect-fig.d.ts.map +1 -0
- package/dist/inspect-fig.js +134 -0
- package/dist/inspect-fig.js.map +1 -0
- package/dist/inspect-frame.d.ts +2 -0
- package/dist/inspect-frame.d.ts.map +1 -0
- package/dist/inspect-frame.js +90 -0
- package/dist/inspect-frame.js.map +1 -0
- package/dist/inspect-nodes.d.ts +5 -0
- package/dist/inspect-nodes.d.ts.map +1 -0
- package/dist/inspect-nodes.js +193 -0
- package/dist/inspect-nodes.js.map +1 -0
- package/dist/mcp/server.d.ts +38 -0
- package/dist/mcp/server.d.ts.map +1 -0
- package/dist/mcp/server.js +1524 -0
- package/dist/mcp/server.js.map +1 -0
- package/dist/parser/fig-reader.d.ts +29 -0
- package/dist/parser/fig-reader.d.ts.map +1 -0
- package/dist/parser/fig-reader.js +182 -0
- package/dist/parser/fig-reader.js.map +1 -0
- package/dist/parser/index.d.ts +48 -0
- package/dist/parser/index.d.ts.map +1 -0
- package/dist/parser/index.js +106 -0
- package/dist/parser/index.js.map +1 -0
- package/dist/parser/kiwi-parser.d.ts +66 -0
- package/dist/parser/kiwi-parser.d.ts.map +1 -0
- package/dist/parser/kiwi-parser.js +491 -0
- package/dist/parser/kiwi-parser.js.map +1 -0
- package/dist/parser/layout-inference.d.ts +63 -0
- package/dist/parser/layout-inference.d.ts.map +1 -0
- package/dist/parser/layout-inference.js +446 -0
- package/dist/parser/layout-inference.js.map +1 -0
- package/dist/parser/types.d.ts +286 -0
- package/dist/parser/types.d.ts.map +1 -0
- package/dist/parser/types.js +6 -0
- package/dist/parser/types.js.map +1 -0
- package/dist/render-single.d.ts +2 -0
- package/dist/render-single.d.ts.map +1 -0
- package/dist/render-single.js +53 -0
- package/dist/render-single.js.map +1 -0
- package/dist/renderer/index.d.ts +16 -0
- package/dist/renderer/index.d.ts.map +1 -0
- package/dist/renderer/index.js +18 -0
- package/dist/renderer/index.js.map +1 -0
- package/dist/renderer/paint-utils.d.ts +35 -0
- package/dist/renderer/paint-utils.d.ts.map +1 -0
- package/dist/renderer/paint-utils.js +105 -0
- package/dist/renderer/paint-utils.js.map +1 -0
- package/dist/renderer/render-screen.d.ts +26 -0
- package/dist/renderer/render-screen.d.ts.map +1 -0
- package/dist/renderer/render-screen.js +547 -0
- package/dist/renderer/render-screen.js.map +1 -0
- package/dist/renderer/render-types.d.ts +43 -0
- package/dist/renderer/render-types.d.ts.map +1 -0
- package/dist/renderer/render-types.js +22 -0
- package/dist/renderer/render-types.js.map +1 -0
- package/dist/renderer/render-utils.d.ts +38 -0
- package/dist/renderer/render-utils.d.ts.map +1 -0
- package/dist/renderer/render-utils.js +126 -0
- package/dist/renderer/render-utils.js.map +1 -0
- package/dist/renderer/screenshot.d.ts +11 -0
- package/dist/renderer/screenshot.d.ts.map +1 -0
- package/dist/renderer/screenshot.js +26 -0
- package/dist/renderer/screenshot.js.map +1 -0
- package/dist/renderer/vector-renderer.d.ts +31 -0
- package/dist/renderer/vector-renderer.d.ts.map +1 -0
- package/dist/renderer/vector-renderer.js +427 -0
- package/dist/renderer/vector-renderer.js.map +1 -0
- package/dist/shared-config.d.ts +9 -0
- package/dist/shared-config.d.ts.map +1 -0
- package/dist/shared-config.js +9 -0
- package/dist/shared-config.js.map +1 -0
- package/dist/test-parser.d.ts +3 -0
- package/dist/test-parser.d.ts.map +1 -0
- package/dist/test-parser.js +74 -0
- package/dist/test-parser.js.map +1 -0
- package/dist/test-render-v2.d.ts +5 -0
- package/dist/test-render-v2.d.ts.map +1 -0
- package/dist/test-render-v2.js +76 -0
- package/dist/test-render-v2.js.map +1 -0
- package/dist/test-render.d.ts +5 -0
- package/dist/test-render.d.ts.map +1 -0
- package/dist/test-render.js +76 -0
- package/dist/test-render.js.map +1 -0
- package/dist/vector-export.d.ts +52 -0
- package/dist/vector-export.d.ts.map +1 -0
- package/dist/vector-export.js +628 -0
- package/dist/vector-export.js.map +1 -0
- package/dist/web-viewer/build-client.d.ts +6 -0
- package/dist/web-viewer/build-client.d.ts.map +1 -0
- package/dist/web-viewer/build-client.js +36 -0
- package/dist/web-viewer/build-client.js.map +1 -0
- package/dist/web-viewer/client/viewer.d.ts +7 -0
- package/dist/web-viewer/client/viewer.d.ts.map +1 -0
- package/dist/web-viewer/client/viewer.js +873 -0
- package/dist/web-viewer/client/viewer.js.map +1 -0
- package/dist/web-viewer/server.d.ts +16 -0
- package/dist/web-viewer/server.d.ts.map +1 -0
- package/dist/web-viewer/server.js +420 -0
- package/dist/web-viewer/server.js.map +1 -0
- package/package.json +66 -0
package/README.md
ADDED
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
# Fig MCP Server
|
|
2
|
+
|
|
3
|
+
An MCP (Model Context Protocol) server for parsing `.fig` files. This enables AI assistants to understand and extract design information from the `.fig` file format.
|
|
4
|
+
|
|
5
|
+
## Features
|
|
6
|
+
|
|
7
|
+
- Parse `.fig` files without API access
|
|
8
|
+
- Extract document structure, nodes, and hierarchy
|
|
9
|
+
- Infer layout properties (flexbox-like direction, gap, padding, alignment)
|
|
10
|
+
- Extract colors, text content, and styling information
|
|
11
|
+
- Find nodes by type or name
|
|
12
|
+
- Get detailed node information for implementation
|
|
13
|
+
|
|
14
|
+
## Installation
|
|
15
|
+
|
|
16
|
+
```bash
|
|
17
|
+
npm install
|
|
18
|
+
npm run build
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
## Usage
|
|
22
|
+
|
|
23
|
+
### As MCP Server
|
|
24
|
+
|
|
25
|
+
Add to your MCP client configuration:
|
|
26
|
+
|
|
27
|
+
```json
|
|
28
|
+
{
|
|
29
|
+
"mcpServers": {
|
|
30
|
+
"fig-mcp": {
|
|
31
|
+
"command": "node",
|
|
32
|
+
"args": ["/path/to/fig-mcp/dist/index.js"]
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
### CLI Inspector
|
|
39
|
+
|
|
40
|
+
```bash
|
|
41
|
+
# Show document structure
|
|
42
|
+
npx tsx src/inspect-fig.ts design.fig summary
|
|
43
|
+
|
|
44
|
+
# Show kiwi schema
|
|
45
|
+
npx tsx src/inspect-fig.ts design.fig schema
|
|
46
|
+
|
|
47
|
+
# Output simplified JSON
|
|
48
|
+
npx tsx src/inspect-fig.ts design.fig json
|
|
49
|
+
|
|
50
|
+
# Show node statistics
|
|
51
|
+
npx tsx src/inspect-fig.ts design.fig stats
|
|
52
|
+
|
|
53
|
+
# List archive contents
|
|
54
|
+
npx tsx src/inspect-fig.ts design.fig list
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
## MCP Tools
|
|
58
|
+
|
|
59
|
+
| Tool | Description |
|
|
60
|
+
|------|-------------|
|
|
61
|
+
| `parse_fig_file` | Parse and return simplified document structure |
|
|
62
|
+
| `get_document_summary` | Text tree of document structure |
|
|
63
|
+
| `find_nodes` | Find nodes by type or name |
|
|
64
|
+
| `get_node_details` | Get details for a node path |
|
|
65
|
+
| `get_layout_info` | Get inferred layout properties |
|
|
66
|
+
| `list_pages` | List all pages |
|
|
67
|
+
| `get_page_contents` | Get contents of a page |
|
|
68
|
+
| `get_text_content` | Extract text content |
|
|
69
|
+
| `get_colors` | Extract color palette |
|
|
70
|
+
|
|
71
|
+
## How It Works
|
|
72
|
+
|
|
73
|
+
1. `.fig` files are ZIP archives containing `canvas.fig` (binary data), `meta.json`, and images
|
|
74
|
+
2. The `canvas.fig` uses Evan Wallace's [kiwi](https://github.com/evanw/kiwi) binary format
|
|
75
|
+
3. The kiwi schema is embedded in each file and extracted at parse time
|
|
76
|
+
4. Document data is decoded using the compiled schema
|
|
77
|
+
5. Layout properties are inferred from node positions and auto-layout settings
|
|
78
|
+
|
|
79
|
+
## Project Structure
|
|
80
|
+
|
|
81
|
+
```
|
|
82
|
+
fig-mcp/
|
|
83
|
+
├── src/
|
|
84
|
+
│ ├── parser/ # Fig file parsing
|
|
85
|
+
│ │ ├── fig-reader.ts # ZIP extraction
|
|
86
|
+
│ │ ├── kiwi-parser.ts # Binary parsing
|
|
87
|
+
│ │ ├── layout-inference.ts
|
|
88
|
+
│ │ └── types.ts
|
|
89
|
+
│ ├── mcp/
|
|
90
|
+
│ │ └── server.ts # MCP server
|
|
91
|
+
│ ├── index.ts # Entry point
|
|
92
|
+
│ └── inspect-fig.ts # CLI tool
|
|
93
|
+
├── kiwi/ # Cloned kiwi library
|
|
94
|
+
├── CLAUDE.md # Development guide
|
|
95
|
+
└── TODO.md # Project roadmap
|
|
96
|
+
```
|
|
97
|
+
|
|
98
|
+
## Limitations
|
|
99
|
+
|
|
100
|
+
- The `.fig` format is undocumented and may change
|
|
101
|
+
- Some complex properties (vector networks, gradients) may not be fully parsed
|
|
102
|
+
- Blob data (embedded images in fills) is not decoded
|
|
103
|
+
- This is for local `.fig` files only (use a cloud API for hosted files)
|
|
104
|
+
|
|
105
|
+
## License
|
|
106
|
+
|
|
107
|
+
MIT
|
|
108
|
+
|
|
109
|
+
## Credits
|
|
110
|
+
|
|
111
|
+
- [Kiwi](https://github.com/evanw/kiwi) by Evan Wallace - Binary format library
|
|
112
|
+
- [MCP SDK](https://github.com/modelcontextprotocol/typescript-sdk) - Protocol implementation
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"compare-get-vector.d.ts","sourceRoot":"","sources":["../src/compare-get-vector.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,124 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Compare get_vector (nodeToSvg) vs renderScreen
|
|
3
|
+
*/
|
|
4
|
+
import { readFigFile } from "./parser/index.js";
|
|
5
|
+
import { parseCanvasFig, extractDocumentTree, formatGUID } from "./parser/kiwi-parser.js";
|
|
6
|
+
import { nodeToSvg } from "./vector-export.js";
|
|
7
|
+
import { renderScreen } from "./renderer/index.js";
|
|
8
|
+
import { writeFileSync } from "fs";
|
|
9
|
+
const FILE_PATH = "/Users/billy/Downloads/AutoDevice (Copy).fig";
|
|
10
|
+
const NODE_ID = process.argv[2] || "457:1681";
|
|
11
|
+
function normalizeNodeId(nodeId) {
|
|
12
|
+
let normalized = nodeId.trim();
|
|
13
|
+
if (/^\d+-\d+$/.test(normalized)) {
|
|
14
|
+
normalized = normalized.replace('-', ':');
|
|
15
|
+
}
|
|
16
|
+
return normalized;
|
|
17
|
+
}
|
|
18
|
+
async function compare() {
|
|
19
|
+
const normalizedId = normalizeNodeId(NODE_ID);
|
|
20
|
+
console.log("Node ID:", normalizedId);
|
|
21
|
+
// Parse the file
|
|
22
|
+
const archive = await readFigFile(FILE_PATH);
|
|
23
|
+
const parsed = parseCanvasFig(archive.canvasFig);
|
|
24
|
+
const doc = extractDocumentTree(parsed.message);
|
|
25
|
+
if (!doc) {
|
|
26
|
+
console.log("Failed to extract document");
|
|
27
|
+
return;
|
|
28
|
+
}
|
|
29
|
+
const blobs = parsed.message["blobs"];
|
|
30
|
+
// Build node index
|
|
31
|
+
const nodeIndex = new Map();
|
|
32
|
+
function indexNode(node) {
|
|
33
|
+
nodeIndex.set(formatGUID(node.guid), node);
|
|
34
|
+
if (node.children) {
|
|
35
|
+
for (const child of node.children) {
|
|
36
|
+
indexNode(child);
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
indexNode(doc);
|
|
41
|
+
const node = nodeIndex.get(normalizedId);
|
|
42
|
+
if (!node) {
|
|
43
|
+
console.log("Node not found:", normalizedId);
|
|
44
|
+
return;
|
|
45
|
+
}
|
|
46
|
+
const sceneNode = node;
|
|
47
|
+
console.log("\n=== NODE INFO ===");
|
|
48
|
+
console.log("Name:", node.name);
|
|
49
|
+
console.log("Type:", node.type);
|
|
50
|
+
console.log("x:", sceneNode.x);
|
|
51
|
+
console.log("y:", sceneNode.y);
|
|
52
|
+
console.log("width:", sceneNode.width);
|
|
53
|
+
console.log("height:", sceneNode.height);
|
|
54
|
+
console.log("Children:", node.children?.length || 0);
|
|
55
|
+
// === get_vector path (nodeToSvg) ===
|
|
56
|
+
console.log("\n=== get_vector (nodeToSvg) ===");
|
|
57
|
+
const vectorResult = nodeToSvg(node, blobs, { includeStyles: true });
|
|
58
|
+
console.log("Size:", vectorResult.width, "x", vectorResult.height);
|
|
59
|
+
console.log("ViewBox:", vectorResult.viewBox);
|
|
60
|
+
// === renderScreen path ===
|
|
61
|
+
console.log("\n=== renderScreen ===");
|
|
62
|
+
const screenResult = renderScreen(node, undefined, blobs, {
|
|
63
|
+
includeFills: true,
|
|
64
|
+
includeStrokes: true,
|
|
65
|
+
includeText: true,
|
|
66
|
+
background: "#1a1a1a",
|
|
67
|
+
});
|
|
68
|
+
console.log("Size:", screenResult.width, "x", screenResult.height);
|
|
69
|
+
// Save outputs
|
|
70
|
+
writeFileSync("output/get-vector-output.svg", vectorResult.svgString);
|
|
71
|
+
writeFileSync("output/render-output.svg", screenResult.svg);
|
|
72
|
+
const html = `<!DOCTYPE html>
|
|
73
|
+
<html>
|
|
74
|
+
<head>
|
|
75
|
+
<title>get_vector vs renderScreen - ${NODE_ID}</title>
|
|
76
|
+
<style>
|
|
77
|
+
body { margin: 0; padding: 40px; background: #0d0d0d; color: #fff; font-family: sans-serif; }
|
|
78
|
+
h1 { font-size: 24px; margin-bottom: 8px; }
|
|
79
|
+
.info { color: #888; font-size: 14px; margin-bottom: 24px; }
|
|
80
|
+
.container { display: flex; gap: 40px; flex-wrap: wrap; }
|
|
81
|
+
.preview { background: #1a1a1a; border-radius: 12px; padding: 40px; }
|
|
82
|
+
.preview h2 { font-size: 14px; color: #666; margin-bottom: 20px; }
|
|
83
|
+
.preview.good h2 { color: #4f4; }
|
|
84
|
+
.preview.bad h2 { color: #f44; }
|
|
85
|
+
.scaled svg { width: 200px; height: auto; }
|
|
86
|
+
pre { font-size: 10px; background: #111; padding: 10px; overflow: auto; max-height: 400px; white-space: pre-wrap; word-break: break-all; }
|
|
87
|
+
</style>
|
|
88
|
+
</head>
|
|
89
|
+
<body>
|
|
90
|
+
<h1>get_vector vs renderScreen: ${NODE_ID}</h1>
|
|
91
|
+
<p class="info">Node: ${node.name} (${node.type}) | x=${sceneNode.x} y=${sceneNode.y} w=${sceneNode.width} h=${sceneNode.height}</p>
|
|
92
|
+
|
|
93
|
+
<div class="container">
|
|
94
|
+
<div class="preview bad">
|
|
95
|
+
<h2>get_vector (nodeToSvg) - ${vectorResult.width.toFixed(1)} x ${vectorResult.height.toFixed(1)}</h2>
|
|
96
|
+
<div class="scaled">${vectorResult.svgString}</div>
|
|
97
|
+
</div>
|
|
98
|
+
|
|
99
|
+
<div class="preview good">
|
|
100
|
+
<h2>renderScreen - ${screenResult.width.toFixed(1)} x ${screenResult.height.toFixed(1)}</h2>
|
|
101
|
+
<div class="scaled">${screenResult.svg.replace('<?xml version="1.0" encoding="UTF-8"?>', '')}</div>
|
|
102
|
+
</div>
|
|
103
|
+
</div>
|
|
104
|
+
|
|
105
|
+
<h2 style="margin-top: 40px;">Raw SVG</h2>
|
|
106
|
+
<div class="container">
|
|
107
|
+
<div class="preview" style="max-width: 45%;">
|
|
108
|
+
<h2>get_vector SVG</h2>
|
|
109
|
+
<pre>${vectorResult.svgString.replace(/</g, '<').replace(/>/g, '>')}</pre>
|
|
110
|
+
</div>
|
|
111
|
+
<div class="preview" style="max-width: 45%;">
|
|
112
|
+
<h2>renderScreen SVG</h2>
|
|
113
|
+
<pre>${screenResult.svg.replace(/</g, '<').replace(/>/g, '>')}</pre>
|
|
114
|
+
</div>
|
|
115
|
+
</div>
|
|
116
|
+
</body>
|
|
117
|
+
</html>`;
|
|
118
|
+
writeFileSync("output/compare.html", html);
|
|
119
|
+
console.log("\nSaved: output/get-vector-output.svg");
|
|
120
|
+
console.log("Saved: output/render-output.svg");
|
|
121
|
+
console.log("Saved: output/compare.html");
|
|
122
|
+
}
|
|
123
|
+
compare().catch(console.error);
|
|
124
|
+
//# sourceMappingURL=compare-get-vector.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"compare-get-vector.js","sourceRoot":"","sources":["../src/compare-get-vector.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"compare-mcp-vs-direct.d.ts","sourceRoot":"","sources":["../src/compare-mcp-vs-direct.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,173 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Compare MCP server's render_screen logic vs direct renderScreen call
|
|
3
|
+
*/
|
|
4
|
+
import { readFigFile, buildNodeIdIndex } from "./parser/index.js";
|
|
5
|
+
import { parseCanvasFig, extractDocumentTree } from "./parser/kiwi-parser.js";
|
|
6
|
+
import { renderScreen } from "./renderer/index.js";
|
|
7
|
+
import { writeFileSync } from "fs";
|
|
8
|
+
const FILE_PATH = "/Users/billy/Downloads/AutoDevice (Copy).fig";
|
|
9
|
+
const NODE_ID = process.argv[2] || "457:1681";
|
|
10
|
+
// Simulate MCP server's getOrParseFigFile
|
|
11
|
+
async function mcpParse(filePath) {
|
|
12
|
+
const { parseFigFile } = await import("./parser/index.js");
|
|
13
|
+
const parsed = await parseFigFile(filePath);
|
|
14
|
+
const nodeIdIndex = buildNodeIdIndex(parsed.document);
|
|
15
|
+
return {
|
|
16
|
+
document: parsed.document,
|
|
17
|
+
images: parsed.images,
|
|
18
|
+
blobs: parsed.blobs,
|
|
19
|
+
nodeIdIndex,
|
|
20
|
+
};
|
|
21
|
+
}
|
|
22
|
+
// Direct parse like render-single.ts
|
|
23
|
+
async function directParse(filePath) {
|
|
24
|
+
const archive = await readFigFile(filePath);
|
|
25
|
+
const parsed = parseCanvasFig(archive.canvasFig);
|
|
26
|
+
const doc = extractDocumentTree(parsed.message);
|
|
27
|
+
const blobs = parsed.message["blobs"];
|
|
28
|
+
return { doc, blobs };
|
|
29
|
+
}
|
|
30
|
+
function normalizeNodeId(nodeId) {
|
|
31
|
+
let normalized = nodeId.trim();
|
|
32
|
+
if (/^\d+-\d+$/.test(normalized)) {
|
|
33
|
+
normalized = normalized.replace('-', ':');
|
|
34
|
+
}
|
|
35
|
+
return normalized;
|
|
36
|
+
}
|
|
37
|
+
async function compare() {
|
|
38
|
+
const normalizedId = normalizeNodeId(NODE_ID);
|
|
39
|
+
console.log("Node ID:", normalizedId);
|
|
40
|
+
// === MCP SERVER PATH ===
|
|
41
|
+
console.log("\n=== MCP SERVER PATH ===");
|
|
42
|
+
const mcpData = await mcpParse(FILE_PATH);
|
|
43
|
+
const mcpNode = mcpData.nodeIdIndex.get(normalizedId);
|
|
44
|
+
if (!mcpNode) {
|
|
45
|
+
console.log("MCP: Node not found");
|
|
46
|
+
return;
|
|
47
|
+
}
|
|
48
|
+
console.log("MCP Node found:", mcpNode.name, mcpNode.type);
|
|
49
|
+
console.log("MCP blobs count:", mcpData.blobs?.length || 0);
|
|
50
|
+
console.log("MCP images count:", mcpData.images?.size || 0);
|
|
51
|
+
// MCP render_screen call (line 1608 in server.ts)
|
|
52
|
+
const mcpResult = renderScreen(mcpNode, mcpData.images, mcpData.blobs, {
|
|
53
|
+
includeFills: true,
|
|
54
|
+
includeStrokes: true,
|
|
55
|
+
includeText: true,
|
|
56
|
+
background: "#1a1a1a",
|
|
57
|
+
});
|
|
58
|
+
console.log("MCP Result size:", mcpResult.width, "x", mcpResult.height);
|
|
59
|
+
console.log("MCP Warnings:", mcpResult.warnings);
|
|
60
|
+
// === DIRECT PATH (render-single.ts) ===
|
|
61
|
+
console.log("\n=== DIRECT PATH (render-single.ts) ===");
|
|
62
|
+
const directData = await directParse(FILE_PATH);
|
|
63
|
+
if (!directData.doc) {
|
|
64
|
+
console.log("Direct: Failed to extract document");
|
|
65
|
+
return;
|
|
66
|
+
}
|
|
67
|
+
// Build index like render-single.ts does
|
|
68
|
+
const { formatGUID } = await import("./parser/kiwi-parser.js");
|
|
69
|
+
const directIndex = new Map();
|
|
70
|
+
function indexNode(node) {
|
|
71
|
+
directIndex.set(formatGUID(node.guid), node);
|
|
72
|
+
if (node.children) {
|
|
73
|
+
for (const child of node.children) {
|
|
74
|
+
indexNode(child);
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
indexNode(directData.doc);
|
|
79
|
+
const directNode = directIndex.get(normalizedId);
|
|
80
|
+
if (!directNode) {
|
|
81
|
+
console.log("Direct: Node not found");
|
|
82
|
+
return;
|
|
83
|
+
}
|
|
84
|
+
console.log("Direct Node found:", directNode.name, directNode.type);
|
|
85
|
+
console.log("Direct blobs count:", directData.blobs?.length || 0);
|
|
86
|
+
// Direct renderScreen call (like render-single.ts line 46)
|
|
87
|
+
const directResult = renderScreen(directNode, undefined, directData.blobs, {
|
|
88
|
+
includeFills: true,
|
|
89
|
+
includeStrokes: true,
|
|
90
|
+
includeText: true,
|
|
91
|
+
background: "#1a1a1a",
|
|
92
|
+
});
|
|
93
|
+
console.log("Direct Result size:", directResult.width, "x", directResult.height);
|
|
94
|
+
console.log("Direct Warnings:", directResult.warnings);
|
|
95
|
+
// === Compare nodes ===
|
|
96
|
+
console.log("\n=== NODE COMPARISON ===");
|
|
97
|
+
console.log("Same node?", mcpNode === directNode);
|
|
98
|
+
console.log("MCP node guid:", mcpNode.guid);
|
|
99
|
+
console.log("Direct node guid:", directNode.guid);
|
|
100
|
+
console.log("MCP node children:", mcpNode.children?.length || 0);
|
|
101
|
+
console.log("Direct node children:", directNode.children?.length || 0);
|
|
102
|
+
// Check if node data is the same
|
|
103
|
+
const mcpScene = mcpNode;
|
|
104
|
+
const directScene = directNode;
|
|
105
|
+
console.log("\nMCP node x/y/w/h:", mcpScene.x, mcpScene.y, mcpScene.width, mcpScene.height);
|
|
106
|
+
console.log("Direct node x/y/w/h:", directScene.x, directScene.y, directScene.width, directScene.height);
|
|
107
|
+
// === KEY DIFFERENCE: Check blobs ===
|
|
108
|
+
console.log("\n=== BLOB COMPARISON ===");
|
|
109
|
+
if (mcpData.blobs && directData.blobs) {
|
|
110
|
+
console.log("MCP blobs length:", mcpData.blobs.length);
|
|
111
|
+
console.log("Direct blobs length:", directData.blobs.length);
|
|
112
|
+
console.log("Same blob array?", mcpData.blobs === directData.blobs);
|
|
113
|
+
// Check first few blobs
|
|
114
|
+
for (let i = 0; i < Math.min(3, mcpData.blobs.length); i++) {
|
|
115
|
+
const mcpBlob = mcpData.blobs[i];
|
|
116
|
+
const directBlob = directData.blobs[i];
|
|
117
|
+
console.log(`Blob ${i}: MCP bytes=${mcpBlob?.bytes?.length}, Direct bytes=${directBlob?.bytes?.length}`);
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
// Save outputs
|
|
121
|
+
writeFileSync("output/mcp-output.svg", mcpResult.svg);
|
|
122
|
+
writeFileSync("output/direct-output.svg", directResult.svg);
|
|
123
|
+
const html = `<!DOCTYPE html>
|
|
124
|
+
<html>
|
|
125
|
+
<head>
|
|
126
|
+
<title>MCP vs Direct Comparison - ${NODE_ID}</title>
|
|
127
|
+
<style>
|
|
128
|
+
body { margin: 0; padding: 40px; background: #0d0d0d; color: #fff; font-family: sans-serif; }
|
|
129
|
+
h1 { font-size: 24px; margin-bottom: 8px; }
|
|
130
|
+
.container { display: flex; gap: 40px; flex-wrap: wrap; }
|
|
131
|
+
.preview { background: #1a1a1a; border-radius: 12px; padding: 40px; }
|
|
132
|
+
.preview h2 { font-size: 14px; color: #666; margin-bottom: 20px; }
|
|
133
|
+
.preview.good h2 { color: #4f4; }
|
|
134
|
+
.preview.bad h2 { color: #f44; }
|
|
135
|
+
.scaled svg { width: 200px; height: auto; }
|
|
136
|
+
pre { font-size: 10px; background: #111; padding: 10px; overflow: auto; max-height: 400px; }
|
|
137
|
+
</style>
|
|
138
|
+
</head>
|
|
139
|
+
<body>
|
|
140
|
+
<h1>MCP vs Direct Comparison: ${NODE_ID}</h1>
|
|
141
|
+
|
|
142
|
+
<div class="container">
|
|
143
|
+
<div class="preview bad">
|
|
144
|
+
<h2>MCP (renderScreen) - ${mcpResult.width.toFixed(1)} x ${mcpResult.height.toFixed(1)}</h2>
|
|
145
|
+
<div class="scaled">${mcpResult.svg.replace('<?xml version="1.0" encoding="UTF-8"?>', '')}</div>
|
|
146
|
+
</div>
|
|
147
|
+
|
|
148
|
+
<div class="preview good">
|
|
149
|
+
<h2>Direct (renderScreen) - ${directResult.width.toFixed(1)} x ${directResult.height.toFixed(1)}</h2>
|
|
150
|
+
<div class="scaled">${directResult.svg.replace('<?xml version="1.0" encoding="UTF-8"?>', '')}</div>
|
|
151
|
+
</div>
|
|
152
|
+
</div>
|
|
153
|
+
|
|
154
|
+
<h2 style="margin-top: 40px;">Raw SVG</h2>
|
|
155
|
+
<div class="container">
|
|
156
|
+
<div class="preview">
|
|
157
|
+
<h2>MCP SVG</h2>
|
|
158
|
+
<pre>${mcpResult.svg.replace(/</g, '<').replace(/>/g, '>')}</pre>
|
|
159
|
+
</div>
|
|
160
|
+
<div class="preview">
|
|
161
|
+
<h2>Direct SVG</h2>
|
|
162
|
+
<pre>${directResult.svg.replace(/</g, '<').replace(/>/g, '>')}</pre>
|
|
163
|
+
</div>
|
|
164
|
+
</div>
|
|
165
|
+
</body>
|
|
166
|
+
</html>`;
|
|
167
|
+
writeFileSync("output/mcp-vs-direct.html", html);
|
|
168
|
+
console.log("\nSaved: output/mcp-output.svg");
|
|
169
|
+
console.log("Saved: output/direct-output.svg");
|
|
170
|
+
console.log("Saved: output/mcp-vs-direct.html");
|
|
171
|
+
}
|
|
172
|
+
compare().catch(console.error);
|
|
173
|
+
//# sourceMappingURL=compare-mcp-vs-direct.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"compare-mcp-vs-direct.js","sourceRoot":"","sources":["../src/compare-mcp-vs-direct.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"compare-renderers.d.ts","sourceRoot":"","sources":["../src/compare-renderers.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Compare renderScreen outputs to debug transform/positioning issues
|
|
3
|
+
*/
|
|
4
|
+
import { readFigFile } from "./parser/index.js";
|
|
5
|
+
import { parseCanvasFig, formatGUID, extractDocumentTree } from "./parser/kiwi-parser.js";
|
|
6
|
+
import { renderScreen } from "./renderer/index.js";
|
|
7
|
+
import { writeFileSync } from "fs";
|
|
8
|
+
const FILE_PATH = "/Users/billy/Downloads/AutoDevice (Copy).fig";
|
|
9
|
+
const NODE_ID = process.argv[2] || "457:1681";
|
|
10
|
+
async function compare() {
|
|
11
|
+
const archive = await readFigFile(FILE_PATH);
|
|
12
|
+
const parsed = parseCanvasFig(archive.canvasFig);
|
|
13
|
+
const doc = extractDocumentTree(parsed.message);
|
|
14
|
+
if (!doc) {
|
|
15
|
+
console.log("Failed to extract document");
|
|
16
|
+
return;
|
|
17
|
+
}
|
|
18
|
+
const blobs = parsed.message["blobs"];
|
|
19
|
+
const nodeIndex = new Map();
|
|
20
|
+
function indexNode(node) {
|
|
21
|
+
nodeIndex.set(formatGUID(node.guid), node);
|
|
22
|
+
if (node.children) {
|
|
23
|
+
for (const child of node.children) {
|
|
24
|
+
indexNode(child);
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
indexNode(doc);
|
|
29
|
+
const node = nodeIndex.get(NODE_ID);
|
|
30
|
+
if (!node) {
|
|
31
|
+
console.log("Node not found:", NODE_ID);
|
|
32
|
+
return;
|
|
33
|
+
}
|
|
34
|
+
console.log("Node:", formatGUID(node.guid));
|
|
35
|
+
console.log("Type:", node.type);
|
|
36
|
+
console.log("Name:", node.name);
|
|
37
|
+
console.log("Children:", node.children?.length || 0);
|
|
38
|
+
const options = {
|
|
39
|
+
includeFills: true,
|
|
40
|
+
includeStrokes: true,
|
|
41
|
+
includeText: true,
|
|
42
|
+
background: "#1a1a1a",
|
|
43
|
+
};
|
|
44
|
+
// Render two passes to compare outputs
|
|
45
|
+
console.log("\n--- Render A (renderScreen) ---");
|
|
46
|
+
const firstResult = renderScreen(node, undefined, blobs, options);
|
|
47
|
+
console.log("Render A Size:", firstResult.width, "x", firstResult.height);
|
|
48
|
+
if (firstResult.warnings.length)
|
|
49
|
+
console.log("Render A Warnings:", firstResult.warnings);
|
|
50
|
+
console.log("\n--- Render B (renderScreen) ---");
|
|
51
|
+
const secondResult = renderScreen(node, undefined, blobs, options);
|
|
52
|
+
console.log("Render B Size:", secondResult.width, "x", secondResult.height);
|
|
53
|
+
if (secondResult.warnings.length)
|
|
54
|
+
console.log("Render B Warnings:", secondResult.warnings);
|
|
55
|
+
// Save both
|
|
56
|
+
writeFileSync("output/compare-a.svg", firstResult.svg);
|
|
57
|
+
writeFileSync("output/compare-b.svg", secondResult.svg);
|
|
58
|
+
console.log("\nSaved: output/compare-a.svg");
|
|
59
|
+
console.log("Saved: output/compare-b.svg");
|
|
60
|
+
// Create comparison HTML
|
|
61
|
+
const html = `<!DOCTYPE html>
|
|
62
|
+
<html>
|
|
63
|
+
<head>
|
|
64
|
+
<title>Renderer Comparison - ${NODE_ID}</title>
|
|
65
|
+
<style>
|
|
66
|
+
body { margin: 0; padding: 40px; background: #0d0d0d; color: #fff; font-family: sans-serif; }
|
|
67
|
+
h1 { font-size: 24px; margin-bottom: 8px; }
|
|
68
|
+
.info { color: #888; font-size: 14px; margin-bottom: 24px; }
|
|
69
|
+
.container { display: flex; gap: 40px; flex-wrap: wrap; }
|
|
70
|
+
.preview { background: #1a1a1a; border-radius: 12px; padding: 40px; }
|
|
71
|
+
.preview h2 { font-size: 14px; color: #666; margin-bottom: 20px; }
|
|
72
|
+
.preview.good h2 { color: #4f4; }
|
|
73
|
+
.preview.bad h2 { color: #f44; }
|
|
74
|
+
.scaled svg { width: 200px; height: auto; }
|
|
75
|
+
</style>
|
|
76
|
+
</head>
|
|
77
|
+
<body>
|
|
78
|
+
<h1>Renderer Comparison: ${NODE_ID}</h1>
|
|
79
|
+
<p class="info">Node: ${node.name} (${node.type})</p>
|
|
80
|
+
|
|
81
|
+
<div class="container">
|
|
82
|
+
<div class="preview bad">
|
|
83
|
+
<h2>Render A - ${firstResult.width.toFixed(1)} x ${firstResult.height.toFixed(1)}</h2>
|
|
84
|
+
<div class="scaled">${firstResult.svg.replace('<?xml version="1.0" encoding="UTF-8"?>', '')}</div>
|
|
85
|
+
</div>
|
|
86
|
+
|
|
87
|
+
<div class="preview good">
|
|
88
|
+
<h2>Render B - ${secondResult.width.toFixed(1)} x ${secondResult.height.toFixed(1)}</h2>
|
|
89
|
+
<div class="scaled">${secondResult.svg.replace('<?xml version="1.0" encoding="UTF-8"?>', '')}</div>
|
|
90
|
+
</div>
|
|
91
|
+
</div>
|
|
92
|
+
|
|
93
|
+
<h2 style="margin-top: 40px;">Raw SVG Comparison</h2>
|
|
94
|
+
<div class="container">
|
|
95
|
+
<div class="preview">
|
|
96
|
+
<h2>Render A SVG</h2>
|
|
97
|
+
<pre style="font-size: 10px; max-height: 300px; overflow: auto; background: #111; padding: 10px;">${firstResult.svg.replace(/</g, '<').replace(/>/g, '>')}</pre>
|
|
98
|
+
</div>
|
|
99
|
+
<div class="preview">
|
|
100
|
+
<h2>Render B SVG</h2>
|
|
101
|
+
<pre style="font-size: 10px; max-height: 300px; overflow: auto; background: #111; padding: 10px;">${secondResult.svg.replace(/</g, '<').replace(/>/g, '>')}</pre>
|
|
102
|
+
</div>
|
|
103
|
+
</div>
|
|
104
|
+
</body>
|
|
105
|
+
</html>`;
|
|
106
|
+
writeFileSync("output/compare.html", html);
|
|
107
|
+
console.log("Saved: output/compare.html");
|
|
108
|
+
}
|
|
109
|
+
compare().catch(console.error);
|
|
110
|
+
//# sourceMappingURL=compare-renderers.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"compare-renderers.js","sourceRoot":"","sources":["../src/compare-renderers.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"debug-stroke-geom.d.ts","sourceRoot":"","sources":["../../src/debug/debug-stroke-geom.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Debug strokeGeometry for complex vector 457:1697
|
|
3
|
+
*/
|
|
4
|
+
import { readFigFile } from "../parser/index.js";
|
|
5
|
+
import { parseCanvasFig, formatGUID, extractDocumentTree } from "../parser/kiwi-parser.js";
|
|
6
|
+
async function debug() {
|
|
7
|
+
const archive = await readFigFile("/Users/billy/Downloads/AutoDevice (Copy).fig");
|
|
8
|
+
const parsed = parseCanvasFig(archive.canvasFig);
|
|
9
|
+
const doc = extractDocumentTree(parsed.message);
|
|
10
|
+
if (!doc)
|
|
11
|
+
return;
|
|
12
|
+
const nodeIndex = new Map();
|
|
13
|
+
function indexNode(node) {
|
|
14
|
+
nodeIndex.set(formatGUID(node.guid), node);
|
|
15
|
+
if (node.children) {
|
|
16
|
+
for (const child of node.children) {
|
|
17
|
+
indexNode(child);
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
indexNode(doc);
|
|
22
|
+
const blobs = parsed.message["blobs"];
|
|
23
|
+
// Check all 3 vectors in frame 457:1694
|
|
24
|
+
for (const id of ["457:1695", "457:1696", "457:1697"]) {
|
|
25
|
+
const rawNode = nodeIndex.get(id);
|
|
26
|
+
if (!rawNode) {
|
|
27
|
+
console.log(`Node ${id} not found`);
|
|
28
|
+
continue;
|
|
29
|
+
}
|
|
30
|
+
const node = rawNode;
|
|
31
|
+
console.log(`\n${"=".repeat(60)}`);
|
|
32
|
+
console.log(`Node ${id}: ${node.name}`);
|
|
33
|
+
console.log("fillGeometry:", JSON.stringify(node.fillGeometry, null, 2));
|
|
34
|
+
console.log("strokeGeometry:", JSON.stringify(node.strokeGeometry, null, 2));
|
|
35
|
+
// If strokeGeometry has commandsBlob, decode it
|
|
36
|
+
const strokeGeom = node.strokeGeometry;
|
|
37
|
+
if (strokeGeom?.[0]?.commandsBlob !== undefined && blobs) {
|
|
38
|
+
const blobIdx = strokeGeom[0].commandsBlob;
|
|
39
|
+
const bytes = blobs[blobIdx].bytes;
|
|
40
|
+
console.log(`\nstrokeGeometry[0].commandsBlob (${bytes.length} bytes):`);
|
|
41
|
+
// Decode path commands
|
|
42
|
+
const view = new DataView(bytes.buffer, bytes.byteOffset, bytes.length);
|
|
43
|
+
const cmdNames = { 0: "Z", 1: "M", 2: "L", 3: "Q", 4: "C", 5: "Q2" };
|
|
44
|
+
const argCounts = { 0: 0, 1: 2, 2: 2, 3: 4, 4: 6, 5: 4 };
|
|
45
|
+
let offset = 0;
|
|
46
|
+
const cmds = [];
|
|
47
|
+
while (offset < bytes.length) {
|
|
48
|
+
const cmd = bytes[offset++];
|
|
49
|
+
const name = cmdNames[cmd] ?? `?${cmd}`;
|
|
50
|
+
const argCount = argCounts[cmd];
|
|
51
|
+
if (argCount === undefined) {
|
|
52
|
+
cmds.push(`${name}(unknown)`);
|
|
53
|
+
break;
|
|
54
|
+
}
|
|
55
|
+
const args = [];
|
|
56
|
+
for (let i = 0; i < argCount && offset + 4 <= bytes.length; i++) {
|
|
57
|
+
args.push(view.getFloat32(offset, true));
|
|
58
|
+
offset += 4;
|
|
59
|
+
}
|
|
60
|
+
cmds.push(`${name}(${args.map(a => a.toFixed(2)).join(", ")})`);
|
|
61
|
+
}
|
|
62
|
+
console.log(cmds.join(" → "));
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
debug().catch(console.error);
|
|
67
|
+
//# sourceMappingURL=debug-stroke-geom.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"debug-stroke-geom.js","sourceRoot":"","sources":["../../src/debug/debug-stroke-geom.ts"],"names":[],"mappings":"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"}
|