pixelweaver 0.1.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 (392) hide show
  1. package/.env.development +1 -0
  2. package/.github/workflows/ci.yml +22 -0
  3. package/.github/workflows/publish.yml +18 -0
  4. package/.prettierignore +5 -0
  5. package/.prettierrc +16 -0
  6. package/.python-version +1 -0
  7. package/.rlsbl/bases/.github/workflows/ci.yml +21 -0
  8. package/.rlsbl/bases/.github/workflows/publish.yml +18 -0
  9. package/.rlsbl/bases/.rlsbl/changes/unreleased.jsonl +0 -0
  10. package/.rlsbl/bases/.rlsbl/hooks/post-release.sh +8 -0
  11. package/.rlsbl/bases/.rlsbl/hooks/pre-checks.sh +5 -0
  12. package/.rlsbl/bases/.rlsbl/hooks/pre-release.sh +8 -0
  13. package/.rlsbl/bases/.rlsbl/lint/go.toml +17 -0
  14. package/.rlsbl/bases/.rlsbl/lint/npm.toml +19 -0
  15. package/.rlsbl/bases/.rlsbl/lint/python.toml +25 -0
  16. package/.rlsbl/bases/CHANGELOG.md +5 -0
  17. package/.rlsbl/bases/LICENSE +21 -0
  18. package/.rlsbl/changes/.validated +1 -0
  19. package/.rlsbl/changes/0.1.0.jsonl +85 -0
  20. package/.rlsbl/changes/0.1.0.md +13 -0
  21. package/.rlsbl/changes/unreleased.jsonl +0 -0
  22. package/.rlsbl/config.json +6 -0
  23. package/.rlsbl/hashes.json +14 -0
  24. package/.rlsbl/hooks/post-release.sh +8 -0
  25. package/.rlsbl/hooks/pre-checks.sh +5 -0
  26. package/.rlsbl/hooks/pre-release.sh +8 -0
  27. package/.rlsbl/lint/go.toml +17 -0
  28. package/.rlsbl/lint/npm.toml +19 -0
  29. package/.rlsbl/lint/python.toml +25 -0
  30. package/.rlsbl/releases/unreleased.toml +0 -0
  31. package/.rlsbl/releases/v0.1.0.toml +3 -0
  32. package/.rlsbl/version +1 -0
  33. package/.selfdoc/hashes/hashes.json +146 -0
  34. package/.strictcli/schema.json +227 -0
  35. package/CHANGELOG.md +17 -0
  36. package/CLAUDE.md +100 -0
  37. package/LICENSE +21 -0
  38. package/README.md +116 -0
  39. package/assets/icon.png +0 -0
  40. package/docs/_README.md +117 -0
  41. package/docs/cli-config.md +35 -0
  42. package/docs/cli-dev.md +21 -0
  43. package/docs/cli-diagnose.md +12 -0
  44. package/docs/cli-index.md +30 -0
  45. package/docs/cli-list.md +18 -0
  46. package/docs/cli-mcp.md +18 -0
  47. package/docs/cli-new.md +26 -0
  48. package/docs/cli-open.md +21 -0
  49. package/docs/cli-serve.md +21 -0
  50. package/docs/cli-stop.md +12 -0
  51. package/docs/gen-index.md +36 -0
  52. package/docs/index.md +13 -0
  53. package/docs/server-src-pixelweaver-__main__.md +12 -0
  54. package/docs/server-src-pixelweaver-autosave.md +12 -0
  55. package/docs/server-src-pixelweaver-bridge.md +12 -0
  56. package/docs/server-src-pixelweaver-cli.md +12 -0
  57. package/docs/server-src-pixelweaver-config.md +12 -0
  58. package/docs/server-src-pixelweaver-connections.md +12 -0
  59. package/docs/server-src-pixelweaver-main.md +12 -0
  60. package/docs/server-src-pixelweaver-mcp_bridge.md +12 -0
  61. package/docs/server-src-pixelweaver-mcp_drawing_tools.md +12 -0
  62. package/docs/server-src-pixelweaver-mcp_export_tools.md +12 -0
  63. package/docs/server-src-pixelweaver-mcp_frame_tools.md +12 -0
  64. package/docs/server-src-pixelweaver-mcp_history_tools.md +12 -0
  65. package/docs/server-src-pixelweaver-mcp_layer_tools.md +12 -0
  66. package/docs/server-src-pixelweaver-mcp_lock.md +12 -0
  67. package/docs/server-src-pixelweaver-mcp_project_tools.md +12 -0
  68. package/docs/server-src-pixelweaver-mcp_read_tools.md +12 -0
  69. package/docs/server-src-pixelweaver-mcp_registry.md +12 -0
  70. package/docs/server-src-pixelweaver-mcp_resources.md +12 -0
  71. package/docs/server-src-pixelweaver-mcp_server.md +12 -0
  72. package/docs/server-src-pixelweaver-protocol.md +12 -0
  73. package/docs/server-src-pixelweaver-state.md +12 -0
  74. package/docs/server-src-pixelweaver-storage.md +12 -0
  75. package/docs/server-src-pixelweaver-websocket.md +12 -0
  76. package/docs/server-src-pixelweaver.md +12 -0
  77. package/e2e/app-launch.test.ts +35 -0
  78. package/e2e/menus.test.ts +26 -0
  79. package/e2e/tools.test.ts +27 -0
  80. package/e2e/undo-redo.test.ts +11 -0
  81. package/eslint.config.js +62 -0
  82. package/index.html +13 -0
  83. package/package.json +48 -0
  84. package/playwright.config.ts +19 -0
  85. package/plugins/builtin/.gitkeep +0 -0
  86. package/plugins/builtin/advanced-fill-tool.ts +146 -0
  87. package/plugins/builtin/circle-tool.ts +186 -0
  88. package/plugins/builtin/diamond-tool.ts +182 -0
  89. package/plugins/builtin/dither-tool.ts +186 -0
  90. package/plugins/builtin/drawing-primitives-plugin.ts +362 -0
  91. package/plugins/builtin/drawing-utils.test.ts +495 -0
  92. package/plugins/builtin/drawing-utils.ts +431 -0
  93. package/plugins/builtin/effects/blur.ts +97 -0
  94. package/plugins/builtin/effects/color-effects.ts +278 -0
  95. package/plugins/builtin/effects/flip.ts +83 -0
  96. package/plugins/builtin/effects/glow.ts +118 -0
  97. package/plugins/builtin/effects/outline.ts +110 -0
  98. package/plugins/builtin/effects/rotate.ts +357 -0
  99. package/plugins/builtin/effects/scale.ts +258 -0
  100. package/plugins/builtin/effects/shadow.ts +111 -0
  101. package/plugins/builtin/effects/sharpen.ts +102 -0
  102. package/plugins/builtin/effects.test.ts +715 -0
  103. package/plugins/builtin/eraser-tool.ts +23 -0
  104. package/plugins/builtin/eyedropper-tool.ts +83 -0
  105. package/plugins/builtin/fill-tool.ts +93 -0
  106. package/plugins/builtin/gradient-tool.ts +204 -0
  107. package/plugins/builtin/gradient.test.ts +142 -0
  108. package/plugins/builtin/importers/aseprite-importer-plugin.ts +174 -0
  109. package/plugins/builtin/importers/aseprite-parser.ts +497 -0
  110. package/plugins/builtin/importers/piskel-importer-plugin.ts +222 -0
  111. package/plugins/builtin/importers/sky-spec-plugin.ts +409 -0
  112. package/plugins/builtin/line-tool.ts +267 -0
  113. package/plugins/builtin/make-stroke-tool.ts +271 -0
  114. package/plugins/builtin/noise-dither.test.ts +151 -0
  115. package/plugins/builtin/noise-tool.ts +131 -0
  116. package/plugins/builtin/pattern-stamp-tool.ts +162 -0
  117. package/plugins/builtin/pencil-tool.ts +25 -0
  118. package/plugins/builtin/rect-tool.ts +179 -0
  119. package/plugins/builtin/selection-tool.ts +388 -0
  120. package/plugins/builtin/selection.test.ts +195 -0
  121. package/plugins/builtin/tool-plugins.test.ts +529 -0
  122. package/public/favicon.svg +7 -0
  123. package/public/sw.js +91 -0
  124. package/pyproject.toml +49 -0
  125. package/scripts/eslint-wave-a-list.sh +24 -0
  126. package/scripts/eslint-wave-a-status.sh +25 -0
  127. package/scripts/fix-index-signature-access.py +127 -0
  128. package/scripts/fix-unchecked-index.py +128 -0
  129. package/scripts/fix-unchecked-vars.py +127 -0
  130. package/scripts/fix-wave-a-bangs.py +36 -0
  131. package/scripts/fix-wave-a-templates.py +108 -0
  132. package/scripts/fix-wave-b-void-expr.py +167 -0
  133. package/scripts/generate-command-params.py +540 -0
  134. package/scripts/migrate-single-frame-to-multi.py +171 -0
  135. package/scripts/smoke-test.sh +77 -0
  136. package/selfdoc.json +10 -0
  137. package/server/README.md +0 -0
  138. package/server/src/pixelweaver/__init__.py +1 -0
  139. package/server/src/pixelweaver/__main__.py +4 -0
  140. package/server/src/pixelweaver/autosave.py +114 -0
  141. package/server/src/pixelweaver/bridge.py +127 -0
  142. package/server/src/pixelweaver/cli.py +199 -0
  143. package/server/src/pixelweaver/config.py +24 -0
  144. package/server/src/pixelweaver/connections.py +54 -0
  145. package/server/src/pixelweaver/main.py +271 -0
  146. package/server/src/pixelweaver/mcp_bridge.py +189 -0
  147. package/server/src/pixelweaver/mcp_drawing_tools.py +178 -0
  148. package/server/src/pixelweaver/mcp_export_tools.py +291 -0
  149. package/server/src/pixelweaver/mcp_frame_tools.py +423 -0
  150. package/server/src/pixelweaver/mcp_history_tools.py +106 -0
  151. package/server/src/pixelweaver/mcp_layer_tools.py +64 -0
  152. package/server/src/pixelweaver/mcp_lock.py +37 -0
  153. package/server/src/pixelweaver/mcp_project_tools.py +302 -0
  154. package/server/src/pixelweaver/mcp_read_tools.py +163 -0
  155. package/server/src/pixelweaver/mcp_registry.py +247 -0
  156. package/server/src/pixelweaver/mcp_resources.py +312 -0
  157. package/server/src/pixelweaver/mcp_server.py +234 -0
  158. package/server/src/pixelweaver/protocol.py +219 -0
  159. package/server/src/pixelweaver/state.py +267 -0
  160. package/server/src/pixelweaver/storage.py +293 -0
  161. package/server/src/pixelweaver/websocket.py +282 -0
  162. package/server/tests/__init__.py +0 -0
  163. package/server/tests/conftest.py +17 -0
  164. package/server/tests/test_api.py +96 -0
  165. package/server/tests/test_bridge.py +161 -0
  166. package/server/tests/test_health.py +9 -0
  167. package/server/tests/test_integration.py +86 -0
  168. package/server/tests/test_mcp_bridge.py +293 -0
  169. package/server/tests/test_mcp_lock.py +34 -0
  170. package/server/tests/test_mcp_registry.py +679 -0
  171. package/server/tests/test_mcp_resources.py +648 -0
  172. package/server/tests/test_protocol.py +125 -0
  173. package/server/tests/test_state.py +87 -0
  174. package/server/tests/test_storage.py +306 -0
  175. package/server/tests/test_websocket.py +275 -0
  176. package/src/App.svelte +107 -0
  177. package/src/app.css +215 -0
  178. package/src/lib/animation/AnimationPreviewPanel.svelte +667 -0
  179. package/src/lib/animation/animation-commands.test.ts +228 -0
  180. package/src/lib/animation/animation-commands.ts +540 -0
  181. package/src/lib/animation/animation-preview-panel-plugin.ts +25 -0
  182. package/src/lib/animation/animation-preview.svelte.ts +151 -0
  183. package/src/lib/animation/clipboard.ts +134 -0
  184. package/src/lib/animation/frame-model.svelte.ts +437 -0
  185. package/src/lib/animation/frame-model.test.ts +314 -0
  186. package/src/lib/animation/frame-selection.svelte.ts +77 -0
  187. package/src/lib/animation/frame-tags.svelte.ts +238 -0
  188. package/src/lib/animation/frame-tags.test.ts +136 -0
  189. package/src/lib/animation/import.test.ts +141 -0
  190. package/src/lib/animation/import.ts +112 -0
  191. package/src/lib/animation/spritesheet-export.test.ts +239 -0
  192. package/src/lib/animation/spritesheet-export.ts +314 -0
  193. package/src/lib/canvas/CanvasViewport.svelte +216 -0
  194. package/src/lib/canvas/canvas-init-plugin.ts +178 -0
  195. package/src/lib/canvas/canvas-renderer.ts +408 -0
  196. package/src/lib/canvas/canvas-state.svelte.ts +232 -0
  197. package/src/lib/canvas/canvas-state.test.ts +139 -0
  198. package/src/lib/canvas/input-handler.ts +221 -0
  199. package/src/lib/canvas/input-plugin.ts +150 -0
  200. package/src/lib/canvas/onion-skin.ts +94 -0
  201. package/src/lib/canvas/pixel-buffer.test.ts +249 -0
  202. package/src/lib/canvas/pixel-buffer.ts +151 -0
  203. package/src/lib/canvas/render-state.svelte.ts +18 -0
  204. package/src/lib/canvas/shape-preview-state.svelte.ts +36 -0
  205. package/src/lib/canvas/tile-mode.test.ts +53 -0
  206. package/src/lib/canvas/tile-mode.ts +92 -0
  207. package/src/lib/canvas/viewport-utils.ts +24 -0
  208. package/src/lib/canvas/zoom-utils.ts +31 -0
  209. package/src/lib/color/.gitkeep +0 -0
  210. package/src/lib/color/color-commands.ts +87 -0
  211. package/src/lib/color/color-state.svelte.ts +98 -0
  212. package/src/lib/color/color-state.test.ts +91 -0
  213. package/src/lib/color/color-utils.test.ts +220 -0
  214. package/src/lib/color/color-utils.ts +243 -0
  215. package/src/lib/color/palette-state.svelte.ts +127 -0
  216. package/src/lib/color/palette-state.test.ts +154 -0
  217. package/src/lib/color/palette.ts +79 -0
  218. package/src/lib/core/bootstrap.ts +66 -0
  219. package/src/lib/core/command-params.generated.ts +1549 -0
  220. package/src/lib/core/command-params.ts +20 -0
  221. package/src/lib/core/command-runner.ts +79 -0
  222. package/src/lib/core/commands.ts +134 -0
  223. package/src/lib/core/dispatcher.test.ts +548 -0
  224. package/src/lib/core/dispatcher.ts +361 -0
  225. package/src/lib/core/index.test.ts +7 -0
  226. package/src/lib/core/notification-state.svelte.ts +119 -0
  227. package/src/lib/core/plugin-api.ts +210 -0
  228. package/src/lib/core/plugin-discovery.test.ts +53 -0
  229. package/src/lib/core/plugin-discovery.ts +65 -0
  230. package/src/lib/core/plugin-loader.test.ts +159 -0
  231. package/src/lib/core/plugin-loader.ts +240 -0
  232. package/src/lib/core/plugin-types.ts +286 -0
  233. package/src/lib/core/registries.svelte.ts +74 -0
  234. package/src/lib/core/tool-options-state.svelte.ts +61 -0
  235. package/src/lib/dock/DockLayout.svelte +375 -0
  236. package/src/lib/dock/TabAddMenu.svelte +90 -0
  237. package/src/lib/dock/dock-persistence.ts +46 -0
  238. package/src/lib/dock/dock-plugin.ts +49 -0
  239. package/src/lib/dock/dock-presets.ts +156 -0
  240. package/src/lib/dock/dock-state.svelte.ts +77 -0
  241. package/src/lib/dock/dock-types.ts +2 -0
  242. package/src/lib/dock/dockview-theme.css +226 -0
  243. package/src/lib/dock/dockview-theme.ts +17 -0
  244. package/src/lib/dock/header-action-renderer.ts +77 -0
  245. package/src/lib/edit/clipboard-state.ts +34 -0
  246. package/src/lib/export/download.ts +201 -0
  247. package/src/lib/export/png-metadata.ts +181 -0
  248. package/src/lib/history/ActionLogPanel.svelte +418 -0
  249. package/src/lib/history/action-log-panel-plugin.ts +24 -0
  250. package/src/lib/history/action-log.svelte.ts +172 -0
  251. package/src/lib/history/action-log.test.ts +168 -0
  252. package/src/lib/history/history-commands.ts +403 -0
  253. package/src/lib/history/macros.svelte.ts +320 -0
  254. package/src/lib/history/macros.test.ts +224 -0
  255. package/src/lib/history/replay-engine.test.ts +241 -0
  256. package/src/lib/history/replay-engine.ts +149 -0
  257. package/src/lib/history/spec-format.test.ts +250 -0
  258. package/src/lib/history/spec-format.ts +210 -0
  259. package/src/lib/iso/SeamCheckerPanel.svelte +251 -0
  260. package/src/lib/iso/iso-math.test.ts +77 -0
  261. package/src/lib/iso/iso-math.ts +77 -0
  262. package/src/lib/iso/seam-checker-panel-plugin.ts +25 -0
  263. package/src/lib/iso/seam-checker.test.ts +126 -0
  264. package/src/lib/iso/seam-checker.ts +93 -0
  265. package/src/lib/iso/tessellation.ts +67 -0
  266. package/src/lib/layers/compositor.test.ts +193 -0
  267. package/src/lib/layers/compositor.ts +175 -0
  268. package/src/lib/layers/layer-commands.test.ts +263 -0
  269. package/src/lib/layers/layer-commands.ts +429 -0
  270. package/src/lib/layers/layer-tree.svelte.ts +516 -0
  271. package/src/lib/layers/layer-tree.test.ts +383 -0
  272. package/src/lib/layers/layer-types.ts +56 -0
  273. package/src/lib/leveleditor/LevelEditorViewport.svelte +1808 -0
  274. package/src/lib/leveleditor/MapPropertiesPanel.svelte +266 -0
  275. package/src/lib/leveleditor/TilePickerPanel.svelte +324 -0
  276. package/src/lib/leveleditor/depth-sort.test.ts +70 -0
  277. package/src/lib/leveleditor/depth-sort.ts +39 -0
  278. package/src/lib/leveleditor/level-editor-commands.ts +353 -0
  279. package/src/lib/leveleditor/level-editor-viewport-plugin.ts +25 -0
  280. package/src/lib/leveleditor/map-properties-panel-plugin.ts +25 -0
  281. package/src/lib/leveleditor/map-state.svelte.ts +372 -0
  282. package/src/lib/leveleditor/map-state.test.ts +243 -0
  283. package/src/lib/leveleditor/tile-picker-panel-plugin.ts +25 -0
  284. package/src/lib/leveleditor/tile-source-registry.svelte.ts +91 -0
  285. package/src/lib/leveleditor/tiled-export.test.ts +144 -0
  286. package/src/lib/leveleditor/tiled-export.ts +374 -0
  287. package/src/lib/pywebview.d.ts +15 -0
  288. package/src/lib/recovery/.gitkeep +0 -0
  289. package/src/lib/recovery/idb-store.ts +118 -0
  290. package/src/lib/recovery/recovery-manager.test.ts +321 -0
  291. package/src/lib/recovery/recovery-manager.ts +115 -0
  292. package/src/lib/recovery/recovery-plugin.ts +55 -0
  293. package/src/lib/recovery/recovery-state.svelte.ts +21 -0
  294. package/src/lib/recovery/sw-plugin.ts +18 -0
  295. package/src/lib/recovery/sw-register.ts +17 -0
  296. package/src/lib/save/directory-format.ts +42 -0
  297. package/src/lib/save/project-snapshot.ts +139 -0
  298. package/src/lib/save/recent-projects.ts +56 -0
  299. package/src/lib/save/save-state.svelte.ts +35 -0
  300. package/src/lib/save/storage.ts +167 -0
  301. package/src/lib/save/zip-format.ts +45 -0
  302. package/src/lib/shortcuts/.gitkeep +0 -0
  303. package/src/lib/shortcuts/ShortcutEditorPanel.svelte +690 -0
  304. package/src/lib/shortcuts/default-bindings.ts +61 -0
  305. package/src/lib/shortcuts/shortcut-editor-panel-plugin.ts +25 -0
  306. package/src/lib/shortcuts/shortcut-init.ts +380 -0
  307. package/src/lib/shortcuts/shortcut-manager.test.ts +466 -0
  308. package/src/lib/shortcuts/shortcut-manager.ts +281 -0
  309. package/src/lib/shortcuts/shortcut-state.svelte.ts +78 -0
  310. package/src/lib/shortcuts/shortcuts-plugin.ts +17 -0
  311. package/src/lib/sync/patch-applicator.ts +300 -0
  312. package/src/lib/sync/patch-types.ts +65 -0
  313. package/src/lib/sync/project-manager.ts +108 -0
  314. package/src/lib/sync/sync-init.ts +152 -0
  315. package/src/lib/sync/sync-plugin.ts +19 -0
  316. package/src/lib/sync/sync-state.svelte.ts +56 -0
  317. package/src/lib/sync/ws-client.test.ts +604 -0
  318. package/src/lib/sync/ws-client.ts +574 -0
  319. package/src/lib/tools/.gitkeep +0 -0
  320. package/src/lib/ui/.gitkeep +0 -0
  321. package/src/lib/ui/AboutDialog.svelte +113 -0
  322. package/src/lib/ui/ColorPicker.svelte +761 -0
  323. package/src/lib/ui/ContextMenu.svelte +216 -0
  324. package/src/lib/ui/ExportDialog.svelte +747 -0
  325. package/src/lib/ui/FrameStrip.svelte +854 -0
  326. package/src/lib/ui/LayerPanel.svelte +810 -0
  327. package/src/lib/ui/MenuBar.svelte +590 -0
  328. package/src/lib/ui/NewProjectDialog.svelte +803 -0
  329. package/src/lib/ui/PluginManagerPanel.svelte +475 -0
  330. package/src/lib/ui/PromptDialog.svelte +252 -0
  331. package/src/lib/ui/RecoveryDialog.svelte +295 -0
  332. package/src/lib/ui/ResizeDialog.svelte +416 -0
  333. package/src/lib/ui/StatusBar.svelte +145 -0
  334. package/src/lib/ui/ToolbarPanel.svelte +488 -0
  335. package/src/lib/ui/animation-menu-commands.ts +194 -0
  336. package/src/lib/ui/command-palette/CommandPalette.svelte +232 -0
  337. package/src/lib/ui/command-palette/command-palette-plugin.ts +30 -0
  338. package/src/lib/ui/command-palette/command-palette-state.svelte.ts +190 -0
  339. package/src/lib/ui/command-palette/command-palette.test.ts +129 -0
  340. package/src/lib/ui/dialog-state.svelte.ts +70 -0
  341. package/src/lib/ui/edit-commands.ts +271 -0
  342. package/src/lib/ui/file-commands.ts +275 -0
  343. package/src/lib/ui/file-open.ts +99 -0
  344. package/src/lib/ui/help-commands.ts +93 -0
  345. package/src/lib/ui/image-commands.ts +181 -0
  346. package/src/lib/ui/layer-menu-commands.ts +420 -0
  347. package/src/lib/ui/menu-builder.ts +224 -0
  348. package/src/lib/ui/notifications/NotificationBanner.svelte +137 -0
  349. package/src/lib/ui/notifications/notification-plugin.ts +29 -0
  350. package/src/lib/ui/notifications/notification-state.svelte.ts +9 -0
  351. package/src/lib/ui/plugin-manager-panel-plugin.ts +26 -0
  352. package/src/lib/ui/plugin-state.svelte.ts +62 -0
  353. package/src/lib/ui/select-commands.ts +75 -0
  354. package/src/lib/ui/theme-plugin.ts +18 -0
  355. package/src/lib/ui/theme.svelte.ts +45 -0
  356. package/src/lib/ui/theme.test.ts +51 -0
  357. package/src/lib/ui/toolbar-config.ts +90 -0
  358. package/src/lib/ui/toolbar-plugin.ts +39 -0
  359. package/src/lib/ui/view-commands.ts +629 -0
  360. package/src/lib/variants/BisectionExportDialog.svelte +500 -0
  361. package/src/lib/variants/VariantPanel.svelte +822 -0
  362. package/src/lib/variants/bisection-export.test.ts +113 -0
  363. package/src/lib/variants/bisection-export.ts +148 -0
  364. package/src/lib/variants/palette-extraction.test.ts +111 -0
  365. package/src/lib/variants/palette-extraction.ts +84 -0
  366. package/src/lib/variants/palette-interpolation.test.ts +113 -0
  367. package/src/lib/variants/palette-interpolation.ts +87 -0
  368. package/src/lib/variants/palette-swap.test.ts +101 -0
  369. package/src/lib/variants/palette-swap.ts +114 -0
  370. package/src/lib/variants/variant-commands.ts +594 -0
  371. package/src/lib/variants/variant-panel-plugin.ts +27 -0
  372. package/src/lib/variants/variant-randomizer.ts +101 -0
  373. package/src/lib/variants/variant-state.svelte.ts +166 -0
  374. package/src/lib/variants/variant-state.test.ts +138 -0
  375. package/src/main.ts +14 -0
  376. package/src/vite-env.d.ts +3 -0
  377. package/svelte.config.js +2 -0
  378. package/todo/.done/audit-design-decisions.md +812 -0
  379. package/todo/.done/audit-implementation-plan.md +1235 -0
  380. package/todo/.done/happy-path-polish.md +177 -0
  381. package/todo/.done/pixelweaver-full-build.md +937 -0
  382. package/todo/.done/server-multi-frame-design.md +405 -0
  383. package/todo/.done/typed-dispatcher-design.md +435 -0
  384. package/todo/.done/unified-toolbar-and-action-system.md +323 -0
  385. package/todo/.obsolete/comprehensive-audit-obsolete-items.md +33 -0
  386. package/todo/.obsolete/tauri-desktop-bundle.md +424 -0
  387. package/todo/comprehensive-audit.md +1085 -0
  388. package/tsconfig.app.json +26 -0
  389. package/tsconfig.json +7 -0
  390. package/tsconfig.node.json +20 -0
  391. package/uv.lock +1167 -0
  392. package/vite.config.ts +32 -0
@@ -0,0 +1,937 @@
1
+ # PixelWeaver -- Full Build Plan
2
+
3
+ ## Context
4
+
5
+ PixelWeaver is a web-based pixel art sprite editor inspired by GameMaker's classic sprite editor, but with modern capabilities: semantic action history, layer-group-based variant generation, a full isometric level editor, MCP tool server for LLM integration, and a fully plugin-based architecture. It ships as a Tauri desktop application (with the browser+server option for Firefox compatibility).
6
+
7
+ It is a personal tool -- opinionated, keyboard-driven, no hand-holding. The primary workflow is animation-focused: creating, editing, and previewing multi-frame sprite animations. Both raw pixel editing and structured spec awareness (semantic drawing commands) are first-class.
8
+
9
+ Born out of dissatisfaction with existing pixel editors and the desire to close the loop between LLM-generated sprite specs and visual editing.
10
+
11
+ ### Key Design Decisions
12
+
13
+ - All phases are parallel work units for subagents, not sequential releases. Everything ships together.
14
+ - All built-in tools are plugins from day 1 -- there is no special "built-in" code path.
15
+ - No separate "zone" concept exists. Layer groups replace zones entirely.
16
+ - Projects support multiple canvases, each with an independent layer tree.
17
+ - Tauri packaging is included from the start. The app expects the user has `uv` installed for the Python server.
18
+
19
+ ## Architecture
20
+
21
+ | Layer | Technology | Role |
22
+ |---|---|---|
23
+ | Desktop Shell | Tauri | Native window, system integration, expects user has `uv` installed |
24
+ | Frontend | Svelte 5 (runes) + Pure Vite SPA (no SvelteKit) | Dark creative tool UI, minimal canvas layout, collapsible panels |
25
+ | Canvas | HTML Canvas 2D | All pixel editing, rendering, zoom/pan, pressure sensitivity via Pointer Events API |
26
+ | Core | Command dispatcher (4 consumers from day 1) | Every action is a Command. Dispatch feeds canvas executor, undo system, semantic log, spec export |
27
+ | Plugins | ES modules | Everything is a plugin (tools, panels, exporters, commands). Core is just canvas + dispatcher + plugin loader |
28
+ | Server | Python FastAPI (API only) | File I/O, MCP endpoint, project management. Vite serves frontend (with HMR in dev) |
29
+ | Protocol | WebSocket | All communication: commands, confirmations, MCP push, state sync |
30
+ | Storage | PNG frames + JSON metadata | Project files on disk as a directory structure |
31
+
32
+ ### Sync Model: Server-Authoritative + Optimistic UI
33
+
34
+ The server owns ALL state. The browser renders optimistically (applies commands locally for instant feedback), and the server confirms or rejects. On conflict, server state wins.
35
+
36
+ - Commands flow: UI -> WebSocket -> Server (validates, persists, broadcasts) -> UI confirmation
37
+ - MCP commands follow the same path through the server
38
+ - Server state: in-memory + periodic disk flush (configurable debounce, e.g. 500ms after last command, + interval, e.g. every 30s)
39
+
40
+ ### WebSocket Protocol
41
+
42
+ WebSocket is the sole communication channel between frontend and server. Covers:
43
+
44
+ - Command submission and confirmation
45
+ - MCP push notifications
46
+ - State synchronization
47
+ - Auto-reconnect with exponential backoff + full state reconciliation on reconnect
48
+
49
+ ### Command Dispatcher (Central Nervous System)
50
+
51
+ Every user action -- whether triggered by mouse click, keyboard shortcut, or MCP tool call -- becomes a Command object that flows through a single dispatch system. All four consumers are active from day 1:
52
+
53
+ - **Canvas executor**: applies the command to the pixel buffer
54
+ - **Undo system**: records the command (with inverse) in the undo stack
55
+ - **Semantic log**: appends a human-readable description ("drew line from (2,3) to (15,8) in #FF0000")
56
+ - **Spec export**: serializes the command for pipeline-compatible output
57
+
58
+ Adding a new tool means: define the command type, implement the executor, done -- it is automatically available via UI, MCP, undo, and export.
59
+
60
+ ### Plugin System (From Day 1)
61
+
62
+ Everything is a plugin, including all built-in tools. There is no separate built-in code path. The core is minimal:
63
+
64
+ - Canvas with zoom/pan/input routing
65
+ - Command dispatcher
66
+ - Plugin loader (respects declared dependency order)
67
+ - Project format reader/writer
68
+
69
+ Plugin boundary: ES modules. Each plugin exports registration functions:
70
+
71
+ ```js
72
+ export function register(api) {
73
+ api.addCommand("draw_line", { execute, undo, describe });
74
+ api.addTool("line", { icon, cursor, onPointerDown, onPointerMove, onPointerUp });
75
+ api.addPanel("line-options", { component: LineOptionsPanel });
76
+ }
77
+ ```
78
+
79
+ No manifest files, no sandboxing (trust-based). Plugins declare explicit dependency arrays in `register()`. Dynamic imports from a plugins directory. Built-in plugins ship in the same format as third-party ones.
80
+
81
+ ### Migration Strategy
82
+
83
+ Each command is tagged with plugin name + version. Each plugin owns its own schema compatibility -- there is no global migration system. When a plugin's command format changes, that plugin is responsible for reading its own older formats.
84
+
85
+ ### Companion Server (Python FastAPI)
86
+
87
+ Required because File System Access API is Chrome/Edge only (Firefox will never support it). The server is API-only -- Vite serves the frontend (with HMR in dev).
88
+
89
+ Server responsibilities:
90
+
91
+ - **File CRUD**: read/write/list/delete project files on disk
92
+ - **Project management**: list projects, create new, open existing
93
+ - **File watching**: detect external changes (e.g. edits in VS Code)
94
+ - **MCP endpoint**: exposes the same Command dispatch as the UI over MCP protocol
95
+ - **State authority**: server is the single source of truth for all project state
96
+ - **Periodic flush**: in-memory state with configurable debounce + interval disk writes
97
+
98
+ Server discovery: configurable port with sensible default (e.g. 7779).
99
+
100
+ ### CLI
101
+
102
+ Full CLI interface:
103
+
104
+ | Command | Description |
105
+ |---|---|
106
+ | `pixelweaver serve` | Start the server (API + file serving) |
107
+ | `pixelweaver export` | Export project from command line |
108
+ | `pixelweaver new` | Create a new project |
109
+ | (extensible) | Additional subcommands as needed |
110
+
111
+ ### Tauri Packaging
112
+
113
+ Tauri wraps the application from the start. The Tauri shell:
114
+
115
+ - Launches the Python FastAPI server as a sidecar process (expects user has `uv` installed)
116
+ - Opens the frontend in a native window
117
+ - Provides system integration (native menus, file dialogs, etc.)
118
+
119
+ The browser+server option remains available for Firefox users or those who prefer it.
120
+
121
+ ### Project Format (PNG + JSON)
122
+
123
+ Each project is a directory on disk. Projects support multiple canvases, each with an independent layer tree.
124
+
125
+ ```
126
+ my-project/
127
+ project.json -- metadata: project name, canvas list, global palette, settings
128
+ canvases/
129
+ main/
130
+ canvas.json -- canvas size, layer tree structure, origin point
131
+ frames/
132
+ 0/
133
+ layer-0.png -- pixel data for layer 0, frame 0
134
+ layer-1.png -- pixel data for layer 1, frame 0
135
+ ...
136
+ 1/
137
+ layer-0.png
138
+ ...
139
+ history.json -- command history for this canvas
140
+ attack/
141
+ canvas.json
142
+ frames/
143
+ ...
144
+ history.json
145
+ variants/
146
+ gold-armor.json -- layer group palette overrides
147
+ exports/ -- generated output (PNG, spritesheets)
148
+ ```
149
+
150
+ Command history is persisted from day 1. Each command is tagged with its plugin name + version for forward compatibility.
151
+
152
+ ### Crash Safety
153
+
154
+ - Service worker + IndexedDB auto-recovery
155
+ - On crash or unexpected close, unsaved state is recoverable from IndexedDB
156
+ - On next launch, the app detects incomplete state and offers recovery
157
+
158
+ ## Layers
159
+
160
+ Layers are a cross-cutting feature that affects canvas, tools, undo, project format, animation, and export.
161
+
162
+ ### Layer Model
163
+
164
+ - Layer structure is shared across all frames within a canvas (same tree, different pixel content per frame)
165
+ - Each frame has independent pixel data for each layer
166
+ - Layer types: pixel layer, layer group
167
+ - Layer groups are nestable (groups can contain groups)
168
+ - Layer groups REPLACE zones entirely -- there is no separate zone concept
169
+
170
+ ### Layer Properties
171
+
172
+ | Property | Description |
173
+ |---|---|
174
+ | Name | User-defined label |
175
+ | Visibility | Show/hide toggle |
176
+ | Opacity | 0-100% |
177
+ | Blend mode | Normal, Multiply, Screen, etc. (extensible via plugins) |
178
+ | Lock | Prevent edits |
179
+
180
+ ### Layer Panel UI
181
+
182
+ - Tree view with indentation for nested groups
183
+ - Expand/collapse groups
184
+ - Drag-and-drop reordering (including into/out of groups)
185
+ - Right-click context menu: rename, duplicate, merge down, flatten group, delete
186
+ - Layer thumbnail preview
187
+
188
+ ### Layer Implications
189
+
190
+ | System | Impact |
191
+ |---|---|
192
+ | Canvas rendering | Composite layers in order with blend modes and opacity |
193
+ | Drawing tools | Operate on the active layer only |
194
+ | Undo | Layer operations are undoable commands (add, delete, reorder, merge, etc.) |
195
+ | Project format | Per-layer PNG files within each frame directory |
196
+ | Animation | Layer tree is shared across frames; pixel data is per-frame-per-layer |
197
+ | Export | Flatten layers on export; optionally export individual layers |
198
+ | Variants | Palette swaps apply per layer group (see Variants phase) |
199
+ | Selection | Selection tools operate within the active layer |
200
+
201
+ ## Multi-Canvas Projects
202
+
203
+ A single project can contain multiple canvases, each with:
204
+
205
+ - Independent canvas dimensions
206
+ - Independent layer tree
207
+ - Independent frame set and animation timeline
208
+ - Independent command history and undo stack
209
+ - An origin point for composite preview positioning
210
+
211
+ ### Multi-Canvas Preview
212
+
213
+ A composite preview mode shows multiple canvases rendered together at their respective origin points. Useful for checking how separate sprite parts (body, weapon, effects) align when composited in-game.
214
+
215
+ ## UI Design
216
+
217
+ ### Layout: Minimal Canvas
218
+
219
+ Canvas dominates the screen. All panels are collapsible overlays/sidebars:
220
+
221
+ - **Menu bar** (top): File, Edit, View, Tools, Plugins
222
+ - **Tool bar** (left): tool icons, vertical, collapsible
223
+ - **Properties panel** (right): context-sensitive (color picker, tool options, layer list), collapsible
224
+ - **Layer panel** (right or left): tree view of layers with expand/collapse for groups
225
+ - **Frame strip** (bottom): classic GM horizontal filmstrip, collapsible
226
+ - **Status bar** (bottom): coords, zoom %, color, frame #, active layer
227
+ - All panels can be hidden for maximum canvas space
228
+
229
+ ### Theming
230
+
231
+ - Dark + light themes
232
+ - Implemented via CSS variables, switchable at runtime
233
+ - Default: dark theme (dark gray panels, accent colors for selection/active states, high contrast canvas area)
234
+ - Modeled after Blender/Aseprite/Figma dark themes
235
+
236
+ ### Guides and Grids
237
+
238
+ - Custom configurable grids (pixel grid at high zoom, user-defined spacing)
239
+ - Draggable horizontal and vertical guide lines
240
+ - Snap-to-guide for drawing tools and selections
241
+
242
+ ## Phase 1 -- Core Editor
243
+
244
+ **Milestone: you can draw, layer, and save pixel art.**
245
+
246
+ ### Canvas System
247
+
248
+ - HTML Canvas 2D rendering
249
+ - Zoom: scroll wheel or +/- keys, pixel grid visible at high zoom levels
250
+ - Pan: middle-click drag or spacebar + drag
251
+ - Canvas sizes: up to 512x512 (arbitrary dimensions within this limit)
252
+ - Cursor shows current tool shape and color
253
+ - Pixel coordinates displayed in status bar
254
+ - Tile/wrap mode: drawing wraps across canvas edges (for seamless tile creation)
255
+ - Pressure sensitivity via Pointer Events API (affects brush size/opacity for supporting tools)
256
+
257
+ ### Layers (Core Feature)
258
+
259
+ - Full layer system as described in the Layers section above
260
+ - Layer groups (nestable)
261
+ - Layer panel with tree view UI
262
+ - Layer operations: add, delete, duplicate, merge, reorder, group/ungroup
263
+ - All layer operations are commands in the dispatcher (undoable, logged, etc.)
264
+
265
+ ### Drawing Tools (Phase 1 Subset -- All Plugins)
266
+
267
+ All tools are plugins from day 1. Phase 1 ships these built-in plugins:
268
+
269
+ - **Pencil**: single pixel placement, click-drag for freehand, pressure-sensitive size
270
+ - **Eraser**: set pixels to transparent, variable size, pressure-sensitive
271
+ - **Eyedropper**: pick color from canvas, activate with Alt+click from any tool
272
+ - **Fill bucket**: flood fill contiguous same-color region
273
+ - **Line**: click-drag, Bresenham rendering
274
+ - **Rectangle**: click-drag for filled or outline, hold Shift for square
275
+ - **Circle/Ellipse**: click-drag for filled or outline, hold Shift for perfect circle
276
+ - **Diamond**: isometric diamond shape, essential for terrain tiles
277
+
278
+ ### Perfect Pixel Lines
279
+
280
+ Two modes available as separate plugins, user chooses which to enable:
281
+
282
+ - **Standard Bresenham**: classic pixel line rendering
283
+ - **No-doubles Bresenham**: prevents two adjacent pixels on the minor axis to avoid staircase artifacts
284
+
285
+ ### Color System
286
+
287
+ - Color picker: headless color library (`culori`) + custom Svelte UI
288
+ - All color spaces: HSV + HSL + RGB + Hex input
289
+ - Foreground/background color (swap with X key)
290
+ - Recent colors strip (last N used colors)
291
+ - **Palette lock** (from the start): define a fixed palette, restrict drawing to those colors
292
+ - Smart palette tracking: auto-collects all colors used in the project, supports bulk recolor
293
+ - **Global palettes**: app-wide palettes including presets (PICO-8, GameBoy, etc.) AND per-project palettes
294
+ - **Palette interpolation**: lerp between palette presets for variant generation
295
+
296
+ ### Command Dispatcher
297
+
298
+ - Command objects: `{ type, plugin, version, params, timestamp }`
299
+ - Execute + inverse for every command (enables undo)
300
+ - Dispatch pipeline: validate -> execute -> record (4 consumers)
301
+ - Human-readable `describe()` for each command type
302
+ - Commands tagged with plugin name + version for migration
303
+
304
+ ### Undo/Redo
305
+
306
+ - **Linear stack with parent pointers** for future branching capability
307
+ - Two-tier undo:
308
+ - Per-frame drawing undo (pixel operations within a single frame/layer)
309
+ - Project-level operation undo (add/delete frame, reorder layers, canvas operations)
310
+ - Per-canvas undo (switching canvases does not mix histories)
311
+ - Command history persisted from day 1
312
+
313
+ ### Keyboard Shortcut System
314
+
315
+ Custom shortcut system from day 1 (no tinykeys/mousetrap dependency):
316
+
317
+ - Fully remappable shortcuts
318
+ - Default keybindings inspired by Aseprite (single letter for tools: B=brush, E=eraser, G=fill, etc.)
319
+ - Shortcut editor panel: search, rebind, reset to defaults
320
+ - Support for modifier combos (Ctrl+, Shift+, Alt+)
321
+ - Conflict detection
322
+ - Import/export shortcut profiles
323
+
324
+ ### Command Palette (Standalone Plugin)
325
+
326
+ - Ctrl+P (or configurable) opens fuzzy search
327
+ - Searches all commands, tools, panels, recent files
328
+ - Shows current keybinding for each item
329
+ - Execute on Enter
330
+
331
+ ### Companion Server
332
+
333
+ - FastAPI app, API-only (Vite serves frontend)
334
+ - WebSocket for all communication (commands, confirmations, state sync)
335
+ - Server-authoritative state model
336
+ - In-memory state + periodic disk flush (configurable debounce + interval)
337
+ - Configurable port (default 7779)
338
+ - CLI: `pixelweaver serve`, `pixelweaver new`, etc.
339
+
340
+ ### Crash Safety and Auto-Save
341
+
342
+ - Service worker + IndexedDB auto-recovery
343
+ - Auto-save: configurable debounce (e.g. 500ms after last command) + interval (e.g. every 30s), both configurable
344
+ - Recovery dialog on next launch if incomplete state detected
345
+
346
+ ### Save/Load
347
+
348
+ - Save project to disk via companion server (directory structure with PNG + JSON)
349
+ - Load existing project
350
+ - New project dialog: name, canvas width, canvas height
351
+ - Multi-canvas support: add/remove canvases within a project
352
+
353
+ ### Export
354
+
355
+ - Export current frame as PNG
356
+ - Export all frames as individual PNGs
357
+
358
+ ### Reference Image
359
+
360
+ - Overlay a reference image on the canvas at adjustable opacity
361
+ - Does not affect output -- purely a visual aid while drawing
362
+
363
+ ### Tauri Shell
364
+
365
+ - Tauri desktop wrapper
366
+ - Launches Python server as sidecar (expects `uv` installed)
367
+ - Native window with system integration
368
+
369
+ ### Files/Dirs That Will Change
370
+
371
+ - `src/` -- Svelte 5 frontend app (pure Vite SPA)
372
+ - `src/lib/core/` -- command dispatcher, undo stack, project format, plugin loader, plugin API
373
+ - `src/lib/canvas/` -- canvas rendering, zoom/pan, input handling, tile/wrap mode, pressure input
374
+ - `src/lib/layers/` -- layer model, layer tree, compositing, layer panel UI
375
+ - `src/lib/tools/` -- drawing tool plugins (pencil, eraser, line, etc.) -- all ES module plugins
376
+ - `src/lib/ui/` -- panels, toolbar, status bar, dialogs, command palette, theming
377
+ - `src/lib/color/` -- color picker (culori-based), palette management, palette lock, interpolation
378
+ - `src/lib/shortcuts/` -- custom shortcut system, editor panel, profiles
379
+ - `src/lib/sync/` -- WebSocket client, optimistic UI, reconnection logic
380
+ - `src/lib/recovery/` -- service worker, IndexedDB crash recovery
381
+ - `server/` -- Python FastAPI companion server
382
+ - `src-tauri/` -- Tauri configuration and native shell
383
+ - `plugins/builtin/` -- all built-in tools as ES module plugins
384
+ - `package.json`, `vite.config.js` -- project config
385
+ - `pyproject.toml` -- server dependencies (managed with `uv`)
386
+ - `src-tauri/tauri.conf.json` -- Tauri config
387
+
388
+ ### Effort: Large
389
+
390
+ This is the foundational phase. Everything else builds on it. Includes canvas, layers, tools, colors, undo, shortcuts, command palette, server, WebSocket protocol, Tauri shell, crash recovery, and the full plugin system. The command dispatcher and plugin API shape everything downstream.
391
+
392
+ ## Phase 2 -- Animation
393
+
394
+ **Milestone: you can create and export sprite animations.**
395
+
396
+ ### Frame Strip
397
+
398
+ - Classic GM horizontal filmstrip at the bottom of the screen
399
+ - Thumbnail preview of each frame (shows flattened layer composite)
400
+ - Click to select and edit a frame
401
+ - Right-click context menu: duplicate, delete, insert before/after, move left/right
402
+ - Drag-and-drop reordering
403
+ - Frame number labels
404
+ - Current frame highlighted
405
+
406
+ ### Frame Operations
407
+
408
+ - Add frame (blank or duplicate current)
409
+ - Remove frame (with confirmation if it has content)
410
+ - Duplicate frame
411
+ - Reorder via drag-and-drop
412
+ - Copy/paste frames (including across projects via clipboard -- see cross-project clipboard)
413
+ - Unlimited frame count
414
+
415
+ ### Frame Timing
416
+
417
+ - Global FPS setting for the animation
418
+ - Per-frame duration overrides (individual frames can have custom timing)
419
+ - Timing displayed in frame strip
420
+
421
+ ### Frame Tags
422
+
423
+ - Tag ranges of frames with labels (e.g. "idle", "walk", "attack")
424
+ - Tags support nesting (tags can contain sub-tags, e.g. "attack" contains "windup" and "strike")
425
+ - Tags visible in the frame strip
426
+ - Export respects tags (export tagged ranges as separate animations)
427
+
428
+ ### Onion Skinning
429
+
430
+ - Configurable frame range (how many frames before/after to show)
431
+ - Adjustable opacity for onion skin layers
432
+ - Tint control (e.g. red for previous frames, blue for next frames)
433
+ - Toggle on/off
434
+
435
+ ### Animation Preview
436
+
437
+ - **Loop preview**: plays frames in sequence at configured FPS (respects per-frame overrides)
438
+ - **Ping-pong**: forward then backward, common for idle animations
439
+ - **Side-by-side**: all frames laid out next to each other simultaneously for comparison
440
+ - **Multi-sprite preview**: load multiple canvases/projects and preview them animating side by side
441
+ - Play/pause/step controls
442
+ - Speed slider
443
+ - Preview window resizable, dockable
444
+
445
+ ### Spritesheet Export
446
+
447
+ Multiple layout options:
448
+
449
+ | Layout | Description |
450
+ |---|---|
451
+ | Horizontal strip | All frames in a single row |
452
+ | Grid | Configurable number of columns |
453
+ | Texture atlas | Packed layout (minimize wasted space) |
454
+
455
+ Spritesheet metadata export formats:
456
+
457
+ | Format | Description |
458
+ |---|---|
459
+ | Custom JSON | PixelWeaver native metadata |
460
+ | TexturePacker-compatible | For engines that import TexturePacker format |
461
+ | Aseprite-compatible | For engines that import Aseprite JSON format |
462
+ | CSS | For web usage (sprite positions as CSS classes) |
463
+
464
+ Additional export options:
465
+
466
+ - Configurable padding between frames
467
+ - Export dialog with preview
468
+ - Export tagged frame ranges as separate spritesheets
469
+
470
+ ### Origin Point
471
+
472
+ - Draggable crosshair on canvas marking the sprite's origin/pivot
473
+ - Snaps to pixel grid
474
+ - Displayed in animation preview (useful for alignment)
475
+ - Stored per canvas in project metadata
476
+
477
+ ### Cross-Project Clipboard
478
+
479
+ - **Internal clipboard**: rich copy that preserves layers, commands, and metadata
480
+ - **System clipboard**: copies as flattened PNG for pasting into other applications
481
+ - Works for frames, selections, and layer content
482
+
483
+ ### Import
484
+
485
+ - PNG import (single frame)
486
+ - Spritesheet import (split into frames with configurable grid/strip settings)
487
+ - Aseprite `.ase` import (implemented as a built-in importer plugin)
488
+ - Piskel `.piskel` import (implemented as a built-in importer plugin)
489
+
490
+ ### Files/Dirs That Will Change
491
+
492
+ - `src/lib/animation/` -- frame strip, preview, timeline logic, frame tags, onion skinning
493
+ - `src/lib/export/` -- spritesheet stitcher, metadata writers (all 4 formats), layout algorithms
494
+ - `src/lib/import/` -- PNG import, spritesheet splitter
495
+ - `src/lib/ui/` -- frame strip panel, preview panel, export dialog, onion skin controls
496
+ - `src/lib/clipboard/` -- cross-project clipboard (internal rich + system PNG)
497
+
498
+ ### Effort: Medium-Large
499
+
500
+ Frame management is straightforward. Animation preview with multi-sprite support, spritesheet layouts, multiple metadata formats, frame tags with nesting, and onion skinning add up to substantial work.
501
+
502
+ ## Phase 3 -- Pro Drawing Tools
503
+
504
+ **Milestone: full drawing toolkit for professional pixel art.**
505
+
506
+ ### Additional Drawing Tools (All Plugins)
507
+
508
+ - **Gradient**: both dithered (Bayer pattern) and smooth (RGB interpolation), user chooses mode
509
+ - **Noise/scatter**: random pixel placement from a color palette within a region
510
+ - **Dither**: ordered 2x2 Bayer dither between two colors
511
+ - **Symmetry/mirror drawing**: full system -- axis H/V/both + radial 3/4/6/8-way + custom angle. Live mirroring while drawing with any tool
512
+ - **Contiguous fill modes**: fill same-color-only, fill with tolerance slider, fill-to-edge
513
+ - **Selection tools**: rectangular select, lasso (freehand), move selection, copy/paste within canvas, cut, delete selection
514
+ - **Pattern stamp**: define a small repeating pattern and paint with it as a brush
515
+
516
+ ### GM Classic Effects (All Plugins)
517
+
518
+ All classic GameMaker sprite effects, each as a separate plugin:
519
+
520
+ - Rotate, flip, stretch, skew
521
+ - Invert colors, grayscale, colorize
522
+ - Brightness/contrast
523
+ - Blur (1px box blur for pixel art softening)
524
+
525
+ ### Effects Pipeline (Broad System)
526
+
527
+ Destructive effects with live preview before committing:
528
+
529
+ - Blur, sharpen
530
+ - Outline, shadow, glow
531
+ - All effects show a live preview on the canvas; user confirms or cancels
532
+ - Effects operate on the active layer
533
+
534
+ ### Files/Dirs That Will Change
535
+
536
+ - `src/lib/tools/` -- new tool plugins (gradient, noise, dither, symmetry, selection, pattern stamp)
537
+ - `plugins/builtin/effects/` -- GM effects and pipeline effects as individual plugins
538
+
539
+ ### Effort: Medium-Large
540
+
541
+ Many individual tools/effects to implement, but each is independent. Symmetry system with radial modes is the most complex single piece.
542
+
543
+ ## Phase 4 -- Semantic History
544
+
545
+ **Milestone: the action log IS the spec. LLM-readable, replayable history.**
546
+
547
+ ### Semantic Action Log
548
+
549
+ Every command's `describe()` output forms a human-readable narrative:
550
+
551
+ ```
552
+ 1. Created new canvas 32x32
553
+ 2. Drew diamond fill at center (16,16) radius 15x7 in #5B8C3E
554
+ 3. Applied noise scatter in region (2,2)-(30,14) with colors [#4A7A2E, #6B9C4E] at 20% density
555
+ 4. Drew isometric outline in #3D6B22
556
+ ```
557
+
558
+ This is not just for display -- it IS the spec format. Exporting the log produces a document that `render.py` (or a compatible renderer) can replay. The `render.py` script exists externally; its spec format will be defined separately.
559
+
560
+ ### Action Log Panel
561
+
562
+ - Scrollable list of all actions in the current canvas/frame
563
+ - Each entry shows: icon, description, timestamp
564
+ - Click to select (highlights affected pixels on canvas)
565
+ - Right-click: edit parameters, delete, disable (skip without removing), duplicate
566
+ - Drag to reorder (with live preview of result)
567
+ - Filter/search within log
568
+
569
+ ### Command Reordering
570
+
571
+ Full replay from scratch: when commands are reordered, all commands are replayed from a blank canvas in the new order. This guarantees correctness regardless of command interdependencies.
572
+
573
+ ### Command Replay/Modification
574
+
575
+ - Select a range of commands and replay them (useful for applying a sequence to a different frame)
576
+ - Edit command parameters inline (change a color, move a coordinate) with live preview
577
+
578
+ ### Macros
579
+
580
+ Included as part of semantic history work:
581
+
582
+ - Record a command sequence as a reusable macro
583
+ - Macro coordinate mode: user chooses absolute or relative per macro
584
+ - Replay macros with parameter overrides
585
+
586
+ ### Spec Export from History
587
+
588
+ - Export the semantic log as a JSON spec compatible with `render.py`'s format
589
+ - Round-trip: import a spec -> appears as a command sequence in the log -> edit visually -> export back to spec
590
+ - Diff two specs visually (highlight what changed between versions)
591
+
592
+ ### Files/Dirs That Will Change
593
+
594
+ - `src/lib/core/` -- enhanced command dispatcher with `describe()`, semantic log store
595
+ - `src/lib/history/` -- action log panel, macro system, command replay/reorder
596
+ - `src/lib/export/` -- spec format exporter
597
+ - `src/lib/import/` -- spec format importer (parse `render.py` JSON specs into command sequences)
598
+
599
+ ### Effort: Large
600
+
601
+ The semantic history is architecturally central and touches everything. Getting `describe()` right for every command, making the log editable and reorderable with live preview (full replay from scratch), macro recording, and the spec round-trip all require careful design.
602
+
603
+ ## Phase 5 -- MCP Integration
604
+
605
+ **Milestone: Claude Code can draw, edit, and manage sprites.**
606
+
607
+ ### MCP Tool Strategy: Dual Layer
608
+
609
+ Both auto-generated raw tools AND curated high-level LLM-friendly tools:
610
+
611
+ | Tool Layer | Description |
612
+ |---|---|
613
+ | Auto-generated raw tools | Every command type in the registry becomes an MCP tool automatically. Parameters match command params exactly. |
614
+ | Curated high-level tools | Hand-written LLM-friendly tools that combine multiple commands for common workflows (e.g. "draw a character outline" = multiple line/curve commands) |
615
+
616
+ ### MCP Concurrency
617
+
618
+ Sequential locking: a mutex is held when MCP is executing a command. UI input during MCP execution is queued and processed after the MCP command completes.
619
+
620
+ ### MCP Read Tools
621
+
622
+ Both approaches:
623
+
624
+ - Separate read-only tools for querying state (get_canvas_info, get_layer_tree, get_palette, etc.)
625
+ - Thumbnails included in mutation responses (base64 thumbnail of the affected region returned with every write operation)
626
+
627
+ ### Tool Categories
628
+
629
+ - **Drawing tools**: draw_pixel, draw_line, draw_rect, draw_circle, draw_diamond, fill, noise, dither, gradient (all command types)
630
+ - **Layer tools**: add_layer, remove_layer, set_active_layer, get_layer_tree, reorder_layers, group_layers
631
+ - **Frame management**: add_frame, remove_frame, duplicate_frame, reorder_frames, set_frame
632
+ - **Project management**: list_projects, open_project, create_project, save_project, get_project_info
633
+ - **Canvas operations**: get_canvas_size, resize_canvas, get_pixel, get_region, list_canvases, add_canvas
634
+ - **History operations**: undo, redo, get_action_log, replay_commands
635
+ - **Variant operations**: set_group_palette, list_variants, generate_variant
636
+ - **Export**: export_png, export_spritesheet, export_spec
637
+
638
+ ### Live Sync
639
+
640
+ When an MCP tool modifies the canvas, the browser UI updates in real-time via WebSocket push. Conversely, when the user draws in the browser, the MCP state stays current. The server-authoritative model ensures consistency.
641
+
642
+ ### Files/Dirs That Will Change
643
+
644
+ - `server/mcp.py` -- MCP server implementation, auto-tool-generation from command registry + curated tools
645
+ - `server/sync.py` -- WebSocket sync, sequential locking / mutex
646
+ - `src/lib/core/` -- command registry introspection API
647
+ - `src/lib/sync/` -- client-side WebSocket listener for server-pushed updates
648
+
649
+ ### Effort: Medium
650
+
651
+ The command dispatcher does most of the heavy lifting. MCP is a thin layer on top. The dual-layer tool strategy (auto + curated) and sequential locking add some complexity.
652
+
653
+ ## Phase 6 -- Variants
654
+
655
+ **Milestone: layer-group-based palette swapping, bisection export, and variant generation.**
656
+
657
+ Layer groups replace the former "zone" concept entirely. A layer group serves dual purpose: organizational grouping of layers AND the semantic unit for palette swapping and variant generation.
658
+
659
+ ### Palette Swap Panel
660
+
661
+ - Each layer group has an associated color palette (the actual colors used in layers within that group)
662
+ - Swap any color in the palette to create a variant
663
+ - Live preview: canvas updates in real-time as you adjust group colors
664
+ - "Extract palette" button: auto-detects the colors used within a layer group
665
+
666
+ ### Bisection (Export Groups Separately)
667
+
668
+ Split a single finished sprite into composable overlay exports:
669
+
670
+ - Select layer groups to export separately (e.g. export "armor" group as its own spritesheet)
671
+ - The exported group contains only its layers' pixels on transparent background
672
+ - Multiple groups can be exported and recombined by the consuming game engine
673
+ - Preview shows the composite (all groups) animating together
674
+
675
+ ### Variant Generation
676
+
677
+ - Define variant presets: named palette overrides per layer group (e.g. "gold armor" = armor group palette swapped to gold tones)
678
+ - **Palette interpolation**: lerp between palette presets to generate intermediate variants
679
+ - Variant grid: see all variants side by side
680
+ - Randomize button: generates random palette combinations across all layer groups for rapid exploration
681
+ - Export variants as individual spritesheets or a combined variant atlas
682
+
683
+ ### Files/Dirs That Will Change
684
+
685
+ - `src/lib/variants/` -- palette swap engine, variant grid, randomizer, preset management, interpolation
686
+ - `src/lib/export/` -- variant export (individual + atlas), bisection export
687
+ - Project format: variants stored as JSON in `variants/` subdirectory
688
+
689
+ ### Effort: Medium-Large
690
+
691
+ Palette swapping per layer group is straightforward given the layer system. Variant generation, interpolation, grid preview, and bisection export are moderately complex.
692
+
693
+ ## Phase 7 -- Level Editor
694
+
695
+ **Milestone: full isometric level editor for placing and composing sprites.**
696
+
697
+ This is a full level editor, not just a preview tool. It provides a separate editing mode for building isometric scenes/maps using sprites created in PixelWeaver.
698
+
699
+ ### Live Tile Tessellation
700
+
701
+ - While editing a terrain tile, a preview panel shows the tile repeated in an isometric grid
702
+ - Adjustable grid size (3x3, 5x5, custom)
703
+ - Updates in real-time as you draw
704
+
705
+ ### Seam Checker
706
+
707
+ - Automated analysis of tile edges
708
+ - Highlights pixels that would create visible seams when tiled
709
+ - Auto-fix suggestions (color-match adjacent edge pixels)
710
+ - Works for all four isometric edges (NE, SE, SW, NW)
711
+
712
+ ### Level Editor Features
713
+
714
+ | Feature | Description |
715
+ |---|---|
716
+ | Multiple map layers | Separate layers for terrain, objects, entities, overlays, etc. |
717
+ | Per-tile height values | All modes: integer steps, half-steps, continuous |
718
+ | Entity properties | Key-value metadata per placed entity |
719
+ | Collision regions | Define collision shapes on the map |
720
+ | Depth sorting | Automatic layer ordering: terrain -> buildings -> entities |
721
+
722
+ ### Level Editor Assets
723
+
724
+ - Assets reference PixelWeaver projects directly -- no separate tileset format
725
+ - Terrain tiles snap to isometric grid positions
726
+ - Entity sprites placed freely (with optional grid snap)
727
+ - Building sprites placed with correct height offset
728
+
729
+ ### Level Editor Export
730
+
731
+ - **Tiled-compatible JSON (.tmj)**: export maps in Tiled's native format for direct game engine consumption
732
+ - Scene layouts saved as part of the project directory
733
+
734
+ ### Files/Dirs That Will Change
735
+
736
+ - `src/lib/leveleditor/` -- map editor, tile placement, entity placement, collision regions
737
+ - `src/lib/iso/` -- tessellation preview, seam checker, isometric math
738
+ - `src/lib/export/` -- Tiled .tmj export
739
+ - `src/lib/ui/` -- level editor mode, tile palette panel, entity panel, height editor
740
+
741
+ ### Effort: Large
742
+
743
+ This is a full level editor with multiple map layers, height values, entity properties, collision regions, and Tiled export. Significantly more complex than the original "preview tool" concept.
744
+
745
+ ## Phase 8 -- Plugin System Formalization
746
+
747
+ **Milestone: third-party plugins work, plugin management UI complete.**
748
+
749
+ Note: the plugin system itself exists from day 1 (Phase 1). This phase formalizes the API documentation, adds the management UI, and ensures the API surface is stable and complete for third-party developers.
750
+
751
+ ### Plugin Loader
752
+
753
+ - Scans a `plugins/` directory (on disk, via companion server) for ES modules
754
+ - Each module exports a `register(api)` function
755
+ - Plugins loaded at startup, can be enabled/disabled at runtime
756
+ - Load order respects declared dependency arrays
757
+ - Trust-based: no sandboxing
758
+
759
+ ### Plugin API Surface
760
+
761
+ ```js
762
+ api.addCommand(name, { execute, undo, describe, params })
763
+ api.addTool(name, { icon, cursor, handlers, optionsPanel })
764
+ api.addPanel(name, { component, position, defaultVisible })
765
+ api.addExporter(name, { extension, export })
766
+ api.addImporter(name, { extensions, import })
767
+ api.addShortcut(name, { defaultKey, command })
768
+ api.getCanvas() // read/write pixel data
769
+ api.getProject() // project metadata
770
+ api.getActiveFrame() // current frame data
771
+ api.getActiveLayers() // layer tree and active layer
772
+ api.dispatch(command) // execute a command
773
+ api.onCommand(callback) // listen to all commands
774
+ ```
775
+
776
+ ### Plugin Management UI
777
+
778
+ - Settings panel listing all plugins (built-in and third-party)
779
+ - Enable/disable toggle per plugin
780
+ - Plugin info: name, description, author, version, commands/tools/panels it registers, dependencies
781
+ - "Open plugins folder" button (opens file manager via companion server)
782
+
783
+ ### Files/Dirs That Will Change
784
+
785
+ - `src/lib/core/plugin-api.js` -- API surface documentation and stability guarantees
786
+ - `src/lib/ui/` -- plugin management panel
787
+ - `plugins/` -- third-party plugin directory
788
+
789
+ ### Effort: Small-Medium
790
+
791
+ Most of the API surface already exists from Phase 1. This phase adds the management UI, documents the API, and ensures stability for third-party use.
792
+
793
+ ## Cross-Cutting Concerns
794
+
795
+ ### Performance
796
+
797
+ - Canvas operations must be responsive at 60fps up to 512x512
798
+ - Layer compositing must be efficient (cache flattened composites, invalidate on change)
799
+ - Undo stack should not grow unbounded in memory -- consider snapshots + command replay for deep histories
800
+ - WebSocket message throughput must handle rapid drawing input
801
+
802
+ ### Crash Safety and Auto-Save
803
+
804
+ - Service worker + IndexedDB auto-recovery
805
+ - Auto-save: configurable debounce (e.g. 500ms after last command) + interval (e.g. every 30s)
806
+ - Recovery dialog on next launch if incomplete state detected
807
+
808
+ ### Theming
809
+
810
+ - Dark + light themes via CSS variables
811
+ - Switchable at runtime
812
+ - All UI components respect theme variables
813
+
814
+ ### Accessibility
815
+
816
+ - All tools accessible via keyboard shortcuts
817
+ - Color picker supports all input modes (hex, RGB, HSL, HSV)
818
+ - Status bar announces tool changes and coordinates
819
+
820
+ ### Error Handling
821
+
822
+ - Companion server down: frontend shows clear message, allows limited offline work (in-memory, export to download)
823
+ - Invalid project files: graceful error with details, never crash silently
824
+ - Plugin errors: caught and reported, never crash the editor
825
+ - WebSocket disconnection: auto-reconnect with exponential backoff + full state reconciliation
826
+
827
+ ### Testing Strategy
828
+
829
+ | Category | Framework | Scope |
830
+ |---|---|---|
831
+ | Unit tests | Vitest | Core (dispatcher, undo, commands, layer model) |
832
+ | Tool integration tests | Vitest | Execute command -> verify pixel buffer state |
833
+ | Server API tests | pytest + httpx | All server endpoints and WebSocket protocol |
834
+ | E2E tests | Playwright | Critical flows (draw, save, load, export, tools, menus, undo-redo) |
835
+
836
+ ### Browser Support
837
+
838
+ - Firefox: required (primary reason the companion server exists)
839
+ - Chrome/Edge: supported
840
+ - Safari: best-effort
841
+
842
+ ## Dependencies
843
+
844
+ ### Frontend (npm)
845
+
846
+ - svelte (v5, runes)
847
+ - @sveltejs/vite-plugin-svelte
848
+ - culori (headless color library for color picker)
849
+ - (No shadcn-svelte, no msgpack, no tinykeys/mousetrap -- custom UI, JSON format, custom shortcuts)
850
+
851
+ ### Server (Python, managed with uv)
852
+
853
+ - fastapi
854
+ - uvicorn
855
+ - websockets (for WebSocket protocol)
856
+ - watchfiles (for file watching)
857
+ - Pillow (for PNG read/write if needed server-side)
858
+
859
+ ### Desktop
860
+
861
+ - @tauri-apps/cli
862
+ - @tauri-apps/api
863
+ - Rust toolchain (for Tauri build)
864
+
865
+ ### Dev
866
+
867
+ - vite
868
+ - vitest (unit/integration tests)
869
+ - playwright (e2e tests)
870
+ - ruff (Python linting)
871
+ - eslint + prettier (JS/Svelte linting)
872
+ - pytest + httpx (server tests)
873
+
874
+ ## Summary Table
875
+
876
+ | Phase | What | Effort | Key Dependencies |
877
+ |---|---|---|---|
878
+ | 1 | Core Editor (canvas, layers, tools, colors, undo, shortcuts, command palette, server, WebSocket, Tauri, crash recovery, plugin system) | Large | -- |
879
+ | 2 | Animation (frames, onion skinning, tags, preview, spritesheet export, import, clipboard) | Medium-Large | Phase 1 |
880
+ | 3 | Pro Drawing Tools (gradient, dither, noise, symmetry, selection, effects pipeline, GM effects) | Medium-Large | Phase 1 |
881
+ | 4 | Semantic History (action log, command replay/reorder, macros, spec round-trip) | Large | Phase 1 |
882
+ | 5 | MCP Integration (dual-layer tool server, sequential locking, live sync) | Medium | Phase 1, 4 |
883
+ | 6 | Variants (layer group palette swap, bisection export, variant generation/grid/randomization, interpolation) | Medium-Large | Phase 1, 2 |
884
+ | 7 | Level Editor (tile tessellation, seam checker, multi-layer maps, height, entities, collision, Tiled export) | Large | Phase 1, 2 |
885
+ | 8 | Plugin Formalization (management UI, API documentation, third-party stability) | Small-Medium | Phase 1 |
886
+
887
+ All phases are parallel work units. They are NOT sequential releases -- everything ships together. Dependencies indicate which phases' foundations must be architecturally complete before work can begin on dependent phases, not release order.
888
+
889
+ Phases 2, 3, 4, 8 can be worked in parallel after Phase 1 foundations are in place.
890
+ Phases 5, 6, 7 have additional dependencies as noted but are otherwise independent of each other.
891
+
892
+ ## Implementation Status
893
+
894
+ *Last updated: 2026-04-10*
895
+
896
+ ### Phase Status
897
+
898
+ | Phase | Name | Status | Notes |
899
+ |---|---|---|---|
900
+ | 1 | Core Editor | Complete | Canvas, layers, tools, colors, undo, shortcuts, command palette, server, WebSocket, crash recovery, plugin system |
901
+ | 2 | Animation | Complete | Frame strip, preview, onion skinning, tags, spritesheet export, import, clipboard |
902
+ | 3 | Pro Drawing Tools | Complete | Gradient, dither, noise, symmetry, selection, effects pipeline, GM effects |
903
+ | 4 | Semantic History | Complete | Action log, command replay/reorder, macros, spec export |
904
+ | 5 | MCP Integration | Complete | Dual-layer tool server, sequential locking, live sync |
905
+ | 6 | Variants | Complete | Palette swap, interpolation, bisection export |
906
+ | 7 | Level Editor | Complete | Isometric editor, tile tessellation, seam checker, Tiled export |
907
+ | 8 | Plugin Formalization | Complete | API docs, plugin discovery, management state |
908
+ | -- | App Assembly / Wiring | Complete | Bootstrap, system plugins, plugin API getters, render state, input handler, canvas viewport |
909
+ | -- | UI Components | Complete | ToolBar, LayerPanel, ColorPicker, FrameStrip, StatusBar, MenuBar, NewProjectDialog, ExportDialog, App.svelte layout |
910
+
911
+ ### Remaining Work
912
+
913
+ The backing state, commands, registries, and plugin logic for each of the
914
+ items below already exist. What is missing is the Svelte component that
915
+ renders them in a dockview panel.
916
+
917
+ | Item | Category | Priority |
918
+ |---|---|---|
919
+ | ActionLogPanel | UI | Low |
920
+ | VariantPanel | UI | Low |
921
+ | PluginManagerPanel | UI | Low |
922
+ | LevelEditorViewport | UI | Low |
923
+ | AnimationPreviewPanel | UI | Low |
924
+ | ShortcutEditorPanel | UI | Low |
925
+
926
+ ### Recently Completed
927
+
928
+ Items previously listed as remaining that have since landed:
929
+
930
+ | Item | Landed |
931
+ |---|---|
932
+ | Tauri sidecar wiring (auto-start Python server via `uv run pixelweaver serve`, port 7779 health check in `src-tauri/src/lib.rs`) | 2026-04-10 |
933
+ | Aseprite `.ase` import (`plugins/builtin/importers/aseprite-importer-plugin.ts` with `aseprite-parser.ts`) | 2026-04-10 |
934
+ | Piskel `.piskel` import (`plugins/builtin/importers/piskel-importer-plugin.ts`) | 2026-04-10 |
935
+ | Playwright E2E tests (`e2e/app-launch.test.ts`, `tools.test.ts`, `menus.test.ts`, `undo-redo.test.ts`, `playwright.config.ts`) | 2026-04-10 |
936
+ | `render.py` spec format compatibility (native export/import via `src/lib/history/spec-format.ts`; Sky JSON ingestion via `plugins/builtin/importers/sky-spec-plugin.ts`) | 2026-04-10 |
937
+ | AnimationPreview panel | UI | Low |