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.
- package/.env.development +1 -0
- package/.github/workflows/ci.yml +22 -0
- package/.github/workflows/publish.yml +18 -0
- package/.prettierignore +5 -0
- package/.prettierrc +16 -0
- package/.python-version +1 -0
- package/.rlsbl/bases/.github/workflows/ci.yml +21 -0
- package/.rlsbl/bases/.github/workflows/publish.yml +18 -0
- package/.rlsbl/bases/.rlsbl/changes/unreleased.jsonl +0 -0
- package/.rlsbl/bases/.rlsbl/hooks/post-release.sh +8 -0
- package/.rlsbl/bases/.rlsbl/hooks/pre-checks.sh +5 -0
- package/.rlsbl/bases/.rlsbl/hooks/pre-release.sh +8 -0
- package/.rlsbl/bases/.rlsbl/lint/go.toml +17 -0
- package/.rlsbl/bases/.rlsbl/lint/npm.toml +19 -0
- package/.rlsbl/bases/.rlsbl/lint/python.toml +25 -0
- package/.rlsbl/bases/CHANGELOG.md +5 -0
- package/.rlsbl/bases/LICENSE +21 -0
- package/.rlsbl/changes/.validated +1 -0
- package/.rlsbl/changes/0.1.0.jsonl +85 -0
- package/.rlsbl/changes/0.1.0.md +13 -0
- package/.rlsbl/changes/unreleased.jsonl +0 -0
- package/.rlsbl/config.json +6 -0
- package/.rlsbl/hashes.json +14 -0
- package/.rlsbl/hooks/post-release.sh +8 -0
- package/.rlsbl/hooks/pre-checks.sh +5 -0
- package/.rlsbl/hooks/pre-release.sh +8 -0
- package/.rlsbl/lint/go.toml +17 -0
- package/.rlsbl/lint/npm.toml +19 -0
- package/.rlsbl/lint/python.toml +25 -0
- package/.rlsbl/releases/unreleased.toml +0 -0
- package/.rlsbl/releases/v0.1.0.toml +3 -0
- package/.rlsbl/version +1 -0
- package/.selfdoc/hashes/hashes.json +146 -0
- package/.strictcli/schema.json +227 -0
- package/CHANGELOG.md +17 -0
- package/CLAUDE.md +100 -0
- package/LICENSE +21 -0
- package/README.md +116 -0
- package/assets/icon.png +0 -0
- package/docs/_README.md +117 -0
- package/docs/cli-config.md +35 -0
- package/docs/cli-dev.md +21 -0
- package/docs/cli-diagnose.md +12 -0
- package/docs/cli-index.md +30 -0
- package/docs/cli-list.md +18 -0
- package/docs/cli-mcp.md +18 -0
- package/docs/cli-new.md +26 -0
- package/docs/cli-open.md +21 -0
- package/docs/cli-serve.md +21 -0
- package/docs/cli-stop.md +12 -0
- package/docs/gen-index.md +36 -0
- package/docs/index.md +13 -0
- package/docs/server-src-pixelweaver-__main__.md +12 -0
- package/docs/server-src-pixelweaver-autosave.md +12 -0
- package/docs/server-src-pixelweaver-bridge.md +12 -0
- package/docs/server-src-pixelweaver-cli.md +12 -0
- package/docs/server-src-pixelweaver-config.md +12 -0
- package/docs/server-src-pixelweaver-connections.md +12 -0
- package/docs/server-src-pixelweaver-main.md +12 -0
- package/docs/server-src-pixelweaver-mcp_bridge.md +12 -0
- package/docs/server-src-pixelweaver-mcp_drawing_tools.md +12 -0
- package/docs/server-src-pixelweaver-mcp_export_tools.md +12 -0
- package/docs/server-src-pixelweaver-mcp_frame_tools.md +12 -0
- package/docs/server-src-pixelweaver-mcp_history_tools.md +12 -0
- package/docs/server-src-pixelweaver-mcp_layer_tools.md +12 -0
- package/docs/server-src-pixelweaver-mcp_lock.md +12 -0
- package/docs/server-src-pixelweaver-mcp_project_tools.md +12 -0
- package/docs/server-src-pixelweaver-mcp_read_tools.md +12 -0
- package/docs/server-src-pixelweaver-mcp_registry.md +12 -0
- package/docs/server-src-pixelweaver-mcp_resources.md +12 -0
- package/docs/server-src-pixelweaver-mcp_server.md +12 -0
- package/docs/server-src-pixelweaver-protocol.md +12 -0
- package/docs/server-src-pixelweaver-state.md +12 -0
- package/docs/server-src-pixelweaver-storage.md +12 -0
- package/docs/server-src-pixelweaver-websocket.md +12 -0
- package/docs/server-src-pixelweaver.md +12 -0
- package/e2e/app-launch.test.ts +35 -0
- package/e2e/menus.test.ts +26 -0
- package/e2e/tools.test.ts +27 -0
- package/e2e/undo-redo.test.ts +11 -0
- package/eslint.config.js +62 -0
- package/index.html +13 -0
- package/package.json +48 -0
- package/playwright.config.ts +19 -0
- package/plugins/builtin/.gitkeep +0 -0
- package/plugins/builtin/advanced-fill-tool.ts +146 -0
- package/plugins/builtin/circle-tool.ts +186 -0
- package/plugins/builtin/diamond-tool.ts +182 -0
- package/plugins/builtin/dither-tool.ts +186 -0
- package/plugins/builtin/drawing-primitives-plugin.ts +362 -0
- package/plugins/builtin/drawing-utils.test.ts +495 -0
- package/plugins/builtin/drawing-utils.ts +431 -0
- package/plugins/builtin/effects/blur.ts +97 -0
- package/plugins/builtin/effects/color-effects.ts +278 -0
- package/plugins/builtin/effects/flip.ts +83 -0
- package/plugins/builtin/effects/glow.ts +118 -0
- package/plugins/builtin/effects/outline.ts +110 -0
- package/plugins/builtin/effects/rotate.ts +357 -0
- package/plugins/builtin/effects/scale.ts +258 -0
- package/plugins/builtin/effects/shadow.ts +111 -0
- package/plugins/builtin/effects/sharpen.ts +102 -0
- package/plugins/builtin/effects.test.ts +715 -0
- package/plugins/builtin/eraser-tool.ts +23 -0
- package/plugins/builtin/eyedropper-tool.ts +83 -0
- package/plugins/builtin/fill-tool.ts +93 -0
- package/plugins/builtin/gradient-tool.ts +204 -0
- package/plugins/builtin/gradient.test.ts +142 -0
- package/plugins/builtin/importers/aseprite-importer-plugin.ts +174 -0
- package/plugins/builtin/importers/aseprite-parser.ts +497 -0
- package/plugins/builtin/importers/piskel-importer-plugin.ts +222 -0
- package/plugins/builtin/importers/sky-spec-plugin.ts +409 -0
- package/plugins/builtin/line-tool.ts +267 -0
- package/plugins/builtin/make-stroke-tool.ts +271 -0
- package/plugins/builtin/noise-dither.test.ts +151 -0
- package/plugins/builtin/noise-tool.ts +131 -0
- package/plugins/builtin/pattern-stamp-tool.ts +162 -0
- package/plugins/builtin/pencil-tool.ts +25 -0
- package/plugins/builtin/rect-tool.ts +179 -0
- package/plugins/builtin/selection-tool.ts +388 -0
- package/plugins/builtin/selection.test.ts +195 -0
- package/plugins/builtin/tool-plugins.test.ts +529 -0
- package/public/favicon.svg +7 -0
- package/public/sw.js +91 -0
- package/pyproject.toml +49 -0
- package/scripts/eslint-wave-a-list.sh +24 -0
- package/scripts/eslint-wave-a-status.sh +25 -0
- package/scripts/fix-index-signature-access.py +127 -0
- package/scripts/fix-unchecked-index.py +128 -0
- package/scripts/fix-unchecked-vars.py +127 -0
- package/scripts/fix-wave-a-bangs.py +36 -0
- package/scripts/fix-wave-a-templates.py +108 -0
- package/scripts/fix-wave-b-void-expr.py +167 -0
- package/scripts/generate-command-params.py +540 -0
- package/scripts/migrate-single-frame-to-multi.py +171 -0
- package/scripts/smoke-test.sh +77 -0
- package/selfdoc.json +10 -0
- package/server/README.md +0 -0
- package/server/src/pixelweaver/__init__.py +1 -0
- package/server/src/pixelweaver/__main__.py +4 -0
- package/server/src/pixelweaver/autosave.py +114 -0
- package/server/src/pixelweaver/bridge.py +127 -0
- package/server/src/pixelweaver/cli.py +199 -0
- package/server/src/pixelweaver/config.py +24 -0
- package/server/src/pixelweaver/connections.py +54 -0
- package/server/src/pixelweaver/main.py +271 -0
- package/server/src/pixelweaver/mcp_bridge.py +189 -0
- package/server/src/pixelweaver/mcp_drawing_tools.py +178 -0
- package/server/src/pixelweaver/mcp_export_tools.py +291 -0
- package/server/src/pixelweaver/mcp_frame_tools.py +423 -0
- package/server/src/pixelweaver/mcp_history_tools.py +106 -0
- package/server/src/pixelweaver/mcp_layer_tools.py +64 -0
- package/server/src/pixelweaver/mcp_lock.py +37 -0
- package/server/src/pixelweaver/mcp_project_tools.py +302 -0
- package/server/src/pixelweaver/mcp_read_tools.py +163 -0
- package/server/src/pixelweaver/mcp_registry.py +247 -0
- package/server/src/pixelweaver/mcp_resources.py +312 -0
- package/server/src/pixelweaver/mcp_server.py +234 -0
- package/server/src/pixelweaver/protocol.py +219 -0
- package/server/src/pixelweaver/state.py +267 -0
- package/server/src/pixelweaver/storage.py +293 -0
- package/server/src/pixelweaver/websocket.py +282 -0
- package/server/tests/__init__.py +0 -0
- package/server/tests/conftest.py +17 -0
- package/server/tests/test_api.py +96 -0
- package/server/tests/test_bridge.py +161 -0
- package/server/tests/test_health.py +9 -0
- package/server/tests/test_integration.py +86 -0
- package/server/tests/test_mcp_bridge.py +293 -0
- package/server/tests/test_mcp_lock.py +34 -0
- package/server/tests/test_mcp_registry.py +679 -0
- package/server/tests/test_mcp_resources.py +648 -0
- package/server/tests/test_protocol.py +125 -0
- package/server/tests/test_state.py +87 -0
- package/server/tests/test_storage.py +306 -0
- package/server/tests/test_websocket.py +275 -0
- package/src/App.svelte +107 -0
- package/src/app.css +215 -0
- package/src/lib/animation/AnimationPreviewPanel.svelte +667 -0
- package/src/lib/animation/animation-commands.test.ts +228 -0
- package/src/lib/animation/animation-commands.ts +540 -0
- package/src/lib/animation/animation-preview-panel-plugin.ts +25 -0
- package/src/lib/animation/animation-preview.svelte.ts +151 -0
- package/src/lib/animation/clipboard.ts +134 -0
- package/src/lib/animation/frame-model.svelte.ts +437 -0
- package/src/lib/animation/frame-model.test.ts +314 -0
- package/src/lib/animation/frame-selection.svelte.ts +77 -0
- package/src/lib/animation/frame-tags.svelte.ts +238 -0
- package/src/lib/animation/frame-tags.test.ts +136 -0
- package/src/lib/animation/import.test.ts +141 -0
- package/src/lib/animation/import.ts +112 -0
- package/src/lib/animation/spritesheet-export.test.ts +239 -0
- package/src/lib/animation/spritesheet-export.ts +314 -0
- package/src/lib/canvas/CanvasViewport.svelte +216 -0
- package/src/lib/canvas/canvas-init-plugin.ts +178 -0
- package/src/lib/canvas/canvas-renderer.ts +408 -0
- package/src/lib/canvas/canvas-state.svelte.ts +232 -0
- package/src/lib/canvas/canvas-state.test.ts +139 -0
- package/src/lib/canvas/input-handler.ts +221 -0
- package/src/lib/canvas/input-plugin.ts +150 -0
- package/src/lib/canvas/onion-skin.ts +94 -0
- package/src/lib/canvas/pixel-buffer.test.ts +249 -0
- package/src/lib/canvas/pixel-buffer.ts +151 -0
- package/src/lib/canvas/render-state.svelte.ts +18 -0
- package/src/lib/canvas/shape-preview-state.svelte.ts +36 -0
- package/src/lib/canvas/tile-mode.test.ts +53 -0
- package/src/lib/canvas/tile-mode.ts +92 -0
- package/src/lib/canvas/viewport-utils.ts +24 -0
- package/src/lib/canvas/zoom-utils.ts +31 -0
- package/src/lib/color/.gitkeep +0 -0
- package/src/lib/color/color-commands.ts +87 -0
- package/src/lib/color/color-state.svelte.ts +98 -0
- package/src/lib/color/color-state.test.ts +91 -0
- package/src/lib/color/color-utils.test.ts +220 -0
- package/src/lib/color/color-utils.ts +243 -0
- package/src/lib/color/palette-state.svelte.ts +127 -0
- package/src/lib/color/palette-state.test.ts +154 -0
- package/src/lib/color/palette.ts +79 -0
- package/src/lib/core/bootstrap.ts +66 -0
- package/src/lib/core/command-params.generated.ts +1549 -0
- package/src/lib/core/command-params.ts +20 -0
- package/src/lib/core/command-runner.ts +79 -0
- package/src/lib/core/commands.ts +134 -0
- package/src/lib/core/dispatcher.test.ts +548 -0
- package/src/lib/core/dispatcher.ts +361 -0
- package/src/lib/core/index.test.ts +7 -0
- package/src/lib/core/notification-state.svelte.ts +119 -0
- package/src/lib/core/plugin-api.ts +210 -0
- package/src/lib/core/plugin-discovery.test.ts +53 -0
- package/src/lib/core/plugin-discovery.ts +65 -0
- package/src/lib/core/plugin-loader.test.ts +159 -0
- package/src/lib/core/plugin-loader.ts +240 -0
- package/src/lib/core/plugin-types.ts +286 -0
- package/src/lib/core/registries.svelte.ts +74 -0
- package/src/lib/core/tool-options-state.svelte.ts +61 -0
- package/src/lib/dock/DockLayout.svelte +375 -0
- package/src/lib/dock/TabAddMenu.svelte +90 -0
- package/src/lib/dock/dock-persistence.ts +46 -0
- package/src/lib/dock/dock-plugin.ts +49 -0
- package/src/lib/dock/dock-presets.ts +156 -0
- package/src/lib/dock/dock-state.svelte.ts +77 -0
- package/src/lib/dock/dock-types.ts +2 -0
- package/src/lib/dock/dockview-theme.css +226 -0
- package/src/lib/dock/dockview-theme.ts +17 -0
- package/src/lib/dock/header-action-renderer.ts +77 -0
- package/src/lib/edit/clipboard-state.ts +34 -0
- package/src/lib/export/download.ts +201 -0
- package/src/lib/export/png-metadata.ts +181 -0
- package/src/lib/history/ActionLogPanel.svelte +418 -0
- package/src/lib/history/action-log-panel-plugin.ts +24 -0
- package/src/lib/history/action-log.svelte.ts +172 -0
- package/src/lib/history/action-log.test.ts +168 -0
- package/src/lib/history/history-commands.ts +403 -0
- package/src/lib/history/macros.svelte.ts +320 -0
- package/src/lib/history/macros.test.ts +224 -0
- package/src/lib/history/replay-engine.test.ts +241 -0
- package/src/lib/history/replay-engine.ts +149 -0
- package/src/lib/history/spec-format.test.ts +250 -0
- package/src/lib/history/spec-format.ts +210 -0
- package/src/lib/iso/SeamCheckerPanel.svelte +251 -0
- package/src/lib/iso/iso-math.test.ts +77 -0
- package/src/lib/iso/iso-math.ts +77 -0
- package/src/lib/iso/seam-checker-panel-plugin.ts +25 -0
- package/src/lib/iso/seam-checker.test.ts +126 -0
- package/src/lib/iso/seam-checker.ts +93 -0
- package/src/lib/iso/tessellation.ts +67 -0
- package/src/lib/layers/compositor.test.ts +193 -0
- package/src/lib/layers/compositor.ts +175 -0
- package/src/lib/layers/layer-commands.test.ts +263 -0
- package/src/lib/layers/layer-commands.ts +429 -0
- package/src/lib/layers/layer-tree.svelte.ts +516 -0
- package/src/lib/layers/layer-tree.test.ts +383 -0
- package/src/lib/layers/layer-types.ts +56 -0
- package/src/lib/leveleditor/LevelEditorViewport.svelte +1808 -0
- package/src/lib/leveleditor/MapPropertiesPanel.svelte +266 -0
- package/src/lib/leveleditor/TilePickerPanel.svelte +324 -0
- package/src/lib/leveleditor/depth-sort.test.ts +70 -0
- package/src/lib/leveleditor/depth-sort.ts +39 -0
- package/src/lib/leveleditor/level-editor-commands.ts +353 -0
- package/src/lib/leveleditor/level-editor-viewport-plugin.ts +25 -0
- package/src/lib/leveleditor/map-properties-panel-plugin.ts +25 -0
- package/src/lib/leveleditor/map-state.svelte.ts +372 -0
- package/src/lib/leveleditor/map-state.test.ts +243 -0
- package/src/lib/leveleditor/tile-picker-panel-plugin.ts +25 -0
- package/src/lib/leveleditor/tile-source-registry.svelte.ts +91 -0
- package/src/lib/leveleditor/tiled-export.test.ts +144 -0
- package/src/lib/leveleditor/tiled-export.ts +374 -0
- package/src/lib/pywebview.d.ts +15 -0
- package/src/lib/recovery/.gitkeep +0 -0
- package/src/lib/recovery/idb-store.ts +118 -0
- package/src/lib/recovery/recovery-manager.test.ts +321 -0
- package/src/lib/recovery/recovery-manager.ts +115 -0
- package/src/lib/recovery/recovery-plugin.ts +55 -0
- package/src/lib/recovery/recovery-state.svelte.ts +21 -0
- package/src/lib/recovery/sw-plugin.ts +18 -0
- package/src/lib/recovery/sw-register.ts +17 -0
- package/src/lib/save/directory-format.ts +42 -0
- package/src/lib/save/project-snapshot.ts +139 -0
- package/src/lib/save/recent-projects.ts +56 -0
- package/src/lib/save/save-state.svelte.ts +35 -0
- package/src/lib/save/storage.ts +167 -0
- package/src/lib/save/zip-format.ts +45 -0
- package/src/lib/shortcuts/.gitkeep +0 -0
- package/src/lib/shortcuts/ShortcutEditorPanel.svelte +690 -0
- package/src/lib/shortcuts/default-bindings.ts +61 -0
- package/src/lib/shortcuts/shortcut-editor-panel-plugin.ts +25 -0
- package/src/lib/shortcuts/shortcut-init.ts +380 -0
- package/src/lib/shortcuts/shortcut-manager.test.ts +466 -0
- package/src/lib/shortcuts/shortcut-manager.ts +281 -0
- package/src/lib/shortcuts/shortcut-state.svelte.ts +78 -0
- package/src/lib/shortcuts/shortcuts-plugin.ts +17 -0
- package/src/lib/sync/patch-applicator.ts +300 -0
- package/src/lib/sync/patch-types.ts +65 -0
- package/src/lib/sync/project-manager.ts +108 -0
- package/src/lib/sync/sync-init.ts +152 -0
- package/src/lib/sync/sync-plugin.ts +19 -0
- package/src/lib/sync/sync-state.svelte.ts +56 -0
- package/src/lib/sync/ws-client.test.ts +604 -0
- package/src/lib/sync/ws-client.ts +574 -0
- package/src/lib/tools/.gitkeep +0 -0
- package/src/lib/ui/.gitkeep +0 -0
- package/src/lib/ui/AboutDialog.svelte +113 -0
- package/src/lib/ui/ColorPicker.svelte +761 -0
- package/src/lib/ui/ContextMenu.svelte +216 -0
- package/src/lib/ui/ExportDialog.svelte +747 -0
- package/src/lib/ui/FrameStrip.svelte +854 -0
- package/src/lib/ui/LayerPanel.svelte +810 -0
- package/src/lib/ui/MenuBar.svelte +590 -0
- package/src/lib/ui/NewProjectDialog.svelte +803 -0
- package/src/lib/ui/PluginManagerPanel.svelte +475 -0
- package/src/lib/ui/PromptDialog.svelte +252 -0
- package/src/lib/ui/RecoveryDialog.svelte +295 -0
- package/src/lib/ui/ResizeDialog.svelte +416 -0
- package/src/lib/ui/StatusBar.svelte +145 -0
- package/src/lib/ui/ToolbarPanel.svelte +488 -0
- package/src/lib/ui/animation-menu-commands.ts +194 -0
- package/src/lib/ui/command-palette/CommandPalette.svelte +232 -0
- package/src/lib/ui/command-palette/command-palette-plugin.ts +30 -0
- package/src/lib/ui/command-palette/command-palette-state.svelte.ts +190 -0
- package/src/lib/ui/command-palette/command-palette.test.ts +129 -0
- package/src/lib/ui/dialog-state.svelte.ts +70 -0
- package/src/lib/ui/edit-commands.ts +271 -0
- package/src/lib/ui/file-commands.ts +275 -0
- package/src/lib/ui/file-open.ts +99 -0
- package/src/lib/ui/help-commands.ts +93 -0
- package/src/lib/ui/image-commands.ts +181 -0
- package/src/lib/ui/layer-menu-commands.ts +420 -0
- package/src/lib/ui/menu-builder.ts +224 -0
- package/src/lib/ui/notifications/NotificationBanner.svelte +137 -0
- package/src/lib/ui/notifications/notification-plugin.ts +29 -0
- package/src/lib/ui/notifications/notification-state.svelte.ts +9 -0
- package/src/lib/ui/plugin-manager-panel-plugin.ts +26 -0
- package/src/lib/ui/plugin-state.svelte.ts +62 -0
- package/src/lib/ui/select-commands.ts +75 -0
- package/src/lib/ui/theme-plugin.ts +18 -0
- package/src/lib/ui/theme.svelte.ts +45 -0
- package/src/lib/ui/theme.test.ts +51 -0
- package/src/lib/ui/toolbar-config.ts +90 -0
- package/src/lib/ui/toolbar-plugin.ts +39 -0
- package/src/lib/ui/view-commands.ts +629 -0
- package/src/lib/variants/BisectionExportDialog.svelte +500 -0
- package/src/lib/variants/VariantPanel.svelte +822 -0
- package/src/lib/variants/bisection-export.test.ts +113 -0
- package/src/lib/variants/bisection-export.ts +148 -0
- package/src/lib/variants/palette-extraction.test.ts +111 -0
- package/src/lib/variants/palette-extraction.ts +84 -0
- package/src/lib/variants/palette-interpolation.test.ts +113 -0
- package/src/lib/variants/palette-interpolation.ts +87 -0
- package/src/lib/variants/palette-swap.test.ts +101 -0
- package/src/lib/variants/palette-swap.ts +114 -0
- package/src/lib/variants/variant-commands.ts +594 -0
- package/src/lib/variants/variant-panel-plugin.ts +27 -0
- package/src/lib/variants/variant-randomizer.ts +101 -0
- package/src/lib/variants/variant-state.svelte.ts +166 -0
- package/src/lib/variants/variant-state.test.ts +138 -0
- package/src/main.ts +14 -0
- package/src/vite-env.d.ts +3 -0
- package/svelte.config.js +2 -0
- package/todo/.done/audit-design-decisions.md +812 -0
- package/todo/.done/audit-implementation-plan.md +1235 -0
- package/todo/.done/happy-path-polish.md +177 -0
- package/todo/.done/pixelweaver-full-build.md +937 -0
- package/todo/.done/server-multi-frame-design.md +405 -0
- package/todo/.done/typed-dispatcher-design.md +435 -0
- package/todo/.done/unified-toolbar-and-action-system.md +323 -0
- package/todo/.obsolete/comprehensive-audit-obsolete-items.md +33 -0
- package/todo/.obsolete/tauri-desktop-bundle.md +424 -0
- package/todo/comprehensive-audit.md +1085 -0
- package/tsconfig.app.json +26 -0
- package/tsconfig.json +7 -0
- package/tsconfig.node.json +20 -0
- package/uv.lock +1167 -0
- 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 |
|