interactive-drawer 0.4.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 (124) hide show
  1. package/README.md +255 -0
  2. package/dist/checkpoint-store.d.ts +39 -0
  3. package/dist/index.js +1606 -0
  4. package/dist/mcp-app.html +124 -0
  5. package/dist/server.d.ts +12 -0
  6. package/dist/server.js +698 -0
  7. package/dist/shared.d.ts +32 -0
  8. package/dist/viewer/assets/Assistant-Bold-gm-uSS1B.woff2 +0 -0
  9. package/dist/viewer/assets/Assistant-Medium-DrcxCXg3.woff2 +0 -0
  10. package/dist/viewer/assets/Assistant-Regular-DVxZuzxb.woff2 +0 -0
  11. package/dist/viewer/assets/Assistant-SemiBold-SCI4bEL9.woff2 +0 -0
  12. package/dist/viewer/assets/Tableau10-B-NsZVaP.js +1 -0
  13. package/dist/viewer/assets/_commonjs-dynamic-modules-TDtrdbi3.js +1 -0
  14. package/dist/viewer/assets/ar-SA-G6X2FPQ2-DadQCH2-.js +10 -0
  15. package/dist/viewer/assets/arc-CQgrOt5x.js +1 -0
  16. package/dist/viewer/assets/array-BKyUJesY.js +1 -0
  17. package/dist/viewer/assets/az-AZ-76LH7QW2-DQfUuqqi.js +1 -0
  18. package/dist/viewer/assets/bg-BG-XCXSNQG7-BB40UBFK.js +5 -0
  19. package/dist/viewer/assets/blockDiagram-c4efeb88-BaF5AmVI.js +118 -0
  20. package/dist/viewer/assets/bn-BD-2XOGV67Q-uzDHfiqC.js +5 -0
  21. package/dist/viewer/assets/c4Diagram-c83219d4-hWhr-GlJ.js +10 -0
  22. package/dist/viewer/assets/ca-ES-6MX7JW3Y-BW7AckRl.js +8 -0
  23. package/dist/viewer/assets/channel-CXejbLtU.js +1 -0
  24. package/dist/viewer/assets/classDiagram-beda092f-CymCu8CT.js +2 -0
  25. package/dist/viewer/assets/classDiagram-v2-2358418a-DJAISyxA.js +2 -0
  26. package/dist/viewer/assets/clone-CfbodbqL.js +1 -0
  27. package/dist/viewer/assets/createText-1719965b-BnEANXd0.js +7 -0
  28. package/dist/viewer/assets/cs-CZ-2BRQDIVT-DuVk-qPr.js +11 -0
  29. package/dist/viewer/assets/da-DK-5WZEPLOC-DFahLFHr.js +5 -0
  30. package/dist/viewer/assets/de-DE-XR44H4JA-DoRzoyVr.js +8 -0
  31. package/dist/viewer/assets/directory-open-01563666-DWU9wJ6I.js +1 -0
  32. package/dist/viewer/assets/directory-open-4ed118d0-CunoC1EB.js +1 -0
  33. package/dist/viewer/assets/edges-96097737-BaZooScF.js +4 -0
  34. package/dist/viewer/assets/el-GR-BZB4AONW--pwLECF8.js +10 -0
  35. package/dist/viewer/assets/erDiagram-0228fc6a-57itH3DJ.js +51 -0
  36. package/dist/viewer/assets/es-ES-U4NZUMDT-C1NjAcMt.js +9 -0
  37. package/dist/viewer/assets/eu-ES-A7QVB2H4-Ck1DCJa4.js +11 -0
  38. package/dist/viewer/assets/fa-IR-HGAKTJCU-tLLl_5WD.js +8 -0
  39. package/dist/viewer/assets/fi-FI-Z5N7JZ37-DVtDP0gn.js +6 -0
  40. package/dist/viewer/assets/file-open-002ab408-DIuFHtCF.js +1 -0
  41. package/dist/viewer/assets/file-open-7c801643-684qeFg4.js +1 -0
  42. package/dist/viewer/assets/file-save-3189631c-C1wFhQhH.js +1 -0
  43. package/dist/viewer/assets/file-save-745eba88-Bb9F9Kg7.js +1 -0
  44. package/dist/viewer/assets/flowDb-c6c81e3f-C7AEsokK.js +10 -0
  45. package/dist/viewer/assets/flowDiagram-50d868cf-CssTUsiu.js +4 -0
  46. package/dist/viewer/assets/flowDiagram-v2-4f6560a1-D0GG9NIT.js +1 -0
  47. package/dist/viewer/assets/flowchart-elk-definition-6af322e1-CRyPEh1i.js +139 -0
  48. package/dist/viewer/assets/fr-FR-RHASNOE6-T_qZ0zEK.js +9 -0
  49. package/dist/viewer/assets/ganttDiagram-a2739b55-DsyTeswu.js +257 -0
  50. package/dist/viewer/assets/gitGraphDiagram-82fe8481-D85sePVV.js +70 -0
  51. package/dist/viewer/assets/gl-ES-HMX3MZ6V-IW3daBzE.js +10 -0
  52. package/dist/viewer/assets/graph-i-2SK2w1.js +1 -0
  53. package/dist/viewer/assets/he-IL-6SHJWFNN-CUxTwbdR.js +10 -0
  54. package/dist/viewer/assets/hi-IN-IWLTKZ5I-DvQFf43e.js +4 -0
  55. package/dist/viewer/assets/hu-HU-A5ZG7DT2-CO4Q4G1z.js +7 -0
  56. package/dist/viewer/assets/id-ID-SAP4L64H-Bf_UXdp6.js +10 -0
  57. package/dist/viewer/assets/image-blob-reduce.esm-D6s-rqMO.js +7 -0
  58. package/dist/viewer/assets/index-5325376f-BRzpdHqA.js +1 -0
  59. package/dist/viewer/assets/index-BDC2daNC.js +275 -0
  60. package/dist/viewer/assets/index-BcAUh2Nm.css +1 -0
  61. package/dist/viewer/assets/index-rEzfVlKD.js +97 -0
  62. package/dist/viewer/assets/infoDiagram-8eee0895-BkRxMuec.js +7 -0
  63. package/dist/viewer/assets/init-Gi6I4Gst.js +1 -0
  64. package/dist/viewer/assets/it-IT-JPQ66NNP-AwjkJc7y.js +11 -0
  65. package/dist/viewer/assets/ja-JP-DBVTYXUO-07sucMhN.js +8 -0
  66. package/dist/viewer/assets/journeyDiagram-c64418c1-6-ZVFaXG.js +139 -0
  67. package/dist/viewer/assets/kaa-6HZHGXH3-CXk_Wo6h.js +1 -0
  68. package/dist/viewer/assets/kab-KAB-ZGHBKWFO-D88OOW68.js +8 -0
  69. package/dist/viewer/assets/katex-BkgLa5T_.js +261 -0
  70. package/dist/viewer/assets/kk-KZ-P5N5QNE5-TzX_GmjC.js +1 -0
  71. package/dist/viewer/assets/km-KH-HSX4SM5Z-Dy-luINx.js +11 -0
  72. package/dist/viewer/assets/ko-KR-MTYHY66A-Bno63g5m.js +9 -0
  73. package/dist/viewer/assets/ku-TR-6OUDTVRD-Daw-B1bN.js +9 -0
  74. package/dist/viewer/assets/layout-BSQSdjji.js +1 -0
  75. package/dist/viewer/assets/line-DajA25FK.js +1 -0
  76. package/dist/viewer/assets/linear-BUWo07xp.js +1 -0
  77. package/dist/viewer/assets/lt-LT-XHIRWOB4-C3_9a2Cz.js +3 -0
  78. package/dist/viewer/assets/lv-LV-5QDEKY6T-3H9zX9pi.js +7 -0
  79. package/dist/viewer/assets/mindmap-definition-8da855dc-DIeJ0MUj.js +425 -0
  80. package/dist/viewer/assets/mr-IN-CRQNXWMA-DLf6m35n.js +13 -0
  81. package/dist/viewer/assets/my-MM-5M5IBNSE-CW_RWZBw.js +1 -0
  82. package/dist/viewer/assets/nb-NO-T6EIAALU-B0ZpuoZJ.js +10 -0
  83. package/dist/viewer/assets/nl-NL-IS3SIHDZ-nZ0JmIIM.js +8 -0
  84. package/dist/viewer/assets/nn-NO-6E72VCQL-C_dDeYAp.js +8 -0
  85. package/dist/viewer/assets/oc-FR-POXYY2M6-CsidHxkc.js +8 -0
  86. package/dist/viewer/assets/ordinal-Cboi1Yqb.js +1 -0
  87. package/dist/viewer/assets/pa-IN-N4M65BXN-DuEUGA-r.js +4 -0
  88. package/dist/viewer/assets/path-CbwjOpE9.js +1 -0
  89. package/dist/viewer/assets/pica-B90j7hbh.js +7 -0
  90. package/dist/viewer/assets/pieDiagram-a8764435-CY0HndHR.js +35 -0
  91. package/dist/viewer/assets/pl-PL-T2D74RX3-D87DC8D9.js +9 -0
  92. package/dist/viewer/assets/pt-BR-5N22H2LF-BtSoEeex.js +9 -0
  93. package/dist/viewer/assets/pt-PT-UZXXM6DQ-D4bk4PLe.js +9 -0
  94. package/dist/viewer/assets/quadrantDiagram-1e28029f-DGki2tT-.js +7 -0
  95. package/dist/viewer/assets/requirementDiagram-08caed73-BkzKWnbZ.js +52 -0
  96. package/dist/viewer/assets/ro-RO-JPDTUUEW-Ra2U-BVb.js +11 -0
  97. package/dist/viewer/assets/roundRect-0PYZxl1G.js +1 -0
  98. package/dist/viewer/assets/ru-RU-B4JR7IUQ-DAMFn0BJ.js +9 -0
  99. package/dist/viewer/assets/sankeyDiagram-a04cb91d-C1WQeKAS.js +8 -0
  100. package/dist/viewer/assets/sequenceDiagram-c5b8d532-BQy1AIyh.js +122 -0
  101. package/dist/viewer/assets/si-LK-N5RQ5JYF-DtRsuwQ6.js +1 -0
  102. package/dist/viewer/assets/sk-SK-C5VTKIMK-Dph_9bOP.js +6 -0
  103. package/dist/viewer/assets/sl-SI-NN7IZMDC-CzYryWZd.js +6 -0
  104. package/dist/viewer/assets/stateDiagram-1ecb1508-f7QEpJSj.js +1 -0
  105. package/dist/viewer/assets/stateDiagram-v2-c2b004d7-B8MjoGqH.js +1 -0
  106. package/dist/viewer/assets/styles-b4e223ce-DfLT12Nx.js +160 -0
  107. package/dist/viewer/assets/styles-ca3715f6-CnuYZzQT.js +207 -0
  108. package/dist/viewer/assets/styles-d45a18b0-Ci9tlpxY.js +116 -0
  109. package/dist/viewer/assets/subset-shared.chunk-B9IoriSA.js +84 -0
  110. package/dist/viewer/assets/subset-worker.chunk-Bpe7TPYu.js +1 -0
  111. package/dist/viewer/assets/sv-SE-XGPEYMSR-B4Y9n4LB.js +10 -0
  112. package/dist/viewer/assets/svgDrawCommon-b86b1483-4HzjGm6B.js +1 -0
  113. package/dist/viewer/assets/ta-IN-2NMHFXQM-DE7pdoSM.js +9 -0
  114. package/dist/viewer/assets/th-TH-HPSO5L25-Dd8iADEt.js +2 -0
  115. package/dist/viewer/assets/timeline-definition-faaaa080-DYgcS_Y5.js +61 -0
  116. package/dist/viewer/assets/tr-TR-DEFEU3FU-DTOmyIrt.js +7 -0
  117. package/dist/viewer/assets/uk-UA-QMV73CPH-B05zHRYx.js +6 -0
  118. package/dist/viewer/assets/vi-VN-M7AON7JQ-ChW6Q5sn.js +5 -0
  119. package/dist/viewer/assets/xychartDiagram-f5964ef8-BrW97HI1.js +7 -0
  120. package/dist/viewer/assets/zh-CN-LNUGB5OW-DF3LdZpE.js +10 -0
  121. package/dist/viewer/assets/zh-HK-E62DVLB3-C3QgGFS0.js +1 -0
  122. package/dist/viewer/assets/zh-TW-RAJ6MFWO-ciUClBxf.js +9 -0
  123. package/dist/viewer/index.html +13 -0
  124. package/package.json +67 -0
package/README.md ADDED
@@ -0,0 +1,255 @@
1
+ # Interactive Drawer
2
+
3
+ > Excalidraw MCP server — let any LLM create and share interactive diagrams
4
+
5
+ [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
6
+ [![Node.js](https://img.shields.io/badge/Node.js-20%2B-green)](https://nodejs.org)
7
+ [![MCP](https://img.shields.io/badge/Protocol-MCP%202025--03--26-blue)](https://modelcontextprotocol.io)
8
+
9
+ ## What It Does
10
+
11
+ Interactive Drawer gives LLMs an MCP tool to draw [Excalidraw](https://excalidraw.com) diagrams. The LLM calls `create_view`, a live viewer link is returned, and the user can open, edit, and export the diagram in their browser — no manual drawing required.
12
+
13
+ Works with **Claude Desktop, Cursor, Goose, Claude Code**, and any MCP-compatible client.
14
+
15
+ ## Architecture
16
+
17
+ ```
18
+ interactive-drawer/
19
+ ├── src/ # MCP server source
20
+ │ ├── main.ts # Entry: CLI args, mode selection
21
+ │ ├── http-app.ts # Express app factory (web mode)
22
+ │ ├── cli.ts # CLI argument parser
23
+ │ ├── server.ts # Studio mode MCP server
24
+ │ ├── remote-server.ts # Web mode MCP server
25
+ │ ├── session-store.ts # In-memory sessions (24h TTL, 100 max)
26
+ │ ├── checkpoint-store.ts # Checkpoint persistence
27
+ │ ├── svg-renderer.ts # Server-side SVG via JSDOM + Excalidraw
28
+ │ ├── shared.ts # Element resolution, constants
29
+ │ └── __tests__/ # 46 tests (vitest + supertest)
30
+ ├── viewer/ # Viewer SPA (React + Excalidraw)
31
+ │ └── src/
32
+ │ ├── components/ViewerPage.tsx
33
+ │ └── hooks/useGestures.ts
34
+ ├── dist/ # Build output
35
+ │ ├── index.js # Server entry (with shebang)
36
+ │ ├── server.js # Importable server module
37
+ │ └── viewer/ # Built viewer SPA
38
+ ├── scripts/build.mjs # esbuild-based build script
39
+ ├── package.json
40
+ ├── Dockerfile
41
+ └── docker-compose.yml
42
+ ```
43
+
44
+ **Two modes:**
45
+ - **Web** (default) — HTTP MCP + REST API + built-in viewer on one port
46
+ - **Studio** (`--stdio`) — stdin/stdout MCP for Claude Desktop, Cursor, etc.
47
+
48
+ ---
49
+
50
+ ## Quick Start
51
+
52
+ ```bash
53
+ git clone https://github.com/anyin233/interactive-drawer
54
+ cd interactive-drawer
55
+ npm install
56
+ cd viewer && npm install && cd ..
57
+ npm run build
58
+ node dist/index.js
59
+ # → http://localhost:3001
60
+ ```
61
+
62
+ ---
63
+
64
+ ## Connect Your LLM
65
+
66
+ ### Web Mode (remote MCP)
67
+
68
+ Start the server, then point your client to the MCP endpoint:
69
+
70
+ **Claude Desktop / Cursor / any MCP client:**
71
+
72
+ ```json
73
+ {
74
+ "mcpServers": {
75
+ "excalidraw": {
76
+ "url": "http://localhost:3001/mcp"
77
+ }
78
+ }
79
+ }
80
+ ```
81
+
82
+ ### Studio Mode (local MCP)
83
+
84
+ No server needed — the LLM client runs the process directly:
85
+
86
+ **Claude Desktop:**
87
+
88
+ ```json
89
+ {
90
+ "mcpServers": {
91
+ "excalidraw": {
92
+ "command": "node",
93
+ "args": ["/path/to/interactive-drawer/dist/index.js", "--stdio"]
94
+ }
95
+ }
96
+ }
97
+ ```
98
+
99
+ **npx (after npm publish):**
100
+
101
+ ```json
102
+ {
103
+ "mcpServers": {
104
+ "excalidraw": {
105
+ "command": "npx",
106
+ "args": ["interactive-drawer", "--stdio"]
107
+ }
108
+ }
109
+ }
110
+ ```
111
+
112
+ ---
113
+
114
+ ## MCP Tools
115
+
116
+ | Tool | Studio | Web | Description |
117
+ |------|:------:|:---:|-------------|
118
+ | `read_me` | yes | yes | Excalidraw element format reference + drawing style picker |
119
+ | `create_view` | yes | yes | Render elements → SVG (+ viewer link in web mode) |
120
+ | `create_session` | - | yes | New drawing session → session key + viewer URL |
121
+ | `get_current_view` | - | yes | Latest SVG including user edits from the browser |
122
+
123
+ **Workflow (web mode):**
124
+ ```
125
+ create_session → read_me → ask user for drawing style → create_view → share viewer URL → iterate
126
+ ```
127
+
128
+ ### Drawing Style Picker
129
+
130
+ After calling `read_me`, the LLM asks users to choose a **font** and **sloppiness**:
131
+
132
+ | Font | Style |
133
+ |------|-------|
134
+ | Excalifont | Hand-drawn, casual (default) |
135
+ | Nunito | Clean, rounded sans-serif |
136
+ | Comic Shanns | Comic/playful |
137
+
138
+ | Sloppiness | Style |
139
+ |------------|-------|
140
+ | Architect | Precise, clean lines |
141
+ | Artist | Slightly rough (default) |
142
+ | Cartoonist | Very rough, wobbly |
143
+
144
+ ---
145
+
146
+ ## Viewer
147
+
148
+ Each `/view/:key` link is a full Excalidraw editor:
149
+
150
+ - Pan (drag), zoom (scroll), edit with full toolbar
151
+ - SVG and PNG export
152
+ - Edits are saved back to the session (LLM can read them via `get_current_view`)
153
+ - Sessions expire after **24 hours**
154
+
155
+ ---
156
+
157
+ ## REST API (Web Mode)
158
+
159
+ | Method | Path | Description |
160
+ |--------|------|-------------|
161
+ | `POST` | `/mcp` | MCP Streamable HTTP |
162
+ | `GET` | `/view/:key` | Browser viewer + editor |
163
+ | `GET` | `/api/sessions/:key` | Session metadata |
164
+ | `GET` | `/api/sessions/:key/elements` | Raw elements JSON |
165
+ | `PUT` | `/api/sessions/:key/elements` | Replace elements |
166
+ | `GET` | `/api/sessions/:key/svg` | Rendered SVG |
167
+ | `GET` | `/` | Status page |
168
+
169
+ ---
170
+
171
+ ## CLI Options
172
+
173
+ ```
174
+ interactive-drawer [options]
175
+
176
+ Options:
177
+ --stdio Studio mode (stdin/stdout MCP transport)
178
+ --port <number> HTTP server port (default: 3001, web mode only)
179
+ --base-url <url> Public URL for viewer links (web mode only)
180
+ --help Show help
181
+ --version Show version
182
+
183
+ Environment Variables:
184
+ PORT Same as --port
185
+ BASE_URL Same as --base-url
186
+ ```
187
+
188
+ ---
189
+
190
+ ## Development
191
+
192
+ ```bash
193
+ npm install
194
+ cd viewer && npm install && cd ..
195
+
196
+ # Run tests
197
+ npm test # 46 server tests
198
+ cd viewer && npm test # 9 viewer tests
199
+
200
+ # Dev mode (watch + serve)
201
+ npm run dev
202
+ ```
203
+
204
+ ---
205
+
206
+ ## Deployment
207
+
208
+ <details>
209
+ <summary>Docker</summary>
210
+
211
+ ```bash
212
+ docker build -t interactive-drawer .
213
+ docker run -d -p 3001:3001 -e BASE_URL=https://draw.example.com interactive-drawer
214
+ ```
215
+
216
+ Or with docker-compose:
217
+
218
+ ```bash
219
+ docker compose up -d
220
+ ```
221
+
222
+ </details>
223
+
224
+ <details>
225
+ <summary>systemd</summary>
226
+
227
+ ```ini
228
+ [Service]
229
+ WorkingDirectory=/opt/interactive-drawer
230
+ ExecStart=node dist/index.js
231
+ Environment=PORT=3001
232
+ Environment=BASE_URL=https://draw.example.com
233
+ Restart=always
234
+ ```
235
+
236
+ </details>
237
+
238
+ <details>
239
+ <summary>nginx (TLS reverse proxy)</summary>
240
+
241
+ ```nginx
242
+ location / {
243
+ proxy_pass http://127.0.0.1:3001;
244
+ proxy_set_header Connection '';
245
+ proxy_buffering off; # required for SSE / MCP Streamable HTTP
246
+ }
247
+ ```
248
+
249
+ </details>
250
+
251
+ ---
252
+
253
+ ## License
254
+
255
+ MIT
@@ -0,0 +1,39 @@
1
+ export interface CheckpointStore {
2
+ save(id: string, data: {
3
+ elements: any[];
4
+ }): Promise<void>;
5
+ load(id: string): Promise<{
6
+ elements: any[];
7
+ } | null>;
8
+ }
9
+ export declare class FileCheckpointStore implements CheckpointStore {
10
+ private dir;
11
+ constructor();
12
+ save(id: string, data: {
13
+ elements: any[];
14
+ }): Promise<void>;
15
+ load(id: string): Promise<{
16
+ elements: any[];
17
+ } | null>;
18
+ /** Remove oldest checkpoints when count exceeds the limit. */
19
+ private pruneOldCheckpoints;
20
+ }
21
+ export declare class MemoryCheckpointStore implements CheckpointStore {
22
+ save(id: string, data: {
23
+ elements: any[];
24
+ }): Promise<void>;
25
+ load(id: string): Promise<{
26
+ elements: any[];
27
+ } | null>;
28
+ }
29
+ export declare class RedisCheckpointStore implements CheckpointStore {
30
+ private redis;
31
+ private getRedis;
32
+ save(id: string, data: {
33
+ elements: any[];
34
+ }): Promise<void>;
35
+ load(id: string): Promise<{
36
+ elements: any[];
37
+ } | null>;
38
+ }
39
+ export declare function createVercelStore(): CheckpointStore;