Revert mermaid plugin (crashes VitePress dev), use tables instead
vitepress-plugin-mermaid patches vitepress's client app entry, which breaks ESM module resolution and renders all pages blank. Replace mermaid diagrams with offset/content tables and pipeline code blocks that render correctly.
This commit is contained in:
parent
8d140eef7c
commit
16033c4c56
10
bun.lock
10
bun.lock
|
|
@ -122,9 +122,7 @@
|
|||
"name": "@open-pencil/docs",
|
||||
"version": "0.1.0",
|
||||
"devDependencies": {
|
||||
"mermaid": "11.4.1",
|
||||
"vitepress": "^1.6.4",
|
||||
"vitepress-plugin-mermaid": "^2.0.17",
|
||||
},
|
||||
},
|
||||
"packages/mcp": {
|
||||
|
|
@ -644,8 +642,6 @@
|
|||
|
||||
"@libp2p/websockets": ["@libp2p/websockets@9.2.16", "", { "dependencies": { "@libp2p/interface": "^2.10.4", "@libp2p/utils": "^6.7.0", "@multiformats/multiaddr": "^12.4.4", "@multiformats/multiaddr-matcher": "^1.7.2", "@multiformats/multiaddr-to-uri": "^11.0.0", "@types/ws": "^8.18.1", "it-ws": "^6.1.5", "main-event": "^1.0.1", "p-defer": "^4.0.1", "p-event": "^6.0.1", "progress-events": "^1.0.1", "race-signal": "^1.1.3", "ws": "^8.18.2" } }, "sha512-jD96ClKeaZvTs+YyGJxOOQSWVe9e9SHmacJ9uE9dqWZjCbPICdCJnOj2pLg258WxVrc+/MRFKSHE/v5f2ZJGCA=="],
|
||||
|
||||
"@mermaid-js/mermaid-mindmap": ["@mermaid-js/mermaid-mindmap@9.3.0", "", { "dependencies": { "@braintree/sanitize-url": "^6.0.0", "cytoscape": "^3.23.0", "cytoscape-cose-bilkent": "^4.1.0", "cytoscape-fcose": "^2.1.0", "d3": "^7.0.0", "khroma": "^2.0.0", "non-layered-tidy-tree-layout": "^2.0.2" } }, "sha512-IhtYSVBBRYviH1Ehu8gk69pMDF8DSRqXBRDMWrEfHoaMruHeaP2DXA3PBnuwsMaCdPQhlUUcy/7DBLAEIXvCAw=="],
|
||||
|
||||
"@mermaid-js/parser": ["@mermaid-js/parser@0.3.0", "", { "dependencies": { "langium": "3.0.0" } }, "sha512-HsvL6zgE5sUPGgkIDlmAWR1HTNHz2Iy11BAWPTa4Jjabkpguy4Ze2gzfLrg6pdRuBvFwgUYyxiaNqZwrEEXepA=="],
|
||||
|
||||
"@modelcontextprotocol/sdk": ["@modelcontextprotocol/sdk@1.27.1", "", { "dependencies": { "@hono/node-server": "^1.19.9", "ajv": "^8.17.1", "ajv-formats": "^3.0.1", "content-type": "^1.0.5", "cors": "^2.8.5", "cross-spawn": "^7.0.5", "eventsource": "^3.0.2", "eventsource-parser": "^3.0.0", "express": "^5.2.1", "express-rate-limit": "^8.2.1", "hono": "^4.11.4", "jose": "^6.1.3", "json-schema-typed": "^8.0.2", "pkce-challenge": "^5.0.0", "raw-body": "^3.0.0", "zod": "^3.25 || ^4.0", "zod-to-json-schema": "^3.25.1" }, "peerDependencies": { "@cfworker/json-schema": "^4.1.1" }, "optionalPeers": ["@cfworker/json-schema"] }, "sha512-sr6GbP+4edBwFndLbM60gf07z0FQ79gaExpnsjMGePXqFcSSb7t6iscpjk9DhFhwd+mTEQrzNafGP8/iGGFYaA=="],
|
||||
|
|
@ -2058,8 +2054,6 @@
|
|||
|
||||
"node-sarif-builder": ["node-sarif-builder@3.4.0", "", { "dependencies": { "@types/sarif": "^2.1.7", "fs-extra": "^11.1.1" } }, "sha512-tGnJW6OKRii9u/b2WiUViTJS+h7Apxx17qsMUjsUeNDiMMX5ZFf8F8Fcz7PAQ6omvOxHZtvDTmOYKJQwmfpjeg=="],
|
||||
|
||||
"non-layered-tidy-tree-layout": ["non-layered-tidy-tree-layout@2.0.2", "", {}, "sha512-gkXMxRzUH+PB0ax9dUN0yYF0S25BqeAYqhgMaLUFmpXLEk7Fcu8f4emJuOAY0V8kjDICxROIKsTAKsV/v355xw=="],
|
||||
|
||||
"npm-run-path": ["npm-run-path@4.0.1", "", { "dependencies": { "path-key": "^3.0.0" } }, "sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw=="],
|
||||
|
||||
"number-allocator": ["number-allocator@1.0.14", "", { "dependencies": { "debug": "^4.3.1", "js-sdsl": "4.3.0" } }, "sha512-OrL44UTVAvkKdOdRQZIJpLkAdjXGTRda052sN4sO77bKEzYYqWKMBjQvrJFzqygI99gL6Z4u2xctPW1tB8ErvA=="],
|
||||
|
|
@ -2506,8 +2500,6 @@
|
|||
|
||||
"vitepress": ["vitepress@1.6.4", "", { "dependencies": { "@docsearch/css": "3.8.2", "@docsearch/js": "3.8.2", "@iconify-json/simple-icons": "^1.2.21", "@shikijs/core": "^2.1.0", "@shikijs/transformers": "^2.1.0", "@shikijs/types": "^2.1.0", "@types/markdown-it": "^14.1.2", "@vitejs/plugin-vue": "^5.2.1", "@vue/devtools-api": "^7.7.0", "@vue/shared": "^3.5.13", "@vueuse/core": "^12.4.0", "@vueuse/integrations": "^12.4.0", "focus-trap": "^7.6.4", "mark.js": "8.11.1", "minisearch": "^7.1.1", "shiki": "^2.1.0", "vite": "^5.4.14", "vue": "^3.5.13" }, "peerDependencies": { "markdown-it-mathjax3": "^4", "postcss": "^8" }, "optionalPeers": ["markdown-it-mathjax3", "postcss"], "bin": { "vitepress": "bin/vitepress.js" } }, "sha512-+2ym1/+0VVrbhNyRoFFesVvBvHAVMZMK0rw60E3X/5349M1GuVdKeazuksqopEdvkKwKGs21Q729jX81/bkBJg=="],
|
||||
|
||||
"vitepress-plugin-mermaid": ["vitepress-plugin-mermaid@2.0.17", "", { "optionalDependencies": { "@mermaid-js/mermaid-mindmap": "^9.3.0" }, "peerDependencies": { "mermaid": "10 || 11", "vitepress": "^1.0.0 || ^1.0.0-alpha" } }, "sha512-IUzYpwf61GC6k0XzfmAmNrLvMi9TRrVRMsUyCA8KNXhg/mQ1VqWnO0/tBVPiX5UoKF1mDUwqn5QV4qAJl6JnUg=="],
|
||||
|
||||
"void-elements": ["void-elements@3.1.0", "", {}, "sha512-Dhxzh5HZuiHQhbvTW9AMetFfBHDMYpo23Uo9btPXgdYP+3T5S+p+jgNy7spra+veYhBP2dCSgxR/i2Y02h5/6w=="],
|
||||
|
||||
"vscode-jsonrpc": ["vscode-jsonrpc@8.2.0", "", {}, "sha512-C+r0eKJUIfiDIfwJhria30+TYWPtuHJXHtI7J0YlOmKAo7ogxP20T0zxB7HZQIFhIyvoBPwWskjxrvAtfjyZfA=="],
|
||||
|
|
@ -2650,8 +2642,6 @@
|
|||
|
||||
"@libp2p/crypto/@noble/hashes": ["@noble/hashes@2.0.1", "", {}, "sha512-XlOlEbQcE9fmuXxrVTXCTlG2nlRXa9Rj3rr5Ue/+tX+nmkgbX720YHh0VR3hBF9xDvwnb8D2shVGOwNx+ulArw=="],
|
||||
|
||||
"@mermaid-js/mermaid-mindmap/@braintree/sanitize-url": ["@braintree/sanitize-url@6.0.4", "", {}, "sha512-s3jaWicZd0pkP0jf5ysyHUI/RE7MHos6qlToFcGWXVp+ykHOy77OUMrfbgJ9it2C5bow7OIQwYYaHjk9XlBQ2A=="],
|
||||
|
||||
"@modelcontextprotocol/sdk/@hono/node-server": ["@hono/node-server@1.19.9", "", { "peerDependencies": { "hono": "^4" } }, "sha512-vHL6w3ecZsky+8P5MD+eFfaGTyCeOHUIFYMGpQGbrBTSmNNoxv0if69rEZ5giu36weC5saFuznL411gRX7bJDw=="],
|
||||
|
||||
"@modelcontextprotocol/sdk/hono": ["hono@4.12.3", "", {}, "sha512-SFsVSjp8sj5UumXOOFlkZOG6XS9SJDKw0TbwFeV+AJ8xlST8kxK5Z/5EYa111UY8732lK2S/xB653ceuaoGwpg=="],
|
||||
|
|
|
|||
|
|
@ -1,5 +1,4 @@
|
|||
import { defineConfig, type DefaultTheme } from 'vitepress'
|
||||
import { withMermaid } from 'vitepress-plugin-mermaid'
|
||||
|
||||
interface SidebarLabels {
|
||||
gettingAround: string
|
||||
|
|
@ -207,7 +206,7 @@ const LOCALES: Record<string, { hreflang: string; ogLocale: string; prefix: stri
|
|||
ru: { hreflang: 'ru', ogLocale: 'ru_RU', prefix: '/ru' },
|
||||
}
|
||||
|
||||
export default withMermaid(defineConfig({
|
||||
export default defineConfig({
|
||||
title: 'OpenPencil',
|
||||
description: 'Open-source, AI-native design editor. Figma alternative built from scratch with full .fig file compatibility.',
|
||||
cleanUrls: true,
|
||||
|
|
@ -376,4 +375,4 @@ export default withMermaid(defineConfig({
|
|||
message: 'Released under the MIT License.',
|
||||
},
|
||||
},
|
||||
}))
|
||||
})
|
||||
|
|
|
|||
|
|
@ -4,41 +4,30 @@
|
|||
|
||||
A `.fig` file is a ZIP archive containing a Kiwi-encoded binary message:
|
||||
|
||||
```mermaid
|
||||
block-beta
|
||||
columns 1
|
||||
A["Magic header: <code>fig-kiwi</code> (8 bytes)"]
|
||||
B["Version (4 bytes, uint32 LE)"]
|
||||
C["Schema length (4 bytes, uint32 LE)"]
|
||||
D["Compressed Kiwi schema"]
|
||||
E["Message length (4 bytes, uint32 LE)"]
|
||||
F["Compressed Kiwi message — NodeChange[]"]
|
||||
G["Blob data — images, vector networks, fonts"]
|
||||
```
|
||||
| Offset | Content |
|
||||
|--------|---------|
|
||||
| 0 | Magic header `fig-kiwi` (8 bytes) |
|
||||
| 8 | Version (4 bytes, uint32 LE) |
|
||||
| 12 | Schema length (4 bytes, uint32 LE) |
|
||||
| 16 | Compressed Kiwi schema |
|
||||
| … | Message length (4 bytes, uint32 LE) |
|
||||
| … | Compressed Kiwi message — `NodeChange[]` (entire document) |
|
||||
| … | Blob data — images, vector networks, fonts |
|
||||
|
||||
## Import Pipeline
|
||||
|
||||
```mermaid
|
||||
flowchart LR
|
||||
A[".fig file"] --> B["Parse header"]
|
||||
B --> C["Decompress Zstd"]
|
||||
C --> D["Decode Kiwi schema"]
|
||||
D --> E["Decode message"]
|
||||
E --> F["NodeChange[]"]
|
||||
F --> G["Build SceneGraph"]
|
||||
G --> H["Resolve blob refs"]
|
||||
H --> I["Render"]
|
||||
```
|
||||
.fig file → parse header → decompress Zstd → decode Kiwi schema
|
||||
→ decode message → NodeChange[] → build SceneGraph
|
||||
→ resolve blob refs → render on canvas
|
||||
```
|
||||
|
||||
## Export Pipeline
|
||||
|
||||
```mermaid
|
||||
flowchart LR
|
||||
A["SceneGraph"] --> B["NodeChange[]"]
|
||||
B --> C["Kiwi encode"]
|
||||
C --> D["Compress"]
|
||||
D --> E["Build ZIP"]
|
||||
E --> F[".fig file"]
|
||||
```
|
||||
SceneGraph → NodeChange[] → Kiwi encode → compress (Zstd/deflate)
|
||||
→ build ZIP (header + schema + message + thumbnail.png)
|
||||
→ write .fig file
|
||||
```
|
||||
|
||||
Export uses <kbd>⌘</kbd><kbd>S</kbd> (Save) and <kbd>⇧</kbd><kbd>⌘</kbd><kbd>S</kbd> (Save As) with native OS dialogs on the desktop app. The exported file includes a `thumbnail.png` required by Figma for file preview.
|
||||
|
|
@ -77,18 +66,7 @@ Figma's schema uses non-contiguous field IDs (e.g. 1, 2, 5, 10 with gaps). The k
|
|||
|
||||
Copy/paste uses the same Kiwi binary encoding:
|
||||
|
||||
```mermaid
|
||||
flowchart LR
|
||||
subgraph Copy
|
||||
A["Selected nodes"] --> B["Encode NodeChange[]"]
|
||||
B --> C["Compress"]
|
||||
C --> D["Clipboard<br/><code>application/x-figma-design</code>"]
|
||||
end
|
||||
subgraph Paste
|
||||
D --> E["Decompress"]
|
||||
E --> F["Decode Kiwi"]
|
||||
F --> G["Create nodes"]
|
||||
end
|
||||
```
|
||||
1. **Copy** — encode selected `NodeChange[]` to Kiwi binary, compress, write to clipboard as `application/x-figma-design` MIME type
|
||||
2. **Paste** — read clipboard, decompress, decode Kiwi binary, create nodes in scene graph
|
||||
|
||||
This enables bidirectional clipboard between OpenPencil and Figma.
|
||||
Encoding happens synchronously in the copy event handler (not async Clipboard API) for browser compatibility. This enables bidirectional clipboard between OpenPencil and Figma.
|
||||
|
|
|
|||
|
|
@ -4,41 +4,30 @@
|
|||
|
||||
A `.fig` file is a ZIP archive containing a Kiwi-encoded binary message:
|
||||
|
||||
```mermaid
|
||||
block-beta
|
||||
columns 1
|
||||
A["Magic header: <code>fig-kiwi</code> (8 bytes)"]
|
||||
B["Version (4 bytes, uint32 LE)"]
|
||||
C["Schema length (4 bytes, uint32 LE)"]
|
||||
D["Compressed Kiwi schema"]
|
||||
E["Message length (4 bytes, uint32 LE)"]
|
||||
F["Compressed Kiwi message — NodeChange[]"]
|
||||
G["Blob data — images, vector networks, fonts"]
|
||||
```
|
||||
| Offset | Content |
|
||||
|--------|---------|
|
||||
| 0 | Magic header `fig-kiwi` (8 bytes) |
|
||||
| 8 | Version (4 bytes, uint32 LE) |
|
||||
| 12 | Schema length (4 bytes, uint32 LE) |
|
||||
| 16 | Compressed Kiwi schema |
|
||||
| … | Message length (4 bytes, uint32 LE) |
|
||||
| … | Compressed Kiwi message — `NodeChange[]` (entire document) |
|
||||
| … | Blob data — images, vector networks, fonts |
|
||||
|
||||
## Import Pipeline
|
||||
|
||||
```mermaid
|
||||
flowchart LR
|
||||
A[".fig file"] --> B["Parse header"]
|
||||
B --> C["Decompress Zstd"]
|
||||
C --> D["Decode Kiwi schema"]
|
||||
D --> E["Decode message"]
|
||||
E --> F["NodeChange[]"]
|
||||
F --> G["Build SceneGraph"]
|
||||
G --> H["Resolve blob refs"]
|
||||
H --> I["Render"]
|
||||
```
|
||||
.fig file → parse header → decompress Zstd → decode Kiwi schema
|
||||
→ decode message → NodeChange[] → build SceneGraph
|
||||
→ resolve blob refs → render on canvas
|
||||
```
|
||||
|
||||
## Export Pipeline
|
||||
|
||||
```mermaid
|
||||
flowchart LR
|
||||
A["SceneGraph"] --> B["NodeChange[]"]
|
||||
B --> C["Kiwi encode"]
|
||||
C --> D["Compress"]
|
||||
D --> E["Build ZIP"]
|
||||
E --> F[".fig file"]
|
||||
```
|
||||
SceneGraph → NodeChange[] → Kiwi encode → compress (Zstd/deflate)
|
||||
→ build ZIP (header + schema + message + thumbnail.png)
|
||||
→ write .fig file
|
||||
```
|
||||
|
||||
Export uses <kbd>⌘</kbd><kbd>S</kbd> (Save) and <kbd>⇧</kbd><kbd>⌘</kbd><kbd>S</kbd> (Save As) with native OS dialogs on the desktop app. The exported file includes a `thumbnail.png` required by Figma for file preview.
|
||||
|
|
@ -77,18 +66,7 @@ Figma's schema uses non-contiguous field IDs (e.g. 1, 2, 5, 10 with gaps). The k
|
|||
|
||||
Copy/paste uses the same Kiwi binary encoding:
|
||||
|
||||
```mermaid
|
||||
flowchart LR
|
||||
subgraph Copy
|
||||
A["Selected nodes"] --> B["Encode NodeChange[]"]
|
||||
B --> C["Compress"]
|
||||
C --> D["Clipboard<br/><code>application/x-figma-design</code>"]
|
||||
end
|
||||
subgraph Paste
|
||||
D --> E["Decompress"]
|
||||
E --> F["Decode Kiwi"]
|
||||
F --> G["Create nodes"]
|
||||
end
|
||||
```
|
||||
1. **Copy** — encode selected `NodeChange[]` to Kiwi binary, compress, write to clipboard as `application/x-figma-design` MIME type
|
||||
2. **Paste** — read clipboard, decompress, decode Kiwi binary, create nodes in scene graph
|
||||
|
||||
This enables bidirectional clipboard between OpenPencil and Figma.
|
||||
Encoding happens synchronously in the copy event handler (not async Clipboard API) for browser compatibility. This enables bidirectional clipboard between OpenPencil and Figma.
|
||||
|
|
|
|||
|
|
@ -4,41 +4,30 @@
|
|||
|
||||
A `.fig` file is a ZIP archive containing a Kiwi-encoded binary message:
|
||||
|
||||
```mermaid
|
||||
block-beta
|
||||
columns 1
|
||||
A["Magic header: <code>fig-kiwi</code> (8 bytes)"]
|
||||
B["Version (4 bytes, uint32 LE)"]
|
||||
C["Schema length (4 bytes, uint32 LE)"]
|
||||
D["Compressed Kiwi schema"]
|
||||
E["Message length (4 bytes, uint32 LE)"]
|
||||
F["Compressed Kiwi message — NodeChange[]"]
|
||||
G["Blob data — images, vector networks, fonts"]
|
||||
```
|
||||
| Offset | Content |
|
||||
|--------|---------|
|
||||
| 0 | Magic header `fig-kiwi` (8 bytes) |
|
||||
| 8 | Version (4 bytes, uint32 LE) |
|
||||
| 12 | Schema length (4 bytes, uint32 LE) |
|
||||
| 16 | Compressed Kiwi schema |
|
||||
| … | Message length (4 bytes, uint32 LE) |
|
||||
| … | Compressed Kiwi message — `NodeChange[]` (entire document) |
|
||||
| … | Blob data — images, vector networks, fonts |
|
||||
|
||||
## Import Pipeline
|
||||
|
||||
```mermaid
|
||||
flowchart LR
|
||||
A[".fig file"] --> B["Parse header"]
|
||||
B --> C["Decompress Zstd"]
|
||||
C --> D["Decode Kiwi schema"]
|
||||
D --> E["Decode message"]
|
||||
E --> F["NodeChange[]"]
|
||||
F --> G["Build SceneGraph"]
|
||||
G --> H["Resolve blob refs"]
|
||||
H --> I["Render"]
|
||||
```
|
||||
.fig file → parse header → decompress Zstd → decode Kiwi schema
|
||||
→ decode message → NodeChange[] → build SceneGraph
|
||||
→ resolve blob refs → render on canvas
|
||||
```
|
||||
|
||||
## Export Pipeline
|
||||
|
||||
```mermaid
|
||||
flowchart LR
|
||||
A["SceneGraph"] --> B["NodeChange[]"]
|
||||
B --> C["Kiwi encode"]
|
||||
C --> D["Compress"]
|
||||
D --> E["Build ZIP"]
|
||||
E --> F[".fig file"]
|
||||
```
|
||||
SceneGraph → NodeChange[] → Kiwi encode → compress (Zstd/deflate)
|
||||
→ build ZIP (header + schema + message + thumbnail.png)
|
||||
→ write .fig file
|
||||
```
|
||||
|
||||
Export uses <kbd>⌘</kbd><kbd>S</kbd> (Save) and <kbd>⇧</kbd><kbd>⌘</kbd><kbd>S</kbd> (Save As) with native OS dialogs on the desktop app. The exported file includes a `thumbnail.png` required by Figma for file preview.
|
||||
|
|
@ -77,18 +66,7 @@ Figma's schema uses non-contiguous field IDs (e.g. 1, 2, 5, 10 with gaps). The k
|
|||
|
||||
Copy/paste uses the same Kiwi binary encoding:
|
||||
|
||||
```mermaid
|
||||
flowchart LR
|
||||
subgraph Copy
|
||||
A["Selected nodes"] --> B["Encode NodeChange[]"]
|
||||
B --> C["Compress"]
|
||||
C --> D["Clipboard<br/><code>application/x-figma-design</code>"]
|
||||
end
|
||||
subgraph Paste
|
||||
D --> E["Decompress"]
|
||||
E --> F["Decode Kiwi"]
|
||||
F --> G["Create nodes"]
|
||||
end
|
||||
```
|
||||
1. **Copy** — encode selected `NodeChange[]` to Kiwi binary, compress, write to clipboard as `application/x-figma-design` MIME type
|
||||
2. **Paste** — read clipboard, decompress, decode Kiwi binary, create nodes in scene graph
|
||||
|
||||
This enables bidirectional clipboard between OpenPencil and Figma.
|
||||
Encoding happens synchronously in the copy event handler (not async Clipboard API) for browser compatibility. This enables bidirectional clipboard between OpenPencil and Figma.
|
||||
|
|
|
|||
|
|
@ -4,41 +4,30 @@
|
|||
|
||||
A `.fig` file is a ZIP archive containing a Kiwi-encoded binary message:
|
||||
|
||||
```mermaid
|
||||
block-beta
|
||||
columns 1
|
||||
A["Magic header: <code>fig-kiwi</code> (8 bytes)"]
|
||||
B["Version (4 bytes, uint32 LE)"]
|
||||
C["Schema length (4 bytes, uint32 LE)"]
|
||||
D["Compressed Kiwi schema"]
|
||||
E["Message length (4 bytes, uint32 LE)"]
|
||||
F["Compressed Kiwi message — NodeChange[]"]
|
||||
G["Blob data — images, vector networks, fonts"]
|
||||
```
|
||||
| Offset | Content |
|
||||
|--------|---------|
|
||||
| 0 | Magic header `fig-kiwi` (8 bytes) |
|
||||
| 8 | Version (4 bytes, uint32 LE) |
|
||||
| 12 | Schema length (4 bytes, uint32 LE) |
|
||||
| 16 | Compressed Kiwi schema |
|
||||
| … | Message length (4 bytes, uint32 LE) |
|
||||
| … | Compressed Kiwi message — `NodeChange[]` (entire document) |
|
||||
| … | Blob data — images, vector networks, fonts |
|
||||
|
||||
## Import Pipeline
|
||||
|
||||
```mermaid
|
||||
flowchart LR
|
||||
A[".fig file"] --> B["Parse header"]
|
||||
B --> C["Decompress Zstd"]
|
||||
C --> D["Decode Kiwi schema"]
|
||||
D --> E["Decode message"]
|
||||
E --> F["NodeChange[]"]
|
||||
F --> G["Build SceneGraph"]
|
||||
G --> H["Resolve blob refs"]
|
||||
H --> I["Render"]
|
||||
```
|
||||
.fig file → parse header → decompress Zstd → decode Kiwi schema
|
||||
→ decode message → NodeChange[] → build SceneGraph
|
||||
→ resolve blob refs → render on canvas
|
||||
```
|
||||
|
||||
## Export Pipeline
|
||||
|
||||
```mermaid
|
||||
flowchart LR
|
||||
A["SceneGraph"] --> B["NodeChange[]"]
|
||||
B --> C["Kiwi encode"]
|
||||
C --> D["Compress"]
|
||||
D --> E["Build ZIP"]
|
||||
E --> F[".fig file"]
|
||||
```
|
||||
SceneGraph → NodeChange[] → Kiwi encode → compress (Zstd/deflate)
|
||||
→ build ZIP (header + schema + message + thumbnail.png)
|
||||
→ write .fig file
|
||||
```
|
||||
|
||||
Export uses <kbd>⌘</kbd><kbd>S</kbd> (Save) and <kbd>⇧</kbd><kbd>⌘</kbd><kbd>S</kbd> (Save As) with native OS dialogs on the desktop app. The exported file includes a `thumbnail.png` required by Figma for file preview.
|
||||
|
|
@ -77,18 +66,7 @@ Figma's schema uses non-contiguous field IDs (e.g. 1, 2, 5, 10 with gaps). The k
|
|||
|
||||
Copy/paste uses the same Kiwi binary encoding:
|
||||
|
||||
```mermaid
|
||||
flowchart LR
|
||||
subgraph Copy
|
||||
A["Selected nodes"] --> B["Encode NodeChange[]"]
|
||||
B --> C["Compress"]
|
||||
C --> D["Clipboard<br/><code>application/x-figma-design</code>"]
|
||||
end
|
||||
subgraph Paste
|
||||
D --> E["Decompress"]
|
||||
E --> F["Decode Kiwi"]
|
||||
F --> G["Create nodes"]
|
||||
end
|
||||
```
|
||||
1. **Copy** — encode selected `NodeChange[]` to Kiwi binary, compress, write to clipboard as `application/x-figma-design` MIME type
|
||||
2. **Paste** — read clipboard, decompress, decode Kiwi binary, create nodes in scene graph
|
||||
|
||||
This enables bidirectional clipboard between OpenPencil and Figma.
|
||||
Encoding happens synchronously in the copy event handler (not async Clipboard API) for browser compatibility. This enables bidirectional clipboard between OpenPencil and Figma.
|
||||
|
|
|
|||
|
|
@ -10,8 +10,6 @@
|
|||
"preview": "vitepress preview"
|
||||
},
|
||||
"devDependencies": {
|
||||
"mermaid": "11.4.1",
|
||||
"vitepress": "^1.6.4",
|
||||
"vitepress-plugin-mermaid": "^2.0.17"
|
||||
"vitepress": "^1.6.4"
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -4,41 +4,30 @@
|
|||
|
||||
A `.fig` file is a ZIP archive containing a Kiwi-encoded binary message:
|
||||
|
||||
```mermaid
|
||||
block-beta
|
||||
columns 1
|
||||
A["Magic header: <code>fig-kiwi</code> (8 bytes)"]
|
||||
B["Version (4 bytes, uint32 LE)"]
|
||||
C["Schema length (4 bytes, uint32 LE)"]
|
||||
D["Compressed Kiwi schema"]
|
||||
E["Message length (4 bytes, uint32 LE)"]
|
||||
F["Compressed Kiwi message — NodeChange[]"]
|
||||
G["Blob data — images, vector networks, fonts"]
|
||||
```
|
||||
| Offset | Content |
|
||||
|--------|---------|
|
||||
| 0 | Magic header `fig-kiwi` (8 bytes) |
|
||||
| 8 | Version (4 bytes, uint32 LE) |
|
||||
| 12 | Schema length (4 bytes, uint32 LE) |
|
||||
| 16 | Compressed Kiwi schema |
|
||||
| … | Message length (4 bytes, uint32 LE) |
|
||||
| … | Compressed Kiwi message — `NodeChange[]` (entire document) |
|
||||
| … | Blob data — images, vector networks, fonts |
|
||||
|
||||
## Import Pipeline
|
||||
|
||||
```mermaid
|
||||
flowchart LR
|
||||
A[".fig file"] --> B["Parse header"]
|
||||
B --> C["Decompress Zstd"]
|
||||
C --> D["Decode Kiwi schema"]
|
||||
D --> E["Decode message"]
|
||||
E --> F["NodeChange[]"]
|
||||
F --> G["Build SceneGraph"]
|
||||
G --> H["Resolve blob refs"]
|
||||
H --> I["Render"]
|
||||
```
|
||||
.fig file → parse header → decompress Zstd → decode Kiwi schema
|
||||
→ decode message → NodeChange[] → build SceneGraph
|
||||
→ resolve blob refs → render on canvas
|
||||
```
|
||||
|
||||
## Export Pipeline
|
||||
|
||||
```mermaid
|
||||
flowchart LR
|
||||
A["SceneGraph"] --> B["NodeChange[]"]
|
||||
B --> C["Kiwi encode"]
|
||||
C --> D["Compress"]
|
||||
D --> E["Build ZIP"]
|
||||
E --> F[".fig file"]
|
||||
```
|
||||
SceneGraph → NodeChange[] → Kiwi encode → compress (Zstd/deflate)
|
||||
→ build ZIP (header + schema + message + thumbnail.png)
|
||||
→ write .fig file
|
||||
```
|
||||
|
||||
Export uses <kbd>⌘</kbd><kbd>S</kbd> (Save) and <kbd>⇧</kbd><kbd>⌘</kbd><kbd>S</kbd> (Save As) with native OS dialogs on the desktop app. The exported file includes a `thumbnail.png` required by Figma for file preview.
|
||||
|
|
@ -77,18 +66,7 @@ Figma's schema uses non-contiguous field IDs (e.g. 1, 2, 5, 10 with gaps). The k
|
|||
|
||||
Copy/paste uses the same Kiwi binary encoding:
|
||||
|
||||
```mermaid
|
||||
flowchart LR
|
||||
subgraph Copy
|
||||
A["Selected nodes"] --> B["Encode NodeChange[]"]
|
||||
B --> C["Compress"]
|
||||
C --> D["Clipboard<br/><code>application/x-figma-design</code>"]
|
||||
end
|
||||
subgraph Paste
|
||||
D --> E["Decompress"]
|
||||
E --> F["Decode Kiwi"]
|
||||
F --> G["Create nodes"]
|
||||
end
|
||||
```
|
||||
1. **Copy** — encode selected `NodeChange[]` to Kiwi binary, compress, write to clipboard as `application/x-figma-design` MIME type
|
||||
2. **Paste** — read clipboard, decompress, decode Kiwi binary, create nodes in scene graph
|
||||
|
||||
This enables bidirectional clipboard between OpenPencil and Figma.
|
||||
Encoding happens synchronously in the copy event handler (not async Clipboard API) for browser compatibility. This enables bidirectional clipboard between OpenPencil and Figma.
|
||||
|
|
|
|||
|
|
@ -4,41 +4,30 @@
|
|||
|
||||
A `.fig` file is a ZIP archive containing a Kiwi-encoded binary message:
|
||||
|
||||
```mermaid
|
||||
block-beta
|
||||
columns 1
|
||||
A["Magic header: <code>fig-kiwi</code> (8 bytes)"]
|
||||
B["Version (4 bytes, uint32 LE)"]
|
||||
C["Schema length (4 bytes, uint32 LE)"]
|
||||
D["Compressed Kiwi schema"]
|
||||
E["Message length (4 bytes, uint32 LE)"]
|
||||
F["Compressed Kiwi message — NodeChange[]"]
|
||||
G["Blob data — images, vector networks, fonts"]
|
||||
```
|
||||
| Offset | Content |
|
||||
|--------|---------|
|
||||
| 0 | Magic header `fig-kiwi` (8 bytes) |
|
||||
| 8 | Version (4 bytes, uint32 LE) |
|
||||
| 12 | Schema length (4 bytes, uint32 LE) |
|
||||
| 16 | Compressed Kiwi schema |
|
||||
| … | Message length (4 bytes, uint32 LE) |
|
||||
| … | Compressed Kiwi message — `NodeChange[]` (entire document) |
|
||||
| … | Blob data — images, vector networks, fonts |
|
||||
|
||||
## Import Pipeline
|
||||
|
||||
```mermaid
|
||||
flowchart LR
|
||||
A[".fig file"] --> B["Parse header"]
|
||||
B --> C["Decompress Zstd"]
|
||||
C --> D["Decode Kiwi schema"]
|
||||
D --> E["Decode message"]
|
||||
E --> F["NodeChange[]"]
|
||||
F --> G["Build SceneGraph"]
|
||||
G --> H["Resolve blob refs"]
|
||||
H --> I["Render"]
|
||||
```
|
||||
.fig file → parse header → decompress Zstd → decode Kiwi schema
|
||||
→ decode message → NodeChange[] → build SceneGraph
|
||||
→ resolve blob refs → render on canvas
|
||||
```
|
||||
|
||||
## Export Pipeline
|
||||
|
||||
```mermaid
|
||||
flowchart LR
|
||||
A["SceneGraph"] --> B["NodeChange[]"]
|
||||
B --> C["Kiwi encode"]
|
||||
C --> D["Compress"]
|
||||
D --> E["Build ZIP"]
|
||||
E --> F[".fig file"]
|
||||
```
|
||||
SceneGraph → NodeChange[] → Kiwi encode → compress (Zstd/deflate)
|
||||
→ build ZIP (header + schema + message + thumbnail.png)
|
||||
→ write .fig file
|
||||
```
|
||||
|
||||
Export uses <kbd>⌘</kbd><kbd>S</kbd> (Save) and <kbd>⇧</kbd><kbd>⌘</kbd><kbd>S</kbd> (Save As) with native OS dialogs on the desktop app. The exported file includes a `thumbnail.png` required by Figma for file preview.
|
||||
|
|
@ -77,18 +66,7 @@ Figma's schema uses non-contiguous field IDs (e.g. 1, 2, 5, 10 with gaps). The k
|
|||
|
||||
Copy/paste uses the same Kiwi binary encoding:
|
||||
|
||||
```mermaid
|
||||
flowchart LR
|
||||
subgraph Copy
|
||||
A["Selected nodes"] --> B["Encode NodeChange[]"]
|
||||
B --> C["Compress"]
|
||||
C --> D["Clipboard<br/><code>application/x-figma-design</code>"]
|
||||
end
|
||||
subgraph Paste
|
||||
D --> E["Decompress"]
|
||||
E --> F["Decode Kiwi"]
|
||||
F --> G["Create nodes"]
|
||||
end
|
||||
```
|
||||
1. **Copy** — encode selected `NodeChange[]` to Kiwi binary, compress, write to clipboard as `application/x-figma-design` MIME type
|
||||
2. **Paste** — read clipboard, decompress, decode Kiwi binary, create nodes in scene graph
|
||||
|
||||
This enables bidirectional clipboard between OpenPencil and Figma.
|
||||
Encoding happens synchronously in the copy event handler (not async Clipboard API) for browser compatibility. This enables bidirectional clipboard between OpenPencil and Figma.
|
||||
|
|
|
|||
|
|
@ -4,41 +4,30 @@
|
|||
|
||||
A `.fig` file is a ZIP archive containing a Kiwi-encoded binary message:
|
||||
|
||||
```mermaid
|
||||
block-beta
|
||||
columns 1
|
||||
A["Magic header: <code>fig-kiwi</code> (8 bytes)"]
|
||||
B["Version (4 bytes, uint32 LE)"]
|
||||
C["Schema length (4 bytes, uint32 LE)"]
|
||||
D["Compressed Kiwi schema"]
|
||||
E["Message length (4 bytes, uint32 LE)"]
|
||||
F["Compressed Kiwi message — NodeChange[]"]
|
||||
G["Blob data — images, vector networks, fonts"]
|
||||
```
|
||||
| Offset | Content |
|
||||
|--------|---------|
|
||||
| 0 | Magic header `fig-kiwi` (8 bytes) |
|
||||
| 8 | Version (4 bytes, uint32 LE) |
|
||||
| 12 | Schema length (4 bytes, uint32 LE) |
|
||||
| 16 | Compressed Kiwi schema |
|
||||
| … | Message length (4 bytes, uint32 LE) |
|
||||
| … | Compressed Kiwi message — `NodeChange[]` (entire document) |
|
||||
| … | Blob data — images, vector networks, fonts |
|
||||
|
||||
## Import Pipeline
|
||||
|
||||
```mermaid
|
||||
flowchart LR
|
||||
A[".fig file"] --> B["Parse header"]
|
||||
B --> C["Decompress Zstd"]
|
||||
C --> D["Decode Kiwi schema"]
|
||||
D --> E["Decode message"]
|
||||
E --> F["NodeChange[]"]
|
||||
F --> G["Build SceneGraph"]
|
||||
G --> H["Resolve blob refs"]
|
||||
H --> I["Render"]
|
||||
```
|
||||
.fig file → parse header → decompress Zstd → decode Kiwi schema
|
||||
→ decode message → NodeChange[] → build SceneGraph
|
||||
→ resolve blob refs → render on canvas
|
||||
```
|
||||
|
||||
## Export Pipeline
|
||||
|
||||
```mermaid
|
||||
flowchart LR
|
||||
A["SceneGraph"] --> B["NodeChange[]"]
|
||||
B --> C["Kiwi encode"]
|
||||
C --> D["Compress"]
|
||||
D --> E["Build ZIP"]
|
||||
E --> F[".fig file"]
|
||||
```
|
||||
SceneGraph → NodeChange[] → Kiwi encode → compress (Zstd/deflate)
|
||||
→ build ZIP (header + schema + message + thumbnail.png)
|
||||
→ write .fig file
|
||||
```
|
||||
|
||||
Export uses <kbd>⌘</kbd><kbd>S</kbd> (Save) and <kbd>⇧</kbd><kbd>⌘</kbd><kbd>S</kbd> (Save As) with native OS dialogs on the desktop app. The exported file includes a `thumbnail.png` required by Figma for file preview.
|
||||
|
|
@ -77,18 +66,7 @@ Figma's schema uses non-contiguous field IDs (e.g. 1, 2, 5, 10 with gaps). The k
|
|||
|
||||
Copy/paste uses the same Kiwi binary encoding:
|
||||
|
||||
```mermaid
|
||||
flowchart LR
|
||||
subgraph Copy
|
||||
A["Selected nodes"] --> B["Encode NodeChange[]"]
|
||||
B --> C["Compress"]
|
||||
C --> D["Clipboard<br/><code>application/x-figma-design</code>"]
|
||||
end
|
||||
subgraph Paste
|
||||
D --> E["Decompress"]
|
||||
E --> F["Decode Kiwi"]
|
||||
F --> G["Create nodes"]
|
||||
end
|
||||
```
|
||||
1. **Copy** — encode selected `NodeChange[]` to Kiwi binary, compress, write to clipboard as `application/x-figma-design` MIME type
|
||||
2. **Paste** — read clipboard, decompress, decode Kiwi binary, create nodes in scene graph
|
||||
|
||||
This enables bidirectional clipboard between OpenPencil and Figma.
|
||||
Encoding happens synchronously in the copy event handler (not async Clipboard API) for browser compatibility. This enables bidirectional clipboard between OpenPencil and Figma.
|
||||
|
|
|
|||
Loading…
Reference in a new issue