@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.
Files changed (186) hide show
  1. package/README.md +112 -0
  2. package/dist/compare-get-vector.d.ts +2 -0
  3. package/dist/compare-get-vector.d.ts.map +1 -0
  4. package/dist/compare-get-vector.js +124 -0
  5. package/dist/compare-get-vector.js.map +1 -0
  6. package/dist/compare-mcp-vs-direct.d.ts +2 -0
  7. package/dist/compare-mcp-vs-direct.d.ts.map +1 -0
  8. package/dist/compare-mcp-vs-direct.js +173 -0
  9. package/dist/compare-mcp-vs-direct.js.map +1 -0
  10. package/dist/compare-renderers.d.ts +2 -0
  11. package/dist/compare-renderers.d.ts.map +1 -0
  12. package/dist/compare-renderers.js +110 -0
  13. package/dist/compare-renderers.js.map +1 -0
  14. package/dist/debug/debug-stroke-geom.d.ts +2 -0
  15. package/dist/debug/debug-stroke-geom.d.ts.map +1 -0
  16. package/dist/debug/debug-stroke-geom.js +67 -0
  17. package/dist/debug/debug-stroke-geom.js.map +1 -0
  18. package/dist/debug/debug-transforms.d.ts +2 -0
  19. package/dist/debug/debug-transforms.d.ts.map +1 -0
  20. package/dist/debug/debug-transforms.js +97 -0
  21. package/dist/debug/debug-transforms.js.map +1 -0
  22. package/dist/debug/debug-vertex.d.ts +2 -0
  23. package/dist/debug/debug-vertex.d.ts.map +1 -0
  24. package/dist/debug/debug-vertex.js +72 -0
  25. package/dist/debug/debug-vertex.js.map +1 -0
  26. package/dist/debug-group.d.ts +5 -0
  27. package/dist/debug-group.d.ts.map +1 -0
  28. package/dist/debug-group.js +44 -0
  29. package/dist/debug-group.js.map +1 -0
  30. package/dist/debug-stroke-geom.d.ts +2 -0
  31. package/dist/debug-stroke-geom.d.ts.map +1 -0
  32. package/dist/debug-stroke-geom.js +67 -0
  33. package/dist/debug-stroke-geom.js.map +1 -0
  34. package/dist/debug-transforms.d.ts +2 -0
  35. package/dist/debug-transforms.d.ts.map +1 -0
  36. package/dist/debug-transforms.js +97 -0
  37. package/dist/debug-transforms.js.map +1 -0
  38. package/dist/debug-vertex.d.ts +2 -0
  39. package/dist/debug-vertex.d.ts.map +1 -0
  40. package/dist/debug-vertex.js +72 -0
  41. package/dist/debug-vertex.js.map +1 -0
  42. package/dist/decode-vector-network.d.ts +5 -0
  43. package/dist/decode-vector-network.d.ts.map +1 -0
  44. package/dist/decode-vector-network.js +160 -0
  45. package/dist/decode-vector-network.js.map +1 -0
  46. package/dist/experimental/paint-utils.d.ts +35 -0
  47. package/dist/experimental/paint-utils.d.ts.map +1 -0
  48. package/dist/experimental/paint-utils.js +105 -0
  49. package/dist/experimental/paint-utils.js.map +1 -0
  50. package/dist/experimental/render-screen-v2.d.ts +32 -0
  51. package/dist/experimental/render-screen-v2.d.ts.map +1 -0
  52. package/dist/experimental/render-screen-v2.js +366 -0
  53. package/dist/experimental/render-screen-v2.js.map +1 -0
  54. package/dist/experimental/render-screen.d.ts +26 -0
  55. package/dist/experimental/render-screen.d.ts.map +1 -0
  56. package/dist/experimental/render-screen.js +547 -0
  57. package/dist/experimental/render-screen.js.map +1 -0
  58. package/dist/experimental/render-types.d.ts +43 -0
  59. package/dist/experimental/render-types.d.ts.map +1 -0
  60. package/dist/experimental/render-types.js +22 -0
  61. package/dist/experimental/render-types.js.map +1 -0
  62. package/dist/experimental/render-utils.d.ts +38 -0
  63. package/dist/experimental/render-utils.d.ts.map +1 -0
  64. package/dist/experimental/render-utils.js +126 -0
  65. package/dist/experimental/render-utils.js.map +1 -0
  66. package/dist/experimental/screenshot.d.ts +11 -0
  67. package/dist/experimental/screenshot.d.ts.map +1 -0
  68. package/dist/experimental/screenshot.js +26 -0
  69. package/dist/experimental/screenshot.js.map +1 -0
  70. package/dist/experimental/vector-renderer.d.ts +31 -0
  71. package/dist/experimental/vector-renderer.d.ts.map +1 -0
  72. package/dist/experimental/vector-renderer.js +427 -0
  73. package/dist/experimental/vector-renderer.js.map +1 -0
  74. package/dist/explore-images.d.ts +9 -0
  75. package/dist/explore-images.d.ts.map +1 -0
  76. package/dist/explore-images.js +307 -0
  77. package/dist/explore-images.js.map +1 -0
  78. package/dist/http-server.d.ts +8 -0
  79. package/dist/http-server.d.ts.map +1 -0
  80. package/dist/http-server.js +95 -0
  81. package/dist/http-server.js.map +1 -0
  82. package/dist/index.d.ts +9 -0
  83. package/dist/index.d.ts.map +1 -0
  84. package/dist/index.js +34 -0
  85. package/dist/index.js.map +1 -0
  86. package/dist/inspect-fig.d.ts +16 -0
  87. package/dist/inspect-fig.d.ts.map +1 -0
  88. package/dist/inspect-fig.js +134 -0
  89. package/dist/inspect-fig.js.map +1 -0
  90. package/dist/inspect-frame.d.ts +2 -0
  91. package/dist/inspect-frame.d.ts.map +1 -0
  92. package/dist/inspect-frame.js +90 -0
  93. package/dist/inspect-frame.js.map +1 -0
  94. package/dist/inspect-nodes.d.ts +5 -0
  95. package/dist/inspect-nodes.d.ts.map +1 -0
  96. package/dist/inspect-nodes.js +193 -0
  97. package/dist/inspect-nodes.js.map +1 -0
  98. package/dist/mcp/server.d.ts +38 -0
  99. package/dist/mcp/server.d.ts.map +1 -0
  100. package/dist/mcp/server.js +1524 -0
  101. package/dist/mcp/server.js.map +1 -0
  102. package/dist/parser/fig-reader.d.ts +29 -0
  103. package/dist/parser/fig-reader.d.ts.map +1 -0
  104. package/dist/parser/fig-reader.js +182 -0
  105. package/dist/parser/fig-reader.js.map +1 -0
  106. package/dist/parser/index.d.ts +48 -0
  107. package/dist/parser/index.d.ts.map +1 -0
  108. package/dist/parser/index.js +106 -0
  109. package/dist/parser/index.js.map +1 -0
  110. package/dist/parser/kiwi-parser.d.ts +66 -0
  111. package/dist/parser/kiwi-parser.d.ts.map +1 -0
  112. package/dist/parser/kiwi-parser.js +491 -0
  113. package/dist/parser/kiwi-parser.js.map +1 -0
  114. package/dist/parser/layout-inference.d.ts +63 -0
  115. package/dist/parser/layout-inference.d.ts.map +1 -0
  116. package/dist/parser/layout-inference.js +446 -0
  117. package/dist/parser/layout-inference.js.map +1 -0
  118. package/dist/parser/types.d.ts +286 -0
  119. package/dist/parser/types.d.ts.map +1 -0
  120. package/dist/parser/types.js +6 -0
  121. package/dist/parser/types.js.map +1 -0
  122. package/dist/render-single.d.ts +2 -0
  123. package/dist/render-single.d.ts.map +1 -0
  124. package/dist/render-single.js +53 -0
  125. package/dist/render-single.js.map +1 -0
  126. package/dist/renderer/index.d.ts +16 -0
  127. package/dist/renderer/index.d.ts.map +1 -0
  128. package/dist/renderer/index.js +18 -0
  129. package/dist/renderer/index.js.map +1 -0
  130. package/dist/renderer/paint-utils.d.ts +35 -0
  131. package/dist/renderer/paint-utils.d.ts.map +1 -0
  132. package/dist/renderer/paint-utils.js +105 -0
  133. package/dist/renderer/paint-utils.js.map +1 -0
  134. package/dist/renderer/render-screen.d.ts +26 -0
  135. package/dist/renderer/render-screen.d.ts.map +1 -0
  136. package/dist/renderer/render-screen.js +547 -0
  137. package/dist/renderer/render-screen.js.map +1 -0
  138. package/dist/renderer/render-types.d.ts +43 -0
  139. package/dist/renderer/render-types.d.ts.map +1 -0
  140. package/dist/renderer/render-types.js +22 -0
  141. package/dist/renderer/render-types.js.map +1 -0
  142. package/dist/renderer/render-utils.d.ts +38 -0
  143. package/dist/renderer/render-utils.d.ts.map +1 -0
  144. package/dist/renderer/render-utils.js +126 -0
  145. package/dist/renderer/render-utils.js.map +1 -0
  146. package/dist/renderer/screenshot.d.ts +11 -0
  147. package/dist/renderer/screenshot.d.ts.map +1 -0
  148. package/dist/renderer/screenshot.js +26 -0
  149. package/dist/renderer/screenshot.js.map +1 -0
  150. package/dist/renderer/vector-renderer.d.ts +31 -0
  151. package/dist/renderer/vector-renderer.d.ts.map +1 -0
  152. package/dist/renderer/vector-renderer.js +427 -0
  153. package/dist/renderer/vector-renderer.js.map +1 -0
  154. package/dist/shared-config.d.ts +9 -0
  155. package/dist/shared-config.d.ts.map +1 -0
  156. package/dist/shared-config.js +9 -0
  157. package/dist/shared-config.js.map +1 -0
  158. package/dist/test-parser.d.ts +3 -0
  159. package/dist/test-parser.d.ts.map +1 -0
  160. package/dist/test-parser.js +74 -0
  161. package/dist/test-parser.js.map +1 -0
  162. package/dist/test-render-v2.d.ts +5 -0
  163. package/dist/test-render-v2.d.ts.map +1 -0
  164. package/dist/test-render-v2.js +76 -0
  165. package/dist/test-render-v2.js.map +1 -0
  166. package/dist/test-render.d.ts +5 -0
  167. package/dist/test-render.d.ts.map +1 -0
  168. package/dist/test-render.js +76 -0
  169. package/dist/test-render.js.map +1 -0
  170. package/dist/vector-export.d.ts +52 -0
  171. package/dist/vector-export.d.ts.map +1 -0
  172. package/dist/vector-export.js +628 -0
  173. package/dist/vector-export.js.map +1 -0
  174. package/dist/web-viewer/build-client.d.ts +6 -0
  175. package/dist/web-viewer/build-client.d.ts.map +1 -0
  176. package/dist/web-viewer/build-client.js +36 -0
  177. package/dist/web-viewer/build-client.js.map +1 -0
  178. package/dist/web-viewer/client/viewer.d.ts +7 -0
  179. package/dist/web-viewer/client/viewer.d.ts.map +1 -0
  180. package/dist/web-viewer/client/viewer.js +873 -0
  181. package/dist/web-viewer/client/viewer.js.map +1 -0
  182. package/dist/web-viewer/server.d.ts +16 -0
  183. package/dist/web-viewer/server.d.ts.map +1 -0
  184. package/dist/web-viewer/server.js +420 -0
  185. package/dist/web-viewer/server.js.map +1 -0
  186. 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,2 @@
1
+ export {};
2
+ //# sourceMappingURL=compare-get-vector.d.ts.map
@@ -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, '&lt;').replace(/>/g, '&gt;')}</pre>
110
+ </div>
111
+ <div class="preview" style="max-width: 45%;">
112
+ <h2>renderScreen SVG</h2>
113
+ <pre>${screenResult.svg.replace(/</g, '&lt;').replace(/>/g, '&gt;')}</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,2 @@
1
+ export {};
2
+ //# sourceMappingURL=compare-mcp-vs-direct.d.ts.map
@@ -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, '&lt;').replace(/>/g, '&gt;')}</pre>
159
+ </div>
160
+ <div class="preview">
161
+ <h2>Direct SVG</h2>
162
+ <pre>${directResult.svg.replace(/</g, '&lt;').replace(/>/g, '&gt;')}</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,2 @@
1
+ export {};
2
+ //# sourceMappingURL=compare-renderers.d.ts.map
@@ -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, '&lt;').replace(/>/g, '&gt;')}</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, '&lt;').replace(/>/g, '&gt;')}</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,2 @@
1
+ export {};
2
+ //# sourceMappingURL=debug-stroke-geom.d.ts.map
@@ -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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"}