@bilalba/fig-mcp 1.0.1 → 1.1.3

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 (76) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +110 -55
  3. package/dist/index.js +55 -2
  4. package/dist/index.js.map +1 -1
  5. package/dist/inspect-fig.d.ts +1 -1
  6. package/dist/inspect-fig.d.ts.map +1 -1
  7. package/dist/inspect-fig.js +7 -3
  8. package/dist/inspect-fig.js.map +1 -1
  9. package/dist/web-viewer/build-client.d.ts +1 -0
  10. package/dist/web-viewer/build-client.d.ts.map +1 -1
  11. package/dist/web-viewer/build-client.js +32 -5
  12. package/dist/web-viewer/build-client.js.map +1 -1
  13. package/dist/web-viewer/client/dist/viewer.js +10 -0
  14. package/dist/web-viewer/client/index.html +138 -0
  15. package/dist/web-viewer/client/styles.css +561 -0
  16. package/package.json +6 -3
  17. package/dist/debug/debug-stroke-geom.d.ts +0 -2
  18. package/dist/debug/debug-stroke-geom.d.ts.map +0 -1
  19. package/dist/debug/debug-stroke-geom.js +0 -67
  20. package/dist/debug/debug-stroke-geom.js.map +0 -1
  21. package/dist/debug/debug-transforms.d.ts +0 -2
  22. package/dist/debug/debug-transforms.d.ts.map +0 -1
  23. package/dist/debug/debug-transforms.js +0 -97
  24. package/dist/debug/debug-transforms.js.map +0 -1
  25. package/dist/debug/debug-vertex.d.ts +0 -2
  26. package/dist/debug/debug-vertex.d.ts.map +0 -1
  27. package/dist/debug/debug-vertex.js +0 -72
  28. package/dist/debug/debug-vertex.js.map +0 -1
  29. package/dist/debug-group.d.ts +0 -5
  30. package/dist/debug-group.d.ts.map +0 -1
  31. package/dist/debug-group.js +0 -44
  32. package/dist/debug-group.js.map +0 -1
  33. package/dist/debug-stroke-geom.d.ts +0 -2
  34. package/dist/debug-stroke-geom.d.ts.map +0 -1
  35. package/dist/debug-stroke-geom.js +0 -67
  36. package/dist/debug-stroke-geom.js.map +0 -1
  37. package/dist/debug-transforms.d.ts +0 -2
  38. package/dist/debug-transforms.d.ts.map +0 -1
  39. package/dist/debug-transforms.js +0 -97
  40. package/dist/debug-transforms.js.map +0 -1
  41. package/dist/debug-vertex.d.ts +0 -2
  42. package/dist/debug-vertex.d.ts.map +0 -1
  43. package/dist/debug-vertex.js +0 -72
  44. package/dist/debug-vertex.js.map +0 -1
  45. package/dist/experimental/paint-utils.d.ts +0 -35
  46. package/dist/experimental/paint-utils.d.ts.map +0 -1
  47. package/dist/experimental/paint-utils.js +0 -105
  48. package/dist/experimental/paint-utils.js.map +0 -1
  49. package/dist/experimental/render-screen-v2.d.ts +0 -32
  50. package/dist/experimental/render-screen-v2.d.ts.map +0 -1
  51. package/dist/experimental/render-screen-v2.js +0 -366
  52. package/dist/experimental/render-screen-v2.js.map +0 -1
  53. package/dist/experimental/render-screen.d.ts +0 -26
  54. package/dist/experimental/render-screen.d.ts.map +0 -1
  55. package/dist/experimental/render-screen.js +0 -547
  56. package/dist/experimental/render-screen.js.map +0 -1
  57. package/dist/experimental/render-types.d.ts +0 -43
  58. package/dist/experimental/render-types.d.ts.map +0 -1
  59. package/dist/experimental/render-types.js +0 -22
  60. package/dist/experimental/render-types.js.map +0 -1
  61. package/dist/experimental/render-utils.d.ts +0 -38
  62. package/dist/experimental/render-utils.d.ts.map +0 -1
  63. package/dist/experimental/render-utils.js +0 -126
  64. package/dist/experimental/render-utils.js.map +0 -1
  65. package/dist/experimental/screenshot.d.ts +0 -11
  66. package/dist/experimental/screenshot.d.ts.map +0 -1
  67. package/dist/experimental/screenshot.js +0 -26
  68. package/dist/experimental/screenshot.js.map +0 -1
  69. package/dist/experimental/vector-renderer.d.ts +0 -31
  70. package/dist/experimental/vector-renderer.d.ts.map +0 -1
  71. package/dist/experimental/vector-renderer.js +0 -427
  72. package/dist/experimental/vector-renderer.js.map +0 -1
  73. package/dist/test-render-v2.d.ts +0 -5
  74. package/dist/test-render-v2.d.ts.map +0 -1
  75. package/dist/test-render-v2.js +0 -76
  76. package/dist/test-render-v2.js.map +0 -1
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2025 bilal
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md CHANGED
@@ -1,106 +1,161 @@
1
- # Fig MCP Server
1
+ # @bilalba/fig-mcp
2
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.
3
+ MCP server for parsing `.fig` files. Enables AI assistants to understand and extract design information from the `.fig` file format for implementation guidance.
4
4
 
5
- ## Features
5
+ ## Installation
6
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
7
+ ```bash
8
+ npm install -g @bilalba/fig-mcp
9
+ ```
13
10
 
14
- ## Installation
11
+ Or use directly with npx:
15
12
 
16
13
  ```bash
17
- npm install
18
- npm run build
14
+ npx @bilalba/fig-mcp --help
19
15
  ```
20
16
 
21
- ## Usage
17
+ ## Quick Start
22
18
 
23
- ### As MCP Server
19
+ ### As MCP Server (for Claude Desktop)
24
20
 
25
- Add to your MCP client configuration:
21
+ Add to your Claude Desktop configuration (`~/Library/Application Support/Claude/claude_desktop_config.json` on macOS):
26
22
 
27
23
  ```json
28
24
  {
29
25
  "mcpServers": {
30
26
  "fig-mcp": {
31
- "command": "node",
32
- "args": ["/path/to/fig-mcp/dist/index.js"]
27
+ "command": "npx",
28
+ "args": ["@bilalba/fig-mcp"]
33
29
  }
34
30
  }
35
31
  }
36
32
  ```
37
33
 
38
- ### CLI Inspector
34
+ Then ask Claude to parse your `.fig` files:
35
+
36
+ > "Parse my design.fig file and show me the document structure"
37
+
38
+ ### Web Viewer
39
+
40
+ Browse and preview `.fig` files in your browser:
39
41
 
40
42
  ```bash
41
- # Show document structure
42
- npx tsx src/inspect-fig.ts design.fig summary
43
+ fig-mcp viewer design.fig
44
+ # Opens http://localhost:3000
45
+ ```
43
46
 
44
- # Show kiwi schema
45
- npx tsx src/inspect-fig.ts design.fig schema
47
+ Features:
48
+ - Tree navigation with collapsible nodes
49
+ - SVG preview with zoom/pan
50
+ - Node details panel
51
+ - Copy node IDs for MCP tool calls
46
52
 
47
- # Output simplified JSON
48
- npx tsx src/inspect-fig.ts design.fig json
53
+ ### CLI Inspector
49
54
 
50
- # Show node statistics
51
- npx tsx src/inspect-fig.ts design.fig stats
55
+ Inspect `.fig` files from the command line:
52
56
 
53
- # List archive contents
54
- npx tsx src/inspect-fig.ts design.fig list
57
+ ```bash
58
+ fig-mcp inspect design.fig summary # Show document structure
59
+ fig-mcp inspect design.fig stats # Show node type counts
60
+ fig-mcp inspect design.fig list # List archive contents
61
+ fig-mcp inspect design.fig json # Output simplified JSON
55
62
  ```
56
63
 
64
+ ## CLI Commands
65
+
66
+ | Command | Description |
67
+ |---------|-------------|
68
+ | `fig-mcp` | Start MCP server (for AI assistants) |
69
+ | `fig-mcp viewer <file> [port]` | Open web viewer |
70
+ | `fig-mcp inspect <file> [cmd]` | Inspect file |
71
+ | `fig-mcp --help` | Show help |
72
+ | `fig-mcp --version` | Show version |
73
+
57
74
  ## MCP Tools
58
75
 
76
+ The MCP server exposes the following tools for AI assistants:
77
+
78
+ ### Document Structure
79
+
59
80
  | Tool | Description |
60
81
  |------|-------------|
61
82
  | `parse_fig_file` | Parse and return simplified document structure |
62
- | `get_document_summary` | Text tree of document structure |
83
+ | `get_document_summary` | Text tree of document structure with pagination |
84
+ | `get_tree_summary` | Hierarchical summary for drill-down navigation |
85
+ | `list_pages` | List all pages (canvases) in the document |
86
+ | `get_page_contents` | Get contents of a specific page |
87
+
88
+ ### Node Queries
89
+
90
+ | Tool | Description |
91
+ |------|-------------|
63
92
  | `find_nodes` | Find nodes by type or name |
64
- | `get_node_details` | Get details for a node path |
93
+ | `get_node_details` | Get details for a node by path |
94
+ | `get_node_by_id` | Get details for a node by GUID |
65
95
  | `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 |
96
+
97
+ ### Content Extraction
98
+
99
+ | Tool | Description |
100
+ |------|-------------|
101
+ | `get_text_content` | Extract all text content |
102
+ | `get_colors` | Extract unique color palette |
103
+ | `list_nodes_with_fills` | List nodes with fill paints |
104
+
105
+ ### Image & Rendering
106
+
107
+ | Tool | Description |
108
+ |------|-------------|
109
+ | `list_images` | List all images with metadata |
110
+ | `get_image` | Get image by hash (base64) |
111
+ | `get_thumbnail` | Get document thumbnail |
112
+ | `render_screen` | Render node subtree as PNG |
113
+ | `get_vector` | Export vector as SVG, PDF, PNG, or WebP |
114
+
115
+ ### Debugging
116
+
117
+ | Tool | Description |
118
+ |------|-------------|
119
+ | `get_schema_info` | Kiwi schema information |
120
+ | `get_raw_message` | Raw decoded message |
121
+ | `list_archive_contents` | List files in the archive |
122
+ | `clear_cache` | Clear file cache |
70
123
 
71
124
  ## How It Works
72
125
 
73
- 1. `.fig` files are ZIP archives containing `canvas.fig` (binary data), `meta.json`, and images
126
+ 1. `.fig` files are ZIP archives containing:
127
+ - `canvas.fig` - Main document data (kiwi binary format)
128
+ - `meta.json` - File metadata
129
+ - `thumbnail.png` - Preview image
130
+ - `images/` - Image assets
131
+
74
132
  2. The `canvas.fig` uses Evan Wallace's [kiwi](https://github.com/evanw/kiwi) binary format
133
+
75
134
  3. The kiwi schema is embedded in each file and extracted at parse time
76
- 4. Document data is decoded using the compiled schema
135
+
136
+ 4. Document data is decoded and transformed into structured information
137
+
77
138
  5. Layout properties are inferred from node positions and auto-layout settings
78
139
 
79
- ## Project Structure
140
+ ## Features
80
141
 
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
- ```
142
+ - Parse `.fig` files locally without API access
143
+ - Extract document structure, nodes, and hierarchy
144
+ - Infer layout properties (flexbox-like direction, gap, padding, alignment)
145
+ - Extract colors, text content, and styling information
146
+ - Render nodes to PNG screenshots
147
+ - Export vectors as SVG, PDF, PNG, or WebP
148
+ - Full effect support (shadows, blurs)
149
+
150
+ ## Requirements
151
+
152
+ - Node.js 18 or higher
97
153
 
98
154
  ## Limitations
99
155
 
100
156
  - 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
157
  - This is for local `.fig` files only (use a cloud API for hosted files)
158
+ - Some complex properties may not be fully parsed
104
159
 
105
160
  ## License
106
161
 
package/dist/index.js CHANGED
@@ -9,8 +9,53 @@ import open from "open";
9
9
  import { startServer } from "./mcp/server.js";
10
10
  import { startHttpServer } from "./http-server.js";
11
11
  import { createServer as createViewerServer } from "./web-viewer/server.js";
12
+ import { runInspect } from "./inspect-fig.js";
13
+ import { readFileSync } from "fs";
14
+ import { fileURLToPath } from "url";
15
+ import { dirname, join } from "path";
12
16
  const args = process.argv.slice(2);
13
- if (args[0] === "viewer") {
17
+ const command = args[0];
18
+ // Get package.json for version
19
+ const __dirname = dirname(fileURLToPath(import.meta.url));
20
+ const pkg = JSON.parse(readFileSync(join(__dirname, "../package.json"), "utf-8"));
21
+ if (command === "--version" || command === "-v") {
22
+ console.log(pkg.version);
23
+ process.exit(0);
24
+ }
25
+ if (command === "--help" || command === "-h" || command === "help") {
26
+ console.log(`
27
+ fig-mcp v${pkg.version} - MCP server for parsing .fig files
28
+
29
+ Usage:
30
+ fig-mcp Start MCP server (for AI assistants)
31
+ fig-mcp viewer <file> [port] Start web viewer for a .fig file
32
+ fig-mcp inspect <file> [command] Inspect a .fig file
33
+
34
+ Viewer:
35
+ Opens a local web UI to browse and preview .fig file contents.
36
+ Default port: 3000
37
+
38
+ Inspect commands:
39
+ list - List archive contents
40
+ schema - Show kiwi schema info
41
+ summary - Show document structure (default)
42
+ raw - Show raw message (truncated)
43
+ json - Output simplified JSON
44
+ stats - Show node type statistics
45
+
46
+ Options:
47
+ --help, -h Show this help
48
+ --version, -v Show version
49
+
50
+ Examples:
51
+ fig-mcp viewer design.fig # Open viewer on port 3000
52
+ fig-mcp viewer design.fig 8080 # Open viewer on port 8080
53
+ fig-mcp inspect design.fig summary # Show document structure
54
+ fig-mcp inspect design.fig stats # Show node type counts
55
+ `);
56
+ process.exit(0);
57
+ }
58
+ if (command === "viewer") {
14
59
  const figFile = args[1];
15
60
  const port = parseInt(args[2] || "3000", 10);
16
61
  if (!figFile) {
@@ -22,7 +67,10 @@ if (args[0] === "viewer") {
22
67
  void open(url);
23
68
  });
24
69
  }
25
- else {
70
+ else if (command === "inspect") {
71
+ await runInspect(args.slice(1));
72
+ }
73
+ else if (!command) {
26
74
  // Start HTTP server for image serving
27
75
  startHttpServer();
28
76
  // Exit when stdin closes (MCP client disconnected)
@@ -35,4 +83,9 @@ else {
35
83
  process.exit(1);
36
84
  });
37
85
  }
86
+ else {
87
+ console.error(`Unknown command: ${command}`);
88
+ console.error("Run 'fig-mcp --help' for usage information.");
89
+ process.exit(1);
90
+ }
38
91
  //# sourceMappingURL=index.js.map
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";AACA;;;;;GAKG;AAEH,OAAO,IAAI,MAAM,MAAM,CAAC;AACxB,OAAO,EAAE,WAAW,EAAE,MAAM,iBAAiB,CAAC;AAC9C,OAAO,EAAE,eAAe,EAAE,MAAM,kBAAkB,CAAC;AACnD,OAAO,EAAE,YAAY,IAAI,kBAAkB,EAAE,MAAM,wBAAwB,CAAC;AAE5E,MAAM,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;AACnC,IAAI,IAAI,CAAC,CAAC,CAAC,KAAK,QAAQ,EAAE,CAAC;IACzB,MAAM,OAAO,GAAG,IAAI,CAAC,CAAC,CAAC,CAAC;IACxB,MAAM,IAAI,GAAG,QAAQ,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,MAAM,EAAE,EAAE,CAAC,CAAC;IAE7C,IAAI,CAAC,OAAO,EAAE,CAAC;QACb,OAAO,CAAC,KAAK,CAAC,gDAAgD,CAAC,CAAC;QAChE,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC;IAED,MAAM,YAAY,GAAG,kBAAkB,CAAC,EAAE,OAAO,EAAE,IAAI,EAAE,CAAC,CAAC;IAC3D,YAAY,CAAC,KAAK,CAAC,CAAC,GAAG,EAAE,EAAE;QACzB,KAAK,IAAI,CAAC,GAAG,CAAC,CAAC;IACjB,CAAC,CAAC,CAAC;AACL,CAAC;KAAM,CAAC;IACN,sCAAsC;IACtC,eAAe,EAAE,CAAC;IAElB,mDAAmD;IACnD,OAAO,CAAC,KAAK,CAAC,EAAE,CAAC,OAAO,EAAE,GAAG,EAAE;QAC7B,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC,CAAC,CAAC;IAEH,mBAAmB;IACnB,WAAW,EAAE,CAAC,KAAK,CAAC,CAAC,KAAK,EAAE,EAAE;QAC5B,OAAO,CAAC,KAAK,CAAC,yBAAyB,EAAE,KAAK,CAAC,CAAC;QAChD,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC,CAAC,CAAC;AACL,CAAC"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
@@ -12,5 +12,5 @@
12
12
  * raw - Show raw message (truncated)
13
13
  * json - Output simplified JSON
14
14
  */
15
- export {};
15
+ export declare function runInspect(args: string[]): Promise<void>;
16
16
  //# sourceMappingURL=inspect-fig.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"inspect-fig.d.ts","sourceRoot":"","sources":["../src/inspect-fig.ts"],"names":[],"mappings":";AACA;;;;;;;;;;;;GAYG"}
1
+ {"version":3,"file":"inspect-fig.d.ts","sourceRoot":"","sources":["../src/inspect-fig.ts"],"names":[],"mappings":";AACA;;;;;;;;;;;;GAYG;AAcH,wBAAsB,UAAU,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,IAAI,CAAC,CA4H9D"}
@@ -13,8 +13,7 @@
13
13
  * json - Output simplified JSON
14
14
  */
15
15
  import { readFigFile, listFigContents, parseCanvasFig, getSchemaInfo, extractDocumentTree, getDocumentSummary, simplifyNode, countNodesByType, } from "./parser/index.js";
16
- async function main() {
17
- const args = process.argv.slice(2);
16
+ export async function runInspect(args) {
18
17
  if (args.length === 0) {
19
18
  console.log(`
20
19
  Fig Inspector - Inspect .fig files
@@ -130,5 +129,10 @@ Commands:
130
129
  process.exit(1);
131
130
  }
132
131
  }
133
- main();
132
+ // Run when executed directly
133
+ const isDirectExecution = import.meta.url === `file://${process.argv[1]}` ||
134
+ process.argv[1]?.endsWith('inspect-fig.ts');
135
+ if (isDirectExecution) {
136
+ runInspect(process.argv.slice(2));
137
+ }
134
138
  //# sourceMappingURL=inspect-fig.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"inspect-fig.js","sourceRoot":"","sources":["../src/inspect-fig.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"inspect-fig.js","sourceRoot":"","sources":["../src/inspect-fig.ts"],"names":[],"mappings":";AACA;;;;;;;;;;;;GAYG;AAGH,OAAO,EACL,WAAW,EACX,eAAe,EACf,cAAc,EACd,aAAa,EACb,mBAAmB,EACnB,kBAAkB,EAClB,YAAY,EACZ,gBAAgB,GACjB,MAAM,mBAAmB,CAAC;AAE3B,MAAM,CAAC,KAAK,UAAU,UAAU,CAAC,IAAc;IAE7C,IAAI,IAAI,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QACtB,OAAO,CAAC,GAAG,CAAC;;;;;;;;;;;;;CAaf,CAAC,CAAC;QACC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC;IAED,MAAM,QAAQ,GAAG,IAAI,CAAC,CAAC,CAAE,CAAC;IAC1B,MAAM,OAAO,GAAG,IAAI,CAAC,CAAC,CAAC,IAAI,SAAS,CAAC;IAErC,IAAI,CAAC;QACH,QAAQ,OAAO,EAAE,CAAC;YAChB,KAAK,MAAM,CAAC,CAAC,CAAC;gBACZ,MAAM,QAAQ,GAAG,MAAM,eAAe,CAAC,QAAQ,CAAC,CAAC;gBACjD,OAAO,CAAC,GAAG,CAAC,mBAAmB,CAAC,CAAC;gBACjC,KAAK,MAAM,IAAI,IAAI,QAAQ,EAAE,CAAC;oBAC5B,OAAO,CAAC,GAAG,CAAC,KAAK,IAAI,EAAE,CAAC,CAAC;gBAC3B,CAAC;gBACD,MAAM;YACR,CAAC;YAED,KAAK,QAAQ,CAAC,CAAC,CAAC;gBACd,MAAM,OAAO,GAAG,MAAM,WAAW,CAAC,QAAQ,CAAC,CAAC;gBAC5C,MAAM,MAAM,GAAG,cAAc,CAAC,OAAO,CAAC,SAAS,CAAC,CAAC;gBACjD,MAAM,UAAU,GAAG,aAAa,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC;gBAChD,OAAO,CAAC,GAAG,CAAC,YAAY,MAAM,CAAC,OAAO,EAAE,CAAC,CAAC;gBAC1C,OAAO,CAAC,GAAG,CAAC,yBAAyB,UAAU,CAAC,eAAe,MAAM,CAAC,CAAC;gBACvE,KAAK,MAAM,GAAG,IAAI,UAAU,CAAC,WAAW,EAAE,CAAC;oBACzC,OAAO,CAAC,GAAG,CAAC,GAAG,GAAG,CAAC,IAAI,IAAI,GAAG,CAAC,IAAI,IAAI,CAAC,CAAC;oBACzC,KAAK,MAAM,KAAK,IAAI,GAAG,CAAC,MAAM,EAAE,CAAC;wBAC/B,MAAM,SAAS,GAAG,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC;wBAC5C,OAAO,CAAC,GAAG,CAAC,KAAK,KAAK,CAAC,IAAI,KAAK,KAAK,CAAC,IAAI,GAAG,SAAS,EAAE,CAAC,CAAC;oBAC5D,CAAC;oBACD,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC;gBACrB,CAAC;gBACD,MAAM;YACR,CAAC;YAED,KAAK,SAAS,CAAC,CAAC,CAAC;gBACf,MAAM,OAAO,GAAG,MAAM,WAAW,CAAC,QAAQ,CAAC,CAAC;gBAC5C,OAAO,CAAC,GAAG,CAAC,SAAS,IAAI,CAAC,SAAS,CAAC,OAAO,CAAC,IAAI,EAAE,IAAI,EAAE,CAAC,CAAC,EAAE,CAAC,CAAC;gBAC9D,OAAO,CAAC,GAAG,CAAC,aAAa,OAAO,CAAC,MAAM,CAAC,IAAI,EAAE,CAAC,CAAC;gBAEhD,MAAM,MAAM,GAAG,cAAc,CAAC,OAAO,CAAC,SAAS,CAAC,CAAC;gBACjD,OAAO,CAAC,GAAG,CAAC,YAAY,MAAM,CAAC,OAAO,EAAE,CAAC,CAAC;gBAE1C,MAAM,QAAQ,GAAG,mBAAmB,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC;gBACrD,IAAI,QAAQ,EAAE,CAAC;oBACb,OAAO,CAAC,GAAG,CAAC,uBAAuB,CAAC,CAAC;oBACrC,OAAO,CAAC,GAAG,CAAC,kBAAkB,CAAC,QAAQ,CAAC,CAAC,CAAC;gBAC5C,CAAC;qBAAM,CAAC;oBACN,OAAO,CAAC,GAAG,CAAC,mCAAmC,CAAC,CAAC;oBACjD,OAAO,CAAC,GAAG,CAAC,mBAAmB,EAAE,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,CAAC;gBAChE,CAAC;gBACD,MAAM;YACR,CAAC;YAED,KAAK,KAAK,CAAC,CAAC,CAAC;gBACX,MAAM,OAAO,GAAG,MAAM,WAAW,CAAC,QAAQ,CAAC,CAAC;gBAC5C,MAAM,MAAM,GAAG,cAAc,CAAC,OAAO,CAAC,SAAS,CAAC,CAAC;gBACjD,IAAI,IAAI,GAAG,IAAI,CAAC,SAAS,CAAC,MAAM,CAAC,OAAO,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC;gBACnD,IAAI,IAAI,CAAC,MAAM,GAAG,KAAK,EAAE,CAAC;oBACxB,IAAI,GAAG,IAAI,CAAC,SAAS,CAAC,CAAC,EAAE,KAAK,CAAC,GAAG,qBAAqB,CAAC;gBAC1D,CAAC;gBACD,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;gBAClB,MAAM;YACR,CAAC;YAED,KAAK,MAAM,CAAC,CAAC,CAAC;gBACZ,MAAM,OAAO,GAAG,MAAM,WAAW,CAAC,QAAQ,CAAC,CAAC;gBAC5C,MAAM,MAAM,GAAG,cAAc,CAAC,OAAO,CAAC,SAAS,CAAC,CAAC;gBACjD,MAAM,QAAQ,GAAG,mBAAmB,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC;gBACrD,IAAI,QAAQ,EAAE,CAAC;oBACb,MAAM,UAAU,GAAG,YAAY,CAAC,QAAQ,CAAC,CAAC;oBAC1C,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,SAAS,CAAC,UAAU,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC,CAAC;gBACnD,CAAC;qBAAM,CAAC;oBACN,OAAO,CAAC,KAAK,CAAC,iCAAiC,CAAC,CAAC;oBACjD,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;gBAClB,CAAC;gBACD,MAAM;YACR,CAAC;YAED,KAAK,OAAO,CAAC,CAAC,CAAC;gBACb,MAAM,OAAO,GAAG,MAAM,WAAW,CAAC,QAAQ,CAAC,CAAC;gBAC5C,MAAM,MAAM,GAAG,cAAc,CAAC,OAAO,CAAC,SAAS,CAAC,CAAC;gBACjD,MAAM,QAAQ,GAAG,mBAAmB,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC;gBACrD,IAAI,QAAQ,EAAE,CAAC;oBACb,MAAM,MAAM,GAAG,gBAAgB,CAAC,QAAQ,CAAC,CAAC;oBAC1C,OAAO,CAAC,GAAG,CAAC,mBAAmB,CAAC,CAAC;oBACjC,MAAM,MAAM,GAAG,MAAM,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC,IAAI,CACxC,CAAC,CAAC,EAAE,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,GAAG,CAAC,CACxB,CAAC;oBACF,KAAK,MAAM,CAAC,IAAI,EAAE,KAAK,CAAC,IAAI,MAAM,EAAE,CAAC;wBACnC,OAAO,CAAC,GAAG,CAAC,KAAK,IAAI,KAAK,KAAK,EAAE,CAAC,CAAC;oBACrC,CAAC;oBACD,OAAO,CAAC,GAAG,CAAC,YAAY,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC,EAAE,CAAC,CAAC;gBAC9E,CAAC;qBAAM,CAAC;oBACN,OAAO,CAAC,KAAK,CAAC,iCAAiC,CAAC,CAAC;oBACjD,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;gBAClB,CAAC;gBACD,MAAM;YACR,CAAC;YAED;gBACE,OAAO,CAAC,KAAK,CAAC,oBAAoB,OAAO,EAAE,CAAC,CAAC;gBAC7C,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QACpB,CAAC;IACH,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,OAAO,CAAC,KAAK,CAAC,QAAQ,EAAE,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC;QACxE,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC;AACH,CAAC;AAED,6BAA6B;AAC7B,MAAM,iBAAiB,GAAG,MAAM,CAAC,IAAI,CAAC,GAAG,KAAK,UAAU,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE;IACvE,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,QAAQ,CAAC,gBAAgB,CAAC,CAAC;AAE9C,IAAI,iBAAiB,EAAE,CAAC;IACtB,UAAU,CAAC,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC;AACpC,CAAC"}
@@ -1,6 +1,7 @@
1
1
  /**
2
2
  * Build script for the web viewer client.
3
3
  * Bundles viewer.ts into a browser-compatible JavaScript file.
4
+ * Also copies static assets to dist/ for npm package.
4
5
  */
5
6
  export {};
6
7
  //# sourceMappingURL=build-client.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"build-client.d.ts","sourceRoot":"","sources":["../../src/web-viewer/build-client.ts"],"names":[],"mappings":"AAAA;;;GAGG"}
1
+ {"version":3,"file":"build-client.d.ts","sourceRoot":"","sources":["../../src/web-viewer/build-client.ts"],"names":[],"mappings":"AAAA;;;;GAIG"}
@@ -1,16 +1,35 @@
1
1
  /**
2
2
  * Build script for the web viewer client.
3
3
  * Bundles viewer.ts into a browser-compatible JavaScript file.
4
+ * Also copies static assets to dist/ for npm package.
4
5
  */
5
6
  import * as esbuild from "esbuild";
7
+ import fs from "node:fs";
6
8
  import path from "node:path";
7
9
  import { fileURLToPath } from "node:url";
8
10
  const __dirname = path.dirname(fileURLToPath(import.meta.url));
11
+ const srcClientDir = path.join(__dirname, "client");
12
+ const distClientDir = path.join(__dirname, "../../dist/web-viewer/client");
13
+ function copyStaticFiles() {
14
+ // Ensure dist directories exist
15
+ fs.mkdirSync(path.join(distClientDir, "dist"), { recursive: true });
16
+ // Copy static files to dist
17
+ const staticFiles = ["index.html", "styles.css"];
18
+ for (const file of staticFiles) {
19
+ const src = path.join(srcClientDir, file);
20
+ const dest = path.join(distClientDir, file);
21
+ if (fs.existsSync(src)) {
22
+ fs.copyFileSync(src, dest);
23
+ console.log(`Copied ${file} to dist/`);
24
+ }
25
+ }
26
+ }
9
27
  async function build() {
10
28
  const watch = process.argv.includes("--watch");
11
- const options = {
12
- entryPoints: [path.join(__dirname, "client/viewer.ts")],
13
- outfile: path.join(__dirname, "client/dist/viewer.js"),
29
+ // Build to src for dev, build to dist for production
30
+ const srcOptions = {
31
+ entryPoints: [path.join(srcClientDir, "viewer.ts")],
32
+ outfile: path.join(srcClientDir, "dist/viewer.js"),
14
33
  bundle: true,
15
34
  minify: !watch,
16
35
  sourcemap: watch,
@@ -20,12 +39,20 @@ async function build() {
20
39
  logLevel: "info",
21
40
  };
22
41
  if (watch) {
23
- const ctx = await esbuild.context(options);
42
+ const ctx = await esbuild.context(srcOptions);
24
43
  await ctx.watch();
25
44
  console.log("Watching for changes...");
26
45
  }
27
46
  else {
28
- await esbuild.build(options);
47
+ // Build to src/client/dist (for dev)
48
+ await esbuild.build(srcOptions);
49
+ // Also build to dist/web-viewer/client/dist (for npm package)
50
+ copyStaticFiles();
51
+ await esbuild.build({
52
+ ...srcOptions,
53
+ outfile: path.join(distClientDir, "dist/viewer.js"),
54
+ sourcemap: false,
55
+ });
29
56
  console.log("Build complete!");
30
57
  }
31
58
  }
@@ -1 +1 @@
1
- {"version":3,"file":"build-client.js","sourceRoot":"","sources":["../../src/web-viewer/build-client.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,KAAK,OAAO,MAAM,SAAS,CAAC;AACnC,OAAO,IAAI,MAAM,WAAW,CAAC;AAC7B,OAAO,EAAE,aAAa,EAAE,MAAM,UAAU,CAAC;AAEzC,MAAM,SAAS,GAAG,IAAI,CAAC,OAAO,CAAC,aAAa,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC;AAE/D,KAAK,UAAU,KAAK;IAClB,MAAM,KAAK,GAAG,OAAO,CAAC,IAAI,CAAC,QAAQ,CAAC,SAAS,CAAC,CAAC;IAE/C,MAAM,OAAO,GAAyB;QACpC,WAAW,EAAE,CAAC,IAAI,CAAC,IAAI,CAAC,SAAS,EAAE,kBAAkB,CAAC,CAAC;QACvD,OAAO,EAAE,IAAI,CAAC,IAAI,CAAC,SAAS,EAAE,uBAAuB,CAAC;QACtD,MAAM,EAAE,IAAI;QACZ,MAAM,EAAE,CAAC,KAAK;QACd,SAAS,EAAE,KAAK;QAChB,MAAM,EAAE,CAAC,WAAW,EAAE,YAAY,EAAE,UAAU,CAAC;QAC/C,MAAM,EAAE,MAAM;QACd,QAAQ,EAAE,SAAS;QACnB,QAAQ,EAAE,MAAM;KACjB,CAAC;IAEF,IAAI,KAAK,EAAE,CAAC;QACV,MAAM,GAAG,GAAG,MAAM,OAAO,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC;QAC3C,MAAM,GAAG,CAAC,KAAK,EAAE,CAAC;QAClB,OAAO,CAAC,GAAG,CAAC,yBAAyB,CAAC,CAAC;IACzC,CAAC;SAAM,CAAC;QACN,MAAM,OAAO,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC;QAC7B,OAAO,CAAC,GAAG,CAAC,iBAAiB,CAAC,CAAC;IACjC,CAAC;AACH,CAAC;AAED,KAAK,EAAE,CAAC,KAAK,CAAC,CAAC,GAAG,EAAE,EAAE;IACpB,OAAO,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;IACnB,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;AAClB,CAAC,CAAC,CAAC"}
1
+ {"version":3,"file":"build-client.js","sourceRoot":"","sources":["../../src/web-viewer/build-client.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,10 @@
1
+ "use strict";(()=>{var _=null,E=[],L=null,y=null,u=1,C="",V=null,f=[],T=null,g=null,r=e=>document.getElementById(e),i={fileName:r("file-name"),openBtn:r("open-btn"),search:r("search"),pagesList:r("pages-list"),tree:r("tree"),canvas:r("canvas"),canvasPlaceholder:r("canvas-placeholder"),zoomIn:r("zoom-in"),zoomOut:r("zoom-out"),zoomLevel:r("zoom-level"),zoomFit:r("zoom-fit"),noSelection:r("no-selection"),nodeDetails:r("node-details"),nodeId:r("node-id"),copyId:r("copy-id"),nodeType:r("node-type"),nodeName:r("node-name"),nodeX:r("node-x"),nodeY:r("node-y"),nodeWidth:r("node-width"),nodeHeight:r("node-height"),textSection:r("text-section"),nodeText:r("node-text"),nodeJson:r("node-json"),fileDialog:r("file-dialog"),filePathInput:r("file-path-input"),cancelOpen:r("cancel-open"),confirmOpen:r("confirm-open")};async function b(e,n){let t=await fetch(e,n);if(!t.ok){let o=await t.json().catch(()=>({error:t.statusText}));throw new Error(o.error||"Request failed")}return t.json()}async function j(){return b("/api/tree")}async function J(e){return b(`/api/node/${encodeURIComponent(e)}`)}async function Z(e){return b(`/api/node-raw/${encodeURIComponent(e)}`)}async function K(e){let n=await fetch(`/api/render/${encodeURIComponent(e)}`);if(!n.ok)throw new Error("Failed to render");return n.text()}async function Q(e){return(await b(`/api/flat-nodes/${encodeURIComponent(e)}`)).nodes}async function ee(e){await b("/api/open",{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({filePath:e})})}function te(e){return{DOCUMENT:"D",CANVAS:"P",FRAME:"F",GROUP:"G",TEXT:"T",RECTANGLE:"R",ELLIPSE:"O",VECTOR:"V",LINE:"L",STAR:"*",REGULAR_POLYGON:"P",COMPONENT:"C",COMPONENT_SET:"S",INSTANCE:"I",BOOLEAN_OPERATION:"B",SLICE:"S",STICKY:"N",SHAPE_WITH_TEXT:"ST",CONNECTOR:"CN",SECTION:"SE"}[e]||"?"}function ne(){i.pagesList.innerHTML="";for(let e of E){let n=document.createElement("div");n.className="page-item",e.id===L&&n.classList.add("selected"),n.dataset.pageId=e.id;let t=document.createElement("span");t.className="page-icon",t.textContent="P",n.appendChild(t);let o=document.createElement("span");o.className="page-name",o.textContent=e.name||"(unnamed)",n.appendChild(o),n.addEventListener("click",()=>ie(e.id)),i.pagesList.appendChild(n)}}function ie(e){L=e,y=null,i.pagesList.querySelectorAll(".page-item").forEach(n=>{n.classList.toggle("selected",n.getAttribute("data-page-id")===e)}),I(),i.canvas.innerHTML='<div id="canvas-placeholder">Select a node to preview</div>',i.noSelection.classList.remove("hidden"),i.nodeDetails.classList.add("hidden")}function oe(e,n){if(!n)return!0;let t=n.toLowerCase();return e.name.toLowerCase().includes(t)||e.type.toLowerCase().includes(t)||e.id.toLowerCase().includes(t)}function G(e,n){return oe(e,n)?!0:e.children?e.children.some(t=>G(t,n)):!1}function N(e,n=0){let t=document.createElement("div");t.className="tree-node",t.dataset.nodeId=e.id;let o=e.children&&e.children.length>0,s=n<2;s&&o&&t.classList.add("expanded");let a=document.createElement("div");a.className="tree-node-row",a.style.paddingLeft=`${n*16+8}px`,e.id===y&&a.classList.add("selected");let l=document.createElement("span");l.className=`tree-toggle ${o?s?"expanded":"collapsed":""}`,o&&l.addEventListener("click",v=>{v.stopPropagation(),t.classList.toggle("expanded"),l.classList.toggle("collapsed"),l.classList.toggle("expanded")}),a.appendChild(l);let c=document.createElement("span");c.className=`tree-icon type-${e.type}`,c.textContent=te(e.type),a.appendChild(c);let d=document.createElement("span");d.className="tree-name",d.textContent=e.name||"(unnamed)",a.appendChild(d);let p=document.createElement("span");if(p.className="tree-type",p.textContent=e.type,a.appendChild(p),a.addEventListener("click",()=>O(e.id)),t.appendChild(a),o){let v=document.createElement("div");v.className="tree-children";for(let w of e.children)C&&!G(w,C)||v.appendChild(N(w,n+1));t.appendChild(v)}return t}function I(){i.tree.innerHTML="";let e=E.find(n=>n.id===L);if(!e){i.tree.innerHTML='<div style="padding: 20px; color: #999;">Select a page to view its contents</div>';return}if(C){let n=o=>{o.classList.add("expanded");let s=o.querySelector(".tree-toggle");s&&(s.classList.remove("collapsed"),s.classList.add("expanded"))},t=document.createDocumentFragment();t.appendChild(N(e)),i.tree.appendChild(t),i.tree.querySelectorAll(".tree-node").forEach(o=>{n(o)})}else i.tree.appendChild(N(e))}async function O(e,n){y=e,i.tree.querySelectorAll(".tree-node-row.selected").forEach(o=>{o.classList.remove("selected")});let t=i.tree.querySelector(`[data-node-id="${e}"] > .tree-node-row`);t&&t.classList.add("selected"),i.noSelection.classList.add("hidden"),i.nodeDetails.classList.remove("hidden"),i.nodeId.textContent=e;try{let[o,s]=await Promise.allSettled([J(e),Z(e)]);if(o.status!=="fulfilled")throw o.reason;let{node:a}=o.value,l=s.status==="fulfilled"?s.value.node:a;i.nodeType.textContent=a.type,i.nodeName.textContent=a.name||"(unnamed)",i.nodeX.textContent=a.x?.toFixed(1)??"-",i.nodeY.textContent=a.y?.toFixed(1)??"-",i.nodeWidth.textContent=a.width?.toFixed(1)??"-",i.nodeHeight.textContent=a.height?.toFixed(1)??"-",a.characters?(i.textSection.classList.remove("hidden"),i.nodeText.textContent=a.characters):i.textSection.classList.add("hidden"),i.nodeJson.textContent=JSON.stringify(l,null,2),n?.skipRender?M(e):await ae(e)}catch(o){console.error("Failed to load node details:",o)}}async function ae(e){let n=e!==V;try{let[t,o]=await Promise.all([K(e),Q(e)]);if(i.canvas.innerHTML=t,i.canvasPlaceholder?.remove(),V=e,f=o,o.length>0){let s=1/0,a=1/0,l=-1/0,c=-1/0;for(let d of o)s=Math.min(s,d.absX),a=Math.min(a,d.absY),l=Math.max(l,d.absX+d.width),c=Math.max(c,d.absY+d.height);g={minX:s,minY:a,width:l-s,height:c-a}}else g=null;if(re(),n){x=0,H=0,u=1;let s=F(),a=i.canvas.parentElement;s?(a.scrollLeft=0,a.scrollTop=0):A()}}catch(t){console.error("Failed to render preview:",t),i.canvas.innerHTML=`<div id="canvas-placeholder">Failed to render: ${t}</div>`,i.canvas.style.width="",i.canvas.style.height="",f=[],g=null}}var x=0,H=0;function F(){let n=i.canvas.parentElement.getBoundingClientRect();i.zoomLevel.textContent=`${Math.round(u*100)}%`,i.canvas.style.transform="";let t=i.canvas.querySelector("svg:not(#hover-overlay)");if(t){x===0&&(x=t.width.baseVal.value||parseFloat(t.getAttribute("width")||"100"),H=t.height.baseVal.value||parseFloat(t.getAttribute("height")||"100"));let o=x*u,s=H*u;t.setAttribute("width",String(o)),t.setAttribute("height",String(s));let a=i.canvas.querySelector("#hover-overlay");a&&(a.setAttribute("width",String(o)),a.setAttribute("height",String(s)));let l=80,c=o+l,d=s+l,p=c<=n.width&&d<=n.height;return p?(i.canvas.style.width="",i.canvas.style.height=""):(i.canvas.style.width=`${c}px`,i.canvas.style.height=`${d}px`),p}return!0}function P(e,n){let t=i.canvas.parentElement,o=t.getBoundingClientRect(),s=u,a=n||{x:o.width/2,y:o.height/2},l=40,c=(t.scrollLeft+a.x-l)/s,d=(t.scrollTop+a.y-l)/s;if(u=e,F())t.scrollLeft=0,t.scrollTop=0;else{let v=c*e+l-a.x,w=d*e+l-a.y,q=Math.max(0,t.scrollWidth-t.clientWidth),U=Math.max(0,t.scrollHeight-t.clientHeight);t.scrollLeft=Math.max(0,Math.min(q,v)),t.scrollTop=Math.max(0,Math.min(U,w))}}function Y(){let e=Math.min(u*1.15,10);P(e)}function X(){let e=Math.max(u/1.15,.1);P(e)}function se(e,n){let t=Math.max(-100,Math.min(100,e)),o=1+Math.abs(t)*.003,s;t<0?s=Math.min(u*o,10):s=Math.max(u/o,.1),P(s,n)}function A(){let e=i.canvas.querySelector("svg:not(#hover-overlay)");if(!e)return;let n=i.canvas.parentElement,t=n.getBoundingClientRect(),o=e.width.baseVal.value||parseFloat(e.getAttribute("width")||"100"),s=e.height.baseVal.value||parseFloat(e.getAttribute("height")||"100"),a=80,l=(t.width-a)/o,c=(t.height-a)/s;u=Math.min(l,c,1);let d=F();n.scrollLeft=0,n.scrollTop=0}var h=null,m=null;function re(){m&&m.remove();let e=i.canvas.querySelector("svg");e&&(m=document.createElement("div"),m.id="svg-wrapper",m.style.cssText=`
2
+ position: relative;
3
+ display: inline-block;
4
+ `,e.parentNode?.insertBefore(m,e),m.appendChild(e),h=document.createElementNS("http://www.w3.org/2000/svg","svg"),h.id="hover-overlay",h.style.cssText=`
5
+ position: absolute;
6
+ top: 0;
7
+ left: 0;
8
+ pointer-events: none;
9
+ overflow: visible;
10
+ `,m.appendChild(h))}function z(){return m?m.querySelector("svg:not(#hover-overlay)"):i.canvas.querySelector("svg:not(#hover-overlay)")}function M(e){if(!h||!g||(h.innerHTML="",!e))return;let n=f.find(d=>d.id===e);if(!n)return;let t=z();if(!t)return;let o=t.width.baseVal.value||parseFloat(t.getAttribute("width")||"0"),s=t.height.baseVal.value||parseFloat(t.getAttribute("height")||"0");h.setAttribute("viewBox",`0 0 ${o} ${s}`),h.setAttribute("width",String(o)),h.setAttribute("height",String(s));let a=n.absX-g.minX,l=n.absY-g.minY,c=document.createElementNS("http://www.w3.org/2000/svg","rect");c.setAttribute("x",String(a)),c.setAttribute("y",String(l)),c.setAttribute("width",String(n.width)),c.setAttribute("height",String(n.height)),c.setAttribute("fill","rgba(0, 120, 212, 0.1)"),c.setAttribute("stroke","#0078d4"),c.setAttribute("stroke-width","2"),h.appendChild(c)}function k(e,n){let t=z();if(!t||!g)return null;let o=t.getBoundingClientRect(),s=t.width.baseVal.value||parseFloat(t.getAttribute("width")||"0"),a=t.height.baseVal.value||parseFloat(t.getAttribute("height")||"0"),l=(e-o.left)/u,c=(n-o.top)/u,d=l+g.minX,p=c+g.minY;return{x:d,y:p}}function R(e,n){return f.filter(t=>t.visible&&e>=t.absX&&e<=t.absX+t.width&&n>=t.absY&&n<=t.absY+t.height).sort((t,o)=>o.depth-t.depth)}function D(e){return e.length===0?null:e[0]}function $(e){let n=i.tree.querySelector(`[data-node-id="${e}"]`);if(!n)return;let t=n.parentElement;for(;t;){if(t.classList?.contains("tree-node")){t.classList.add("expanded");let s=t.querySelector(":scope > .tree-node-row > .tree-toggle");s&&(s.classList.remove("collapsed"),s.classList.add("expanded"))}if(t.id==="tree")break;t=t.parentElement}let o=n.querySelector(":scope > .tree-node-row");o&&o.scrollIntoView({behavior:"smooth",block:"center"})}function le(e){if(f.length===0)return;let n=k(e.clientX,e.clientY);if(!n){T=null,M(null);return}let t=R(n.x,n.y),o=D(t);o?.id!==T&&(T=o?.id??null,M(T))}function ce(e){if(f.length===0)return;let n=k(e.clientX,e.clientY);if(!n)return;let t=R(n.x,n.y),o=D(t);if(o){$(o.id);let s=f.some(a=>a.id===o.id);O(o.id,{skipRender:s})}}function de(e){if(f.length===0)return;let n=k(e.clientX,e.clientY);if(!n)return;let t=R(n.x,n.y),o=D(t);o&&($(o.id),O(o.id))}function ue(){T=null,M(null)}function me(){i.fileDialog.classList.remove("hidden"),i.filePathInput.focus()}function S(){i.fileDialog.classList.add("hidden")}async function B(){let e=i.filePathInput.value.trim();if(e)try{i.confirmOpen.disabled=!0,i.confirmOpen.textContent="Loading...",await ee(e),S(),L=null,y=null,await W(),i.fileName.textContent=e.split("/").pop()||e}catch(n){alert(`Failed to open file: ${n}`)}finally{i.confirmOpen.disabled=!1,i.confirmOpen.textContent="Open"}}async function W(){try{let{tree:e,meta:n}=await j();_=e,E=[],e.children&&(E=e.children.filter(t=>t.type==="CANVAS")),E.length>0&&!L&&(L=E[0].id),ne(),I(),n?.name&&(i.fileName.textContent=n.name)}catch(e){console.error("Failed to load tree:",e),E=[],i.pagesList.innerHTML="",i.tree.innerHTML='<div style="padding: 20px; color: #999;">No file loaded. Click "Open File" to start.</div>'}}async function he(){if(y)try{await navigator.clipboard.writeText(y);let e=i.copyId.textContent;i.copyId.textContent="Copied!",setTimeout(()=>{i.copyId.textContent=e},1e3)}catch{let e=document.createElement("textarea");e.value=y,document.body.appendChild(e),e.select(),document.execCommand("copy"),document.body.removeChild(e)}}function pe(){i.zoomIn.addEventListener("click",Y),i.zoomOut.addEventListener("click",X),i.zoomFit.addEventListener("click",A),document.addEventListener("keydown",e=>{e.target instanceof HTMLInputElement||(e.key==="="||e.key==="+"?(e.preventDefault(),Y()):e.key==="-"?(e.preventDefault(),X()):e.key==="0"&&(e.preventDefault(),A()))}),i.canvas.parentElement?.addEventListener("wheel",e=>{if(e.ctrlKey||e.metaKey){e.preventDefault();let t=i.canvas.parentElement.getBoundingClientRect(),o={x:e.clientX-t.left,y:e.clientY-t.top};se(e.deltaY,o)}},{passive:!1}),i.canvas.addEventListener("mousemove",le),i.canvas.addEventListener("click",ce),i.canvas.addEventListener("dblclick",de),i.canvas.addEventListener("mouseleave",ue),i.search.addEventListener("input",e=>{C=e.target.value,I()}),i.openBtn.addEventListener("click",me),i.cancelOpen.addEventListener("click",S),i.confirmOpen.addEventListener("click",B),i.filePathInput.addEventListener("keydown",e=>{e.key==="Enter"?B():e.key==="Escape"&&S()}),i.fileDialog.addEventListener("click",e=>{e.target===i.fileDialog&&S()}),i.copyId.addEventListener("click",he),W()}document.addEventListener("DOMContentLoaded",pe);})();
@@ -0,0 +1,138 @@
1
+ <!DOCTYPE html>
2
+ <html lang="en">
3
+ <head>
4
+ <meta charset="UTF-8">
5
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
6
+ <title>Fig Viewer</title>
7
+ <link rel="stylesheet" href="/styles.css">
8
+ </head>
9
+ <body>
10
+ <div id="app">
11
+ <!-- Header -->
12
+ <header id="header">
13
+ <h1>Fig Viewer</h1>
14
+ <div id="file-info">
15
+ <span id="file-name">No file loaded</span>
16
+ <button id="open-btn" title="Open .fig file">Open File</button>
17
+ </div>
18
+ </header>
19
+
20
+ <!-- Main layout -->
21
+ <div id="main">
22
+ <!-- Left panel: Tree view -->
23
+ <aside id="tree-panel">
24
+ <!-- Pages list -->
25
+ <div id="pages-section">
26
+ <div id="pages-header">
27
+ <span>Pages</span>
28
+ </div>
29
+ <div id="pages-list"></div>
30
+ </div>
31
+
32
+ <!-- Tree with search -->
33
+ <div id="tree-section">
34
+ <div id="tree-header">
35
+ <input type="text" id="search" placeholder="Search nodes..." />
36
+ </div>
37
+ <div id="tree-container">
38
+ <div id="tree"></div>
39
+ </div>
40
+ </div>
41
+ </aside>
42
+
43
+ <!-- Center: Canvas/Preview -->
44
+ <main id="canvas-panel">
45
+ <div id="canvas-toolbar">
46
+ <button id="zoom-in" title="Zoom in">+</button>
47
+ <span id="zoom-level">100%</span>
48
+ <button id="zoom-out" title="Zoom out">-</button>
49
+ <button id="zoom-fit" title="Fit to view">Fit</button>
50
+ </div>
51
+ <div id="canvas-container">
52
+ <div id="canvas">
53
+ <div id="canvas-placeholder">
54
+ Select a node to preview
55
+ </div>
56
+ </div>
57
+ </div>
58
+ </main>
59
+
60
+ <!-- Right panel: Node details -->
61
+ <aside id="details-panel">
62
+ <div id="details-header">
63
+ <h2>Node Details</h2>
64
+ </div>
65
+ <div id="details-content">
66
+ <div id="no-selection">Select a node to see details</div>
67
+ <div id="node-details" class="hidden">
68
+ <div class="detail-section">
69
+ <div class="detail-row">
70
+ <label>ID</label>
71
+ <div class="detail-value">
72
+ <code id="node-id"></code>
73
+ <button id="copy-id" title="Copy ID">Copy</button>
74
+ </div>
75
+ </div>
76
+ <div class="detail-row">
77
+ <label>Type</label>
78
+ <span id="node-type"></span>
79
+ </div>
80
+ <div class="detail-row">
81
+ <label>Name</label>
82
+ <span id="node-name"></span>
83
+ </div>
84
+ </div>
85
+
86
+ <div class="detail-section">
87
+ <h3>Bounds</h3>
88
+ <div class="detail-grid">
89
+ <div class="detail-cell">
90
+ <label>X</label>
91
+ <span id="node-x">-</span>
92
+ </div>
93
+ <div class="detail-cell">
94
+ <label>Y</label>
95
+ <span id="node-y">-</span>
96
+ </div>
97
+ <div class="detail-cell">
98
+ <label>W</label>
99
+ <span id="node-width">-</span>
100
+ </div>
101
+ <div class="detail-cell">
102
+ <label>H</label>
103
+ <span id="node-height">-</span>
104
+ </div>
105
+ </div>
106
+ </div>
107
+
108
+ <div class="detail-section" id="text-section">
109
+ <h3>Text</h3>
110
+ <div id="node-text"></div>
111
+ </div>
112
+
113
+ <div class="detail-section">
114
+ <h3>Raw JSON</h3>
115
+ <pre id="node-json"></pre>
116
+ </div>
117
+ </div>
118
+ </div>
119
+ </aside>
120
+ </div>
121
+ </div>
122
+
123
+ <!-- File picker dialog (hidden by default) -->
124
+ <div id="file-dialog" class="dialog hidden">
125
+ <div class="dialog-content">
126
+ <h2>Open .fig File</h2>
127
+ <p>Enter the path to a .fig file on your local machine:</p>
128
+ <input type="text" id="file-path-input" placeholder="/path/to/design.fig" />
129
+ <div class="dialog-buttons">
130
+ <button id="cancel-open">Cancel</button>
131
+ <button id="confirm-open" class="primary">Open</button>
132
+ </div>
133
+ </div>
134
+ </div>
135
+
136
+ <script src="/viewer.js"></script>
137
+ </body>
138
+ </html>